sprite_list = "sprite_list" / Struct( "type" / Byte, "active" / If(lambda ctx: ctx.type != 0, active_sprite), "animated" / If(lambda ctx: ctx.type == 2, animated_sprite), Embedded( If(lambda ctx: ctx.type != 0, Struct("order" / Byte, "flag" / Byte, "count" / Byte)))) static = "static" / Struct( "object_type" / Int16ul, "sprite" / Int16ul, "garrisoned_in_id" / Int32sl, "hitpoints" / Float32l, "object_state" / Byte, "sleep" / Flag, "doppleganger" / Flag, "go_to_sleep" / Flag, "object_id" / Int32ul, "facet" / Byte, "x" / Float32l, "y" / Float32l, "z" / Float32l, "screen_offset_x" / Int16ul, "screen_offset_y" / Int16ul, "shadow_offset_x" / Int16ul, "shadow_offset_y" / Int16ul, "selected_group" / If(lambda ctx: find_version(ctx) == Version.AOK, Byte), ResourceEnum("resource_type" / Int16sl), "amount" / Float32l, "worker_count" / Byte, "current_damage" / Byte, "damaged_lately_timer" / Byte, "under_attack" / Byte, "pathing_group_len" / Int32ul, "pathing_group" / Array(lambda ctx: ctx.pathing_group_len, "object_id" / Int32ul), "group_id" / Int32sl, "roo_already_called" / Byte, "de_static_unk1" / If(lambda ctx: find_version(ctx) == Version.DE, Bytes(19)), "has_sprite_list" / Byte, "sprite_list" / If(lambda ctx: ctx.has_sprite_list != 0, RepeatUntil(lambda x, lst, ctx: lst[-1].type == 0, sprite_list)), "de_effect_block" / If( lambda ctx: find_version(ctx) == Version.DE, Struct( Padding(4), "has_effect" / Byte, "effect" / If( lambda ctx: ctx.has_effect == 1, Struct(Padding(3), "length" / Int16ul,
"train_sound" / Int16ul, "damage_sound" / Int16ul, "death_spawn" / Int16ul, "sort_number" / Byte, "can_be_built_on" / Byte, "button_picture" / Int16ul, "hide_in_editor" / Byte, "portrait" / Int16ul, "enabled" / Byte, "disabled" / Byte, "tile_req" / Struct("x" / Int16ul, "y" / Int16ul), "center_tile_req" / Struct("x" / Int16ul, "y" / Int16ul), "construction_radius" / Struct("x" / Float32l, "y" / Float32l), "elevation_flag" / Byte, "fog_flag" / Byte, "terrain_restriction_id" / Int16ul, "movement_type" / Byte, "attribute_max" / Int16ul, "attribute_rot" / Float32l, "area_effect_level" / Byte, "combat_level" / Byte, "select_level" / Byte, "map_draw_level" / Byte, "unit_level" / Byte, "multiple_attribute_mod" / Float32l, "map_color" / Byte, "help_string_id" / Int32ul, "help_page_id" / Int32ul, "hotkey_id" / Int32ul, "recyclable" / Byte, "track_as_resource" / Byte, "create_doppleganger" / Byte, "resource_group" / Byte, "occlusion_mask" / Byte, "obstruction_type" / Byte, "selection_shape" / Byte, "object_flags" / If(lambda ctx: find_version(ctx) != Version.AOK, Int32ul), "civilization" / Byte, "attribute_piece" / Byte, "outline_radius" / Struct("x" / Float32l, "y" / Float32l, "z" / Float32l), "attributes" / Array(3, attribute), "num_damage_sprites" / Byte, "damage_sprites" / Array(this.num_damage_sprites, damage_sprite), "selected_sound" / Int16ul, "death_sound" / Int16ul, "attack_reaction" / Byte, "convert_terrain_flag" / Byte, "name" / String(this.name_len), "copy_id" / Int16ul, "group" / Int16ul) animated = "animated" / Struct(base, "speed" / Float32l) moving = "moving" / Struct( animated, "move_sprite" / Int16ul, "run_sprite" / Int16ul, "turn_speed" / Float32l, "size_class" / Byte, "trailing_unit" / Int16ul, "trailing_options" / Byte, "trailing_spacing" / Float32l, "move_algorithm" / Byte, "turn_radius" / Float32l,
lambda ctx: ctx._._.version != Version.DE, Struct( Array(16, "num_disabled_techs" / Int32ul), Array(16, Array(30, Padding(4))), Array(16, "num_disabled_units" / Int32ul), Array(16, Array(30, Padding(4))), Array(16, "num_disabled_buildings" / Int32ul), Array(16, Array(20, Padding(4))), )), If(lambda ctx: ctx._._.version == Version.DE, Bytes(196)), If(lambda ctx: ctx._._.version == Version.HD, Bytes(644)), "padding" / Bytes(12)) # Game settings. game_settings = "game_settings" / Struct( Array(16, AgeEnum("starting_ages" / Int32sl)), "hd" / If(lambda ctx: find_version(ctx) == Version.HD, Bytes(16)), Padding(4), Padding(8), "map_id" / If(lambda ctx: ctx._._.version != Version.AOK, Int32ul), Peek("difficulty_id" / Int32ul), DifficultyEnum( "difficulty" / Int32ul), "lock_teams" / Int32ul, If( lambda ctx: ctx._._.version == Version.DE, Struct( Padding(29), If(lambda ctx: find_save_version(ctx) >= 13.07, Padding(1)), If(lambda ctx: find_save_version(ctx) >= 13.34, Padding(132)), If(lambda ctx: find_save_version(ctx) >= 20.06, Padding(1)), If(lambda ctx: find_save_version(ctx) >= 20.16, Padding(4)), If(lambda ctx: find_save_version(ctx) >= 25.02, Padding(4 * 16)), If(lambda ctx: find_save_version(ctx) >= 25.06, Padding(4)))), Array(
"wood_score" / Float32l, "stone_score" / Float32l, "gold_score" / Float32l, Embedded( If( lambda ctx: find_save_version(ctx) >= 11.76, Struct( "wood_bonus0" / Float32l, "food_bonus0" / Float32l, "relic_rate" / Float32l, "heresy" / Float32l, "theocracy" / Float32l, "crenellations" / Float32l, "construction_rate_mod" / Float32l, "hun_wonder_bonus" / Float32l, "spies_discount" / Float32l, ))), Embedded( If(lambda ctx: find_version(ctx) in (Version.DE, Version.HD), Struct(Array(this._._.num_header_data - 198, Float32l)))), Embedded( If( lambda ctx: find_version(ctx) in [Version.USERPATCH15, Version.MCP], Struct(ModVersionAdapter("mod" / Float32l), Array( 6, Float32l), "trickle_food" / Float32l, "trickle_wood" / Float32l, "trickle_stone" / Float32l, "trickle_gold" / Float32l, "reveal_enemy_tcs" / Float32l, "reveal_gaia_class_1" / Float32l, "reveal_gaia_class_2" / Float32l, Array(28, Float32l)))), Embedded( If(this._._._._.version == Version.MCP, Struct(Array(65, Float32l)))))
"garrisoned_in_id"/Int32sl, "hitpoints"/Float32l, "object_state"/Byte, "sleep"/Flag, "doppleganger"/Flag, "go_to_sleep"/Flag, "object_id"/Int32ul, "facet"/Byte, "x"/Float32l, "y"/Float32l, "z"/Float32l, "screen_offset_x"/Int16ul, "screen_offset_y"/Int16ul, "shadow_offset_x"/Int16ul, "shadow_offset_y"/Int16ul, "selected_group"/If(lambda ctx: find_version(ctx) == Version.AOK, Byte), ResourceEnum("resource_type"/Int16sl), "amount"/Float32l, "worker_count"/IfThenElse(lambda ctx: find_save_version(ctx) == 12.36, Int32ul, Byte), "current_damage"/Byte, "damaged_lately_timer"/Byte, "under_attack"/Byte, "pathing_group_len"/Int32ul, "pathing_group"/Array(lambda ctx: ctx.pathing_group_len, "object_id"/Int32ul), "group_id"/Int32sl, "roo_already_called"/Byte, "de_static_unk1"/If(lambda ctx: find_version(ctx) == Version.DE, Bytes(17)), If(lambda ctx: find_save_version(ctx) >= 26.16, Byte), "de_has_object_props"/If(lambda ctx: find_version(ctx) == Version.DE, Int16ul), "de_object_props"/IfThenElse(lambda ctx: ctx.de_has_object_props == 1, Struct( Bytes(162),
"wood_score" / Float32l, "stone_score" / Float32l, "gold_score" / Float32l, Embedded( If( lambda ctx: find_save_version(ctx) >= 11.76, Struct( "wood_bonus0" / Float32l, "food_bonus0" / Float32l, "relic_rate" / Float32l, "heresy" / Float32l, "theocracy" / Float32l, "crenellations" / Float32l, "construction_rate_mod" / Float32l, "hun_wonder_bonus" / Float32l, "spies_discount" / Float32l, ))), Embedded( If(lambda ctx: find_version(ctx) == Version.DE, Struct(Array(this._._.num_header_data - 198, Float32l)))), Embedded( If( lambda ctx: find_version(ctx) in [Version.USERPATCH15, Version.MCP], Struct(ModVersionAdapter("mod" / Float32l), Array( 6, Float32l), "trickle_food" / Float32l, "trickle_wood" / Float32l, "trickle_stone" / Float32l, "trickle_gold" / Float32l, "reveal_enemy_tcs" / Float32l, "reveal_gaia_class_1" / Float32l, "reveal_gaia_class_2" / Float32l, Array(28, Float32l)))), Embedded( If(this._._._._.version == Version.MCP, Struct(Array(65, Float32l)))))
"garrisoned_in_id" / Int32sl, "hitpoints" / Float32l, "object_state" / Byte, "sleep" / Flag, "doppleganger" / Flag, "go_to_sleep" / Flag, "object_id" / Int32ul, "facet" / Byte, "x" / Float32l, "y" / Float32l, "z" / Float32l, "screen_offset_x" / Int16ul, "screen_offset_y" / Int16ul, "shadow_offset_x" / Int16ul, "shadow_offset_y" / Int16ul, "selected_group" / If(lambda ctx: find_version(ctx) == Version.AOK, Byte), ResourceEnum("resource_type" / Int16sl), "amount" / Float32l, "worker_count" / IfThenElse(lambda ctx: find_save_version(ctx) == 12.36, Int32ul, Byte), "current_damage" / Byte, "damaged_lately_timer" / Byte, "under_attack" / Byte, "pathing_group_len" / Int32ul, "pathing_group" / Array(lambda ctx: ctx.pathing_group_len, "object_id" / Int32ul), "group_id" / Int32sl, "roo_already_called" / Byte, "de_static_unk1" / If(lambda ctx: find_version(ctx) == Version.DE, Bytes(19)), "has_sprite_list" / Byte,