Convert format calls to f-strings

This commit is contained in:
Jared Miller 2026-02-12 19:59:00 -05:00
parent f0438812fc
commit 5cccb9b521
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
50 changed files with 293 additions and 458 deletions

56
art.py
View file

@ -107,8 +107,8 @@ class Art:
def __init__(self, filename, app, charset, palette, width, height):
"Creates a new, blank document with given parameters."
self.valid = False
if filename and not filename.endswith(".{}".format(ART_FILE_EXTENSION)):
filename += ".{}".format(ART_FILE_EXTENSION)
if filename and not filename.endswith(f".{ART_FILE_EXTENSION}"):
filename += f".{ART_FILE_EXTENSION}"
self.filename = filename
self.app = app
# save "time loaded" for menu sorting
@ -162,11 +162,11 @@ class Art:
def log_init(self):
self.app.log("created new document:")
self.app.log(" character set: {}".format(self.charset.name))
self.app.log(" palette: {}".format(self.palette.name))
self.app.log(" width/height: {} x {}".format(self.width, self.height))
self.app.log(" frames: {}".format(self.frames))
self.app.log(" layers: {}".format(self.layers))
self.app.log(f" character set: {self.charset.name}")
self.app.log(f" palette: {self.palette.name}")
self.app.log(f" width/height: {self.width} x {self.height}")
self.app.log(f" frames: {self.frames}")
self.app.log(f" layers: {self.layers}")
def init_layers(self):
self.layers = 1
@ -218,7 +218,7 @@ class Art:
if self.app.ui and self is self.app.ui.active_art:
self.app.ui.set_active_frame(index)
if log:
self.app.log("Created new frame at index {}".format(str(index)))
self.app.log(f"Created new frame at index {str(index)}")
def add_frame_to_end(self, delay=DEFAULT_FRAME_DELAY, log=True):
"Add a blank frame at the end of the current animation."
@ -245,9 +245,7 @@ class Art:
if self is self.app.ui.active_art:
self.app.ui.set_active_frame(dest_frame_index - 1)
self.app.log(
"Duplicated frame {} at frame {}".format(
src_frame_index + 1, dest_frame_index
)
f"Duplicated frame {src_frame_index + 1} at frame {dest_frame_index}"
)
def delete_frame_at(self, index):
@ -307,7 +305,7 @@ class Art:
z = z if z is not None else self.layers_z[src_index]
self.layers_z.append(z)
self.layers_visibility.append(True)
new_name = new_name or "Copy of {}".format(self.layer_names[src_index])
new_name = new_name or f"Copy of {self.layer_names[src_index]}"
self.layer_names.append(new_name)
# rebuild geo with added verts for new layer
self.geo_changed = True
@ -316,7 +314,7 @@ class Art:
self.app.ui.set_active_layer(self.layers - 1)
# don't log new layers created on the fly in game mode
if not self.app.game_mode:
self.app.log("Added new layer {}".format(new_name))
self.app.log(f"Added new layer {new_name}")
self.set_unsaved_changes(True)
def clear_frame_layer(self, frame, layer, bg_color=0, fg_color=None):
@ -367,7 +365,7 @@ class Art:
self.geo_changed = True
if log:
self.app.ui.message_line.post_line(
"Character set changed to {}".format(self.charset.name)
f"Character set changed to {self.charset.name}"
)
def set_charset_by_name(self, new_charset_name):
@ -383,7 +381,7 @@ class Art:
self.set_unsaved_changes(True)
if log:
self.app.ui.message_line.post_line(
"Color palette changed to {}".format(self.palette.name)
f"Color palette changed to {self.palette.name}"
)
def set_palette_by_name(self, new_palette_name):
@ -870,7 +868,7 @@ class Art:
json.dump(d, open(self.filename, "w"), sort_keys=True, indent=1)
self.set_unsaved_changes(False)
# self.app.log('saved %s to disk in %.5f seconds' % (self.filename, end_time - start_time))
self.app.log("saved {}".format(self.filename))
self.app.log(f"saved {self.filename}")
# remove old thumbnail
thumb_dir = self.app.cache_dir + THUMBNAIL_CACHE_DIR
if os.path.exists(self.filename):
@ -935,9 +933,7 @@ class Art:
json.dump(d, open(self.filename + "2", "w"), sort_keys=True, indent=None)
end_time = time.time()
self.app.log(
"ALT saved {} to disk in {:.5f} seconds".format(
self.filename, end_time - start_time
)
f"ALT saved {self.filename} to disk in {end_time - start_time:.5f} seconds"
)
def set_unsaved_changes(self, new_status):
@ -985,13 +981,13 @@ class Art:
exec(open(script_filename).read())
# (assume script changed art)
self.unsaved_changes = True
logline = "Executed {}".format(script_filename)
logline = f"Executed {script_filename}"
if log:
self.app.log(logline)
error = False
except Exception:
error = True
logline = "Error executing {}:".format(script_filename)
logline = f"Error executing {script_filename}:"
self.app.log(logline)
# skip first 3 lines of callstack before artscript exec
for line in traceback.format_exc().split("\n")[3:]:
@ -1021,7 +1017,7 @@ class Art:
if not script_filename:
return
if script_filename in self.scripts:
self.app.log("script {} is already running.".format(script_filename))
self.app.log(f"script {script_filename} is already running.")
return
# add to "scripts currently running" list
self.scripts.append(script_filename)
@ -1037,7 +1033,7 @@ class Art:
if not script_filename:
return
if script_filename not in self.scripts:
self.app.log("script {} exists but isn't running.".format(script_filename))
self.app.log(f"script {script_filename} exists but isn't running.")
return
script_index = self.scripts.index(script_filename)
self.scripts.pop(script_index)
@ -1240,12 +1236,12 @@ class ArtFromDisk(Art):
self.valid = True
def log_init(self):
self.app.log("Loaded {} from disk:".format(filename))
self.app.log(" character set: {}".format(self.charset.name))
self.app.log(" palette: {}".format(self.palette.name))
self.app.log(" width/height: {} x {}".format(self.width, self.height))
self.app.log(" frames: {}".format(self.frames))
self.app.log(" layers: {}".format(self.layers))
self.app.log(f"Loaded {filename} from disk:")
self.app.log(f" character set: {self.charset.name}")
self.app.log(f" palette: {self.palette.name}")
self.app.log(f" width/height: {self.width} x {self.height}")
self.app.log(f" frames: {self.frames}")
self.app.log(f" layers: {self.layers}")
def init_layers(self):
frames = self.loaded_data["frames"]
@ -1256,7 +1252,7 @@ class ArtFromDisk(Art):
self.layers_z.append(layer["z"])
self.layers_visibility.append(bool(layer.get("visible", 1)))
layer_num = str(i + 1)
self.layer_names.append(layer.get("name", "Layer {}".format(layer_num)))
self.layer_names.append(layer.get("name", f"Layer {layer_num}"))
active_layer = self.loaded_data.get("active_layer", 0)
self.set_active_layer(active_layer)

View file

@ -23,10 +23,8 @@ class ArtExporter:
self.app = app
self.art = self.app.ui.active_art
# add file extension to output filename if not present
if self.file_extension and not out_filename.endswith(
".{}".format(self.file_extension)
):
out_filename += ".{}".format(self.file_extension)
if self.file_extension and not out_filename.endswith(f".{self.file_extension}"):
out_filename += f".{self.file_extension}"
# output filename in documents/art dir
if not out_filename.startswith(self.app.documents_dir + ART_DIR):
out_filename = self.app.documents_dir + ART_DIR + out_filename
@ -41,10 +39,7 @@ class ArtExporter:
if self.run_export(out_filename, options):
self.success = True
else:
line = "{} failed to export {}, see console for errors".format(
self.__class__.__name__,
out_filename,
)
line = f"{self.__class__.__name__} failed to export {out_filename}, see console for errors"
self.app.log(line)
self.app.ui.message_line.post_line(line, hold_time=10, error=True)
except Exception:

View file

@ -32,9 +32,7 @@ class ArtImporter:
def __init__(self, app, in_filename, options={}):
self.app = app
new_filename = "{}.{}".format(
os.path.splitext(in_filename)[0], ART_FILE_EXTENSION
)
new_filename = f"{os.path.splitext(in_filename)[0]}.{ART_FILE_EXTENSION}"
self.art = self.app.new_art(new_filename)
# use charset and palette of existing art
charset = (

View file

@ -312,4 +312,4 @@ class Camera:
self.mouse_panned = False
def log_loc(self):
self.app.log("camera x={}, y={}, z={}".format(self.x, self.y, self.z))
self.app.log(f"camera x={self.x}, y={self.y}, z={self.z}")

View file

@ -32,22 +32,16 @@ class CharacterSetLord:
success = charset.load_char_data()
if success:
self.app.log(
"CharacterSetLord: success reloading {}".format(
charset.filename
)
f"CharacterSetLord: success reloading {charset.filename}"
)
else:
self.app.log(
"CharacterSetLord: failed reloading {}".format(
charset.filename
),
f"CharacterSetLord: failed reloading {charset.filename}",
True,
)
except Exception:
self.app.log(
"CharacterSetLord: failed reloading {}".format(
charset.filename
),
f"CharacterSetLord: failed reloading {charset.filename}",
True,
)
@ -62,7 +56,7 @@ class CharacterSet:
src_filename, CHARSET_DIR, CHARSET_FILE_EXTENSION
)
if not self.filename:
self.app.log("Couldn't find character set data {}".format(self.filename))
self.app.log(f"Couldn't find character set data {self.filename}")
return
self.name = os.path.basename(self.filename)
self.name = os.path.splitext(self.name)[0]
@ -76,9 +70,7 @@ class CharacterSet:
return
# report
if log and not self.app.game_mode:
self.app.log(
"loaded charmap '{}' from {}:".format(self.name, self.filename)
)
self.app.log(f"loaded charmap '{self.name}' from {self.filename}:")
self.report()
self.init_success = True
@ -97,9 +89,7 @@ class CharacterSet:
char_data.pop(0).strip(), CHARSET_DIR, "png"
)
if not img_filename:
self.app.log(
"Couldn't find character set image {}".format(self.image_filename)
)
self.app.log(f"Couldn't find character set image {self.image_filename}")
return False
self.image_filename = img_filename
# now that we know the image file's name, store its last modified time
@ -176,19 +166,13 @@ class CharacterSet:
def report(self):
self.app.log(
" source texture {} is {} x {} pixels".format(
self.image_filename, self.image_width, self.image_height
)
f" source texture {self.image_filename} is {self.image_width} x {self.image_height} pixels"
)
self.app.log(
" char pixel width/height is {} x {}".format(
self.char_width, self.char_height
f" char pixel width/height is {self.char_width} x {self.char_height}"
)
)
self.app.log(
" char map width/height is {} x {}".format(self.map_width, self.map_height)
)
self.app.log(" last character index: {}".format(self.last_index))
self.app.log(f" char map width/height is {self.map_width} x {self.map_height}")
self.app.log(f" last character index: {self.last_index}")
def has_updated(self):
"return True if source image file has changed since last check"

View file

@ -307,9 +307,7 @@ class Collideable:
frame = self.go.renderable.frame
if self.go.col_layer_name not in self.go.art.layer_names:
self.go.app.dev_log(
"{}: Couldn't find collision layer with name '{}'".format(
self.go.name, self.go.col_layer_name
)
f"{self.go.name}: Couldn't find collision layer with name '{self.go.col_layer_name}'"
)
return
layer = self.go.art.layer_names.index(self.go.col_layer_name)
@ -443,9 +441,7 @@ class CollisionLord:
def report(self):
print(
"{}: {} dynamic shapes, {} static shapes".format(
self, len(self.dynamic_shapes), len(self.static_shapes)
)
f"{self}: {len(self.dynamic_shapes)} dynamic shapes, {len(self.static_shapes)} static shapes"
)
def reset(self):

