Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ nml/__version__.py
nml.egg-info/*
nml_lz77*
regression/*output*/*
.python-version
36 changes: 14 additions & 22 deletions nml/actions/action0.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ def print_stats():
for feature in used_ids:
used = feature.get_num_allocated()
if used > 0 and feature.dynamic_allocation:
generic.print_info("{} items: {}/{}".format(feature.name, used, feature.get_max_allocated()))
generic.print_info(f"{feature.name} items: {used}/{feature.get_max_allocated()}")


def mark_id_used(feature, id, num_ids):
Expand Down Expand Up @@ -263,8 +263,7 @@ def check_id_range(feature, id, num_ids, pos):

# Check that IDs are valid and in range.
if not blk_alloc.in_range(id, num_ids):
msg = "Item ID must be in range 0..{:d}, encountered {:d}..{:d}."
msg = msg.format(blk_alloc.last, id, id + num_ids - 1)
msg = f"Item ID must be in range 0..{blk_alloc.last}, encountered {id}..{id + num_ids - 1}."
raise generic.ScriptError(msg, pos)

# ID already defined, but with the same size: OK
Expand All @@ -279,18 +278,15 @@ def check_id_range(feature, id, num_ids, pos):

if blk_alloc.get_size(id) is not None:
# ID already defined with a different size: error.
raise generic.ScriptError(
"Item with ID {:d} has already been defined, but with a different size.".format(id), pos
)
raise generic.ScriptError(f"Item with ID {id} has already been defined, but with a different size.", pos)

if blk_alloc.is_address_free(id):
# First item id free -> any of the additional tile ids must be blocked.
msg = "This multi-tile house requires that item IDs {:d}..{:d} are free, but they are not."
msg = msg.format(id, id + num_ids - 1)
msg = f"This multi-tile house requires that item IDs {id}..{id + num_ids - 1} are free, but they are not."
raise generic.ScriptError(msg, pos)

# ID already defined as part of a multi-tile house.
raise generic.ScriptError("Item ID {:d} has already used as part of a multi-tile house.".format(id), pos)
raise generic.ScriptError(f"Item ID {id} has already used as part of a multi-tile house.", pos)


def get_free_id(feature, num_ids, pos):
Expand All @@ -310,8 +306,7 @@ def get_free_id(feature, num_ids, pos):

addr = blk_alloc.find_unused(num_ids)
if addr is None:
msg = "Unable to allocate ID for item, no more free IDs available (maximum is {:d})"
msg = msg.format(blk_alloc.last)
msg = f"Unable to allocate ID for item, no more free IDs available (maximum is {blk_alloc.last})"
raise generic.ScriptError(msg, pos)

blk_alloc.mark_used(addr, num_ids)
Expand Down Expand Up @@ -449,9 +444,8 @@ def get_property_info_list(feature, name):
assert feature in range(0, len(properties)) # guaranteed by item
if properties[feature] is None:
raise generic.ScriptError(
"Setting properties for feature '{}' is not possible, no properties are defined.".format(
general.feature_name(feature)
),
f"Setting properties for feature '{general.feature_name(feature)}' is not possible,"
" no properties are defined.",
name.pos,
)

Expand Down Expand Up @@ -615,13 +609,11 @@ def apply_threshold(value):
# This can be used to set a label (=string of length 4) to the value of a parameter.
if not isinstance(value, expression.StringLiteral):
raise generic.ScriptError(
"Value for property {:d} must be a string literal".format(prop_info["num"]), value.pos
f"Value for property {prop_info['num']} must be a string literal", value.pos
)
if grfstrings.get_string_size(value.value, False, True) != prop_info["string_literal"]:
raise generic.ScriptError(
"Value for property {:d} must be of length {:d}".format(
prop_info["num"], prop_info["string_literal"]
),
f"Value for property {prop_info['num']} must be of length {prop_info['string_literal']}",
value.pos,
)

