diff options
-rw-r--r-- | debug.c | 4 | ||||
-rw-r--r-- | debug.h | 1 | ||||
-rw-r--r-- | oldloader.c | 2900 |
3 files changed, 1460 insertions, 1445 deletions
@@ -12,6 +12,7 @@ int _debug_misc_level; int _debug_ms_level; int _debug_net_level; int _debug_spritecache_level; +int _debug_oldloader_level; void CDECL debug(const char *s, ...) @@ -46,7 +47,8 @@ void SetDebugString(const char *s) DEBUG_LEVEL(misc), DEBUG_LEVEL(ms), DEBUG_LEVEL(net), - DEBUG_LEVEL(spritecache) + DEBUG_LEVEL(spritecache), + DEBUG_LEVEL(oldloader) }; #undef DEBUG_LEVEL @@ -13,6 +13,7 @@ extern int _debug_ms_level; extern int _debug_net_level; extern int _debug_spritecache_level; + extern int _debug_oldloader_level; #endif void CDECL debug(const char *s, ...); diff --git a/oldloader.c b/oldloader.c index b46fd3c90..2e3e3ae4c 100644 --- a/oldloader.c +++ b/oldloader.c @@ -2,7 +2,6 @@ #include "ttd.h" #include "table/strings.h" #include "map.h" -#include "tile.h" #include "town.h" #include "industry.h" #include "station.h" @@ -11,1604 +10,1615 @@ #include "engine.h" #include "vehicle.h" #include "signs.h" +#include "debug.h" #include "depot.h" -extern byte _name_array[512][32]; -extern TileIndex _animated_tile_list[256]; -extern uint16 _custom_sprites_base; +enum { + HEADER_SIZE = 49, + BUFFER_SIZE = 4096, + + OLD_MAP_SIZE = 256 * 256 +}; + +typedef struct LoadgameState { + FILE *file; + + uint chunk_size; + + bool decoding; + byte decode_char; + + uint buffer_count; + uint buffer_cur; + byte buffer[BUFFER_SIZE]; + + uint total_read; + bool failed; +} LoadgameState; + +typedef bool OldChunkProc(LoadgameState *ls, int num); + +typedef struct OldChunks { + uint32 type; //! Type of field + uint32 amount; //! Amount of fields + + void *ptr; //! Pointer where to save the data (may only be set if offset is 0) + uint offset; //! Offset from basepointer (may only be set if ptr is NULL) + OldChunkProc *proc; //! Pointer to function that is called with OC_CHUNK +} OldChunks; + +/* OldChunk-Type */ +enum { + OC_END = 0, + OC_NULL = 1 << 0, + OC_CHUNK = 1 << 1, + OC_ASSERT = 1 << 2, + + OC_VAR_I8 = 1 << 9, + OC_VAR_U8 = 1 << 10, + OC_VAR_I16 = 1 << 11, + OC_VAR_U16 = 1 << 12, + OC_VAR_I32 = 1 << 13, + OC_VAR_U32 = 1 << 14, + OC_VAR_I64 = 1 << 15, + + OC_FILE_I8 = 1 << 17, + OC_FILE_U8 = 1 << 18, + OC_FILE_I16 = 1 << 19, + OC_FILE_U16 = 1 << 20, + OC_FILE_I32 = 1 << 21, + OC_FILE_U32 = 1 << 22, + + OC_INT8 = OC_VAR_I8 | OC_FILE_I8, + OC_UINT8 = OC_VAR_U8 | OC_FILE_U8, + OC_INT16 = OC_VAR_I16 | OC_FILE_I16, + OC_UINT16 = OC_VAR_U16 | OC_FILE_U16, + OC_INT32 = OC_VAR_I32 | OC_FILE_I32, + OC_UINT32 = OC_VAR_U32 | OC_FILE_U32, + + OC_TILE = OC_VAR_U32 | OC_FILE_U16 +}; +/* If it fails, check lines above.. */ +assert_compile(sizeof(TileIndex) == 4); + +static LoadgameState _ls; +static uint32 _bump_assert_value; +static bool _read_ttdpatch_flags; + +/** + * + * Reads a byte from a file (do not call yourself, use ReadByte()) + * + */ +static byte ReadByteFromFile(LoadgameState *ls) +{ + /* To avoid slow reads, we read BUFFER_SIZE of bytes per time + and just return a byte per time */ + if (ls->buffer_cur >= ls->buffer_count) { + /* Read some new bytes from the file */ + int count = fread(ls->buffer, 1, BUFFER_SIZE, ls->file); + + /* We tried to read, but there is nothing in the file anymore.. */ + if (count == 0) { + DEBUG(oldloader, 1)("[OldLoader] Read past end of file, loading failed"); + ls->failed = true; + } -#if defined(_MSC_VER) || defined(__WATCOMC__) -#pragma pack(push, 1) -#endif - -typedef struct { - uint16 string_id; - uint16 x; - uint16 right; - uint16 y; - uint16 bottom; - uint16 duration; - uint32 params[2]; -} GCC_PACK OldTextEffect; -assert_compile(sizeof(OldTextEffect) == 0x14); - -typedef struct { - uint16 xy; - uint16 population; - uint16 townnametype; - uint32 townnameparts; - byte grow_counter; - byte sort_index; - int16 sign_left, sign_top; - byte namewidth_1, namewidth_2; - uint16 flags12; - uint16 radius[5]; - uint16 ratings[8]; - uint32 have_ratings; - uint32 statues; - uint16 num_houses; - byte time_until_rebuild; - byte growth_rate; - uint16 new_max_pass, new_max_mail; - uint16 new_act_pass, new_act_mail; - uint16 max_pass, max_mail; - uint16 act_pass, act_mail; - byte pct_pass_transported, pct_mail_transported; - uint16 new_act_food, new_act_water; - uint16 act_food, act_water; - byte road_build_months; - byte fund_buildings_months; - // unused bytes at the end of the Town Struct - uint32 unk56; - uint32 unk5A; -} GCC_PACK OldTown; -assert_compile(sizeof(OldTown) == 0x5E); - -typedef struct { - uint16 xy; - uint32 town; -} GCC_PACK OldDepot; -assert_compile(sizeof(OldDepot) == 0x6); - -typedef struct { - uint32 price; - uint16 frac; -} GCC_PACK OldPrice; -assert_compile(sizeof(OldPrice) == 0x6); - -typedef struct { - uint32 price; - uint16 frac; - uint16 unused; -} GCC_PACK OldPaymentRate; -assert_compile(sizeof(OldPaymentRate) == 8); - -typedef struct { - uint16 waiting_acceptance; - byte days_since_pickup; - byte rating; - byte enroute_from; - byte enroute_time; - byte last_speed; - byte last_age; -} GCC_PACK OldGoodsEntry; -assert_compile(sizeof(OldGoodsEntry) == 8); - -typedef struct { - uint16 xy; - uint32 town; - uint16 bus_tile, lorry_tile, train_tile, airport_tile, dock_tile; - byte platforms; - byte alpha_order_obsolete; // alpha_order is obsolete since savegame format 4 - byte namewidth_1, namewidth_2; - uint16 string_id; - int16 sign_left, sign_top; - uint16 had_vehicle_of_type; - OldGoodsEntry goods[12]; - byte time_since_load, time_since_unload; - byte delete_ctr; - byte owner; - byte facilities; - byte airport_type; - byte truck_stop_status, bus_stop_status; - byte blocked_months_obsolete; - byte unk85; - uint16 airport_flags; - uint16 last_vehicle; - uint32 unk8A; -} GCC_PACK OldStation; -assert_compile(sizeof(OldStation) == 0x8E); - -typedef struct { - uint16 xy; - uint32 town; - byte width; - byte height; - byte produced_cargo[2]; - uint16 cargo_waiting[2]; - byte production_rate[2]; - byte accepts_cargo[3]; - byte prod_level; - uint16 last_mo_production[2]; - uint16 last_mo_transported[2]; - byte pct_transported[2]; - uint16 total_production[2]; - uint16 total_transported[2]; - byte type; - byte owner; - byte color_map; - byte last_prod_year; - uint16 counter; - byte was_cargo_delivered; - byte nothing; - uint32 unk2E; - uint32 unk32; -} GCC_PACK OldIndustry; -assert_compile(sizeof(OldIndustry) == 0x36); - -typedef struct { - int32 cost[13]; -} GCC_PACK OldPlayerExpenses; -assert_compile(sizeof(OldPlayerExpenses) == 0x34); - -typedef struct { - int32 income; - int32 expenses; - uint32 delivered_cargo; - uint32 performance_history; - uint32 company_value; -} GCC_PACK OldPlayerEconomy; -assert_compile(sizeof(OldPlayerEconomy) == 0x14); - -typedef struct { - uint16 spec_tile; - uint16 use_tile; - byte rand_rng; - byte cur_rule; - byte unk6; - byte unk7; - byte buildcmd_a; - byte buildcmd_b; - byte direction; - byte cargo; - byte unused[8]; -} GCC_PACK OldAiBuildRec; -assert_compile(sizeof(OldAiBuildRec) == 0x14); - -typedef struct { - uint16 tile; - byte data; -} GCC_PACK OldAiBannedTile; -assert_compile(sizeof(OldAiBannedTile) == 3); - -typedef struct { - uint16 name_1; - uint32 name_2; - uint32 face; - uint16 pres_name_1; - uint32 pres_name_2; - uint32 money; - uint32 loan; - byte color; - byte money_fract; - byte quarters_of_bankrupcy; - byte bankrupt_asked; - uint32 bankrupt_value; - uint16 bankrupt_timeout; - uint32 cargo_types; - OldPlayerExpenses expenses[3]; - OldPlayerEconomy economy[24 + 1]; - uint16 inaugurated_date; - uint16 last_build_coordinate; - byte num_valid_stat_ent; - byte ai_state; - byte unused; - byte ai_state_mode; - uint16 ai_state_counter; - uint16 ai_timeout_counter; - OldAiBuildRec ai_src, ai_dst, ai_mid1, ai_mid2; - byte unused_2[20]; - byte ai_cargo_type; - byte ai_num_wagons; - byte ai_build_kind; - byte ai_num_build_rec; - byte ai_num_loco_to_build; - byte ai_num_want_fullload; - byte unused_3[14]; - uint16 ai_loco_id; // NOT USED - uint16 ai_wagonlist[9]; - byte ai_order_list_blocks[20]; - uint16 ai_start_tile_a; - uint16 ai_start_tile_b; - uint16 ai_cur_tile_a; - uint16 ai_cur_tile_b; - byte ai_start_dir_a; - byte ai_start_dir_b; - byte ai_cur_dir_a; - byte ai_cur_dir_b; - byte ai_banned_tile_count; - OldAiBannedTile banned_tiles[16]; - byte ai_railtype_to_use; - byte ai_route_type_mask; - byte block_preview; - byte ai_tick; - byte max_railtype; - uint16 location_of_house; - byte share_owners[4]; - uint32 unk3AA; - uint32 unk3AE; -} GCC_PACK OldPlayer; -assert_compile(sizeof(OldPlayer) == 0x3B2); - -typedef struct { - byte track; - byte force_proceed; - uint16 crash_anim_pos; - byte railtype; -} GCC_PACK OldVehicleRailUnion; -assert_compile(sizeof(OldVehicleRailUnion) == 5); - -typedef struct { - byte unk0; - byte targetairport; - uint16 crashed_counter; - byte state; -} GCC_PACK OldVehicleAirUnion; -assert_compile(sizeof(OldVehicleAirUnion) == 5); - -typedef struct { - byte state; - byte frame; - uint16 unk2; - byte overtaking; - byte overtaking_ctr; - uint16 crashed_ctr; - byte reverse_ctr; -} GCC_PACK OldVehicleRoadUnion; -assert_compile(sizeof(OldVehicleRoadUnion) == 9); - -typedef struct { - uint16 unk0; - byte unk2; -} GCC_PACK OldVehicleSpecialUnion; -assert_compile(sizeof(OldVehicleSpecialUnion) == 3); - -typedef struct { - uint16 image_override; - uint16 unk2; -} GCC_PACK OldVehicleDisasterUnion; -assert_compile(sizeof(OldVehicleDisasterUnion) == 4); - -typedef struct { - byte state; -} GCC_PACK OldVehicleShipUnion; -assert_compile(sizeof(OldVehicleShipUnion) == 1); - -typedef union { - OldVehicleRailUnion rail; - OldVehicleAirUnion air; - OldVehicleRoadUnion road; - OldVehicleSpecialUnion special; - OldVehicleDisasterUnion disaster; - OldVehicleShipUnion ship; - byte pad[10]; -} GCC_PACK OldVehicleUnion; -assert_compile(sizeof(OldVehicleUnion) == 10); - -typedef struct { - byte type; - byte subtype; - uint16 next_hash; // NOLOAD, calculated automatically. - uint16 index; // NOLOAD, calculated automatically. - uint32 schedule_ptr; - byte next_order, next_order_param; - byte num_orders; - byte cur_order_index; - uint16 dest_tile; - uint16 load_unload_time_rem; - uint16 date_of_last_service; - uint16 service_interval; - byte last_station_visited; - byte tick_counter; - uint16 max_speed; - uint16 x_pos, y_pos; - byte z_pos; - byte direction; - byte x_offs, y_offs; - byte sprite_width, sprite_height, z_height; - byte owner; - uint16 tile; - uint16 cur_image; - - int16 left_coord, right_coord, top_coord, bottom_coord; // NOLOAD, calculated automatically. - uint16 vehstatus; - uint16 cur_speed; - byte subspeed; - byte acceleration; - byte progress; - byte cargo_type; - uint16 capacity; - uint16 number_of_pieces; - byte source_of_pieces; - byte days_in_transit; - uint16 age_in_days, max_age_in_days; - byte build_year; - byte unitnumber; - uint16 engine_type; - byte spritenum; - byte day_counter; - byte breakdowns_since_last_service; - byte breakdown_ctr, breakdown_delay, breakdown_chance; - uint16 reliability, reliability_spd_dec; - uint32 profit_this_year, profit_last_year; - uint16 next_in_chain; - uint32 value; - uint16 string_id; - OldVehicleUnion u; - byte unused[20]; -} GCC_PACK OldVehicle; -assert_compile(sizeof(OldVehicle) == 0x80); - -typedef struct { - byte name[32]; -} GCC_PACK OldName; - -typedef struct { - uint16 text; - int16 x,y,z; - byte namewidth_1, namewidth_2; - int16 sign_left, sign_top; -} GCC_PACK OldSign; -assert_compile(sizeof(OldSign) == 0xE); - -typedef struct { - uint16 player_avail; - uint16 intro_date; - uint16 age; - uint16 reliability, reliability_spd_dec, reliability_start, reliability_max, reliability_final; - uint16 duration_phase_1, duration_phase_2, duration_phase_3; - byte lifelength; - byte flags; - byte preview_player; - byte preview_wait; - byte railtype; - byte unk1B; -} GCC_PACK OldEngine; -assert_compile(sizeof(OldEngine) == 0x1C); - -typedef struct { - byte cargo_type; - byte age; - byte from; - byte to; -} GCC_PACK OldSubsidy; -assert_compile(sizeof(OldSubsidy) == 4); - -typedef struct { - uint16 max_no_competitors; - uint16 competitor_start_time; - uint16 number_towns; - uint16 number_industries; - uint16 max_loan; - uint16 initial_interest; - uint16 vehicle_costs; - uint16 competitor_speed; - uint16 competitor_intelligence; - uint16 vehicle_breakdowns; - uint16 subsidy_multiplier; - uint16 construction_cost; - uint16 terrain_type; - uint16 quantity_sea_lakes; - uint16 economy; - uint16 line_reverse_mode; - uint16 disasters; -} GCC_PACK OldGameSettings; -assert_compile(sizeof(OldGameSettings) == 0x22); - -typedef struct { - uint16 date; - uint16 date_fract; - - OldTextEffect te_list[30]; // NOLOAD: not so important. - uint32 seed_1, seed_2; - - OldTown town_list[70]; - uint16 order_list[5000]; - - uint16 animated_tile_list[256]; - uint32 ptr_to_next_order; - OldDepot depots[255]; - - uint32 cur_town_ptr; - uint16 timer_counter; - uint16 land_code; // NOLOAD: never needed in game - uint16 age_cargo_skip_counter; - uint16 tick_counter; - uint16 cur_tileloop_tile; - - OldPrice prices[49]; - OldPaymentRate cargo_payment_rates[12]; - - byte map_owner[256*256]; - byte map2[256*256]; - uint16 map3[256*256]; - byte map_extra[256*256/4]; - - OldStation stations[250]; - OldIndustry industries[90]; - OldPlayer players[8]; - OldVehicle vehicles[850]; - OldName names[500]; - - uint16 vehicle_position_hash[0x1000]; // NOLOAD, calculated automatically. - - OldSign signs[40]; - OldEngine engines[256]; - - uint16 vehicle_id_ctr_day; - OldSubsidy subsidies[8]; - - uint16 next_competitor_start; - - uint16 saved_main_scrollpos_x, saved_main_scrollpos_y, saved_main_scrollpos_zoom; - uint32 maximum_loan, maximum_loan_unround; - uint16 economy_fluct; - uint16 disaster_delay; - - //NOLOAD. These are calculated from InitializeLandscapeVariables - uint16 cargo_names_s[12], cargo_names_p[12], cargo_names_long_s[12], cargo_names_long_p[12], cargo_names_short[12]; - uint16 cargo_sprites[12]; - - uint16 engine_name_strings[256]; - - //NOLOAD. These are calculated from InitializeLandscapeVariables - uint16 railveh_by_cargo_1[12], railveh_by_cargo_2[12], railveh_by_cargo_3[12]; - uint16 roadveh_by_cargo_start[12]; - byte roadveh_by_cargo_count[12]; - uint16 ship_of_type_start[12]; - byte ship_of_type_count[12]; - - byte human_player_1, human_player_2; //NOLOAD. Calculated automatically. - byte station_tick_ctr; - byte currency; - byte use_kilometers; - byte cur_player_tick_index; - byte cur_year, cur_month; //NOLOAD. Calculated automatically. - byte player_colors[8]; //NOLOAD. Calculated automatically - - byte inflation_amount; - byte inflation_amount_payment_rates; - byte interest_rate; - - byte avail_aircraft; - byte road_side; - byte town_name_type; - OldGameSettings game_diff; - byte difficulty_level; - byte landscape_type; - byte trees_tick_ctr; - byte vehicle_design_names; - byte snow_line_height; - - byte new_industry_randtable[32]; // NOLOAD. Not needed due to different code design. - - //NOLOAD. Initialized by InitializeLandscapeVariables - byte cargo_weights[12]; - byte transit_days_table_1[12]; - byte transit_days_table_2[12]; - - byte map_type_and_height[256*256]; - byte map5[256*256]; -} GCC_PACK OldMain; -assert_compile(sizeof(OldMain) == 487801 + 256*256*2); + ls->buffer_count = count; + ls->buffer_cur = 0; + } -#if defined(_MSC_VER) || defined(__WATCOMC__) -#pragma pack(pop) -#endif + return ls->buffer[ls->buffer_cur++]; +} -#define REMAP_TOWN_IDX(x) (x - (0x0459154 - 0x0458EF0)) / sizeof(OldTown) -#define REMAP_TOWN_PTR(x) GetTown( REMAP_TOWN_IDX(x) ) +/** + * + * Reads a byte from the buffer and decompress if needed + * + */ +static byte ReadByte(LoadgameState *ls) +{ + /* Old savegames have a nice compression algorithm (RLE) + which means that we have a chunk, which starts with a length + byte. If that byte is negative, we have to repeat the next byte + that many times (+1). Else, we need to read that amount of bytes. + Works pretty good if you have many zero's behind eachother */ + int8 new_byte; + + /* Check if we are reading a chunk */ + if (ls->chunk_size != 0) { + ls->total_read++; + ls->chunk_size--; + + /* If we are decoding, return the decode_char */ + if (ls->decoding) + return ls->decode_char; + + /* Else return byte from file */ + return ReadByteFromFile(ls); + } -#define REMAP_ORDER_IDX(x) (x - (0x045AB08 - 0x0458EF0)) / sizeof(uint16) + /* Read new chunk */ + new_byte = ReadByteFromFile(ls); -typedef struct LoadSavegameState { - int8 mode; - byte rep_char; + if (new_byte < 0) { + /* Repeat next char for new_byte times */ + ls->decoding = true; + ls->decode_char = ReadByteFromFile(ls); + ls->chunk_size = -new_byte + 1; + } else { + ls->decoding = false; + ls->chunk_size = new_byte + 1; + } - size_t count; - size_t buffer_count; - FILE *fin; + /* Call this function again to return a byte */ + return ReadByte(ls); +} - byte *buffer_cur; +/** + * + * Loads a chunk from the old savegame + * + */ +static bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks) +{ + const OldChunks *chunk = chunks; + byte *ptr; + uint i; - byte buffer[4096]; + while (chunk->type != OC_END) { + ptr = chunk->ptr; -} LoadSavegameState; + for (i = 0; i < chunk->amount; i++) { + if (ls->failed) + return false; -static LoadSavegameState *_cur_state; + /* Handle simple types */ + if ((chunk->type & 0xFF) != 0) { + switch (chunk->type & 0xFF) { + case OC_NULL: + /* Just read the byte and forget about it */ + ReadByte(ls); + break; -static byte GetSavegameByteFromBuffer(void) -{ - LoadSavegameState *lss = _cur_state; - - if (lss->buffer_count == 0) { - int count = fread(lss->buffer, 1, 4096, lss->fin) ; -/* if (count == 0) { - memset(lss->buffer, 0, sizeof(lss->buffer)); - count = 4096; - }*/ - assert(count != 0); - lss->buffer_count = count; - lss->buffer_cur = lss->buffer; - } + case OC_CHUNK: + /* Call function, with 'i' as parameter to tell which item we + are going to read */ + if (!chunk->proc(ls, i)) + return false; + break; - lss->buffer_count--; - return *lss->buffer_cur++; -} + case OC_ASSERT: + DEBUG(oldloader, 4)("[OldLoader] Assert point: %x / %x", ls->total_read, chunk->offset + _bump_assert_value); + if (ls->total_read != chunk->offset + _bump_assert_value) + ls->failed = true; -static byte DecodeSavegameByte(void) -{ - LoadSavegameState *lss = _cur_state; - int8 x; + break; - if (lss->mode < 0) { - if (lss->count != 0) { - lss->count--; - return lss->rep_char; - } - } else if (lss->mode > 0) { - if (lss->count != 0) { - lss->count--; - return GetSavegameByteFromBuffer(); + } + } else { + uint32 res = 0; + + /* Reading from the file: bit 16 to 23 have the FILE */ + switch (((chunk->type >> 16) & 0xFF) << 16) { + case OC_FILE_I8: + res = ReadByte(ls); + res = (int8)res; + break; + + case OC_FILE_U8: + res = ReadByte(ls); + break; + + case OC_FILE_U16: + res = ReadByte(ls); + res += ReadByte(ls) << 8; + break; + + case OC_FILE_I16: + res = ReadByte(ls); + res += ReadByte(ls) << 8; + res = (int16)res; + break; + + case OC_FILE_U32: + res = ReadByte(ls); + res += ReadByte(ls) << 8; + res += ReadByte(ls) << 16; + res += ReadByte(ls) << 24; + break; + + case OC_FILE_I32: + res = ReadByte(ls); + res += ReadByte(ls) << 8; + res += ReadByte(ls) << 16; + res += ReadByte(ls) << 24; + res = (int32)res; + break; + } + + /* Sanity check */ + assert(base != NULL || chunk->ptr != NULL); + + /* Writing to the var: bit 8 till 15 have the VAR */ + switch (((chunk->type >> 8) & 0xFF) << 8) { + case OC_VAR_I8: + /* Write the data */ + if (chunk->ptr != NULL) { + *(int8 *)ptr = res & 0xFF; + ptr++; + } else + *(int8 *)(base + chunk->offset) = res & 0xFF; + break; + + case OC_VAR_U8: + /* Write the data */ + if (chunk->ptr != NULL) { + *(uint8 *)ptr = res & 0xFF; + ptr++; + } else + *(uint8 *)(base + chunk->offset) = res & 0xFF; + break; + + case OC_VAR_U16: + /* Write the data */ + if (chunk->ptr != NULL) { + *(uint16 *)ptr = res & 0xFFFF; + ptr += 2; + } else + *(uint16 *)(base + chunk->offset) = res & 0xFFFF; + break; + + case OC_VAR_I16: + /* Write the data */ + if (chunk->ptr != NULL) { + *(int16 *)ptr = res & 0xFFFF; + ptr += 2; + } else + *(int16 *)(base + chunk->offset) = res & 0xFFFF; + break; + + case OC_VAR_U32: + /* Write the data */ + if (chunk->ptr != NULL) { + *(uint32 *)ptr = res; + ptr += 4; + } else + *(uint32 *)(base + chunk->offset) = res; + break; + + case OC_VAR_I32: + /* Write the data */ + if (chunk->ptr != NULL) { + *(int32 *)ptr = res; + ptr += 4; + } else + *(int32 *)(base + chunk->offset) = res; + break; + + case OC_VAR_I64: + /* Write the data */ + if (chunk->ptr != NULL) { + *(int64 *)ptr = res; + ptr += 8; + } else + *(int64 *)(base + chunk->offset) = res; + break; + } + } } - } - x = GetSavegameByteFromBuffer(); - if (x >= 0) { - lss->count = x; - lss->mode = 1; - return GetSavegameByteFromBuffer(); - } else { - lss->mode = -1; - lss->count = -x; - lss->rep_char = GetSavegameByteFromBuffer(); - return lss->rep_char; + chunk++; } + + return true; } -static void LoadSavegameBytes(void *p, size_t count) +/** + * + * Initialize some data before reading + * + */ +static void InitLoading(LoadgameState *ls) { - byte *ptr = (byte*)p; - assert(count > 0); - do { - *ptr++ = DecodeSavegameByte(); - } while (--count); + ls->chunk_size = 0; + ls->total_read = 0; + ls->failed = false; + + ls->decoding = false; + ls->decode_char = 0; + + ls->buffer_cur = 0; + ls->buffer_count = 0; + memset(ls->buffer, 0, BUFFER_SIZE); + + _bump_assert_value = 0; + + _read_ttdpatch_flags = false; } + +/* + * Begin -- Stuff to fix the savegames to be OpenTTD compatible + */ + extern uint32 GetOldTownName(uint32 townnameparts, byte old_town_name_type); -static void FixTown(OldTown *o, int num, byte town_name_type) +static void FixOldTowns(void) { - Town *t; - uint i = 0; + Town *town; - do { - if (o->xy == 0) + /* Convert town-names if needed */ + FOR_ALL_TOWNS(town) { + if (town->xy == 0) continue; - if (!AddBlockIfNeeded(&_town_pool, i)) - error("Towns: failed loading savegame: too many towns"); + if (IS_INT_INSIDE(town->townnametype, 0x20C1, 0x20C3)) { + town->townnametype = SPECSTR_TOWNNAME_ENGLISH + _opt.town_name; + town->townnameparts = GetOldTownName(town->townnameparts, _opt.town_name); + } + } +} - t = GetTown(i); +static void FixOldStations(void) +{ + Station *st; + + FOR_ALL_STATIONS(st) { + /* Check if we need to swap width and height for the station */ + if (st->train_tile) { + if (_map5[st->train_tile] & 1) { + int w = st->trainst_w; + int h = st->trainst_h; + intswap(w, h); + st->trainst_w = w; + st->trainst_h = h; + } + } - t->xy = o->xy; - t->population = o->population; - t->townnametype = o->townnametype; - t->townnameparts = o->townnameparts; - // Random TownNames - if (IS_INT_INSIDE(o->townnametype, 0x20C1, 0x20C2 + 1)) { - t->townnametype = SPECSTR_TOWNNAME_ENGLISH + town_name_type; - if (o->xy) - t->townnameparts = GetOldTownName(o->townnameparts, town_name_type); + /* Check if there is a bus or truck station, and convert to new format */ + if (st->bus_tile_obsolete != 0) { + st->bus_stops = AllocateRoadStop(); + st->bus_stops->xy = st->bus_tile_obsolete; + st->bus_stops->used = true; + st->bus_stops->status = 3; + st->bus_stops->station = st->index; + st->bus_stops->next = NULL; + st->bus_stops->prev = NULL; + st->bus_stops->slot[0] = st->bus_stops->slot[1] = INVALID_SLOT; } - t->grow_counter = o->grow_counter; - t->flags12 = o->flags12; - memcpy(t->ratings,o->ratings,sizeof(t->ratings)); - t->have_ratings = o->have_ratings; - t->statues = o->statues; - t->num_houses = o->num_houses; - t->time_until_rebuild = o->time_until_rebuild; - t->growth_rate = o->growth_rate; - t->new_max_pass = o->new_max_pass; - t->new_max_mail = o->new_max_mail; - t->new_act_pass = o->new_act_pass; - t->new_act_mail = o->new_act_mail; - t->max_pass = o->max_pass; - t->max_mail = o->max_mail; - t->act_pass = o->act_pass; - t->act_mail = o->act_mail; - t->pct_pass_transported = o->pct_pass_transported; - t->pct_mail_transported = o->pct_mail_transported; - t->new_act_food = o->new_act_food; - t->new_act_water = o->new_act_water; - t->act_food = o->act_food; - t->act_water = o->act_water; - t->road_build_months = o->road_build_months; - t->fund_buildings_months = o->fund_buildings_months; - } while (i++,o++,--num); + if (st->lorry_tile_obsolete != 0) { + st->truck_stops = AllocateRoadStop(); + st->truck_stops->xy = st->lorry_tile_obsolete; + st->truck_stops->used = true; + st->truck_stops->status = 3; + st->truck_stops->station = st->index; + st->truck_stops->next = NULL; + st->truck_stops->prev = NULL; + st->truck_stops->slot[0] = st->truck_stops->slot[1] = INVALID_SLOT; + } + } } -static void FixIndustry(OldIndustry *o, int num) +static void FixOldVehicles(void) { - Industry *i; - uint j = 0; + /* Check for shared orders, and link them correctly */ + { + Vehicle *v; - do { - if (o->xy == 0) - continue; + FOR_ALL_VEHICLES(v) { + Vehicle *u; + + if (v->type == 0) + continue; + + FOR_ALL_VEHICLES_FROM(u, v->index + 1) { + if (u->type == 0) + continue; - if (!AddBlockIfNeeded(&_industry_pool, j)) - error("Industries: failed loading savegame: too many industries"); - - i = GetIndustry(j); - - i->xy = o->xy; - i->town = REMAP_TOWN_PTR(o->town); - i->width = o->width; - i->height = o->height; - i->produced_cargo[0] = o->produced_cargo[0]; - i->produced_cargo[1] = o->produced_cargo[1]; - i->cargo_waiting[0] = o->cargo_waiting[0]; - i->cargo_waiting[1] = o->cargo_waiting[1]; - i->production_rate[0] = o->production_rate[0]; - i->production_rate[1] = o->production_rate[1]; - i->accepts_cargo[0] = o->accepts_cargo[0]; - i->accepts_cargo[1] = o->accepts_cargo[1]; - i->accepts_cargo[2] = o->accepts_cargo[2]; - i->prod_level = o->prod_level; - i->last_mo_production[0] = o->last_mo_production[0]; - i->last_mo_production[1] = o->last_mo_production[1]; - - i->last_mo_transported[0] = o->last_mo_transported[0]; - i->last_mo_transported[1] = o->last_mo_transported[1]; - i->last_mo_transported[2] = o->last_mo_transported[2]; - - i->pct_transported[0] = o->pct_transported[0]; - i->pct_transported[1] = o->pct_transported[1]; - - i->total_production[0] = o->total_production[0]; - i->total_production[1] = o->total_production[1]; - - i->total_transported[0] = i->total_transported[0]; - i->total_transported[1] = i->total_transported[1]; - - i->type = o->type; - i->owner = o->owner; - i->color_map = o->color_map; - i->last_prod_year = o->last_prod_year; - i->counter = o->counter; - i->was_cargo_delivered = o->was_cargo_delivered; - } while (j++,o++,--num); + /* If a vehicle has the same orders, add the link to eachother + in both vehicles */ + if (v->orders == u->orders) { + v->next_shared = u; + u->prev_shared = v; + break; + } + } + } + } + + if (_vehicle_id_ctr_day > GetVehiclePoolSize()) + _vehicle_id_ctr_day = 0; } -static void FixGoodsEntry(GoodsEntry *g, OldGoodsEntry *o, int num) +/* + * End -- Stuff to fix the savegames to be OpenTTD compatible + */ + + +/* Help: + * - OCL_SVAR: load 'type' to offset 'offset' in a struct of type 'base', which must also + * be given via base in LoadChunk() as real pointer + * - OCL_VAR: load 'type' to a global var + * - OCL_END: every struct must end with this + * - OCL_NULL: read 'amount' of bytes and send them to /dev/null or something + * - OCL_CHUNK: load an other proc to load a part of the savegame, 'amount' times + * - OCL_ASSERT: to check if we are really at the place we expect to be.. because old savegames are too binary to be sure ;) + */ +#define OCL_SVAR(type, base, offset) { type, 1, NULL, offsetof(base, offset), NULL } +#define OCL_VAR(type, amount, pointer) { type, amount, pointer, 0, NULL } +#define OCL_END() { OC_END, 0, NULL, 0, NULL } +#define OCL_NULL(amount) { OC_NULL, amount, NULL, 0, NULL } +#define OCL_CHUNK(amount, proc) { OC_CHUNK, amount, NULL, 0, proc } +#define OCL_ASSERT(size) { OC_ASSERT, 1, NULL, size, NULL } + +/* The savegames has some hard-coded pointers, because it always enters the same + piece of memory.. we don't.. so we need to remap ;) + Old Towns are 94 bytes big + Old Orders are 2 bytes big */ +#define REMAP_TOWN_IDX(x) ((x) - (0x0459154 - 0x0458EF0)) / 94 +#define REMAP_ORDER_IDX(x) ((x) - (0x045AB08 - 0x0458EF0)) / 2 + +extern TileIndex _animated_tile_list[256]; +extern byte _name_array[512][32]; +extern uint16 _custom_sprites_base; + +static byte _old_vehicle_multipler; +static uint8 _old_map3[OLD_MAP_SIZE * 2]; +static bool _new_ttdpatch_format; +static uint32 _old_town_index; +static uint16 _old_string_id; +static uint16 _old_string_id_2; + +void ReadTTDPatchFlags(void) { - do { - g->waiting_acceptance = o->waiting_acceptance; - g->days_since_pickup = o->days_since_pickup; - g->rating = o->rating; - g->enroute_from = o->enroute_from; - g->enroute_time = o->enroute_time; - g->last_speed = o->last_speed; - g->last_age = o->last_age; - } while (g++,o++,--num); + int i; + + if (_read_ttdpatch_flags) + return; + + _read_ttdpatch_flags = true; + + /* TTDPatch misuses _old_map3 for flags.. read them! */ + _old_vehicle_multipler = _old_map3[0]; + /* Somehow.... there was an error in some savegames, so 0 becomes 1 + and 1 becomes 2. The rest of the values are okay */ + if (_old_vehicle_multipler < 2) + _old_vehicle_multipler++; + + /* TTDPatch incraeses the Vehicle-part in the middle of the game, + so if the multipler is anything else but 1, the assert fails.. + bump the assert value so it doesn't! + (1 multipler == 850 vehicles + 1 vehicle == 128 bytes */ + _bump_assert_value = (_old_vehicle_multipler - 1) * 850 * 128; + + _new_ttdpatch_format = false; + + if (_old_map3[0x1FFFA] == 'T' && _old_map3[0x1FFFA + 1] == 'T' && + _old_map3[0x1FFFA + 2] == 'D' && _old_map3[0x1FFFA + 3] == 'p') + _new_ttdpatch_format = true; + + /* Clean the misused places */ + for (i = 0; i < 17; i++) + _old_map3[i] = 0; + for (i = 0x1FE00; i < 0x20000; i++) + _old_map3[i] = 0; + + if (_new_ttdpatch_format) + DEBUG(oldloader, 1)("[OldLoader] Found TTDPatch game"); + + DEBUG(oldloader, 1)("[OldLoader] Vehicle-multipler is set to %d (%d vehicles)", _old_vehicle_multipler, _old_vehicle_multipler * 850); } -static void FixStation(OldStation *o, int num) +static const OldChunks town_chunk[] = { + OCL_SVAR( OC_TILE, Town, xy ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, population ), + OCL_SVAR( OC_UINT16, Town, townnametype ), + OCL_SVAR( OC_UINT32, Town, townnameparts ), + OCL_SVAR( OC_UINT8, Town, grow_counter ), + OCL_NULL( 1 ), // sort_index, no longer in use + OCL_NULL( 4 ), // sign-coordinates, no longer in use + OCL_NULL( 2 ), // namewidth, no longer in use + OCL_SVAR( OC_UINT16, Town, flags12 ), + OCL_NULL( 10 ), // radius, no longer in use + + OCL_SVAR( OC_UINT16, Town, ratings[0] ), + OCL_SVAR( OC_UINT16, Town, ratings[1] ), + OCL_SVAR( OC_UINT16, Town, ratings[2] ), + OCL_SVAR( OC_UINT16, Town, ratings[3] ), + OCL_SVAR( OC_UINT16, Town, ratings[4] ), + OCL_SVAR( OC_UINT16, Town, ratings[5] ), + OCL_SVAR( OC_UINT16, Town, ratings[6] ), + OCL_SVAR( OC_UINT16, Town, ratings[7] ), + + /* XXX - This is pretty odd.. we read 32bit, but only write 8bit.. sure there is + nothing changed?? */ + OCL_SVAR( OC_FILE_U32 | OC_VAR_U8, Town, have_ratings ), + OCL_SVAR( OC_FILE_U32 | OC_VAR_U8, Town, statues ), + OCL_SVAR( OC_UINT16, Town, num_houses ), + OCL_SVAR( OC_UINT8, Town, time_until_rebuild ), + OCL_SVAR( OC_UINT8, Town, growth_rate ), + + OCL_SVAR( OC_UINT16, Town, new_max_pass ), + OCL_SVAR( OC_UINT16, Town, new_max_mail ), + OCL_SVAR( OC_UINT16, Town, new_act_pass ), + OCL_SVAR( OC_UINT16, Town, new_act_mail ), + OCL_SVAR( OC_UINT16, Town, max_pass ), + OCL_SVAR( OC_UINT16, Town, max_mail ), + OCL_SVAR( OC_UINT16, Town, act_pass ), + OCL_SVAR( OC_UINT16, Town, act_mail ), + + OCL_SVAR( OC_UINT8, Town, pct_pass_transported ), + OCL_SVAR( OC_UINT8, Town, pct_mail_transported ), + + OCL_SVAR( OC_UINT16, Town, new_act_food ), + OCL_SVAR( OC_UINT16, Town, new_act_water ), + OCL_SVAR( OC_UINT16, Town, act_food ), + OCL_SVAR( OC_UINT16, Town, act_water ), + + OCL_SVAR( OC_UINT8, Town, road_build_months ), + OCL_SVAR( OC_UINT8, Town, fund_buildings_months ), + + OCL_NULL( 8 ), // some junk at the end of the record + + OCL_END() +}; +static bool LoadOldTown(LoadgameState *ls, int num) { - Station *s; - uint i = 0; + if (!AddBlockIfNeeded(&_town_pool, num)) + error("Towns: failed loading savegame: too many towns"); - do { - if (o->xy == 0) - continue; + return LoadChunk(ls, GetTown(num), town_chunk); +} - if (!AddBlockIfNeeded(&_station_pool, i)) - error("Stations: failed loading savegame: too many stations"); +static uint16 _old_order; +static const OldChunks order_chunk[] = { + OCL_VAR ( OC_UINT16, 1, &_old_order ), + OCL_END() +}; +static bool LoadOldOrder(LoadgameState *ls, int num) +{ + if (!AddBlockIfNeeded(&_order_pool, num)) + error("Orders: failed loading savegame: too many orders"); - s = GetStation(i); + if (!LoadChunk(ls, NULL, order_chunk)) + return false; - s->xy = o->xy; - s->town = REMAP_TOWN_PTR(o->town); + AssignOrder(GetOrder(num), UnpackOldOrder(_old_order)); - s->bus_stops = NULL; - s->truck_stops = NULL; + /* Relink the orders to eachother (in TTD(Patch) the orders for one + vehicle are behind eachother, with OT_NOTHING as indication that + it is the last order */ + if (num > 0 && GetOrder(num)->type != OT_NOTHING) + GetOrder(num - 1)->next = GetOrder(num); - if (o->bus_tile != 0) { - s->bus_stops = AllocateRoadStop(); - s->bus_stops->xy = o->bus_tile; - s->bus_stops->used = true; - s->bus_stops->status = 3; - s->bus_stops->station = s->index; - s->bus_stops->next = NULL; - s->bus_stops->prev = NULL; - s->bus_stops->slot[0] = s->bus_stops->slot[1] = INVALID_SLOT; - } + return true; +} - if (o->lorry_tile != 0) { - s->truck_stops = AllocateRoadStop(); - s->truck_stops->xy = o->lorry_tile; - s->truck_stops->used = true; - s->truck_stops->status = 3; - s->truck_stops->station = s->index; - s->truck_stops->next = NULL; - s->truck_stops->prev = NULL; - s->truck_stops->slot[0] = s->truck_stops->slot[1] = INVALID_SLOT; - } +static const OldChunks depot_chunk[] = { + OCL_SVAR( OC_TILE, Depot, xy ), + OCL_VAR ( OC_UINT32, 1, &_old_town_index ), + OCL_END() +}; +static bool LoadOldDepot(LoadgameState *ls, int num) +{ + if (!AddBlockIfNeeded(&_depot_pool, num)) + error("Depots: failed loading savegame: too many depots"); - s->train_tile = o->train_tile; - s->airport_tile = o->airport_tile; - s->dock_tile = o->dock_tile; + if (!LoadChunk(ls, GetDepot(num), depot_chunk)) + return false; - if (o->train_tile) { - int w = (o->platforms >> 3) & 0x7; - int h = (o->platforms & 0x7); - if (_map5[o->train_tile]&1) intswap(w,h); - s->trainst_w = w; - s->trainst_h = h; - } + if (GetDepot(num)->xy != 0) { + GetDepot(num)->town_index = REMAP_TOWN_IDX(_old_town_index); + } - s->string_id = RemapOldStringID(o->string_id); - s->had_vehicle_of_type = o->had_vehicle_of_type; - FixGoodsEntry(s->goods, o->goods, lengthof(o->goods)); - s->time_since_load = o->time_since_load; - s->time_since_unload = o->time_since_unload; - s->delete_ctr = o->delete_ctr; - s->owner = o->owner; - s->facilities = o->facilities; - s->airport_type = o->airport_type; - if (s->truck_stops != NULL) - s->truck_stops->status = o->truck_stop_status; - if (s->bus_stops != NULL) - s->bus_stops->status = o->bus_stop_status; - s->blocked_months_obsolete = o->blocked_months_obsolete; - s->airport_flags = o->airport_flags; - s->last_vehicle = o->last_vehicle; - } while (i++,o++,--num); + return true; } -static void FixDepot(OldDepot *o, int num) +static int32 _old_price; +static uint16 _old_price_frac; +static const OldChunks price_chunk[] = { + OCL_VAR ( OC_INT32, 1, &_old_price ), + OCL_VAR ( OC_UINT16, 1, &_old_price_frac ), + OCL_END() +}; +static bool LoadOldPrice(LoadgameState *ls, int num) { - Depot *depot; - uint i = 0; + if (!LoadChunk(ls, NULL, price_chunk)) + return false; - do { - if (o->xy == 0) - continue; + /* We use a struct to store the prices, but they are ints in a row.. + so just access the struct as an array of int32's */ + ((int32*)&_price)[num] = _old_price; + _price_frac[num] = _old_price_frac; + + return true; +} + +static const OldChunks cargo_payment_rate_chunk[] = { + OCL_VAR ( OC_INT32, 1, &_old_price ), + OCL_VAR ( OC_UINT16, 1, &_old_price_frac ), - if (!AddBlockIfNeeded(&_depot_pool, i)) - error("Depots: failed loading savegame: too many depots"); + OCL_NULL( 2 ), // Junk + OCL_END() +}; +static bool LoadOldCargoPaymentRate(LoadgameState *ls, int num) +{ + if (!LoadChunk(ls, NULL, cargo_payment_rate_chunk)) + return false; - depot = GetDepot(i); + _cargo_payment_rates[num] = -_old_price; + _cargo_payment_rates_frac[num] = _old_price_frac; - depot->town_index = REMAP_TOWN_IDX(o->town); - depot->xy = o->xy; - } while (i++,o++,--num); + return true; } -static void FixOrder(uint16 *o, int num) +static uint8 _old_platforms; +static uint _current_station_id; + +static const OldChunks goods_chunk[] = { + OCL_SVAR( OC_UINT16, GoodsEntry, waiting_acceptance ), + OCL_SVAR( OC_UINT8, GoodsEntry, days_since_pickup ), + OCL_SVAR( OC_UINT8, GoodsEntry, rating ), + OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, GoodsEntry, enroute_from ), + OCL_SVAR( OC_UINT8, GoodsEntry, enroute_time ), + OCL_SVAR( OC_UINT8, GoodsEntry, last_speed ), + OCL_SVAR( OC_UINT8, GoodsEntry, last_age ), + + OCL_END() +}; +static bool LoadOldGood(LoadgameState *ls, int num) { - Order *order; - int i; + Station *st = GetStation(_current_station_id); + return LoadChunk(ls, &st->goods[num], goods_chunk); +} + +static const OldChunks station_chunk[] = { + OCL_SVAR( OC_TILE, Station, xy ), + OCL_VAR ( OC_UINT32, 1, &_old_town_index ), + + OCL_SVAR( OC_TILE, Station, bus_tile_obsolete ), + OCL_SVAR( OC_TILE, Station, lorry_tile_obsolete ), + OCL_SVAR( OC_TILE, Station, train_tile ), + OCL_SVAR( OC_TILE, Station, airport_tile ), + OCL_SVAR( OC_TILE, Station, dock_tile ), + + OCL_VAR ( OC_UINT8, 1, &_old_platforms ), + + OCL_NULL( 1 ), // sort-index, no longer in use + OCL_NULL( 2 ), // sign-width, no longer in use + + OCL_VAR ( OC_UINT16, 1, &_old_string_id ), + + OCL_NULL( 4 ), // sign left/top, no longer in use - for (i = 0; i < num; ++i) { - if (!AddBlockIfNeeded(&_order_pool, i)) - error("Orders: failed loading savegame: too many orders"); + OCL_SVAR( OC_UINT16, Station, had_vehicle_of_type ), - order = GetOrder(i); - AssignOrder(order, UnpackOldOrder(*o)); - /* Recover the next list */ - if (i > 0 && order->type != OT_NOTHING) - GetOrder(i - 1)->next = order; + OCL_CHUNK( 12, LoadOldGood ), - o++; + OCL_SVAR( OC_UINT8, Station, time_since_load ), + OCL_SVAR( OC_UINT8, Station, time_since_unload ), + OCL_SVAR( OC_UINT8, Station, delete_ctr ), + OCL_SVAR( OC_UINT8, Station, owner ), + OCL_SVAR( OC_UINT8, Station, facilities ), + OCL_SVAR( OC_UINT8, Station, airport_type ), + OCL_NULL( 2 ), // Bus/truck status, no longer in use + OCL_SVAR( OC_UINT8, Station, blocked_months_obsolete ), + OCL_NULL( 1 ), // Unknown + OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Station, airport_flags ), + OCL_SVAR( OC_UINT16, Station, last_vehicle ), + + OCL_NULL( 4 ), // Junk at end of chunk + + OCL_END() +}; +static bool LoadOldStation(LoadgameState *ls, int num) +{ + Station *st; + + if (!AddBlockIfNeeded(&_station_pool, num)) + error("Stations: failed loading savegame: too many stations"); + + st = GetStation(num); + _current_station_id = num; + + if (!LoadChunk(ls, st, station_chunk)) + return false; + + if (st->xy != 0) { + if (st->train_tile) { + /* Calculate the trainst_w and trainst_h */ + int w = (_old_platforms >> 3) & 0x7; + int h = (_old_platforms & 0x7); + st->trainst_w = w; + st->trainst_h = h; + } + + st->town = GetTown(REMAP_TOWN_IDX(_old_town_index)); + st->string_id = RemapOldStringID(_old_string_id); } + + return true; } -static void FixVehicle(OldVehicle *o, int num) -{ - Vehicle *n; - uint i = 0; +static const OldChunks industry_chunk[] = { + OCL_SVAR( OC_TILE, Industry, xy ), + OCL_VAR ( OC_UINT32, 1, &_old_town_index ), + OCL_SVAR( OC_UINT8, Industry, width ), + OCL_SVAR( OC_UINT8, Industry, height ), + OCL_SVAR( OC_UINT8, Industry, produced_cargo[0] ), + OCL_SVAR( OC_UINT8, Industry, produced_cargo[1] ), - do { - if (o->type == 0) - continue; + OCL_SVAR( OC_UINT16, Industry, cargo_waiting[0] ), + OCL_SVAR( OC_UINT16, Industry, cargo_waiting[1] ), - if (!AddBlockIfNeeded(&_vehicle_pool, i)) - error("Vehicles: failed loading savegame: too many vehicles"); + OCL_SVAR( OC_UINT8, Industry, production_rate[0] ), + OCL_SVAR( OC_UINT8, Industry, production_rate[1] ), - n = GetVehicle(i); + OCL_SVAR( OC_UINT8, Industry, accepts_cargo[0] ), + OCL_SVAR( OC_UINT8, Industry, accepts_cargo[1] ), + OCL_SVAR( OC_UINT8, Industry, accepts_cargo[2] ), - n->type = o->type; - n->subtype = o->subtype; + OCL_SVAR( OC_UINT8, Industry, prod_level ), - if (o->schedule_ptr == 0xFFFFFFFF || o->schedule_ptr == 0) { - n->orders = NULL; - } else { - n->orders = GetOrder(REMAP_ORDER_IDX(o->schedule_ptr)); - } + OCL_SVAR( OC_UINT16, Industry, last_mo_production[0] ), + OCL_SVAR( OC_UINT16, Industry, last_mo_production[1] ), + OCL_SVAR( OC_UINT16, Industry, last_mo_transported[0] ), + OCL_SVAR( OC_UINT16, Industry, last_mo_transported[1] ), - n->current_order.type = o->next_order & 0x0f; - n->current_order.flags = o->next_order >> 4; - n->current_order.station = o->next_order_param; - n->num_orders = o->num_orders; - n->cur_order_index = o->cur_order_index; - n->dest_tile = o->dest_tile; - n->load_unload_time_rem = o->load_unload_time_rem; - n->date_of_last_service = o->date_of_last_service; - n->service_interval = o->service_interval; - n->last_station_visited = o->last_station_visited; - n->tick_counter = o->tick_counter; - n->max_speed = o->max_speed; - n->x_pos = o->x_pos; - n->y_pos = o->y_pos; - n->z_pos = o->z_pos; - n->direction = o->direction; - n->x_offs = o->x_offs; - n->y_offs = o->y_offs; - n->sprite_width = o->sprite_width; - n->sprite_height = o->sprite_height; - n->z_height = o->z_height; - n->owner = o->owner; - n->tile = o->tile; - n->cur_image = o->cur_image; - if (o->cur_image >= 0x2000) // TTDPatch maps sprites from 0x2000 up. - n->cur_image -= 0x2000 - _custom_sprites_base; - - n->vehstatus = o->vehstatus; - n->cur_speed = o->cur_speed; - n->subspeed = o->subspeed; - n->acceleration = o->acceleration; - n->progress = o->progress; - n->cargo_type = o->cargo_type; - n->cargo_cap = o->capacity; - n->cargo_count = o->number_of_pieces; - n->cargo_source = o->source_of_pieces; - n->cargo_days = o->days_in_transit; - n->age = o->age_in_days; - n->max_age = o->max_age_in_days; - n->build_year = o->build_year; - n->unitnumber = o->unitnumber; - n->engine_type = o->engine_type; - switch (o->spritenum) { - case 0xfd: n->spritenum = 0xfd; break; - case 0xff: n->spritenum = 0xfe; break; - default: n->spritenum = o->spritenum >> 1; break; - } - n->day_counter = o->day_counter; - n->breakdowns_since_last_service = o->breakdowns_since_last_service; - n->breakdown_ctr = o->breakdown_ctr; - n->breakdown_delay = o->breakdown_delay; - n->breakdown_chance = o->breakdown_chance; - n->reliability = o->reliability; - n->reliability_spd_dec = o->reliability_spd_dec; - n->profit_this_year = o->profit_this_year; - n->profit_last_year = o->profit_last_year; - n->next = (o->next_in_chain == 0xFFFF) ? NULL : GetVehicle(o->next_in_chain); - n->value = o->value; - n->string_id = RemapOldStringID(o->string_id); - - switch(o->type) { - case VEH_Train: - n->u.rail.track = o->u.rail.track; - n->u.rail.force_proceed = o->u.rail.force_proceed; - n->u.rail.crash_anim_pos = o->u.rail.crash_anim_pos; - n->u.rail.railtype = o->u.rail.railtype; - break; - - case VEH_Road: - n->u.road.state = o->u.road.state; - n->u.road.frame = o->u.road.frame; - n->u.road.unk2 = o->u.road.unk2; - n->u.road.overtaking = o->u.road.overtaking; - n->u.road.overtaking_ctr = o->u.road.overtaking_ctr; - n->u.road.crashed_ctr = o->u.road.crashed_ctr; - n->u.road.reverse_ctr = o->u.road.reverse_ctr; - break; - case VEH_Ship: - n->u.ship.state = o->u.ship.state; - break; - case VEH_Aircraft: - n->u.air.crashed_counter = o->u.air.crashed_counter; - n->u.air.pos = o->u.air.unk0; - n->u.air.targetairport = o->u.air.targetairport; - n->u.air.state = o->u.air.state; - break; - case VEH_Special: - n->u.special.unk0 = o->u.special.unk0; - n->u.special.unk2 = o->u.special.unk2; - n->subtype = o->subtype >> 1; - break; - case VEH_Disaster: - n->u.disaster.image_override = o->u.disaster.image_override; - n->u.disaster.unk2 = o->u.disaster.unk2; - break; - } - } while (i++,o++,--num); + OCL_SVAR( OC_UINT8, Industry, pct_transported[0] ), + OCL_SVAR( OC_UINT8, Industry, pct_transported[1] ), - /* Check for shared orders, and link them correctly */ - { - Vehicle *v; + OCL_SVAR( OC_UINT16, Industry, total_production[0] ), + OCL_SVAR( OC_UINT16, Industry, total_production[1] ), + OCL_SVAR( OC_UINT16, Industry, total_transported[0] ), + OCL_SVAR( OC_UINT16, Industry, total_transported[1] ), - FOR_ALL_VEHICLES(v) { - Vehicle *u; + OCL_SVAR( OC_UINT8, Industry, type ), + OCL_SVAR( OC_UINT8, Industry, owner ), + OCL_SVAR( OC_UINT8, Industry, color_map ), + OCL_SVAR( OC_UINT8, Industry, last_prod_year ), + OCL_SVAR( OC_UINT16, Industry, counter ), + OCL_SVAR( OC_UINT8, Industry, was_cargo_delivered ), - if (v->type == 0) - continue; + OCL_NULL( 9 ), // Random junk at the end of this chunk - FOR_ALL_VEHICLES_FROM(u, v->index + 1) { - if (u->type == 0) - continue; + OCL_END() +}; +static bool LoadOldIndustry(LoadgameState *ls, int num) +{ + Industry *i; - /* If a vehicle has the same orders, add the link to eachother - in both vehicles */ - if (v->orders == u->orders) { - v->next_shared = u; - u->prev_shared = v; - break; - } - } - } + if (!AddBlockIfNeeded(&_industry_pool, num)) + error("Industries: failed loading savegame: too many industries"); + + i = GetIndustry(num); + if (!LoadChunk(ls, i, industry_chunk)) + return false; + + if (i->xy != 0) { + i->town = GetTown(REMAP_TOWN_IDX(_old_town_index)); } + + return true; } -static void FixSubsidy(Subsidy *n, OldSubsidy *o, int num) +static uint _current_player_id; +static uint16 _old_inaugurated_year; +static int32 _old_yearly; + +static const OldChunks player_yearly_chunk[] = { + OCL_VAR( OC_INT32, 1, &_old_yearly ), + OCL_END() +}; +static bool OldPlayerYearly(LoadgameState *ls, int num) { - do { - n->age = o->age; - n->cargo_type = o->cargo_type; - n->from = o->from; - n->to = o->to; - } while (n++,o++,--num); + int i; + Player *p = DEREF_PLAYER(_current_player_id); + + for (i = 0; i < 13; i++) { + if (!LoadChunk(ls, NULL, player_yearly_chunk)) + return false; + + p->yearly_expenses[num][i] = _old_yearly; + } + + return true; } -static void FixEconomy(PlayerEconomyEntry *n, OldPlayerEconomy *o) +static const OldChunks player_economy_chunk[] = { + OCL_SVAR( OC_INT32, PlayerEconomyEntry, income ), + OCL_SVAR( OC_INT32, PlayerEconomyEntry, expenses ), + OCL_SVAR( OC_INT32, PlayerEconomyEntry, delivered_cargo ), + OCL_SVAR( OC_INT32, PlayerEconomyEntry, performance_history ), + OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, PlayerEconomyEntry, company_value ), + + OCL_END() +}; +static bool OldPlayerEconomy(LoadgameState *ls, int num) { - n->company_value = o->company_value; - n->delivered_cargo = o->delivered_cargo; - n->income = -o->income; - n->expenses = -o->expenses; - n->performance_history = o->performance_history; + int i; + Player *p = DEREF_PLAYER(_current_player_id); + + if (!LoadChunk(ls, &p->cur_economy, player_economy_chunk)) + return false; + + /* Don't ask, but the number in TTD(Patch) are inversed to OpenTTD */ + p->cur_economy.income = -p->cur_economy.income; + p->cur_economy.expenses = -p->cur_economy.expenses; + + for (i = 0; i < 24; i++) { + if (!LoadChunk(ls, &p->old_economy[i], player_economy_chunk)) + return false; + + p->old_economy[i].income = -p->old_economy[i].income; + p->old_economy[i].expenses = -p->old_economy[i].expenses; + } + + return true; } -static void FixAiBuildRec(AiBuildRec *n, OldAiBuildRec *o) +static const OldChunks player_ai_build_rec_chunk[] = { + OCL_SVAR( OC_TILE, AiBuildRec, spec_tile ), + OCL_SVAR( OC_TILE, AiBuildRec, use_tile ), + OCL_SVAR( OC_UINT8, AiBuildRec, rand_rng ), + OCL_SVAR( OC_UINT8, AiBuildRec, cur_building_rule ), + OCL_SVAR( OC_UINT8, AiBuildRec, unk6 ), + OCL_SVAR( OC_UINT8, AiBuildRec, unk7 ), + OCL_SVAR( OC_UINT8, AiBuildRec, buildcmd_a ), + OCL_SVAR( OC_UINT8, AiBuildRec, buildcmd_b ), + OCL_SVAR( OC_UINT8, AiBuildRec, direction ), + OCL_SVAR( OC_UINT8, AiBuildRec, cargo ), + + OCL_NULL( 8 ), // Junk... + + OCL_END() +}; +static bool OldLoadAIBuildRec(LoadgameState *ls, int num) +{ + Player *p = DEREF_PLAYER(_current_player_id); + + switch (num) { + case 0: return LoadChunk(ls, &p->ai.src, player_ai_build_rec_chunk); + case 1: return LoadChunk(ls, &p->ai.dst, player_ai_build_rec_chunk); + case 2: return LoadChunk(ls, &p->ai.mid1, player_ai_build_rec_chunk); + case 3: return LoadChunk(ls, &p->ai.mid2, player_ai_build_rec_chunk); + } + + return false; +} +static const OldChunks player_ai_chunk[] = { + OCL_SVAR( OC_UINT8, PlayerAI, state ), + OCL_NULL( 1 ), // Junk + OCL_SVAR( OC_UINT8, PlayerAI, state_mode ), + OCL_SVAR( OC_UINT16, PlayerAI, state_counter ), + OCL_SVAR( OC_UINT16, PlayerAI, timeout_counter ), + + OCL_CHUNK( 4, OldLoadAIBuildRec ), + + OCL_NULL( 20 ), // More junk + + OCL_SVAR( OC_UINT8, PlayerAI, cargo_type ), + OCL_SVAR( OC_UINT8, PlayerAI, num_wagons ), + OCL_SVAR( OC_UINT8, PlayerAI, build_kind ), + OCL_SVAR( OC_UINT8, PlayerAI, num_build_rec ), + OCL_SVAR( OC_UINT8, PlayerAI, num_loco_to_build ), + OCL_SVAR( OC_UINT8, PlayerAI, num_want_fullload ), + + OCL_NULL( 14 ), // Oh no more junk :| + + OCL_NULL( 2 ), // Loco-id, not used + + OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[0] ), + OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[1] ), + OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[2] ), + OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[3] ), + OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[4] ), + OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[5] ), + OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[6] ), + OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[7] ), + OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[8] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[0] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[1] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[2] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[3] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[4] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[5] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[6] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[7] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[8] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[9] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[10] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[11] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[12] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[13] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[14] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[15] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[16] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[17] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[18] ), + OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[19] ), + + OCL_SVAR( OC_UINT16, PlayerAI, start_tile_a ), + OCL_SVAR( OC_UINT16, PlayerAI, start_tile_b ), + OCL_SVAR( OC_UINT16, PlayerAI, cur_tile_a ), + OCL_SVAR( OC_UINT16, PlayerAI, cur_tile_b ), + + OCL_SVAR( OC_UINT8, PlayerAI, start_dir_a ), + OCL_SVAR( OC_UINT8, PlayerAI, start_dir_b ), + OCL_SVAR( OC_UINT8, PlayerAI, cur_dir_a ), + OCL_SVAR( OC_UINT8, PlayerAI, cur_dir_b ), + + OCL_SVAR( OC_UINT8, PlayerAI, banned_tile_count ), + + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[0] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[0] ), + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[1] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[1] ), + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[2] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[2] ), + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[3] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[3] ), + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[4] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[4] ), + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[5] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[5] ), + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[6] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[6] ), + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[7] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[7] ), + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[8] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[8] ), + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[9] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[9] ), + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[10] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[10] ), + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[11] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[11] ), + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[12] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[12] ), + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[13] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[13] ), + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[14] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[14] ), + OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[15] ), + OCL_SVAR( OC_UINT8, PlayerAI, banned_val[15] ), + + OCL_SVAR( OC_UINT8, PlayerAI, railtype_to_use ), + OCL_SVAR( OC_UINT8, PlayerAI, route_type_mask ), + + OCL_END() +}; +static bool OldPlayerAI(LoadgameState *ls, int num) { - n->spec_tile = o->spec_tile; - n->use_tile = o->use_tile; - n->rand_rng = o->rand_rng; - n->cur_building_rule = o->cur_rule; - n->unk6 = o->unk6; - n->unk7 = o->unk7; - n->buildcmd_a = o->buildcmd_a; - n->buildcmd_b = o->buildcmd_b; - n->direction = o->direction; - n->cargo = o->cargo; + Player *p = DEREF_PLAYER(_current_player_id); + + return LoadChunk(ls, &p->ai, player_ai_chunk); } -static void FixPlayer(Player *n, OldPlayer *o, int num, byte town_name_type) +static const OldChunks player_chunk[] = { + OCL_VAR ( OC_UINT16, 1, &_old_string_id ), + OCL_SVAR( OC_UINT32, Player, name_2 ), + OCL_SVAR( OC_UINT32, Player, face ), + OCL_VAR ( OC_UINT16, 1, &_old_string_id_2 ), + OCL_SVAR( OC_UINT32, Player, president_name_2 ), + + OCL_SVAR( OC_INT32, Player, player_money ), + OCL_SVAR( OC_INT32, Player, current_loan ), + + OCL_SVAR( OC_UINT8, Player, player_color ), + OCL_SVAR( OC_UINT8, Player, player_money_fraction ), + OCL_SVAR( OC_UINT8, Player, quarters_of_bankrupcy ), + OCL_SVAR( OC_UINT8, Player, bankrupt_asked ), + OCL_SVAR( OC_UINT32, Player, bankrupt_value ), + OCL_SVAR( OC_UINT16, Player, bankrupt_timeout ), + + OCL_SVAR( OC_FILE_U32 | OC_VAR_U16, Player, cargo_types ), + + OCL_CHUNK( 3, OldPlayerYearly ), + OCL_CHUNK( 1, OldPlayerEconomy ), + + OCL_VAR ( OC_UINT16, 1, &_old_inaugurated_year ), + OCL_SVAR( OC_TILE, Player, last_build_coordinate ), + OCL_SVAR( OC_UINT8, Player, num_valid_stat_ent ), + + OCL_CHUNK( 1, OldPlayerAI ), + + OCL_SVAR( OC_UINT8, Player, block_preview ), + OCL_SVAR( OC_UINT8, Player, ai.tick ), + OCL_SVAR( OC_UINT8, Player, max_railtype ), + OCL_SVAR( OC_TILE, Player, location_of_house ), + OCL_SVAR( OC_UINT8, Player, share_owners[0] ), + OCL_SVAR( OC_UINT8, Player, share_owners[1] ), + OCL_SVAR( OC_UINT8, Player, share_owners[2] ), + OCL_SVAR( OC_UINT8, Player, share_owners[3] ), + + OCL_NULL( 8 ), // junk at end of chunk + + OCL_END() +}; +static bool LoadOldPlayer(LoadgameState *ls, int num) { - int i, j; - int x = 0; - - do { - n->name_1 = RemapOldStringID(o->name_1); - n->name_2 = o->name_2; - /* In every Old TTD(Patch) game Player1 (0) is human, and all others are AI - * (Except in .SV2 savegames, which were 2 player games, but we are not fixing - * that - */ - - if (x == 0) { - if (o->name_1 == 0) // if first player doesn't have a name, he is 'unnamed' - n->name_1 = STR_SV_UNNAMED; - } else { - n->is_ai = 1; - } + Player *p = DEREF_PLAYER(num); - if (o->name_1 != 0) - n->is_active = true; - - n->face = o->face; - n->president_name_1 = o->pres_name_1; - n->president_name_2 = o->pres_name_2; - - n->money64 = n->player_money = o->money; - n->current_loan = o->loan; - - // Correct money for scenario loading. - // It's always 893288 pounds (and no loan), if not corrected - if(o->money==0xda168) - n->money64 = n->player_money = n->current_loan =100000; - - n->player_color = o->color; - _player_colors[x] = o->color; - x++; - - n->player_money_fraction = o->money_fract; - n->quarters_of_bankrupcy = o->quarters_of_bankrupcy; - n->bankrupt_asked = o->bankrupt_asked; - n->bankrupt_value = o->bankrupt_value; - n->bankrupt_timeout = o->bankrupt_timeout; - n->cargo_types = o->cargo_types; - - for(i=0; i!=3; i++) - for(j=0; j!=13; j++) - n->yearly_expenses[i][j] = o->expenses[i].cost[j]; - - FixEconomy(&n->cur_economy, &o->economy[0]); - for(i=0; i!=24; i++) FixEconomy(&n->old_economy[i], &o->economy[i+1]); - n->inaugurated_year = o->inaugurated_date - MAX_YEAR_BEGIN_REAL; - n->last_build_coordinate = o->last_build_coordinate; - n->num_valid_stat_ent = o->num_valid_stat_ent; - - /* Not good, since AI doesn't have a vehicle assigned as - * in p->ai.cur_veh and thus will crash on certain actions. - * Best is to set state to AiStateVehLoop (2) - * n->ai.state = o->ai_state; - */ - n->ai.state = 2; - n->ai.state_mode = o->ai_state_mode; - n->ai.state_counter = o->ai_state_counter; - n->ai.timeout_counter = o->ai_timeout_counter; - n->ai.banned_tile_count = o->ai_banned_tile_count; - n->ai.railtype_to_use = o->ai_railtype_to_use; - - FixAiBuildRec(&n->ai.src, &o->ai_src); - FixAiBuildRec(&n->ai.dst, &o->ai_dst); - FixAiBuildRec(&n->ai.mid1, &o->ai_mid1); - FixAiBuildRec(&n->ai.mid2, &o->ai_mid2); - - n->ai.cargo_type = o->ai_cargo_type; - n->ai.num_wagons = o->ai_num_wagons; - n->ai.num_build_rec = o->ai_num_build_rec; - n->ai.num_loco_to_build = o->ai_num_loco_to_build; - n->ai.num_want_fullload = o->ai_num_want_fullload; - - for(i=0; i!=9; i++) n->ai.wagon_list[i] = o->ai_wagonlist[i]; - memcpy(n->ai.order_list_blocks, o->ai_order_list_blocks, 20); - n->ai.start_tile_a = o->ai_start_tile_a; - n->ai.start_tile_b = o->ai_start_tile_b; - n->ai.cur_tile_a = o->ai_cur_tile_a; - n->ai.cur_tile_b = o->ai_cur_tile_b; - n->ai.start_dir_a = o->ai_start_dir_a; - n->ai.start_dir_b = o->ai_start_dir_b; - n->ai.cur_dir_a = o->ai_cur_dir_a; - n->ai.cur_dir_b = o->ai_cur_dir_b; - - for(i=0; i!=16; i++) { - n->ai.banned_tiles[i] = o->banned_tiles[i].tile; - n->ai.banned_val[i] = o->banned_tiles[i].data; - } + _current_player_id = num; - n->ai.build_kind = o->ai_build_kind; - n->ai.route_type_mask = o->ai_route_type_mask; - n->ai.tick = o->ai_tick; + if (!LoadChunk(ls, p, player_chunk)) + return false; - n->block_preview = o->block_preview; - n->max_railtype = (o->max_railtype == 0) ? 1 : o->max_railtype; - n->location_of_house = o->location_of_house; - if (o->location_of_house == 0xFFFF) n->location_of_house = 0; + p->name_1 = RemapOldStringID(_old_string_id); + p->president_name_1 = RemapOldStringID(_old_string_id_2); + p->money64 = p->player_money; - n->share_owners[0] = o->share_owners[0]; - n->share_owners[1] = o->share_owners[1]; - n->share_owners[2] = o->share_owners[2]; - n->share_owners[3] = o->share_owners[3]; + if (num == 0) { + /* If the first player has no name, make sure we call it UNNAMED */ + if (p->name_1 == 0) + p->name_1 = STR_SV_UNNAMED; + } else { + /* Beside some multiplayer maps (1 on 1), which we don't official support, + all other players are an AI.. mark them as such */ + p->is_ai = 1; + } - if (o->ai_state == 2) { - n->ai.cur_veh = NULL; - } - } while (n++,o++,--num); + /* Sometimes it is better to not ask.. in old scenarios, the money + was always 893288 pounds. In the newer versions this is correct, + but correct for those oldies + Ps: this also means that if you had exact 893288 pounds, you will go back + to 10000.. this is a very VERY small chance ;) */ + if (p->player_money == 0xda168) + p->money64 = p->player_money = p->current_loan = 100000; + + _player_colors[num] = p->player_color; + p->inaugurated_year = _old_inaugurated_year - MAX_YEAR_BEGIN_REAL; + if (p->location_of_house == 0xFFFF) + p->location_of_house = 0; + + return true; } -static void FixName(OldName *o, int num) +static uint32 _old_order_ptr; +static uint16 _old_next_ptr; +static uint32 _current_vehicle_id; + +static const OldChunks vehicle_train_chunk[] = { + OCL_SVAR( OC_UINT8, VehicleRail, track ), + OCL_SVAR( OC_UINT8, VehicleRail, force_proceed ), + OCL_SVAR( OC_UINT16, VehicleRail, crash_anim_pos ), + OCL_SVAR( OC_UINT8, VehicleRail, railtype ), + + OCL_NULL( 5 ), // Junk + + OCL_END() +}; +static const OldChunks vehicle_road_chunk[] = { + OCL_SVAR( OC_UINT8, VehicleRoad, state ), + OCL_SVAR( OC_UINT8, VehicleRoad, frame ), + OCL_SVAR( OC_UINT16, VehicleRoad, unk2 ), + OCL_SVAR( OC_UINT8, VehicleRoad, overtaking ), + OCL_SVAR( OC_UINT8, VehicleRoad, overtaking_ctr ), + OCL_SVAR( OC_UINT16, VehicleRoad, crashed_ctr ), + OCL_SVAR( OC_UINT8, VehicleRoad, reverse_ctr ), + + OCL_NULL( 1 ), // Junk + + OCL_END() +}; +static const OldChunks vehicle_ship_chunk[] = { + OCL_SVAR( OC_UINT8, VehicleShip, state ), + + OCL_NULL( 9 ), // Junk + + OCL_END() +}; +static const OldChunks vehicle_air_chunk[] = { + OCL_SVAR( OC_UINT8, VehicleAir, pos ), + OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, VehicleAir, targetairport ), + OCL_SVAR( OC_UINT16, VehicleAir, crashed_counter ), + OCL_SVAR( OC_UINT8, VehicleAir, state ), + + OCL_NULL( 5 ), // Junk + + OCL_END() +}; +static const OldChunks vehicle_special_chunk[] = { + OCL_SVAR( OC_UINT16, VehicleSpecial, unk0 ), + OCL_SVAR( OC_UINT8, VehicleSpecial, unk2 ), + + OCL_NULL( 7 ), // Junk + + OCL_END() +}; +static const OldChunks vehicle_disaster_chunk[] = { + OCL_SVAR( OC_UINT16, VehicleDisaster, image_override ), + OCL_SVAR( OC_UINT16, VehicleDisaster, unk2 ), + + OCL_NULL( 6 ), // Junk + + OCL_END() +}; +static const OldChunks vehicle_empty_chunk[] = { + OCL_NULL( 10 ), // Junk + + OCL_END() +}; +static bool LoadOldVehicleUnion(LoadgameState *ls, int num) { - int i; - for(i=0; i!=num; i++) { - memcpy(_name_array[i], o[i].name, sizeof(o[i].name)); + Vehicle *v = GetVehicle(_current_vehicle_id); + uint temp = ls->total_read; + bool res; + + switch (v->type) { + case VEH_Train: res = LoadChunk(ls, &v->u.rail, vehicle_train_chunk); break; + case VEH_Road: res = LoadChunk(ls, &v->u.road, vehicle_road_chunk); break; + case VEH_Ship: res = LoadChunk(ls, &v->u.ship, vehicle_ship_chunk); break; + case VEH_Aircraft: res = LoadChunk(ls, &v->u.air, vehicle_air_chunk); break; + case VEH_Special: res = LoadChunk(ls, &v->u.special, vehicle_special_chunk); break; + case VEH_Disaster: res = LoadChunk(ls, &v->u.disaster, vehicle_disaster_chunk); break; + default: res = LoadChunk(ls, NULL, vehicle_empty_chunk); break; + } + + /* This chunk size should always be 10 bytes */ + if (ls->total_read - temp != 10) { + DEBUG(oldloader, 4)("[OldLoader] Assert failed in Vehicle"); + return false; } + + return res; } -static void FixSign(OldSign *o, int num) +static const OldChunks vehicle_chunk[] = { + OCL_SVAR( OC_UINT8, Vehicle, type ), + OCL_SVAR( OC_UINT8, Vehicle, subtype ), + + OCL_NULL( 2 ), // Hash, calculated automaticly + OCL_NULL( 2 ), // Index, calculated automaticly + + OCL_VAR ( OC_UINT32, 1, &_old_order_ptr ), + OCL_VAR ( OC_UINT16, 1, &_old_order ), + + OCL_SVAR( OC_UINT8, Vehicle, num_orders ), + OCL_SVAR( OC_UINT8, Vehicle, cur_order_index ), + OCL_SVAR( OC_TILE, Vehicle, dest_tile ), + OCL_SVAR( OC_UINT16, Vehicle, load_unload_time_rem ), + OCL_SVAR( OC_UINT16, Vehicle, date_of_last_service ), + OCL_SVAR( OC_UINT16, Vehicle, service_interval ), + OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, last_station_visited ), + OCL_SVAR( OC_UINT8, Vehicle, tick_counter ), + OCL_SVAR( OC_UINT16, Vehicle, max_speed ), + + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, x_pos ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, y_pos ), + OCL_SVAR( OC_UINT8, Vehicle, z_pos ), + OCL_SVAR( OC_UINT8, Vehicle, direction ), + OCL_SVAR( OC_INT8, Vehicle, x_offs ), + OCL_SVAR( OC_INT8, Vehicle, y_offs ), + OCL_SVAR( OC_UINT8, Vehicle, sprite_width ), + OCL_SVAR( OC_UINT8, Vehicle, sprite_height ), + OCL_SVAR( OC_UINT8, Vehicle, z_height ), + + OCL_SVAR( OC_UINT8, Vehicle, owner ), + OCL_SVAR( OC_TILE, Vehicle, tile ), + OCL_SVAR( OC_UINT16, Vehicle, cur_image ), + + OCL_NULL( 8 ), // Vehicle sprite box, calculated automaticly + + OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, Vehicle, vehstatus ), + OCL_SVAR( OC_UINT16, Vehicle, cur_speed ), + OCL_SVAR( OC_UINT8, Vehicle, subspeed ), + OCL_SVAR( OC_UINT8, Vehicle, acceleration ), + OCL_SVAR( OC_UINT8, Vehicle, progress ), + + OCL_SVAR( OC_UINT8, Vehicle, cargo_type ), + OCL_SVAR( OC_UINT16, Vehicle, cargo_cap ), + OCL_SVAR( OC_UINT16, Vehicle, cargo_count ), + OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, cargo_source ), + OCL_SVAR( OC_UINT8, Vehicle, cargo_days ), + + OCL_SVAR( OC_UINT16, Vehicle, age ), + OCL_SVAR( OC_UINT16, Vehicle, max_age ), + OCL_SVAR( OC_UINT8, Vehicle, build_year ), + OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, unitnumber ), + + OCL_SVAR( OC_UINT16, Vehicle, engine_type ), + + OCL_SVAR( OC_UINT8, Vehicle, spritenum ), + OCL_SVAR( OC_UINT8, Vehicle, day_counter ), + + OCL_SVAR( OC_UINT8, Vehicle, breakdowns_since_last_service ), + OCL_SVAR( OC_UINT8, Vehicle, breakdown_ctr ), + OCL_SVAR( OC_UINT8, Vehicle, breakdown_delay ), + OCL_SVAR( OC_UINT8, Vehicle, breakdown_chance ), + + OCL_SVAR( OC_UINT16, Vehicle, reliability ), + OCL_SVAR( OC_UINT16, Vehicle, reliability_spd_dec ), + + OCL_SVAR( OC_INT32, Vehicle, profit_this_year ), + OCL_SVAR( OC_INT32, Vehicle, profit_last_year ), + + OCL_VAR ( OC_UINT16, 1, &_old_next_ptr ), + + OCL_SVAR( OC_UINT32, Vehicle, value ), + + OCL_VAR ( OC_UINT16, 1, &_old_string_id ), + + OCL_CHUNK( 1, LoadOldVehicleUnion ), + + OCL_NULL( 20 ), // Junk at end of struct (TTDPatch has some data in it) + + OCL_END() +}; +static bool LoadOldVehicle(LoadgameState *ls, int num) { - SignStruct *n; - uint i = 0; + uint i; - do { - if (o->text == 0) - continue; + /* Read the TTDPatch flags, because we need some info from it */ + ReadTTDPatchFlags(); - if (!AddBlockIfNeeded(&_sign_pool, i)) - error("Signs: failed loading savegame: too many signs"); + for (i = 0; i < _old_vehicle_multipler; i++) { + Vehicle *v; - n = GetSign(i); + _current_vehicle_id = num * _old_vehicle_multipler + i; - n->str = o->text; - n->x = o->x; - n->y = o->y; - n->z = o->z; - } while (i++,o++,--num); + if (!AddBlockIfNeeded(&_vehicle_pool, _current_vehicle_id)) + error("Vehicles: failed loading savegame: too many vehicles"); + + v = GetVehicle(_current_vehicle_id); + if (!LoadChunk(ls, v, vehicle_chunk)) + return false; + + if (_old_order_ptr != 0 && _old_order_ptr != 0xFFFFFFFF) { + v->orders = GetOrder(REMAP_ORDER_IDX(_old_order_ptr)); + } + AssignOrder(&v->current_order, UnpackOldOrder(_old_order)); + /* TTDPatch maps sprites from 0x2000 up. */ + if (v->cur_image >= 0x2000) + v->cur_image -= 0x2000 - _custom_sprites_base; + + /* For some reason we need to correct for this */ + switch (v->spritenum) { + case 0xfd: break; + case 0xff: v->spritenum = 0xfe; break; + default: v->spritenum >>= 1; break; + } + + if (_old_next_ptr != 0xFFFF) + v->next = GetVehicle(_old_next_ptr); + + v->string_id = RemapOldStringID(_old_string_id); + + /* Vehicle-subtype is different in TTD(Patch) */ + if (v->type == VEH_Special) + v->subtype = v->subtype >> 1; + } + + return true; } -static void FixEngine(Engine *n, OldEngine *o, int num) +static const OldChunks sign_chunk[] = { + OCL_SVAR( OC_UINT16, SignStruct, str ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32,SignStruct, x ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32,SignStruct, y ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I8, SignStruct, z ), + + OCL_NULL( 6 ), // Width of sign, no longer in use + + OCL_END() +}; +static bool LoadOldSign(LoadgameState *ls, int num) { - int i = 0; - - do { - n->player_avail = o->player_avail; - n->intro_date = o->intro_date; - n->age = o->age; - if ((i >= 27 && i < 54) || (i >= 57 && i < 84) || (i >= 89 && i < 116)) - n->age = 0xffff; - n->reliability = o->reliability; - n->reliability_spd_dec = o->reliability_spd_dec; - n->reliability_start = o->reliability_start; - n->reliability_max = o->reliability_max; - n->reliability_final = o->reliability_final; - n->duration_phase_1 = o->duration_phase_1; - n->duration_phase_2 = o->duration_phase_2; - n->duration_phase_3 = o->duration_phase_3; - n->lifelength = o->lifelength; - n->flags = o->flags; - n->preview_player = o->preview_player; - n->preview_wait = o->preview_wait; - n->railtype = o->railtype; - } while (n++,o++,i++,--num); + if (!AddBlockIfNeeded(&_sign_pool, num)) + error("Signs: failed loading savegame: too many signs"); + + return LoadChunk(ls, GetSign(num), sign_chunk); } -static void FixGameDifficulty(GameDifficulty *n, OldGameSettings *o) +static const OldChunks engine_chunk[] = { + OCL_SVAR( OC_UINT16, Engine, player_avail ), + OCL_SVAR( OC_UINT16, Engine, intro_date ), + OCL_SVAR( OC_UINT16, Engine, age ), + OCL_SVAR( OC_UINT16, Engine, reliability ), + OCL_SVAR( OC_UINT16, Engine, reliability_spd_dec ), + OCL_SVAR( OC_UINT16, Engine, reliability_start ), + OCL_SVAR( OC_UINT16, Engine, reliability_max ), + OCL_SVAR( OC_UINT16, Engine, reliability_final ), + OCL_SVAR( OC_UINT16, Engine, duration_phase_1 ), + OCL_SVAR( OC_UINT16, Engine, duration_phase_2 ), + OCL_SVAR( OC_UINT16, Engine, duration_phase_3 ), + + OCL_SVAR( OC_UINT8, Engine, lifelength ), + OCL_SVAR( OC_UINT8, Engine, flags ), + OCL_SVAR( OC_UINT8, Engine, preview_player ), + OCL_SVAR( OC_UINT8, Engine, preview_wait ), + OCL_SVAR( OC_UINT8, Engine, railtype ), + + OCL_NULL( 1 ), // Junk + + OCL_END() +}; +static bool LoadOldEngine(LoadgameState *ls, int num) { - n->max_no_competitors = o->max_no_competitors; - n->competitor_start_time = o->competitor_start_time; - n->number_towns = o->number_towns; - n->number_industries = o->number_industries; - n->max_loan = o->max_loan; - n->initial_interest = o->initial_interest; - n->vehicle_costs = o->vehicle_costs; - n->competitor_speed = o->competitor_speed; - n->competitor_intelligence = o->competitor_intelligence; - n->vehicle_breakdowns = o->vehicle_breakdowns; - n->subsidy_multiplier = o->subsidy_multiplier; - n->construction_cost = o->construction_cost; - n->terrain_type = o->terrain_type; - n->quantity_sea_lakes = o->quantity_sea_lakes; - n->economy = o->economy; - n->line_reverse_mode = o->line_reverse_mode; - n->disasters = o->disasters; + if (!LoadChunk(ls, &_engines[num], engine_chunk)) + return false; + + /* Make sure wagons are marked as do-not-age */ + if ((num >= 27 && num < 54) || (num >= 57 && num < 84) || (num >= 89 && num < 116)) + _engines[num].age = 0xFFFF; + + return true; } -#ifdef TTD_BIG_ENDIAN -/* This function fixes the endiannes issues on Big Endian machines. - * Obviously only uint16 (WORD) and uint32 (LONG WORD) 's are fixed - * since these are different on Big Endian machines. A single byte has - * the same ordening */ -static void FixEndianness(OldMain *m) +static const OldChunks subsidy_chunk[] = { + OCL_SVAR( OC_UINT8, Subsidy, cargo_type ), + OCL_SVAR( OC_UINT8, Subsidy, age ), + OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Subsidy, from ), + OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Subsidy, to ), + + OCL_END() +}; +static bool LoadOldSubsidy(LoadgameState *ls, int num) { - int i; - m->date = BSWAP16(m->date); - m->date_fract = BSWAP16(m->date_fract); - m->seed_1 = BSWAP32(m->seed_1); - m->seed_2 = BSWAP32(m->seed_2); - - /* ----------- TOWNS ----------- */ - for (i = 0; i < 70; i++) { // OldTown town_list[70]; - int j; - m->town_list[i].xy = BSWAP16(m->town_list[i].xy); - m->town_list[i].population = BSWAP16(m->town_list[i].population); - m->town_list[i].townnametype = BSWAP16(m->town_list[i].townnametype); - m->town_list[i].townnameparts = BSWAP32(m->town_list[i].townnameparts); - m->town_list[i].sign_left = BSWAP16(m->town_list[i].sign_left); - m->town_list[i].sign_top = BSWAP16(m->town_list[i].sign_top); - m->town_list[i].flags12 = BSWAP16(m->town_list[i].flags12); - for (j = 0; j < 5; j++) // uint16 radius[5]; - m->town_list[i].radius[j] = BSWAP16(m->town_list[i].radius[j]); - for (j = 0; j < 8; j++) // uint16 ratings[8]; - m->town_list[i].ratings[j] = BSWAP16(m->town_list[i].ratings[j]); - m->town_list[i].have_ratings = BSWAP32(m->town_list[i].have_ratings); - m->town_list[i].statues = BSWAP32(m->town_list[i].statues); - m->town_list[i].num_houses = BSWAP16(m->town_list[i].num_houses); - m->town_list[i].new_max_pass = BSWAP16(m->town_list[i].new_max_pass); - m->town_list[i].new_max_mail = BSWAP16(m->town_list[i].new_max_mail); - m->town_list[i].new_act_pass = BSWAP16(m->town_list[i].new_act_pass); - m->town_list[i].new_act_mail = BSWAP16(m->town_list[i].new_act_mail); - m->town_list[i].max_pass = BSWAP16(m->town_list[i].max_pass); - m->town_list[i].max_mail = BSWAP16(m->town_list[i].max_mail); - m->town_list[i].act_pass = BSWAP16(m->town_list[i].act_pass); - m->town_list[i].act_mail = BSWAP16(m->town_list[i].act_mail); - m->town_list[i].new_act_food = BSWAP16(m->town_list[i].new_act_food); - m->town_list[i].new_act_water = BSWAP16(m->town_list[i].new_act_water); - m->town_list[i].act_food = BSWAP16(m->town_list[i].act_food); - m->town_list[i].act_water = BSWAP16(m->town_list[i].act_water); - m->town_list[i].unk56 = BSWAP32(m->town_list[i].unk56); - m->town_list[i].unk5A = BSWAP32(m->town_list[i].unk5A); - } + return LoadChunk(ls, &_subsidies[num], subsidy_chunk); +} - /* ----------- ORDER LIST ----------- */ - for (i = 0; i < 5000; i++) // uint16 order_list[5000]; - m->order_list[i] = BSWAP16(m->order_list[i]); +static const OldChunks game_difficulty_chunk[] = { + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, max_no_competitors ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, competitor_start_time ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, number_towns ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, number_industries ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, max_loan ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, initial_interest ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, vehicle_costs ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, competitor_speed ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, competitor_intelligence ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, vehicle_breakdowns ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, subsidy_multiplier ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, construction_cost ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, terrain_type ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, quantity_sea_lakes ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, economy ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, line_reverse_mode ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, disasters ), + OCL_END() +}; +static bool LoadOldGameDifficulty(LoadgameState *ls, int num) +{ + return LoadChunk(ls, &_opt.diff, game_difficulty_chunk); +} - /* ----------- ANIMATED TILE LIST ----------- */ - for (i = 0; i < 256; i++) // uint16 animated_tile_list[256]; - m->animated_tile_list[i] = BSWAP16(m->animated_tile_list[i]); - m->ptr_to_next_order = BSWAP32(m->ptr_to_next_order); +static bool LoadOldMapPart1(LoadgameState *ls, int num) +{ + uint i; - /* ----------- DEPOTS ----------- */ - for (i = 0; i < 255; i++) { // OldDepot depots[255]; - m->depots[i].xy = BSWAP16(m->depots[i].xy); - m->depots[i].town = BSWAP32(m->depots[i].town); + for (i = 0; i < OLD_MAP_SIZE; i++) { + _map_owner[i] = ReadByte(ls); } - - m->cur_town_ptr = BSWAP32(m->cur_town_ptr); - m->timer_counter = BSWAP16(m->timer_counter); - m->land_code = BSWAP16(m->land_code); - m->age_cargo_skip_counter = BSWAP16(m->age_cargo_skip_counter); - m->tick_counter = BSWAP16(m->tick_counter); - m->cur_tileloop_tile = BSWAP16(m->cur_tileloop_tile); - - /* ----------- PRICES ----------- */ - for (i = 0; i < 49; i++) { // OldPrice prices[49]; - m->prices[i].price = BSWAP32(m->prices[i].price); - m->prices[i].frac = BSWAP16(m->prices[i].frac); + for (i = 0; i < OLD_MAP_SIZE; i++) { + _map2[i] = ReadByte(ls); } - - /* ----------- CARGO PAYMENT RATES ----------- */ - for (i = 0; i < 12; i++) { // OldPaymentRate cargo_payment_rates[12]; - m->cargo_payment_rates[i].price = BSWAP32(m->cargo_payment_rates[i].price); - m->cargo_payment_rates[i].frac = BSWAP16(m->cargo_payment_rates[i].frac); - m->cargo_payment_rates[i].unused = BSWAP16(m->cargo_payment_rates[i].unused); + for (i = 0; i < OLD_MAP_SIZE; i++) { + _old_map3[i * 2] = ReadByte(ls); + _old_map3[i * 2 + 1] = ReadByte(ls); + } + for (i = 0; i < OLD_MAP_SIZE / 4; i++) { + _map_extra_bits[i] = ReadByte(ls); } - /* ----------- MAP3 ----------- */ - for (i = 0; i < (256*256); i++) // uint16 map3[256*256]; - m->map3[i] = BSWAP16(m->map3[i]); - - /* ----------- STATIONS ----------- */ - for (i = 0; i < 250; i++) { // OldStation stations[250]; - int j; - m->stations[i].xy = BSWAP16(m->stations[i].xy); - m->stations[i].town = BSWAP32(m->stations[i].town); - m->stations[i].bus_tile = BSWAP16(m->stations[i].bus_tile); - m->stations[i].lorry_tile = BSWAP16(m->stations[i].lorry_tile); - m->stations[i].train_tile = BSWAP16(m->stations[i].train_tile); - m->stations[i].airport_tile = BSWAP16(m->stations[i].airport_tile); - m->stations[i].dock_tile = BSWAP16(m->stations[i].dock_tile); - m->stations[i].string_id = BSWAP16(m->stations[i].string_id); - m->stations[i].sign_left = BSWAP16(m->stations[i].sign_left); - m->stations[i].sign_top = BSWAP16(m->stations[i].sign_top); - m->stations[i].had_vehicle_of_type = BSWAP16(m->stations[i].had_vehicle_of_type); - for (j = 0; j < 12; j++) // OldGoodsEntry goods[12]; - m->stations[i].goods[j].waiting_acceptance = BSWAP16(m->stations[i].goods[j].waiting_acceptance); - m->stations[i].airport_flags = BSWAP16(m->stations[i].airport_flags); - m->stations[i].last_vehicle = BSWAP16(m->stations[i].last_vehicle); - m->stations[i].unk8A = BSWAP32(m->stations[i].unk8A); + if (ls->failed) + return false; + + return true; +} +static bool LoadOldMapPart2(LoadgameState *ls, int num) +{ + uint i; + + for (i = 0; i < OLD_MAP_SIZE; i++) { + _map_type_and_height[i] = ReadByte(ls); + } + for (i = 0; i < OLD_MAP_SIZE; i++) { + _map5[i] = ReadByte(ls); } - /* ----------- INDUSTRIES ----------- */ - for (i = 0; i < 90; i++) { // OldIndustry industries[90]; - m->industries[i].xy = BSWAP16(m->industries[i].xy); - m->industries[i].town = BSWAP32(m->industries[i].town); - m->industries[i].cargo_waiting[0] = BSWAP16(m->industries[i].cargo_waiting[0]); - m->industries[i].cargo_waiting[1] = BSWAP16(m->industries[i].cargo_waiting[1]); + if (ls->failed) + return false; - m->industries[i].last_mo_production[0] = BSWAP16(m->industries[i].last_mo_production[0]); - m->industries[i].last_mo_production[1] = BSWAP16(m->industries[i].last_mo_production[1]); + return true; +} - m->industries[i].last_mo_transported[0] = BSWAP16(m->industries[i].last_mo_transported[0]); - m->industries[i].last_mo_transported[1] = BSWAP16(m->industries[i].last_mo_transported[1]); - m->industries[i].total_production[0] = BSWAP16(m->industries[i].total_production[0]); - m->industries[i].total_production[1] = BSWAP16(m->industries[i].total_production[1]); +static uint32 _old_cur_town_ctr; +static const OldChunks main_chunk[] = { + OCL_ASSERT( 0 ), + OCL_VAR ( OC_UINT16, 1, &_date ), + OCL_VAR ( OC_UINT16, 1, &_date_fract ), + OCL_NULL( 600 ), // TextEffects + OCL_VAR ( OC_UINT32, 2, &_random_seeds[0] ), - m->industries[i].total_transported[0] = BSWAP16(m->industries[i].total_transported[0]); - m->industries[i].total_transported[1] = BSWAP16(m->industries[i].total_transported[1]); - m->industries[i].counter = BSWAP16(m->industries[i].counter); - m->industries[i].unk2E = BSWAP32(m->industries[i].unk2E); - m->industries[i].unk32 = BSWAP32(m->industries[i].unk32); - } + OCL_ASSERT( 0x264 ), + OCL_CHUNK( 70, LoadOldTown ), + OCL_ASSERT( 0x1C18 ), + OCL_CHUNK(5000, LoadOldOrder ), + OCL_ASSERT( 0x4328 ), - /* ----------- PLAYERS ----------- */ - for (i = 0; i < 8; i++) { // OldPlayer players[8]; - int j, k; - m->players[i].name_1 = BSWAP16(m->players[i].name_1); - m->players[i].name_2 = BSWAP32(m->players[i].name_2); - m->players[i].face = BSWAP32(m->players[i].face); - m->players[i].pres_name_1 = BSWAP16(m->players[i].pres_name_1); - m->players[i].pres_name_2 = BSWAP32(m->players[i].pres_name_2); - m->players[i].money = BSWAP32(m->players[i].money); - m->players[i].loan = BSWAP32(m->players[i].loan); - m->players[i].bankrupt_value = BSWAP32(m->players[i].bankrupt_value); - m->players[i].bankrupt_timeout = BSWAP16(m->players[i].bankrupt_timeout); - m->players[i].cargo_types = BSWAP32(m->players[i].cargo_types); - - for (j = 0; j < 3; j++) { // OldPlayerExpenses expenses[3]; - for (k = 0; k < 13; k++) - m->players[i].expenses[j].cost[k] = BSWAP32(m->players[i].expenses[j].cost[k]); - } + OCL_VAR ( OC_TILE, 256, &_animated_tile_list[0] ), + OCL_NULL( 4 ), // old end-of-order-list-pointer, no longer in use - for (j = 0; j < (24 + 1); j++) { // OldPlayerEconomy economy[24 + 1]; - m->players[i].economy->income = BSWAP32(m->players[i].economy->income); - m->players[i].economy->expenses = BSWAP32(m->players[i].economy->expenses); - m->players[i].economy->delivered_cargo = BSWAP32(m->players[i].economy->delivered_cargo); - m->players[i].economy->performance_history = BSWAP32(m->players[i].economy->performance_history); - m->players[i].economy->company_value = BSWAP32(m->players[i].economy->company_value); - } + OCL_CHUNK( 255, LoadOldDepot ), + OCL_ASSERT( 0x4B26 ), - m->players[i].inaugurated_date = BSWAP16(m->players[i].inaugurated_date); - m->players[i].last_build_coordinate = BSWAP16(m->players[i].last_build_coordinate); - m->players[i].ai_state_counter = BSWAP16(m->players[i].ai_state_counter); - m->players[i].ai_timeout_counter = BSWAP16(m->players[i].ai_timeout_counter); - - // OldAiBuildRec ai_src, ai_dst, ai_mid1, ai_mid2; - m->players[i].ai_src.spec_tile = BSWAP16(m->players[i].ai_src.spec_tile); - m->players[i].ai_src.use_tile = BSWAP16(m->players[i].ai_src.use_tile); - m->players[i].ai_dst.spec_tile = BSWAP16(m->players[i].ai_dst.spec_tile); - m->players[i].ai_dst.use_tile = BSWAP16(m->players[i].ai_dst.use_tile); - m->players[i].ai_mid1.spec_tile = BSWAP16(m->players[i].ai_mid1.spec_tile); - m->players[i].ai_mid1.use_tile = BSWAP16(m->players[i].ai_mid1.use_tile); - m->players[i].ai_mid2.spec_tile = BSWAP16(m->players[i].ai_mid2.spec_tile); - m->players[i].ai_mid2.use_tile = BSWAP16(m->players[i].ai_mid2.use_tile); - - m->players[i].ai_loco_id = BSWAP16(m->players[i].ai_loco_id); - - for (j = 0; j < 9; j++) - m->players[i].ai_wagonlist[j] = BSWAP16(m->players[i].ai_wagonlist[j]); - m->players[i].ai_start_tile_a = BSWAP16(m->players[i].ai_start_tile_a); - m->players[i].ai_start_tile_b = BSWAP16(m->players[i].ai_start_tile_b); - m->players[i].ai_cur_tile_a = BSWAP16(m->players[i].ai_cur_tile_a); - m->players[i].ai_cur_tile_b = BSWAP16(m->players[i].ai_cur_tile_b); - for (j = 0; j < 16; j++) // OldAiBannedTile banned_tiles[16]; - m->players[i].banned_tiles[j].tile= BSWAP16(m->players[i].banned_tiles[j].tile); - m->players[i].location_of_house = BSWAP16(m->players[i].location_of_house); - m->players[i].unk3AA = BSWAP32(m->players[i].unk3AA); - m->players[i].unk3AE = BSWAP32(m->players[i].unk3AE); - } + OCL_VAR ( OC_UINT32, 1, &_old_cur_town_ctr ), + OCL_NULL( 2 ), // timer_counter, no longer in use + OCL_NULL( 2 ), // land_code, no longer in use - /* ----------- VEHICLES ----------- */ - for (i = 0; i < 850; i++) { // OldVehicle vehicles[850]; - m->vehicles[i].next_hash = BSWAP16(m->vehicles[i].next_hash); - m->vehicles[i].index = BSWAP16(m->vehicles[i].index); - m->vehicles[i].schedule_ptr = BSWAP32(m->vehicles[i].schedule_ptr); - m->vehicles[i].dest_tile = BSWAP16(m->vehicles[i].dest_tile); - m->vehicles[i].load_unload_time_rem = BSWAP16(m->vehicles[i].load_unload_time_rem); - m->vehicles[i].date_of_last_service = BSWAP16(m->vehicles[i].date_of_last_service); - m->vehicles[i].service_interval = BSWAP16(m->vehicles[i].service_interval); - m->vehicles[i].max_speed = BSWAP16(m->vehicles[i].max_speed); - m->vehicles[i].x_pos = BSWAP16(m->vehicles[i].x_pos); - m->vehicles[i].y_pos = BSWAP16(m->vehicles[i].y_pos); - m->vehicles[i].tile = BSWAP16(m->vehicles[i].tile); - m->vehicles[i].cur_image = BSWAP16(m->vehicles[i].cur_image); - m->vehicles[i].left_coord = BSWAP16(m->vehicles[i].left_coord); - m->vehicles[i].right_coord = BSWAP16(m->vehicles[i].right_coord); - m->vehicles[i].top_coord = BSWAP16(m->vehicles[i].top_coord); - m->vehicles[i].bottom_coord = BSWAP16(m->vehicles[i].bottom_coord); - m->vehicles[i].vehstatus = BSWAP16(m->vehicles[i].vehstatus); - m->vehicles[i].cur_speed = BSWAP16(m->vehicles[i].cur_speed); - m->vehicles[i].capacity = BSWAP16(m->vehicles[i].capacity); - m->vehicles[i].number_of_pieces = BSWAP16(m->vehicles[i].number_of_pieces); - m->vehicles[i].age_in_days = BSWAP16(m->vehicles[i].age_in_days); - m->vehicles[i].max_age_in_days = BSWAP16(m->vehicles[i].max_age_in_days); - m->vehicles[i].engine_type = BSWAP16(m->vehicles[i].engine_type); - m->vehicles[i].reliability = BSWAP16(m->vehicles[i].reliability); - m->vehicles[i].reliability_spd_dec = BSWAP16(m->vehicles[i].reliability_spd_dec); - m->vehicles[i].profit_this_year = BSWAP32(m->vehicles[i].profit_this_year); - m->vehicles[i].profit_last_year = BSWAP32(m->vehicles[i].profit_last_year); - m->vehicles[i].next_in_chain = BSWAP16(m->vehicles[i].next_in_chain); - m->vehicles[i].value = BSWAP32(m->vehicles[i].value); - m->vehicles[i].string_id = BSWAP16(m->vehicles[i].string_id); - - // OldVehicleUnion u; - switch (m->vehicles[i].type) { - case VEH_Train: - m->vehicles[i].u.rail.crash_anim_pos = BSWAP16(m->vehicles[i].u.rail.crash_anim_pos); - break; - case VEH_Aircraft: - m->vehicles[i].u.air.crashed_counter = BSWAP16(m->vehicles[i].u.air.crashed_counter); - break; - case VEH_Road: - m->vehicles[i].u.road.unk2 = BSWAP16(m->vehicles[i].u.road.unk2); - m->vehicles[i].u.road.crashed_ctr = BSWAP16(m->vehicles[i].u.road.crashed_ctr); - break; - case VEH_Special: - m->vehicles[i].u.special.unk0 = BSWAP16(m->vehicles[i].u.special.unk0); - break; - case VEH_Disaster: - m->vehicles[i].u.disaster.image_override = BSWAP16(m->vehicles[i].u.disaster.image_override); - m->vehicles[i].u.disaster.unk2 = BSWAP16(m->vehicles[i].u.disaster.unk2); - break; - } - } + OCL_VAR ( OC_FILE_U16 | OC_VAR_U8, 1, &_age_cargo_skip_counter ), + OCL_VAR ( OC_UINT16, 1, &_tick_counter ), + OCL_VAR ( OC_TILE, 1, &_cur_tileloop_tile ), - /* ----------- SIGNS ----------- */ - for (i = 0; i < 40; i++) { // OldSign signs[40]; - m->signs[i].text = BSWAP16(m->signs[i].text); - m->signs[i].x = BSWAP16(m->signs[i].x); - m->signs[i].y = BSWAP16(m->signs[i].y); - m->signs[i].z = BSWAP16(m->signs[i].z); - m->signs[i].sign_left = BSWAP16(m->signs[i].sign_left); - m->signs[i].sign_top = BSWAP16(m->signs[i].sign_top); - } + OCL_CHUNK( 49, LoadOldPrice ), + OCL_CHUNK( 12, LoadOldCargoPaymentRate ), - /* ----------- ENGINES ----------- */ - for (i = 0; i < 256; i++) { // OldEngine engines[256]; - m->engines[i].player_avail = BSWAP16(m->engines[i].player_avail); - m->engines[i].intro_date = BSWAP16(m->engines[i].intro_date); - m->engines[i].age = BSWAP16(m->engines[i].age); - m->engines[i].reliability = BSWAP16(m->engines[i].reliability); - m->engines[i].reliability_spd_dec = BSWAP16(m->engines[i].reliability_spd_dec); - m->engines[i].reliability_start = BSWAP16(m->engines[i].reliability_start); - m->engines[i].reliability_max = BSWAP16(m->engines[i].reliability_max); - m->engines[i].reliability_final = BSWAP16(m->engines[i].reliability_final); - m->engines[i].duration_phase_1 = BSWAP16(m->engines[i].duration_phase_1); - m->engines[i].duration_phase_2 = BSWAP16(m->engines[i].duration_phase_2); - m->engines[i].duration_phase_3 = BSWAP16(m->engines[i].duration_phase_3); - } + OCL_ASSERT( 0x4CBA ), - m->vehicle_id_ctr_day = BSWAP16(m->vehicle_id_ctr_day); - - m->next_competitor_start = BSWAP16(m->next_competitor_start); - m->saved_main_scrollpos_x = BSWAP16(m->saved_main_scrollpos_x); - m->saved_main_scrollpos_y = BSWAP16(m->saved_main_scrollpos_y); - m->saved_main_scrollpos_zoom = BSWAP16(m->saved_main_scrollpos_zoom); - m->maximum_loan = BSWAP32(m->maximum_loan); - m->maximum_loan_unround = BSWAP32(m->maximum_loan_unround); - m->economy_fluct = BSWAP16(m->economy_fluct); - m->disaster_delay = BSWAP16(m->disaster_delay); - - for (i = 0; i < 256; i++) // uint16 engine_name_strings[256]; - m->engine_name_strings[i] = BSWAP16(m->engine_name_strings[i]); - - /* ----------- GAME SETTINGS ----------- */ - m->game_diff.max_no_competitors = BSWAP16(m->game_diff.max_no_competitors); - m->game_diff.competitor_start_time = BSWAP16(m->game_diff.competitor_start_time); - m->game_diff.number_towns = BSWAP16(m->game_diff.number_towns); - m->game_diff.number_industries = BSWAP16(m->game_diff.number_industries); - m->game_diff.max_loan = BSWAP16(m->game_diff.max_loan); - m->game_diff.initial_interest = BSWAP16(m->game_diff.initial_interest); - m->game_diff.vehicle_costs = BSWAP16(m->game_diff.vehicle_costs); - m->game_diff.competitor_speed = BSWAP16(m->game_diff.competitor_speed); - m->game_diff.competitor_intelligence= BSWAP16(m->game_diff.competitor_intelligence); - m->game_diff.vehicle_breakdowns = BSWAP16(m->game_diff.vehicle_breakdowns); - m->game_diff.subsidy_multiplier = BSWAP16(m->game_diff.subsidy_multiplier); - m->game_diff.construction_cost = BSWAP16(m->game_diff.construction_cost); - m->game_diff.terrain_type = BSWAP16(m->game_diff.terrain_type); - m->game_diff.quantity_sea_lakes = BSWAP16(m->game_diff.quantity_sea_lakes); - m->game_diff.economy = BSWAP16(m->game_diff.economy); - m->game_diff.line_reverse_mode = BSWAP16(m->game_diff.line_reverse_mode); - m->game_diff.disasters = BSWAP16(m->game_diff.disasters); -} -#endif + OCL_CHUNK( 1, LoadOldMapPart1 ), -// loader for old style savegames -bool LoadOldSaveGame(const char *file) + OCL_ASSERT( 0x48CBA ), + + OCL_CHUNK(250, LoadOldStation ), + OCL_CHUNK( 90, LoadOldIndustry ), + OCL_CHUNK( 8, LoadOldPlayer ), + + OCL_ASSERT( 0x547F2 ), + + OCL_CHUNK( 850, LoadOldVehicle ), + + OCL_ASSERT( 0x6F0F2 ), + + OCL_VAR ( OC_UINT8, 32 * 500, &_name_array[0] ), + + OCL_NULL( 0x2000 ), // Old hash-table, no longer in use + + OCL_CHUNK( 40, LoadOldSign ), + OCL_CHUNK(256, LoadOldEngine ), + + OCL_VAR ( OC_UINT16, 1, &_vehicle_id_ctr_day ), + + OCL_CHUNK( 8, LoadOldSubsidy ), + + OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_next_competitor_start ), + OCL_VAR ( OC_FILE_I16 | OC_VAR_I32, 1, &_saved_scrollpos_x ), + OCL_VAR ( OC_FILE_I16 | OC_VAR_I32, 1, &_saved_scrollpos_y ), + OCL_VAR ( OC_FILE_U16 | OC_VAR_U8, 1, &_saved_scrollpos_zoom ), + + OCL_VAR ( OC_UINT32, 1, &_economy.max_loan ), + OCL_VAR ( OC_UINT32, 1, &_economy.max_loan_unround ), + OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_economy.fluct ), + + OCL_VAR ( OC_UINT16, 1, &_disaster_delay ), + + OCL_NULL( 144 ), // cargo-stuff, calculated in InitializeLandscapeVariables + + OCL_VAR ( OC_UINT16, 256, &_engine_name_strings[0] ), + + OCL_NULL( 144 ), // AI cargo-stuff, calculated in InitializeLandscapeVariables + OCL_NULL( 2 ), // Company indexes of players, no longer in use + + OCL_VAR ( OC_FILE_U8 | OC_VAR_U16, 1, &_station_tick_ctr ), + + OCL_VAR ( OC_UINT8, 1, &_opt.currency ), + OCL_VAR ( OC_UINT8, 1, &_opt.kilometers ), + OCL_VAR ( OC_FILE_U8 | OC_VAR_U32, 1, &_cur_player_tick_index ), + + OCL_NULL( 2 ), // Date stuff, calculated automaticly + OCL_NULL( 8 ), // Player colors, calculated automaticly + + OCL_VAR ( OC_UINT8, 1, &_economy.infl_amount ), + OCL_VAR ( OC_UINT8, 1, &_economy.infl_amount_pr ), + OCL_VAR ( OC_UINT8, 1, &_economy.interest_rate ), + OCL_VAR ( OC_UINT8, 1, &_avail_aircraft ), + OCL_VAR ( OC_UINT8, 1, &_opt.road_side ), + OCL_VAR ( OC_UINT8, 1, &_opt.town_name ), + + OCL_CHUNK( 1, LoadOldGameDifficulty ), + + OCL_ASSERT( 0x77130 ), + + OCL_VAR ( OC_UINT8, 1, &_opt.diff_level ), + OCL_VAR ( OC_UINT8, 1, &_opt.landscape ), + OCL_VAR ( OC_UINT8, 1, &_trees_tick_ctr ), + + OCL_NULL( 1 ), // Custom vehicle types yes/no, no longer used + OCL_VAR ( OC_UINT8, 1, &_opt.snow_line ), + + OCL_NULL( 32 ), // new_industry_randtable, no longer used (because of new design) + OCL_NULL( 36 ), // cargo-stuff, calculated in InitializeLandscapeVariables + + OCL_ASSERT( 0x77179 ), + + OCL_CHUNK( 1, LoadOldMapPart2 ), + + OCL_ASSERT( 0x97179 ), + + /* Below any (if available) extra chunks from TTDPatch can follow */ + + OCL_END() +}; +static bool LoadOldMain(LoadgameState *ls) { - LoadSavegameState lss; - OldMain *m; - uint map_size; - uint i; + int i; + + /* The first 49 is the name of the game + checksum, skip it */ + fseek(ls->file, HEADER_SIZE, SEEK_SET); - _cur_state = &lss; - memset(&lss, 0, sizeof(lss)); - - lss.fin = fopen(file, "rb"); - if (lss.fin == NULL) return false; - - /* B - byte 8bit (1) - * W - word 16bit (2 bytes) - * L - 'long' word 32bit (4 bytes) - */ - fseek(lss.fin, 49, SEEK_SET); // 47B TITLE, W Checksum - Total 49 - - /* Load the file into memory - * Game Data 0x77179 + L4 (256x256) + L5 (256x256) - */ - m = (OldMain *)malloc(sizeof(OldMain)); - LoadSavegameBytes(m, sizeof(OldMain)); - #ifdef TTD_BIG_ENDIAN - FixEndianness(m); - #endif - - // copy sections of it to our datastructures. - map_size = MapSize(); - memcpy(_map_owner, m->map_owner, map_size); - memcpy(_map_type_and_height, m->map_type_and_height, map_size); - memcpy(_map5, m->map5, map_size); - for (i = 0; i != map_size; i++) { - _map2[i] = m->map2[i]; - _map3_lo[i] = m->map3[i] & 0xFF; - _map3_hi[i] = m->map3[i] >> 8; + DEBUG(oldloader, 4)("[OldLoader] Going to read main chunk.."); + /* Load the biggest chunk */ + if (!LoadChunk(&_ls, NULL, main_chunk)) { + DEBUG(oldloader, 0)("[OldLoader] Loading failed!"); + return false; } - memcpy(_map_extra_bits, m->map_extra, map_size / 4); + DEBUG(oldloader, 4)("[OldLoader] Done. Converting stuff.."); - // go through the tables and see if we can find any ttdpatch presignals. Then convert those to our format. - for (i = 0; i != map_size; i++) { + /* Fix some general stuff */ + _opt.landscape = _opt.landscape & 0xF; + + /* Remap some pointers */ + _cur_town_ctr = REMAP_TOWN_IDX(_old_cur_town_ctr); + + /* _old_map3 is changed in _map3_lo and _map3_hi */ + for (i = 0; i < OLD_MAP_SIZE; i++) { + _map3_lo[i] = _old_map3[i * 2]; + _map3_hi[i] = _old_map3[i * 2 + 1]; + } + + for (i = 0; i < OLD_MAP_SIZE; i ++) { + /* We save presignals different from TTDPatch, convert them */ if (IsTileType(i, MP_RAILWAY) && (_map5[i] & 0xC0) == 0x40) { - // this byte is always zero in real ttd. + /* This byte is always zero in TTD for this type of tile */ if (_map3_hi[i]) { - // convert ttdpatch presignal format to openttd presignal format. + /* Convert the presignals to our own format */ _map3_hi[i] = (_map3_hi[i] >> 1) & 7; } } } - FixTown(m->town_list, lengthof(m->town_list), m->town_name_type); - FixIndustry(m->industries, lengthof(m->industries)); - FixStation(m->stations, lengthof(m->stations)); - - FixDepot(m->depots, lengthof(m->depots)); - FixOrder(m->order_list, lengthof(m->order_list)); - FixVehicle(m->vehicles, lengthof(m->vehicles)); - FixSubsidy(_subsidies, m->subsidies, lengthof(m->subsidies)); - - FixPlayer(_players, m->players, lengthof(m->players), m->town_name_type); - FixName(m->names, lengthof(m->names)); - FixSign(m->signs, lengthof(m->signs)); - FixEngine(_engines, m->engines, lengthof(m->engines)); - - _opt.diff_level = m->difficulty_level; - _opt.currency = m->currency; - _opt.kilometers = m->use_kilometers; - _opt.town_name = m->town_name_type; - _opt.landscape = m->landscape_type & 0xf; - _opt.snow_line = m->snow_line_height; - _opt.autosave = 0; - _opt.road_side = m->road_side; - FixGameDifficulty(&_opt.diff, &m->game_diff); - - // Load globals - _date = m->date; - _date_fract = m->date_fract; - _tick_counter = m->tick_counter; - _vehicle_id_ctr_day = m->vehicle_id_ctr_day; - _age_cargo_skip_counter = m->age_cargo_skip_counter; - _avail_aircraft = m->avail_aircraft; - _cur_tileloop_tile = m->cur_tileloop_tile; - _disaster_delay = m->disaster_delay; - _station_tick_ctr = m->station_tick_ctr; - _random_seeds[0][0] = m->seed_1; - _random_seeds[0][1] = m->seed_2; - _cur_town_ctr = REMAP_TOWN_IDX(m->cur_town_ptr); - _cur_player_tick_index = m->cur_player_tick_index; - _next_competitor_start = m->next_competitor_start; - _trees_tick_ctr = m->trees_tick_ctr; - _saved_scrollpos_x = m->saved_main_scrollpos_x; - _saved_scrollpos_y = m->saved_main_scrollpos_y; - _saved_scrollpos_zoom = m->saved_main_scrollpos_zoom; - - // Load economy stuff - _economy.max_loan = m->maximum_loan; - _economy.max_loan_unround = m->maximum_loan_unround; - _economy.fluct = m->economy_fluct; - _economy.interest_rate = m->interest_rate; - _economy.infl_amount = m->inflation_amount; - _economy.infl_amount_pr = m->inflation_amount_payment_rates; - - for (i = 0; i != lengthof(m->animated_tile_list); ++i) - _animated_tile_list[i] = m->animated_tile_list[i]; - memcpy(_engine_name_strings, m->engine_name_strings, sizeof(m->engine_name_strings)); - - for(i=0; i!=lengthof(m->prices); i++) { - ((uint32*)&_price)[i] = m->prices[i].price; - _price_frac[i] = m->prices[i].frac; - } + /* Fix the game to be compatible with OpenTTD */ + FixOldTowns(); + FixOldStations(); + FixOldVehicles(); - for(i=0; i!=lengthof(m->cargo_payment_rates); i++) { - _cargo_payment_rates[i] = -(int32)m->cargo_payment_rates[i].price; - _cargo_payment_rates_frac[i] = m->cargo_payment_rates[i].frac; + AddTypeToEngines(); + + /* We have a new difficulty setting */ + _opt.diff.town_council_tolerance = clamp(_opt.diff_level, 0, 2); + + DEBUG(oldloader, 4)("[OldLoader] Done!"); + DEBUG(oldloader, 1)("[OldLoader] TTD(Patch) savegame successfully converted"); + + return true; +} + +bool LoadOldSaveGame(const char *file) +{ + DEBUG(oldloader, 4)("[OldLoader] Trying to load an TTD(Patch) savegame"); + + InitLoading(&_ls); + + /* Open file */ + _ls.file = fopen(file, "rb"); + + if (_ls.file == NULL) { + DEBUG(oldloader, 0)("[OldLoader] Could not open file %s", file); + return false; } - free(m); - fclose(lss.fin); + /* Load the main chunk */ + if (!LoadOldMain(&_ls)) + return false; + + fclose(_ls.file); + return true; } @@ -1621,7 +1631,9 @@ void GetOldSaveGameName(char *title, const char *file) title[48] = 0; if (!f) return; - if (fread(title, 1, 48, f) != 48) title[0] = 0; + if (fread(title, 1, 48, f) != 48) + title[0] = 0; + fclose(f); } |