tron@2186: /* $Id$ */ tron@2186: rubidium@10455: /** @file oldloader.cpp Loading of old TTD(patch) savegames. */ glx@9505: truelight@0: #include "stdafx.h" Darkvater@1891: #include "openttd.h" tron@3558: #include "station_map.h" truelight@0: #include "town.h" truelight@0: #include "industry.h" rubidium@9724: #include "player_func.h" rubidium@9724: #include "player_base.h" rubidium@9620: #include "aircraft.h" rubidium@9620: #include "roadveh.h" rubidium@9620: #include "ship.h" rubidium@9620: #include "train.h" rubidium@9837: #include "signs_base.h" truelight@1322: #include "debug.h" rubidium@10249: #include "depot_base.h" rubidium@9628: #include "newgrf_config.h" truelight@9429: #include "ai/ai.h" rubidium@9723: #include "zoom_func.h" rubidium@9723: #include "functions.h" rubidium@9723: #include "date_func.h" rubidium@9723: #include "vehicle_func.h" rubidium@9723: #include "variables.h" rubidium@10455: #include "saveload.h" glx@10294: #include "strings_func.h" glx@10294: #include "effectvehicle_base.h" rubidium@9724: rubidium@9724: #include "table/strings.h" truelight@0: truelight@1322: enum { truelight@1322: HEADER_SIZE = 49, truelight@1322: BUFFER_SIZE = 4096, truelight@0: truelight@1322: OLD_MAP_SIZE = 256 * 256 truelight@1322: }; truelight@0: rubidium@6574: struct LoadgameState { truelight@1322: FILE *file; truelight@0: truelight@1322: uint chunk_size; truelight@0: truelight@1322: bool decoding; truelight@1322: byte decode_char; truelight@0: truelight@1322: uint buffer_count; truelight@1322: uint buffer_cur; truelight@1322: byte buffer[BUFFER_SIZE]; truelight@0: truelight@1322: uint total_read; truelight@1322: bool failed; rubidium@6574: }; truelight@0: truelight@1322: /* OldChunk-Type */ rubidium@6574: enum OldChunkType { Darkvater@3627: OC_SIMPLE = 0, Darkvater@3627: OC_NULL = 1, Darkvater@3627: OC_CHUNK = 2, Darkvater@3627: OC_ASSERT = 3, Darkvater@3627: /* 8 bytes allocated (256 max) */ truelight@1322: Darkvater@3627: OC_VAR_I8 = 1 << 8, Darkvater@3627: OC_VAR_U8 = 2 << 8, Darkvater@3627: OC_VAR_I16 = 3 << 8, Darkvater@3627: OC_VAR_U16 = 4 << 8, Darkvater@3627: OC_VAR_I32 = 5 << 8, Darkvater@3627: OC_VAR_U32 = 6 << 8, Darkvater@3627: OC_VAR_I64 = 7 << 8, Darkvater@3627: /* 8 bytes allocated (256 max) */ truelight@1322: Darkvater@3627: OC_FILE_I8 = 1 << 16, Darkvater@3627: OC_FILE_U8 = 2 << 16, Darkvater@3627: OC_FILE_I16 = 3 << 16, Darkvater@3627: OC_FILE_U16 = 4 << 16, Darkvater@3627: OC_FILE_I32 = 5 << 16, Darkvater@3627: OC_FILE_U32 = 6 << 16, Darkvater@3627: /* 8 bytes allocated (256 max) */ truelight@1322: truelight@1322: OC_INT8 = OC_VAR_I8 | OC_FILE_I8, truelight@1322: OC_UINT8 = OC_VAR_U8 | OC_FILE_U8, truelight@1322: OC_INT16 = OC_VAR_I16 | OC_FILE_I16, truelight@1322: OC_UINT16 = OC_VAR_U16 | OC_FILE_U16, truelight@1322: OC_INT32 = OC_VAR_I32 | OC_FILE_I32, truelight@1322: OC_UINT32 = OC_VAR_U32 | OC_FILE_U32, truelight@1322: Darkvater@3627: OC_TILE = OC_VAR_U32 | OC_FILE_U16, Darkvater@3627: glx@10294: /** glx@10294: * Dereference the pointer once before writing to it, glx@10294: * so we do not have to use big static arrays. glx@10294: */ glx@10294: OC_DEREFERENCE_POINTER = 1 << 31, glx@10294: Darkvater@3627: OC_END = 0 ///< End of the whole chunk, all 32bits set to zero rubidium@6574: }; Darkvater@3627: rubidium@5838: DECLARE_ENUM_AS_BIT_SET(OldChunkType); rubidium@5838: Darkvater@3627: typedef bool OldChunkProc(LoadgameState *ls, int num); Darkvater@3627: rubidium@6574: struct OldChunks { Darkvater@3627: OldChunkType type; ///< Type of field Darkvater@3627: uint32 amount; ///< Amount of fields Darkvater@3627: Darkvater@3627: void *ptr; ///< Pointer where to save the data (may only be set if offset is 0) Darkvater@3627: uint offset; ///< Offset from basepointer (may only be set if ptr is NULL) Darkvater@3627: OldChunkProc *proc; ///< Pointer to function that is called with OC_CHUNK rubidium@6574: }; Darkvater@3627: truelight@1322: /* If it fails, check lines above.. */ truelight@1322: assert_compile(sizeof(TileIndex) == 4); truelight@1322: rubidium@10455: extern SavegameType _savegame_type; rubidium@10455: extern uint32 _ttdp_version; rubidium@10455: truelight@1322: static uint32 _bump_assert_value; truelight@1322: static bool _read_ttdpatch_flags; truelight@1322: rubidium@5838: static OldChunkType GetOldChunkType(OldChunkType type) {return (OldChunkType)GB(type, 0, 8);} rubidium@5838: static OldChunkType GetOldChunkVarType(OldChunkType type) {return (OldChunkType)(GB(type, 8, 8) << 8);} rubidium@5838: static OldChunkType GetOldChunkFileType(OldChunkType type) {return (OldChunkType)(GB(type, 16, 8) << 16);} Darkvater@3627: Darkvater@3627: static inline byte CalcOldVarLen(OldChunkType type) Darkvater@3627: { Darkvater@3627: static const byte type_mem_size[] = {0, 1, 1, 2, 2, 4, 4, 8}; Darkvater@3627: byte length = GB(type, 8, 8); Darkvater@3627: assert(length != 0 && length < lengthof(type_mem_size)); Darkvater@3627: return type_mem_size[length]; Darkvater@3627: } Darkvater@3627: truelight@1322: /** truelight@1322: * truelight@1322: * Reads a byte from a file (do not call yourself, use ReadByte()) truelight@1322: * truelight@1322: */ truelight@1322: static byte ReadByteFromFile(LoadgameState *ls) truelight@0: { truelight@1322: /* To avoid slow reads, we read BUFFER_SIZE of bytes per time truelight@1322: and just return a byte per time */ truelight@1322: if (ls->buffer_cur >= ls->buffer_count) { truelight@1322: /* Read some new bytes from the file */ truelight@4321: int count = (int)fread(ls->buffer, 1, BUFFER_SIZE, ls->file); truelight@0: truelight@1322: /* We tried to read, but there is nothing in the file anymore.. */ truelight@1322: if (count == 0) { Darkvater@5568: DEBUG(oldloader, 0, "Read past end of file, loading failed"); truelight@1322: ls->failed = true; truelight@1322: } truelight@1322: truelight@1322: ls->buffer_count = count; truelight@1322: ls->buffer_cur = 0; truelight@0: } truelight@0: truelight@1322: return ls->buffer[ls->buffer_cur++]; truelight@0: } truelight@0: truelight@1322: /** truelight@1322: * truelight@1322: * Reads a byte from the buffer and decompress if needed truelight@1322: * truelight@1322: */ truelight@1322: static byte ReadByte(LoadgameState *ls) truelight@0: { truelight@1322: /* Old savegames have a nice compression algorithm (RLE) truelight@1322: which means that we have a chunk, which starts with a length truelight@1322: byte. If that byte is negative, we have to repeat the next byte rubidium@9601: that many times ( + 1). Else, we need to read that amount of bytes. truelight@1322: Works pretty good if you have many zero's behind eachother */ truelight@0: tron@2453: if (ls->chunk_size == 0) { tron@2453: /* Read new chunk */ tron@2453: int8 new_byte = ReadByteFromFile(ls); truelight@1322: tron@2453: if (new_byte < 0) { tron@2453: /* Repeat next char for new_byte times */ tron@2453: ls->decoding = true; tron@2453: ls->decode_char = ReadByteFromFile(ls); tron@2453: ls->chunk_size = -new_byte + 1; tron@2453: } else { tron@2453: ls->decoding = false; tron@2453: ls->chunk_size = new_byte + 1; tron@2453: } truelight@0: } truelight@193: tron@2453: ls->total_read++; tron@2453: ls->chunk_size--; truelight@1322: tron@2453: return ls->decoding ? ls->decode_char : ReadByteFromFile(ls); truelight@1322: } truelight@1322: Darkvater@3627: static inline uint16 ReadUint16(LoadgameState *ls) Darkvater@3627: { Darkvater@3627: byte x = ReadByte(ls); Darkvater@3627: return x | ReadByte(ls) << 8; Darkvater@3627: } Darkvater@3627: Darkvater@3627: static inline uint32 ReadUint32(LoadgameState *ls) Darkvater@3627: { Darkvater@3627: uint16 x = ReadUint16(ls); Darkvater@3627: return x | ReadUint16(ls) << 16; Darkvater@3627: } Darkvater@3627: truelight@1322: /** truelight@1322: * truelight@1322: * Loads a chunk from the old savegame truelight@1322: * truelight@1322: */ truelight@1322: static bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks) truelight@1322: { truelight@1322: const OldChunks *chunk = chunks; rubidium@5838: byte *base_ptr = (byte*)base; truelight@1322: truelight@1322: while (chunk->type != OC_END) { glx@10294: byte *ptr = (byte*)chunk->ptr; glx@10294: if ((chunk->type & OC_DEREFERENCE_POINTER) != 0) ptr = *(byte**)ptr; truelight@1322: glx@10294: for (uint i = 0; i < chunk->amount; i++) { Darkvater@3626: if (ls->failed) return false; truelight@1322: truelight@1322: /* Handle simple types */ Darkvater@3627: if (GetOldChunkType(chunk->type) != 0) { Darkvater@3627: switch (GetOldChunkType(chunk->type)) { Darkvater@3626: /* Just read the byte and forget about it */ Darkvater@3626: case OC_NULL: ReadByte(ls); break; truelight@1322: truelight@1322: case OC_CHUNK: truelight@1322: /* Call function, with 'i' as parameter to tell which item we tron@2951: * are going to read */ tron@2951: if (!chunk->proc(ls, i)) return false; truelight@1322: break; truelight@1322: truelight@1322: case OC_ASSERT: Darkvater@5568: DEBUG(oldloader, 4, "Assert point: 0x%X / 0x%X", ls->total_read, chunk->offset + _bump_assert_value); Darkvater@3626: if (ls->total_read != chunk->offset + _bump_assert_value) ls->failed = true; Darkvater@3629: default: break; truelight@1322: } truelight@1322: } else { truelight@9718: uint64 res = 0; truelight@1322: Darkvater@3627: /* Reading from the file: bits 16 to 23 have the FILE type */ Darkvater@3627: switch (GetOldChunkFileType(chunk->type)) { Darkvater@3627: case OC_FILE_I8: res = (int8)ReadByte(ls); break; Darkvater@3627: case OC_FILE_U8: res = ReadByte(ls); break; Darkvater@3627: case OC_FILE_I16: res = (int16)ReadUint16(ls); break; Darkvater@3627: case OC_FILE_U16: res = ReadUint16(ls); break; Darkvater@3627: case OC_FILE_I32: res = (int32)ReadUint32(ls); break; Darkvater@3627: case OC_FILE_U32: res = ReadUint32(ls); break; Darkvater@3627: default: NOT_REACHED(); truelight@1322: } truelight@1322: truelight@1322: /* Sanity check */ truelight@1325: assert(base_ptr != NULL || chunk->ptr != NULL); truelight@1322: Darkvater@3627: /* Writing to the var: bits 8 to 15 have the VAR type */ Darkvater@3627: if (chunk->ptr == NULL) ptr = base_ptr + chunk->offset; truelight@1322: Darkvater@3627: /* Write the data */ Darkvater@3627: switch (GetOldChunkVarType(chunk->type)) { Darkvater@3627: case OC_VAR_I8: *(int8 *)ptr = GB(res, 0, 8); break; Darkvater@3627: case OC_VAR_U8: *(uint8 *)ptr = GB(res, 0, 8); break; Darkvater@3627: case OC_VAR_I16:*(int16 *)ptr = GB(res, 0, 16); break; Darkvater@3627: case OC_VAR_U16:*(uint16*)ptr = GB(res, 0, 16); break; Darkvater@3627: case OC_VAR_I32:*(int32 *)ptr = res; break; Darkvater@3627: case OC_VAR_U32:*(uint32*)ptr = res; break; Darkvater@3627: case OC_VAR_I64:*(int64 *)ptr = res; break; Darkvater@3627: default: NOT_REACHED(); Darkvater@3627: } truelight@1322: Darkvater@3627: /* Increase pointer base for arrays when looping */ Darkvater@3627: if (chunk->amount > 1 && chunk->ptr != NULL) ptr += CalcOldVarLen(chunk->type); truelight@1322: } truelight@1322: } truelight@1322: truelight@1322: chunk++; truelight@1322: } truelight@1322: truelight@1322: return true; truelight@1322: } truelight@1322: truelight@1322: /** truelight@1322: * truelight@1322: * Initialize some data before reading truelight@1322: * truelight@1322: */ truelight@1322: static void InitLoading(LoadgameState *ls) truelight@1322: { truelight@1322: ls->chunk_size = 0; truelight@1322: ls->total_read = 0; truelight@1322: ls->failed = false; truelight@1322: truelight@1322: ls->decoding = false; truelight@1322: ls->decode_char = 0; truelight@1322: truelight@1322: ls->buffer_cur = 0; truelight@1322: ls->buffer_count = 0; truelight@1322: memset(ls->buffer, 0, BUFFER_SIZE); truelight@1322: truelight@1322: _bump_assert_value = 0; truelight@1322: rubidium@10455: _savegame_type = SGT_TTD; rubidium@10455: _ttdp_version = 0; rubidium@10455: truelight@1322: _read_ttdpatch_flags = false; truelight@1322: } truelight@1322: truelight@1322: truelight@1322: /* truelight@1322: * Begin -- Stuff to fix the savegames to be OpenTTD compatible truelight@1322: */ truelight@1322: truelight@1322: extern uint32 GetOldTownName(uint32 townnameparts, byte old_town_name_type); truelight@1322: rubidium@6573: static void FixOldTowns() truelight@1322: { truelight@1322: Town *town; truelight@1322: truelight@1322: /* Convert town-names if needed */ truelight@1322: FOR_ALL_TOWNS(town) { rubidium@9723: if (IsInsideMM(town->townnametype, 0x20C1, 0x20C3)) { glx@10776: town->townnametype = SPECSTR_TOWNNAME_ENGLISH + _settings_game.game_creation.town_name; glx@10776: town->townnameparts = GetOldTownName(town->townnameparts, _settings_game.game_creation.town_name); truelight@1322: } truelight@193: } truelight@0: } truelight@0: rubidium@6573: static void FixOldStations() truelight@0: { truelight@1322: Station *st; truelight@919: truelight@1322: FOR_ALL_STATIONS(st) { truelight@1322: /* Check if we need to swap width and height for the station */ tron@3558: if (st->train_tile != 0 && GetRailStationAxis(st->train_tile) != AXIS_X) { tron@5984: Swap(st->trainst_w, st->trainst_h); darkvater@4: } truelight@1024: } truelight@1024: } truelight@1024: rubidium@6573: static void FixOldVehicles() truelight@0: { truelight@1024: /* Check for shared orders, and link them correctly */ tron@2951: Vehicle* v; truelight@1024: tron@2951: FOR_ALL_VEHICLES(v) { Darkvater@3626: Vehicle *u; truelight@1024: glx@9624: /* We haven't used this bit for stations for ages */ rubidium@9628: if (v->type == VEH_ROAD && rubidium@9628: v->u.road.state != RVSB_IN_DEPOT && rubidium@9628: v->u.road.state != RVSB_WORMHOLE) { rubidium@9722: ClrBit(v->u.road.state, RVS_IS_STOPPING); rubidium@9628: } glx@9624: rubidium@9826: /* The subtype should be 0, but it sometimes isn't :( */ rubidium@9826: if (v->type == VEH_ROAD) v->subtype = 0; rubidium@9826: rubidium@9826: /* Sometimes primary vehicles would have a nothing (invalid) order rubidium@9826: * or vehicles that could not have an order would still have a rubidium@9826: * (loading) order which causes assertions and the like later on. rubidium@9826: */ rubidium@9826: if (!IsPlayerBuildableVehicleType(v) || rubidium@9869: (v->IsPrimaryVehicle() && v->current_order.IsType(OT_NOTHING))) { rubidium@9869: v->current_order.MakeDummy(); rubidium@9826: } rubidium@9826: tron@2951: FOR_ALL_VEHICLES_FROM(u, v->index + 1) { tron@2951: /* If a vehicle has the same orders, add the link to eachother tron@2951: * in both vehicles */ tron@2951: if (v->orders == u->orders) { tron@2951: v->next_shared = u; tron@2951: u->prev_shared = v; tron@2951: break; truelight@1024: } truelight@1024: } truelight@1024: } truelight@0: } truelight@0: truelight@1322: /* truelight@1322: * End -- Stuff to fix the savegames to be OpenTTD compatible truelight@1322: */ truelight@0: truelight@193: truelight@1322: /* Help: truelight@1322: * - OCL_SVAR: load 'type' to offset 'offset' in a struct of type 'base', which must also truelight@1322: * be given via base in LoadChunk() as real pointer truelight@1322: * - OCL_VAR: load 'type' to a global var truelight@1322: * - OCL_END: every struct must end with this truelight@1322: * - OCL_NULL: read 'amount' of bytes and send them to /dev/null or something truelight@1322: * - OCL_CHUNK: load an other proc to load a part of the savegame, 'amount' times truelight@1322: * - OCL_ASSERT: to check if we are really at the place we expect to be.. because old savegames are too binary to be sure ;) truelight@1322: */ KUDr@5922: #define OCL_SVAR(type, base, offset) { type, 1, NULL, (uint)cpp_offsetof(base, offset), NULL } truelight@1322: #define OCL_VAR(type, amount, pointer) { type, amount, pointer, 0, NULL } truelight@1322: #define OCL_END() { OC_END, 0, NULL, 0, NULL } truelight@1322: #define OCL_NULL(amount) { OC_NULL, amount, NULL, 0, NULL } truelight@1322: #define OCL_CHUNK(amount, proc) { OC_CHUNK, amount, NULL, 0, proc } truelight@1322: #define OCL_ASSERT(size) { OC_ASSERT, 1, NULL, size, NULL } truelight@0: truelight@1322: /* The savegames has some hard-coded pointers, because it always enters the same truelight@1322: piece of memory.. we don't.. so we need to remap ;) truelight@1322: Old Towns are 94 bytes big truelight@1322: Old Orders are 2 bytes big */ truelight@1322: #define REMAP_TOWN_IDX(x) ((x) - (0x0459154 - 0x0458EF0)) / 94 truelight@1322: #define REMAP_ORDER_IDX(x) ((x) - (0x045AB08 - 0x0458EF0)) / 2 truelight@0: truelight@9718: extern TileIndex *_animated_tile_list; truelight@9718: extern uint _animated_tile_count; glx@10294: extern char *_old_name_array; truelight@0: Darkvater@3626: static byte _old_vehicle_multiplier; glx@10294: static uint8 *_old_map3; truelight@1322: static uint32 _old_town_index; truelight@1322: static uint16 _old_string_id; truelight@1322: static uint16 _old_string_id_2; Darkvater@6400: static uint16 _old_extra_chunk_nums; truelight@1322: rubidium@6573: static void ReadTTDPatchFlags() truelight@1322: { tron@2951: if (_read_ttdpatch_flags) return; truelight@1322: truelight@1322: _read_ttdpatch_flags = true; truelight@1322: truelight@1322: /* TTDPatch misuses _old_map3 for flags.. read them! */ Darkvater@3626: _old_vehicle_multiplier = _old_map3[0]; truelight@1322: /* Somehow.... there was an error in some savegames, so 0 becomes 1 truelight@1322: and 1 becomes 2. The rest of the values are okay */ Darkvater@3626: if (_old_vehicle_multiplier < 2) _old_vehicle_multiplier++; truelight@1322: Darkvater@6342: /* TTDPatch increases the Vehicle-part in the middle of the game, truelight@1322: so if the multipler is anything else but 1, the assert fails.. truelight@1322: bump the assert value so it doesn't! truelight@1322: (1 multipler == 850 vehicles truelight@1322: 1 vehicle == 128 bytes */ Darkvater@3626: _bump_assert_value = (_old_vehicle_multiplier - 1) * 850 * 128; truelight@1322: rubidium@10455: for (uint i = 0; i < 17; i++) { // check tile 0, too rubidium@10455: if (_old_map3[i] != 0) _savegame_type = SGT_TTDP1; rubidium@10455: } rubidium@10455: truelight@1326: /* Check if we have a modern TTDPatch savegame (has extra data all around) */ rubidium@10455: if (memcmp(&_old_map3[0x1FFFA], "TTDp", 4) == 0) _savegame_type = SGT_TTDP2; truelight@1322: rubidium@10455: _old_extra_chunk_nums = _old_map3[_savegame_type == SGT_TTDP2 ? 0x1FFFE : 0x2]; Darkvater@6400: truelight@1322: /* Clean the misused places */ rubidium@10455: for (uint i = 0; i < 17; i++) _old_map3[i] = 0; rubidium@10455: for (uint i = 0x1FE00; i < 0x20000; i++) _old_map3[i] = 0; truelight@1322: rubidium@10455: if (_savegame_type == SGT_TTDP2) DEBUG(oldloader, 2, "Found TTDPatch game"); truelight@1322: Darkvater@6342: DEBUG(oldloader, 3, "Vehicle-multiplier is set to %d (%d vehicles)", _old_vehicle_multiplier, _old_vehicle_multiplier * 850); truelight@0: } truelight@0: truelight@1322: static const OldChunks town_chunk[] = { truelight@1322: OCL_SVAR( OC_TILE, Town, xy ), rubidium@9826: OCL_NULL( 2 ), ///< population, no longer in use truelight@1322: OCL_SVAR( OC_UINT16, Town, townnametype ), truelight@1322: OCL_SVAR( OC_UINT32, Town, townnameparts ), truelight@1322: OCL_SVAR( OC_UINT8, Town, grow_counter ), glx@9505: OCL_NULL( 1 ), ///< sort_index, no longer in use glx@9505: OCL_NULL( 4 ), ///< sign-coordinates, no longer in use glx@9505: OCL_NULL( 2 ), ///< namewidth, no longer in use truelight@1322: OCL_SVAR( OC_UINT16, Town, flags12 ), glx@9505: OCL_NULL( 10 ), ///< radius, no longer in use truelight@988: truelight@1322: OCL_SVAR( OC_UINT16, Town, ratings[0] ), truelight@1322: OCL_SVAR( OC_UINT16, Town, ratings[1] ), truelight@1322: OCL_SVAR( OC_UINT16, Town, ratings[2] ), truelight@1322: OCL_SVAR( OC_UINT16, Town, ratings[3] ), truelight@1322: OCL_SVAR( OC_UINT16, Town, ratings[4] ), truelight@1322: OCL_SVAR( OC_UINT16, Town, ratings[5] ), truelight@1322: OCL_SVAR( OC_UINT16, Town, ratings[6] ), truelight@1322: OCL_SVAR( OC_UINT16, Town, ratings[7] ), truelight@0: truelight@1322: /* XXX - This is pretty odd.. we read 32bit, but only write 8bit.. sure there is rubidium@9601: nothing changed ? ? */ truelight@1322: OCL_SVAR( OC_FILE_U32 | OC_VAR_U8, Town, have_ratings ), truelight@1322: OCL_SVAR( OC_FILE_U32 | OC_VAR_U8, Town, statues ), rubidium@9826: OCL_NULL( 2 ), ///< num_houses, no longer in use truelight@1322: OCL_SVAR( OC_UINT8, Town, time_until_rebuild ), truelight@1322: OCL_SVAR( OC_UINT8, Town, growth_rate ), truelight@1322: truelight@1322: OCL_SVAR( OC_UINT16, Town, new_max_pass ), truelight@1322: OCL_SVAR( OC_UINT16, Town, new_max_mail ), truelight@1322: OCL_SVAR( OC_UINT16, Town, new_act_pass ), truelight@1322: OCL_SVAR( OC_UINT16, Town, new_act_mail ), truelight@1322: OCL_SVAR( OC_UINT16, Town, max_pass ), truelight@1322: OCL_SVAR( OC_UINT16, Town, max_mail ), truelight@1322: OCL_SVAR( OC_UINT16, Town, act_pass ), truelight@1322: OCL_SVAR( OC_UINT16, Town, act_mail ), truelight@1322: truelight@1322: OCL_SVAR( OC_UINT8, Town, pct_pass_transported ), truelight@1322: OCL_SVAR( OC_UINT8, Town, pct_mail_transported ), truelight@1322: truelight@1322: OCL_SVAR( OC_UINT16, Town, new_act_food ), truelight@1322: OCL_SVAR( OC_UINT16, Town, new_act_water ), truelight@1322: OCL_SVAR( OC_UINT16, Town, act_food ), truelight@1322: OCL_SVAR( OC_UINT16, Town, act_water ), truelight@1322: truelight@1322: OCL_SVAR( OC_UINT8, Town, road_build_months ), truelight@1322: OCL_SVAR( OC_UINT8, Town, fund_buildings_months ), truelight@1322: glx@9505: OCL_NULL( 8 ), ///< some junk at the end of the record truelight@1322: truelight@1322: OCL_END() truelight@1322: }; truelight@1322: static bool LoadOldTown(LoadgameState *ls, int num) truelight@1322: { rubidium@9694: return LoadChunk(ls, new (num) Town(), town_chunk); truelight@0: } truelight@0: truelight@1322: static uint16 _old_order; truelight@1322: static const OldChunks order_chunk[] = { truelight@1322: OCL_VAR ( OC_UINT16, 1, &_old_order ), truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static bool LoadOldOrder(LoadgameState *ls, int num) truelight@0: { Darkvater@3626: if (!LoadChunk(ls, NULL, order_chunk)) return false; truelight@1322: rubidium@9869: new (num) Order(UnpackOldOrder(_old_order)); truelight@1322: truelight@1322: /* Relink the orders to eachother (in TTD(Patch) the orders for one bjarni@6589: vehicle are behind eachother, with an invalid order (OT_NOTHING) as indication that truelight@1322: it is the last order */ bjarni@6589: if (num > 0 && GetOrder(num)->IsValid()) truelight@1322: GetOrder(num - 1)->next = GetOrder(num); truelight@1322: truelight@1322: return true; truelight@0: } truelight@0: truelight@9718: static bool LoadOldAnimTileList(LoadgameState *ls, int num) truelight@9718: { truelight@9718: /* This is sligthly hackish - we must load a chunk into an array whose truelight@9718: * address isn't static, but instead pointed to by _animated_tile_list. truelight@9718: * To achieve that, create an OldChunks list on the stack on the fly. truelight@9718: * The list cannot be static because the value of _animated_tile_list truelight@9718: * can change between calls. */ truelight@9718: truelight@9718: const OldChunks anim_chunk[] = { truelight@9718: OCL_VAR ( OC_TILE, 256, _animated_tile_list ), truelight@9718: OCL_END () truelight@9718: }; truelight@9718: truelight@9718: if (!LoadChunk(ls, NULL, anim_chunk)) return false; truelight@9718: truelight@9718: /* Update the animated tile counter by counting till the first zero in the array */ truelight@9718: for (_animated_tile_count = 0; _animated_tile_count < 256; _animated_tile_count++) { truelight@9718: if (_animated_tile_list[_animated_tile_count] == 0) break; truelight@9718: } truelight@9718: truelight@9718: return true; truelight@9718: } truelight@9718: truelight@1322: static const OldChunks depot_chunk[] = { truelight@1322: OCL_SVAR( OC_TILE, Depot, xy ), truelight@1322: OCL_VAR ( OC_UINT32, 1, &_old_town_index ), truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static bool LoadOldDepot(LoadgameState *ls, int num) darkvater@436: { rubidium@9694: if (!LoadChunk(ls, new (num) Depot(), depot_chunk)) return false; darkvater@436: rubidium@9694: if (IsValidDepotID(num)) { truelight@1322: GetDepot(num)->town_index = REMAP_TOWN_IDX(_old_town_index); darkvater@436: } darkvater@436: truelight@1322: return true; truelight@1322: } darkvater@436: truelight@1322: static int32 _old_price; truelight@1322: static uint16 _old_price_frac; truelight@1322: static const OldChunks price_chunk[] = { truelight@1322: OCL_VAR ( OC_INT32, 1, &_old_price ), truelight@1322: OCL_VAR ( OC_UINT16, 1, &_old_price_frac ), truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static bool LoadOldPrice(LoadgameState *ls, int num) truelight@1322: { Darkvater@3626: if (!LoadChunk(ls, NULL, price_chunk)) return false; darkvater@436: truelight@1322: /* We use a struct to store the prices, but they are ints in a row.. truelight@1322: so just access the struct as an array of int32's */ glx@9629: ((Money*)&_price)[num] = _old_price; truelight@1322: _price_frac[num] = _old_price_frac; darkvater@436: truelight@1322: return true; truelight@1322: } darkvater@436: truelight@1322: static const OldChunks cargo_payment_rate_chunk[] = { truelight@1322: OCL_VAR ( OC_INT32, 1, &_old_price ), truelight@1322: OCL_VAR ( OC_UINT16, 1, &_old_price_frac ), truelight@1322: glx@9505: OCL_NULL( 2 ), ///< Junk truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static bool LoadOldCargoPaymentRate(LoadgameState *ls, int num) truelight@1322: { Darkvater@3626: if (!LoadChunk(ls, NULL, cargo_payment_rate_chunk)) return false; truelight@1322: truelight@1322: _cargo_payment_rates[num] = -_old_price; truelight@1322: _cargo_payment_rates_frac[num] = _old_price_frac; truelight@1322: truelight@1322: return true; truelight@1322: } truelight@1322: glx@9629: static uint8 _old_platforms; glx@9629: static uint _current_station_id; glx@9629: static uint16 _waiting_acceptance; glx@9629: static uint8 _cargo_source; glx@9629: static uint8 _cargo_days; truelight@1322: truelight@1322: static const OldChunks goods_chunk[] = { glx@9629: OCL_VAR ( OC_UINT16, 1, &_waiting_acceptance ), truelight@1322: OCL_SVAR( OC_UINT8, GoodsEntry, days_since_pickup ), truelight@1322: OCL_SVAR( OC_UINT8, GoodsEntry, rating ), glx@9629: OCL_VAR ( OC_UINT8, 1, &_cargo_source ), glx@9629: OCL_VAR ( OC_UINT8, 1, &_cargo_days ), truelight@1322: OCL_SVAR( OC_UINT8, GoodsEntry, last_speed ), truelight@1322: OCL_SVAR( OC_UINT8, GoodsEntry, last_age ), truelight@1322: truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static bool LoadOldGood(LoadgameState *ls, int num) truelight@1322: { truelight@1322: Station *st = GetStation(_current_station_id); glx@9629: GoodsEntry *ge = &st->goods[num]; glx@9629: bool ret = LoadChunk(ls, ge, goods_chunk); rubidium@9701: if (!ret) return false; rubidium@9701: rubidium@9722: SB(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15)); rubidium@9701: SB(ge->acceptance_pickup, GoodsEntry::PICKUP, 1, _cargo_source != 0xFF); rubidium@9701: if (GB(_waiting_acceptance, 0, 12) != 0) { glx@9629: CargoPacket *cp = new CargoPacket(); glx@9629: cp->source = (_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source; glx@9629: cp->count = GB(_waiting_acceptance, 0, 12); glx@9629: cp->days_in_transit = _cargo_days; glx@9629: ge->cargo.Append(cp); glx@9629: } glx@9629: return ret; truelight@1322: } truelight@1322: truelight@1322: static const OldChunks station_chunk[] = { truelight@1322: OCL_SVAR( OC_TILE, Station, xy ), truelight@1322: OCL_VAR ( OC_UINT32, 1, &_old_town_index ), truelight@1322: glx@9505: OCL_NULL( 4 ), ///< bus/lorry tile truelight@1322: OCL_SVAR( OC_TILE, Station, train_tile ), truelight@1322: OCL_SVAR( OC_TILE, Station, airport_tile ), truelight@1322: OCL_SVAR( OC_TILE, Station, dock_tile ), truelight@1322: truelight@1322: OCL_VAR ( OC_UINT8, 1, &_old_platforms ), truelight@1322: glx@9505: OCL_NULL( 1 ), ///< sort-index, no longer in use glx@9505: OCL_NULL( 2 ), ///< sign-width, no longer in use truelight@1322: truelight@1322: OCL_VAR ( OC_UINT16, 1, &_old_string_id ), truelight@1322: glx@9505: OCL_NULL( 4 ), ///< sign left/top, no longer in use truelight@1322: truelight@1322: OCL_SVAR( OC_UINT16, Station, had_vehicle_of_type ), truelight@1322: truelight@1322: OCL_CHUNK( 12, LoadOldGood ), truelight@1322: truelight@1322: OCL_SVAR( OC_UINT8, Station, time_since_load ), truelight@1322: OCL_SVAR( OC_UINT8, Station, time_since_unload ), truelight@1322: OCL_SVAR( OC_UINT8, Station, delete_ctr ), truelight@1322: OCL_SVAR( OC_UINT8, Station, owner ), truelight@1322: OCL_SVAR( OC_UINT8, Station, facilities ), truelight@1322: OCL_SVAR( OC_UINT8, Station, airport_type ), tron@6128: /* Bus/truck status, no longer in use tron@6128: * Blocked months tron@6128: * Unknown tron@6128: */ tron@6128: OCL_NULL( 4 ), truelight@1322: OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Station, airport_flags ), glx@9505: OCL_NULL( 2 ), ///< last_vehicle. now last_vehicle_type truelight@1322: glx@9505: OCL_NULL( 4 ), ///< Junk at end of chunk truelight@1322: truelight@1322: OCL_END() truelight@1322: }; truelight@1322: static bool LoadOldStation(LoadgameState *ls, int num) truelight@1322: { glx@9624: Station *st = new (num) Station(); truelight@1322: _current_station_id = num; truelight@1322: truelight@1322: if (!LoadChunk(ls, st, station_chunk)) truelight@1322: return false; truelight@1322: celestar@6322: if (st->IsValid()) { truelight@1322: if (st->train_tile) { truelight@1322: /* Calculate the trainst_w and trainst_h */ tron@2140: uint w = GB(_old_platforms, 3, 3); tron@2140: uint h = GB(_old_platforms, 0, 3); truelight@1322: st->trainst_w = w; truelight@1322: st->trainst_h = h; darkvater@436: } darkvater@436: truelight@1322: st->town = GetTown(REMAP_TOWN_IDX(_old_town_index)); truelight@1322: st->string_id = RemapOldStringID(_old_string_id); darkvater@436: } darkvater@436: truelight@1322: return true; truelight@1322: } darkvater@436: truelight@1322: static const OldChunks industry_chunk[] = { truelight@1322: OCL_SVAR( OC_TILE, Industry, xy ), truelight@1322: OCL_VAR ( OC_UINT32, 1, &_old_town_index ), truelight@1322: OCL_SVAR( OC_UINT8, Industry, width ), truelight@1322: OCL_SVAR( OC_UINT8, Industry, height ), glx@9624: OCL_NULL( 2 ), ///< used to be industry's produced_cargo darkvater@436: rubidium@9631: OCL_SVAR( OC_UINT16, Industry, produced_cargo_waiting[0] ), rubidium@9631: OCL_SVAR( OC_UINT16, Industry, produced_cargo_waiting[1] ), darkvater@436: truelight@1322: OCL_SVAR( OC_UINT8, Industry, production_rate[0] ), truelight@1322: OCL_SVAR( OC_UINT8, Industry, production_rate[1] ), truelight@1322: glx@9624: OCL_NULL( 3 ), ///< used to be industry's accepts_cargo truelight@1322: truelight@1322: OCL_SVAR( OC_UINT8, Industry, prod_level ), truelight@1322: glx@9626: OCL_SVAR( OC_UINT16, Industry, this_month_production[0] ), glx@9626: OCL_SVAR( OC_UINT16, Industry, this_month_production[1] ), glx@9626: OCL_SVAR( OC_UINT16, Industry, this_month_transported[0] ), glx@9626: OCL_SVAR( OC_UINT16, Industry, this_month_transported[1] ), truelight@1322: glx@9626: OCL_SVAR( OC_UINT8, Industry, last_month_pct_transported[0] ), glx@9626: OCL_SVAR( OC_UINT8, Industry, last_month_pct_transported[1] ), truelight@1322: glx@9626: OCL_SVAR( OC_UINT16, Industry, last_month_production[0] ), glx@9626: OCL_SVAR( OC_UINT16, Industry, last_month_production[1] ), glx@9626: OCL_SVAR( OC_UINT16, Industry, last_month_transported[0] ), glx@9626: OCL_SVAR( OC_UINT16, Industry, last_month_transported[1] ), truelight@1322: truelight@1322: OCL_SVAR( OC_UINT8, Industry, type ), truelight@1322: OCL_SVAR( OC_UINT8, Industry, owner ), belugas@4942: OCL_SVAR( OC_UINT8, Industry, random_color ), rubidium@4326: OCL_SVAR( OC_FILE_U8 | OC_VAR_I32, Industry, last_prod_year ), truelight@1322: OCL_SVAR( OC_UINT16, Industry, counter ), truelight@1322: OCL_SVAR( OC_UINT8, Industry, was_cargo_delivered ), truelight@1322: glx@9505: OCL_NULL( 9 ), ///< Random junk at the end of this chunk truelight@1322: truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static bool LoadOldIndustry(LoadgameState *ls, int num) truelight@1322: { rubidium@9694: Industry *i = new (num) Industry(); Darkvater@3626: if (!LoadChunk(ls, i, industry_chunk)) return false; truelight@1322: rubidium@9694: if (i->IsValid()) { truelight@1322: i->town = GetTown(REMAP_TOWN_IDX(_old_town_index)); truelight@9718: IncIndustryTypeCount(i->type); darkvater@436: } darkvater@436: truelight@1322: return true; truelight@1322: } darkvater@436: tron@2498: static PlayerID _current_player_id; truelight@1322: static int32 _old_yearly; truelight@1322: truelight@1322: static const OldChunks player_yearly_chunk[] = { truelight@1322: OCL_VAR( OC_INT32, 1, &_old_yearly ), truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static bool OldPlayerYearly(LoadgameState *ls, int num) truelight@1322: { truelight@1322: int i; celestar@1962: Player *p = GetPlayer(_current_player_id); truelight@1322: truelight@1322: for (i = 0; i < 13; i++) { Darkvater@3626: if (!LoadChunk(ls, NULL, player_yearly_chunk)) return false; truelight@1322: truelight@1322: p->yearly_expenses[num][i] = _old_yearly; truelight@1322: } truelight@1322: truelight@1322: return true; darkvater@436: } truelight@0: truelight@1322: static const OldChunks player_economy_chunk[] = { truelight@9718: OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, PlayerEconomyEntry, income ), truelight@9718: OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, PlayerEconomyEntry, expenses ), truelight@1322: OCL_SVAR( OC_INT32, PlayerEconomyEntry, delivered_cargo ), truelight@1322: OCL_SVAR( OC_INT32, PlayerEconomyEntry, performance_history ), truelight@1322: OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, PlayerEconomyEntry, company_value ), truelight@1322: truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static bool OldPlayerEconomy(LoadgameState *ls, int num) truelight@0: { truelight@1322: int i; celestar@1962: Player *p = GetPlayer(_current_player_id); truelight@1322: Darkvater@3626: if (!LoadChunk(ls, &p->cur_economy, player_economy_chunk)) return false; truelight@1322: truelight@1322: /* Don't ask, but the number in TTD(Patch) are inversed to OpenTTD */ truelight@1322: p->cur_economy.income = -p->cur_economy.income; truelight@1322: p->cur_economy.expenses = -p->cur_economy.expenses; truelight@1322: truelight@1322: for (i = 0; i < 24; i++) { Darkvater@3626: if (!LoadChunk(ls, &p->old_economy[i], player_economy_chunk)) return false; truelight@1322: truelight@1322: p->old_economy[i].income = -p->old_economy[i].income; truelight@1322: p->old_economy[i].expenses = -p->old_economy[i].expenses; truelight@1322: } truelight@1322: truelight@1322: return true; truelight@1322: } truelight@1322: truelight@1322: static const OldChunks player_chunk[] = { truelight@1322: OCL_VAR ( OC_UINT16, 1, &_old_string_id ), truelight@1322: OCL_SVAR( OC_UINT32, Player, name_2 ), truelight@1322: OCL_SVAR( OC_UINT32, Player, face ), truelight@1322: OCL_VAR ( OC_UINT16, 1, &_old_string_id_2 ), truelight@1322: OCL_SVAR( OC_UINT32, Player, president_name_2 ), truelight@1322: truelight@1322: OCL_SVAR( OC_INT32, Player, player_money ), truelight@1322: OCL_SVAR( OC_INT32, Player, current_loan ), truelight@1322: truelight@1322: OCL_SVAR( OC_UINT8, Player, player_color ), truelight@1322: OCL_SVAR( OC_UINT8, Player, player_money_fraction ), truelight@1322: OCL_SVAR( OC_UINT8, Player, quarters_of_bankrupcy ), truelight@1322: OCL_SVAR( OC_UINT8, Player, bankrupt_asked ), truelight@9718: OCL_SVAR( OC_FILE_U32 | OC_VAR_I64, Player, bankrupt_value ), truelight@1322: OCL_SVAR( OC_UINT16, Player, bankrupt_timeout ), truelight@1322: glx@10294: OCL_SVAR( OC_UINT32, Player, cargo_types ), truelight@1322: truelight@1322: OCL_CHUNK( 3, OldPlayerYearly ), truelight@1322: OCL_CHUNK( 1, OldPlayerEconomy ), truelight@1322: Darkvater@5865: OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Player, inaugurated_year), Darkvater@5865: OCL_SVAR( OC_TILE, Player, last_build_coordinate ), Darkvater@5865: OCL_SVAR( OC_UINT8, Player, num_valid_stat_ent ), truelight@1322: truelight@9359: OCL_NULL( 230 ), // Old AI truelight@1322: truelight@1322: OCL_SVAR( OC_UINT8, Player, block_preview ), truelight@9359: OCL_NULL( 1 ), // Old AI celestar@2147: OCL_SVAR( OC_UINT8, Player, avail_railtypes ), truelight@1322: OCL_SVAR( OC_TILE, Player, location_of_house ), truelight@1322: OCL_SVAR( OC_UINT8, Player, share_owners[0] ), truelight@1322: OCL_SVAR( OC_UINT8, Player, share_owners[1] ), truelight@1322: OCL_SVAR( OC_UINT8, Player, share_owners[2] ), truelight@1322: OCL_SVAR( OC_UINT8, Player, share_owners[3] ), truelight@1322: glx@9505: OCL_NULL( 8 ), ///< junk at end of chunk truelight@1322: truelight@1322: OCL_END() truelight@1322: }; tron@2951: truelight@1322: static bool LoadOldPlayer(LoadgameState *ls, int num) truelight@1322: { rubidium@5838: Player *p = GetPlayer((PlayerID)num); truelight@1322: rubidium@5838: _current_player_id = (PlayerID)num; truelight@1322: Darkvater@3626: if (!LoadChunk(ls, p, player_chunk)) return false; truelight@1322: truelight@1322: p->name_1 = RemapOldStringID(_old_string_id); truelight@1322: p->president_name_1 = RemapOldStringID(_old_string_id_2); glx@9629: p->player_money = p->player_money; truelight@1322: truelight@1322: if (num == 0) { truelight@1322: /* If the first player has no name, make sure we call it UNNAMED */ truelight@1322: if (p->name_1 == 0) truelight@1322: p->name_1 = STR_SV_UNNAMED; truelight@1322: } else { truelight@1322: /* Beside some multiplayer maps (1 on 1), which we don't official support, truelight@1322: all other players are an AI.. mark them as such */ Darkvater@3345: p->is_ai = true; truelight@1322: } truelight@1322: truelight@1322: /* Sometimes it is better to not ask.. in old scenarios, the money truelight@1322: was always 893288 pounds. In the newer versions this is correct, truelight@1322: but correct for those oldies truelight@1322: Ps: this also means that if you had exact 893288 pounds, you will go back truelight@1322: to 10000.. this is a very VERY small chance ;) */ truelight@1326: if (p->player_money == 893288) glx@9629: p->player_money = p->current_loan = 100000; truelight@1322: truelight@1322: _player_colors[num] = p->player_color; Darkvater@5865: p->inaugurated_year -= ORIGINAL_BASE_YEAR; truelight@1322: if (p->location_of_house == 0xFFFF) truelight@1322: p->location_of_house = 0; truelight@1322: glx@10740: p->is_ai = p->is_ai && AI_StartNewAI(p->index); peter1138@2814: truelight@1322: return true; truelight@1322: } truelight@1322: truelight@1322: static uint32 _old_order_ptr; truelight@1322: static uint16 _old_next_ptr; truelight@1322: static uint32 _current_vehicle_id; truelight@1322: truelight@1322: static const OldChunks vehicle_train_chunk[] = { truelight@1322: OCL_SVAR( OC_UINT8, VehicleRail, track ), truelight@1322: OCL_SVAR( OC_UINT8, VehicleRail, force_proceed ), truelight@1322: OCL_SVAR( OC_UINT16, VehicleRail, crash_anim_pos ), truelight@1322: OCL_SVAR( OC_UINT8, VehicleRail, railtype ), truelight@1322: glx@9505: OCL_NULL( 5 ), ///< Junk truelight@1322: truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static const OldChunks vehicle_road_chunk[] = { truelight@1322: OCL_SVAR( OC_UINT8, VehicleRoad, state ), truelight@1322: OCL_SVAR( OC_UINT8, VehicleRoad, frame ), peter1138@3009: OCL_SVAR( OC_UINT16, VehicleRoad, blocked_ctr ), truelight@1322: OCL_SVAR( OC_UINT8, VehicleRoad, overtaking ), truelight@1322: OCL_SVAR( OC_UINT8, VehicleRoad, overtaking_ctr ), truelight@1322: OCL_SVAR( OC_UINT16, VehicleRoad, crashed_ctr ), truelight@1322: OCL_SVAR( OC_UINT8, VehicleRoad, reverse_ctr ), truelight@1322: glx@9505: OCL_NULL( 1 ), ///< Junk truelight@1322: truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static const OldChunks vehicle_ship_chunk[] = { truelight@1322: OCL_SVAR( OC_UINT8, VehicleShip, state ), truelight@1322: glx@9505: OCL_NULL( 9 ), ///< Junk truelight@1322: truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static const OldChunks vehicle_air_chunk[] = { truelight@1322: OCL_SVAR( OC_UINT8, VehicleAir, pos ), truelight@1322: OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, VehicleAir, targetairport ), truelight@1322: OCL_SVAR( OC_UINT16, VehicleAir, crashed_counter ), truelight@1322: OCL_SVAR( OC_UINT8, VehicleAir, state ), truelight@1322: glx@9505: OCL_NULL( 5 ), ///< Junk truelight@1322: truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: glx@10294: static const OldChunks vehicle_effect_chunk[] = { glx@10294: OCL_SVAR( OC_UINT16, VehicleEffect, animation_state ), glx@10294: OCL_SVAR( OC_UINT8, VehicleEffect, animation_substate ), truelight@1322: truelight@1322: OCL_NULL( 7 ), // Junk truelight@1322: truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static const OldChunks vehicle_disaster_chunk[] = { truelight@1322: OCL_SVAR( OC_UINT16, VehicleDisaster, image_override ), rubidium@9694: OCL_SVAR( OC_UINT16, VehicleDisaster, big_ufo_destroyer_target ), truelight@1322: glx@9505: OCL_NULL( 6 ), ///< Junk truelight@1322: truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static const OldChunks vehicle_empty_chunk[] = { glx@9505: OCL_NULL( 10 ), ///< Junk truelight@1322: truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static bool LoadOldVehicleUnion(LoadgameState *ls, int num) truelight@1322: { truelight@1322: Vehicle *v = GetVehicle(_current_vehicle_id); truelight@1322: uint temp = ls->total_read; truelight@1322: bool res; truelight@1322: truelight@1322: switch (v->type) { Darkvater@6340: default: NOT_REACHED(); rubidium@9826: case VEH_INVALID : res = LoadChunk(ls, NULL, vehicle_empty_chunk); break; rubidium@9826: case VEH_TRAIN : res = LoadChunk(ls, &v->u.rail, vehicle_train_chunk); break; rubidium@9826: case VEH_ROAD : res = LoadChunk(ls, &v->u.road, vehicle_road_chunk); break; rubidium@9826: case VEH_SHIP : res = LoadChunk(ls, &v->u.ship, vehicle_ship_chunk); break; rubidium@9826: case VEH_AIRCRAFT: res = LoadChunk(ls, &v->u.air, vehicle_air_chunk); break; glx@10294: case VEH_EFFECT : res = LoadChunk(ls, &v->u.effect, vehicle_effect_chunk); break; rubidium@9826: case VEH_DISASTER: res = LoadChunk(ls, &v->u.disaster, vehicle_disaster_chunk); break; truelight@1322: } truelight@1322: truelight@1322: /* This chunk size should always be 10 bytes */ truelight@1322: if (ls->total_read - temp != 10) { Darkvater@6342: DEBUG(oldloader, 0, "Assert failed in VehicleUnion: invalid chunk size"); truelight@1322: return false; truelight@1322: } truelight@1322: truelight@1322: return res; truelight@1322: } truelight@1322: glx@9629: static uint16 _cargo_count; glx@9629: truelight@1322: static const OldChunks vehicle_chunk[] = { truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, subtype ), truelight@1322: glx@9505: OCL_NULL( 2 ), ///< Hash, calculated automatically glx@9505: OCL_NULL( 2 ), ///< Index, calculated automatically truelight@1322: truelight@1322: OCL_VAR ( OC_UINT32, 1, &_old_order_ptr ), truelight@1322: OCL_VAR ( OC_UINT16, 1, &_old_order ), truelight@1322: truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, num_orders ), truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, cur_order_index ), truelight@1322: OCL_SVAR( OC_TILE, Vehicle, dest_tile ), truelight@1322: OCL_SVAR( OC_UINT16, Vehicle, load_unload_time_rem ), rubidium@4326: OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, date_of_last_service ), truelight@1322: OCL_SVAR( OC_UINT16, Vehicle, service_interval ), truelight@1322: OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, last_station_visited ), truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, tick_counter ), truelight@1322: OCL_SVAR( OC_UINT16, Vehicle, max_speed ), truelight@1322: truelight@1322: OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, x_pos ), truelight@1322: OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, y_pos ), truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, z_pos ), truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, direction ), rubidium@9620: OCL_NULL( 2 ), ///< x_offs and y_offs, calculated automatically rubidium@9869: OCL_NULL( 2 ), ///< x_extent and y_extent, calculated automatically rubidium@9869: OCL_NULL( 1 ), ///< z_extent, calculated automatically truelight@1322: truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, owner ), truelight@1322: OCL_SVAR( OC_TILE, Vehicle, tile ), truelight@1322: OCL_SVAR( OC_UINT16, Vehicle, cur_image ), truelight@1322: glx@9505: OCL_NULL( 8 ), ///< Vehicle sprite box, calculated automatically truelight@1322: truelight@1322: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, Vehicle, vehstatus ), truelight@1322: OCL_SVAR( OC_UINT16, Vehicle, cur_speed ), truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, subspeed ), truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, acceleration ), truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, progress ), truelight@1322: truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, cargo_type ), truelight@1322: OCL_SVAR( OC_UINT16, Vehicle, cargo_cap ), glx@9629: OCL_VAR ( OC_UINT16, 1, &_cargo_count ), glx@9629: OCL_VAR ( OC_UINT8, 1, &_cargo_source ), glx@9629: OCL_VAR ( OC_UINT8, 1, &_cargo_days ), truelight@1322: rubidium@4326: OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, age ), rubidium@4326: OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, max_age ), rubidium@4326: OCL_SVAR( OC_FILE_U8 | OC_VAR_I32, Vehicle, build_year ), truelight@1322: OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, unitnumber ), truelight@1322: truelight@1322: OCL_SVAR( OC_UINT16, Vehicle, engine_type ), truelight@1322: truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, spritenum ), truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, day_counter ), truelight@1322: truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, breakdowns_since_last_service ), truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, breakdown_ctr ), truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, breakdown_delay ), truelight@1322: OCL_SVAR( OC_UINT8, Vehicle, breakdown_chance ), truelight@1322: truelight@1322: OCL_SVAR( OC_UINT16, Vehicle, reliability ), truelight@1322: OCL_SVAR( OC_UINT16, Vehicle, reliability_spd_dec ), truelight@1322: truelight@9718: OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, Vehicle, profit_this_year ), truelight@9718: OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, Vehicle, profit_last_year ), truelight@1322: truelight@1322: OCL_VAR ( OC_UINT16, 1, &_old_next_ptr ), truelight@1322: truelight@1322: OCL_SVAR( OC_UINT32, Vehicle, value ), truelight@1322: truelight@1322: OCL_VAR ( OC_UINT16, 1, &_old_string_id ), truelight@1322: truelight@1322: OCL_CHUNK( 1, LoadOldVehicleUnion ), truelight@1322: glx@9505: OCL_NULL( 20 ), ///< Junk at end of struct (TTDPatch has some data in it) truelight@1322: truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: rubidium@9703: bool LoadOldVehicle(LoadgameState *ls, int num) truelight@1322: { tron@959: uint i; truelight@0: truelight@1322: /* Read the TTDPatch flags, because we need some info from it */ truelight@1322: ReadTTDPatchFlags(); truelight@0: Darkvater@3626: for (i = 0; i < _old_vehicle_multiplier; i++) { Darkvater@3626: _current_vehicle_id = num * _old_vehicle_multiplier + i; truelight@1322: rubidium@9826: /* Read the vehicle type and allocate the right vehicle */ rubidium@9826: Vehicle *v; rubidium@9826: switch (ReadByte(ls)) { rubidium@9826: default: NOT_REACHED(); rubidium@9826: case 0x00 /*VEH_INVALID */: v = new (_current_vehicle_id) InvalidVehicle(); break; rubidium@9826: case 0x10 /*VEH_TRAIN */: v = new (_current_vehicle_id) Train(); break; rubidium@9826: case 0x11 /*VEH_ROAD */: v = new (_current_vehicle_id) RoadVehicle(); break; rubidium@9826: case 0x12 /*VEH_SHIP */: v = new (_current_vehicle_id) Ship(); break; rubidium@9826: case 0x13 /*VEH_AIRCRAFT*/: v = new (_current_vehicle_id) Aircraft(); break; glx@10294: case 0x14 /*VEH_EFFECT */: v = new (_current_vehicle_id) EffectVehicle(); break; rubidium@9826: case 0x15 /*VEH_DISASTER*/: v = new (_current_vehicle_id) DisasterVehicle(); break; rubidium@9826: } Darkvater@3626: if (!LoadChunk(ls, v, vehicle_chunk)) return false; truelight@1322: truelight@1340: /* This should be consistent, else we have a big problem... */ truelight@1340: if (v->index != _current_vehicle_id) { Darkvater@5568: DEBUG(oldloader, 0, "Loading failed - vehicle-array is invalid"); truelight@1340: return false; truelight@1340: } truelight@1340: truelight@1322: if (_old_order_ptr != 0 && _old_order_ptr != 0xFFFFFFFF) { rubidium@9826: uint old_id = REMAP_ORDER_IDX(_old_order_ptr); rubidium@9826: /* There is a maximum of 5000 orders in old savegames, so *if* rubidium@9826: * we go over that limit something is very wrong. In that case rubidium@9826: * we just assume there are no orders for the vehicle. rubidium@9826: */ rubidium@9826: if (old_id < 5000) v->orders = GetOrder(old_id); truelight@1322: } rubidium@9869: v->current_order.AssignOrder(UnpackOldOrder(_old_order)); truelight@1322: truelight@1322: /* For some reason we need to correct for this */ truelight@1322: switch (v->spritenum) { truelight@1322: case 0xfd: break; truelight@1322: case 0xff: v->spritenum = 0xfe; break; truelight@1322: default: v->spritenum >>= 1; break; truelight@1322: } truelight@1322: truelight@9718: if (_old_next_ptr != 0xFFFF) v->next = GetVehiclePoolSize() <= _old_next_ptr ? new (_old_next_ptr) InvalidVehicle() : GetVehicle(_old_next_ptr); truelight@1322: rubidium@9724: _old_string_id = RemapOldStringID(_old_string_id); rubidium@9724: v->name = CopyFromOldName(_old_string_id); truelight@1322: truelight@1322: /* Vehicle-subtype is different in TTD(Patch) */ glx@10294: if (v->type == VEH_EFFECT) v->subtype = v->subtype >> 1; glx@9629: glx@9629: if (_cargo_count != 0) { glx@9629: CargoPacket *cp = new CargoPacket((_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source, _cargo_count); glx@9629: cp->days_in_transit = _cargo_days; glx@9629: v->cargo.Append(cp); glx@9629: } truelight@0: } truelight@0: truelight@1322: return true; truelight@1322: } truelight@1322: truelight@1322: static const OldChunks sign_chunk[] = { rubidium@9724: OCL_VAR ( OC_UINT16, 1, &_old_string_id ), rubidium@9601: OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Sign, x ), rubidium@9601: OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Sign, y ), truelight@4349: OCL_SVAR( OC_FILE_U16 | OC_VAR_I8, Sign, z ), truelight@1322: glx@9505: OCL_NULL( 6 ), ///< Width of sign, no longer in use truelight@1322: truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static bool LoadOldSign(LoadgameState *ls, int num) truelight@1322: { rubidium@9724: Sign *si = new (num) Sign(); rubidium@9724: if (!LoadChunk(ls, si, sign_chunk)) return false; rubidium@9724: rubidium@9724: _old_string_id = RemapOldStringID(_old_string_id); rubidium@9724: si->name = CopyFromOldName(_old_string_id); rubidium@9724: rubidium@9724: return true; truelight@1322: } truelight@1322: truelight@1322: static const OldChunks engine_chunk[] = { truelight@1322: OCL_SVAR( OC_UINT16, Engine, player_avail ), rubidium@4326: OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Engine, intro_date ), rubidium@4326: OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Engine, age ), truelight@1322: OCL_SVAR( OC_UINT16, Engine, reliability ), truelight@1322: OCL_SVAR( OC_UINT16, Engine, reliability_spd_dec ), truelight@1322: OCL_SVAR( OC_UINT16, Engine, reliability_start ), truelight@1322: OCL_SVAR( OC_UINT16, Engine, reliability_max ), truelight@1322: OCL_SVAR( OC_UINT16, Engine, reliability_final ), truelight@1322: OCL_SVAR( OC_UINT16, Engine, duration_phase_1 ), truelight@1322: OCL_SVAR( OC_UINT16, Engine, duration_phase_2 ), truelight@1322: OCL_SVAR( OC_UINT16, Engine, duration_phase_3 ), truelight@1322: truelight@1322: OCL_SVAR( OC_UINT8, Engine, lifelength ), truelight@1322: OCL_SVAR( OC_UINT8, Engine, flags ), glx@9732: OCL_SVAR( OC_UINT8, Engine, preview_player_rank ), truelight@1322: OCL_SVAR( OC_UINT8, Engine, preview_wait ), truelight@1322: glx@9505: OCL_NULL( 2 ), ///< Junk truelight@1322: truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static bool LoadOldEngine(LoadgameState *ls, int num) truelight@1322: { rubidium@10455: Engine *e = GetTempDataEngine(num); rubidium@10455: if (!LoadChunk(ls, e, engine_chunk)) return false; truelight@1322: truelight@1322: /* Make sure wagons are marked as do-not-age */ truelight@1322: if ((num >= 27 && num < 54) || (num >= 57 && num < 84) || (num >= 89 && num < 116)) rubidium@10455: e->age = 0xFFFF; truelight@1322: truelight@1322: return true; truelight@1322: } truelight@1322: rubidium@9724: static bool LoadOldEngineName(LoadgameState *ls, int num) rubidium@9724: { rubidium@10455: Engine *e = GetTempDataEngine(num); rubidium@9724: e->name = CopyFromOldName(RemapOldStringID(ReadUint16(ls))); rubidium@9724: return true; rubidium@9724: } rubidium@9724: truelight@1322: static const OldChunks subsidy_chunk[] = { truelight@1322: OCL_SVAR( OC_UINT8, Subsidy, cargo_type ), truelight@1322: OCL_SVAR( OC_UINT8, Subsidy, age ), truelight@1322: OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Subsidy, from ), truelight@1322: OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Subsidy, to ), truelight@1322: truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: Darkvater@3626: static inline bool LoadOldSubsidy(LoadgameState *ls, int num) truelight@1322: { truelight@1322: return LoadChunk(ls, &_subsidies[num], subsidy_chunk); truelight@1322: } truelight@1322: truelight@1322: static const OldChunks game_difficulty_chunk[] = { rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, max_no_competitors ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, competitor_start_time ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, number_towns ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, number_industries ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, DifficultySettings, max_loan ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, initial_interest ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, vehicle_costs ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, competitor_speed ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, competitor_intelligence ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, vehicle_breakdowns ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, subsidy_multiplier ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, construction_cost ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, terrain_type ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, quantity_sea_lakes ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, economy ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, line_reverse_mode ), rubidium@10715: OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, disasters ), truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: Darkvater@3626: static inline bool LoadOldGameDifficulty(LoadgameState *ls, int num) truelight@1322: { glx@10776: bool ret = LoadChunk(ls, &_settings_game.difficulty, game_difficulty_chunk); glx@10776: _settings_game.difficulty.max_loan *= 1000; rubidium@10715: return ret; truelight@1322: } truelight@1322: truelight@1322: truelight@1322: static bool LoadOldMapPart1(LoadgameState *ls, int num) truelight@1322: { truelight@1322: uint i; truelight@1322: truelight@1322: for (i = 0; i < OLD_MAP_SIZE; i++) { tron@2360: _m[i].m1 = ReadByte(ls); truelight@1322: } truelight@1322: for (i = 0; i < OLD_MAP_SIZE; i++) { tron@2049: _m[i].m2 = ReadByte(ls); truelight@1322: } truelight@1322: for (i = 0; i < OLD_MAP_SIZE; i++) { truelight@1322: _old_map3[i * 2] = ReadByte(ls); truelight@1322: _old_map3[i * 2 + 1] = ReadByte(ls); truelight@1322: } truelight@1322: for (i = 0; i < OLD_MAP_SIZE / 4; i++) { tron@2049: byte b = ReadByte(ls); belugas@5847: _m[i * 4 + 0].m6 = GB(b, 0, 2); belugas@5847: _m[i * 4 + 1].m6 = GB(b, 2, 2); belugas@5847: _m[i * 4 + 2].m6 = GB(b, 4, 2); belugas@5847: _m[i * 4 + 3].m6 = GB(b, 6, 2); truelight@1322: } truelight@1322: truelight@1326: return !ls->failed; truelight@1322: } Darkvater@3626: truelight@1322: static bool LoadOldMapPart2(LoadgameState *ls, int num) truelight@1322: { truelight@1322: uint i; truelight@1322: truelight@1322: for (i = 0; i < OLD_MAP_SIZE; i++) { tron@2049: _m[i].type_height = ReadByte(ls); truelight@1322: } truelight@1322: for (i = 0; i < OLD_MAP_SIZE; i++) { tron@2049: _m[i].m5 = ReadByte(ls); truelight@1322: } truelight@1322: truelight@1326: return !ls->failed; truelight@1322: } truelight@1322: Darkvater@6400: static bool LoadTTDPatchExtraChunks(LoadgameState *ls, int num) Darkvater@6400: { Darkvater@6400: ReadTTDPatchFlags(); Darkvater@6400: Darkvater@6400: DEBUG(oldloader, 2, "Found %d extra chunk(s)", _old_extra_chunk_nums); Darkvater@6400: Darkvater@6400: for (int i = 0; i != _old_extra_chunk_nums; i++) { Darkvater@6400: uint16 id = ReadUint16(ls); Darkvater@6400: uint32 len = ReadUint32(ls); Darkvater@6400: Darkvater@6400: switch (id) { Darkvater@6411: /* List of GRFIDs, used in the savegame. 0x8004 is the new ID Darkvater@6400: * They are saved in a 'GRFID:4 active:1' format, 5 bytes for each entry */ Darkvater@6400: case 0x2: Darkvater@6400: case 0x8004: { Darkvater@6411: /* Skip the first element: TTDP hack for the Action D special variables (FFFF0000 01) */ Darkvater@6400: ReadUint32(ls); ReadByte(ls); len -= 5; Darkvater@6400: Darkvater@6400: ClearGRFConfigList(&_grfconfig); Darkvater@6400: while (len != 0) { Darkvater@6400: uint32 grfid = ReadUint32(ls); Darkvater@6400: Darkvater@6400: if (ReadByte(ls) == 1) { Darkvater@6434: GRFConfig *c = CallocT(1); Darkvater@6434: c->grfid = grfid; Darkvater@6434: c->filename = strdup("TTDP game, no information"); Darkvater@6400: Darkvater@6434: AppendToGRFConfigList(&_grfconfig, c); Darkvater@6434: DEBUG(oldloader, 3, "TTDPatch game using GRF file with GRFID %0X", BSWAP32(c->grfid)); Darkvater@6400: } Darkvater@6400: len -= 5; Darkvater@6400: }; Darkvater@6400: Darkvater@6400: /* Append static NewGRF configuration */ Darkvater@6400: AppendStaticGRFConfigs(&_grfconfig); Darkvater@6400: } break; Darkvater@6411: glx@9505: /* TTDPatch version and configuration */ rubidium@10455: case 0x3: rubidium@10455: _ttdp_version = ReadUint32(ls); rubidium@10455: DEBUG(oldloader, 3, "Game saved with TTDPatch version %d.%d.%d r%d", rubidium@10455: GB(_ttdp_version, 24, 8), GB(_ttdp_version, 20, 4), GB(_ttdp_version, 16, 4), GB(_ttdp_version, 0, 16)); Darkvater@6400: len -= 4; Darkvater@6400: while (len-- != 0) ReadByte(ls); // skip the configuration rubidium@10455: break; Darkvater@6411: Darkvater@6400: default: Darkvater@6400: DEBUG(oldloader, 4, "Skipping unknown extra chunk %X", id); Darkvater@6400: while (len-- != 0) ReadByte(ls); Darkvater@6400: break; Darkvater@6400: } Darkvater@6400: } Darkvater@6400: Darkvater@6400: return !ls->failed; Darkvater@6400: } Darkvater@6400: rubidium@10249: extern TileIndex _cur_tileloop_tile; truelight@1322: static uint32 _old_cur_town_ctr; truelight@1322: static const OldChunks main_chunk[] = { truelight@1322: OCL_ASSERT( 0 ), rubidium@4326: OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_date ), truelight@1322: OCL_VAR ( OC_UINT16, 1, &_date_fract ), glx@9505: OCL_NULL( 600 ), ///< TextEffects rubidium@9724: OCL_VAR ( OC_UINT32, 2, &_random.state ), truelight@1322: truelight@1322: OCL_ASSERT( 0x264 ), truelight@1322: OCL_CHUNK( 70, LoadOldTown ), truelight@1322: OCL_ASSERT( 0x1C18 ), truelight@1322: OCL_CHUNK(5000, LoadOldOrder ), truelight@1322: OCL_ASSERT( 0x4328 ), truelight@1322: truelight@9718: OCL_CHUNK( 1, LoadOldAnimTileList ), glx@9505: OCL_NULL( 4 ), ///< old end-of-order-list-pointer, no longer in use truelight@1322: truelight@1322: OCL_CHUNK( 255, LoadOldDepot ), truelight@1322: OCL_ASSERT( 0x4B26 ), truelight@1322: truelight@1322: OCL_VAR ( OC_UINT32, 1, &_old_cur_town_ctr ), glx@9505: OCL_NULL( 2 ), ///< timer_counter, no longer in use glx@9505: OCL_NULL( 2 ), ///< land_code, no longer in use truelight@1322: truelight@1322: OCL_VAR ( OC_FILE_U16 | OC_VAR_U8, 1, &_age_cargo_skip_counter ), truelight@1322: OCL_VAR ( OC_UINT16, 1, &_tick_counter ), truelight@1322: OCL_VAR ( OC_TILE, 1, &_cur_tileloop_tile ), truelight@1322: truelight@1322: OCL_CHUNK( 49, LoadOldPrice ), truelight@1322: OCL_CHUNK( 12, LoadOldCargoPaymentRate ), truelight@1322: truelight@1322: OCL_ASSERT( 0x4CBA ), truelight@1322: truelight@1322: OCL_CHUNK( 1, LoadOldMapPart1 ), truelight@1322: truelight@1322: OCL_ASSERT( 0x48CBA ), truelight@1322: truelight@1322: OCL_CHUNK(250, LoadOldStation ), truelight@1322: OCL_CHUNK( 90, LoadOldIndustry ), truelight@1322: OCL_CHUNK( 8, LoadOldPlayer ), truelight@1322: truelight@1322: OCL_ASSERT( 0x547F2 ), truelight@1322: truelight@1322: OCL_CHUNK( 850, LoadOldVehicle ), truelight@1322: truelight@1322: OCL_ASSERT( 0x6F0F2 ), truelight@1322: glx@10294: OCL_VAR ( OC_UINT8 | OC_DEREFERENCE_POINTER, 32 * 500, &_old_name_array ), truelight@1322: glx@9505: OCL_NULL( 0x2000 ), ///< Old hash-table, no longer in use truelight@1322: truelight@1322: OCL_CHUNK( 40, LoadOldSign ), truelight@1322: OCL_CHUNK(256, LoadOldEngine ), truelight@1322: truelight@1322: OCL_VAR ( OC_UINT16, 1, &_vehicle_id_ctr_day ), truelight@1322: truelight@1322: OCL_CHUNK( 8, LoadOldSubsidy ), truelight@1322: truelight@1322: OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_next_competitor_start ), truelight@1322: OCL_VAR ( OC_FILE_I16 | OC_VAR_I32, 1, &_saved_scrollpos_x ), truelight@1322: OCL_VAR ( OC_FILE_I16 | OC_VAR_I32, 1, &_saved_scrollpos_y ), truelight@1322: OCL_VAR ( OC_FILE_U16 | OC_VAR_U8, 1, &_saved_scrollpos_zoom ), truelight@1322: truelight@9718: OCL_VAR ( OC_FILE_U32 | OC_VAR_I64, 1, &_economy.max_loan ), truelight@9718: OCL_VAR ( OC_FILE_U32 | OC_VAR_I64, 1, &_economy.max_loan_unround ), truelight@9718: OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_economy.fluct ), truelight@1322: truelight@1322: OCL_VAR ( OC_UINT16, 1, &_disaster_delay ), truelight@1322: glx@9505: OCL_NULL( 144 ), ///< cargo-stuff, calculated in InitializeLandscapeVariables truelight@1322: rubidium@9724: OCL_CHUNK(256, LoadOldEngineName ), truelight@1322: glx@9505: OCL_NULL( 144 ), ///< AI cargo-stuff, calculated in InitializeLandscapeVariables glx@9505: OCL_NULL( 2 ), ///< Company indexes of players, no longer in use truelight@1322: truelight@1322: OCL_VAR ( OC_FILE_U8 | OC_VAR_U16, 1, &_station_tick_ctr ), truelight@1322: rubidium@10867: OCL_VAR ( OC_UINT8, 1, &_settings_game.locale.currency ), rubidium@10867: OCL_VAR ( OC_UINT8, 1, &_settings_game.locale.units ), truelight@1322: OCL_VAR ( OC_FILE_U8 | OC_VAR_U32, 1, &_cur_player_tick_index ), truelight@1322: glx@9505: OCL_NULL( 2 ), ///< Date stuff, calculated automatically glx@9505: OCL_NULL( 8 ), ///< Player colors, calculated automatically truelight@1322: truelight@1322: OCL_VAR ( OC_UINT8, 1, &_economy.infl_amount ), truelight@1322: OCL_VAR ( OC_UINT8, 1, &_economy.infl_amount_pr ), truelight@1322: OCL_VAR ( OC_UINT8, 1, &_economy.interest_rate ), tron@6222: OCL_NULL( 1 ), // available airports glx@10776: OCL_VAR ( OC_UINT8, 1, &_settings_game.vehicle.road_side ), glx@10776: OCL_VAR ( OC_UINT8, 1, &_settings_game.game_creation.town_name ), truelight@1322: truelight@1322: OCL_CHUNK( 1, LoadOldGameDifficulty ), truelight@1322: truelight@1322: OCL_ASSERT( 0x77130 ), truelight@1322: glx@10776: OCL_VAR ( OC_UINT8, 1, &_settings_game.difficulty.diff_level ), glx@10776: OCL_VAR ( OC_UINT8, 1, &_settings_game.game_creation.landscape ), truelight@1322: OCL_VAR ( OC_UINT8, 1, &_trees_tick_ctr ), truelight@1322: glx@9505: OCL_NULL( 1 ), ///< Custom vehicle types yes/no, no longer used glx@10776: OCL_VAR ( OC_UINT8, 1, &_settings_game.game_creation.snow_line ), truelight@1322: glx@9505: OCL_NULL( 32 ), ///< new_industry_randtable, no longer used (because of new design) glx@9505: OCL_NULL( 36 ), ///< cargo-stuff, calculated in InitializeLandscapeVariables truelight@1322: truelight@1322: OCL_ASSERT( 0x77179 ), truelight@1322: truelight@1322: OCL_CHUNK( 1, LoadOldMapPart2 ), truelight@1322: truelight@1322: OCL_ASSERT( 0x97179 ), truelight@1322: truelight@1322: /* Below any (if available) extra chunks from TTDPatch can follow */ Darkvater@6400: OCL_CHUNK(1, LoadTTDPatchExtraChunks), truelight@1322: truelight@1322: OCL_END() truelight@1322: }; Darkvater@3626: truelight@1322: static bool LoadOldMain(LoadgameState *ls) truelight@1322: { truelight@1322: int i; truelight@1322: truelight@1322: /* The first 49 is the name of the game + checksum, skip it */ truelight@1322: fseek(ls->file, HEADER_SIZE, SEEK_SET); truelight@1322: Darkvater@6342: DEBUG(oldloader, 3, "Reading main chunk..."); truelight@1322: /* Load the biggest chunk */ glx@10294: _old_map3 = MallocT(OLD_MAP_SIZE * 2); tron@2452: if (!LoadChunk(ls, NULL, main_chunk)) { Darkvater@5568: DEBUG(oldloader, 0, "Loading failed"); glx@10294: free(_old_map3); truelight@1322: return false; truelight@1322: } Darkvater@6342: DEBUG(oldloader, 3, "Done, converting game data..."); truelight@1322: truelight@1322: /* Fix some general stuff */ glx@10776: _settings_game.game_creation.landscape = _settings_game.game_creation.landscape & 0xF; truelight@1322: truelight@1322: /* Remap some pointers */ truelight@1322: _cur_town_ctr = REMAP_TOWN_IDX(_old_cur_town_ctr); truelight@1322: truelight@1322: /* _old_map3 is changed in _map3_lo and _map3_hi */ truelight@1322: for (i = 0; i < OLD_MAP_SIZE; i++) { tron@2049: _m[i].m3 = _old_map3[i * 2]; tron@2049: _m[i].m4 = _old_map3[i * 2 + 1]; truelight@1322: } truelight@1322: truelight@1322: for (i = 0; i < OLD_MAP_SIZE; i ++) { Darkvater@6341: switch (GetTileType(i)) { glx@9624: case MP_STATION: glx@9624: _m[i].m4 = 0; // We do not understand this TTDP station mapping (yet) glx@9624: switch (_m[i].m5) { glx@9624: /* We have drive through stops at a totally different place */ rubidium@9686: case 0x53: case 0x54: _m[i].m5 += 170 - 0x53; break; // Bus drive through rubidium@9686: case 0x57: case 0x58: _m[i].m5 += 168 - 0x57; break; // Truck drive through rubidium@9686: case 0x55: case 0x56: _m[i].m5 += 170 - 0x55; break; // Bus tram stop rubidium@9686: case 0x59: case 0x5A: _m[i].m5 += 168 - 0x59; break; // Truck tram stop rubidium@9686: default: break; glx@9624: } glx@9624: break; glx@9624: Darkvater@6341: case MP_RAILWAY: Darkvater@6341: /* We save presignals different from TTDPatch, convert them */ Darkvater@6341: if (GetRailTileType(i) == RAIL_TILE_SIGNALS) { Darkvater@6341: /* This byte is always zero in TTD for this type of tile */ Darkvater@6341: if (_m[i].m4) /* Convert the presignals to our own format */ Darkvater@6341: _m[i].m4 = (_m[i].m4 >> 1) & 7; Darkvater@6341: } Darkvater@6341: /* TTDPatch stores PBS things in L6 and all elsewhere; so we'll just Darkvater@6341: * clear it for ourselves and let OTTD's rebuild PBS itself */ Darkvater@6341: _m[i].m4 &= 0xF; /* Only keep the lower four bits; upper four is PBS */ Darkvater@6341: break; glx@10645: glx@10645: case MP_WATER: glx@10645: if (GetWaterClass(i) == 3) MakeRiver(i, Random()); glx@10645: break; glx@10645: glx@10645: default: glx@10645: break; truelight@0: } truelight@0: } truelight@0: truelight@9718: /* Make sure the available engines are really available, otherwise truelight@9718: * we will get a "new vehicle"-spree. */ rubidium@9724: Engine *e; rubidium@9724: FOR_ALL_ENGINES(e) { truelight@9718: if (_date >= (e->intro_date + 365)) { truelight@9718: e->flags = (e->flags & ~ENGINE_EXCLUSIVE_PREVIEW) | ENGINE_AVAILABLE; truelight@9718: e->player_avail = (byte)-1; truelight@9718: } truelight@9718: } truelight@9718: truelight@1322: /* Fix the game to be compatible with OpenTTD */ truelight@1322: FixOldTowns(); truelight@1322: FixOldStations(); truelight@1322: FixOldVehicles(); truelight@0: truelight@1322: /* We have a new difficulty setting */ glx@10776: _settings_game.difficulty.town_council_tolerance = Clamp(_settings_game.difficulty.diff_level, 0, 2); truelight@0: Darkvater@6342: DEBUG(oldloader, 3, "Finished converting game data"); Darkvater@5568: DEBUG(oldloader, 1, "TTD(Patch) savegame successfully converted"); truelight@0: glx@10294: free(_old_map3); glx@10294: truelight@1322: return true; truelight@1322: } truelight@1322: truelight@1322: bool LoadOldSaveGame(const char *file) truelight@1322: { tron@2452: LoadgameState ls; tron@2452: Darkvater@6342: DEBUG(oldloader, 3, "Trying to load a TTD(Patch) savegame"); truelight@1322: tron@2452: InitLoading(&ls); truelight@1322: truelight@1322: /* Open file */ tron@2452: ls.file = fopen(file, "rb"); truelight@1322: tron@2452: if (ls.file == NULL) { Darkvater@5568: DEBUG(oldloader, 0, "Cannot open file '%s'", file); truelight@1322: return false; truelight@0: } truelight@0: truelight@1322: /* Load the main chunk */ tron@2452: if (!LoadOldMain(&ls)) return false; truelight@193: tron@2452: fclose(ls.file); truelight@1322: rubidium@10455: /* Some old TTD(Patch) savegames could have buoys at tile 0 rubidium@10142: * (without assigned station struct) rubidium@10142: * MakeWater() can be used as long as sea has the same rubidium@10142: * format as old savegames (eg. everything is zeroed) */ rubidium@10142: MakeWater(0); rubidium@10142: truelight@6557: _pause_game = 2; truelight@1340: truelight@0: return true; truelight@0: } truelight@0: Darkvater@4221: void GetOldSaveGameName(char *title, const char *path, const char *file) truelight@0: { Darkvater@4221: char filename[MAX_PATH]; Darkvater@4221: FILE *f; Darkvater@4221: Darkvater@4221: snprintf(filename, lengthof(filename), "%s" PATHSEP "%s", path, file); Darkvater@4221: f = fopen(filename, "rb"); Darkvater@4221: title[0] = '\0'; Darkvater@4221: title[48] = '\0'; truelight@0: Darkvater@3626: if (f == NULL) return; truelight@1326: Darkvater@3626: if (fread(title, 1, 48, f) != 48) snprintf(title, 48, "Corrupt file"); truelight@1322: truelight@0: fclose(f); truelight@0: }