View file

@ -141,9 +141,7 @@ class Cursor:
self.app.keyboard_editing = True
if self.logg:
self.app.log(
"Cursor: {},{},{} scale {:.2f},{:.2f}".format(
self.x, self.y, self.z, self.scale_x, self.scale_y
)
f"Cursor: {self.x},{self.y},{self.z} scale {self.scale_x:.2f},{self.scale_y:.2f}"
)
def set_scale(self, new_scale):
@ -186,7 +184,7 @@ class Cursor:
x0, y0 = self.x, -self.y
x1, y1 = self.last_x, -self.last_y
tiles = vector.get_tiles_along_line(x0, y0, x1, y1)
print("drag from {},{} to {},{}:".format(x0, y0, x1, y1))
print(f"drag from {x0},{y0} to {x1},{y1}:")
print(tiles)
return tiles

View file

@ -23,11 +23,7 @@ class EditCommand:
# get unique-ish ID from memory address
addr = self.__repr__()
addr = addr[addr.find("0") : -1]
s = "EditCommand_{}: {} tiles, time {}".format(
addr,
self.get_number_of_commands(),
self.finish_time,
)
s = f"EditCommand_{addr}: {self.get_number_of_commands()} tiles, time {self.finish_time}"
return s
def add_command_tiles(self, new_command_tiles):
@ -95,7 +91,7 @@ class EntireArtCommand:
for atype in self.array_types:
# save list as eg "b_chars" for "character data before operation"
src_data = getattr(self.art, atype)
var_name = "{}_{}".format(prefix, atype)
var_name = f"{prefix}_{atype}"
# deep copy each frame's data, else before == after
new_data = []
for frame in src_data:
@ -152,10 +148,8 @@ class EditCommandTile:
str(self.y).rjust(2, "0"),
self.creation_time,
)
s += "c{} f{} b{} x{} -> ".format(
self.b_char, self.b_fg, self.b_bg, self.b_xform
)
s += "c{} f{} b{} x{}".format(self.a_char, self.a_fg, self.a_bg, self.a_xform)
s += f"c{self.b_char} f{self.b_fg} b{self.b_bg} x{self.b_xform} -> "
s += f"c{self.a_char} f{self.a_fg} b{self.a_bg} x{self.a_xform}"
return s
def __eq__(self, value):
@ -261,7 +255,7 @@ class CommandStack:
self.undo_commands, self.redo_commands = [], []
def __str__(self):
s = "stack for {}:\n".format(self.art.filename)
s = f"stack for {self.art.filename}:\n"
s += "===\nundo:\n"
for cmd in self.undo_commands:
s += str(cmd) + "\n"

View file

@ -100,7 +100,7 @@ class ConvertImageOptionsDialog(ImportOptionsDialog):
# can't assume any art is open, use defaults if needed
w = self.ui.active_art.width if self.ui.active_art else DEFAULT_WIDTH
h = self.ui.active_art.height if self.ui.active_art else DEFAULT_HEIGHT
label %= "{} x {}".format(w, h)
label %= f"{w} x {h}"
elif field_index == 7:
# scale # might not be valid
valid, _ = self.is_input_valid()

View file

@ -50,7 +50,7 @@ class ImageSequenceConverter:
self.app.update_window_title()
def fail(self):
self.app.log("Bad frame {}".format(self.image_filenames[0]), error=True)
self.app.log(f"Bad frame {self.image_filenames[0]}", error=True)
self.finish(True)
def update(self):
@ -65,9 +65,7 @@ class ImageSequenceConverter:
time_taken = time.time() - self.start_time
(verb, error) = ("cancelled", True) if cancelled else ("finished", False)
self.app.log(
"Conversion of image sequence {} {} after {:.3f} seconds".format(
self.image_name, verb, time_taken
),
f"Conversion of image sequence {self.image_name} {verb} after {time_taken:.3f} seconds",
error,
)
self.app.converter = None
@ -97,7 +95,7 @@ image chosen.
bicubic_scale = options["bicubic_scale"]
# get dir listing with full pathname
in_dir = os.path.dirname(in_filename)
in_files = ["{}/{}".format(in_dir, f) for f in os.listdir(in_dir)]
in_files = [f"{in_dir}/{f}" for f in os.listdir(in_dir)]
in_files.sort()
# assume numeric sequence starts from chosen file
in_files = in_files[in_files.index(in_filename) :]

View file

@ -37,7 +37,7 @@ class PNGExportOptionsDialog(ExportOptionsDialog):
scale = int(self.field_texts[0])
width = art.charset.char_width * art.width * scale
height = art.charset.char_height * art.height * scale
label %= "{} x {}".format(width, height)
label %= f"{width} x {height}"
return label
def is_input_valid(self):

View file

@ -24,12 +24,12 @@ def get_full_filename(
if use_frame:
fn += "_{}".format(str(frame).rjust(4, "0"))
if use_layer:
fn += "_{}".format(layer_name)
fn += f"_{layer_name}"
# strip unfriendly chars from output filename
for forbidden_char in ["\\", "/", "*", ":"]:
fn = fn.replace(forbidden_char, "")
# add path and extension for final mutated filename
return "{}/{}.{}".format(dirname, fn, FILE_EXTENSION)
return f"{dirname}/{fn}.{FILE_EXTENSION}"
class PNGSetExportOptionsDialog(ExportOptionsDialog):
@ -78,7 +78,7 @@ class PNGSetExportOptionsDialog(ExportOptionsDialog):
scale = int(self.field_texts[0])
width = art.charset.char_width * art.width * scale
height = art.charset.char_height * art.height * scale
label %= "{} x {}".format(width, height)
label %= f"{width} x {height}"
# show how many images exported set will be
elif field_index == 4:
export_frames = bool(self.field_texts[2].strip())

View file

@ -243,9 +243,7 @@ class GameObject:
if v not in obj_data:
if self.log_load:
self.app.dev_log(
"Serialized property '{}' not found for {}".format(
v, self.name
)
f"Serialized property '{v}' not found for {self.name}"
)
continue
# if value is in data and serialized list but undeclared, do so
@ -288,7 +286,7 @@ class GameObject:
"Dict of all Arts this object can reference, eg for states"
# if art_src not specified, create a new art according to dimensions
if self.generate_art:
self.art_src = "{}_art".format(self.name)
self.art_src = f"{self.name}_art"
self.art = self.app.new_art(
self.art_src,
self.art_width,
@ -308,7 +306,7 @@ class GameObject:
self.art = self.arts[art]
break
if not self.art:
self.app.log("Couldn't spawn GameObject with art {}".format(self.art_src))
self.app.log(f"Couldn't spawn GameObject with art {self.art_src}")
return
self.renderable = GameObjectRenderable(self.app, self.art, self)
self.renderable.alpha = self.alpha
@ -345,9 +343,7 @@ class GameObject:
self.start_animating()
if self.log_spawn:
self.app.log(
"Spawned {} with Art {}".format(
self.name, os.path.basename(self.art.filename)
)
f"Spawned {self.name} with Art {os.path.basename(self.art.filename)}"
)
def get_unique_name(self):
@ -379,13 +375,13 @@ class GameObject:
if self.facing_changes_art:
# load each facing for each state
for facing in FACINGS.values():
art_name = "{}_{}_{}".format(self.art_src, state, facing)
art_name = f"{self.art_src}_{state}_{facing}"
art = self.app.load_art(art_name, False)
if art:
self.arts[art_name] = art
else:
# load each state
art_name = "{}_{}".format(self.art_src, state)
art_name = f"{self.art_src}_{state}"
art = self.app.load_art(art_name, False)
if art:
self.arts[art_name] = art
@ -667,14 +663,14 @@ class GameObject:
"Return Art (and 'flip X' bool) that best represents current state"
# use current state if none specified
state = self.state if state is None else state
art_state_name = "{}_{}".format(self.art_src, self.state)
art_state_name = f"{self.art_src}_{self.state}"
# simple case: no facing, just state
if not self.facing_changes_art:
# return art for current state, use default if not available
if art_state_name in self.arts:
return self.arts[art_state_name], False
else:
default_name = "{}_{}".format(self.art_src, self.state or DEFAULT_STATE)
default_name = f"{self.art_src}_{self.state or DEFAULT_STATE}"
# assert(default_name in self.arts
# don't assert - if base+state name available, use that
if default_name in self.arts:
@ -685,7 +681,7 @@ class GameObject:
# more complex case: art determined by both state and facing
facing_suffix = FACINGS[self.facing]
# first see if anim exists for this exact state, skip subsequent logic
exact_name = "{}_{}".format(art_state_name, facing_suffix)
exact_name = f"{art_state_name}_{facing_suffix}"
if exact_name in self.arts:
return self.arts[exact_name], False
# see what anims are available and try to choose best for facing
@ -696,11 +692,11 @@ class GameObject:
break
# if NO anims for current state, fall back to default
if not has_state:
default_name = "{}_{}".format(self.art_src, DEFAULT_STATE)
default_name = f"{self.art_src}_{DEFAULT_STATE}"
art_state_name = default_name
front_name = "{}_{}".format(art_state_name, FACINGS[GOF_FRONT])
left_name = "{}_{}".format(art_state_name, FACINGS[GOF_LEFT])
right_name = "{}_{}".format(art_state_name, FACINGS[GOF_RIGHT])
front_name = f"{art_state_name}_{FACINGS[GOF_FRONT]}"
left_name = f"{art_state_name}_{FACINGS[GOF_LEFT]}"
right_name = f"{art_state_name}_{FACINGS[GOF_RIGHT]}"
has_front = front_name in self.arts
has_left = left_name in self.arts
has_right = right_name in self.arts
@ -991,9 +987,7 @@ class GameObject:
or self.timer_functions_post_update.get(timer_name, None)
)
if not timer:
self.app.log(
"Timer named {} not found on object {}".format(timer_name, self.name)
)
self.app.log(f"Timer named {timer_name} not found on object {self.name}")
d = [
self.timer_functions_pre_update,
self.timer_functions_update,
@ -1120,9 +1114,7 @@ class GameObject:
or abs(self.y) > self.kill_distance_from_origin
):
self.app.log(
"{} reached {} from origin, destroying.".format(
self.name, self.kill_distance_from_origin
)
f"{self.name} reached {self.kill_distance_from_origin} from origin, destroying."
)
self.destroy()

View file

@ -44,9 +44,7 @@ class GameRoom:
for v in self.serialized:
if v not in room_data:
self.world.app.dev_log(
"Serialized property '{}' not found for room {}".format(
v, self.name
)
f"Serialized property '{v}' not found for room {self.name}"
)
continue
if not hasattr(self, v):
@ -92,9 +90,7 @@ class GameRoom:
def set_camera_marker_name(self, marker_name):
if marker_name not in self.world.objects:
self.world.app.log(
"Couldn't find camera marker with name {}".format(marker_name)
)
self.world.app.log(f"Couldn't find camera marker with name {marker_name}")
return
self.camera_marker_name = marker_name
if self is self.world.current_room:
@ -109,7 +105,7 @@ class GameRoom:
def entered(self, old_room):
"Run when the player enters this room."
if self.log_changes:
self.world.app.log('Room "{}" entered'.format(self.name))
self.world.app.log(f'Room "{self.name}" entered')
# set camera if marker is set
if self.world.room_camera_changes_enabled:
self.use_camera_marker()
@ -124,7 +120,7 @@ class GameRoom:
def exited(self, new_room):
"Run when the player exits this room."
if self.log_changes:
self.world.app.log('Room "{}" exited'.format(self.name))
self.world.app.log(f'Room "{self.name}" exited')
# tell objects in this room player has exited
for obj in self.objects.values():
obj.room_exited(self, new_room)
@ -133,7 +129,7 @@ class GameRoom:
"Add object with given name to this room."
obj = self.world.objects.get(obj_name, None)
if not obj:
self.world.app.log("Couldn't find object named {}".format(obj_name))
self.world.app.log(f"Couldn't find object named {obj_name}")
return
self.add_object(obj)
@ -146,7 +142,7 @@ class GameRoom:
"Remove object with given name from this room."
obj = self.world.objects.get(obj_name, None)
if not obj:
self.world.app.log("Couldn't find object named {}".format(obj_name))
self.world.app.log(f"Couldn't find object named {obj_name}")
return
self.remove_object(obj)
@ -156,13 +152,13 @@ class GameRoom:
self.objects.pop(obj.name)
else:
self.world.app.log(
"GameRoom {} doesn't contain GameObject {}".format(self.name, obj.name)
f"GameRoom {self.name} doesn't contain GameObject {obj.name}"
)
if self.name in obj.rooms:
obj.rooms.pop(self.name)
else:
self.world.app.log(
"GameObject {} not found in GameRoom {}".format(obj.name, self.name)
f"GameObject {obj.name} not found in GameRoom {self.name}"
)
def get_dict(self):

View file

@ -369,9 +369,7 @@ class WarpTrigger(StaticTileTrigger):
marker = self.world.objects.get(self.destination_marker_name, None)
if not marker:
self.app.log(
"Warp destination object {} not found".format(
self.destination_marker_name
)
f"Warp destination object {self.destination_marker_name} not found"
)
return
other.set_loc(marker.x, marker.y, marker.z)
@ -384,9 +382,7 @@ class WarpTrigger(StaticTileTrigger):
and room.name != self.destination_room_name
):
self.app.log(
"Marker {}'s room differs from destination room {}".format(
marker.name, self.destination_room_name
)
f"Marker {marker.name}'s room differs from destination room {self.destination_room_name}"
)
self.world.change_room(room.name)
other.last_warp_update = self.world.updates
@ -504,9 +500,7 @@ class SoundBlaster(LocationMarker):
self.sound_filenames[self.sound_name] = filename
return
self.world.app.log(
"Couldn't find sound file {} for SoundBlaster {}".format(
self.sound_name, self.name
)
f"Couldn't find sound file {self.sound_name} for SoundBlaster {self.name}"
)
def room_entered(self, room, old_room):