Expand All @@ -635,7 +627,7 @@ def apply_threshold(value):
elif isinstance(value, expression.String):
if "string" not in prop_info:
raise generic.ScriptError(
"String used as value for non-string property: " + str(prop_info["num"]), value.pos
f"String used as value for non-string property: {prop_info['num']}", value.pos
)
string_range = apply_threshold(prop_info["string"])
stringid, string_actions = action4.get_string_action4s(feature, string_range, value, id)
Expand Down Expand Up @@ -683,14 +675,14 @@ def validate_prop_info_list(prop_info_list, pos_list, feature):
if info in prop_info:
generic.print_warning(
generic.Warning.GENERIC,
"Property '{}' should be set before all other properties and graphics.".format(prop_name),
f"Property '{prop_name}' should be set before all other properties and graphics.",
pos,
)
break
for info in prop_info:
if "required" in info and info not in prop_info_list:
generic.print_error(
"Property '{}' is not set. Item will be invalid.".format(prop_name),
f"Property '{prop_name}' is not set. Item will be invalid.",
pos_list[-1],
)

Expand Down Expand Up @@ -1027,7 +1019,7 @@ def get_disable_actions(disable):
"""
feature = disable.feature.value
if feature not in disable_info:
raise generic.ScriptError("disable_item() is not available for feature {:d}.".format(feature), disable.pos)
raise generic.ScriptError(f"disable_item() is not available for feature {feature}.", disable.pos)
if disable.first_id is None:
# No ids set -> disable all
assert disable.last_id is None
Expand Down
26 changes: 11 additions & 15 deletions nml/actions/action0properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import itertools

from nml import generic, nmlop, global_constants
from nml import generic, global_constants, nmlop
from nml.expression import (
AcceptCargo,
Array,
Expand Down Expand Up @@ -43,7 +43,7 @@ def write(self, file):
@param file: The outputfile we have to write to.
@type file: L{SpriteOutputBase}
"""
raise NotImplementedError("write is not implemented in {!r}".format(type(self)))
raise NotImplementedError(f"write is not implemented in {type(self)!r}")

def get_size(self):
"""
Expand All @@ -53,7 +53,7 @@ def get_size(self):
@return: The size of this property in bytes.
@rtype: C{int}
"""
raise NotImplementedError("get_size is not implemented in {!r}".format(type(self)))
raise NotImplementedError(f"get_size is not implemented in {type(self)!r}")


class Action0Property(BaseAction0Property):
Expand Down Expand Up @@ -261,9 +261,7 @@ def cargo_list(value, max_num_cargos):
@type prop_size: C{int}
"""
if not isinstance(value, Array) or len(value.values) > max_num_cargos:
raise generic.ScriptError(
"Cargo list must be an array with no more than {:d} values".format(max_num_cargos), value.pos
)
raise generic.ScriptError(f"Cargo list must be an array with no more than {max_num_cargos} values", value.pos)
cargoes = value.values + [ConstantNumeric(0xFF, value.pos) for _ in range(max_num_cargos - len(value.values))]

ret = None
Expand Down Expand Up @@ -419,7 +417,7 @@ def single_or_list(prop_name, single_num, multiple_num, value):
if len(value.values) == 1:
return [Action0Property(single_num, value.values[0].reduce_constant(), 1)]
return [VariableByteListProp(multiple_num, [[type.reduce_constant().value for type in value.values]])]
raise generic.ScriptError("'{}' must be a constant or an array of constants".format(prop_name))
raise generic.ScriptError(f"'{prop_name}' must be a constant or an array of constants")


#
Expand Down Expand Up @@ -785,10 +783,8 @@ def station_layouts(value):
length = len(layout.values[0].values)
number = len(layout.values)
if (length, number) in layouts:
generic.print_warning(
generic.Warning.GENERIC, "Redefinition of layout {}x{}".format(length, number), layout.pos
)
layouts[(length, number)] = []
generic.print_warning(generic.Warning.GENERIC, f"Redefinition of layout {length}x{number}", layout.pos)
layouts[length, number] = []
for platform in layout.values:
if not isinstance(platform, Array) or len(platform.values) == 0:
raise generic.ScriptError("A platform must be an array of tile types")
Expand All @@ -798,10 +794,10 @@ def station_layouts(value):
if type.reduce_constant().value % 2 != 0:
generic.print_warning(
generic.Warning.GENERIC,
"Invalid tile {} in layout {}x{}".format(type, length, number),
f"Invalid tile {type} in layout {length}x{number}",
type.pos,
)
layouts[(length, number)].append(
layouts[length, number].append(
[nmlop.AND(type, 0xFE).reduce_constant().value for type in platform.values]
)
return [StationLayoutProp(0x0E, layouts)]
Expand Down Expand Up @@ -1127,7 +1123,7 @@ def industry_layouts(value):
layouts = []
for name in value.values:
if name.value not in tilelayout_names:
raise generic.ScriptError("Unknown layout name '{}'".format(name.value), name.pos)
raise generic.ScriptError(f"Unknown layout name '{name.value}'", name.pos)
layouts.append(tilelayout_names[name.value])
return [IndustryLayoutProp(layouts)]

Expand Down Expand Up @@ -1443,7 +1439,7 @@ def airport_layouts(value):
layouts = []
for name in value.values:
if name.value not in tilelayout_names:
raise generic.ScriptError("Unknown layout name '{}'".format(name.value), name.pos)
raise generic.ScriptError(f"Unknown layout name '{name.value}'", name.pos)
layout = tilelayout_names[name.value]
if "rotation" not in layout.properties:
raise generic.ScriptError("Airport layouts must have the 'rotation' property", layout.pos)
Expand Down
9 changes: 6 additions & 3 deletions nml/actions/action1.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
with NML; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA."""

from nml.actions import base_action, real_sprite, action2
from nml.actions import action2, base_action, real_sprite


class Action1(base_action.BaseAction):
Expand Down Expand Up @@ -231,10 +231,13 @@ def get_action1_index(spriteset, feature):
@rtype: C{int}
"""
assert feature in spriteset_collections
act1_idx = None
for spriteset_collection in spriteset_collections[feature]:
if spriteset in spriteset_collection.spritesets:
return spriteset_collection.get_index(spriteset)
assert False
act1_idx = spriteset_collection.get_index(spriteset)
break
assert act1_idx is not None
return act1_idx


def make_cb_failure_action1(feature):
Expand Down
15 changes: 7 additions & 8 deletions nml/actions/action11.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
Action 11 support classes (sounds).
"""

__license__ = """
NML is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand All @@ -13,9 +17,6 @@
with NML; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA."""

"""
Action 11 support classes (sounds).
"""
import os

from nml import generic
Expand Down Expand Up @@ -45,12 +46,10 @@ def __init__(self, fname, pos):

def prepare_output(self, sprite_num):
if not os.access(self.fname, os.R_OK):
raise generic.ScriptError("Sound file '{}' does not exist.".format(self.fname), self.pos)
raise generic.ScriptError(f"Sound file '{self.fname}' does not exist.", self.pos)
size = os.path.getsize(self.fname)
if size == 0:
raise generic.ScriptError(
"Expected sound file '{}' to have a non-zero length.".format(self.fname), self.pos
)
raise generic.ScriptError(f"Expected sound file '{self.fname}' to have a non-zero length.", self.pos)

def write(self, file):
file.print_named_filedata(self.fname)
Expand Down Expand Up @@ -102,7 +101,7 @@ def print_stats():
"""
if len(registered_sounds) > 0:
# Currently NML does not optimise the order of sound effects. So we assume NUM_ANIMATION_SOUNDS as the maximum.
generic.print_info("Sound effects: {}/{}".format(len(registered_sounds), NUM_ANIMATION_SOUNDS))
generic.print_info(f"Sound effects: {len(registered_sounds)}/{NUM_ANIMATION_SOUNDS}")


def add_sound(args, pos):
Expand Down
6 changes: 3 additions & 3 deletions nml/actions/action14.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,15 @@ def get_size(self):

@return: The size (in bytes) of this node.
"""
raise NotImplementedError("get_size must be implemented in Action14Node-subclass {!r}".format(type(self)))
raise NotImplementedError(f"get_size must be implemented in Action14Node-subclass {type(self)!r}")

def write(self, file):
"""
Write this node to the output file.

@param file: The file to write the output to.
"""
raise NotImplementedError("write must be implemented in Action14Node-subclass {!r}".format(type(self)))
raise NotImplementedError(f"write must be implemented in Action14Node-subclass {type(self)!r}")

