Last active
October 1, 2020 20:06
-
-
Save LordAro/d292a50202928def4bb6e8338713c053 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# fmt: off | |
properties = [ | |
# Feature 0x00 - Trains | |
{ | |
**general_veh_props, | |
"track_type": {"size": 1, "num": 0x05}, | |
"ai_special_flag": {"size": 1, "num": 0x08}, | |
"speed": {"size": 2, "num": 0x09, "unit_type": "speed", "unit_conversion": (5000, 1397), "adjust_value": lambda val, unit: ottd_display_speed(val, 1, 1, unit)}, | |
# 09 doesn"t exist | |
"power": {"size": 2, "num": 0x0B, "unit_type": "power"}, | |
# 0A doesn"t exist | |
"running_cost_factor": {"size": 1, "num": 0x0D}, | |
"running_cost_base": {"size": 4, "num": 0x0E}, | |
# 0F -11 don"t exist | |
"sprite_id": {"size": 1, "num": 0x12}, | |
"dual_headed": {"size": 1, "num": 0x13}, | |
"cargo_capacity": {"size": 1, "num": 0x14}, | |
"default_cargo_type": {"size": 1, "num": 0x15}, | |
"weight": two_byte_property(0x16, 0x24, {"unit_type": "weight"}, {"unit_type": "weight"}), | |
"cost_factor": {"size": 1, "num": 0x17}, | |
"ai_engine_rank": {"size": 1, "num": 0x18}, | |
"engine_class": {"size": 1, "num": 0x19}, | |
# 1A (sort purchase list) is implemented elsewhere | |
"extra_power_per_wagon": {"size": 2, "num": 0x1B, "unit_type": "power"}, | |
"refit_cost": {"size": 1, "num": 0x1C}, | |
# 1D (refittable cargo types) is removed, it is zeroed when setting a different refit property | |
# 1E (callback flags) is not set by user | |
"tractive_effort_coefficient": {"size": 1, "num": 0x1F, "unit_conversion": 255}, | |
"air_drag_coefficient": {"size": 1, "num": 0x20, "unit_conversion": 255}, | |
"length": {"size": 1, "num": 0x21, "value_function": vehicle_length}, | |
# 22 has two names, to simplify docs | |
"visual_effect_and_powered": {"size": 1, "num": 0x22}, | |
"effect_spawn_model_and_powered": {"size": 1, "num": 0x22}, | |
"extra_weight_per_wagon": {"size": 1, "num": 0x23, "unit_type": "weight"}, | |
# 24 is high byte of 16 (weight) | |
"bitmask_vehicle_info": {"size": 1, "num": 0x25}, | |
"retire_early": {"size": 1, "num": 0x26}, | |
"misc_flags": {"size": 1, "num": 0x27}, | |
"refittable_cargo_classes": [{"size": 2, "num": 0x28}, zero_refit_mask(0x1D)], | |
"non_refittable_cargo_classes": [{"size": 2, "num": 0x29}, zero_refit_mask(0x1D)], | |
"introduction_date": {"size": 4, "num": 0x2A}, | |
"cargo_age_period": {"size": 2, "num": 0x2B}, | |
"cargo_allow_refit": [{"custom_function": lambda value: ctt_list(0x2C, value)}, zero_refit_mask(0x1D)], | |
"cargo_disallow_refit": [{"custom_function": lambda value: ctt_list(0x2D, value)}, zero_refit_mask(0x1D)], | |
}, | |
# Feature 0x01 - Road Vehicles | |
{ | |
**general_veh_props, | |
"road_type": {"size": 1, "num": 0x05}, | |
"tram_type": {"size": 1, "num": 0x05}, | |
"speed": roadveh_speed_prop({"unit_type": "speed", "unit_conversion": (10000, 1397), "adjust_value": lambda val, unit: ottd_display_speed(val, 1, 2, unit)}), | |
"running_cost_factor": {"size": 1, "num": 0x09}, | |
"running_cost_base": {"size": 4, "num": 0x0A}, | |
# 0B -0D don"t exist | |
"sprite_id": {"size": 1, "num": 0x0E}, | |
"cargo_capacity": {"size": 1, "num": 0x0F}, | |
"default_cargo_type": {"size": 1, "num": 0x10}, | |
"cost_factor": {"size": 1, "num": 0x11}, | |
"sound_effect": {"size": 1, "num": 0x12}, | |
"power": {"size": 1, "num": 0x13, "unit_type": "power", "unit_conversion": (1, 10)}, | |
"weight": {"size": 1, "num": 0x14, "unit_type": "weight", "unit_conversion": 4}, | |
# 15 is set together with 08 (see above) | |
# 16 (refittable cargo types) is removed, it is zeroed when setting a different refit property | |
# 17 (callback flags) is not set by user | |
"tractive_effort_coefficient": {"size": 1, "num": 0x18, "unit_conversion": 255}, | |
"air_drag_coefficient": {"size": 1, "num": 0x19, "unit_conversion": 255}, | |
"refit_cost": {"size": 1, "num": 0x1A}, | |
"retire_early": {"size": 1, "num": 0x1B}, | |
"misc_flags": {"size": 1, "num": 0x1C}, | |
"refittable_cargo_classes": [{"size": 2, "num": 0x1D}, zero_refit_mask(0x16)], | |
"non_refittable_cargo_classes": [{"size": 2, "num": 0x1E}, zero_refit_mask(0x16)], | |
"introduction_date": {"size": 4, "num": 0x1F}, | |
# 20 (sort purchase list) is implemented elsewhere | |
# 21 has two names, to simplify docs | |
"visual_effect": {"size": 1, "num": 0x21}, | |
"effect_spawn_model": {"size": 1, "num": 0x21}, | |
"cargo_age_period": {"size": 2, "num": 0x22}, | |
"length": {"size": 1, "num": 0x23, "value_function": vehicle_length}, | |
"cargo_allow_refit": [{"custom_function": lambda value: ctt_list(0x24, value)}, zero_refit_mask(0x16)], | |
"cargo_disallow_refit": [{"custom_function": lambda value: ctt_list(0x25, value)}, zero_refit_mask(0x16)], | |
}, | |
# Feature 0x02 - Ships | |
{ | |
**general_veh_props, | |
"sprite_id": {"size": 1, "num": 0x08}, | |
"is_refittable": {"size": 1, "num": 0x09}, | |
"cost_factor": {"size": 1, "num": 0x0A}, | |
"speed": {"size": 1, "num": 0x0B, "unit_type": "speed", "unit_conversion": (10000, 1397), "adjust_value": lambda val, unit: ottd_display_speed(val, 1, 2, unit)}, | |
"default_cargo_type": {"size": 1, "num": 0x0C}, | |
"cargo_capacity": {"size": 2, "num": 0x0D}, | |
# 0E does not exist | |
"running_cost_factor": {"size": 1, "num": 0x0F}, | |
"sound_effect": {"size": 1, "num": 0x10}, | |
# 11 (refittable cargo types) is removed, it is zeroed when setting a different refit property | |
# 12 (callback flags) is not set by user | |
"refit_cost": {"size": 1, "num": 0x13}, | |
"ocean_speed_fraction": {"size": 1, "num": 0x14, "unit_conversion": 255, "value_function": speed_fraction}, | |
"canal_speed_fraction": {"size": 1, "num": 0x15, "unit_conversion": 255, "value_function": speed_fraction}, | |
"retire_early": {"size": 1, "num": 0x16}, | |
"misc_flags": {"size": 1, "num": 0x17}, | |
"refittable_cargo_classes": [{"size": 2, "num": 0x18}, zero_refit_mask(0x11)], | |
"non_refittable_cargo_classes": [{"size": 2, "num": 0x19}, zero_refit_mask(0x11)], | |
"introduction_date": {"size": 4, "num": 0x1A}, | |
# 1B (sort purchase list) is implemented elsewhere | |
# 1C has two names, to simplify docs | |
"visual_effect": {"size": 1, "num": 0x1C}, | |
"effect_spawn_model": {"size": 1, "num": 0x1C}, | |
"cargo_age_period": {"size": 2, "num": 0x1D}, | |
"cargo_allow_refit": [{"custom_function": lambda value: ctt_list(0x1E, value)}, zero_refit_mask(0x11)], | |
"cargo_disallow_refit": [{"custom_function": lambda value: ctt_list(0x1F, value)}, zero_refit_mask(0x11)], | |
}, | |
# Feature 0x03 - Aircraft | |
{ | |
**general_veh_props, | |
"sprite_id": {"size": 1, "num": 0x08}, | |
"aircraft_type": [{"size": 1, "num": 0x09, "value_function": aircraft_is_heli}, {"size": 1, "num": 0x0A, "value_function": aircraft_is_large}], | |
"cost_factor": {"size": 1, "num": 0x0B}, | |
"speed": {"size": 1, "num": 0x0C, "unit_type": "speed", "unit_conversion": (701, 2507), "adjust_value": lambda val, unit: ottd_display_speed(val, 128, 10, unit)}, | |
"acceleration": {"size": 1, "num": 0x0D}, | |
"running_cost_factor": {"size": 1, "num": 0x0E}, | |
"passenger_capacity": {"size": 2, "num": 0x0F}, | |
# 10 does not exist | |
"mail_capacity": {"size": 1, "num": 0x11}, | |
"sound_effect": {"size": 1, "num": 0x12}, | |
# 13 (refittable cargo types) is removed, it is zeroed when setting a different refit property | |
# 14 (callback flags) is not set by user | |
"refit_cost": {"size": 1, "num": 0x15}, | |
"retire_early": {"size": 1, "num": 0x16}, | |
"misc_flags": {"size": 1, "num": 0x17}, | |
"refittable_cargo_classes": [{"size": 2, "num": 0x18}, zero_refit_mask(0x13)], | |
"non_refittable_cargo_classes": [{"size": 2, "num": 0x19}, zero_refit_mask(0x13)], | |
"introduction_date": {"size": 4, "num": 0x1A}, | |
# 1B (sort purchase list) is implemented elsewhere | |
"cargo_age_period": {"size": 2, "num": 0x1C}, | |
"cargo_allow_refit": [{"custom_function": lambda value: ctt_list(0x1D, value)}, zero_refit_mask(0x13)], | |
"cargo_disallow_refit": [{"custom_function": lambda value: ctt_list(0x1E, value)}, zero_refit_mask(0x13)], | |
"range": {"size": 2, "num": 0x1F}, | |
}, | |
# Feature 0x04 - Stations | |
None, # TODO | |
# Feature 0x05 - Canals | |
{ | |
# 08 (callback flags) not set by user | |
"graphic_flags": {"size": 1, "num": 0x09}, | |
}, | |
# Feature 0x06 - Bridges | |
None, # TODO | |
# Feature 0x07 - Houses | |
{ | |
"substitute": {"size": 1, "num": 0x08, "multitile_function": mt_house_old_id, "first": None}, | |
"building_flags": two_byte_property(0x09, 0x19, {"multitile_function": mt_house_prop09}, {"multitile_function": lambda *args: mt_house_mask(0xFE, *args)}), | |
"years_available": [{"size": 2, "num": 0x0A, "multitile_function": mt_house_zero, "value_function": house_prop_0A}, | |
{"size": 2, "num": 0x21, "multitile_function": mt_house_zero, "value_function": lambda value: house_prop_21_22(value, 0)}, | |
{"size": 2, "num": 0x22, "multitile_function": mt_house_zero, "value_function": lambda value: house_prop_21_22(value, 1)}], | |
"population": {"size": 1, "num": 0x0B, "multitile_function": mt_house_zero}, | |
"mail_multiplier": {"size": 1, "num": 0x0C, "multitile_function": mt_house_zero}, | |
# prop 0D - 0F are replaced by prop 23 | |
"local_authority_impact": {"size": 2, "num": 0x10, "multitile_function": mt_house_same}, | |
"removal_cost_multiplier": {"size": 1, "num": 0x11, "multitile_function": mt_house_same}, | |
"name": {"size": 2, "num": 0x12, "string": 0xDC, "multitile_function": mt_house_same}, | |
"availability_mask": {"size": 2, "num": 0x13, "multitile_function": mt_house_zero, "value_function": house_available_mask}, | |
# prop 14 (callback flags 1) is not set by user | |
"override": {"size": 1, "num": 0x15, "multitile_function": mt_house_old_id}, | |
"refresh_multiplier": {"size": 1, "num": 0x16, "multitile_function": mt_house_same}, | |
"random_colours": {"size": 4, "num": 0x17, "multitile_function": mt_house_same, "value_function": house_random_colours}, | |
"probability": {"size": 1, "num": 0x18, "multitile_function": mt_house_zero, "unit_conversion": 16}, | |
# prop 19 is the high byte of prop 09 | |
"animation_info": {"size": 1, "num": 0x1A, "multitile_function": mt_house_same, "value_function": lambda value: animation_info(value, 7, 128)}, | |
"animation_speed": {"size": 1, "num": 0x1B, "multitile_function": mt_house_same}, | |
"building_class": {"size": 1, "num": 0x1C, "multitile_function": mt_house_class}, | |
# prop 1D (callback flags 2) is not set by user | |
# prop 1E is replaced by prop 23 | |
"minimum_lifetime": {"size": 1, "num": 0x1F, "multitile_function": mt_house_zero}, | |
"watched_cargo_types": {"multitile_function": mt_house_same, "custom_function": lambda *values: ctt_list(0x20, *values)}, | |
# prop 21 -22 see above (years_available, prop 0A) | |
"accepted_cargos": {"multitile_function": mt_house_same, "custom_function": lambda *values: accepted_cargos(0x23, *values)}, | |
}, | |
# Feature 0x08 - General Vars | |
None, # Implemented elsewhere (e.g. basecost, snowline) | |
# Feature 0x09 - Industry Tiles | |
{ | |
"substitute": {"size": 1, "num": 0x08, "first": None}, | |
"override": {"size": 1, "num": 0x09}, | |
# prop 0A - 0C are replaced by prop 13 | |
"land_shape_flags": {"size": 1, "num": 0x0D}, | |
# prop 0E (callback flags) is not set by user | |
"animation_info": {"size": 2, "num": 0x0F, "value_function": animation_info}, | |
"animation_speed": {"size": 1, "num": 0x10}, | |
"animation_triggers": {"size": 1, "num": 0x11}, | |
"special_flags": {"size": 1, "num": 0x12}, | |
"accepted_cargos": {"custom_function": lambda value: accepted_cargos(0x13, value)}, | |
}, | |
# Feature 0x0A - Industries | |
{ | |
"substitute": {"size": 1, "num": 0x08, "first": None}, | |
"override": {"size": 1, "num": 0x09}, | |
"layouts": {"custom_function": industry_layouts}, # = prop 0A | |
"life_type": {"size": 1, "num": 0x0B}, | |
"closure_msg": {"size": 2, "num": 0x0C, "string": 0xDC}, | |
"prod_increase_msg": {"size": 2, "num": 0x0D, "string": 0xDC}, | |
"prod_decrease_msg": {"size": 2, "num": 0x0E, "string": 0xDC}, | |
"fund_cost_multiplier": {"size": 1, "num": 0x0F}, | |
"prod_cargo_types": {"size": 2, "num": 0x10, "value_function": lambda value: cargo_list(value, 2), "replaced_by": "cargo_types"}, | |
"accept_cargo_types": {"size": 4, "num": 0x11, "value_function": lambda value: cargo_list(value, 3), "replaced_by": "cargo_types"}, | |
"prod_multiplier": {"custom_function": industry_prod_multiplier, "replaced_by": "cargo_types"}, # = prop 12,13 | |
"min_cargo_distr": {"size": 1, "num": 0x14}, | |
"random_sound_effects": {"custom_function": random_sounds}, # = prop 15 | |
"conflicting_ind_types": {"custom_function": industry_conflicting_types}, # = prop 16 | |
"prob_random": {"size": 1, "num": 0x17}, # Obsolete, ambiguous name, use "prob_map_gen" instead | |
"prob_map_gen": {"size": 1, "num": 0x17}, | |
"prob_in_game": {"size": 1, "num": 0x18}, | |
"map_colour": {"size": 1, "num": 0x19}, | |
"spec_flags": {"size": 4, "num": 0x1A}, | |
"new_ind_msg": {"size": 2, "num": 0x1B, "string": 0xDC}, | |
"input_multiplier_1": {"custom_function": lambda value: industry_input_multiplier(value, 0x1C), "replaced_by": "cargo_types"}, | |
"input_multiplier_2": {"custom_function": lambda value: industry_input_multiplier(value, 0x1D), "replaced_by": "cargo_types"}, | |
"input_multiplier_3": {"custom_function": lambda value: industry_input_multiplier(value, 0x1E), "replaced_by": "cargo_types"}, | |
"name": {"size": 2, "num": 0x1F, "string": 0xDC}, | |
"prospect_chance": {"size": 4, "num": 0x20, "unit_conversion": 0xFFFFFFFF}, | |
# prop 21, 22 (callback flags) are not set by user | |
"remove_cost_multiplier": {"size": 4, "num": 0x23}, | |
"nearby_station_name": {"size": 2, "num": 0x24, "string": 0xDC}, | |
"cargo_types": {"custom_function": industry_cargo_types}, # = prop 25+26+27+28 combined in one structure | |
}, | |
# Feature 0x0B - Cargoes | |
{ | |
"number": {"num" : 0x08, "size" : 1}, | |
"type_name": {"num" : 0x09, "size" : 2, "string" : 0xDC}, | |
"unit_name": {"num" : 0x0A, "size" : 2, "string" : 0xDC}, | |
# Properties 0B, 0C are not used by OpenTTD | |
"type_abbreviation": {"num" : 0x0D, "size" : 2, "string" : 0xDC}, | |
"sprite": {"num" : 0x0E, "size" : 2}, | |
"weight": {"num" : 0x0F, "size" : 1, "unit_type" : "weight", "unit_conversion" : 16}, | |
"penalty_lowerbound": {"num" : 0x10, "size" : 1}, | |
"single_penalty_length": {"num" : 0x11, "size" : 1}, | |
"price_factor": {"num" : 0x12, "size" : 4, "unit_conversion" : (1 << 21, 10 * 20 * 255)}, # 10 units of cargo across 20 tiles, with time factor = 255 | |
"station_list_colour": {"num" : 0x13, "size" : 1}, | |
"cargo_payment_list_colour": {"num" : 0x14, "size" : 1}, | |
"is_freight": {"num" : 0x15, "size" : 1}, | |
"cargo_classes": {"num" : 0x16, "size" : 2}, | |
"cargo_label": {"num" : 0x17, "size" : 4, "string_literal": 4}, | |
"town_growth_effect": {"num" : 0x18, "size" : 1}, | |
"town_growth_multiplier": {"num" : 0x19, "size" : 2, "unit_conversion" : 0x100}, | |
# 1A (callback flags) is not set by user | |
"units_of_cargo": {"num" : 0x1B, "size" : 2, "string" : 0xDC}, | |
"items_of_cargo": {"num" : 0x1C, "size" : 2, "string" : 0xDC}, | |
"capacity_multiplier": {"num" : 0x1D, "size" : 2, "unit_conversion" : 0x100}, | |
}, | |
# Feature 0x0C - Sounds | |
None, # Implemented differently | |
# Feature 0x0D - Airports | |
{ | |
"override": {"size": 1, "num": 0x08, "first":None}, | |
# 09 does not exist | |
"layouts": {"custom_function": airport_layouts}, # = prop 0A | |
# 0B does not exist | |
"years_available": {"custom_function": airport_years}, # = prop 0C | |
"ttd_airport_type": {"size": 1, "num": 0x0D}, | |
"catchment_area": {"size": 1, "num": 0x0E}, | |
"noise_level": {"size": 1, "num": 0x0F}, | |
"name": {"size": 2, "num": 0x10, "string": 0xDC}, | |
"maintenance_cost": {"size": 2, "num": 0x11}, | |
}, | |
# Feature 0x0E - Signals | |
None, # No action0 | |
# Feature 0x0F - Objects | |
{ | |
"class": {"size": 4, "num": 0x08, "first": None, "string_literal": 4}, | |
# strings might be according to specs be either 0xD0 or 0xD4 | |
"classname": {"size": 2, "num": 0x09, "string": 0xD0}, | |
"name": {"size": 2, "num": 0x0A, "string": 0xD0}, | |
"climates_available": {"size": 1, "num": 0x0B}, | |
"size": {"custom_function": object_size}, # = prop 0C | |
"build_cost_multiplier": {"size": 1, "num": 0x0D}, | |
"introduction_date": {"size": 4, "num": 0x0E}, | |
"end_of_life_date": {"size": 4, "num": 0x0F}, | |
"object_flags": {"size": 2, "num": 0x10}, | |
"animation_info": {"size": 2, "num": 0x11, "value_function": animation_info}, | |
"animation_speed": {"size": 1, "num": 0x12}, | |
"animation_triggers": {"size": 2, "num": 0x13}, | |
"remove_cost_multiplier": {"size": 1, "num": 0x14}, | |
# 15 (callback flags) is not set by user | |
"height": {"size": 1, "num": 0x16}, | |
"num_views": {"size": 1, "num": 0x17}, | |
"count_per_map256": {"size": 1, "num": 0x18}, | |
}, | |
# Feature 0x10 - Rail Types | |
{ | |
**common_tracktype_props, | |
"compatible_railtype_list": {"custom_function": lambda x: label_list(x, 0x0E, "Railtype")}, | |
"powered_railtype_list": {"custom_function": lambda x: label_list(x, 0x0F, "Railtype")}, | |
"railtype_flags": {"size": 1, "num": 0x10}, | |
"curve_speed_multiplier": {"size": 1, "num": 0x11}, | |
"station_graphics": {"size": 1, "num": 0x12}, | |
"speed_limit": {"size": 2, "num": 0x14, "unit_type": "speed", "unit_conversion": (5000, 1397), "adjust_value": lambda val, unit: ottd_display_speed(val, 1, 1, unit)}, | |
"acceleration_model": {"size": 1, "num": 0x15}, | |
"requires_railtype_list": {"custom_function": lambda x: label_list(x, 0x18, "Railtype")}, | |
"introduces_railtype_list": {"custom_function": lambda x: label_list(x, 0x19, "Railtype")}, | |
"alternative_railtype_list": {"custom_function": lambda x: label_list(x, 0x1D, "Railtype")}, | |
}, | |
# Feature 0x11 - Airport tiles | |
{ | |
"substitute": {"size": 1, "num": 0x08, "first": None}, | |
"override": {"size": 1, "num": 0x09}, | |
# 0A - 0D don"t exist (yet?) | |
# 0E (callback flags) is not set by user | |
"animation_info": {"size": 2, "num": 0x0F, "value_function": animation_info}, | |
"animation_speed": {"size": 1, "num": 0x10}, | |
"animation_triggers": {"size": 1, "num": 0x11}, | |
}, | |
# Feature 0x12 - Road Types | |
{ | |
**common_tracktype_props, | |
"powered_roadtype_list": {"custom_function": lambda x: label_list(x, 0x0F, "Roadtype")}, | |
"roadtype_flags": {"size": 1, "num": 0x10}, | |
"speed_limit": {"size": 2, "num": 0x14, "unit_type": "speed", "unit_conversion": (10000, 1397), "adjust_value": lambda val, unit: ottd_display_speed(val, 1, 2, unit)}, | |
"requires_roadtype_list": {"custom_function": lambda x: label_list(x, 0x18, "Roadtype")}, | |
"introduces_roadtype_list": {"custom_function": lambda x: label_list(x, 0x19, "Roadtype")}, | |
"alternative_roadtype_list": {"custom_function": lambda x: label_list(x, 0x1D, "Roadtype")}, | |
}, | |
# Feature 0x13 - Tram Types | |
{ | |
**common_tracktype_props, | |
"powered_tramtype_list": {"custom_function": lambda x: label_list(x, 0x0F, "Tramtype")}, | |
"tramtype_flags": {"size": 1, "num": 0x10}, | |
"speed_limit": {"size": 2, "num": 0x14, "unit_type": "speed", "unit_conversion": (10000, 1397), "adjust_value": lambda val, unit: ottd_display_speed(val, 1, 2, unit)}, | |
"requires_tramtype_list": {"custom_function": lambda x: label_list(x, 0x18, "Tramtype")}, | |
"introduces_tramtype_list": {"custom_function": lambda x: label_list(x, 0x19, "Tramtype")}, | |
"alternative_tramtype_list": {"custom_function": lambda x: label_list(x, 0x1D, "Tramtype")}, | |
}, | |
] | |
# fmt: on |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
properties = [ | |
# Feature 0x00 - Trains | |
{ | |
**general_veh_props, | |
"track_type": {"size": 1, "num": 0x05}, | |
"ai_special_flag": {"size": 1, "num": 0x08}, | |
"speed": { | |
"size": 2, | |
"num": 0x09, | |
"unit_type": "speed", | |
"unit_conversion": (5000, 1397), | |
"adjust_value": lambda val, unit: ottd_display_speed(val, 1, 1, unit), | |
}, | |
# 09 doesn"t exist | |
"power": {"size": 2, "num": 0x0B, "unit_type": "power"}, | |
# 0A doesn"t exist | |
"running_cost_factor": {"size": 1, "num": 0x0D}, | |
"running_cost_base": {"size": 4, "num": 0x0E}, | |
# 0F -11 don"t exist | |
"sprite_id": {"size": 1, "num": 0x12}, | |
"dual_headed": {"size": 1, "num": 0x13}, | |
"cargo_capacity": {"size": 1, "num": 0x14}, | |
"default_cargo_type": {"size": 1, "num": 0x15}, | |
"weight": two_byte_property(0x16, 0x24, {"unit_type": "weight"}, {"unit_type": "weight"}), | |
"cost_factor": {"size": 1, "num": 0x17}, | |
"ai_engine_rank": {"size": 1, "num": 0x18}, | |
"engine_class": {"size": 1, "num": 0x19}, | |
# 1A (sort purchase list) is implemented elsewhere | |
"extra_power_per_wagon": {"size": 2, "num": 0x1B, "unit_type": "power"}, | |
"refit_cost": {"size": 1, "num": 0x1C}, | |
# 1D (refittable cargo types) is removed, it is zeroed when setting a different refit property | |
# 1E (callback flags) is not set by user | |
"tractive_effort_coefficient": {"size": 1, "num": 0x1F, "unit_conversion": 255}, | |
"air_drag_coefficient": {"size": 1, "num": 0x20, "unit_conversion": 255}, | |
"length": {"size": 1, "num": 0x21, "value_function": vehicle_length}, | |
# 22 has two names, to simplify docs | |
"visual_effect_and_powered": {"size": 1, "num": 0x22}, | |
"effect_spawn_model_and_powered": {"size": 1, "num": 0x22}, | |
"extra_weight_per_wagon": {"size": 1, "num": 0x23, "unit_type": "weight"}, | |
# 24 is high byte of 16 (weight) | |
"bitmask_vehicle_info": {"size": 1, "num": 0x25}, | |
"retire_early": {"size": 1, "num": 0x26}, | |
"misc_flags": {"size": 1, "num": 0x27}, | |
"refittable_cargo_classes": [{"size": 2, "num": 0x28}, zero_refit_mask(0x1D)], | |
"non_refittable_cargo_classes": [{"size": 2, "num": 0x29}, zero_refit_mask(0x1D)], | |
"introduction_date": {"size": 4, "num": 0x2A}, | |
"cargo_age_period": {"size": 2, "num": 0x2B}, | |
"cargo_allow_refit": [{"custom_function": lambda value: ctt_list(0x2C, value)}, zero_refit_mask(0x1D)], | |
"cargo_disallow_refit": [{"custom_function": lambda value: ctt_list(0x2D, value)}, zero_refit_mask(0x1D)], | |
}, | |
# Feature 0x01 - Road Vehicles | |
{ | |
**general_veh_props, | |
"road_type": {"size": 1, "num": 0x05}, | |
"tram_type": {"size": 1, "num": 0x05}, | |
"speed": roadveh_speed_prop( | |
{ | |
"unit_type": "speed", | |
"unit_conversion": (10000, 1397), | |
"adjust_value": lambda val, unit: ottd_display_speed(val, 1, 2, unit), | |
} | |
), | |
"running_cost_factor": {"size": 1, "num": 0x09}, | |
"running_cost_base": {"size": 4, "num": 0x0A}, | |
# 0B -0D don"t exist | |
"sprite_id": {"size": 1, "num": 0x0E}, | |
"cargo_capacity": {"size": 1, "num": 0x0F}, | |
"default_cargo_type": {"size": 1, "num": 0x10}, | |
"cost_factor": {"size": 1, "num": 0x11}, | |
"sound_effect": {"size": 1, "num": 0x12}, | |
"power": {"size": 1, "num": 0x13, "unit_type": "power", "unit_conversion": (1, 10)}, | |
"weight": {"size": 1, "num": 0x14, "unit_type": "weight", "unit_conversion": 4}, | |
# 15 is set together with 08 (see above) | |
# 16 (refittable cargo types) is removed, it is zeroed when setting a different refit property | |
# 17 (callback flags) is not set by user | |
"tractive_effort_coefficient": {"size": 1, "num": 0x18, "unit_conversion": 255}, | |
"air_drag_coefficient": {"size": 1, "num": 0x19, "unit_conversion": 255}, | |
"refit_cost": {"size": 1, "num": 0x1A}, | |
"retire_early": {"size": 1, "num": 0x1B}, | |
"misc_flags": {"size": 1, "num": 0x1C}, | |
"refittable_cargo_classes": [{"size": 2, "num": 0x1D}, zero_refit_mask(0x16)], | |
"non_refittable_cargo_classes": [{"size": 2, "num": 0x1E}, zero_refit_mask(0x16)], | |
"introduction_date": {"size": 4, "num": 0x1F}, | |
# 20 (sort purchase list) is implemented elsewhere | |
# 21 has two names, to simplify docs | |
"visual_effect": {"size": 1, "num": 0x21}, | |
"effect_spawn_model": {"size": 1, "num": 0x21}, | |
"cargo_age_period": {"size": 2, "num": 0x22}, | |
"length": {"size": 1, "num": 0x23, "value_function": vehicle_length}, | |
"cargo_allow_refit": [{"custom_function": lambda value: ctt_list(0x24, value)}, zero_refit_mask(0x16)], | |
"cargo_disallow_refit": [{"custom_function": lambda value: ctt_list(0x25, value)}, zero_refit_mask(0x16)], | |
}, | |
# Feature 0x02 - Ships | |
{ | |
**general_veh_props, | |
"sprite_id": {"size": 1, "num": 0x08}, | |
"is_refittable": {"size": 1, "num": 0x09}, | |
"cost_factor": {"size": 1, "num": 0x0A}, | |
"speed": { | |
"size": 1, | |
"num": 0x0B, | |
"unit_type": "speed", | |
"unit_conversion": (10000, 1397), | |
"adjust_value": lambda val, unit: ottd_display_speed(val, 1, 2, unit), | |
}, | |
"default_cargo_type": {"size": 1, "num": 0x0C}, | |
"cargo_capacity": {"size": 2, "num": 0x0D}, | |
# 0E does not exist | |
"running_cost_factor": {"size": 1, "num": 0x0F}, | |
"sound_effect": {"size": 1, "num": 0x10}, | |
# 11 (refittable cargo types) is removed, it is zeroed when setting a different refit property | |
# 12 (callback flags) is not set by user | |
"refit_cost": {"size": 1, "num": 0x13}, | |
"ocean_speed_fraction": {"size": 1, "num": 0x14, "unit_conversion": 255, "value_function": speed_fraction}, | |
"canal_speed_fraction": {"size": 1, "num": 0x15, "unit_conversion": 255, "value_function": speed_fraction}, | |
"retire_early": {"size": 1, "num": 0x16}, | |
"misc_flags": {"size": 1, "num": 0x17}, | |
"refittable_cargo_classes": [{"size": 2, "num": 0x18}, zero_refit_mask(0x11)], | |
"non_refittable_cargo_classes": [{"size": 2, "num": 0x19}, zero_refit_mask(0x11)], | |
"introduction_date": {"size": 4, "num": 0x1A}, | |
# 1B (sort purchase list) is implemented elsewhere | |
# 1C has two names, to simplify docs | |
"visual_effect": {"size": 1, "num": 0x1C}, | |
"effect_spawn_model": {"size": 1, "num": 0x1C}, | |
"cargo_age_period": {"size": 2, "num": 0x1D}, | |
"cargo_allow_refit": [{"custom_function": lambda value: ctt_list(0x1E, value)}, zero_refit_mask(0x11)], | |
"cargo_disallow_refit": [{"custom_function": lambda value: ctt_list(0x1F, value)}, zero_refit_mask(0x11)], | |
}, | |
# Feature 0x03 - Aircraft | |
{ | |
**general_veh_props, | |
"sprite_id": {"size": 1, "num": 0x08}, | |
"aircraft_type": [ | |
{"size": 1, "num": 0x09, "value_function": aircraft_is_heli}, | |
{"size": 1, "num": 0x0A, "value_function": aircraft_is_large}, | |
], | |
"cost_factor": {"size": 1, "num": 0x0B}, | |
"speed": { | |
"size": 1, | |
"num": 0x0C, | |
"unit_type": "speed", | |
"unit_conversion": (701, 2507), | |
"adjust_value": lambda val, unit: ottd_display_speed(val, 128, 10, unit), | |
}, | |
"acceleration": {"size": 1, "num": 0x0D}, | |
"running_cost_factor": {"size": 1, "num": 0x0E}, | |
"passenger_capacity": {"size": 2, "num": 0x0F}, | |
# 10 does not exist | |
"mail_capacity": {"size": 1, "num": 0x11}, | |
"sound_effect": {"size": 1, "num": 0x12}, | |
# 13 (refittable cargo types) is removed, it is zeroed when setting a different refit property | |
# 14 (callback flags) is not set by user | |
"refit_cost": {"size": 1, "num": 0x15}, | |
"retire_early": {"size": 1, "num": 0x16}, | |
"misc_flags": {"size": 1, "num": 0x17}, | |
"refittable_cargo_classes": [{"size": 2, "num": 0x18}, zero_refit_mask(0x13)], | |
"non_refittable_cargo_classes": [{"size": 2, "num": 0x19}, zero_refit_mask(0x13)], | |
"introduction_date": {"size": 4, "num": 0x1A}, | |
# 1B (sort purchase list) is implemented elsewhere | |
"cargo_age_period": {"size": 2, "num": 0x1C}, | |
"cargo_allow_refit": [{"custom_function": lambda value: ctt_list(0x1D, value)}, zero_refit_mask(0x13)], | |
"cargo_disallow_refit": [{"custom_function": lambda value: ctt_list(0x1E, value)}, zero_refit_mask(0x13)], | |
"range": {"size": 2, "num": 0x1F}, | |
}, | |
# Feature 0x04 - Stations | |
None, # TODO | |
# Feature 0x05 - Canals | |
{ | |
# 08 (callback flags) not set by user | |
"graphic_flags": {"size": 1, "num": 0x09}, | |
}, | |
# Feature 0x06 - Bridges | |
None, # TODO | |
# Feature 0x07 - Houses | |
{ | |
"substitute": {"size": 1, "num": 0x08, "multitile_function": mt_house_old_id, "first": None}, | |
"building_flags": two_byte_property( | |
0x09, | |
0x19, | |
{"multitile_function": mt_house_prop09}, | |
{"multitile_function": lambda *args: mt_house_mask(0xFE, *args)}, | |
), | |
"years_available": [ | |
{"size": 2, "num": 0x0A, "multitile_function": mt_house_zero, "value_function": house_prop_0A}, | |
{ | |
"size": 2, | |
"num": 0x21, | |
"multitile_function": mt_house_zero, | |
"value_function": lambda value: house_prop_21_22(value, 0), | |
}, | |
{ | |
"size": 2, | |
"num": 0x22, | |
"multitile_function": mt_house_zero, | |
"value_function": lambda value: house_prop_21_22(value, 1), | |
}, | |
], | |
"population": {"size": 1, "num": 0x0B, "multitile_function": mt_house_zero}, | |
"mail_multiplier": {"size": 1, "num": 0x0C, "multitile_function": mt_house_zero}, | |
# prop 0D - 0F are replaced by prop 23 | |
"local_authority_impact": {"size": 2, "num": 0x10, "multitile_function": mt_house_same}, | |
"removal_cost_multiplier": {"size": 1, "num": 0x11, "multitile_function": mt_house_same}, | |
"name": {"size": 2, "num": 0x12, "string": 0xDC, "multitile_function": mt_house_same}, | |
"availability_mask": { | |
"size": 2, | |
"num": 0x13, | |
"multitile_function": mt_house_zero, | |
"value_function": house_available_mask, | |
}, | |
# prop 14 (callback flags 1) is not set by user | |
"override": {"size": 1, "num": 0x15, "multitile_function": mt_house_old_id}, | |
"refresh_multiplier": {"size": 1, "num": 0x16, "multitile_function": mt_house_same}, | |
"random_colours": { | |
"size": 4, | |
"num": 0x17, | |
"multitile_function": mt_house_same, | |
"value_function": house_random_colours, | |
}, | |
"probability": {"size": 1, "num": 0x18, "multitile_function": mt_house_zero, "unit_conversion": 16}, | |
# prop 19 is the high byte of prop 09 | |
"animation_info": { | |
"size": 1, | |
"num": 0x1A, | |
"multitile_function": mt_house_same, | |
"value_function": lambda value: animation_info(value, 7, 128), | |
}, | |
"animation_speed": {"size": 1, "num": 0x1B, "multitile_function": mt_house_same}, | |
"building_class": {"size": 1, "num": 0x1C, "multitile_function": mt_house_class}, | |
# prop 1D (callback flags 2) is not set by user | |
# prop 1E is replaced by prop 23 | |
"minimum_lifetime": {"size": 1, "num": 0x1F, "multitile_function": mt_house_zero}, | |
"watched_cargo_types": { | |
"multitile_function": mt_house_same, | |
"custom_function": lambda *values: ctt_list(0x20, *values), | |
}, | |
# prop 21 -22 see above (years_available, prop 0A) | |
"accepted_cargos": { | |
"multitile_function": mt_house_same, | |
"custom_function": lambda *values: accepted_cargos(0x23, *values), | |
}, | |
}, | |
# Feature 0x08 - General Vars | |
None, # Implemented elsewhere (e.g. basecost, snowline) | |
# Feature 0x09 - Industry Tiles | |
{ | |
"substitute": {"size": 1, "num": 0x08, "first": None}, | |
"override": {"size": 1, "num": 0x09}, | |
# prop 0A - 0C are replaced by prop 13 | |
"land_shape_flags": {"size": 1, "num": 0x0D}, | |
# prop 0E (callback flags) is not set by user | |
"animation_info": {"size": 2, "num": 0x0F, "value_function": animation_info}, | |
"animation_speed": {"size": 1, "num": 0x10}, | |
"animation_triggers": {"size": 1, "num": 0x11}, | |
"special_flags": {"size": 1, "num": 0x12}, | |
"accepted_cargos": {"custom_function": lambda value: accepted_cargos(0x13, value)}, | |
}, | |
# Feature 0x0A - Industries | |
{ | |
"substitute": {"size": 1, "num": 0x08, "first": None}, | |
"override": {"size": 1, "num": 0x09}, | |
"layouts": {"custom_function": industry_layouts}, # = prop 0A | |
"life_type": {"size": 1, "num": 0x0B}, | |
"closure_msg": {"size": 2, "num": 0x0C, "string": 0xDC}, | |
"prod_increase_msg": {"size": 2, "num": 0x0D, "string": 0xDC}, | |
"prod_decrease_msg": {"size": 2, "num": 0x0E, "string": 0xDC}, | |
"fund_cost_multiplier": {"size": 1, "num": 0x0F}, | |
"prod_cargo_types": { | |
"size": 2, | |
"num": 0x10, | |
"value_function": lambda value: cargo_list(value, 2), | |
"replaced_by": "cargo_types", | |
}, | |
"accept_cargo_types": { | |
"size": 4, | |
"num": 0x11, | |
"value_function": lambda value: cargo_list(value, 3), | |
"replaced_by": "cargo_types", | |
}, | |
"prod_multiplier": {"custom_function": industry_prod_multiplier, "replaced_by": "cargo_types"}, # = prop 12,13 | |
"min_cargo_distr": {"size": 1, "num": 0x14}, | |
"random_sound_effects": {"custom_function": random_sounds}, # = prop 15 | |
"conflicting_ind_types": {"custom_function": industry_conflicting_types}, # = prop 16 | |
"prob_random": {"size": 1, "num": 0x17}, # Obsolete, ambiguous name, use "prob_map_gen" instead | |
"prob_map_gen": {"size": 1, "num": 0x17}, | |
"prob_in_game": {"size": 1, "num": 0x18}, | |
"map_colour": {"size": 1, "num": 0x19}, | |
"spec_flags": {"size": 4, "num": 0x1A}, | |
"new_ind_msg": {"size": 2, "num": 0x1B, "string": 0xDC}, | |
"input_multiplier_1": { | |
"custom_function": lambda value: industry_input_multiplier(value, 0x1C), | |
"replaced_by": "cargo_types", | |
}, | |
"input_multiplier_2": { | |
"custom_function": lambda value: industry_input_multiplier(value, 0x1D), | |
"replaced_by": "cargo_types", | |
}, | |
"input_multiplier_3": { | |
"custom_function": lambda value: industry_input_multiplier(value, 0x1E), | |
"replaced_by": "cargo_types", | |
}, | |
"name": {"size": 2, "num": 0x1F, "string": 0xDC}, | |
"prospect_chance": {"size": 4, "num": 0x20, "unit_conversion": 0xFFFFFFFF}, | |
# prop 21, 22 (callback flags) are not set by user | |
"remove_cost_multiplier": {"size": 4, "num": 0x23}, | |
"nearby_station_name": {"size": 2, "num": 0x24, "string": 0xDC}, | |
"cargo_types": {"custom_function": industry_cargo_types}, # = prop 25+26+27+28 combined in one structure | |
}, | |
# Feature 0x0B - Cargoes | |
{ | |
"number": {"num": 0x08, "size": 1}, | |
"type_name": {"num": 0x09, "size": 2, "string": 0xDC}, | |
"unit_name": {"num": 0x0A, "size": 2, "string": 0xDC}, | |
# Properties 0B, 0C are not used by OpenTTD | |
"type_abbreviation": {"num": 0x0D, "size": 2, "string": 0xDC}, | |
"sprite": {"num": 0x0E, "size": 2}, | |
"weight": {"num": 0x0F, "size": 1, "unit_type": "weight", "unit_conversion": 16}, | |
"penalty_lowerbound": {"num": 0x10, "size": 1}, | |
"single_penalty_length": {"num": 0x11, "size": 1}, | |
"price_factor": { | |
"num": 0x12, | |
"size": 4, | |
"unit_conversion": (1 << 21, 10 * 20 * 255), | |
}, # 10 units of cargo across 20 tiles, with time factor = 255 | |
"station_list_colour": {"num": 0x13, "size": 1}, | |
"cargo_payment_list_colour": {"num": 0x14, "size": 1}, | |
"is_freight": {"num": 0x15, "size": 1}, | |
"cargo_classes": {"num": 0x16, "size": 2}, | |
"cargo_label": {"num": 0x17, "size": 4, "string_literal": 4}, | |
"town_growth_effect": {"num": 0x18, "size": 1}, | |
"town_growth_multiplier": {"num": 0x19, "size": 2, "unit_conversion": 0x100}, | |
# 1A (callback flags) is not set by user | |
"units_of_cargo": {"num": 0x1B, "size": 2, "string": 0xDC}, | |
"items_of_cargo": {"num": 0x1C, "size": 2, "string": 0xDC}, | |
"capacity_multiplier": {"num": 0x1D, "size": 2, "unit_conversion": 0x100}, | |
}, | |
# Feature 0x0C - Sounds | |
None, # Implemented differently | |
# Feature 0x0D - Airports | |
{ | |
"override": {"size": 1, "num": 0x08, "first": None}, | |
# 09 does not exist | |
"layouts": {"custom_function": airport_layouts}, # = prop 0A | |
# 0B does not exist | |
"years_available": {"custom_function": airport_years}, # = prop 0C | |
"ttd_airport_type": {"size": 1, "num": 0x0D}, | |
"catchment_area": {"size": 1, "num": 0x0E}, | |
"noise_level": {"size": 1, "num": 0x0F}, | |
"name": {"size": 2, "num": 0x10, "string": 0xDC}, | |
"maintenance_cost": {"size": 2, "num": 0x11}, | |
}, | |
# Feature 0x0E - Signals | |
None, # No action0 | |
# Feature 0x0F - Objects | |
{ | |
"class": {"size": 4, "num": 0x08, "first": None, "string_literal": 4}, | |
# strings might be according to specs be either 0xD0 or 0xD4 | |
"classname": {"size": 2, "num": 0x09, "string": 0xD0}, | |
"name": {"size": 2, "num": 0x0A, "string": 0xD0}, | |
"climates_available": {"size": 1, "num": 0x0B}, | |
"size": {"custom_function": object_size}, # = prop 0C | |
"build_cost_multiplier": {"size": 1, "num": 0x0D}, | |
"introduction_date": {"size": 4, "num": 0x0E}, | |
"end_of_life_date": {"size": 4, "num": 0x0F}, | |
"object_flags": {"size": 2, "num": 0x10}, | |
"animation_info": {"size": 2, "num": 0x11, "value_function": animation_info}, | |
"animation_speed": {"size": 1, "num": 0x12}, | |
"animation_triggers": {"size": 2, "num": 0x13}, | |
"remove_cost_multiplier": {"size": 1, "num": 0x14}, | |
# 15 (callback flags) is not set by user | |
"height": {"size": 1, "num": 0x16}, | |
"num_views": {"size": 1, "num": 0x17}, | |
"count_per_map256": {"size": 1, "num": 0x18}, | |
}, | |
# Feature 0x10 - Rail Types | |
{ | |
**common_tracktype_props, | |
"compatible_railtype_list": {"custom_function": lambda x: label_list(x, 0x0E, "Railtype")}, | |
"powered_railtype_list": {"custom_function": lambda x: label_list(x, 0x0F, "Railtype")}, | |
"railtype_flags": {"size": 1, "num": 0x10}, | |
"curve_speed_multiplier": {"size": 1, "num": 0x11}, | |
"station_graphics": {"size": 1, "num": 0x12}, | |
"speed_limit": { | |
"size": 2, | |
"num": 0x14, | |
"unit_type": "speed", | |
"unit_conversion": (5000, 1397), | |
"adjust_value": lambda val, unit: ottd_display_speed(val, 1, 1, unit), | |
}, | |
"acceleration_model": {"size": 1, "num": 0x15}, | |
"requires_railtype_list": {"custom_function": lambda x: label_list(x, 0x18, "Railtype")}, | |
"introduces_railtype_list": {"custom_function": lambda x: label_list(x, 0x19, "Railtype")}, | |
"alternative_railtype_list": {"custom_function": lambda x: label_list(x, 0x1D, "Railtype")}, | |
}, | |
# Feature 0x11 - Airport tiles | |
{ | |
"substitute": {"size": 1, "num": 0x08, "first": None}, | |
"override": {"size": 1, "num": 0x09}, | |
# 0A - 0D don"t exist (yet?) | |
# 0E (callback flags) is not set by user | |
"animation_info": {"size": 2, "num": 0x0F, "value_function": animation_info}, | |
"animation_speed": {"size": 1, "num": 0x10}, | |
"animation_triggers": {"size": 1, "num": 0x11}, | |
}, | |
# Feature 0x12 - Road Types | |
{ | |
**common_tracktype_props, | |
"powered_roadtype_list": {"custom_function": lambda x: label_list(x, 0x0F, "Roadtype")}, | |
"roadtype_flags": {"size": 1, "num": 0x10}, | |
"speed_limit": { | |
"size": 2, | |
"num": 0x14, | |
"unit_type": "speed", | |
"unit_conversion": (10000, 1397), | |
"adjust_value": lambda val, unit: ottd_display_speed(val, 1, 2, unit), | |
}, | |
"requires_roadtype_list": {"custom_function": lambda x: label_list(x, 0x18, "Roadtype")}, | |
"introduces_roadtype_list": {"custom_function": lambda x: label_list(x, 0x19, "Roadtype")}, | |
"alternative_roadtype_list": {"custom_function": lambda x: label_list(x, 0x1D, "Roadtype")}, | |
}, | |
# Feature 0x13 - Tram Types | |
{ | |
**common_tracktype_props, | |
"powered_tramtype_list": {"custom_function": lambda x: label_list(x, 0x0F, "Tramtype")}, | |
"tramtype_flags": {"size": 1, "num": 0x10}, | |
"speed_limit": { | |
"size": 2, | |
"num": 0x14, | |
"unit_type": "speed", | |
"unit_conversion": (10000, 1397), | |
"adjust_value": lambda val, unit: ottd_display_speed(val, 1, 2, unit), | |
}, | |
"requires_tramtype_list": {"custom_function": lambda x: label_list(x, 0x18, "Tramtype")}, | |
"introduces_tramtype_list": {"custom_function": lambda x: label_list(x, 0x19, "Tramtype")}, | |
"alternative_tramtype_list": {"custom_function": lambda x: label_list(x, 0x1D, "Tramtype")}, | |
}, | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment