Skip to content

Commit

Permalink
Codechange: stub in a structure to support Variants
Browse files Browse the repository at this point in the history
  • Loading branch information
andythenorth committed Dec 10, 2022
1 parent 0897cbd commit 9a287ae
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/docs_templates/trains.pt
Expand Up @@ -135,7 +135,7 @@
${doc_helper.unpack_name_string(consist)}
</td>
<td class="date">${consist.intro_year}</td>
<td class="number">${sum([unit.default_cargo_capacity for unit in consist.units])} t</td>
<td class="number">${doc_helper.capacity_formatted_for_docs(consist)}</td>
<td class="number">${consist.speed} mph</td>
<td>${consist.track_type}</td>
<td>
Expand Down
6 changes: 3 additions & 3 deletions src/gestalt_graphics/pipelines.py
Expand Up @@ -64,7 +64,7 @@ def process_buy_menu_sprite(self, spritesheet):

# hard-coded positions for buy menu sprite (if used - it's optional)
x_offset = 0
for unit_counter, unit in enumerate(self.consist.units):
for unit_counter, unit in enumerate(self.consist.default_variant.units):
# !! currently no cap on purchase menu sprite width
# !! consist has a buy_menu_width prop which caps to 64 which could be used (+1px overlap)
unit_length_in_pixels = 4 * unit.vehicle_length
Expand Down Expand Up @@ -512,12 +512,12 @@ def process_buy_menu_sprite_from_randomisation_candidates(self, spritesheet):
# take the first and last candidates;
# note that we have to call set here, due to the way random candidates are padded out to make power of 2 list lengths for random bits
# we have to use frozen_roster_items as the roster object won't pickle for multiprocessing use (never figured out why)
if len(self.consist.units) > 1:
if len(self.consist.default_variant.units) > 1:
raise BaseException(
"GenerateBuyMenuSpriteFromRandomisationCandidatesPipeline won't work with articulated consists - called by "
+ self.consist.id
)
unit_length_in_pixels = 4 * self.consist.units[0].vehicle_length
unit_length_in_pixels = 4 * self.consist.default_variant.units[0].vehicle_length
unit_slice_length_in_pixels = (
int(unit_length_in_pixels / 2)
+ graphics_constants.randomised_wagon_extra_unit_width
Expand Down
6 changes: 5 additions & 1 deletion src/render_docs.py
Expand Up @@ -379,6 +379,10 @@ def get_replaced_by_name(self, replacement_consist_id, consists):
if consist.id == replacement_consist_id:
return self.unpack_name_string(consist)

def capacity_formatted_for_docs(self, consist):
result = sum([unit.default_cargo_capacity for unit in consist.default_variant.units])
return str(result) + " t"

def power_formatted_for_docs(self, consist):
if consist.wagons_add_power:
return [str(consist.cab_power) + " hp"]
Expand Down Expand Up @@ -422,7 +426,7 @@ def get_props_to_print_in_code_reference(self, subclass):
result = self.fetch_prop(result, "Buy Cost", vehicle.buy_cost)
result = self.fetch_prop(result, "Running Cost", vehicle.running_cost)
result = self.fetch_prop(
result, "Loading Speed", [unit.loading_speed for unit in vehicle.units]
result, "Loading Speed", [unit.loading_speed for unit in vehicle.default_variant.units]
)

props_to_print[vehicle] = result["vehicle"]
Expand Down
10 changes: 5 additions & 5 deletions src/roster.py
Expand Up @@ -224,9 +224,9 @@ def validate_vehicles(self, numeric_id_defender):
+ consist.id
+ "' is defined more than once - to fix, search src for the duplicate"
)
if len(consist.units) == 0:
if len(consist.default_variant.units) == 0:
raise BaseException("Error: " + consist.id + " has no units defined")
elif len(consist.units) == 1:
elif len(consist.default_variant.units) == 1:
if consist.base_numeric_id <= global_constants.max_articulated_id:
raise BaseException(
"Error: "
Expand All @@ -237,8 +237,8 @@ def validate_vehicles(self, numeric_id_defender):
)
# utils.echo_message(consist.id + " with base_numeric_id " + str(consist.base_numeric_id) + " needs a base_numeric_id larger than 8200 as the range below 8200 is reserved for articulated vehicles")
# utils.echo_message(str(consist.base_numeric_id))
elif len(consist.units) > 1:
for unit in consist.units:
elif len(consist.default_variant.units) > 1:
for unit in consist.default_variant.units:
if unit.numeric_id > global_constants.max_articulated_id:
raise BaseException(
"Error: "
Expand All @@ -249,7 +249,7 @@ def validate_vehicles(self, numeric_id_defender):
+ str(global_constants.max_articulated_id)
+ " (use a lower consist base_numeric_id)"
)
for unit in set(consist.units):
for unit in set(consist.default_variant.units):
if unit.numeric_id in numeric_id_defender:
raise BaseException(
"Error: unit "
Expand Down
2 changes: 1 addition & 1 deletion src/templates/articulated_parts.pynml
@@ -1,6 +1,6 @@
// add the units to articulated consist
switch (FEAT_TRAINS, SELF, ${consist.id}_articulated_cb_switch, extra_callback_info1) {
<tal:trailing_units repeat="unit consist.units">
<tal:trailing_units repeat="unit consist.default_variant.units">
${repeat.unit.index}: return ${unit.id};
</tal:trailing_units>
return CB_RESULT_NO_MORE_ARTICULATED_PARTS;
Expand Down
2 changes: 1 addition & 1 deletion src/templates/properties_vehicle.pynml
Expand Up @@ -143,7 +143,7 @@ item(FEAT_TRAINS, ${vehicle.id}, ${vehicle.numeric_id}) {
speed: ${vehicle.id}_switch_speed;
purchase_speed: ${int(1.60934 * consist.speed)};
</tal:speed_is_optional>
<tal:add_articulated_parts condition="len(consist.units) > 1">
<tal:add_articulated_parts condition="len(consist.default_variant.units) > 1">
articulated_part: ${consist.id}_articulated_cb_switch;
</tal:add_articulated_parts>
<!--! setting buy menu text for engines and some wagons with role set currently - this is starting to look jank AF eh-->
Expand Down
33 changes: 23 additions & 10 deletions src/train.py
Expand Up @@ -120,8 +120,7 @@ def __init__(self, **kwargs):
self.floating_run_cost_multiplier = 1
# fixed (baseline) run costs on this subtype, 100 points
self.fixed_run_cost_points = 30 # default, over-ride in subclass as needed
# create structure to hold the units
self.units = []
self.variants = [Variant()]
# one default cargo for the whole consist, no mixed cargo shenanigans, it fails with auto-replace
self.default_cargos = []
self.class_refit_groups = []
Expand Down Expand Up @@ -152,6 +151,11 @@ def __init__(self, **kwargs):
# aids 'project management'
self.sprites_complete = kwargs.get("sprites_complete", False)

@property
def default_variant(self):
# convenience method for docs etc
return self.variants[0]

def add_unit(self, type, repeat=1, **kwargs):
unit = type(consist=self, **kwargs)
count = len(self.unique_units)
Expand All @@ -162,14 +166,14 @@ def add_unit(self, type, repeat=1, **kwargs):
unit.id = self.id + "_" + str(count)
unit.numeric_id = self.base_numeric_id + count
for repeat_num in range(repeat):
self.units.append(unit)
self.default_variant.units.append(unit)

@property
def unique_units(self):
# units may be repeated in the consist, sometimes we need an ordered list of unique units
# set() doesn't preserve list order, which matters, so do it the hard way
unique_units = []
for unit in self.units:
for unit in self.default_variant.units:
if unit not in unique_units:
unique_units.append(unit)
return unique_units
Expand All @@ -178,7 +182,7 @@ def unique_units(self):
def unique_spriterow_nums(self):
# find the unique spriterow numbers, used in graphics generation
result = []
for unit in set([unit.spriterow_num for unit in self.units]):
for unit in set([unit.spriterow_num for unit in self.default_variant.units]):
result.append(unit)
# extend with alternative cc livery if present, spritesheet format assumes unit_1_default, unit_1_alternative_cc_livery, unit_2_default, unit_2_alternative_cc_livery if present
if self.gestalt_graphics.alternative_cc_livery is not None:
Expand Down Expand Up @@ -628,12 +632,12 @@ def power_speed_ratio(self):

@property
def weight(self):
return sum([getattr(unit, "weight", 0) for unit in self.units])
return sum([getattr(unit, "weight", 0) for unit in self.default_variant.units])

@property
def length(self):
# total length of the consist
return sum([unit.vehicle_length for unit in self.units])
return sum([unit.vehicle_length for unit in self.default_variant.units])

@property
def loading_speed_multiplier(self):
Expand Down Expand Up @@ -728,7 +732,7 @@ def nml_expression_for_vehicle_is_electrically_powered_by_tile(self):
def buy_menu_x_loc(self):
# automatic buy menu sprite if single-unit consist
# extend this to check an auto_buy_menu_sprite property if manual over-rides are needed in future
if len(self.units) > 1:
if len(self.default_variant.units) > 1:
# custom buy menu sprite for articulated vehicles
return 360
elif self.is_randomised_wagon or self.is_caboose:
Expand Down Expand Up @@ -928,7 +932,7 @@ def cite(self):
return cite_name + ", " + random.choice(cite_titles)

def render_articulated_switch(self, templates):
if len(self.units) > 1:
if len(self.default_variant.units) > 1:
template = templates["articulated_parts.pynml"]
nml_result = template(consist=self, global_constants=global_constants)
return nml_result
Expand Down Expand Up @@ -989,7 +993,7 @@ def render(self, templates, graphics_path):
self.assert_power()
# templating
nml_result = ""
if len(self.units) > 1:
if len(self.default_variant.units) > 1:
nml_result = nml_result + self.render_articulated_switch(templates)
for unit in self.unique_units:
nml_result = nml_result + unit.render(templates, graphics_path)
Expand Down Expand Up @@ -4448,6 +4452,15 @@ def __init__(self, **kwargs):
self.gestalt_graphics = GestaltGraphicsCustom("vehicle_torpedo_car.pynml")


class Variant(object):
"""
Base class for buyable variants of a consist, which align with Variants in the grf spec
"""

def __init__(self, **kwargs):
self.units = []


class Train(object):
"""
Base class for all types of trains
Expand Down

0 comments on commit 9a287ae

Please sign in to comment.