def write_type_id(self, file):
file.print_string(self.type_string, False, True)
Expand Down Expand Up @@ -266,7 +266,7 @@ def param_desc_actions(root, params):
if min_val > max_val or def_val < min_val or def_val > max_val:
generic.print_warning(
generic.Warning.GENERIC,
"Limits for GRF parameter {} are incoherent, ignoring.".format(param_num),
f"Limits for GRF parameter {param_num} are incoherent, ignoring.",
)
min_val = 0
max_val = 0xFFFFFFFF
Expand Down
30 changes: 11 additions & 19 deletions nml/actions/action2.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,11 @@ def print_stats():
"""
if spritegroup_stats[0] > 0:
generic.print_info(
"Concurrent spritegroups: {}/{} ({})".format(
spritegroup_stats[0], total_action2_ids, str(spritegroup_stats[1])
)
f"Concurrent spritegroups: {spritegroup_stats[0]}/{total_action2_ids} ({spritegroup_stats[1]})"
)
if a2register_stats[0] > 0:
generic.print_info(
"Concurrent Action2 registers: {}/{} ({})".format(
a2register_stats[0], total_tmp_locations, str(a2register_stats[1])
)
f"Concurrent Action2 registers: {a2register_stats[0]}/{total_tmp_locations} ({a2register_stats[1]})"
)


Expand Down Expand Up @@ -117,7 +113,7 @@ def prepare_output(self, sprite_num):
)

def write_sprite_start(self, file, size, extra_comment=None):
assert self.num_refs == 0, "Action2 reference counting has {:d} dangling references.".format(self.num_refs)
assert self.num_refs == 0, f"Action2 reference counting has {self.num_refs} dangling references."
file.comment("Name: " + self.name)
if extra_comment:
for c in extra_comment:
Expand Down Expand Up @@ -298,10 +294,8 @@ def __init__(self):
Instead, call initialize(...).
"""
raise NotImplementedError(
(
"__init__ must be implemented in ASTSpriteGroup-subclass {!r},"
" initialize(..) should be called instead"
).format(type(self))
f"__init__ must be implemented in ASTSpriteGroup-subclass {type(self)!r},"
" initialize(..) should be called instead"
)

def initialize(self, name=None, feature=None, num_params=0):
Expand Down Expand Up @@ -389,7 +383,7 @@ def prepare_act2_output(self):
assert self.name is not None
generic.print_warning(
generic.Warning.OPTIMISATION,
"Block '{}' is not referenced, ignoring.".format(self.name.value),
f"Block '{self.name.value}' is not referenced, ignoring.",
self.pos,
)

Expand Down Expand Up @@ -433,7 +427,7 @@ def collect_references(self):
@rtype: C{iterable} of L{SpriteGroupRef}
"""
raise NotImplementedError(
"collect_references must be implemented in ASTSpriteGroup-subclass {!r}".format(type(self))
f"collect_references must be implemented in ASTSpriteGroup-subclass {type(self)!r}"
)

def set_action2(self, action2, feature):
Expand Down Expand Up @@ -492,16 +486,14 @@ def _add_reference(self, target_ref):
# Passing parameters is not possible here
if len(target_ref.param_list) != 0:
raise generic.ScriptError(
"Passing parameters to '{}' is only possible from a spritelayout.".format(
target_ref.name.value
),
f"Passing parameters to '{target_ref.name.value}' is only possible from a spritelayout.",
target_ref.pos,
)

self.used_sprite_sets.append(target)
else:
if len(target_ref.param_list) != target.num_params:
msg = "'{}' expects {:d} parameters, encountered {:d}."
msg = "'{}' expects {} parameters, encountered {}."
msg = msg.format(target_ref.name.value, target.num_params, len(target_ref.param_list))
raise generic.ScriptError(msg, target_ref.pos)

Expand Down Expand Up @@ -543,7 +535,7 @@ def register_spritegroup(spritegroup):
"""
name = spritegroup.name.value
if name in spritegroup_list:
raise generic.ScriptError("Block with name '{}' has already been defined".format(name), spritegroup.pos)
raise generic.ScriptError(f"Block with name '{name}' has already been defined", spritegroup.pos)
spritegroup_list[name] = spritegroup
global_constants.spritegroups[name] = name

Expand All @@ -559,5 +551,5 @@ def resolve_spritegroup(name):
@rtype: L{ASTSpriteGroup}
"""
if name.value not in spritegroup_list:
raise generic.ScriptError("Unknown identifier encountered: '{}'".format(name.value), name.pos)
raise generic.ScriptError(f"Unknown identifier encountered: '{name.value}'", name.pos)
return spritegroup_list[name.value]
Loading
Loading