Exemple #1
0
# Game settings.
game_settings = "game_settings" / Struct(
    Array(16, AgeEnum("starting_ages" / Int32sl)), 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, Padding(29)),
    Array(
        9, "player_info" /
        Struct("data_ref" / Int32ul, PlayerTypeEnum("type" / Int32ul),
               "name" / PascalString(lengthfield="name_length" / Int32ul))),
    Padding(36), Padding(4),
    IfThenElse(
        lambda ctx: ctx._._.version == Version.DE, "end_of_game_settings" /
        Find(b'\x9a\x99\x99\x99\x99\x99\x01\x40', None), "end_of_game_settings"
        / Find(b'\x9a\x99\x99\x99\x99\x99\xf9\x3f', None)))

# Triggers.
triggers = "triggers" / Struct(
    Padding(1),
    "num_triggers" / Int32ul,
    # parse if num > 0
    If(lambda ctx: ctx._._.version == Version.DE, Padding(1032)))

# Scenario metadata.
scenario = "scenario" / Struct(
    scenario_header,
    messages,
    scenario_players,
    victory,
Exemple #2
0
# Objects that exist on the map at the start of the recorded game
existing_object = "objects" / Struct(
    "type" / Byte,
    "player_id" / Byte,
    Embedded("properties" / Switch(lambda ctx: ctx.type, {
        10: static,
        20: animated,
        25: animated,
        30: moving,
        40: action,
        50: base_combat,
        60: missile,
        70: combat,
        80: building,
        90: static
    },
                                   default=Pass)),
)

# Default values for objects, nothing of real interest
default_object = "default_object" / Struct(
    ObjectTypeEnum("type" / Byte), Padding(14),
    "properties" / Switch(lambda ctx: ctx.type, {
        "gaia": Padding(24),
        "object": Padding(32),
        "fish": Padding(32),
        "other": Padding(28),
    },
                          default="end_of_object" / Find(b'\x21\x16', 200)))
Exemple #3
0
    # The following sections can be refined with further research.
    # There are clearly some patterns.
    "has_extra"/Byte,
    If(lambda ctx: ctx.has_extra == 2, Padding(
        34
    )),
    Padding(4)
)

# Units - typically villagers, scout, and any sheep within LOS
unit = "unit"/Struct(
    Embedded(existing_object_header),
    # Not pretty, but we don't know how to parse a unit yet.
    # Also, this only works on non-restored games.
    # This isn't a constant footer, these are actually initial values of some sort.
    "end_of_unit"/Find(b'\xff\xff\xff\xff\x00\x00\x80\xbf\x00\x00\x80\xbf\xff\xff\xff' \
                       b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00', None)
)

# Buildings - ID doesn't match Build action ID - buildings can have multiple parts
building = "building"/Struct(
    Embedded(existing_object_header),
    Padding(32),
    # The following sections can be refined with further research.
    # There are clearly some patterns.
    "has_extra"/Byte,
    If(lambda ctx: ctx.has_extra == 2, Padding(
        17
    )),
    Padding(16),
    "has_extra2"/Byte,
    If(lambda ctx: ctx.has_extra2 == 1, Padding(
Exemple #4
0
                        lambda ctx: ctx.num_saved_views, "saved_view" /
                        Struct("camera_x" / Float32l, "camera_y" / Float32l))),
            ))),
    "spawn_location" / Struct("x" / Int16ul, "y" / Int16ul),
    "culture" / Byte,
    "civilization" / Byte,
    "game_status" / Byte,
    "resigned" / Flag,
    Padding(1),
    "player_color" / Byte,
    Padding(1))

# Initial state of players, including Gaia.
player = "players" / Struct(
    "type" / Byte, "unk" / Byte, attributes, "end_of_attr" / Tell,
    "start_of_objects" / Find(b'\x0b\x00\x08\x00\x00\x00\x02\x00\x00', None),
    Embedded("x" / Struct("end_of_objects" / GotoObjectsEnd(),
                          Array(0, existing_object))))
x = Struct(
    "start_of_objects" / Find(b'\x0b\x00\x08\x00\x00\x00\x02\x00\x00', None),
    # If this isn't a restored game, we can read all the existing objects
    Embedded("not_restored" / If(
        this._.restore_time == 0 and this._._.version != Version.DE,
        Struct(
            RepeatUpTo(b'\x00', existing_object),
            Padding(14),
            "eoo" / Tell,
            "end_of_objects" /
            GotoObjectsEnd()  # Find the objects end just in case
        ))),
    # Can't parse existing objects in a restored game, skip the whole structure
Exemple #5
0
    "civilization" / Byte,
    "game_status" / Byte,
    "resigned" / Flag,
    Padding(1),
    "player_color" / Byte,
    Padding(1),
)