View file

@ -220,7 +220,7 @@ class GameWorld:
new_obj = self.spawn_object_of_class(self.classname_to_spawn, x, y)
if self.current_room:
self.current_room.add_object(new_obj)
self.app.ui.message_line.post_line("Spawned {}".format(new_obj.name))
self.app.ui.message_line.post_line(f"Spawned {new_obj.name}")
return
objects = self.get_objects_at(x, y)
next_obj = self.pick_next_object_at(x, y)
@ -408,7 +408,7 @@ class GameWorld:
self.unload_game()
new_dir = self.app.documents_dir + TOP_GAME_DIR + new_game_dir + "/"
if os.path.exists(new_dir):
self.app.log("Game dir {} already exists!".format(new_game_dir))
self.app.log(f"Game dir {new_game_dir} already exists!")
return False
os.mkdir(new_dir)
os.mkdir(new_dir + ART_DIR)
@ -514,7 +514,7 @@ class GameWorld:
self.game_name = dir_name
if not d.endswith("/"):
self.game_dir += "/"
self.app.log("Game data folder is now {}".format(self.game_dir))
self.app.log(f"Game data folder is now {self.game_dir}")
# set sounds dir before loading state; some obj inits depend on it
self.sounds_dir = self.game_dir + SOUNDS_DIR
if reset:
@ -526,7 +526,7 @@ class GameWorld:
self.classes = self._get_all_loaded_classes()
break
if not self.game_dir:
self.app.log("Couldn't find game directory {}".format(dir_name))
self.app.log(f"Couldn't find game directory {dir_name}")
def _remove_non_current_game_modules(self):
"""
@ -535,7 +535,7 @@ class GameWorld:
"""
modules_to_remove = []
games_dir_prefix = TOP_GAME_DIR.replace("/", "")
this_game_dir_prefix = "{}.{}".format(games_dir_prefix, self.game_name)
this_game_dir_prefix = f"{games_dir_prefix}.{self.game_name}"
for module_name in sys.modules:
# remove any module that isn't for this game or part of its path
if (
@ -758,7 +758,7 @@ class GameWorld:
and line.strip() != "method()"
):
self.app.log(line.rstrip())
s = "Error in {}.{}! See console.".format(obj.name, method.__name__)
s = f"Error in {obj.name}.{method.__name__}! See console."
self.app.ui.message_line.post_line(s, 10, True)
def pre_update(self):
@ -938,14 +938,14 @@ class GameWorld:
if filename and filename != "":
if not filename.endswith(STATE_FILE_EXTENSION):
filename += "." + STATE_FILE_EXTENSION
filename = "{}{}".format(self.game_dir, filename)
filename = f"{self.game_dir}{filename}"
else:
# state filename example:
# games/mytestgame2/1431116386.gs
timestamp = int(time.time())
filename = "{}{}.{}".format(self.game_dir, timestamp, STATE_FILE_EXTENSION)
filename = f"{self.game_dir}{timestamp}.{STATE_FILE_EXTENSION}"
json.dump(d, open(filename, "w"), sort_keys=True, indent=1)
self.app.log("Saved game state {} to disk.".format(filename))
self.app.log(f"Saved game state {filename} to disk.")
self.app.update_window_title()
def _get_all_loaded_classes(self):
@ -982,7 +982,7 @@ class GameWorld:
obj_class = obj.__class__.__name__
spawned = self.spawn_object_of_class(obj_class, x, y)
if spawned:
self.app.log("{} reset to class defaults".format(obj.name))
self.app.log(f"{obj.name} reset to class defaults")
if obj is self.player:
self.player = spawned
obj.destroy()
@ -994,9 +994,9 @@ class GameWorld:
new_objects.append(self.duplicate_object(obj))
# report on objects created
if len(new_objects) == 1:
self.app.log("{} created from {}".format(new_objects[0].name, obj.name))
self.app.log(f"{new_objects[0].name} created from {obj.name}")
elif len(new_objects) > 1:
self.app.log("{} new objects created".format(len(new_objects)))
self.app.log(f"{len(new_objects)} new objects created")
def duplicate_object(self, obj):
"Create a duplicate of given object."
@ -1025,9 +1025,7 @@ class GameWorld:
for other_obj in self.objects.values():
if other_obj is not self and other_obj.name == new_name:
self.app.ui.message_line.post_line(
"Can't rename {} to {}, name already in use".format(
obj.name, new_name
)
f"Can't rename {obj.name} to {new_name}, name already in use"
)
return
self.objects.pop(obj.name)
@ -1068,7 +1066,7 @@ class GameWorld:
def add_room(self, new_room_name, new_room_classname="GameRoom"):
"Add a new Room with given name of (optional) given class."
if new_room_name in self.rooms:
self.log("Room called {} already exists!".format(new_room_name))
self.log(f"Room called {new_room_name} already exists!")
return
new_room_class = self.classes[new_room_classname]
new_room = new_room_class(self, new_room_name)
@ -1086,7 +1084,7 @@ class GameWorld:
def change_room(self, new_room_name):
"Set world's current active room to Room with given name."
if new_room_name not in self.rooms:
self.app.log("Couldn't change to missing room {}".format(new_room_name))
self.app.log(f"Couldn't change to missing room {new_room_name}")
return
old_room = self.current_room
self.current_room = self.rooms[new_room_name]
@ -1124,7 +1122,7 @@ class GameWorld:
d = json.load(open(filename))
# self.app.log('Loading game state %s...' % filename)
except Exception:
self.app.log("Couldn't load game state from {}".format(filename))
self.app.log(f"Couldn't load game state from {filename}")
# self.app.log(sys.exc_info())
return
errors = False
@ -1161,7 +1159,7 @@ class GameWorld:
self.hud = hud_class(self)
self.hud_class_name = hud_class.__name__
if not errors and self.app.init_success:
self.app.log("Loaded game state from {}".format(filename))
self.app.log(f"Loaded game state from {filename}")
self.last_state_loaded = filename
self.set_for_all_objects("show_collision", self.show_collision_all)
self.set_for_all_objects("show_bounds", self.show_bounds_all)
@ -1172,13 +1170,13 @@ class GameWorld:
def report(self):
"Print (not log) information about current world state."
print("--------------\n{} report:".format(self))
print(f"--------------\n{self} report:")
obj_arts, obj_rends, obj_dbg_rends, obj_cols, obj_col_rends = 0, 0, 0, 0, 0
attachments = 0
# create merged dict of existing and just-spawned objects
all_objects = self.objects.copy()
all_objects.update(self.new_objects)
print("{} objects:".format(len(all_objects)))
print(f"{len(all_objects)} objects:")
for obj in all_objects.values():
obj_arts += len(obj.arts)
if obj.renderable is not None:
@ -1192,30 +1190,18 @@ class GameWorld:
obj_col_rends += len(obj.collision.renderables)
attachments += len(obj.attachments)
print(
"""
{} arts in objects, {} arts loaded,
{} HUD arts, {} HUD renderables,
{} renderables, {} debug renderables,
{} collideables, {} collideable viz renderables,
{} attachments""".format(
obj_arts,
len(self.art_loaded),
len(self.hud.arts),
len(self.hud.renderables),
obj_rends,
obj_dbg_rends,
obj_cols,
obj_col_rends,
attachments,
)
f"""
{obj_arts} arts in objects, {len(self.art_loaded)} arts loaded,
{len(self.hud.arts)} HUD arts, {len(self.hud.renderables)} HUD renderables,
{obj_rends} renderables, {obj_dbg_rends} debug renderables,
{obj_cols} collideables, {obj_col_rends} collideable viz renderables,
{attachments} attachments"""
)
self.cl.report()
print(
"{} charsets loaded, {} palettes".format(
len(self.app.charsets), len(self.app.palettes)
f"{len(self.app.charsets)} charsets loaded, {len(self.app.palettes)} palettes"
)
)
print("{} arts loaded for edit".format(len(self.app.art_loaded_for_edit)))
print(f"{len(self.app.art_loaded_for_edit)} arts loaded for edit")
def toggle_all_origin_viz(self):
"Toggle visibility of XYZ markers for all object origins."

View file

@ -55,7 +55,7 @@ class CrawlPlayer(Player):
if key == "up"
else DIR_NAMES[OPPOSITE_DIRS[self.direction]]
)
self.app.log("can't go {}!".format(dir_name))
self.app.log(f"can't go {dir_name}!")
else:
self.x, self.y = self.maze.x + new_x, self.maze.y - new_y
# update art to show facing

View file

@ -79,7 +79,7 @@ class Fireplace(GameObject):
self.credit_screen = None
self.music_exists = False
if os.path.exists(self.world.sounds_dir + MUSIC_FILENAME):
self.app.log("{} found in {}".format(MUSIC_FILENAME, self.world.sounds_dir))
self.app.log(f"{MUSIC_FILENAME} found in {self.world.sounds_dir}")
self.world.play_music(MUSIC_FILENAME)
self.music_paused = False
self.music_exists = True
@ -88,9 +88,7 @@ class Fireplace(GameObject):
self.credit_screen.z = 1.1
self.credit_screen.set_scale(0.75, 0.75, 1)
else:
self.app.log(
"No {} found in {}".format(MUSIC_FILENAME, self.world.sounds_dir)
)
self.app.log(f"No {MUSIC_FILENAME} found in {self.world.sounds_dir}")
self.set_new_message_time()
def update(self):
@ -191,16 +189,12 @@ class Fireplace(GameObject):
self.app.fb.toggle_crt()
elif key == "=" or key == "+":
self.target_particles += 10
self.art.write_string(
0, 0, 0, 0, "Embers: {}".format(self.target_particles), 15, 1
)
self.art.write_string(0, 0, 0, 0, f"Embers: {self.target_particles}", 15, 1)
elif key == "-":
if self.target_particles <= 10:
return
self.target_particles -= 10
self.art.write_string(
0, 0, 0, 0, "Embers: {}".format(self.target_particles), 15, 1
)
self.art.write_string(0, 0, 0, 0, f"Embers: {self.target_particles}", 15, 1)
class FireParticle:

View file

@ -79,7 +79,7 @@ class Board(GameObject):
self.reset()
return
# get list of valid keys from length of tile_colors
valid_keys = ["{}".format(str(i + 1)) for i in range(len(TILE_COLORS))]
valid_keys = [f"{str(i + 1)}" for i in range(len(TILE_COLORS))]
if key not in valid_keys:
return
key = int(key) - 1

View file

@ -88,7 +88,7 @@ class MazePickup(GameObject):
def picked_up(self, new_holder):
self.holder = new_holder
self.world.hud.post_msg("got {}!".format(self.display_name))
self.world.hud.post_msg(f"got {self.display_name}!")
self.disable_collision()
self.play_sound("pickup")
@ -167,9 +167,7 @@ class MazeLock(StaticTileBG):
if other.held_object and type(other.held_object) is self.key_type:
self.unlocked(other)
else:
self.world.hud.post_msg(
"blocked - need {}!".format(self.key_type.display_name)
)
self.world.hud.post_msg(f"blocked - need {self.key_type.display_name}!")
def unlocked(self, other):
self.disable_collision()

View file

@ -89,10 +89,8 @@ class FlowerObject(GameObject):
# track # of growth updates we've had
self.grows = 0
# create an art document we can add frames to and later export
self.export_filename = "{}{}wildflower_{}".format(
self.app.documents_dir,
ART_DIR,
self.seed,
self.export_filename = (
f"{self.app.documents_dir}{ART_DIR}wildflower_{self.seed}"
)
self.exportable_art = self.app.new_art(
self.export_filename,

View file

@ -69,7 +69,7 @@ class FlowerGlobals(WorldGlobalsObject):
scale=4,
bg_color=self.world.bg_color,
)
self.app.log("Exported {}.png".format(self.flower.export_filename))
self.app.log(f"Exported {self.flower.export_filename}.png")
class SeedDisplay(GameObject):

View file

@ -38,7 +38,7 @@ class ImageConverter:
self.init_success = False
image_filename = app.find_filename_path(image_filename)
if not image_filename or not os.path.exists(image_filename):
app.log("ImageConverter: Couldn't find image {}".format(image_filename))
app.log(f"ImageConverter: Couldn't find image {image_filename}")
app.converter = None
return
self.app = app
@ -266,9 +266,7 @@ class ImageConverter:
time_taken = time.time() - self.start_time
verb = "cancelled" if cancelled else "finished"
self.app.log(
"Conversion of image {} {} after {:.3f} seconds".format(
self.image_filename, verb, time_taken
)
f"Conversion of image {self.image_filename} {verb} after {time_taken:.3f} seconds"
)
self.app.converter = None
self.preview_sprite = None

View file

@ -14,9 +14,7 @@ def get_frame_image(app, art, frame, allow_crt=True, scale=1, bg_color=(0, 0, 0,
# error out if over max texture size
if w > app.max_texture_size or h > app.max_texture_size:
app.log(
"ERROR: Image output size ({} x {}) exceeds your hardware's max supported texture size ({} x {})!".format(
w, h, app.max_texture_size, app.max_texture_size
),
f"ERROR: Image output size ({w} x {h}) exceeds your hardware's max supported texture size ({app.max_texture_size} x {app.max_texture_size})!",
error=True,
)
app.log(

View file

@ -89,13 +89,13 @@ class InputLord:
) < os.path.getmtime(BINDS_TEMPLATE_FILENAME)
if not binds_outdated and os.path.exists(binds_filename):
exec(open(binds_filename).read())
self.app.log("Loaded key binds from {}".format(binds_filename))
self.app.log(f"Loaded key binds from {binds_filename}")
else:
default_data = open(BINDS_TEMPLATE_FILENAME).readlines()[1:]
new_binds = open(binds_filename, "w")
new_binds.writelines(default_data)
new_binds.close()
self.app.log("Created new key binds file {}".format(binds_filename))
self.app.log(f"Created new key binds file {binds_filename}")
exec("".join(default_data))
if not self.edit_bind_src:
self.app.log("No bind data found, Is binds.cfg.default present?")
@ -109,9 +109,9 @@ class InputLord:
# bind data could be a single item (string) or a list/tuple
bind_data = self.edit_bind_src[bind_string]
if type(bind_data) is str:
bind_fnames = ["BIND_{}".format(bind_data)]
bind_fnames = [f"BIND_{bind_data}"]
else:
bind_fnames = ["BIND_{}".format(s) for s in bind_data]
bind_fnames = [f"BIND_{s}" for s in bind_data]
bind_functions = []
for bind_fname in bind_fnames:
if not hasattr(self, bind_fname):
@ -123,7 +123,7 @@ class InputLord:
js_init = sdl2.SDL_InitSubSystem(sdl2.SDL_INIT_JOYSTICK)
if js_init != 0:
self.app.log(
"SDL2: Couldn't initialize joystick subsystem, code {}".format(js_init)
f"SDL2: Couldn't initialize joystick subsystem, code {js_init}"
)
return
sticks = sdl2.SDL_NumJoysticks()
@ -137,9 +137,7 @@ class InputLord:
pad_axes = sdl2.SDL_JoystickNumAxes(pad)
pad_buttons = sdl2.SDL_JoystickNumButtons(pad)
self.app.log(
"Gamepad found: {} with {} axes, {} buttons".format(
pad_name, pad_axes, pad_buttons
)
f"Gamepad found: {pad_name} with {pad_axes} axes, {pad_buttons} buttons"
)
self.gamepad = pad
# before main loop begins, set initial mouse position -
@ -205,7 +203,7 @@ class InputLord:
if not hasattr(button, "menu_data"):
continue
for item in button.menu_data.items:
if function.__name__ == "BIND_{}".format(item.command):
if function.__name__ == f"BIND_{item.command}":
items.append(item)
return items
@ -1225,14 +1223,10 @@ class InputLord:
for obj in self.app.gw.selected_objects:
if obj.orig_collision_type and obj.collision_type == CT_NONE:
obj.enable_collision()
self.ui.message_line.post_line(
"Collision enabled for {}".format(obj.name)
)
self.ui.message_line.post_line(f"Collision enabled for {obj.name}")
elif obj.collision_type != CT_NONE:
obj.disable_collision()
self.ui.message_line.post_line(
"Collision disabled for {}".format(obj.name)
)
self.ui.message_line.post_line(f"Collision disabled for {obj.name}")
def BIND_toggle_game_edit_ui(self):
self.ui.toggle_game_edit_ui()

View file

@ -32,12 +32,10 @@ class PaletteLord:
if palette.has_updated():
try:
palette.load_image()
self.app.log(
"PaletteLord: success reloading {}".format(palette.filename)
)
self.app.log(f"PaletteLord: success reloading {palette.filename}")
except Exception:
self.app.log(
"PaletteLord: failed reloading {}".format(palette.filename),
f"PaletteLord: failed reloading {palette.filename}",
True,
)
@ -50,7 +48,7 @@ class Palette:
src_filename, PALETTE_DIR, PALETTE_EXTENSIONS
)
if self.filename is None:
self.app.log("Couldn't find palette image {}".format(src_filename))
self.app.log(f"Couldn't find palette image {src_filename}")
return
self.last_image_change = os.path.getmtime(self.filename)
self.name = os.path.basename(self.filename)
@ -58,12 +56,10 @@ class Palette:
self.load_image()
self.base_filename = os.path.splitext(os.path.basename(self.filename))[0]
if log and not self.app.game_mode:
self.app.log(
"loaded palette '{}' from {}:".format(self.name, self.filename)
)
self.app.log(" unique colors found: {}".format(int(len(self.colors) - 1)))
self.app.log(" darkest color index: {}".format(self.darkest_index))
self.app.log(" lightest color index: {}".format(self.lightest_index))
self.app.log(f"loaded palette '{self.name}' from {self.filename}:")
self.app.log(f" unique colors found: {int(len(self.colors) - 1)}")
self.app.log(f" darkest color index: {self.darkest_index}")
self.app.log(f" lightest color index: {self.lightest_index}")
self.init_success = True
def load_image(self):
@ -222,7 +218,7 @@ class PaletteFromList(Palette):
self.init_success = False
self.app = app
# generate a unique non-user-facing palette name
name = "PaletteFromList_{}".format(time.time())
name = f"PaletteFromList_{time.time()}"
self.filename = self.name = self.base_filename = name
colors = []
for color in src_color_list:
@ -250,10 +246,10 @@ class PaletteFromList(Palette):
x += 1
self.texture = Texture(img.tobytes(), MAX_COLORS, 1)
if log and not self.app.game_mode:
self.app.log("generated new palette '{}'".format(self.name))
self.app.log(" unique colors: {}".format(int(len(self.colors) - 1)))
self.app.log(" darkest color index: {}".format(self.darkest_index))
self.app.log(" lightest color index: {}".format(self.lightest_index))
self.app.log(f"generated new palette '{self.name}'")
self.app.log(f" unique colors: {int(len(self.colors) - 1)}")
self.app.log(f" darkest color index: {self.darkest_index}")
self.app.log(f" lightest color index: {self.lightest_index}")
def has_updated(self):
"No bitmap source for this type of palette, so no hot-reload"
@ -265,7 +261,7 @@ class PaletteFromFile(Palette):
self.init_success = False
src_filename = app.find_filename_path(src_filename)
if not src_filename:
app.log("Couldn't find palette source image {}".format(src_filename))
app.log(f"Couldn't find palette source image {src_filename}")
return
# dither source image, re-save it, use that as the source for a palette
src_img = Image.open(src_filename)
@ -283,9 +279,7 @@ class PaletteFromFile(Palette):
# if new filename exists, add a number to avoid overwriting
if os.path.exists(palette_path + palette_filename + ".png"):
i = 0
while os.path.exists(
"{}{}{}.png".format(palette_path, palette_filename, str(i))
):
while os.path.exists(f"{palette_path}{palette_filename}{str(i)}.png"):
i += 1
palette_filename += str(i)
# (re-)add path and PNG extension

View file

@ -284,7 +284,7 @@ class Application:
gpu_renderer = GL.glGetString(GL.GL_RENDERER).decode("utf-8")
except Exception:
gpu_renderer = "[couldn't detect renderer]"
self.log(" GPU: {} - {}".format(gpu_vendor, gpu_renderer))
self.log(f" GPU: {gpu_vendor} - {gpu_renderer}")
try:
# try single-argument GL2.0 version first
gl_ver = GL.glGetString(GL.GL_VERSION)
@ -293,7 +293,7 @@ class Application:
gl_ver = gl_ver.decode("utf-8")
except Exception:
gl_ver = "[couldn't detect GL version]"
self.log(" OpenGL detected: {}".format(gl_ver))
self.log(f" OpenGL detected: {gl_ver}")
# GL 1.1 doesn't even habla shaders, quit if we fail GLSL version check
try:
glsl_ver = GL.glGetString(GL.GL_SHADING_LANGUAGE_VERSION)
@ -306,7 +306,7 @@ class Application:
self.should_quit = True
return
glsl_ver = glsl_ver.decode("utf-8") if glsl_ver != None else None
self.log(" GLSL detected: {}".format(glsl_ver) or "[unknown]")
self.log(f" GLSL detected: {glsl_ver}" or "[unknown]")
# verify that we got at least a 2.1 context
majorv, minorv = ctypes.c_int(0), ctypes.c_int(0)
video.SDL_GL_GetAttribute(video.SDL_GL_CONTEXT_MAJOR_VERSION, majorv)
@ -343,43 +343,31 @@ class Application:
GL.glGetIntegerv(GL.GL_MAX_TEXTURE_SIZE, mts)
self.max_texture_size = mts.value
self.log(
" Maximum supported texture size: {} x {}".format(
self.max_texture_size, self.max_texture_size
)
f" Maximum supported texture size: {self.max_texture_size} x {self.max_texture_size}"
)
self.log(
" Detected screen resolution: {:.0f} x {:.0f}, window: {} x {}".format(
screen_width, screen_height, self.window_width, self.window_height
)
f" Detected screen resolution: {screen_width:.0f} x {screen_height:.0f}, window: {self.window_width} x {self.window_height}"
)
self.log("Detecting software environment...")
self.log(" OS: {}".format(platform.platform()))
self.log(f" OS: {platform.platform()}")
py_version = " ".join(sys.version.split("\n"))
# report 32 vs 64 bit as it's not clear from sys.version or OS
bitness = platform.architecture()[0]
# on linux, report whether we're running x11 or wayland
if platform.system() == "Linux":
driver = sdl2.SDL_GetCurrentVideoDriver().decode("utf-8")
self.log(' Linux SDL2 "video driver": {}'.format(driver))
self.log(" Python: {} ({})".format(py_version, bitness))
module_versions = "PySDL2 {}, ".format(sdl2.__version__)
module_versions += "numpy {}, ".format(numpy.__version__)
module_versions += "PyOpenGL {}, ".format(OpenGL.__version__)
module_versions += "appdirs {}, ".format(appdirs.__version__)
module_versions += "PIL {}".format(PIL.__version__)
self.log(" Modules: {}".format(module_versions))
sdl_version = "{}.{}.{} ".format(
sdl2.version.SDL_MAJOR_VERSION,
sdl2.version.SDL_MINOR_VERSION,
sdl2.version.SDL_PATCHLEVEL,
)
self.log(f' Linux SDL2 "video driver": {driver}')
self.log(f" Python: {py_version} ({bitness})")
module_versions = f"PySDL2 {sdl2.__version__}, "
module_versions += f"numpy {numpy.__version__}, "
module_versions += f"PyOpenGL {OpenGL.__version__}, "
module_versions += f"appdirs {appdirs.__version__}, "
module_versions += f"PIL {PIL.__version__}"
self.log(f" Modules: {module_versions}")
sdl_version = f"{sdl2.version.SDL_MAJOR_VERSION}.{sdl2.version.SDL_MINOR_VERSION}.{sdl2.version.SDL_PATCHLEVEL} "
sdl_version += sdl2.version.SDL_GetRevision().decode("utf-8")
sdl_version += ", SDLmixer: {}.{}.{}".format(
sdlmixer.SDL_MIXER_MAJOR_VERSION,
sdlmixer.SDL_MIXER_MINOR_VERSION,
sdlmixer.SDL_MIXER_PATCHLEVEL,
)
self.log(" SDL: {}".format(sdl_version))
sdl_version += f", SDLmixer: {sdlmixer.SDL_MIXER_MAJOR_VERSION}.{sdlmixer.SDL_MIXER_MINOR_VERSION}.{sdlmixer.SDL_MIXER_PATCHLEVEL}"
self.log(f" SDL: {sdl_version}")
# draw black screen while doing other init
GL.glClearColor(0.0, 0.0, 0.0, 1.0)
GL.glClear(GL.GL_COLOR_BUFFER_BIT)
@ -566,7 +554,7 @@ class Application:
and "_bootstrap._gcd_import" not in line
):
self.log(line.rstrip())
s = "Error importing module {}! See console.".format(module_name)
s = f"Error importing module {module_name}! See console."
if self.ui:
self.ui.message_line.post_line(s, 10, True)
@ -589,7 +577,7 @@ class Application:
art = None
if not valid_filename:
if autocreate:
self.log("Creating new art {}".format(filename))
self.log(f"Creating new art {filename}")
return self.new_art(filename)
else:
# self.log("Couldn't find art %s" % filename)
@ -641,7 +629,7 @@ class Application:
self.edit_renderables.remove(r)
if art is self.ui.active_art:
self.ui.active_art = None
self.log("Unloaded {}".format(art.filename))
self.log(f"Unloaded {art.filename}")
if len(self.art_loaded_for_edit) > 0:
self.ui.set_active_art(self.art_loaded_for_edit[0])
self.update_window_title()
@ -698,7 +686,7 @@ class Application:
extensions = [extensions]
for dirname in dirnames:
for ext in extensions:
f = "{}{}".format(dirname, filename)
f = f"{dirname}{filename}"
# filename passed in might already have intended extension,
# eg from a directory listing
if ext and ext != "" and not filename.endswith(ext):
@ -727,7 +715,7 @@ class Application:
if basename in self.converter_modules:
m = importlib.reload(self.converter_modules[basename])
else:
m = importlib.import_module("formats.{}".format(basename))
m = importlib.import_module(f"formats.{basename}")
self.converter_modules[basename] = m
except Exception as e:
self.log_import_exception(e, basename)
@ -782,7 +770,7 @@ class Application:
def set_window_title(self, text=None):
# if editing is locked, don't even show Playscii name
new_title = "{} - {}".format(APP_NAME, text) if self.can_edit else str(text)
new_title = f"{APP_NAME} - {text}" if self.can_edit else str(text)
new_title = bytes(new_title, "utf-8")
sdl2.SDL_SetWindowTitle(self.window, new_title)
@ -837,7 +825,7 @@ class Application:
def screenshot(self):
"saves a date + time-stamped screenshot"
timestamp = time.strftime("%Y-%m-%d_%H-%M-%S")
output_filename = "playscii_{}.png".format(timestamp)
output_filename = f"playscii_{timestamp}.png"
w, h = self.window_width, self.window_height
pixels = GL.glReadPixels(
0, 0, w, h, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, outputType=None
@ -845,8 +833,8 @@ class Application:
pixel_bytes = pixels.flatten().tobytes()
img = Image.frombytes(mode="RGBA", size=(w, h), data=pixel_bytes)
img = img.transpose(Image.FLIP_TOP_BOTTOM)
img.save("{}{}".format(self.documents_dir + SCREENSHOT_DIR, output_filename))
self.log("Saved screenshot {}".format(output_filename))
img.save(f"{self.documents_dir + SCREENSHOT_DIR}{output_filename}")
self.log(f"Saved screenshot {output_filename}")
def enter_game_mode(self):
self.game_mode = True
@ -964,17 +952,12 @@ class Application:
def debug_onion_frames(self):
"debug function to log onion renderable state"
# TODO: remove this once it's served its purpose
debug = ["current frame: {}".format(self.ui.active_art.active_frame), ""]
debug = [f"current frame: {self.ui.active_art.active_frame}", ""]
debug.append("onion_renderables_prev:")
def get_onion_info(i, r):
visible = "VISIBLE" if r.visible else ""
return "{}: {} frame {} {}".format(
i,
r.art.filename.ljust(20),
r.frame,
visible,
)
return f"{i}: {r.art.filename.ljust(20)} frame {r.frame} {visible}"
for i, r in enumerate(self.onion_renderables_prev):
debug.append(get_onion_info(i, r))
@ -995,7 +978,7 @@ class Application:
if line.strip():
self.log(line.rstrip())
return
self.log("Using {} as overlay image.".format(image_filename))
self.log(f"Using {image_filename} as overlay image.")
self.overlay_renderable = r
self.ui.size_and_position_overlay_image()
self.draw_overlay = True
@ -1062,7 +1045,7 @@ class Application:
# setting already found, remove this redundant line
self.config_lines.remove(line)
# get current value from top-level scope and write it to end of cfg
self.config_lines += "{} = {}\n".format(setting_name, setting_value)
self.config_lines += f"{setting_name} = {setting_value}\n"
def save_persistent_config(self):
"write options we want to persist across sessions to config file"
@ -1130,7 +1113,7 @@ class Application:
editor_bin = os.environ.get("EDITOR", None)
if not editor_bin:
return
cmd = '{} "{}"'.format(editor_bin, cfg_path)
cmd = f'{editor_bin} "{cfg_path}"'
os.system(cmd)
# update resident cfg file lines, which will be saved out on exit
self.config_lines = open(cfg_path).readlines()
@ -1140,7 +1123,7 @@ class Application:
def open_local_url(self, url):
"opens given local (this file system) URL in a cross-platform way"
webbrowser.open("file://{}/{}".format(os.getcwd(), url))
webbrowser.open(f"file://{os.getcwd()}/{url}")
def open_help_docs(self):
self.open_local_url(WEBSITE_HELP_URL)
@ -1206,7 +1189,7 @@ def get_paths():
if os.path.exists(documents_dir + DOCUMENTS_SUBDIR):
documents_dir += DOCUMENTS_SUBDIR
# add Playscii/ to documents path
documents_dir += "/{}/".format(APP_NAME)
documents_dir += f"/{APP_NAME}/"
# create Playscii dir AND subdirs for user art, charsets etc if not present
for subdir in [
"",
@ -1246,7 +1229,7 @@ class Logger:
self.log_file = open(config_dir + LOG_FILENAME, "w", bufsize)
def log(self, new_line):
self.log_file.write("{}\n".format(new_line))
self.log_file.write(f"{new_line}\n")
self.lines.append(str(new_line))
print(new_line)
@ -1261,7 +1244,7 @@ def get_app():
# start logger even before Application has initialized so we can write to it
# startup message: application and version #
logger = Logger(config_dir)
logger.log("{} v{}".format(APP_NAME, get_version()))
logger.log(f"{APP_NAME} v{get_version()}")
# see if "autoplay this game" file exists and has anything in it
autoplay_game = None
if os.path.exists(AUTOPLAY_GAME_FILENAME):
@ -1271,7 +1254,7 @@ def get_app():
# load in config - may change above values and submodule class defaults
cfg_filename = config_dir + CONFIG_FILENAME
if os.path.exists(cfg_filename):
logger.log("Loading config from {}...".format(cfg_filename))
logger.log(f"Loading config from {cfg_filename}...")
# execute cfg line by line so we can continue past lines with errors.
# this does mean that commenting out blocks with triple-quotes fails,
# but that's not a good practice anyway.
@ -1291,7 +1274,7 @@ def get_app():
if "Error" in el:
error = el
break
logger.log(" Removing line {} with {}".format(i, error))
logger.log(f" Removing line {i} with {error}")
new_cfg = open(cfg_filename, "w")
new_cfg.writelines(new_cfg_lines)
new_cfg.close()
@ -1304,7 +1287,7 @@ def get_app():
new_cfg.writelines(default_data)
new_cfg.close()
exec("".join(default_data))
logger.log("Created new config file {}".format(cfg_filename))
logger.log(f"Created new config file {cfg_filename}")
art_to_load, game_dir_to_load, state_to_load = None, None, None
# usage:
# playscii.py [artfile] | [-game gamedir [-state statefile | artfile]]

View file

@ -97,7 +97,7 @@ class TileRenderable:
if self.app.use_vao:
GL.glBindVertexArray(0)
if self.log_create_destroy:
self.app.log("created: {}".format(self))
self.app.log(f"created: {self}")
def __str__(self):
"for debug purposes, return a concise unique name"
@ -107,7 +107,7 @@ class TileRenderable:
break
else:
i = 0
return "{} {} {}".format(self.art.get_simple_name(), self.__class__.__name__, i)
return f"{self.art.get_simple_name()} {self.__class__.__name__} {i}"
def create_buffers(self):
# vertex positions and elements
@ -232,15 +232,7 @@ class TileRenderable:
):
if self.log_buffer_updates:
self.app.log(
"update_buffer: {}, {}, {}, {}, {}, {}, {}".format(
buffer_index,
array,
target,
buffer_type,
data_type,
attrib_name,
attrib_size,
)
f"update_buffer: {buffer_index}, {array}, {target}, {buffer_type}, {data_type}, {attrib_name}, {attrib_size}"
)
GL.glBindBuffer(target, buffer_index)
GL.glBufferData(target, array.nbytes, array, buffer_type)
@ -269,9 +261,7 @@ class TileRenderable:
self.frame = new_frame_index % self.art.frames
self.update_tile_buffers(True, True, True, True)
if self.log_animation:
self.app.log(
"{} animating from frames {} to {}".format(self, old_frame, self.frame)
)
self.app.log(f"{self} animating from frames {old_frame} to {self.frame}")
def start_animating(self):
"Start animation playback."
@ -322,9 +312,7 @@ class TileRenderable:
self.goal_x, self.goal_y, self.goal_z = x, y, z
if self.log_animation:
self.app.log(
"{} will move to {},{}".format(
self.art.filename, self.goal_x, self.goal_y
)
f"{self.art.filename} will move to {self.goal_x},{self.goal_y}"
)
def snap_to(self, x, y, z):
@ -413,7 +401,7 @@ class TileRenderable:
if self.art and self in self.art.renderables:
self.art.renderables.remove(self)
if self.log_create_destroy:
self.app.log("destroyed: {}".format(self))
self.app.log(f"destroyed: {self}")
def get_projection_matrix(self):
"""

View file

@ -27,7 +27,7 @@ class LineRenderable:
self.app = app
# we may be attached to a game object
self.go = game_object
self.unique_name = "{}_{}".format(int(time.time()), self.__class__.__name__)
self.unique_name = f"{int(time.time())}_{self.__class__.__name__}"
self.quad_size_ref = quad_size_ref
self.x, self.y, self.z = 0, 0, 0
self.scale_x, self.scale_y = 1, 1
@ -94,7 +94,7 @@ class LineRenderable:
if self.app.use_vao:
GL.glBindVertexArray(0)
if self.log_create_destroy:
self.app.log("created: {}".format(self))
self.app.log(f"created: {self}")
def __str__(self):
"for debug purposes, return a unique name"
@ -178,7 +178,7 @@ class LineRenderable:
GL.glDeleteVertexArrays(1, [self.vao])
GL.glDeleteBuffers(3, [self.vert_buffer, self.elem_buffer, self.color_buffer])
if self.log_create_destroy:
self.app.log("destroyed: {}".format(self))
self.app.log(f"destroyed: {self}")
def render(self):
if not self.visible:

View file

@ -23,7 +23,7 @@ class SpriteRenderable:
def __init__(self, app, texture_filename=None, image_data=None):
self.app = app
self.unique_name = "{}_{}".format(int(time.time()), self.__class__.__name__)
self.unique_name = f"{int(time.time())}_{self.__class__.__name__}"
self.x, self.y, self.z = self.get_initial_position()
self.scale_x, self.scale_y, self.scale_z = self.get_initial_scale()
if self.app.use_vao:

View file

@ -65,34 +65,26 @@ class Shader:
self.last_vert_change = time.time()
vert_source = self.get_shader_source(self.vert_source_file)
if self.log_compile:
self.sl.app.log(
"Compiling vertex shader {}...".format(self.vert_source_file)
)
self.sl.app.log(f"Compiling vertex shader {self.vert_source_file}...")
self.vert_shader = self.try_compile_shader(
vert_source, GL.GL_VERTEX_SHADER, self.vert_source_file
)
if self.log_compile and self.vert_shader:
self.sl.app.log(
"Compiled vertex shader {} in {:.6f} seconds".format(
self.vert_source_file, time.time() - self.last_vert_change
)
f"Compiled vertex shader {self.vert_source_file} in {time.time() - self.last_vert_change:.6f} seconds"
)
# fragment shader
self.frag_source_file = frag_source_file
self.last_frag_change = time.time()
frag_source = self.get_shader_source(self.frag_source_file)
if self.log_compile:
self.sl.app.log(
"Compiling fragment shader {}...".format(self.frag_source_file)
)
self.sl.app.log(f"Compiling fragment shader {self.frag_source_file}...")
self.frag_shader = self.try_compile_shader(
frag_source, GL.GL_FRAGMENT_SHADER, self.frag_source_file
)
if self.log_compile and self.frag_shader:
self.sl.app.log(
"Compiled fragment shader {} in {:.6f} seconds".format(
self.frag_source_file, time.time() - self.last_frag_change
)
f"Compiled fragment shader {self.frag_source_file} in {time.time() - self.last_frag_change:.6f} seconds"
)
# shader program
if self.vert_shader and self.frag_shader:
@ -109,7 +101,7 @@ class Shader:
shader_version = self.glsl_version_macos
else:
shader_version = self.glsl_version_unix
version_string = "#version {}\n".format(shader_version)
version_string = f"#version {shader_version}\n"
src = bytes(version_string, "utf-8") + src
return src
@ -118,7 +110,7 @@ class Shader:
try:
shader = shaders.compileShader(source, shader_type)
except Exception as e:
self.sl.app.log("{}: ".format(source_filename))
self.sl.app.log(f"{source_filename}: ")
lines = e.args[0].split("\\n")
# salvage block after "shader compile failure" enclosed in b""
pre = lines.pop(0).split('b"')
@ -148,9 +140,9 @@ class Shader:
try:
new_shader = shaders.compileShader(new_shader_source, shader_type)
# TODO: use try_compile_shader instead here, make sure exception passes thru ok
self.sl.app.log("ShaderLord: success reloading {}".format(file_to_reload))
self.sl.app.log(f"ShaderLord: success reloading {file_to_reload}")
except Exception:
self.sl.app.log("ShaderLord: failed reloading {}".format(file_to_reload))
self.sl.app.log(f"ShaderLord: failed reloading {file_to_reload}")
return
# recompile program with new shader
if shader_type == GL.GL_VERTEX_SHADER:

16
ui.py
View file

@ -120,7 +120,7 @@ class UI:
# create tools
for t in self.tool_classes:
new_tool = t(self)
tool_name = "{}_tool".format(new_tool.name)
tool_name = f"{new_tool.name}_tool"
setattr(self, tool_name, new_tool)
# stick in a list for popup tool tab
self.tools.append(new_tool)
@ -208,9 +208,7 @@ class UI:
self.set_elements_scale()
if self.scale != old_scale:
self.message_line.post_line(
"UI scale is now {} ({:.3f} x {:.3f})".format(
self.scale, self.width_tiles, self.height_tiles
)
f"UI scale is now {self.scale} ({self.width_tiles:.3f} x {self.height_tiles:.3f})"
)
def set_elements_scale(self):
@ -283,7 +281,7 @@ class UI:
self.app.update_window_title()
if self.app.can_edit:
self.message_line.post_line(
"{} {}".format(self.art_selected_log, self.active_art.filename)
f"{self.art_selected_log} {self.active_art.filename}"
)
def set_active_art_by_filename(self, art_filename):
@ -349,9 +347,7 @@ class UI:
if self.menu_bar.active_menu_name and not cycled_fill:
self.menu_bar.close_active_menu()
self.message_line.post_line(
"{} {}".format(
self.selected_tool.get_button_caption(), self.tool_selected_log
)
f"{self.selected_tool.get_button_caption()} {self.tool_selected_log}"
)
def cycle_fill_tool_mode(self):
@ -380,7 +376,7 @@ class UI:
self.selected_xform = new_xform
self.popup.set_xform(new_xform)
self.tool_settings_changed = True
line = "{} {}".format(self.xform_selected_log, uv_names[self.selected_xform])
line = f"{self.xform_selected_log} {uv_names[self.selected_xform]}"
self.message_line.post_line(line)
def cycle_selected_xform(self, back=False):
@ -598,7 +594,7 @@ class UI:
command = EntireArtCommand(art, min_x, min_y)
command.save_tiles(before=True)
art.resize(w, h, min_x, min_y)
self.app.log("Resized {} to {} x {}".format(art.filename, w, h))
self.app.log(f"Resized {art.filename} to {w} x {h}")
art.set_unsaved_changes(True)
# clear selection to avoid having tiles we know are OoB selected
self.select_tool.selected_tiles = {}

View file

@ -74,7 +74,7 @@ class NewArtDialog(BaseFileDialog):
def get_initial_field_text(self, field_number):
if field_number == 0:
return "new{}".format(len(self.ui.app.art_loaded_for_edit))
return f"new{len(self.ui.app.art_loaded_for_edit)}"
elif field_number == 2:
return str(DEFAULT_WIDTH)
elif field_number == 4:
@ -116,7 +116,7 @@ class NewArtDialog(BaseFileDialog):
name = self.field_texts[0]
w, h = int(self.field_texts[2]), int(self.field_texts[4])
self.ui.app.new_art_for_edit(name, w, h)
self.ui.app.log("Created {}.psci with size {} x {}".format(name, w, h))
self.ui.app.log(f"Created {name}.psci with size {w} x {h}")
self.dismiss()
@ -266,7 +266,7 @@ class ImportOptionsDialog(UIDialog):
importer = app.importer(app, filename, options)
if importer.success:
if app.importer.completes_instantly:
app.log("Imported {} successfully.".format(filename))
app.log(f"Imported {filename} successfully.")
app.importer = None
@ -280,7 +280,7 @@ class ExportOptionsDialog(UIDialog):
# if importer needs no options, run it
exporter = app.exporter(app, filename, options)
if exporter.success:
app.log("Exported {} successfully.".format(exporter.out_filename))
app.log(f"Exported {exporter.out_filename} successfully.")
class ExportFileDialog(ConvertFileDialog):
@ -606,7 +606,7 @@ class AddLayerDialog(UIDialog):
def get_initial_field_text(self, field_number):
if field_number == 0:
return "Layer {}".format(str(self.ui.active_art.layers + 1))
return f"Layer {str(self.ui.active_art.layers + 1)}"
elif field_number == 1:
return str(
self.ui.active_art.layers_z[self.ui.active_art.active_layer]
@ -761,7 +761,7 @@ class SetCameraZoomDialog(UIDialog):
def get_initial_field_text(self, field_number):
if field_number == 0:
return "{:.1f}".format(self.ui.app.camera.get_current_zoom_pct())
return f"{self.ui.app.camera.get_current_zoom_pct():.1f}"
return ""
def is_input_valid(self):

View file

@ -52,17 +52,13 @@ class UIButton:
"common code for button event logging"
if self.element.ui.logg:
self.element.ui.app.log(
"UIButton: {}'s {} {}".format(
self.element.__class__.__name__, self.__class__.__name__, event_type
)
f"UIButton: {self.element.__class__.__name__}'s {self.__class__.__name__} {event_type}"
)
def set_state(self, new_state):
if new_state not in BUTTON_STATES:
self.element.ui.app.log(
"Unrecognized state for button {}: {}".format(
self.__class__.__name__, new_state
)
f"Unrecognized state for button {self.__class__.__name__}: {new_state}"
)
return
self.dimmed = new_state == "dimmed"
@ -70,8 +66,8 @@ class UIButton:
self.set_state_colors()
def get_state_colors(self, state):
fg = getattr(self, "{}_fg_color".format(state))
bg = getattr(self, "{}_bg_color".format(state))
fg = getattr(self, f"{state}_fg_color")
bg = getattr(self, f"{state}_bg_color")
return fg, bg
def set_state_colors(self):

View file

@ -178,7 +178,7 @@ class ChooserDialog(UIDialog):
try:
os.listdir(new_dir)
except PermissionError:
line = "No permission to access {}!".format(os.path.abspath(new_dir))
line = f"No permission to access {os.path.abspath(new_dir)}!"
self.ui.message_line.post_line(line, error=True)
return False
self.current_dir = new_dir

View file

@ -138,11 +138,9 @@ class ImportCommand(ConsoleCommand):
if c.__name__ == importer_classname:
importer_class = c
if not importer_class:
console.ui.app.log(
"Couldn't find importer class {}".format(importer_classname)
)
console.ui.app.log(f"Couldn't find importer class {importer_classname}")
if not os.path.exists(filename):
console.ui.app.log("Couldn't find file {}".format(filename))
console.ui.app.log(f"Couldn't find file {filename}")
importer_class(console.ui.app, filename)
@ -159,9 +157,7 @@ class ExportCommand(ConsoleCommand):
if c.__name__ == exporter_classname:
exporter_class = c
if not exporter_class:
console.ui.app.log(
"Couldn't find exporter class {}".format(exporter_classname)
)
console.ui.app.log(f"Couldn't find exporter class {exporter_classname}")
exporter_class(console.ui.app, filename)
@ -231,7 +227,7 @@ class CommandListCommand(ConsoleCommand):
command_list.sort()
for command in command_list:
desc = commands[command].description
console.ui.app.log(" {} - {}".format(command, desc))
console.ui.app.log(f" {command} - {desc}")
class RunArtScriptCommand(ConsoleCommand):
@ -421,7 +417,7 @@ class ConsoleUI(UIElement):
"draw current user input on second to last line, with >_ prompt"
# clear entire user line first
self.art.write_string(0, 0, 0, -2, " " * self.width, self.text_color)
self.art.write_string(0, 0, 0, -2, "{} ".format(self.prompt), self.text_color)
self.art.write_string(0, 0, 0, -2, f"{self.prompt} ", self.text_color)
# if first item of line is a valid command, change its color
items = self.current_line.split()
if len(items) > 0 and items[0] in commands:
@ -491,7 +487,7 @@ class ConsoleUI(UIElement):
self.toggle()
return
elif keystr == "Return":
line = "{} {}".format(self.prompt, self.current_line)
line = f"{self.prompt} {self.current_line}"
self.ui.app.log(line)
# if command is same as last, don't repeat it
if len(self.command_history) == 0 or (
@ -583,7 +579,7 @@ class ConsoleUI(UIElement):
output = str(eval(line))
except Exception as e:
# try to output useful error text
output = "{}: {}".format(e.__class__.__name__, str(e))
output = f"{e.__class__.__name__}: {str(e)}"
# commands CAN return None, so only log if there's something
if output and output != "None":
self.ui.app.log(output)

View file

@ -296,10 +296,7 @@ class EditListPanel(GamePanel):
self.list_scroll_index = min(self.list_scroll_index, len(self.items))
def get_label(self):
label = "{} ({})".format(
self.list_operation_labels[self.list_operation],
self.cancel_tip,
)
label = f"{self.list_operation_labels[self.list_operation]} ({self.cancel_tip})"
# some labels contain variables
if "%s" in label:
if self.list_operation == LO_SET_ROOM_OBJECTS:
@ -475,7 +472,7 @@ class EditListPanel(GamePanel):
items = self.list_rooms()
# prefix room names with "ROOM:"
for item in items:
item.name = "ROOM: {}".format(item.name)
item.name = f"ROOM: {item.name}"
items += self.list_objects()
return items

View file

@ -37,7 +37,7 @@ class UIElement:
self.ui = ui
self.hovered_buttons = []
# generate a unique name
art_name = "{}_{}".format(int(time.time()), self.__class__.__name__)
art_name = f"{int(time.time())}_{self.__class__.__name__}"
self.art = UIArt(
art_name,
self.ui.app,
@ -135,9 +135,7 @@ class UIElement:
mouse_button = mouse_button or "[n/a]"
if self.ui.logg:
self.ui.app.log(
"UIElement: {} {} with mouse button {}".format(
self.__class__.__name__, event_type, mouse_button
)
f"UIElement: {self.__class__.__name__} {event_type} with mouse button {mouse_button}"
)
def is_visible(self):
@ -302,11 +300,11 @@ class FPSCounterUI(UIElement):
color = self.ui.colors.yellow
if self.ui.app.fps < 10:
color = self.ui.colors.red
text = "{:.1f} fps".format(self.ui.app.fps)
text = f"{self.ui.app.fps:.1f} fps"
x = self.tile_width - 1
self.art.write_string(0, 0, x, 0, text, color, None, True)
# display last tick time; frame_time includes delay, is useless
text = "{:.1f} ms ".format(self.ui.app.frame_time)
text = f"{self.ui.app.frame_time:.1f} ms "
self.art.write_string(0, 0, x, 1, text, color, None, True)
def render(self):

View file

@ -144,15 +144,15 @@ class ArtChooserItem(BaseFileChooserItem):
return []
mod_time = time.gmtime(self.art_mod_time)
mod_time = time.strftime("%Y-%m-%d %H:%M:%S", mod_time)
lines = ["last change: {}".format(mod_time)]
line = "{} x {}, ".format(self.art_width, self.art_height)
line += "{} frame".format(self.art_frames)
lines = [f"last change: {mod_time}"]
line = f"{self.art_width} x {self.art_height}, "
line += f"{self.art_frames} frame"
# pluralize properly
line += "s" if self.art_frames > 1 else ""
line += ", {} layer".format(self.art_layers)
line += f", {self.art_layers} layer"
line += "s" if self.art_layers > 1 else ""
lines += [line]
lines += ["char: {}, pal: {}".format(self.art_charset, self.art_palette)]
lines += [f"char: {self.art_charset}, pal: {self.art_palette}"]
return lines
def get_preview_texture(self, app):
@ -312,7 +312,7 @@ class PaletteChooserItem(BaseFileChooserItem):
def get_description_lines(self):
colors = len(self.palette.colors)
return ["Unique colors: {}".format(str(colors - 1))]
return [f"Unique colors: {str(colors - 1)}"]
def get_preview_texture(self, app):
return self.palette.src_texture
@ -370,7 +370,7 @@ class CharsetChooserItem(BaseFileChooserItem):
if line.startswith("//"):
lines.append(line[2:])
break
lines.append("Characters: {}".format(str(self.charset.last_index)))
lines.append(f"Characters: {str(self.charset.last_index)}")
return lines
def get_preview_texture(self, app):

View file

@ -443,7 +443,7 @@ class GameRoomMenuData(PulldownMenuData):
item = TempMenuItemClass
# leave spaces for mark
item.label = " {}".format(room_name)
item.label = f" {room_name}"
# pad, put Z depth on far right
item.label = item.label.ljust(longest_line)
# trim to keep below a max length

View file

@ -131,5 +131,5 @@ class AboutDialog(PagedInfoDialog):
all_modes_visible = True
def __init__(self, ui, options):
self.title += " {}".format(ui.app.version)
self.title += f" {ui.app.version}"
PagedInfoDialog.__init__(self, ui, options)

View file

@ -217,7 +217,7 @@ class MenuBar(UIElement):
button.width = len(button.caption) + 2
button.x = x
x += button.width + self.button_padding
setattr(self, "{}_button".format(button.name), button)
setattr(self, f"{button.name}_button", button)
# NOTE: callback already defined in MenuButton class,
# menu data for pulldown with set in MenuButton subclass
button.pulldown = self.ui.pulldown

View file

@ -173,7 +173,7 @@ class PulldownMenu(UIElement):
for bind_tuple in binds:
command_functions = binds[bind_tuple]
for f in command_functions:
if f.__name__ == "BIND_{}".format(menu_item.command):
if f.__name__ == f"BIND_{menu_item.command}":
shortcut = ""
# shift, alt, ctrl
if bind_tuple[1]:
@ -187,5 +187,5 @@ class PulldownMenu(UIElement):
if not (bind_tuple[0].startswith("_") and len(bind_tuple[0]) > 1):
shortcut += bind_tuple[0]
return shortcut, f
self.ui.app.log("Shortcut/command not found: {}".format(menu_item.command))
self.ui.app.log(f"Shortcut/command not found: {menu_item.command}")
return "", null

View file

@ -249,42 +249,42 @@ class ToolToggleArtToolbar(ArtModePulldownMenuItem):
class ToolPaintItem(ArtModePulldownMenuItem):
# two spaces in front of each label to leave room for mark
label = " {}".format(PencilTool.button_caption)
label = f" {PencilTool.button_caption}"
command = "select_pencil_tool"
class ToolEraseItem(ArtModePulldownMenuItem):
label = " {}".format(EraseTool.button_caption)
label = f" {EraseTool.button_caption}"
command = "select_erase_tool"
class ToolRotateItem(ArtModePulldownMenuItem):
label = " {}".format(RotateTool.button_caption)
label = f" {RotateTool.button_caption}"
command = "select_rotate_tool"
class ToolGrabItem(ArtModePulldownMenuItem):
label = " {}".format(GrabTool.button_caption)
label = f" {GrabTool.button_caption}"
command = "select_grab_tool"
class ToolTextItem(ArtModePulldownMenuItem):
label = " {}".format(TextTool.button_caption)
label = f" {TextTool.button_caption}"
command = "select_text_tool"
class ToolSelectItem(ArtModePulldownMenuItem):
label = " {}".format(SelectTool.button_caption)
label = f" {SelectTool.button_caption}"
command = "select_select_tool"
class ToolPasteItem(ArtModePulldownMenuItem):
label = " {}".format(PasteTool.button_caption)
label = f" {PasteTool.button_caption}"
command = "select_paste_tool"
class ToolFillItem(ArtModePulldownMenuItem):
label = " {}".format(FillTool.button_caption)
label = f" {FillTool.button_caption}"
command = "select_fill_tool"
@ -301,7 +301,7 @@ class ToolIncreaseBrushSizeItem(ArtModePulldownMenuItem):
if not app.ui.selected_tool.brush_size:
return "Increase brush size"
size = app.ui.selected_tool.brush_size + 1
return "Increase brush size to {}".format(size)
return f"Increase brush size to {size}"
class ToolDecreaseBrushSizeItem(ArtModePulldownMenuItem):
@ -317,7 +317,7 @@ class ToolDecreaseBrushSizeItem(ArtModePulldownMenuItem):
if not app.ui.selected_tool.brush_size:
return "Decrease brush size"
size = app.ui.selected_tool.brush_size - 1
return "Decrease brush size to {}".format(size)
return f"Decrease brush size to {size}"
class ToolSettingsItem(ArtModePulldownMenuItem):
@ -368,9 +368,7 @@ class ToolSetFillBoundariesItem(ArtModePulldownMenuItem):
return type(app.ui.selected_tool) is not FillTool
def get_label(app):
return "Fill tool bounded by: {}".format(
app.ui.fill_tool.boundary_mode_names[app.ui.fill_tool.boundary_mode]
)
return f"Fill tool bounded by: {app.ui.fill_tool.boundary_mode_names[app.ui.fill_tool.boundary_mode]}"
#
@ -600,7 +598,7 @@ class FrameCycleOnionFramesItem(ArtModePulldownMenuItem):
return not app.ui.active_art or app.ui.active_art.frames < 2
def get_label(app):
return "Number of onion frames: {}".format(app.onion_show_frames)
return f"Number of onion frames: {app.onion_show_frames}"
class FrameCycleOnionDisplayItem(ArtModePulldownMenuItem):
@ -617,7 +615,7 @@ class FrameCycleOnionDisplayItem(ArtModePulldownMenuItem):
display = "Previous"
else:
display = "Next"
return "Onion frames show: {}".format(display)
return f"Onion frames show: {display}"
class FrameAddFrameItem(ArtModePulldownMenuItem):
@ -872,7 +870,7 @@ class ToolMenuData(PulldownMenuData):
# if it's a tool setting toggle, use its own mark check function
if item.__bases__[0] is ToolSettingsItem or hasattr(item, "should_mark"):
return item.should_mark(ui)
return item.label == " {}".format(ui.selected_tool.button_caption)
return item.label == f" {ui.selected_tool.button_caption}"
class ViewMenuData(PulldownMenuData):
@ -933,7 +931,7 @@ class ArtMenuData(PulldownMenuData):
item = TempMenuItemClass
# leave spaces for mark
item.label = " {}".format(art.filename)
item.label = f" {art.filename}"
item.command = "art_switch_to"
item.cb_arg = art.filename
# order list by art's time loaded
@ -1008,7 +1006,7 @@ class LayerMenuData(PulldownMenuData):
item = TempMenuItemClass
# leave spaces for mark
item.label = " {}".format(layer_name)
item.label = f" {layer_name}"
if not app.ui.active_art.layers_visibility[i]:
item.label += " (hidden)"
# pad, put Z depth on far right
@ -1016,7 +1014,7 @@ class LayerMenuData(PulldownMenuData):
# trim to keep below a max length
item.label = item.label[:longest_line]
# spaces between layer name and z depth
item.label += "z:{:.2f}".format(app.ui.active_art.layers_z[i])
item.label += f"z:{app.ui.active_art.layers_z[i]:.2f}"
# tell PulldownMenu's button creation process not to auto-pad
item.no_pad = True
item.command = "layer_switch_to"

View file

@ -64,7 +64,7 @@ class PropertyItem:
def set_value(self, value):
# convert value to a button-friendly string
if type(value) is float:
valstr = "{:.3f}".format(value)
valstr = f"{value:.3f}"
# non-fixed decimal version may be shorter, if so use it
if len(str(value)) < len(valstr):
valstr = str(value)
@ -178,7 +178,7 @@ class EditObjectPanel(GamePanel):
elif selected == 1 and self.world.selected_objects[0]:
return self.world.selected_objects[0].name
else:
return "[{} selected]".format(selected)
return f"[{selected} selected]"
def refresh_items(self):
if len(self.world.selected_objects) == 0:
@ -222,14 +222,14 @@ class EditObjectPanel(GamePanel):
button.can_hover = False
return
# set button caption, width, x based on value
button.caption = "{} ".format(item.prop_value)
button.caption = f"{item.prop_value} "
button.width = len(button.caption) + 1
button.x = self.tile_width - button.width
button.cb_arg = item
button.can_hover = True
# set non-button text to the left correctly
x = button.x + 1
label = "{}: ".format(item.prop_name)
label = f"{item.prop_name}: "
self.art.write_string(0, 0, x, y, label, UIColors.darkgrey, None, True)
def update(self):

View file

@ -261,10 +261,10 @@ class ToolPopup(UIElement):
for tool in self.ui.tools:
tool_button = ToolButton(self)
# caption: 1-space padding from left
tool_button.caption = " {}".format(tool.button_caption)
tool_button_name = "{}_tool_button".format(tool.name)
tool_button.caption = f" {tool.button_caption}"
tool_button_name = f"{tool.name}_tool_button"
setattr(self, tool_button_name, tool_button)
cb_name = "{}_pressed".format(tool_button_name)
cb_name = f"{tool_button_name}_pressed"
tool_button.callback = getattr(self, cb_name)
# set a special property UI can refer to
tool_button.tool_name = tool.name
@ -280,9 +280,9 @@ class ToolPopup(UIElement):
buttons = []
for button_class in button_dict:
button = button_class(self)
button_name = "{}_button".format(button_dict[button_class])
button_name = f"{button_dict[button_class]}_button"
setattr(self, button_name, button)
cb_name = "{}_pressed".format(button_name)
cb_name = f"{button_name}_pressed"
button.callback = getattr(self, cb_name)
buttons.append(button)
return buttons
@ -439,13 +439,12 @@ class ToolPopup(UIElement):
# position & caption charset button
y = self.tab_height + 1
self.choose_charset_button.y = y
self.choose_charset_button.caption = " {} {} ".format(
CharSetChooserButton.caption,
charset.name,
self.choose_charset_button.caption = (
f" {CharSetChooserButton.caption} {charset.name} "
)
self.choose_charset_button.width = len(self.choose_charset_button.caption)
# charset scale
charset_scale = "{:.2f}x".format(self.charset_swatch.char_scale)
charset_scale = f"{self.charset_swatch.char_scale:.2f}x"
x = -self.scale_charset_up_button.width * 2
self.art.write_string(0, 0, x, y, charset_scale, None, None, True)
# transform labels and buttons, eg
@ -460,9 +459,8 @@ class ToolPopup(UIElement):
pal_caption_y = (cqh * charset.map_height) / self.art.quad_height
pal_caption_y += self.tab_height + 5
self.choose_palette_button.y = int(pal_caption_y)
self.choose_palette_button.caption = " {} {} ".format(
PaletteChooserButton.caption,
palette.name,
self.choose_palette_button.caption = (
f" {PaletteChooserButton.caption} {palette.name} "
)
self.choose_palette_button.width = len(self.choose_palette_button.caption)
# set button states so captions draw properly
@ -495,10 +493,7 @@ class ToolPopup(UIElement):
# draw current tool settings
x = TOOL_PANE_WIDTH + 1
y = self.tab_height + 1
label = "{} {}".format(
self.ui.selected_tool.button_caption,
self.tool_settings_label,
)
label = f"{self.ui.selected_tool.button_caption} {self.tool_settings_label}"
self.art.write_string(0, 0, x, y, label)
x += 1
y += 2
@ -510,7 +505,7 @@ class ToolPopup(UIElement):
# calculate X of + and - buttons based on size string
self.brush_size_down_button.x = TOOL_PANE_WIDTH + len(label) + 2
label += " " * (self.brush_size_down_button.width + 1)
label += "{}".format(self.ui.selected_tool.brush_size)
label += f"{self.ui.selected_tool.brush_size}"
self.brush_size_up_button.x = TOOL_PANE_WIDTH + len(label) + 3
self.art.write_string(0, 0, x, y, label)
else:
@ -546,7 +541,7 @@ class ToolPopup(UIElement):
(self.affects_xform_label, self.ui.selected_tool.affects_xform)
]
for label, toggle in label_toggle_pairs:
self.art.write_string(0, 0, x + w + 1, y, "{}".format(label))
self.art.write_string(0, 0, x + w + 1, y, f"{label}")
# self.art.set_tile_at(0, 0, x, y, get_affects_char(toggle), 4, 2)
self.art.set_char_index_at(0, 0, x + 1, y, get_affects_char(toggle))
y += 1

View file

@ -29,7 +29,7 @@ class CharToggleButton(StatusBarToggleButton):
tooltip_on_hover = True
def get_tooltip_text(self):
return "character index: {}".format(self.element.ui.selected_char)
return f"character index: {self.element.ui.selected_char}"
def get_tooltip_location(self):
return 1, self.element.get_tile_y() - 1
@ -54,7 +54,7 @@ class FGToggleButton(StatusBarToggleButton):
tooltip_on_hover = True
def get_tooltip_text(self):
return "foreground color index: {}".format(self.element.ui.selected_fg_color)
return f"foreground color index: {self.element.ui.selected_fg_color}"
def get_tooltip_location(self):
return 8, self.element.get_tile_y() - 1
@ -78,7 +78,7 @@ class BGToggleButton(StatusBarToggleButton):
tooltip_on_hover = True
def get_tooltip_text(self):
return "background color index: {}".format(self.element.ui.selected_bg_color)
return f"background color index: {self.element.ui.selected_bg_color}"
def get_tooltip_location(self):
return 15, self.element.get_tile_y() - 1
@ -188,7 +188,7 @@ class StatusBarUI(UIElement):
art = ui.active_art
self.ui = ui
# create 3 custom Arts w/ source charset and palette, renderables for each
art_name = "{}_{}".format(int(time.time()), self.__class__.__name__)
art_name = f"{int(time.time())}_{self.__class__.__name__}"
self.char_art = UIArt(
art_name, ui.app, art.charset, art.palette, self.swatch_width, 1
)
@ -225,7 +225,7 @@ class StatusBarUI(UIElement):
for button_class, button_name in self.button_names.items():
button = button_class(self)
setattr(self, button_name + "_button", button)
cb_name = "{}_button_pressed".format(button_name)
cb_name = f"{button_name}_button_pressed"
button.callback = getattr(self, cb_name)
self.buttons.append(button)
# keep a mapping of button names to buttons, for eg tooltip updates
@ -436,17 +436,15 @@ class StatusBarUI(UIElement):
# NOTE: button X offsets will be set in write_right_elements
null = "---"
layers = art.layers if art else 0
layer = "{}/{}".format(art.active_layer + 1, layers) if art else null
layer = f"{art.active_layer + 1}/{layers}" if art else null
self.layer_cycle_button.caption = layer
self.layer_cycle_button.width = len(self.layer_cycle_button.caption)
frames = art.frames if art else 0
frame = "{}/{}".format(art.active_frame + 1, frames) if art else null
frame = f"{art.active_frame + 1}/{frames}" if art else null
self.frame_cycle_button.caption = frame
self.frame_cycle_button.width = len(self.frame_cycle_button.caption)
# zoom %
zoom = (
"{:.1f}".format(self.ui.app.camera.get_current_zoom_pct()) if art else null
)
zoom = f"{self.ui.app.camera.get_current_zoom_pct():.1f}" if art else null
self.zoom_set_button.caption = zoom[:5] # maintain size
def update(self):
@ -514,7 +512,7 @@ class StatusBarUI(UIElement):
color = self.dim_color
tile_x = str(tile_x).rjust(3)
tile_y = str(tile_y).rjust(3)
tile = "{},{}".format(tile_x, tile_y)
tile = f"{tile_x},{tile_y}"
self.art.write_string(0, 0, x, 0, tile, color, dark, True)
# tile label
x -= len(tile)

View file

@ -20,7 +20,7 @@ class UISwatch(UIElement):
self.tile_width, self.tile_height = self.get_size()
art = self.ui.active_art
# generate a unique name for debug purposes
art_name = "{}_{}".format(int(time.time()), self.__class__.__name__)
art_name = f"{int(time.time())}_{self.__class__.__name__}"
self.art = UIArt(
art_name,
self.ui.app,
@ -405,7 +405,7 @@ class PaletteSwatch(UISwatch):
class ColorSelectionLabelArt(UIArt):
def __init__(self, ui, letter):
letter_index = ui.charset.get_char_index(letter)
art_name = "{}_{}".format(int(time.time()), self.__class__.__name__)
art_name = f"{int(time.time())}_{self.__class__.__name__}"
UIArt.__init__(self, art_name, ui.app, ui.charset, ui.palette, 1, 1)
label_color = ui.colors.white
label_bg_color = 0

View file

@ -586,7 +586,4 @@ class FillTool(UITool):
]
def get_button_caption(self):
return "{} ({} bounded)".format(
self.button_caption,
self.boundary_mode_names[self.boundary_mode],
)
return f"{self.button_caption} ({self.boundary_mode_names[self.boundary_mode]} bounded)"

View file

@ -11,7 +11,7 @@ class Vec3:
self.x, self.y, self.z = x, y, z
def __str__(self):
return "Vec3 {:.4f}, {:.4f}, {:.4f}".format(self.x, self.y, self.z)
return f"Vec3 {self.x:.4f}, {self.y:.4f}, {self.z:.4f}"
def __sub__(self, b):
"Return a new vector subtracted from given other vector."