def discard_extra_map_stuff(data: ScnDataReader): data.mark("Extra map stuff") # NB: Values from genie-rs skip way past random map data in AOE1 files. # data.int32(debug='_map_row_offset') # data.float32(debug='_map_min_x') # data.float32(debug='_map_min_y') # data.float32(debug='_map_max_x') # data.float32(debug='_map_max_y') # data.float32(debug='_map_max_x') # data.float32(debug='_map_max_y') # data.uint16(debug='_additional_terrain_count') # data.uint16(debug='_borders_used') # data.uint16(debug='_max_terrain') # data.uint16(debug='_tile_width') # data.uint16(debug='_tile_height') # data.uint16(debug='_tile_half_width') # data.uint16(debug='_tile_half_height') # data.uint16(debug='_elev_height') # data.uint16(debug='_current_row') # data.uint16(debug='_current_column') # data.uint16(debug='_block_begin_row') # data.uint16(debug='_block_end_row') # data.uint16(debug='_block_begin_column') # data.uint16(debug='_block_end_column') # data.int32(debug='_seach_map_pointer') # data.int32(debug='_seach_map_rows_pointer') # data.uint8(debug='_any_frame_change') # data.uint8(debug='_map_visible') # data.uint8(debug='_map_fog_of_war') # data.read(21 + 157 * 4) data.read(68)
def read_de(data: ScnDataReader): base = ScnEngineProperties.read_de(data) # expecting global victory conditions around here somewhere for i in range(0, 8): data.uint32(debug='unknown value a {}'.format(i)) data.uint32(debug='unknown value b') # 900 data.uint32(debug='unknown value c') # 9000 # expecting diplomacy for i in range(0, 16): for j in range(0, 16): val = data.uint32() logging.debug("Unknown value from=%d to=%d val=%d", i, j, val) # lots of '3'. # expecting 12 individual victory conditions for each player for i in range(0, 16): for j in range(0, 12): # TODO read these ??? data.read(60) check3 = data.int32(debug='check value 3') if check3 != -99: raise Exception( "Check value did not match in scenario data, giving up") # Probably allied victory for i in range(0, 16): data.uint32(debug='allied victory player {}'.format(i)) # disabled tech for i in range(0, 16): for j in range(0, 20): disabled_tech_id = data.uint32() logging.debug("Disabled tech player %d, position %d: %d", i, j, disabled_tech_id) data.uint32(debug='unknown field 1') data.uint32(debug='unknown field 2') data.uint32(debug='unknown field 3') # might be full tech tree for j in range(0, 16): # maybe ? data.uint32(debug='starting age player {}'.format(j)) check4 = data.int32(debug='check value 2') if check4 != -99: raise Exception( "Check value did not match in scenario data, giving up") # view ? data.float32() data.float32() game_properties = ScnGameProperties(base) logging.debug(game_properties) return game_properties
def load(file_name: str): if not (file_name.endswith(".slp")): raise Exception("SLP file must end with .slp") with open(file_name, 'rb') as f: all_data = f.read() data = ScnDataReader(all_data) header = SlpHeader.read(data) frames = [] for i in range(0, header.frames): data.mark('frame {}'.format(i)) frame_info = SlpFrameInfo.read(data) # Sub-reader for outline data (identified by offset) outline_region_start = frame_info.outline_table_offset outline_region_end = outline_region_start + frame_info.height * 4 outline_reader = ScnDataReader( all_data[outline_region_start:outline_region_end]) frame_outline = SlpOutline.read(outline_reader, frame_info.height) # Sub-reader for pixel offsets command_offset_region_start = frame_info.command_table_offset command_offset_region_end = command_offset_region_start + frame_info.height * 4 command_offset_reader = ScnDataReader( all_data[command_offset_region_start:command_offset_region_end]) command_offset = SlpCommandOffset.read(command_offset_reader, frame_info.height) # Sub-reader for pixel data (very inefficient..) command_data_reader = ScnDataReader(all_data) command_data_reader.read( command_offset.row[0] ) # read and discard so that we don't need to do maths to find in-file offset rows = [] for y in range(0, frame_info.height): row = SlpRow.read(command_data_reader, frame_outline.row[y]) rows.append(row) frames.append(SlpFrame(frame_info, rows)) return SlpFile(header, frames)
def read_classic(data: ScnDataReader): base = ScnEngineProperties.read_classic(data) version = base.rge_version if version <= 1.13: for i in range(0, 16): # skip past player names player_name = data.string_fixed(size=256) raise Exception( "Not implemented: Don't know how to read player base properties from <1.13 file" ) else: player_start_resources = [] for i in range(0, 16): # Ignoring at the moment this_player_start_resources = ScnPlayerStartResources.read( data, version) player_start_resources.append(this_player_start_resources) if version >= 1.02: check5 = data.int32() if check5 != -99: raise Exception( "Check value did not match in scenario data, giving up") victory_conquest = data.uint32() victory_ruins = data.uint32() victory_artifacts = data.uint32() victory_discoveries = data.uint32() victory_exploration = data.uint32() victory_gold = data.uint32() victory_all_flag = data.boolean32() if version >= 1.13: mp_victory_type = data.uint32() victory_score = data.uint32() victory_time = data.uint32() for i in range(0, 16): for j in range(0, 16): stance = data.uint32() logging.debug("Diplomacy from=%d to=%d stance=%d", i, j, stance) # 12 victory conditions for each player for i in range(0, 16): for j in range(0, 12): # TODO read these ??? individual_victory_blob = data.read(60) if version >= 1.02: check5 = data.int32() if check5 != -99: raise Exception( "Check value did not match in scenario data, giving up") # Allied victory for i in range(0, 16): allied_victory = data.uint32() if version >= 1.24: raise Exception( "Not implemented: Don't know how to read team information from >=1.24 file" ) if version >= 1.18: # Also has disabled units and building, where are they in older versions? raise Exception( "Not implemented: Don't know how to read tech tree from >=1.18 file" ) elif version > 1.03: for i in range(0, 16): for j in range(0, 20): disabled_tech_id = data.uint32() logging.debug("Disabled tech player %d, position %d: %d", i, j, disabled_tech_id) if version > 1.04: data.uint32() # No idea if version >= 1.12: data.uint32() # No idea full_tech_tree = data.boolean32() if version > 1.05: for i in range(0, 16): player_start_age = data.uint32() if version >= 1.02: check6 = data.int32() if check6 != -99: raise Exception( "Check value did not match in scenario data, giving up") if version >= 1.19: # 'view'?? data.uint32() data.uint32() if version >= 1.21: raise Exception( "Not implemented: Don't know how to read map type from >=1.21 file" ) if version >= 1.21: raise Exception( "Not implemented: Don't know how to read base priorities from >=1.21 file" ) game_properties = ScnGameProperties(base) logging.debug(game_properties) return game_properties
def read_classic(data: ScnDataReader): # TODO actually store this stuff version = data.float32(debug='version') if version > 1.13: for i in range(0, 16): # skip past player names player_name = data.string_fixed(size=256) if version > 1.16: raise Exception("Not implemented: player string table not understood") if version > 1.13: for i in range(0, 16): player_base = ScnPlayerBaseProperties.read(data) logging.debug(player_base) is_conquest = False if version > 1.07: is_conquest = data.boolean8() # Something to do with timelines? check1 = data.uint16() check2 = data.uint16() check3 = data.float32() if check1 != 0 or check2 != 0 or check3 < -1 or check3 > 1: raise Exception("Unexpected values in scenario data, giving up") filename = data.string16(debug='filename') if version > 1.16: raise Exception("Not implemented: scenario instruction string table not understood") if version > 1.22: raise Exception("Not implemented: scout string table not understood") description = data.string16(debug='description') if version >= 1.11: hints_message = data.string16(debug='hints_message') win_message = data.string16(debug='win_message') loss_message = data.string16(debug='loss_message') history_message = data.string16(debug='history_message') if version > 1.22: raise Exception("Not implemented: scout data not understood") pregame_cinematic = data.string16(debug='pregame_cinematic') victory_cinematic = data.string16(debug='victory_cinematic') loss_cinematic = data.string16(debug='loss_cinematic') if version >= 1.09: mission_bmp = data.string16() logging.debug("mission_bmp='%s'", mission_bmp) if version >= 1.10: mission_image = data.uint32() width = data.uint32() height = data.uint32() orientation = data.uint16() if width > 0 or height > 0: raise Exception("Mission BMP data not understood") for i in range(0, 16): player_build_list = data.string16() logging.debug("Player %d build list %s", i, player_build_list) for i in range(0, 16): player_city_plan = data.string16() logging.debug("Player %d city plan %s", i, player_city_plan) if version >= 1.08: for i in range(0, 16): player_personality = data.string16() logging.debug("Player %d personality %s", i, player_personality) for i in range(0, 16): """ Embedded files """ build_list_length = data.uint32() city_plan_length = data.uint32() ai_rules_length = data.uint32() if version >= 1.08 else 0 data.read(build_list_length) data.read(city_plan_length) data.read(ai_rules_length) if version >= 1.20: raise Exception("Not implemented: AI rules not understood") if version >= 1.02: check4 = data.int32() if check4 != -99: raise Exception("Check value did not match in scenario data, giving up") rge_scen = ScnEngineProperties( version ) logging.debug(rge_scen) return rge_scen
def read(data: ScnDataReader): cmd_byte = data.uint8() if cmd_byte & 0x03 == 0x00: # "Lesser draw" draw_len = cmd_byte >> 2 draw_px = data.read(draw_len) # if draw len == 0 ?? return SlpDrawCommand(SlpDrawCommandType.PALETTE_PIXELS_DRAW, draw_len, draw_px) elif cmd_byte & 0x03 == 0x01: # "Lesser skip" draw_len = cmd_byte >> 2 if draw_len == 0: draw_len = data.uint8() return SlpDrawCommand(SlpDrawCommandType.TRANSPARENT_DRAW, draw_len, b"") elif cmd_byte & 0x0F == 0x02: # "Greater draw" draw_len = ((cmd_byte & 0xF0) << 4) + data.uint8() draw_px = data.read(draw_len) return SlpDrawCommand(SlpDrawCommandType.PALETTE_PIXELS_DRAW, draw_len, draw_px) elif cmd_byte & 0x0F == 0x03: # "Greater skip" draw_len = ((cmd_byte & 0xF0) << 4) + data.uint8() return SlpDrawCommand(SlpDrawCommandType.TRANSPARENT_DRAW, draw_len, b"") elif cmd_byte & 0x0F == 0x06: # "Player color draw" draw_len = cmd_byte >> 4 if draw_len == 0: draw_len = data.uint8() draw_px = data.read(draw_len) return SlpDrawCommand(SlpDrawCommandType.PLAYER_PIXELS_DRAW, draw_len, draw_px) elif cmd_byte & 0x0F == 0x07: # "Fill" draw_len = cmd_byte >> 4 if draw_len == 0: draw_len = data.uint8() draw_px = data.read(1) return SlpDrawCommand(SlpDrawCommandType.PALETTE_PIXEL_REPEAT, draw_len, draw_px) elif cmd_byte & 0x0F == 0x0A: # "Player color fill" draw_len = cmd_byte >> 4 if draw_len == 0: draw_len = data.uint8() draw_px = data.read(1) return SlpDrawCommand(SlpDrawCommandType.PLAYER_PIXEL_REPEAT, draw_len, draw_px) elif cmd_byte & 0x0F == 0x0B: draw_len = cmd_byte >> 4 if draw_len == 0: draw_len = data.uint8() return SlpDrawCommand(SlpDrawCommandType.SHADOW_DRAW, draw_len, b"") elif cmd_byte & 0x0F == 0x0E: cmd_idx = cmd_byte >> 4 return SlpDrawCommand(SlpDrawCommandType.EXTENDED_COMMAND, 1, bytes([cmd_idx])) elif cmd_byte == 0x0F: # ? Strange end of row?? return SlpDrawCommand(SlpDrawCommandType.END_OF_ROW, 0, b"") print(cmd_byte) raise Exception("Unrecognised SLP draw byte, file may be corrupt.")
def read(data: ScnDataReader): return DRSResourceType(data.read(4))