# Initial state of players, including Gaia.
player = "players" / Struct(
    "type" / Byte,
    "unk" / Byte,
    attributes,
    "end_of_attr" / Tell,
    "start_of_objects" / Find([
        b'\x0b\x00\x08\x00\x00\x00\x02\x00\x00',
        b'\x0b\x00\x0e\x00\x00\x00\x02\x00\x00'
    ], None),
    Embedded(
        IfThenElse(
            lambda ctx: ctx._.restore_time == 0,
            Struct(
                "objects" / RepeatUpTo(b'\x00', existing_object),
                Const(b'\x00\x0b'),
                # Skip Gaia trees for performance reasons
                Embedded(
                    IfThenElse(
                        this._.type != 2,
                        Struct(
                            "s_size" / Int32ul, "s_grow" / Int32ul,
                            "sleeping_objects" /
                            RepeatUpTo(b'\x00', existing_object),
        Array(
            lambda ctx: ctx.num_saved_views, "saved_view" /
            Struct("camera_x" / Float32l, "camera_y" / Float32l))),
    "map_size" / Struct("x" / Int16ul, "y" / Int16ul),
    "culture" / Byte,
    "civilization" / Byte,
    "game_status" / Byte,
    "resigned" / Flag,
    Padding(1),
    "player_color" / Byte,
    Padding(1))

# Initial state of players, including Gaia.
player = "players" / Struct(
    attributes,
    "start_of_objects" / Find(b'\x0b\x00\x08\x00\x00\x00\x02\x00\x00', None),
    # If this isn't a restored game, we can read all the existing objects
    Embedded("not_restored" / If(
        this._.restore_time == 0,
        Struct(
            RepeatUpTo(b'\x00', existing_object),
            Padding(14),
            "end_of_objects" /
            GotoObjectsEnd()  # Find the objects end just in case
        ))),

    # Can't parse existing objects in a restored game, skip the whole structure
    Embedded("is_restored" / If(
        this._.restore_time > 0,
        Struct(
            "end_of_objects" / GotoObjectsEnd(),
Exemple #7
0
            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(
        9, "player_info" /
        Struct("data_ref" / Int32ul, PlayerTypeEnum("type" / Int32ul),
               "name" / PascalString(lengthfield="name_length" / Int32ul))),
    Padding(36), Padding(4),
    IfThenElse(
        lambda ctx: ctx._._.version == Version.DE,
        Struct(
            If(lambda ctx: find_save_version(ctx) < 13.34,
               Find(struct.pack('<d', 2.2), None)),
            If(lambda ctx: 25.06 > find_save_version(ctx) >= 13.34,
               Find(struct.pack('<d', 2.4), None)),
            If(lambda ctx: 25.22 > find_save_version(ctx) >= 25.06,
               Find(struct.pack('<d', 2.5), None)),
            If(lambda ctx: 26.16 > find_save_version(ctx) >= 25.22,
               Find(struct.pack('<d', 2.6), None)),
            If(lambda ctx: find_save_version(ctx) >= 26.16,
               Find(struct.pack('<d', 3.0), None))), "end_of_game_settings" /
        Find(b'\x9a\x99\x99\x99\x99\x99\xf9\\x3f', None)))

# Triggers.
triggers = "triggers" / Struct(
    Padding(1),
    "num_triggers" / Int32ul,
    # parse if num > 0
Exemple #8
0
 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),
     Find(b'`\n\x00\x00`\n\x00\x00', 1000), # Skip a large unparseable block that (likely) contains RMS-modified object data
     Bytes(2)
 ), Struct(
     "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_extension"/If(lambda ctx: find_version(ctx) == Version.DE, Struct(
         "particles"/Array(5, particle),
         If(lambda ctx: find_save_version(ctx) >= 13.15, Bytes(5)),
         If(lambda ctx: find_save_version(ctx) >= 13.17, Bytes(2)),
         If(lambda ctx: find_save_version(ctx) >= 13.34, Struct(
             Bytes(2),
             de_string,
             de_string,
             Bytes(2)
         ))
     ))
Exemple #9
0
            If(lambda ctx: find_save_version(ctx) >= 25.06, Padding(4)),
        )),
    Array(
        9, "player_info" /
        Struct("data_ref" / Int32ul, PlayerTypeEnum("type" / Int32ul),
               "name" / PascalString(lengthfield="name_length" / Int32ul))),
    Padding(36),
    Padding(4),
    IfThenElse(
        lambda ctx: ctx._._.version == Version.DE,
        IfThenElse(
            lambda ctx: find_save_version(ctx) >= 13.34,
            IfThenElse(
                lambda ctx: find_save_version(ctx) >= 25.06,
                "end_of_game_settings" /
                Find(b'\x00\x00\x00\x00\x00\x00\x04\x40', None),  # double: 2.5
                "end_of_game_settings" /
                Find(b'\x33\x33\x33\x33\x33\x33\x03\x40', None)  # double: 2.4
            ),
            "end_of_game_settings" /
            Find(b'\x9a\x99\x99\x99\x99\x99\x01\x40', None)  # double: 2.2
        ),
        "end_of_game_settings" /
        Find(b'\x9a\x99\x99\x99\x99\x99\xf9\\x3f', None)  # double: 1.6
    ))

# Triggers.
triggers = "triggers" / Struct(
    Padding(1),
    "num_triggers" / Int32ul,
    # parse if num > 0
Exemple #10
0
    Array(
        this.num_rules, "rules" / Struct(
            Padding(12), "num_facts" / Byte, "num_facts_actions" / Byte,
            Padding(2),
            Array(
                16, "data" / Struct("type" / Int32ul, "id" / Int16ul, Padding(
                    2), Array(4, "params" / Int32ul))))))

ai = "ai" / Struct(
    "has_ai" / Int32ul,  # if true, parse AI
    "yep" / If(
        this.has_ai == 1,
        IfThenElse(
            lambda ctx: ctx._.version == Version.DE,
            Find(
                b'\00' * 4096, None
            ),  # The ai structure in DE seems to have changed, for now we simply skip it
            "ais" / Struct(
                "max_strings" / Int16ul,
                "num_strings" / Int16ul,
                Padding(4),
                Array(
                    this.num_strings, "strings" /
                    PascalString(lengthfield="name_length" / Int32ul,
                                 encoding='latin1')),
                Padding(6),
                Array(8, script),
                Padding(104),
                Array(80, "timers" / Int32sl),
                Array(256, "shared_goals" / Int32sl),
                Padding(4096),