diff options
author | smatz <smatz@openttd.org> | 2009-01-04 15:32:25 +0000 |
---|---|---|
committer | smatz <smatz@openttd.org> | 2009-01-04 15:32:25 +0000 |
commit | 7368c740a646c958797b5dff90d6c5b51236e2a4 (patch) | |
tree | 56e0ff1f4048e467cf123e92ca788c3c4bbc0f94 /src | |
parent | c9e8fd307e36b3d35f5bf7d01cffe64b1e75b846 (diff) | |
download | openttd-7368c740a646c958797b5dff90d6c5b51236e2a4.tar.xz |
(svn r14828) -Codechange: move most of save/load-specific code to separate files
Diffstat (limited to 'src')
88 files changed, 5049 insertions, 4715 deletions
diff --git a/src/ai/default/default.cpp b/src/ai/default/default.cpp index 8cbbafdaa..ab20b5952 100644 --- a/src/ai/default/default.cpp +++ b/src/ai/default/default.cpp @@ -25,7 +25,6 @@ #include "../../window_func.h" #include "../../vehicle_func.h" #include "../../functions.h" -#include "../../saveload.h" #include "../../company_func.h" #include "../../company_base.h" #include "../../settings_type.h" @@ -4027,74 +4026,3 @@ void AiDoGameLoop(Company *c) _ai_actions[_companies_ai[c->index].state](c); } - - -static const SaveLoad _company_ai_desc[] = { - SLE_VAR(CompanyAI, state, SLE_UINT8), - SLE_VAR(CompanyAI, tick, SLE_UINT8), - SLE_CONDVAR(CompanyAI, state_counter, SLE_FILE_U16 | SLE_VAR_U32, 0, 12), - SLE_CONDVAR(CompanyAI, state_counter, SLE_UINT32, 13, SL_MAX_VERSION), - SLE_VAR(CompanyAI, timeout_counter, SLE_UINT16), - - SLE_VAR(CompanyAI, state_mode, SLE_UINT8), - SLE_VAR(CompanyAI, banned_tile_count, SLE_UINT8), - SLE_VAR(CompanyAI, railtype_to_use, SLE_UINT8), - - SLE_VAR(CompanyAI, cargo_type, SLE_UINT8), - SLE_VAR(CompanyAI, num_wagons, SLE_UINT8), - SLE_VAR(CompanyAI, build_kind, SLE_UINT8), - SLE_VAR(CompanyAI, num_build_rec, SLE_UINT8), - SLE_VAR(CompanyAI, num_loco_to_build, SLE_UINT8), - SLE_VAR(CompanyAI, num_want_fullload, SLE_UINT8), - - SLE_VAR(CompanyAI, route_type_mask, SLE_UINT8), - - SLE_CONDVAR(CompanyAI, start_tile_a, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(CompanyAI, start_tile_a, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(CompanyAI, cur_tile_a, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(CompanyAI, cur_tile_a, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_VAR(CompanyAI, start_dir_a, SLE_UINT8), - SLE_VAR(CompanyAI, cur_dir_a, SLE_UINT8), - - SLE_CONDVAR(CompanyAI, start_tile_b, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(CompanyAI, start_tile_b, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(CompanyAI, cur_tile_b, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(CompanyAI, cur_tile_b, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_VAR(CompanyAI, start_dir_b, SLE_UINT8), - SLE_VAR(CompanyAI, cur_dir_b, SLE_UINT8), - - SLE_REF(CompanyAI, cur_veh, REF_VEHICLE), - - SLE_ARR(CompanyAI, wagon_list, SLE_UINT16, 9), - SLE_ARR(CompanyAI, order_list_blocks, SLE_UINT8, 20), - SLE_ARR(CompanyAI, banned_tiles, SLE_UINT16, 16), - - SLE_CONDNULL(64, 2, SL_MAX_VERSION), - SLE_END() -}; - -static const SaveLoad _company_ai_build_rec_desc[] = { - SLE_CONDVAR(AiBuildRec, spec_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(AiBuildRec, spec_tile, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(AiBuildRec, use_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(AiBuildRec, use_tile, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_VAR(AiBuildRec, rand_rng, SLE_UINT8), - SLE_VAR(AiBuildRec, cur_building_rule, SLE_UINT8), - SLE_VAR(AiBuildRec, unk6, SLE_UINT8), - SLE_VAR(AiBuildRec, unk7, SLE_UINT8), - SLE_VAR(AiBuildRec, buildcmd_a, SLE_UINT8), - SLE_VAR(AiBuildRec, buildcmd_b, SLE_UINT8), - SLE_VAR(AiBuildRec, direction, SLE_UINT8), - SLE_VAR(AiBuildRec, cargo, SLE_UINT8), - SLE_END() -}; - - -void SaveLoad_AI(CompanyID company) -{ - CompanyAI *cai = &_companies_ai[company]; - SlObject(cai, _company_ai_desc); - for (int i = 0; i != cai->num_build_rec; i++) { - SlObject(&cai->src + i, _company_ai_build_rec_desc); - } -} diff --git a/src/ai/default/default.h b/src/ai/default/default.h index 69d65a396..843cf0f17 100644 --- a/src/ai/default/default.h +++ b/src/ai/default/default.h @@ -10,7 +10,6 @@ #include "../../rail_type.h" void AiDoGameLoop(Company *c); -void SaveLoad_AI(CompanyID company); struct AiBuildRec { TileIndex spec_tile; diff --git a/src/ai/trolly/trolly.h b/src/ai/trolly/trolly.h index a1d8e0cd9..60180694c 100644 --- a/src/ai/trolly/trolly.h +++ b/src/ai/trolly/trolly.h @@ -10,6 +10,7 @@ #include "../../vehicle_type.h" #include "../../date_type.h" #include "../../engine_type.h" +#include "../../direction_type.h" /* * These defines can be altered to change the behavoir of the AI diff --git a/src/aircraft.h b/src/aircraft.h index 2a143db91..b5a231e25 100644 --- a/src/aircraft.h +++ b/src/aircraft.h @@ -99,6 +99,11 @@ void UpdateAirplanesOnNewStation(const Station *st); */ void UpdateAircraftCache(Vehicle *v); +void AircraftLeaveHangar(Vehicle *v); +void AircraftNextAirportPos_and_Order(Vehicle *v); +void SetAircraftPosition(Vehicle *v, int x, int y, int z); +byte GetAircraftFlyingAltitude(const Vehicle *v); + /** * This class 'wraps' Vehicle; you do not actually instantiate this class. * You create a Vehicle using AllocateVehicle, so it is added to the pool diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index 5cd7f7bb4..41bc1663f 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -82,9 +82,6 @@ static bool AirportFindFreeTerminal(Vehicle *v, const AirportFTAClass *apc); static bool AirportFindFreeHelipad(Vehicle *v, const AirportFTAClass *apc); static void CrashAirplane(Vehicle *v); -void AircraftNextAirportPos_and_Order(Vehicle *v); -static byte GetAircraftFlyingAltitude(const Vehicle *v); - static const SpriteID _aircraft_sprite[] = { 0x0EB5, 0x0EBD, 0x0EC5, 0x0ECD, 0x0ED5, 0x0EDD, 0x0E9D, 0x0EA5, @@ -727,7 +724,7 @@ static void HelicopterTickHandler(Vehicle *v) EndVehicleMove(u); } -static void SetAircraftPosition(Vehicle *v, int x, int y, int z) +void SetAircraftPosition(Vehicle *v, int x, int y, int z) { v->x_pos = x; v->y_pos = y; @@ -883,7 +880,7 @@ static int UpdateAircraftSpeed(Vehicle *v, uint speed_limit = SPEED_LIMIT_NONE, * @param v The vehicle. Should be an aircraft * @returns Altitude in pixel units */ -static byte GetAircraftFlyingAltitude(const Vehicle *v) +byte GetAircraftFlyingAltitude(const Vehicle *v) { /* Make sure Aircraft fly no lower so that they don't conduct * CFITs (controlled flight into terrain) @@ -1433,7 +1430,7 @@ void AircraftNextAirportPos_and_Order(Vehicle *v) v->u.air.pos = v->u.air.previous_pos = AircraftGetEntryPoint(v, apc); } -static void AircraftLeaveHangar(Vehicle *v) +void AircraftLeaveHangar(Vehicle *v) { v->cur_speed = 0; v->subspeed = 0; @@ -2096,42 +2093,6 @@ Station *GetTargetAirportIfValid(const Vehicle *v) return st->airport_tile == INVALID_TILE ? NULL : st; } -/** need to be called to load aircraft from old version */ -void UpdateOldAircraft() -{ - /* set airport_flags to 0 for all airports just to be sure */ - Station *st; - FOR_ALL_STATIONS(st) { - st->airport_flags = 0; // reset airport - } - - Vehicle *v_oldstyle; - FOR_ALL_VEHICLES(v_oldstyle) { - /* airplane has another vehicle with subtype 4 (shadow), helicopter also has 3 (rotor) - * skip those */ - if (v_oldstyle->type == VEH_AIRCRAFT && IsNormalAircraft(v_oldstyle)) { - /* airplane in terminal stopped doesn't hurt anyone, so goto next */ - if (v_oldstyle->vehstatus & VS_STOPPED && v_oldstyle->u.air.state == 0) { - v_oldstyle->u.air.state = HANGAR; - continue; - } - - AircraftLeaveHangar(v_oldstyle); // make airplane visible if it was in a depot for example - v_oldstyle->vehstatus &= ~VS_STOPPED; // make airplane moving - v_oldstyle->u.air.state = FLYING; - AircraftNextAirportPos_and_Order(v_oldstyle); // move it to the entry point of the airport - GetNewVehiclePosResult gp = GetNewVehiclePos(v_oldstyle); - v_oldstyle->tile = 0; // aircraft in air is tile=0 - - /* correct speed of helicopter-rotors */ - if (v_oldstyle->subtype == AIR_HELICOPTER) v_oldstyle->Next()->Next()->cur_speed = 32; - - /* set new position x,y,z */ - SetAircraftPosition(v_oldstyle, gp.x, gp.y, GetAircraftFlyingAltitude(v_oldstyle)); - } - } -} - /** * Updates the status of the Aircraft heading or in the station * @param st Station been updated diff --git a/src/animated_tile.cpp b/src/animated_tile.cpp index a66225ae6..fd3fc12f8 100644 --- a/src/animated_tile.cpp +++ b/src/animated_tile.cpp @@ -4,7 +4,6 @@ #include "stdafx.h" #include "openttd.h" -#include "saveload.h" #include "landscape.h" #include "core/alloc_func.hpp" #include "functions.h" @@ -14,7 +13,7 @@ TileIndex *_animated_tile_list = NULL; /** The number of animated tiles in the current state. */ uint _animated_tile_count = 0; /** The number of slots for animated tiles allocated currently. */ -static uint _animated_tile_allocated = 0; +uint _animated_tile_allocated = 0; /** * Removes the given tile from the animated tile table. @@ -90,46 +89,3 @@ void InitializeAnimatedTiles() _animated_tile_count = 0; _animated_tile_allocated = 256; } - -/** - * Save the ANIT chunk. - */ -static void Save_ANIT() -{ - SlSetLength(_animated_tile_count * sizeof(*_animated_tile_list)); - SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32); -} - -/** - * Load the ANIT chunk; the chunk containing the animated tiles. - */ -static void Load_ANIT() -{ - /* Before version 80 we did NOT have a variable length animated tile table */ - if (CheckSavegameVersion(80)) { - /* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */ - SlArray(_animated_tile_list, 256, CheckSavegameVersion(6) ? (SLE_FILE_U16 | SLE_VAR_U32) : SLE_UINT32); - - for (_animated_tile_count = 0; _animated_tile_count < 256; _animated_tile_count++) { - if (_animated_tile_list[_animated_tile_count] == 0) break; - } - return; - } - - _animated_tile_count = (uint)SlGetFieldLength() / sizeof(*_animated_tile_list); - - /* Determine a nice rounded size for the amount of allocated tiles */ - _animated_tile_allocated = 256; - while (_animated_tile_allocated < _animated_tile_count) _animated_tile_allocated *= 2; - - _animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, _animated_tile_allocated); - SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32); -} - -/** - * "Definition" imported by the saveload code to be able to load and save - * the animated tile table. - */ -extern const ChunkHandler _animated_tile_chunk_handlers[] = { - { 'ANIT', Save_ANIT, Load_ANIT, CH_RIFF | CH_LAST}, -}; diff --git a/src/autoreplace.cpp b/src/autoreplace.cpp index a2da94776..830236019 100644 --- a/src/autoreplace.cpp +++ b/src/autoreplace.cpp @@ -6,7 +6,6 @@ #include "openttd.h" #include "debug.h" #include "command_func.h" -#include "saveload.h" #include "group.h" #include "autoreplace_base.h" #include "oldpool_func.h" @@ -102,46 +101,6 @@ CommandCost RemoveEngineReplacement(EngineRenewList *erl, EngineID engine, Group return CMD_ERROR; } -static const SaveLoad _engine_renew_desc[] = { - SLE_VAR(EngineRenew, from, SLE_UINT16), - SLE_VAR(EngineRenew, to, SLE_UINT16), - - SLE_REF(EngineRenew, next, REF_ENGINE_RENEWS), - SLE_CONDVAR(EngineRenew, group_id, SLE_UINT16, 60, SL_MAX_VERSION), - SLE_END() -}; - -static void Save_ERNW() -{ - EngineRenew *er; - - FOR_ALL_ENGINE_RENEWS(er) { - SlSetArrayIndex(er->index); - SlObject(er, _engine_renew_desc); - } -} - -static void Load_ERNW() -{ - int index; - - while ((index = SlIterateArray()) != -1) { - EngineRenew *er = new (index) EngineRenew(); - SlObject(er, _engine_renew_desc); - - /* Advanced vehicle lists, ungrouped vehicles got added */ - if (CheckSavegameVersion(60)) { - er->group_id = ALL_GROUP; - } else if (CheckSavegameVersion(71)) { - if (er->group_id == DEFAULT_GROUP) er->group_id = ALL_GROUP; - } - } -} - -extern const ChunkHandler _autoreplace_chunk_handlers[] = { - { 'ERNW', Save_ERNW, Load_ERNW, CH_ARRAY | CH_LAST}, -}; - void InitializeEngineRenews() { /* Clean the engine renew pool and create 1 block in it */ diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp index 971db12ef..3c043829a 100644 --- a/src/cargopacket.cpp +++ b/src/cargopacket.cpp @@ -3,10 +3,8 @@ /** @file cargopacket.cpp Implementation of the cargo packets */ #include "stdafx.h" -#include "openttd.h" #include "station_base.h" #include "cargopacket.h" -#include "saveload.h" #include "oldpool_func.h" /* Initialize the cargopacket-pool */ @@ -43,42 +41,6 @@ bool CargoPacket::SameSource(const CargoPacket *cp) const return this->source_xy == cp->source_xy && this->days_in_transit == cp->days_in_transit && this->paid_for == cp->paid_for; } -static const SaveLoad _cargopacket_desc[] = { - SLE_VAR(CargoPacket, source, SLE_UINT16), - SLE_VAR(CargoPacket, source_xy, SLE_UINT32), - SLE_VAR(CargoPacket, loaded_at_xy, SLE_UINT32), - SLE_VAR(CargoPacket, count, SLE_UINT16), - SLE_VAR(CargoPacket, days_in_transit, SLE_UINT8), - SLE_VAR(CargoPacket, feeder_share, SLE_INT64), - SLE_VAR(CargoPacket, paid_for, SLE_BOOL), - - SLE_END() -}; - -static void Save_CAPA() -{ - CargoPacket *cp; - - FOR_ALL_CARGOPACKETS(cp) { - SlSetArrayIndex(cp->index); - SlObject(cp, _cargopacket_desc); - } -} - -static void Load_CAPA() -{ - int index; - - while ((index = SlIterateArray()) != -1) { - CargoPacket *cp = new (index) CargoPacket(); - SlObject(cp, _cargopacket_desc); - } -} - -extern const ChunkHandler _cargopacket_chunk_handlers[] = { - { 'CAPA', Save_CAPA, Load_CAPA, CH_ARRAY | CH_LAST}, -}; - /* * * Cargo list implementation diff --git a/src/cheat.cpp b/src/cheat.cpp index 8a7d2e04c..8f18e5bc1 100644 --- a/src/cheat.cpp +++ b/src/cheat.cpp @@ -3,7 +3,6 @@ /** @file cheat.cpp Handling (loading/saving/initializing) of cheats. */ #include "stdafx.h" -#include "saveload.h" #include "cheat_type.h" Cheats _cheats; @@ -13,31 +12,6 @@ void InitializeCheats() memset(&_cheats, 0, sizeof(Cheats)); } -static void Save_CHTS() -{ - /* Cannot use lengthof because _cheats is of type Cheats, not Cheat */ - byte count = sizeof(_cheats) / sizeof(Cheat); - Cheat *cht = (Cheat*) &_cheats; - Cheat *cht_last = &cht[count]; - - SlSetLength(count * 2); - for (; cht != cht_last; cht++) { - SlWriteByte(cht->been_used); - SlWriteByte(cht->value); - } -} - -static void Load_CHTS() -{ - Cheat *cht = (Cheat*)&_cheats; - size_t count = SlGetFieldLength() / 2; - - for (uint i = 0; i < count; i++) { - cht[i].been_used = (SlReadByte() != 0); - cht[i].value = (SlReadByte() != 0); - } -} - bool CheatHasBeenUsed() { /* Cannot use lengthof because _cheats is of type Cheats, not Cheat */ @@ -50,8 +24,3 @@ bool CheatHasBeenUsed() return false; } - - -extern const ChunkHandler _cheat_chunk_handlers[] = { - { 'CHTS', Save_CHTS, Load_CHTS, CH_RIFF | CH_LAST} -}; diff --git a/src/cheat_gui.cpp b/src/cheat_gui.cpp index 19b07e460..1ddb1c662 100644 --- a/src/cheat_gui.cpp +++ b/src/cheat_gui.cpp @@ -10,7 +10,7 @@ #include "company_func.h" #include "gfx_func.h" #include "date_func.h" -#include "saveload.h" +#include "saveload/saveload.h" #include "window_gui.h" #include "newgrf.h" #include "settings_type.h" diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 087e490dc..338abc88b 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -10,7 +10,6 @@ #include "company_gui.h" #include "town.h" #include "news_func.h" -#include "saveload.h" #include "command_func.h" #include "network/network.h" #include "network/network_func.h" @@ -111,74 +110,6 @@ void DrawCompanyIcon(CompanyID c, int x, int y) } /** - * Converts an old company manager's face format to the new company manager's face format - * - * Meaning of the bits in the old face (some bits are used in several times): - * - 4 and 5: chin - * - 6 to 9: eyebrows - * - 10 to 13: nose - * - 13 to 15: lips (also moustache for males) - * - 16 to 19: hair - * - 20 to 22: eye color - * - 20 to 27: tie, ear rings etc. - * - 28 to 30: glasses - * - 19, 26 and 27: race (bit 27 set and bit 19 equal to bit 26 = black, otherwise white) - * - 31: gender (0 = male, 1 = female) - * - * @param face the face in the old format - * @return the face in the new format - */ -CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32 face) -{ - CompanyManagerFace cmf = 0; - GenderEthnicity ge = GE_WM; - - if (HasBit(face, 31)) SetBit(ge, GENDER_FEMALE); - if (HasBit(face, 27) && (HasBit(face, 26) == HasBit(face, 19))) SetBit(ge, ETHNICITY_BLACK); - - SetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, ge, ge); - SetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge, GB(face, 28, 3) <= 1); - SetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR, ge, HasBit(ge, ETHNICITY_BLACK) ? 0 : ClampU(GB(face, 20, 3), 5, 7) - 5); - SetCompanyManagerFaceBits(cmf, CMFV_CHIN, ge, ScaleCompanyManagerFaceValue(CMFV_CHIN, ge, GB(face, 4, 2))); - SetCompanyManagerFaceBits(cmf, CMFV_EYEBROWS, ge, ScaleCompanyManagerFaceValue(CMFV_EYEBROWS, ge, GB(face, 6, 4))); - SetCompanyManagerFaceBits(cmf, CMFV_HAIR, ge, ScaleCompanyManagerFaceValue(CMFV_HAIR, ge, GB(face, 16, 4))); - SetCompanyManagerFaceBits(cmf, CMFV_JACKET, ge, ScaleCompanyManagerFaceValue(CMFV_JACKET, ge, GB(face, 20, 2))); - SetCompanyManagerFaceBits(cmf, CMFV_COLLAR, ge, ScaleCompanyManagerFaceValue(CMFV_COLLAR, ge, GB(face, 22, 2))); - SetCompanyManagerFaceBits(cmf, CMFV_GLASSES, ge, GB(face, 28, 1)); - - uint lips = GB(face, 10, 4); - if (!HasBit(ge, GENDER_FEMALE) && lips < 4) { - SetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE, ge, true); - SetCompanyManagerFaceBits(cmf, CMFV_MOUSTACHE, ge, max(lips, 1U) - 1); - } else { - if (!HasBit(ge, GENDER_FEMALE)) { - lips = lips * 15 / 16; - lips -= 3; - if (HasBit(ge, ETHNICITY_BLACK) && lips > 8) lips = 0; - } else { - lips = ScaleCompanyManagerFaceValue(CMFV_LIPS, ge, lips); - } - SetCompanyManagerFaceBits(cmf, CMFV_LIPS, ge, lips); - - uint nose = GB(face, 13, 3); - if (ge == GE_WF) { - nose = (nose * 3 >> 3) * 3 >> 2; // There is 'hole' in the nose sprites for females - } else { - nose = ScaleCompanyManagerFaceValue(CMFV_NOSE, ge, nose); - } - SetCompanyManagerFaceBits(cmf, CMFV_NOSE, ge, nose); - } - - uint tie_earring = GB(face, 24, 4); - if (!HasBit(ge, GENDER_FEMALE) || tie_earring < 3) { // Not all females have an earring - if (HasBit(ge, GENDER_FEMALE)) SetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge, true); - SetCompanyManagerFaceBits(cmf, CMFV_TIE_EARRING, ge, HasBit(ge, GENDER_FEMALE) ? tie_earring : ScaleCompanyManagerFaceValue(CMFV_TIE_EARRING, ge, tie_earring / 2)); - } - - return cmf; -} - -/** * Checks whether a company manager's face is a valid encoding. * Unused bits are not enforced to be 0. * @param cmf the fact to check @@ -936,159 +867,3 @@ CommandCost CmdCompanyCtrl(TileIndex tile, uint32 flags, uint32 p1, uint32 p2, c return CommandCost(); } - -/* Save/load of companies */ -static const SaveLoad _company_desc[] = { - SLE_VAR(Company, name_2, SLE_UINT32), - SLE_VAR(Company, name_1, SLE_STRINGID), - SLE_CONDSTR(Company, name, SLE_STR, 0, 84, SL_MAX_VERSION), - - SLE_VAR(Company, president_name_1, SLE_UINT16), - SLE_VAR(Company, president_name_2, SLE_UINT32), - SLE_CONDSTR(Company, president_name, SLE_STR, 0, 84, SL_MAX_VERSION), - - SLE_VAR(Company, face, SLE_UINT32), - - /* money was changed to a 64 bit field in savegame version 1. */ - SLE_CONDVAR(Company, money, SLE_VAR_I64 | SLE_FILE_I32, 0, 0), - SLE_CONDVAR(Company, money, SLE_INT64, 1, SL_MAX_VERSION), - - SLE_CONDVAR(Company, current_loan, SLE_VAR_I64 | SLE_FILE_I32, 0, 64), - SLE_CONDVAR(Company, current_loan, SLE_INT64, 65, SL_MAX_VERSION), - - SLE_VAR(Company, colour, SLE_UINT8), - SLE_VAR(Company, money_fraction, SLE_UINT8), - SLE_CONDVAR(Company, avail_railtypes, SLE_UINT8, 0, 57), - SLE_VAR(Company, block_preview, SLE_UINT8), - - SLE_CONDVAR(Company, cargo_types, SLE_FILE_U16 | SLE_VAR_U32, 0, 93), - SLE_CONDVAR(Company, cargo_types, SLE_UINT32, 94, SL_MAX_VERSION), - SLE_CONDVAR(Company, location_of_HQ, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Company, location_of_HQ, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(Company, last_build_coordinate, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Company, last_build_coordinate, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(Company, inaugurated_year, SLE_FILE_U8 | SLE_VAR_I32, 0, 30), - SLE_CONDVAR(Company, inaugurated_year, SLE_INT32, 31, SL_MAX_VERSION), - - SLE_ARR(Company, share_owners, SLE_UINT8, 4), - - SLE_VAR(Company, num_valid_stat_ent, SLE_UINT8), - - SLE_VAR(Company, quarters_of_bankrupcy, SLE_UINT8), - SLE_CONDVAR(Company, bankrupt_asked, SLE_FILE_U8 | SLE_VAR_U16, 0, 103), - SLE_CONDVAR(Company, bankrupt_asked, SLE_UINT16, 104, SL_MAX_VERSION), - SLE_VAR(Company, bankrupt_timeout, SLE_INT16), - SLE_CONDVAR(Company, bankrupt_value, SLE_VAR_I64 | SLE_FILE_I32, 0, 64), - SLE_CONDVAR(Company, bankrupt_value, SLE_INT64, 65, SL_MAX_VERSION), - - /* yearly expenses was changed to 64-bit in savegame version 2. */ - SLE_CONDARR(Company, yearly_expenses, SLE_FILE_I32 | SLE_VAR_I64, 3 * 13, 0, 1), - SLE_CONDARR(Company, yearly_expenses, SLE_INT64, 3 * 13, 2, SL_MAX_VERSION), - - SLE_CONDVAR(Company, is_ai, SLE_BOOL, 2, SL_MAX_VERSION), - SLE_CONDNULL(1, 4, 99), - - /* Engine renewal settings */ - SLE_CONDNULL(512, 16, 18), - SLE_CONDREF(Company, engine_renew_list, REF_ENGINE_RENEWS, 19, SL_MAX_VERSION), - SLE_CONDVAR(Company, engine_renew, SLE_BOOL, 16, SL_MAX_VERSION), - SLE_CONDVAR(Company, engine_renew_months, SLE_INT16, 16, SL_MAX_VERSION), - SLE_CONDVAR(Company, engine_renew_money, SLE_UINT32, 16, SL_MAX_VERSION), - SLE_CONDVAR(Company, renew_keep_length, SLE_BOOL, 2, SL_MAX_VERSION), // added with 16.1, but was blank since 2 - - /* reserve extra space in savegame here. (currently 63 bytes) */ - SLE_CONDNULL(63, 2, SL_MAX_VERSION), - - SLE_END() -}; - -static const SaveLoad _company_economy_desc[] = { - /* these were changed to 64-bit in savegame format 2 */ - SLE_CONDVAR(CompanyEconomyEntry, income, SLE_FILE_I32 | SLE_VAR_I64, 0, 1), - SLE_CONDVAR(CompanyEconomyEntry, income, SLE_INT64, 2, SL_MAX_VERSION), - SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_FILE_I32 | SLE_VAR_I64, 0, 1), - SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_INT64, 2, SL_MAX_VERSION), - SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_FILE_I32 | SLE_VAR_I64, 0, 1), - SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_INT64, 2, SL_MAX_VERSION), - - SLE_VAR(CompanyEconomyEntry, delivered_cargo, SLE_INT32), - SLE_VAR(CompanyEconomyEntry, performance_history, SLE_INT32), - - SLE_END() -}; - -static const SaveLoad _company_livery_desc[] = { - SLE_CONDVAR(Livery, in_use, SLE_BOOL, 34, SL_MAX_VERSION), - SLE_CONDVAR(Livery, colour1, SLE_UINT8, 34, SL_MAX_VERSION), - SLE_CONDVAR(Livery, colour2, SLE_UINT8, 34, SL_MAX_VERSION), - SLE_END() -}; - -static void SaveLoad_PLYR(Company *c) -{ - int i; - - SlObject(c, _company_desc); - - /* Write AI? */ - if (!IsHumanCompany(c->index)) { - SaveLoad_AI(c->index); - } - - /* Write economy */ - SlObject(&c->cur_economy, _company_economy_desc); - - /* Write old economy entries. */ - for (i = 0; i < c->num_valid_stat_ent; i++) { - SlObject(&c->old_economy[i], _company_economy_desc); - } - - /* Write each livery entry. */ - int num_liveries = CheckSavegameVersion(63) ? LS_END - 4 : (CheckSavegameVersion(85) ? LS_END - 2: LS_END); - for (i = 0; i < num_liveries; i++) { - SlObject(&c->livery[i], _company_livery_desc); - } - - if (num_liveries < LS_END) { - /* We want to insert some liveries somewhere in between. This means some have to be moved. */ - memmove(&c->livery[LS_FREIGHT_WAGON], &c->livery[LS_PASSENGER_WAGON_MONORAIL], (LS_END - LS_FREIGHT_WAGON) * sizeof(c->livery[0])); - c->livery[LS_PASSENGER_WAGON_MONORAIL] = c->livery[LS_MONORAIL]; - c->livery[LS_PASSENGER_WAGON_MAGLEV] = c->livery[LS_MAGLEV]; - } - - if (num_liveries == LS_END - 4) { - /* Copy bus/truck liveries over to trams */ - c->livery[LS_PASSENGER_TRAM] = c->livery[LS_BUS]; - c->livery[LS_FREIGHT_TRAM] = c->livery[LS_TRUCK]; - } -} - -static void Save_PLYR() -{ - Company *c; - FOR_ALL_COMPANIES(c) { - SlSetArrayIndex(c->index); - SlAutolength((AutolengthProc*)SaveLoad_PLYR, c); - } -} - -static void Load_PLYR() -{ - int index; - while ((index = SlIterateArray()) != -1) { - Company *c = new (index) Company(); - SaveLoad_PLYR(c); - _company_colours[index] = c->colour; - - /* This is needed so an AI is attached to a loaded AI */ - if (c->is_ai && (!_networking || _network_server) && _ai.enabled) { - /* Clear the memory of the new AI, otherwise we might be doing wrong things. */ - memset(&_companies_ainew[index], 0, sizeof(CompanyAiNew)); - AI_StartNewAI(c->index); - } - } -} - -extern const ChunkHandler _company_chunk_handlers[] = { - { 'PLYR', Save_PLYR, Load_PLYR, CH_ARRAY | CH_LAST}, -}; diff --git a/src/company_manager_face.h b/src/company_manager_face.h index 6f2a96ff9..184f7d87c 100644 --- a/src/company_manager_face.h +++ b/src/company_manager_face.h @@ -7,6 +7,8 @@ #include "core/random_func.hpp" #include "core/bitmath_func.hpp" +#include "table/sprites.h" +#include "company_type.h" /** The gender/race combinations that we have faces for */ enum GenderEthnicity { @@ -228,7 +230,6 @@ static inline SpriteID GetCompanyManagerFaceSprite(CompanyManagerFace cmf, Compa } void DrawCompanyManagerFace(CompanyManagerFace face, int color, int x, int y); -CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32 face); bool IsValidCompanyManagerFace(CompanyManagerFace cmf); #endif /* COMPANY_MANAGER_FACE_H */ diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 92f6a7934..e98997d66 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -8,7 +8,7 @@ #include "debug.h" #include "engine_func.h" #include "landscape.h" -#include "saveload.h" +#include "saveload/saveload.h" #include "variables.h" #include "network/network.h" #include "network/network_func.h" diff --git a/src/date.cpp b/src/date.cpp index d20665f86..9d2f8e29f 100644 --- a/src/date.cpp +++ b/src/date.cpp @@ -15,7 +15,7 @@ #include "vehicle_base.h" #include "debug.h" #include "rail_gui.h" -#include "saveload.h" +#include "saveload/saveload.h" Year _cur_year; ///< Current year, starting at 0 Month _cur_month; ///< Current month (0..11) diff --git a/src/depot.cpp b/src/depot.cpp index 005f067b1..cf6ec603a 100644 --- a/src/depot.cpp +++ b/src/depot.cpp @@ -3,10 +3,8 @@ /** @file depot.cpp Handling of depots. */ #include "stdafx.h" -#include "openttd.h" #include "depot_base.h" #include "landscape.h" -#include "saveload.h" #include "order_func.h" #include "window_func.h" #include "oldpool_func.h" @@ -51,35 +49,3 @@ void InitializeDepots() _Depot_pool.CleanPool(); _Depot_pool.AddBlockToPool(); } - - -static const SaveLoad _depot_desc[] = { - SLE_CONDVAR(Depot, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Depot, xy, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_VAR(Depot, town_index, SLE_UINT16), - SLE_END() -}; - -static void Save_DEPT() -{ - Depot *depot; - - FOR_ALL_DEPOTS(depot) { - SlSetArrayIndex(depot->index); - SlObject(depot, _depot_desc); - } -} - -static void Load_DEPT() -{ - int index; - - while ((index = SlIterateArray()) != -1) { - Depot *depot = new (index) Depot(); - SlObject(depot, _depot_desc); - } -} - -extern const ChunkHandler _depot_chunk_handlers[] = { - { 'DEPT', Save_DEPT, Load_DEPT, CH_ARRAY | CH_LAST}, -}; diff --git a/src/economy.cpp b/src/economy.cpp index 3c220d329..f8d0205b0 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -9,7 +9,6 @@ #include "company_base.h" #include "company_func.h" #include "command_func.h" -#include "saveload.h" #include "industry.h" #include "industry_map.h" #include "town.h" @@ -767,7 +766,7 @@ void SetPriceBaseMultiplier(uint price, byte factor) * Initialize the variables that will maintain the daily industry change system. * @param init_counter specifies if the counter is required to be initialized */ -static void StartupIndustryDailyChanges(bool init_counter) +void StartupIndustryDailyChanges(bool init_counter) { uint map_size = MapLogX() + MapLogY(); /* After getting map size, it needs to be scaled appropriately and divided by 31, @@ -1121,37 +1120,6 @@ no_add:; InvalidateWindow(WC_SUBSIDIES_LIST, 0); } -static const SaveLoad _subsidies_desc[] = { - SLE_VAR(Subsidy, cargo_type, SLE_UINT8), - SLE_VAR(Subsidy, age, SLE_UINT8), - SLE_CONDVAR(Subsidy, from, SLE_FILE_U8 | SLE_VAR_U16, 0, 4), - SLE_CONDVAR(Subsidy, from, SLE_UINT16, 5, SL_MAX_VERSION), - SLE_CONDVAR(Subsidy, to, SLE_FILE_U8 | SLE_VAR_U16, 0, 4), - SLE_CONDVAR(Subsidy, to, SLE_UINT16, 5, SL_MAX_VERSION), - SLE_END() -}; - -static void Save_SUBS() -{ - int i; - Subsidy *s; - - for (i = 0; i != lengthof(_subsidies); i++) { - s = &_subsidies[i]; - if (s->cargo_type != CT_INVALID) { - SlSetArrayIndex(i); - SlObject(s, _subsidies_desc); - } - } -} - -static void Load_SUBS() -{ - int index; - while ((index = SlIterateArray()) != -1) - SlObject(&_subsidies[index], _subsidies_desc); -} - Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type) { const CargoSpec *cs = GetCargo(cargo_type); @@ -1994,54 +1962,3 @@ CommandCost CmdBuyCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2, co } return CommandCost(EXPENSES_OTHER, c->bankrupt_value); } - -/** Prices */ -static void SaveLoad_PRIC() -{ - int vt = CheckSavegameVersion(65) ? (SLE_FILE_I32 | SLE_VAR_I64) : SLE_INT64; - SlArray(&_price, NUM_PRICES, vt); - SlArray(&_price_frac, NUM_PRICES, SLE_UINT16); -} - -/** Cargo payment rates */ -static void SaveLoad_CAPR() -{ - uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO; - int vt = CheckSavegameVersion(65) ? (SLE_FILE_I32 | SLE_VAR_I64) : SLE_INT64; - SlArray(&_cargo_payment_rates, num_cargo, vt); - SlArray(&_cargo_payment_rates_frac, num_cargo, SLE_UINT16); -} - -static const SaveLoad _economy_desc[] = { - SLE_CONDVAR(Economy, max_loan, SLE_FILE_I32 | SLE_VAR_I64, 0, 64), - SLE_CONDVAR(Economy, max_loan, SLE_INT64, 65, SL_MAX_VERSION), - SLE_CONDVAR(Economy, max_loan_unround, SLE_FILE_I32 | SLE_VAR_I64, 0, 64), - SLE_CONDVAR(Economy, max_loan_unround, SLE_INT64, 65, SL_MAX_VERSION), - SLE_CONDVAR(Economy, max_loan_unround_fract, SLE_UINT16, 70, SL_MAX_VERSION), - SLE_VAR(Economy, fluct, SLE_INT16), - SLE_VAR(Economy, interest_rate, SLE_UINT8), - SLE_VAR(Economy, infl_amount, SLE_UINT8), - SLE_VAR(Economy, infl_amount_pr, SLE_UINT8), - SLE_CONDVAR(Economy, industry_daily_change_counter, SLE_UINT32, 102, SL_MAX_VERSION), - SLE_END() -}; - -/** Economy variables */ -static void Save_ECMY() -{ - SlObject(&_economy, _economy_desc); -} - -/** Economy variables */ -static void Load_ECMY() -{ - SlObject(&_economy, _economy_desc); - StartupIndustryDailyChanges(CheckSavegameVersion(102)); // old savegames will need to be initialized -} - -extern const ChunkHandler _economy_chunk_handlers[] = { - { 'PRIC', SaveLoad_PRIC, SaveLoad_PRIC, CH_RIFF | CH_AUTO_LENGTH}, - { 'CAPR', SaveLoad_CAPR, SaveLoad_CAPR, CH_RIFF | CH_AUTO_LENGTH}, - { 'SUBS', Save_SUBS, Load_SUBS, CH_ARRAY}, - { 'ECMY', Save_ECMY, Load_ECMY, CH_RIFF | CH_LAST}, -}; diff --git a/src/economy_func.h b/src/economy_func.h index e9c569832..8bbb4a7cc 100644 --- a/src/economy_func.h +++ b/src/economy_func.h @@ -34,6 +34,7 @@ Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode); void DeleteSubsidyWithTown(TownID index); void DeleteSubsidyWithIndustry(IndustryID index); void DeleteSubsidyWithStation(StationID index); +void StartupIndustryDailyChanges(bool init_counter); Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type); uint MoveGoodsToStation(TileIndex tile, int w, int h, CargoID type, uint amount); diff --git a/src/effectvehicle.cpp b/src/effectvehicle.cpp index 5caae25da..6d97b49c2 100644 --- a/src/effectvehicle.cpp +++ b/src/effectvehicle.cpp @@ -15,7 +15,6 @@ #include "gfx_func.h" #include "news_func.h" #include "command_func.h" -#include "saveload.h" #include "company_func.h" #include "debug.h" #include "vehicle_gui.h" diff --git a/src/engine.cpp b/src/engine.cpp index 564ff33f5..c8a256f10 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -9,7 +9,6 @@ #include "company_func.h" #include "command_func.h" #include "news_func.h" -#include "saveload.h" #include "variables.h" #include "train.h" #include "aircraft.h" @@ -27,7 +26,6 @@ #include "oldpool_func.h" #include "core/alloc_func.hpp" #include "vehicle_func.h" -#include <map> #include "table/strings.h" #include "table/engines.h" @@ -613,112 +611,3 @@ CargoID GetEngineCargoType(EngineID engine) default: NOT_REACHED(); return CT_INVALID; } } - -static const SaveLoad _engine_desc[] = { - SLE_CONDVAR(Engine, intro_date, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), - SLE_CONDVAR(Engine, intro_date, SLE_INT32, 31, SL_MAX_VERSION), - SLE_CONDVAR(Engine, age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), - SLE_CONDVAR(Engine, age, SLE_INT32, 31, SL_MAX_VERSION), - SLE_VAR(Engine, reliability, SLE_UINT16), - SLE_VAR(Engine, reliability_spd_dec, SLE_UINT16), - SLE_VAR(Engine, reliability_start, SLE_UINT16), - SLE_VAR(Engine, reliability_max, SLE_UINT16), - SLE_VAR(Engine, reliability_final, SLE_UINT16), - SLE_VAR(Engine, duration_phase_1, SLE_UINT16), - SLE_VAR(Engine, duration_phase_2, SLE_UINT16), - SLE_VAR(Engine, duration_phase_3, SLE_UINT16), - - SLE_VAR(Engine, lifelength, SLE_UINT8), - SLE_VAR(Engine, flags, SLE_UINT8), - SLE_VAR(Engine, preview_company_rank,SLE_UINT8), - SLE_VAR(Engine, preview_wait, SLE_UINT8), - SLE_CONDNULL(1, 0, 44), - SLE_CONDVAR(Engine, company_avail, SLE_FILE_U8 | SLE_VAR_U16, 0, 103), - SLE_CONDVAR(Engine, company_avail, SLE_UINT16, 104, SL_MAX_VERSION), - SLE_CONDSTR(Engine, name, SLE_STR, 0, 84, SL_MAX_VERSION), - - /* reserve extra space in savegame here. (currently 16 bytes) */ - SLE_CONDNULL(16, 2, SL_MAX_VERSION), - - SLE_END() -}; - -static std::map<EngineID, Engine> _temp_engine; - -Engine *GetTempDataEngine(EngineID index) -{ - return &_temp_engine[index]; -} - -static void Save_ENGN() -{ - Engine *e; - FOR_ALL_ENGINES(e) { - SlSetArrayIndex(e->index); - SlObject(e, _engine_desc); - } -} - -static void Load_ENGN() -{ - /* As engine data is loaded before engines are initialized we need to load - * this information into a temporary array. This is then copied into the - * engine pool after processing NewGRFs by CopyTempEngineData(). */ - int index; - while ((index = SlIterateArray()) != -1) { - Engine *e = GetTempDataEngine(index); - SlObject(e, _engine_desc); - } -} - -/** - * Copy data from temporary engine array into the real engine pool. - */ -void CopyTempEngineData() -{ - Engine *e; - FOR_ALL_ENGINES(e) { - if (e->index >= _temp_engine.size()) break; - - const Engine *se = GetTempDataEngine(e->index); - e->intro_date = se->intro_date; - e->age = se->age; - e->reliability = se->reliability; - e->reliability_spd_dec = se->reliability_spd_dec; - e->reliability_start = se->reliability_start; - e->reliability_max = se->reliability_max; - e->reliability_final = se->reliability_final; - e->duration_phase_1 = se->duration_phase_1; - e->duration_phase_2 = se->duration_phase_2; - e->duration_phase_3 = se->duration_phase_3; - e->lifelength = se->lifelength; - e->flags = se->flags; - e->preview_company_rank= se->preview_company_rank; - e->preview_wait = se->preview_wait; - e->company_avail = se->company_avail; - if (se->name != NULL) e->name = strdup(se->name); - } - - /* Get rid of temporary data */ - _temp_engine.clear(); -} - -static void Load_ENGS() -{ - /* Load old separate String ID list into a temporary array. This - * was always 256 entries. */ - StringID names[256]; - - SlArray(names, lengthof(names), SLE_STRINGID); - - /* Copy each string into the temporary engine array. */ - for (EngineID engine = 0; engine < lengthof(names); engine++) { - Engine *e = GetTempDataEngine(engine); - e->name = CopyFromOldName(names[engine]); - } -} - -extern const ChunkHandler _engine_chunk_handlers[] = { - { 'ENGN', Save_ENGN, Load_ENGN, CH_ARRAY }, - { 'ENGS', NULL, Load_ENGS, CH_RIFF | CH_LAST }, -}; diff --git a/src/gamelog.cpp b/src/gamelog.cpp index b57f7a47a..a9d9d4bd4 100644 --- a/src/gamelog.cpp +++ b/src/gamelog.cpp @@ -4,7 +4,7 @@ #include "stdafx.h" #include "openttd.h" -#include "saveload.h" +#include "saveload/saveload.h" #include "core/alloc_func.hpp" #include "core/bitmath_func.hpp" #include "core/math_func.hpp" @@ -13,13 +13,15 @@ #include "string_func.h" #include "settings_type.h" #include "newgrf_config.h" -#include <string.h> -#include <stdarg.h> #include "gamelog.h" +#include "gamelog_internal.h" #include "console_func.h" #include "debug.h" #include "rev.h" +#include <string.h> +#include <stdarg.h> + extern const uint16 SAVEGAME_VERSION; ///< current savegame version extern SavegameType _savegame_type; ///< type of savegame we are loading @@ -28,79 +30,11 @@ extern uint32 _ttdp_version; ///< version of TTDP savegame (if applicable) extern uint16 _sl_version; ///< the major savegame version identifier extern byte _sl_minor_version; ///< the minor savegame version, DO NOT USE! -/** Type of logged change */ -enum GamelogChangeType { - GLCT_MODE, ///< Scenario editor x Game, different landscape - GLCT_REVISION, ///< Changed game revision string - GLCT_OLDVER, ///< Loaded from savegame without logged data - GLCT_PATCH, ///< Non-networksafe patch value changed - GLCT_GRFADD, ///< Removed GRF - GLCT_GRFREM, ///< Added GRF - GLCT_GRFCOMPAT, ///< Loading compatible GRF - GLCT_GRFPARAM, ///< GRF parameter changed - GLCT_GRFMOVE, ///< GRF order changed - GLCT_GRFBUG, ///< GRF bug triggered - GLCT_END, ///< So we know how many GLCTs are there - GLCT_NONE = 0xFF, ///< In savegames, end of list -}; - - -/** Contains information about one logged change */ -struct LoggedChange { - GamelogChangeType ct; ///< Type of change logged in this struct - union { - struct { - byte mode; ///< new game mode - Editor x Game - byte landscape; ///< landscape (temperate, arctic, ...) - } mode; - struct { - char text[NETWORK_REVISION_LENGTH]; ///< revision string, _openttd_revision - uint32 newgrf; ///< _openttd_newgrf_version - uint16 slver; ///< _sl_version - byte modified; ///< _openttd_revision_modified - } revision; - struct { - uint32 type; ///< type of savegame, @see SavegameType - uint32 version; ///< major and minor version OR ttdp version - } oldver; - GRFIdentifier grfadd; ///< ID and md5sum of added GRF - struct { - uint32 grfid; ///< ID of removed GRF - } grfrem; - GRFIdentifier grfcompat; ///< ID and new md5sum of changed GRF - struct { - uint32 grfid; ///< ID of GRF with changed parameters - } grfparam; - struct { - uint32 grfid; ///< ID of moved GRF - int32 offset; ///< offset, positive = move down - } grfmove; - struct { - char *name; ///< name of the patch - int32 oldval; ///< old value - int32 newval; ///< new value - } patch; - struct { - uint64 data; ///< additional data - uint32 grfid; ///< ID of problematic GRF - byte bug; ///< type of bug, @see enum GRFBugs - } grfbug; - }; -}; - - -/** Contains information about one logged action that caused at least one logged change */ -struct LoggedAction { - LoggedChange *change; ///< First logged change in this action - uint32 changes; ///< Number of changes in this action - GamelogActionType at; ///< Type of action - uint16 tick; ///< Tick when it happened -}; static GamelogActionType _gamelog_action_type = GLAT_NONE; ///< action to record if anything changes -static LoggedAction *_gamelog_action = NULL; ///< first logged action -static uint _gamelog_actions = 0; ///< number of actions +LoggedAction *_gamelog_action = NULL; ///< first logged action +uint _gamelog_actions = 0; ///< number of actions static LoggedAction *_current_action = NULL; ///< current action we are logging, NULL when there is no action active @@ -728,155 +662,3 @@ void GamelogGRFUpdate(const GRFConfig *oldc, const GRFConfig *newc) free(ol); free(nl); } - - -static const SaveLoad _glog_action_desc[] = { - SLE_VAR(LoggedAction, tick, SLE_UINT16), - SLE_END() -}; - -static const SaveLoad _glog_mode_desc[] = { - SLE_VAR(LoggedChange, mode.mode, SLE_UINT8), - SLE_VAR(LoggedChange, mode.landscape, SLE_UINT8), - SLE_END() -}; - -static const SaveLoad _glog_revision_desc[] = { - SLE_ARR(LoggedChange, revision.text, SLE_UINT8, NETWORK_REVISION_LENGTH), - SLE_VAR(LoggedChange, revision.newgrf, SLE_UINT32), - SLE_VAR(LoggedChange, revision.slver, SLE_UINT16), - SLE_VAR(LoggedChange, revision.modified, SLE_UINT8), - SLE_END() -}; - -static const SaveLoad _glog_oldver_desc[] = { - SLE_VAR(LoggedChange, oldver.type, SLE_UINT32), - SLE_VAR(LoggedChange, oldver.version, SLE_UINT32), - SLE_END() -}; - -static const SaveLoad _glog_patch_desc[] = { - SLE_STR(LoggedChange, patch.name, SLE_STR, 128), - SLE_VAR(LoggedChange, patch.oldval, SLE_INT32), - SLE_VAR(LoggedChange, patch.newval, SLE_INT32), - SLE_END() -}; - -static const SaveLoad _glog_grfadd_desc[] = { - SLE_VAR(LoggedChange, grfadd.grfid, SLE_UINT32 ), - SLE_ARR(LoggedChange, grfadd.md5sum, SLE_UINT8, 16), - SLE_END() -}; - -static const SaveLoad _glog_grfrem_desc[] = { - SLE_VAR(LoggedChange, grfrem.grfid, SLE_UINT32), - SLE_END() -}; - -static const SaveLoad _glog_grfcompat_desc[] = { - SLE_VAR(LoggedChange, grfcompat.grfid, SLE_UINT32 ), - SLE_ARR(LoggedChange, grfcompat.md5sum, SLE_UINT8, 16), - SLE_END() -}; - -static const SaveLoad _glog_grfparam_desc[] = { - SLE_VAR(LoggedChange, grfparam.grfid, SLE_UINT32), - SLE_END() -}; - -static const SaveLoad _glog_grfmove_desc[] = { - SLE_VAR(LoggedChange, grfmove.grfid, SLE_UINT32), - SLE_VAR(LoggedChange, grfmove.offset, SLE_INT32), - SLE_END() -}; - -static const SaveLoad _glog_grfbug_desc[] = { - SLE_VAR(LoggedChange, grfbug.data, SLE_UINT64), - SLE_VAR(LoggedChange, grfbug.grfid, SLE_UINT32), - SLE_VAR(LoggedChange, grfbug.bug, SLE_UINT8), - SLE_END() -}; - -static const SaveLoad *_glog_desc[] = { - _glog_mode_desc, - _glog_revision_desc, - _glog_oldver_desc, - _glog_patch_desc, - _glog_grfadd_desc, - _glog_grfrem_desc, - _glog_grfcompat_desc, - _glog_grfparam_desc, - _glog_grfmove_desc, - _glog_grfbug_desc, -}; - -assert_compile(lengthof(_glog_desc) == GLCT_END); - -static void Load_GLOG() -{ - assert(_gamelog_action == NULL); - assert(_gamelog_actions == 0); - - GamelogActionType at; - while ((at = (GamelogActionType)SlReadByte()) != GLAT_NONE) { - _gamelog_action = ReallocT(_gamelog_action, _gamelog_actions + 1); - LoggedAction *la = &_gamelog_action[_gamelog_actions++]; - - la->at = at; - - SlObject(la, _glog_action_desc); // has to be saved after 'DATE'! - la->change = NULL; - la->changes = 0; - - GamelogChangeType ct; - while ((ct = (GamelogChangeType)SlReadByte()) != GLCT_NONE) { - la->change = ReallocT(la->change, la->changes + 1); - - LoggedChange *lc = &la->change[la->changes++]; - /* for SLE_STR, pointer has to be valid! so make it NULL */ - memset(lc, 0, sizeof(*lc)); - lc->ct = ct; - - assert((uint)ct < GLCT_END); - - SlObject(lc, _glog_desc[ct]); - } - } -} - -static void Save_GLOG() -{ - const LoggedAction *laend = &_gamelog_action[_gamelog_actions]; - size_t length = 0; - - for (const LoggedAction *la = _gamelog_action; la != laend; la++) { - const LoggedChange *lcend = &la->change[la->changes]; - for (LoggedChange *lc = la->change; lc != lcend; lc++) { - assert((uint)lc->ct < lengthof(_glog_desc)); - length += SlCalcObjLength(lc, _glog_desc[lc->ct]) + 1; - } - length += 4; - } - length++; - - SlSetLength(length); - - for (LoggedAction *la = _gamelog_action; la != laend; la++) { - SlWriteByte(la->at); - SlObject(la, _glog_action_desc); - - const LoggedChange *lcend = &la->change[la->changes]; - for (LoggedChange *lc = la->change; lc != lcend; lc++) { - SlWriteByte(lc->ct); - assert((uint)lc->ct < GLCT_END); - SlObject(lc, _glog_desc[lc->ct]); - } - SlWriteByte(GLCT_NONE); - } - SlWriteByte(GLAT_NONE); -} - - -extern const ChunkHandler _gamelog_chunk_handlers[] = { - { 'GLOG', Save_GLOG, Load_GLOG, CH_RIFF | CH_LAST } -}; diff --git a/src/gamelog_internal.h b/src/gamelog_internal.h new file mode 100644 index 000000000..db5affd03 --- /dev/null +++ b/src/gamelog_internal.h @@ -0,0 +1,82 @@ +/* $Id$ */ + +/** @file gamelog_internal.h Declaration shared among gamelog.cpp and saveload/gamelog_sl.cpp */ + +#ifndef GAMELOG_INTERNAL_H +#define GAMELOG_INTERNAL_H + +#include "network/core/config.h" + +/** Type of logged change */ +enum GamelogChangeType { + GLCT_MODE, ///< Scenario editor x Game, different landscape + GLCT_REVISION, ///< Changed game revision string + GLCT_OLDVER, ///< Loaded from savegame without logged data + GLCT_PATCH, ///< Non-networksafe patch value changed + GLCT_GRFADD, ///< Removed GRF + GLCT_GRFREM, ///< Added GRF + GLCT_GRFCOMPAT, ///< Loading compatible GRF + GLCT_GRFPARAM, ///< GRF parameter changed + GLCT_GRFMOVE, ///< GRF order changed + GLCT_GRFBUG, ///< GRF bug triggered + GLCT_END, ///< So we know how many GLCTs are there + GLCT_NONE = 0xFF, ///< In savegames, end of list +}; + + +/** Contains information about one logged change */ +struct LoggedChange { + GamelogChangeType ct; ///< Type of change logged in this struct + union { + struct { + byte mode; ///< new game mode - Editor x Game + byte landscape; ///< landscape (temperate, arctic, ...) + } mode; + struct { + char text[NETWORK_REVISION_LENGTH]; ///< revision string, _openttd_revision + uint32 newgrf; ///< _openttd_newgrf_version + uint16 slver; ///< _sl_version + byte modified; ///< _openttd_revision_modified + } revision; + struct { + uint32 type; ///< type of savegame, @see SavegameType + uint32 version; ///< major and minor version OR ttdp version + } oldver; + GRFIdentifier grfadd; ///< ID and md5sum of added GRF + struct { + uint32 grfid; ///< ID of removed GRF + } grfrem; + GRFIdentifier grfcompat; ///< ID and new md5sum of changed GRF + struct { + uint32 grfid; ///< ID of GRF with changed parameters + } grfparam; + struct { + uint32 grfid; ///< ID of moved GRF + int32 offset; ///< offset, positive = move down + } grfmove; + struct { + char *name; ///< name of the patch + int32 oldval; ///< old value + int32 newval; ///< new value + } patch; + struct { + uint64 data; ///< additional data + uint32 grfid; ///< ID of problematic GRF + byte bug; ///< type of bug, @see enum GRFBugs + } grfbug; + }; +}; + + +/** Contains information about one logged action that caused at least one logged change */ +struct LoggedAction { + LoggedChange *change; ///< First logged change in this action + uint32 changes; ///< Number of changes in this action + GamelogActionType at; ///< Type of action + uint16 tick; ///< Tick when it happened +}; + +extern LoggedAction *_gamelog_action; +extern uint _gamelog_actions; + +#endif /* GAMELOG_INTERNAL_H */ diff --git a/src/genworld.cpp b/src/genworld.cpp index 23a978272..ef6c87151 100644 --- a/src/genworld.cpp +++ b/src/genworld.cpp @@ -26,7 +26,7 @@ #include "newgrf_storage.h" #include "water.h" #include "tilehighlight_func.h" -#include "saveload.h" +#include "saveload/saveload.h" #include "table/sprites.h" diff --git a/src/group_cmd.cpp b/src/group_cmd.cpp index 3a80c3d49..44e3b6bb3 100644 --- a/src/group_cmd.cpp +++ b/src/group_cmd.cpp @@ -6,7 +6,6 @@ #include "openttd.h" #include "variables.h" #include "command_func.h" -#include "saveload.h" #include "debug.h" #include "group.h" #include "train.h" @@ -421,40 +420,3 @@ void RemoveAllGroupsForCompany(const CompanyID company) if (company == g->owner) delete g; } } - - -static const SaveLoad _group_desc[] = { - SLE_CONDVAR(Group, name, SLE_NAME, 0, 83), - SLE_CONDSTR(Group, name, SLE_STR, 0, 84, SL_MAX_VERSION), - SLE_VAR(Group, num_vehicle, SLE_UINT16), - SLE_VAR(Group, owner, SLE_UINT8), - SLE_VAR(Group, vehicle_type, SLE_UINT8), - SLE_VAR(Group, replace_protection, SLE_BOOL), - SLE_END() -}; - - -static void Save_GROUP(void) -{ - Group *g; - - FOR_ALL_GROUPS(g) { - SlSetArrayIndex(g->index); - SlObject(g, _group_desc); - } -} - - -static void Load_GROUP(void) -{ - int index; - - while ((index = SlIterateArray()) != -1) { - Group *g = new (index) Group(); - SlObject(g, _group_desc); - } -} - -extern const ChunkHandler _group_chunk_handlers[] = { - { 'GRPS', Save_GROUP, Load_GROUP, CH_ARRAY | CH_LAST}, -}; diff --git a/src/heightmap.cpp b/src/heightmap.cpp index 1add9853c..2ca58b14c 100644 --- a/src/heightmap.cpp +++ b/src/heightmap.cpp @@ -10,7 +10,7 @@ #include "void_map.h" #include "debug.h" #include "gui.h" -#include "saveload.h" +#include "saveload/saveload.h" #include "bmp.h" #include "gfx_func.h" #include "core/alloc_func.hpp" diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index e9e4e68d4..3c9262458 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -14,7 +14,6 @@ #include "industry.h" #include "town.h" #include "news_func.h" -#include "saveload.h" #include "variables.h" #include "cheat_func.h" #include "genworld.h" @@ -2397,146 +2396,3 @@ extern const TileTypeProcs _tile_type_industry_procs = { GetFoundation_Industry, /* get_foundation_proc */ TerraformTile_Industry, /* terraform_tile_proc */ }; - -static const SaveLoad _industry_desc[] = { - SLE_CONDVAR(Industry, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Industry, xy, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_VAR(Industry, width, SLE_UINT8), - SLE_VAR(Industry, height, SLE_UINT8), - SLE_REF(Industry, town, REF_TOWN), - SLE_CONDNULL( 2, 0, 60), ///< used to be industry's produced_cargo - SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 2, 78, SL_MAX_VERSION), - SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 3, 70, SL_MAX_VERSION), - SLE_ARR(Industry, produced_cargo_waiting, SLE_UINT16, 2), - SLE_ARR(Industry, production_rate, SLE_UINT8, 2), - SLE_CONDNULL( 3, 0, 60), ///< used to be industry's accepts_cargo - SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 3, 78, SL_MAX_VERSION), - SLE_VAR(Industry, prod_level, SLE_UINT8), - SLE_ARR(Industry, this_month_production, SLE_UINT16, 2), - SLE_ARR(Industry, this_month_transported, SLE_UINT16, 2), - SLE_ARR(Industry, last_month_pct_transported, SLE_UINT8, 2), - SLE_ARR(Industry, last_month_production, SLE_UINT16, 2), - SLE_ARR(Industry, last_month_transported, SLE_UINT16, 2), - - SLE_VAR(Industry, counter, SLE_UINT16), - - SLE_VAR(Industry, type, SLE_UINT8), - SLE_VAR(Industry, owner, SLE_UINT8), - SLE_VAR(Industry, random_color, SLE_UINT8), - SLE_CONDVAR(Industry, last_prod_year, SLE_FILE_U8 | SLE_VAR_I32, 0, 30), - SLE_CONDVAR(Industry, last_prod_year, SLE_INT32, 31, SL_MAX_VERSION), - SLE_VAR(Industry, was_cargo_delivered, SLE_UINT8), - - SLE_CONDVAR(Industry, founder, SLE_UINT8, 70, SL_MAX_VERSION), - SLE_CONDVAR(Industry, construction_date, SLE_INT32, 70, SL_MAX_VERSION), - SLE_CONDVAR(Industry, construction_type, SLE_UINT8, 70, SL_MAX_VERSION), - SLE_CONDVAR(Industry, last_cargo_accepted_at, SLE_INT32, 70, SL_MAX_VERSION), - SLE_CONDVAR(Industry, selected_layout, SLE_UINT8, 73, SL_MAX_VERSION), - - SLE_CONDARRX(cpp_offsetof(Industry, psa) + cpp_offsetof(Industry::PersistentStorage, storage), SLE_UINT32, 16, 76, SL_MAX_VERSION), - - SLE_CONDVAR(Industry, random_triggers, SLE_UINT8, 82, SL_MAX_VERSION), - SLE_CONDVAR(Industry, random, SLE_UINT16, 82, SL_MAX_VERSION), - - /* reserve extra space in savegame here. (currently 32 bytes) */ - SLE_CONDNULL(32, 2, SL_MAX_VERSION), - - SLE_END() -}; - -static void Save_INDY() -{ - Industry *ind; - - /* Write the industries */ - FOR_ALL_INDUSTRIES(ind) { - SlSetArrayIndex(ind->index); - SlObject(ind, _industry_desc); - } -} - -/* Save and load the mapping between the industry/tile id on the map, and the grf file - * it came from. */ -static const SaveLoad _industries_id_mapping_desc[] = { - SLE_VAR(EntityIDMapping, grfid, SLE_UINT32), - SLE_VAR(EntityIDMapping, entity_id, SLE_UINT8), - SLE_VAR(EntityIDMapping, substitute_id, SLE_UINT8), - SLE_END() -}; - -static void Save_IIDS() -{ - uint i; - uint j = _industry_mngr.GetMaxMapping(); - - for (i = 0; i < j; i++) { - SlSetArrayIndex(i); - SlObject(&_industry_mngr.mapping_ID[i], _industries_id_mapping_desc); - } -} - -static void Save_TIDS() -{ - uint i; - uint j = _industile_mngr.GetMaxMapping(); - - for (i = 0; i < j; i++) { - SlSetArrayIndex(i); - SlObject(&_industile_mngr.mapping_ID[i], _industries_id_mapping_desc); - } -} - -static void Load_INDY() -{ - int index; - - ResetIndustryCounts(); - - while ((index = SlIterateArray()) != -1) { - Industry *i = new (index) Industry(); - SlObject(i, _industry_desc); - IncIndustryTypeCount(i->type); - } -} - -static void Load_IIDS() -{ - int index; - uint max_id; - - /* clear the current mapping stored. - * This will create the manager if ever it is not yet done */ - _industry_mngr.ResetMapping(); - - /* get boundary for the temporary map loader NUM_INDUSTRYTYPES? */ - max_id = _industry_mngr.GetMaxMapping(); - - while ((index = SlIterateArray()) != -1) { - if ((uint)index >= max_id) break; - SlObject(&_industry_mngr.mapping_ID[index], _industries_id_mapping_desc); - } -} - -static void Load_TIDS() -{ - int index; - uint max_id; - - /* clear the current mapping stored. - * This will create the manager if ever it is not yet done */ - _industile_mngr.ResetMapping(); - - /* get boundary for the temporary map loader NUM_INDUSTILES? */ - max_id = _industile_mngr.GetMaxMapping(); - - while ((index = SlIterateArray()) != -1) { - if ((uint)index >= max_id) break; - SlObject(&_industile_mngr.mapping_ID[index], _industries_id_mapping_desc); - } -} - -extern const ChunkHandler _industry_chunk_handlers[] = { - { 'INDY', Save_INDY, Load_INDY, CH_ARRAY}, - { 'IIDS', Save_IIDS, Load_IIDS, CH_ARRAY}, - { 'TIDS', Save_TIDS, Load_TIDS, CH_ARRAY | CH_LAST}, -}; diff --git a/src/misc.cpp b/src/misc.cpp index 3d51bf2b2..bccaf2c62 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -7,7 +7,6 @@ #include "currency.h" #include "landscape.h" #include "news_func.h" -#include "saveload.h" #include "vehicle_gui.h" #include "variables.h" #include "cheat_func.h" @@ -134,290 +133,3 @@ void InitializeLandscapeVariables(bool only_constants) _cargo_payment_rates_frac[i] = 0; } } - -static const SaveLoadGlobVarList _date_desc[] = { - SLEG_CONDVAR(_date, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), - SLEG_CONDVAR(_date, SLE_INT32, 31, SL_MAX_VERSION), - SLEG_VAR(_date_fract, SLE_UINT16), - SLEG_VAR(_tick_counter, SLE_UINT16), - SLEG_VAR(_vehicle_id_ctr_day, SLE_UINT16), - SLEG_VAR(_age_cargo_skip_counter, SLE_UINT8), - SLE_CONDNULL(1, 0, 45), - SLEG_CONDVAR(_cur_tileloop_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLEG_CONDVAR(_cur_tileloop_tile, SLE_UINT32, 6, SL_MAX_VERSION), - SLEG_VAR(_disaster_delay, SLE_UINT16), - SLEG_VAR(_station_tick_ctr, SLE_UINT16), - SLEG_VAR(_random.state[0], SLE_UINT32), - SLEG_VAR(_random.state[1], SLE_UINT32), - SLEG_CONDVAR(_cur_town_ctr, SLE_FILE_U8 | SLE_VAR_U32, 0, 9), - SLEG_CONDVAR(_cur_town_ctr, SLE_UINT32, 10, SL_MAX_VERSION), - SLEG_VAR(_cur_company_tick_index, SLE_FILE_U8 | SLE_VAR_U32), - SLEG_VAR(_next_competitor_start, SLE_FILE_U16 | SLE_VAR_U32), - SLEG_VAR(_trees_tick_ctr, SLE_UINT8), - SLEG_CONDVAR(_pause_game, SLE_UINT8, 4, SL_MAX_VERSION), - SLEG_CONDVAR(_cur_town_iter, SLE_UINT32, 11, SL_MAX_VERSION), - SLEG_END() -}; - -/* Save load date related variables as well as persistent tick counters - * XXX: currently some unrelated stuff is just put here */ -static void SaveLoad_DATE() -{ - SlGlobList(_date_desc); -} - - -static const SaveLoadGlobVarList _view_desc[] = { - SLEG_CONDVAR(_saved_scrollpos_x, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), - SLEG_CONDVAR(_saved_scrollpos_x, SLE_INT32, 6, SL_MAX_VERSION), - SLEG_CONDVAR(_saved_scrollpos_y, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), - SLEG_CONDVAR(_saved_scrollpos_y, SLE_INT32, 6, SL_MAX_VERSION), - SLEG_VAR(_saved_scrollpos_zoom, SLE_UINT8), - SLEG_END() -}; - -static void SaveLoad_VIEW() -{ - SlGlobList(_view_desc); -} - -static uint32 _map_dim_x; -static uint32 _map_dim_y; - -static const SaveLoadGlobVarList _map_dimensions[] = { - SLEG_CONDVAR(_map_dim_x, SLE_UINT32, 6, SL_MAX_VERSION), - SLEG_CONDVAR(_map_dim_y, SLE_UINT32, 6, SL_MAX_VERSION), - SLEG_END() -}; - -static void Save_MAPS() -{ - _map_dim_x = MapSizeX(); - _map_dim_y = MapSizeY(); - SlGlobList(_map_dimensions); -} - -static void Load_MAPS() -{ - SlGlobList(_map_dimensions); - AllocateMap(_map_dim_x, _map_dim_y); -} - -enum { - MAP_SL_BUF_SIZE = 4096 -}; - -static void Load_MAPT() -{ - SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].type_height = buf[j]; - } -} - -static void Save_MAPT() -{ - SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - SlSetLength(size); - for (TileIndex i = 0; i != size;) { - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].type_height; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); - } -} - -static void Load_MAP1() -{ - SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m1 = buf[j]; - } -} - -static void Save_MAP1() -{ - SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - SlSetLength(size); - for (TileIndex i = 0; i != size;) { - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m1; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); - } -} - -static void Load_MAP2() -{ - SmallStackSafeStackAlloc<uint16, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, - /* In those versions the m2 was 8 bits */ - CheckSavegameVersion(5) ? SLE_FILE_U8 | SLE_VAR_U16 : SLE_UINT16 - ); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m2 = buf[j]; - } -} - -static void Save_MAP2() -{ - SmallStackSafeStackAlloc<uint16, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - SlSetLength(size * sizeof(uint16)); - for (TileIndex i = 0; i != size;) { - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m2; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT16); - } -} - -static void Load_MAP3() -{ - SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m3 = buf[j]; - } -} - -static void Save_MAP3() -{ - SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - SlSetLength(size); - for (TileIndex i = 0; i != size;) { - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m3; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); - } -} - -static void Load_MAP4() -{ - SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m4 = buf[j]; - } -} - -static void Save_MAP4() -{ - SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - SlSetLength(size); - for (TileIndex i = 0; i != size;) { - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m4; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); - } -} - -static void Load_MAP5() -{ - SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m5 = buf[j]; - } -} - -static void Save_MAP5() -{ - SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - SlSetLength(size); - for (TileIndex i = 0; i != size;) { - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m5; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); - } -} - -static void Load_MAP6() -{ - SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - if (CheckSavegameVersion(42)) { - for (TileIndex i = 0; i != size;) { - /* 1024, otherwise we overflow on 64x64 maps! */ - SlArray(buf, 1024, SLE_UINT8); - for (uint j = 0; j != 1024; j++) { - _m[i++].m6 = GB(buf[j], 0, 2); - _m[i++].m6 = GB(buf[j], 2, 2); - _m[i++].m6 = GB(buf[j], 4, 2); - _m[i++].m6 = GB(buf[j], 6, 2); - } - } - } else { - for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m6 = buf[j]; - } - } -} - -static void Save_MAP6() -{ - SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - SlSetLength(size); - for (TileIndex i = 0; i != size;) { - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m6; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); - } -} - -static void Load_MAP7() -{ - SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m7 = buf[j]; - } -} - -static void Save_MAP7() -{ - SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; - TileIndex size = MapSize(); - - SlSetLength(size); - for (TileIndex i = 0; i != size;) { - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m7; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); - } -} - -extern const ChunkHandler _misc_chunk_handlers[] = { - { 'MAPS', Save_MAPS, Load_MAPS, CH_RIFF }, - { 'MAPT', Save_MAPT, Load_MAPT, CH_RIFF }, - { 'MAPO', Save_MAP1, Load_MAP1, CH_RIFF }, - { 'MAP2', Save_MAP2, Load_MAP2, CH_RIFF }, - { 'M3LO', Save_MAP3, Load_MAP3, CH_RIFF }, - { 'M3HI', Save_MAP4, Load_MAP4, CH_RIFF }, - { 'MAP5', Save_MAP5, Load_MAP5, CH_RIFF }, - { 'MAPE', Save_MAP6, Load_MAP6, CH_RIFF }, - { 'MAP7', Save_MAP7, Load_MAP7, CH_RIFF }, - - { 'DATE', SaveLoad_DATE, SaveLoad_DATE, CH_RIFF}, - { 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, CH_RIFF | CH_LAST}, -}; diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index bd27e065b..b0dd24d00 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -9,7 +9,7 @@ #include "landscape.h" #include "newgrf.h" #include "newgrf_text.h" -#include "saveload.h" +#include "saveload/saveload.h" #include "tile_map.h" #include "gui.h" #include "window_gui.h" diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 145d61dd6..2d7256beb 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -12,7 +12,7 @@ #include "network_client.h" #include "network_gamelist.h" #include "network_gui.h" -#include "../saveload.h" +#include "../saveload/saveload.h" #include "../command_func.h" #include "../console_func.h" #include "../variables.h" diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 5f5d5692c..2fc06f4a1 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -17,7 +17,7 @@ #include "network_udp.h" #include "../console_func.h" #include "../command_func.h" -#include "../saveload.h" +#include "../saveload/saveload.h" #include "../station_base.h" #include "../variables.h" #include "../genworld.h" diff --git a/src/newgrf.h b/src/newgrf.h index 253d8f334..83690e003 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -121,7 +121,7 @@ extern GRFLoadedFeatures _loaded_newgrf_features; void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage); void LoadNewGRF(uint load_index, uint file_index); -void ReloadNewGRFData(); // in openttd.cpp +void ReloadNewGRFData(); // in saveload/afterload.cpp void CDECL grfmsg(int severity, const char *str, ...); diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp index 389aeb408..b579e5e98 100644 --- a/src/newgrf_config.cpp +++ b/src/newgrf_config.cpp @@ -6,7 +6,6 @@ #include "openttd.h" #include "debug.h" #include "variables.h" -#include "saveload.h" #include "md5.h" #include "newgrf.h" #include "newgrf_config.h" @@ -495,48 +494,3 @@ bool GRFConfig::IsOpenTTDBaseGRF() const { return (this->grfid & 0x00FFFFFF) == OPENTTD_GRAPHICS_BASE_GRF_ID; } - - -static const SaveLoad _grfconfig_desc[] = { - SLE_STR(GRFConfig, filename, SLE_STR, 0x40), - SLE_VAR(GRFConfig, grfid, SLE_UINT32), - SLE_ARR(GRFConfig, md5sum, SLE_UINT8, 16), - SLE_ARR(GRFConfig, param, SLE_UINT32, 0x80), - SLE_VAR(GRFConfig, num_params, SLE_UINT8), - SLE_CONDVAR(GRFConfig, windows_paletted, SLE_BOOL, 101, SL_MAX_VERSION), - SLE_END() -}; - - -static void Save_NGRF() -{ - int index = 0; - - for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { - if (HasBit(c->flags, GCF_STATIC)) continue; - SlSetArrayIndex(index++); - SlObject(c, _grfconfig_desc); - } -} - - -static void Load_NGRF() -{ - ClearGRFConfigList(&_grfconfig); - while (SlIterateArray() != -1) { - GRFConfig *c = CallocT<GRFConfig>(1); - SlObject(c, _grfconfig_desc); - if (CheckSavegameVersion(101)) c->windows_paletted = (_use_palette == PAL_WINDOWS); - AppendToGRFConfigList(&_grfconfig, c); - } - - /* Append static NewGRF configuration */ - AppendStaticGRFConfigs(&_grfconfig); -} - -extern const ChunkHandler _newgrf_chunk_handlers[] = { - { 'NGRF', Save_NGRF, Load_NGRF, CH_ARRAY | CH_LAST } -}; - - - diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp index ce7558f97..c02e0e42b 100644 --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -34,53 +34,6 @@ static HouseClassMapping _class_mapping[HOUSE_CLASS_MAX]; HouseOverrideManager _house_mngr(NEW_HOUSE_OFFSET, HOUSE_MAX, INVALID_HOUSE_ID); -/** - * Check and update town and house values. - * - * Checked are the HouseIDs. Updated are the - * town population the number of houses per - * town, the town radius and the max passengers - * of the town. - */ -void UpdateHousesAndTowns() -{ - Town *town; - InitializeBuildingCounts(); - - /* Reset town population and num_houses */ - FOR_ALL_TOWNS(town) { - town->population = 0; - town->num_houses = 0; - } - - for (TileIndex t = 0; t < MapSize(); t++) { - HouseID house_id; - - if (!IsTileType(t, MP_HOUSE)) continue; - - house_id = GetHouseType(t); - if (!GetHouseSpecs(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) { - /* The specs for this type of house are not available any more, so - * replace it with the substitute original house type. */ - house_id = _house_mngr.GetSubstituteID(house_id); - SetHouseType(t, house_id); - } - - town = GetTownByTile(t); - IncreaseBuildingCount(town, house_id); - if (IsHouseCompleted(t)) town->population += GetHouseSpecs(house_id)->population; - - /* Increase the number of houses for every house, but only once. */ - if (GetHouseNorthPart(house_id) == 0) town->num_houses++; - } - - /* Update the population and num_house dependant values */ - FOR_ALL_TOWNS(town) { - UpdateTownRadius(town); - UpdateTownMaxPass(town); - } -} - HouseClassID AllocateHouseClassID(byte grf_class_id, uint32 grfid) { /* Start from 1 because 0 means that no class has been assigned. */ diff --git a/src/newgrf_house.h b/src/newgrf_house.h index 9a6f32d01..ce08e1213 100644 --- a/src/newgrf_house.h +++ b/src/newgrf_house.h @@ -7,6 +7,7 @@ #include "town_type.h" #include "newgrf_callbacks.h" +#include "tile_cmd.h" /** * Makes class IDs unique to each GRF file. @@ -26,8 +27,6 @@ struct HouseClassMapping { uint8 class_id; ////< The class id within the grf file }; -void UpdateHousesAndTowns(); - HouseClassID AllocateHouseClassID(byte grf_class_id, uint32 grfid); void InitializeBuildingCounts(); diff --git a/src/newgrf_station.h b/src/newgrf_station.h index 5d42cde72..13844268b 100644 --- a/src/newgrf_station.h +++ b/src/newgrf_station.h @@ -13,6 +13,7 @@ #include "strings_type.h" #include "sprite.h" #include "direction_type.h" +#include "newgrf.h" enum StationClassID { STAT_CLASS_BEGIN = 0, ///< the lowest valid value diff --git a/src/openttd.cpp b/src/openttd.cpp index 613d63151..fd478955d 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -25,7 +25,7 @@ #include "window_func.h" #include "debug.h" -#include "saveload.h" +#include "saveload/saveload.h" #include "landscape.h" #include "company_func.h" #include "company_base.h" @@ -96,7 +96,6 @@ void IncreaseDate(); void DoPaletteAnimations(); void MusicLoop(); void ResetMusic(); -void ResetOldNames(); void ProcessAsyncSaveFinish(); void CallWindowTickEvent(); @@ -1182,1566 +1181,3 @@ void GameLoop() _sound_driver->MainLoop(); MusicLoop(); } - -static void ConvertTownOwner() -{ - for (TileIndex tile = 0; tile != MapSize(); tile++) { - switch (GetTileType(tile)) { - case MP_ROAD: - if (GB(_m[tile].m5, 4, 2) == ROAD_TILE_CROSSING && HasBit(_m[tile].m3, 7)) { - _m[tile].m3 = OWNER_TOWN; - } - /* FALLTHROUGH */ - - case MP_TUNNELBRIDGE: - if (GetTileOwner(tile) & 0x80) SetTileOwner(tile, OWNER_TOWN); - break; - - default: break; - } - } -} - -/* since savegame version 4.1, exclusive transport rights are stored at towns */ -static void UpdateExclusiveRights() -{ - Town *t; - - FOR_ALL_TOWNS(t) { - t->exclusivity = INVALID_COMPANY; - } - - /* FIXME old exclusive rights status is not being imported (stored in s->blocked_months_obsolete) - * could be implemented this way: - * 1.) Go through all stations - * Build an array town_blocked[ town_id ][ company_id ] - * that stores if at least one station in that town is blocked for a company - * 2.) Go through that array, if you find a town that is not blocked for - * one company, but for all others, then give him exclusivity. - */ -} - -static const byte convert_currency[] = { - 0, 1, 12, 8, 3, - 10, 14, 19, 4, 5, - 9, 11, 13, 6, 17, - 16, 22, 21, 7, 15, - 18, 2, 20, }; - -/* since savegame version 4.2 the currencies are arranged differently */ -static void UpdateCurrencies() -{ - _settings_game.locale.currency = convert_currency[_settings_game.locale.currency]; -} - -/* Up to revision 1413 the invisible tiles at the southern border have not been - * MP_VOID, even though they should have. This is fixed by this function - */ -static void UpdateVoidTiles() -{ - uint i; - - for (i = 0; i < MapMaxY(); ++i) MakeVoid(i * MapSizeX() + MapMaxX()); - for (i = 0; i < MapSizeX(); ++i) MakeVoid(MapSizeX() * MapMaxY() + i); -} - -/* since savegame version 6.0 each sign has an "owner", signs without owner (from old games are set to 255) */ -static void UpdateSignOwner() -{ - Sign *si; - - FOR_ALL_SIGNS(si) si->owner = OWNER_NONE; -} - -extern void UpdateOldAircraft(); - - -static inline RailType UpdateRailType(RailType rt, RailType min) -{ - return rt >= min ? (RailType)(rt + 1): rt; -} - -/** - * Initialization of the windows and several kinds of caches. - * This is not done directly in AfterLoadGame because these - * functions require that all saveload conversions have been - * done. As people tend to add savegame conversion stuff after - * the intialization of the windows and caches quite some bugs - * had been made. - * Moving this out of there is both cleaner and less bug-prone. - * - * @return true if everything went according to plan, otherwise false. - */ -static bool InitializeWindowsAndCaches() -{ - /* Initialize windows */ - ResetWindowSystem(); - SetupColorsAndInitialWindow(); - - extern void ResetViewportAfterLoadGame(); - ResetViewportAfterLoadGame(); - - /* Update coordinates of the signs. */ - UpdateAllStationVirtCoord(); - UpdateAllSignVirtCoords(); - UpdateAllTownVirtCoords(); - UpdateAllWaypointSigns(); - - Company *c; - FOR_ALL_COMPANIES(c) { - /* For each company, verify (while loading a scenario) that the inauguration date is the current year and set it - * accordingly if it is not the case. No need to set it on companies that are not been used already, - * thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */ - if (_file_to_saveload.filetype == FT_SCENARIO && c->inaugurated_year != MIN_YEAR) { - c->inaugurated_year = _cur_year; - } - } - - SetCachedEngineCounts(); - - /* Towns have a noise controlled number of airports system - * So each airport's noise value must be added to the town->noise_reached value - * Reset each town's noise_reached value to '0' before. */ - UpdateAirportsNoise(); - - CheckTrainsLengths(); - - return true; -} - -/** - * Signal handler used to give a user a more useful report for crashes during - * the savegame loading process; especially when there's problems with the - * NewGRFs that are required by the savegame. - * @param unused well... unused - */ -void CDECL HandleSavegameLoadCrash(int unused) -{ - char buffer[8192]; - char *p = buffer; - p += seprintf(p, lastof(buffer), - "Loading your savegame caused OpenTTD to crash.\n" - "This is most likely caused by a missing NewGRF or a NewGRF that has been\n" - "loaded as replacement for a missing NewGRF. OpenTTD cannot easily\n" - "determine whether a replacement NewGRF is of a newer or older version.\n" - "It will load a NewGRF with the same GRF ID as the missing NewGRF. This\n" - "means that if the author makes incompatible NewGRFs with the same GRF ID\n" - "OpenTTD cannot magically do the right thing. In most cases OpenTTD will\n" - "load the savegame and not crash, but this is an exception.\n" - "Please load the savegame with the appropriate NewGRFs. When loading a\n" - "savegame still crashes when all NewGRFs are found you should file a\n" - "bug report. The missing NewGRFs are:\n"); - - for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { - if (HasBit(c->flags, GCF_COMPATIBLE)) { - char buf[40]; - md5sumToString(buf, lastof(buf), c->md5sum); - p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s. Tried another NewGRF with same GRF ID\n", BSWAP32(c->grfid), c->filename, buf); - } - if (c->status == GCS_NOT_FOUND) { - char buf[40]; - md5sumToString(buf, lastof(buf), c->md5sum); - p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s\n", BSWAP32(c->grfid), c->filename, buf); - } - } - - ShowInfo(buffer); -} - -bool AfterLoadGame() -{ - typedef void (CDECL *SignalHandlerPointer)(int); - SignalHandlerPointer prev_segfault = signal(SIGSEGV, HandleSavegameLoadCrash); - SignalHandlerPointer prev_abort = signal(SIGABRT, HandleSavegameLoadCrash); - - TileIndex map_size = MapSize(); - Company *c; - - if (CheckSavegameVersion(98)) GamelogOldver(); - - GamelogTestRevision(); - GamelogTestMode(); - - if (CheckSavegameVersion(98)) GamelogGRFAddList(_grfconfig); - - /* in very old versions, size of train stations was stored differently */ - if (CheckSavegameVersion(2)) { - Station *st; - FOR_ALL_STATIONS(st) { - if (st->train_tile != 0 && st->trainst_h == 0) { - extern SavegameType _savegame_type; - uint n = _savegame_type == SGT_OTTD ? 4 : 3; // OTTD uses 4 bits per dimensions, TTD 3 bits - uint w = GB(st->trainst_w, n, n); - uint h = GB(st->trainst_w, 0, n); - - if (GetRailStationAxis(st->train_tile) != AXIS_X) Swap(w, h); - - st->trainst_w = w; - st->trainst_h = h; - - assert(GetStationIndex(st->train_tile + TileDiffXY(w - 1, h - 1)) == st->index); - } - } - } - - /* in version 2.1 of the savegame, town owner was unified. */ - if (CheckSavegameVersionOldStyle(2, 1)) ConvertTownOwner(); - - /* from version 4.1 of the savegame, exclusive rights are stored at towns */ - if (CheckSavegameVersionOldStyle(4, 1)) UpdateExclusiveRights(); - - /* from version 4.2 of the savegame, currencies are in a different order */ - if (CheckSavegameVersionOldStyle(4, 2)) UpdateCurrencies(); - - /* from version 6.1 of the savegame, signs have an "owner" */ - if (CheckSavegameVersionOldStyle(6, 1)) UpdateSignOwner(); - - /* In old version there seems to be a problem that water is owned by - * OWNER_NONE, not OWNER_WATER.. I can't replicate it for the current - * (4.3) version, so I just check when versions are older, and then - * walk through the whole map.. */ - if (CheckSavegameVersionOldStyle(4, 3)) { - for (TileIndex t = 0; t < map_size; t++) { - if (IsTileType(t, MP_WATER) && GetTileOwner(t) >= MAX_COMPANIES) { - SetTileOwner(t, OWNER_WATER); - } - } - } - - if (CheckSavegameVersion(84)) { - FOR_ALL_COMPANIES(c) { - c->name = CopyFromOldName(c->name_1); - if (c->name != NULL) c->name_1 = STR_SV_UNNAMED; - c->president_name = CopyFromOldName(c->president_name_1); - if (c->president_name != NULL) c->president_name_1 = SPECSTR_PRESIDENT_NAME; - } - - Station *st; - FOR_ALL_STATIONS(st) { - st->name = CopyFromOldName(st->string_id); - /* generating new name would be too much work for little effect, use the station name fallback */ - if (st->name != NULL) st->string_id = STR_SV_STNAME_FALLBACK; - } - - Town *t; - FOR_ALL_TOWNS(t) { - t->name = CopyFromOldName(t->townnametype); - if (t->name != NULL) t->townnametype = SPECSTR_TOWNNAME_START + _settings_game.game_creation.town_name; - } - - Waypoint *wp; - FOR_ALL_WAYPOINTS(wp) { - wp->name = CopyFromOldName(wp->string); - wp->string = STR_EMPTY; - } - - for (uint i = 0; i < GetSignPoolSize(); i++) { - /* invalid signs are determined by si->ower == INVALID_COMPANY now */ - Sign *si = GetSign(i); - if (!si->IsValid() && si->name != NULL) { - si->owner = OWNER_NONE; - } - } - } - - /* From this point the old names array is cleared. */ - ResetOldNames(); - - if (CheckSavegameVersion(106)) { - /* no station is determined by 'tile == INVALID_TILE' now (instead of '0') */ - Station *st; - FOR_ALL_STATIONS(st) { - if (st->airport_tile == 0) st->airport_tile = INVALID_TILE; - if (st->dock_tile == 0) st->dock_tile = INVALID_TILE; - if (st->train_tile == 0) st->train_tile = INVALID_TILE; - } - - /* the same applies to Company::location_of_HQ */ - Company *c; - FOR_ALL_COMPANIES(c) { - if (c->location_of_HQ == 0 || (CheckSavegameVersion(4) && c->location_of_HQ == 0xFFFF)) { - c->location_of_HQ = INVALID_TILE; - } - } - } - - /* convert road side to my format. */ - if (_settings_game.vehicle.road_side) _settings_game.vehicle.road_side = 1; - - /* Check if all NewGRFs are present, we are very strict in MP mode */ - GRFListCompatibility gcf_res = IsGoodGRFConfigList(); - if (_networking && gcf_res != GLC_ALL_GOOD) { - SetSaveLoadError(STR_NETWORK_ERR_CLIENT_NEWGRF_MISMATCH); - /* Restore the signals */ - signal(SIGSEGV, prev_segfault); - signal(SIGABRT, prev_abort); - return false; - } - - switch (gcf_res) { - case GLC_COMPATIBLE: _switch_mode_errorstr = STR_NEWGRF_COMPATIBLE_LOAD_WARNING; break; - case GLC_NOT_FOUND: _switch_mode_errorstr = STR_NEWGRF_DISABLED_WARNING; _pause_game = -1; break; - default: break; - } - - /* Update current year - * must be done before loading sprites as some newgrfs check it */ - SetDate(_date); - - /* Force dynamic engines off when loading older savegames */ - if (CheckSavegameVersion(95)) _settings_game.vehicle.dynamic_engines = 0; - - /* Load the sprites */ - GfxLoadSprites(); - LoadStringWidthTable(); - - /* Copy temporary data to Engine pool */ - CopyTempEngineData(); - - /* Connect front and rear engines of multiheaded trains and converts - * subtype to the new format */ - if (CheckSavegameVersionOldStyle(17, 1)) ConvertOldMultiheadToNew(); - - /* Connect front and rear engines of multiheaded trains */ - ConnectMultiheadedTrains(); - - /* reinit the landscape variables (landscape might have changed) */ - InitializeLandscapeVariables(true); - - /* Update all vehicles */ - AfterLoadVehicles(true); - - /* Update all waypoints */ - if (CheckSavegameVersion(12)) FixOldWaypoints(); - - /* in version 2.2 of the savegame, we have new airports */ - if (CheckSavegameVersionOldStyle(2, 2)) UpdateOldAircraft(); - - AfterLoadTown(); - - /* make sure there is a town in the game */ - if (_game_mode == GM_NORMAL && !ClosestTownFromTile(0, UINT_MAX)) { - SetSaveLoadError(STR_NO_TOWN_IN_SCENARIO); - /* Restore the signals */ - signal(SIGSEGV, prev_segfault); - signal(SIGABRT, prev_abort); - return false; - } - - /* The void tiles on the southern border used to belong to a wrong class (pre 4.3). - * This problem appears in savegame version 21 too, see r3455. But after loading the - * savegame and saving again, the buggy map array could be converted to new savegame - * version. It didn't show up before r12070. */ - if (CheckSavegameVersion(87)) UpdateVoidTiles(); - - /* If Load Scenario / New (Scenario) Game is used, - * a company does not exist yet. So create one here. - * 1 exeption: network-games. Those can have 0 companies - * But this exeption is not true for non dedicated network_servers! */ - if (!IsValidCompanyID(COMPANY_FIRST) && (!_networking || (_networking && _network_server && !_network_dedicated))) - DoStartupNewCompany(false); - - if (CheckSavegameVersion(72)) { - /* Locks/shiplifts in very old savegames had OWNER_WATER as owner */ - for (TileIndex t = 0; t < MapSize(); t++) { - switch (GetTileType(t)) { - default: break; - - case MP_WATER: - if (GetWaterTileType(t) == WATER_TILE_LOCK && GetTileOwner(t) == OWNER_WATER) SetTileOwner(t, OWNER_NONE); - break; - - case MP_STATION: { - if (HasBit(_m[t].m6, 3)) SetBit(_m[t].m6, 2); - StationGfx gfx = GetStationGfx(t); - StationType st; - if ( IsInsideMM(gfx, 0, 8)) { // Railway station - st = STATION_RAIL; - SetStationGfx(t, gfx - 0); - } else if (IsInsideMM(gfx, 8, 67)) { // Airport - st = STATION_AIRPORT; - SetStationGfx(t, gfx - 8); - } else if (IsInsideMM(gfx, 67, 71)) { // Truck - st = STATION_TRUCK; - SetStationGfx(t, gfx - 67); - } else if (IsInsideMM(gfx, 71, 75)) { // Bus - st = STATION_BUS; - SetStationGfx(t, gfx - 71); - } else if (gfx == 75) { // Oil rig - st = STATION_OILRIG; - SetStationGfx(t, gfx - 75); - } else if (IsInsideMM(gfx, 76, 82)) { // Dock - st = STATION_DOCK; - SetStationGfx(t, gfx - 76); - } else if (gfx == 82) { // Buoy - st = STATION_BUOY; - SetStationGfx(t, gfx - 82); - } else if (IsInsideMM(gfx, 83, 168)) { // Extended airport - st = STATION_AIRPORT; - SetStationGfx(t, gfx - 83 + 67 - 8); - } else if (IsInsideMM(gfx, 168, 170)) { // Drive through truck - st = STATION_TRUCK; - SetStationGfx(t, gfx - 168 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET); - } else if (IsInsideMM(gfx, 170, 172)) { // Drive through bus - st = STATION_BUS; - SetStationGfx(t, gfx - 170 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET); - } else { - /* Restore the signals */ - signal(SIGSEGV, prev_segfault); - signal(SIGABRT, prev_abort); - return false; - } - SB(_m[t].m6, 3, 3, st); - } break; - } - } - } - - for (TileIndex t = 0; t < map_size; t++) { - switch (GetTileType(t)) { - case MP_STATION: { - Station *st = GetStationByTile(t); - - /* Set up station spread; buoys do not have one */ - if (!IsBuoy(t)) st->rect.BeforeAddTile(t, StationRect::ADD_FORCE); - - switch (GetStationType(t)) { - case STATION_TRUCK: - case STATION_BUS: - if (CheckSavegameVersion(6)) { - /* From this version on there can be multiple road stops of the - * same type per station. Convert the existing stops to the new - * internal data structure. */ - RoadStop *rs = new RoadStop(t); - if (rs == NULL) error("Too many road stops in savegame"); - - RoadStop **head = - IsTruckStop(t) ? &st->truck_stops : &st->bus_stops; - *head = rs; - } - break; - - case STATION_OILRIG: { - /* Very old savegames sometimes have phantom oil rigs, i.e. - * an oil rig which got shut down, but not completly removed from - * the map - */ - TileIndex t1 = TILE_ADDXY(t, 0, 1); - if (IsTileType(t1, MP_INDUSTRY) && - GetIndustryGfx(t1) == GFX_OILRIG_1) { - /* The internal encoding of oil rigs was changed twice. - * It was 3 (till 2.2) and later 5 (till 5.1). - * Setting it unconditionally does not hurt. - */ - GetStationByTile(t)->airport_type = AT_OILRIG; - } else { - DeleteOilRig(t); - } - break; - } - - default: break; - } - break; - } - - default: break; - } - } - - /* In version 6.1 we put the town index in the map-array. To do this, we need - * to use m2 (16bit big), so we need to clean m2, and that is where this is - * all about ;) */ - if (CheckSavegameVersionOldStyle(6, 1)) { - for (TileIndex t = 0; t < map_size; t++) { - switch (GetTileType(t)) { - case MP_HOUSE: - _m[t].m4 = _m[t].m2; - SetTownIndex(t, CalcClosestTownFromTile(t, UINT_MAX)->index); - break; - - case MP_ROAD: - _m[t].m4 |= (_m[t].m2 << 4); - if ((GB(_m[t].m5, 4, 2) == ROAD_TILE_CROSSING ? (Owner)_m[t].m3 : GetTileOwner(t)) == OWNER_TOWN) { - SetTownIndex(t, CalcClosestTownFromTile(t, UINT_MAX)->index); - } else { - SetTownIndex(t, 0); - } - break; - - default: break; - } - } - } - - /* From version 9.0, we update the max passengers of a town (was sometimes negative - * before that. */ - if (CheckSavegameVersion(9)) { - Town *t; - FOR_ALL_TOWNS(t) UpdateTownMaxPass(t); - } - - /* From version 16.0, we included autorenew on engines, which are now saved, but - * of course, we do need to initialize them for older savegames. */ - if (CheckSavegameVersion(16)) { - FOR_ALL_COMPANIES(c) { - c->engine_renew_list = NULL; - c->engine_renew = false; - c->engine_renew_months = -6; - c->engine_renew_money = 100000; - } - - /* When loading a game, _local_company is not yet set to the correct value. - * However, in a dedicated server we are a spectator, so nothing needs to - * happen. In case we are not a dedicated server, the local company always - * becomes company 0, unless we are in the scenario editor where all the - * companies are 'invalid'. - */ - if (!_network_dedicated && IsValidCompanyID(COMPANY_FIRST)) { - c = GetCompany(COMPANY_FIRST); - c->engine_renew = _settings_client.gui.autorenew; - c->engine_renew_months = _settings_client.gui.autorenew_months; - c->engine_renew_money = _settings_client.gui.autorenew_money; - } - } - - if (CheckSavegameVersion(48)) { - for (TileIndex t = 0; t < map_size; t++) { - switch (GetTileType(t)) { - case MP_RAILWAY: - if (IsPlainRailTile(t)) { - /* Swap ground type and signal type for plain rail tiles, so the - * ground type uses the same bits as for depots and waypoints. */ - uint tmp = GB(_m[t].m4, 0, 4); - SB(_m[t].m4, 0, 4, GB(_m[t].m2, 0, 4)); - SB(_m[t].m2, 0, 4, tmp); - } else if (HasBit(_m[t].m5, 2)) { - /* Split waypoint and depot rail type and remove the subtype. */ - ClrBit(_m[t].m5, 2); - ClrBit(_m[t].m5, 6); - } - break; - - case MP_ROAD: - /* Swap m3 and m4, so the track type for rail crossings is the - * same as for normal rail. */ - Swap(_m[t].m3, _m[t].m4); - break; - - default: break; - } - } - } - - if (CheckSavegameVersion(61)) { - /* Added the RoadType */ - bool old_bridge = CheckSavegameVersion(42); - for (TileIndex t = 0; t < map_size; t++) { - switch(GetTileType(t)) { - case MP_ROAD: - SB(_m[t].m5, 6, 2, GB(_m[t].m5, 4, 2)); - switch (GetRoadTileType(t)) { - default: NOT_REACHED(); - case ROAD_TILE_NORMAL: - SB(_m[t].m4, 0, 4, GB(_m[t].m5, 0, 4)); - SB(_m[t].m4, 4, 4, 0); - SB(_m[t].m6, 2, 4, 0); - break; - case ROAD_TILE_CROSSING: - SB(_m[t].m4, 5, 2, GB(_m[t].m5, 2, 2)); - break; - case ROAD_TILE_DEPOT: break; - } - SetRoadTypes(t, ROADTYPES_ROAD); - break; - - case MP_STATION: - if (IsRoadStop(t)) SetRoadTypes(t, ROADTYPES_ROAD); - break; - - case MP_TUNNELBRIDGE: - /* Middle part of "old" bridges */ - if (old_bridge && IsBridge(t) && HasBit(_m[t].m5, 6)) break; - if (((old_bridge && IsBridge(t)) ? (TransportType)GB(_m[t].m5, 1, 2) : GetTunnelBridgeTransportType(t)) == TRANSPORT_ROAD) { - SetRoadTypes(t, ROADTYPES_ROAD); - } - break; - - default: break; - } - } - } - - if (CheckSavegameVersion(42)) { - Vehicle* v; - - for (TileIndex t = 0; t < map_size; t++) { - if (MayHaveBridgeAbove(t)) ClearBridgeMiddle(t); - if (IsBridgeTile(t)) { - if (HasBit(_m[t].m5, 6)) { // middle part - Axis axis = (Axis)GB(_m[t].m5, 0, 1); - - if (HasBit(_m[t].m5, 5)) { // transport route under bridge? - if (GB(_m[t].m5, 3, 2) == TRANSPORT_RAIL) { - MakeRailNormal( - t, - GetTileOwner(t), - axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X, - GetRailType(t) - ); - } else { - TownID town = IsTileOwner(t, OWNER_TOWN) ? ClosestTownFromTile(t, UINT_MAX)->index : 0; - - MakeRoadNormal( - t, - axis == AXIS_X ? ROAD_Y : ROAD_X, - ROADTYPES_ROAD, - town, - GetTileOwner(t), OWNER_NONE, OWNER_NONE - ); - } - } else { - if (GB(_m[t].m5, 3, 2) == 0) { - MakeClear(t, CLEAR_GRASS, 3); - } else { - if (GetTileSlope(t, NULL) != SLOPE_FLAT) { - MakeShore(t); - } else { - if (GetTileOwner(t) == OWNER_WATER) { - MakeWater(t); - } else { - MakeCanal(t, GetTileOwner(t), Random()); - } - } - } - } - SetBridgeMiddle(t, axis); - } else { // ramp - Axis axis = (Axis)GB(_m[t].m5, 0, 1); - uint north_south = GB(_m[t].m5, 5, 1); - DiagDirection dir = ReverseDiagDir(XYNSToDiagDir(axis, north_south)); - TransportType type = (TransportType)GB(_m[t].m5, 1, 2); - - _m[t].m5 = 1 << 7 | type << 2 | dir; - } - } - } - - FOR_ALL_VEHICLES(v) { - if (v->type != VEH_TRAIN && v->type != VEH_ROAD) continue; - if (IsBridgeTile(v->tile)) { - DiagDirection dir = GetTunnelBridgeDirection(v->tile); - - if (dir != DirToDiagDir(v->direction)) continue; - switch (dir) { - default: NOT_REACHED(); - case DIAGDIR_NE: if ((v->x_pos & 0xF) != 0) continue; break; - case DIAGDIR_SE: if ((v->y_pos & 0xF) != TILE_SIZE - 1) continue; break; - case DIAGDIR_SW: if ((v->x_pos & 0xF) != TILE_SIZE - 1) continue; break; - case DIAGDIR_NW: if ((v->y_pos & 0xF) != 0) continue; break; - } - } else if (v->z_pos > GetSlopeZ(v->x_pos, v->y_pos)) { - v->tile = GetNorthernBridgeEnd(v->tile); - } else { - continue; - } - if (v->type == VEH_TRAIN) { - v->u.rail.track = TRACK_BIT_WORMHOLE; - } else { - v->u.road.state = RVSB_WORMHOLE; - } - } - } - - /* Elrails got added in rev 24 */ - if (CheckSavegameVersion(24)) { - Vehicle *v; - RailType min_rail = RAILTYPE_ELECTRIC; - - FOR_ALL_VEHICLES(v) { - if (v->type == VEH_TRAIN) { - RailType rt = RailVehInfo(v->engine_type)->railtype; - - v->u.rail.railtype = rt; - if (rt == RAILTYPE_ELECTRIC) min_rail = RAILTYPE_RAIL; - } - } - - /* .. so we convert the entire map from normal to elrail (so maintain "fairness") */ - for (TileIndex t = 0; t < map_size; t++) { - switch (GetTileType(t)) { - case MP_RAILWAY: - SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); - break; - - case MP_ROAD: - if (IsLevelCrossing(t)) { - SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); - } - break; - - case MP_STATION: - if (IsRailwayStation(t)) { - SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); - } - break; - - case MP_TUNNELBRIDGE: - if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) { - SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); - } - break; - - default: - break; - } - } - - FOR_ALL_VEHICLES(v) { - if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) TrainConsistChanged(v, true); - } - - } - - /* In version 16.1 of the savegame a company can decide if trains, which get - * replaced, shall keep their old length. In all prior versions, just default - * to false */ - if (CheckSavegameVersionOldStyle(16, 1)) { - FOR_ALL_COMPANIES(c) c->renew_keep_length = false; - } - - /* In version 17, ground type is moved from m2 to m4 for depots and - * waypoints to make way for storing the index in m2. The custom graphics - * id which was stored in m4 is now saved as a grf/id reference in the - * waypoint struct. */ - if (CheckSavegameVersion(17)) { - Waypoint *wp; - - FOR_ALL_WAYPOINTS(wp) { - if (wp->deleted == 0) { - const StationSpec *statspec = NULL; - - if (HasBit(_m[wp->xy].m3, 4)) - statspec = GetCustomStationSpec(STAT_CLASS_WAYP, _m[wp->xy].m4 + 1); - - if (statspec != NULL) { - wp->stat_id = _m[wp->xy].m4 + 1; - wp->grfid = statspec->grffile->grfid; - wp->localidx = statspec->localidx; - } else { - /* No custom graphics set, so set to default. */ - wp->stat_id = 0; - wp->grfid = 0; - wp->localidx = 0; - } - - /* Move ground type bits from m2 to m4. */ - _m[wp->xy].m4 = GB(_m[wp->xy].m2, 0, 4); - /* Store waypoint index in the tile. */ - _m[wp->xy].m2 = wp->index; - } - } - } else { - /* As of version 17, we recalculate the custom graphic ID of waypoints - * from the GRF ID / station index. */ - AfterLoadWaypoints(); - } - - /* From version 15, we moved a semaphore bit from bit 2 to bit 3 in m4, making - * room for PBS. Now in version 21 move it back :P. */ - if (CheckSavegameVersion(21) && !CheckSavegameVersion(15)) { - for (TileIndex t = 0; t < map_size; t++) { - switch (GetTileType(t)) { - case MP_RAILWAY: - if (HasSignals(t)) { - /* convert PBS signals to combo-signals */ - if (HasBit(_m[t].m2, 2)) SetSignalType(t, TRACK_X, SIGTYPE_COMBO); - - /* move the signal variant back */ - SetSignalVariant(t, TRACK_X, HasBit(_m[t].m2, 3) ? SIG_SEMAPHORE : SIG_ELECTRIC); - ClrBit(_m[t].m2, 3); - } - - /* Clear PBS reservation on track */ - if (!IsRailDepotTile(t)) { - SB(_m[t].m4, 4, 4, 0); - } else { - ClrBit(_m[t].m3, 6); - } - break; - - case MP_ROAD: /* Clear PBS reservation on crossing */ - if (IsLevelCrossing(t)) ClrBit(_m[t].m5, 0); - break; - - case MP_STATION: /* Clear PBS reservation on station */ - ClrBit(_m[t].m3, 6); - break; - - default: break; - } - } - } - - if (CheckSavegameVersion(25)) { - Vehicle *v; - FOR_ALL_VEHICLES(v) { - if (v->type == VEH_ROAD) { - v->vehstatus &= ~0x40; - v->u.road.slot = NULL; - v->u.road.slot_age = 0; - } - } - } else { - Vehicle *v; - FOR_ALL_VEHICLES(v) { - if (v->type == VEH_ROAD && v->u.road.slot != NULL) v->u.road.slot->num_vehicles++; - } - } - - if (CheckSavegameVersion(26)) { - Station *st; - FOR_ALL_STATIONS(st) { - st->last_vehicle_type = VEH_INVALID; - } - } - - YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK); - - if (CheckSavegameVersion(34)) FOR_ALL_COMPANIES(c) ResetCompanyLivery(c); - - FOR_ALL_COMPANIES(c) { - c->avail_railtypes = GetCompanyRailtypes(c->index); - c->avail_roadtypes = GetCompanyRoadtypes(c->index); - } - - if (!CheckSavegameVersion(27)) AfterLoadStations(); - - /* Time starts at 0 instead of 1920. - * Account for this in older games by adding an offset */ - if (CheckSavegameVersion(31)) { - Station *st; - Waypoint *wp; - Engine *e; - Industry *i; - Vehicle *v; - - _date += DAYS_TILL_ORIGINAL_BASE_YEAR; - _cur_year += ORIGINAL_BASE_YEAR; - - FOR_ALL_STATIONS(st) st->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR; - FOR_ALL_WAYPOINTS(wp) wp->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR; - FOR_ALL_ENGINES(e) e->intro_date += DAYS_TILL_ORIGINAL_BASE_YEAR; - FOR_ALL_COMPANIES(c) c->inaugurated_year += ORIGINAL_BASE_YEAR; - FOR_ALL_INDUSTRIES(i) i->last_prod_year += ORIGINAL_BASE_YEAR; - - FOR_ALL_VEHICLES(v) { - v->date_of_last_service += DAYS_TILL_ORIGINAL_BASE_YEAR; - v->build_year += ORIGINAL_BASE_YEAR; - } - } - - /* From 32 on we save the industry who made the farmland. - * To give this prettyness to old savegames, we remove all farmfields and - * plant new ones. */ - if (CheckSavegameVersion(32)) { - Industry *i; - - for (TileIndex t = 0; t < map_size; t++) { - if (IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_FIELDS)) { - /* remove fields */ - MakeClear(t, CLEAR_GRASS, 3); - } else if (IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES)) { - /* remove fences around fields */ - SetFenceSE(t, 0); - SetFenceSW(t, 0); - } - } - - FOR_ALL_INDUSTRIES(i) { - uint j; - - if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) { - for (j = 0; j != 50; j++) PlantRandomFarmField(i); - } - } - } - - /* Setting no refit flags to all orders in savegames from before refit in orders were added */ - if (CheckSavegameVersion(36)) { - Order *order; - Vehicle *v; - - FOR_ALL_ORDERS(order) { - order->SetRefit(CT_NO_REFIT); - } - - FOR_ALL_VEHICLES(v) { - v->current_order.SetRefit(CT_NO_REFIT); - } - } - - /* from version 38 we have optional elrails, since we cannot know the - * preference of a user, let elrails enabled; it can be disabled manually */ - if (CheckSavegameVersion(38)) _settings_game.vehicle.disable_elrails = false; - /* do the same as when elrails were enabled/disabled manually just now */ - SettingsDisableElrail(_settings_game.vehicle.disable_elrails); - InitializeRailGUI(); - - /* From version 53, the map array was changed for house tiles to allow - * space for newhouses grf features. A new byte, m7, was also added. */ - if (CheckSavegameVersion(53)) { - for (TileIndex t = 0; t < map_size; t++) { - if (IsTileType(t, MP_HOUSE)) { - if (GB(_m[t].m3, 6, 2) != TOWN_HOUSE_COMPLETED) { - /* Move the construction stage from m3[7..6] to m5[5..4]. - * The construction counter does not have to move. */ - SB(_m[t].m5, 3, 2, GB(_m[t].m3, 6, 2)); - SB(_m[t].m3, 6, 2, 0); - - /* The "house is completed" bit is now in m6[2]. */ - SetHouseCompleted(t, false); - } else { - /* The "lift has destination" bit has been moved from - * m5[7] to m7[0]. */ - SB(_me[t].m7, 0, 1, HasBit(_m[t].m5, 7)); - ClrBit(_m[t].m5, 7); - - /* The "lift is moving" bit has been removed, as it does - * the same job as the "lift has destination" bit. */ - ClrBit(_m[t].m1, 7); - - /* The position of the lift goes from m1[7..0] to m6[7..2], - * making m1 totally free, now. The lift position does not - * have to be a full byte since the maximum value is 36. */ - SetLiftPosition(t, GB(_m[t].m1, 0, 6 )); - - _m[t].m1 = 0; - _m[t].m3 = 0; - SetHouseCompleted(t, true); - } - } - } - } - - /* Check and update house and town values */ - UpdateHousesAndTowns(); - - if (CheckSavegameVersion(43)) { - for (TileIndex t = 0; t < map_size; t++) { - if (IsTileType(t, MP_INDUSTRY)) { - switch (GetIndustryGfx(t)) { - case GFX_POWERPLANT_SPARKS: - SetIndustryAnimationState(t, GB(_m[t].m1, 2, 5)); - break; - - case GFX_OILWELL_ANIMATED_1: - case GFX_OILWELL_ANIMATED_2: - case GFX_OILWELL_ANIMATED_3: - SetIndustryAnimationState(t, GB(_m[t].m1, 0, 2)); - break; - - case GFX_COAL_MINE_TOWER_ANIMATED: - case GFX_COPPER_MINE_TOWER_ANIMATED: - case GFX_GOLD_MINE_TOWER_ANIMATED: - SetIndustryAnimationState(t, _m[t].m1); - break; - - default: /* No animation states to change */ - break; - } - } - } - } - - if (CheckSavegameVersion(44)) { - Vehicle *v; - /* If we remove a station while cargo from it is still enroute, payment calculation will assume - * 0, 0 to be the source of the cargo, resulting in very high payments usually. v->source_xy - * stores the coordinates, preserving them even if the station is removed. However, if a game is loaded - * where this situation exists, the cargo-source information is lost. in this case, we set the source - * to the current tile of the vehicle to prevent excessive profits - */ - FOR_ALL_VEHICLES(v) { - const CargoList::List *packets = v->cargo.Packets(); - for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) { - CargoPacket *cp = *it; - cp->source_xy = IsValidStationID(cp->source) ? GetStation(cp->source)->xy : v->tile; - cp->loaded_at_xy = cp->source_xy; - } - v->cargo.InvalidateCache(); - } - - /* Store position of the station where the goods come from, so there - * are no very high payments when stations get removed. However, if the - * station where the goods came from is already removed, the source - * information is lost. In that case we set it to the position of this - * station */ - Station *st; - FOR_ALL_STATIONS(st) { - for (CargoID c = 0; c < NUM_CARGO; c++) { - GoodsEntry *ge = &st->goods[c]; - - const CargoList::List *packets = ge->cargo.Packets(); - for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) { - CargoPacket *cp = *it; - cp->source_xy = IsValidStationID(cp->source) ? GetStation(cp->source)->xy : st->xy; - cp->loaded_at_xy = cp->source_xy; - } - } - } - } - - if (CheckSavegameVersion(45)) { - Vehicle *v; - /* Originally just the fact that some cargo had been paid for was - * stored to stop people cheating and cashing in several times. This - * wasn't enough though as it was cleared when the vehicle started - * loading again, even if it didn't actually load anything, so now the - * amount of cargo that has been paid for is stored. */ - FOR_ALL_VEHICLES(v) { - const CargoList::List *packets = v->cargo.Packets(); - for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) { - CargoPacket *cp = *it; - cp->paid_for = HasBit(v->vehicle_flags, 2); - } - ClrBit(v->vehicle_flags, 2); - v->cargo.InvalidateCache(); - } - } - - /* Buoys do now store the owner of the previous water tile, which can never - * be OWNER_NONE. So replace OWNER_NONE with OWNER_WATER. */ - if (CheckSavegameVersion(46)) { - Station *st; - FOR_ALL_STATIONS(st) { - if (st->IsBuoy() && IsTileOwner(st->xy, OWNER_NONE) && TileHeight(st->xy) == 0) SetTileOwner(st->xy, OWNER_WATER); - } - } - - if (CheckSavegameVersion(50)) { - Vehicle *v; - /* Aircraft units changed from 8 mph to 1 km/h */ - FOR_ALL_VEHICLES(v) { - if (v->type == VEH_AIRCRAFT && v->subtype <= AIR_AIRCRAFT) { - const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type); - v->cur_speed *= 129; - v->cur_speed /= 10; - v->max_speed = avi->max_speed; - v->acceleration = avi->acceleration; - } - } - } - - if (CheckSavegameVersion(49)) FOR_ALL_COMPANIES(c) c->face = ConvertFromOldCompanyManagerFace(c->face); - - if (CheckSavegameVersion(52)) { - for (TileIndex t = 0; t < map_size; t++) { - if (IsStatueTile(t)) { - _m[t].m2 = CalcClosestTownFromTile(t, UINT_MAX)->index; - } - } - } - - /* A patch option containing the proportion of towns that grow twice as - * fast was added in version 54. From version 56 this is now saved in the - * town as cities can be built specifically in the scenario editor. */ - if (CheckSavegameVersion(56)) { - Town *t; - - FOR_ALL_TOWNS(t) { - if (_settings_game.economy.larger_towns != 0 && (t->index % _settings_game.economy.larger_towns) == 0) { - t->larger_town = true; - } - } - } - - if (CheckSavegameVersion(57)) { - Vehicle *v; - /* Added a FIFO queue of vehicles loading at stations */ - FOR_ALL_VEHICLES(v) { - if ((v->type != VEH_TRAIN || IsFrontEngine(v)) && // for all locs - !(v->vehstatus & (VS_STOPPED | VS_CRASHED)) && // not stopped or crashed - v->current_order.IsType(OT_LOADING)) { // loading - GetStation(v->last_station_visited)->loading_vehicles.push_back(v); - - /* The loading finished flag is *only* set when actually completely - * finished. Because the vehicle is loading, it is not finished. */ - ClrBit(v->vehicle_flags, VF_LOADING_FINISHED); - } - } - } else if (CheckSavegameVersion(59)) { - /* For some reason non-loading vehicles could be in the station's loading vehicle list */ - - Station *st; - FOR_ALL_STATIONS(st) { - std::list<Vehicle *>::iterator iter; - for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end();) { - Vehicle *v = *iter; - iter++; - if (!v->current_order.IsType(OT_LOADING)) st->loading_vehicles.remove(v); - } - } - } - - if (CheckSavegameVersion(58)) { - /* patch difficulty number_industries other than zero get bumped to +1 - * since a new option (very low at position1) has been added */ - if (_settings_game.difficulty.number_industries > 0) { - _settings_game.difficulty.number_industries++; - } - - /* Same goes for number of towns, although no test is needed, just an increment */ - _settings_game.difficulty.number_towns++; - } - - if (CheckSavegameVersion(64)) { - /* copy the signal type/variant and move signal states bits */ - for (TileIndex t = 0; t < map_size; t++) { - if (IsTileType(t, MP_RAILWAY) && HasSignals(t)) { - SetSignalStates(t, GB(_m[t].m2, 4, 4)); - SetSignalVariant(t, INVALID_TRACK, GetSignalVariant(t, TRACK_X)); - SetSignalType(t, INVALID_TRACK, GetSignalType(t, TRACK_X)); - ClrBit(_m[t].m2, 7); - } - } - } - - if (CheckSavegameVersion(69)) { - /* In some old savegames a bit was cleared when it should not be cleared */ - Vehicle *v; - FOR_ALL_VEHICLES(v) { - if (v->type == VEH_ROAD && (v->u.road.state == 250 || v->u.road.state == 251)) { - SetBit(v->u.road.state, RVS_IS_STOPPING); - } - } - } - - if (CheckSavegameVersion(70)) { - /* Added variables to support newindustries */ - Industry *i; - FOR_ALL_INDUSTRIES(i) i->founder = OWNER_NONE; - } - - /* From version 82, old style canals (above sealevel (0), WATER owner) are no longer supported. - Replace the owner for those by OWNER_NONE. */ - if (CheckSavegameVersion(82)) { - for (TileIndex t = 0; t < map_size; t++) { - if (IsTileType(t, MP_WATER) && - GetWaterTileType(t) == WATER_TILE_CLEAR && - GetTileOwner(t) == OWNER_WATER && - TileHeight(t) != 0) { - SetTileOwner(t, OWNER_NONE); - } - } - } - - /* - * Add the 'previous' owner to the ship depots so we can reset it with - * the correct values when it gets destroyed. This prevents that - * someone can remove canals owned by somebody else and it prevents - * making floods using the removal of ship depots. - */ - if (CheckSavegameVersion(83)) { - for (TileIndex t = 0; t < map_size; t++) { - if (IsTileType(t, MP_WATER) && IsShipDepot(t)) { - _m[t].m4 = (TileHeight(t) == 0) ? OWNER_WATER : OWNER_NONE; - } - } - } - - if (CheckSavegameVersion(74)) { - Station *st; - FOR_ALL_STATIONS(st) { - for (CargoID c = 0; c < NUM_CARGO; c++) { - st->goods[c].last_speed = 0; - if (st->goods[c].cargo.Count() != 0) SetBit(st->goods[c].acceptance_pickup, GoodsEntry::PICKUP); - } - } - } - - if (CheckSavegameVersion(78)) { - Industry *i; - uint j; - FOR_ALL_INDUSTRIES(i) { - const IndustrySpec *indsp = GetIndustrySpec(i->type); - for (j = 0; j < lengthof(i->produced_cargo); j++) { - i->produced_cargo[j] = indsp->produced_cargo[j]; - } - for (j = 0; j < lengthof(i->accepts_cargo); j++) { - i->accepts_cargo[j] = indsp->accepts_cargo[j]; - } - } - } - - /* Before version 81, the density of grass was always stored as zero, and - * grassy trees were always drawn fully grassy. Furthermore, trees on rough - * land used to have zero density, now they have full density. Therefore, - * make all grassy/rough land trees have a density of 3. */ - if (CheckSavegameVersion(81)) { - for (TileIndex t = 0; t < map_size; t++) { - if (GetTileType(t) == MP_TREES) { - TreeGround groundType = GetTreeGround(t); - if (groundType != TREE_GROUND_SNOW_DESERT) SetTreeGroundDensity(t, groundType, 3); - } - } - } - - - if (CheckSavegameVersion(93)) { - /* Rework of orders. */ - Order *order; - FOR_ALL_ORDERS(order) order->ConvertFromOldSavegame(); - - Vehicle *v; - FOR_ALL_VEHICLES(v) { - if (v->orders.list != NULL && v->orders.list->GetFirstOrder() != NULL && !v->orders.list->GetFirstOrder()->IsValid()) { - v->orders.list->FreeChain(); - v->orders.list = NULL; - } - - v->current_order.ConvertFromOldSavegame(); - if (v->type == VEH_ROAD && v->IsPrimaryVehicle() && v->FirstShared() == v) { - FOR_VEHICLE_ORDERS(v, order) order->SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); - } - } - } else if (CheckSavegameVersion(94)) { - /* Unload and transfer are now mutual exclusive. */ - Order *order; - FOR_ALL_ORDERS(order) { - if ((order->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == (OUFB_UNLOAD | OUFB_TRANSFER)) { - order->SetUnloadType(OUFB_TRANSFER); - order->SetLoadType(OLFB_NO_LOAD); - } - } - - Vehicle *v; - FOR_ALL_VEHICLES(v) { - if ((v->current_order.GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == (OUFB_UNLOAD | OUFB_TRANSFER)) { - v->current_order.SetUnloadType(OUFB_TRANSFER); - v->current_order.SetLoadType(OLFB_NO_LOAD); - } - } - } - - if (CheckSavegameVersion(84)) { - /* Update go to buoy orders because they are just waypoints */ - Order *order; - FOR_ALL_ORDERS(order) { - if (order->IsType(OT_GOTO_STATION) && GetStation(order->GetDestination())->IsBuoy()) { - order->SetLoadType(OLF_LOAD_IF_POSSIBLE); - order->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE); - } - } - - /* Set all share owners to INVALID_COMPANY for - * 1) all inactive companies - * (when inactive companies were stored in the savegame - TTD, TTDP and some - * *really* old revisions of OTTD; else it is already set in InitializeCompanies()) - * 2) shares that are owned by inactive companies or self - * (caused by cheating clients in earlier revisions) */ - FOR_ALL_COMPANIES(c) { - for (uint i = 0; i < 4; i++) { - CompanyID company = c->share_owners[i]; - if (company == INVALID_COMPANY) continue; - if (!IsValidCompanyID(company) || company == c->index) c->share_owners[i] = INVALID_COMPANY; - } - } - } - - if (CheckSavegameVersion(86)) { - for (TileIndex t = 0; t < map_size; t++) { - /* Move river flag and update canals to use water class */ - if (IsTileType(t, MP_WATER)) { - if (GetWaterClass(t) != WATER_CLASS_RIVER) { - if (IsWater(t)) { - Owner o = GetTileOwner(t); - if (o == OWNER_WATER) { - MakeWater(t); - } else { - MakeCanal(t, o, Random()); - } - } else if (IsShipDepot(t)) { - Owner o = (Owner)_m[t].m4; // Original water owner - SetWaterClass(t, o == OWNER_WATER ? WATER_CLASS_SEA : WATER_CLASS_CANAL); - } - } - } - } - - /* Update locks, depots, docks and buoys to have a water class based - * on its neighbouring tiles. Done after river and canal updates to - * ensure neighbours are correct. */ - for (TileIndex t = 0; t < map_size; t++) { - if (GetTileSlope(t, NULL) != SLOPE_FLAT) continue; - - if (IsTileType(t, MP_WATER) && IsLock(t)) SetWaterClassDependingOnSurroundings(t, false); - if (IsTileType(t, MP_STATION) && (IsDock(t) || IsBuoy(t))) SetWaterClassDependingOnSurroundings(t, false); - } - } - - if (CheckSavegameVersion(87)) { - for (TileIndex t = 0; t < map_size; t++) { - /* skip oil rigs at borders! */ - if ((IsTileType(t, MP_WATER) || IsBuoyTile(t)) && - (TileX(t) == 0 || TileY(t) == 0 || TileX(t) == MapMaxX() - 1 || TileY(t) == MapMaxY() - 1)) { - /* Some version 86 savegames have wrong water class at map borders (under buoy, or after removing buoy). - * This conversion has to be done before buoys with invalid owner are removed. */ - SetWaterClass(t, WATER_CLASS_SEA); - } - - if (IsBuoyTile(t) || IsDriveThroughStopTile(t) || IsTileType(t, MP_WATER)) { - Owner o = GetTileOwner(t); - if (o < MAX_COMPANIES && !IsValidCompanyID(o)) { - _current_company = o; - ChangeTileOwner(t, o, INVALID_OWNER); - } - if (IsBuoyTile(t)) { - /* reset buoy owner to OWNER_NONE in the station struct - * (even if it is owned by active company) */ - GetStationByTile(t)->owner = OWNER_NONE; - } - } else if (IsTileType(t, MP_ROAD)) { - /* works for all RoadTileType */ - for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { - /* update even non-existing road types to update tile owner too */ - Owner o = GetRoadOwner(t, rt); - if (o < MAX_COMPANIES && !IsValidCompanyID(o)) SetRoadOwner(t, rt, OWNER_NONE); - } - if (IsLevelCrossing(t)) { - Owner o = GetTileOwner(t); - if (!IsValidCompanyID(o)) { - /* remove leftover rail piece from crossing (from very old savegames) */ - _current_company = o; - DoCommand(t, 0, GetCrossingRailTrack(t), DC_EXEC | DC_BANKRUPT, CMD_REMOVE_SINGLE_RAIL); - } - } - } - } - - /* Convert old PF settings to new */ - if (_settings_game.pf.yapf.rail_use_yapf || CheckSavegameVersion(28)) { - _settings_game.pf.pathfinder_for_trains = VPF_YAPF; - } else { - _settings_game.pf.pathfinder_for_trains = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_NTP); - } - - if (_settings_game.pf.yapf.road_use_yapf || CheckSavegameVersion(28)) { - _settings_game.pf.pathfinder_for_roadvehs = VPF_YAPF; - } else { - _settings_game.pf.pathfinder_for_roadvehs = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_OPF); - } - - if (_settings_game.pf.yapf.ship_use_yapf) { - _settings_game.pf.pathfinder_for_ships = VPF_YAPF; - } else { - _settings_game.pf.pathfinder_for_ships = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_OPF); - } - } - - if (CheckSavegameVersion(88)) { - /* Profits are now with 8 bit fract */ - Vehicle *v; - FOR_ALL_VEHICLES(v) { - v->profit_this_year <<= 8; - v->profit_last_year <<= 8; - v->running_ticks = 0; - } - } - - if (CheckSavegameVersion(91)) { - /* Increase HouseAnimationFrame from 5 to 7 bits */ - for (TileIndex t = 0; t < map_size; t++) { - if (IsTileType(t, MP_HOUSE) && GetHouseType(t) >= NEW_HOUSE_OFFSET) { - SetHouseAnimationFrame(t, GB(_m[t].m6, 3, 5)); - } - } - } - - if (CheckSavegameVersion(62)) { - /* Remove all trams from savegames without tram support. - * There would be trams without tram track under causing crashes sooner or later. */ - Vehicle *v; - FOR_ALL_VEHICLES(v) { - if (v->type == VEH_ROAD && v->First() == v && - HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM)) { - if (_switch_mode_errorstr == INVALID_STRING_ID || _switch_mode_errorstr == STR_NEWGRF_COMPATIBLE_LOAD_WARNING) { - _switch_mode_errorstr = STR_LOADGAME_REMOVED_TRAMS; - } - delete v; - } - } - } - - if (CheckSavegameVersion(99)) { - for (TileIndex t = 0; t < map_size; t++) { - /* Set newly introduced WaterClass of industry tiles */ - if (IsTileType(t, MP_STATION) && IsOilRig(t)) { - SetWaterClassDependingOnSurroundings(t, true); - } - if (IsTileType(t, MP_INDUSTRY)) { - if ((GetIndustrySpec(GetIndustryType(t))->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) { - SetWaterClassDependingOnSurroundings(t, true); - } else { - SetWaterClass(t, WATER_CLASS_INVALID); - } - } - - /* Replace "house construction year" with "house age" */ - if (IsTileType(t, MP_HOUSE) && IsHouseCompleted(t)) { - _m[t].m5 = Clamp(_cur_year - (_m[t].m5 + ORIGINAL_BASE_YEAR), 0, 0xFF); - } - } - } - - /* Move the signal variant back up one bit for PBS. We don't convert the old PBS - * format here, as an old layout wouldn't work properly anyway. To be safe, we - * clear any possible PBS reservations as well. */ - if (CheckSavegameVersion(100)) { - for (TileIndex t = 0; t < map_size; t++) { - switch (GetTileType(t)) { - case MP_RAILWAY: - if (HasSignals(t)) { - /* move the signal variant */ - SetSignalVariant(t, TRACK_UPPER, HasBit(_m[t].m2, 2) ? SIG_SEMAPHORE : SIG_ELECTRIC); - SetSignalVariant(t, TRACK_LOWER, HasBit(_m[t].m2, 6) ? SIG_SEMAPHORE : SIG_ELECTRIC); - ClrBit(_m[t].m2, 2); - ClrBit(_m[t].m2, 6); - } - - /* Clear PBS reservation on track */ - if (IsRailDepot(t) ||IsRailWaypoint(t)) { - SetDepotWaypointReservation(t, false); - } else { - SetTrackReservation(t, TRACK_BIT_NONE); - } - break; - - case MP_ROAD: /* Clear PBS reservation on crossing */ - if (IsLevelCrossing(t)) SetCrossingReservation(t, false); - break; - - case MP_STATION: /* Clear PBS reservation on station */ - if (IsRailwayStation(t)) SetRailwayStationReservation(t, false); - break; - - case MP_TUNNELBRIDGE: /* Clear PBS reservation on tunnels/birdges */ - if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) SetTunnelBridgeReservation(t, false); - break; - - default: break; - } - } - } - - /* Reserve all tracks trains are currently on. */ - if (CheckSavegameVersion(101)) { - Vehicle *v; - FOR_ALL_VEHICLES(v) { - if (v->type == VEH_TRAIN) { - if ((v->u.rail.track & TRACK_BIT_WORMHOLE) == TRACK_BIT_WORMHOLE) { - TryReserveRailTrack(v->tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(v->tile))); - } else if ((v->u.rail.track & TRACK_BIT_MASK) != TRACK_BIT_NONE) { - TryReserveRailTrack(v->tile, TrackBitsToTrack(v->u.rail.track)); - } - } - } - - /* Give owners to waypoints, based on rail tracks it is sitting on. - * If none is available, specify OWNER_NONE */ - Waypoint *wp; - FOR_ALL_WAYPOINTS(wp) { - Owner owner = (IsRailWaypointTile(wp->xy) ? GetTileOwner(wp->xy) : OWNER_NONE); - wp->owner = IsValidCompanyID(owner) ? owner : OWNER_NONE; - } - } - - if (CheckSavegameVersion(102)) { - for (TileIndex t = 0; t < map_size; t++) { - /* Now all crossings should be in correct state */ - if (IsLevelCrossingTile(t)) UpdateLevelCrossing(t, false); - } - } - - if (CheckSavegameVersion(103)) { - /* Non-town-owned roads now store the closest town */ - UpdateNearestTownForRoadTiles(false); - - /* signs with invalid owner left from older savegames */ - Sign *si; - FOR_ALL_SIGNS(si) { - if (si->owner != OWNER_NONE && !IsValidCompanyID(si->owner)) si->owner = OWNER_NONE; - } - - /* Station can get named based on an industry type, but the current ones - * are not, so mark them as if they are not named by an industry. */ - Station *st; - FOR_ALL_STATIONS(st) { - st->indtype = IT_INVALID; - } - } - - if (CheckSavegameVersion(104)) { - Vehicle *v; - FOR_ALL_VEHICLES(v) { - /* Set engine_type of shadow and rotor */ - if (v->type == VEH_AIRCRAFT && !IsNormalAircraft(v)) { - v->engine_type = v->First()->engine_type; - } - } - - /* More companies ... */ - Company *c; - FOR_ALL_COMPANIES(c) { - if (c->bankrupt_asked == 0xFF) c->bankrupt_asked = 0xFFFF; - } - - Engine *e; - FOR_ALL_ENGINES(e) { - if (e->company_avail == 0xFF) e->company_avail = 0xFFFF; - } - - Town *t; - FOR_ALL_TOWNS(t) { - if (t->have_ratings == 0xFF) t->have_ratings = 0xFFFF; - for (uint i = 8; i != MAX_COMPANIES; i++) t->ratings[i] = RATING_INITIAL; - } - } - - GamelogPrintDebug(1); - - bool ret = InitializeWindowsAndCaches(); - /* Restore the signals */ - signal(SIGSEGV, prev_segfault); - signal(SIGABRT, prev_abort); - return ret; -} - -/** Reload all NewGRF files during a running game. This is a cut-down - * version of AfterLoadGame(). - * XXX - We need to reset the vehicle position hash because with a non-empty - * hash AfterLoadVehicles() will loop infinitely. We need AfterLoadVehicles() - * to recalculate vehicle data as some NewGRF vehicle sets could have been - * removed or added and changed statistics */ -void ReloadNewGRFData() -{ - /* reload grf data */ - GfxLoadSprites(); - LoadStringWidthTable(); - ResetEconomy(); - /* reload vehicles */ - ResetVehiclePosHash(); - AfterLoadVehicles(false); - StartupEngines(); - SetCachedEngineCounts(); - /* update station and waypoint graphics */ - AfterLoadWaypoints(); - AfterLoadStations(); - /* Check and update house and town values */ - UpdateHousesAndTowns(); - /* Update livery selection windows */ - for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) InvalidateWindowData(WC_COMPANY_COLOR, i, _loaded_newgrf_features.has_2CC); - /* redraw the whole screen */ - MarkWholeScreenDirty(); - CheckTrainsLengths(); -} diff --git a/src/order_base.h b/src/order_base.h index b7c01282d..44e8d9c15 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -431,7 +431,4 @@ static inline bool IsValidOrderListID(uint index) #define FOR_ALL_ORDER_LISTS_FROM(ol, start) for (ol = GetOrderList(start); ol != NULL; ol = (ol->index + 1U < GetOrderListPoolSize()) ? GetOrderList(ol->index + 1U) : NULL) if (ol->IsValid()) #define FOR_ALL_ORDER_LISTS(ol) FOR_ALL_ORDER_LISTS_FROM(ol, 0) -/* (Un)pack routines */ -Order UnpackOldOrder(uint16 packed); - #endif /* ORDER_H */ diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index d0678c457..4686a564d 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -13,7 +13,6 @@ #include "command_func.h" #include "company_func.h" #include "news_func.h" -#include "saveload.h" #include "vehicle_gui.h" #include "cargotype.h" #include "aircraft.h" @@ -147,82 +146,6 @@ Order::Order(uint32 packed) this->travel_time = 0; } -void Order::ConvertFromOldSavegame() -{ - uint8 old_flags = this->flags; - this->flags = 0; - - /* First handle non-stop */ - if (_settings_client.gui.sg_new_nonstop) { - /* OFB_NON_STOP */ - this->SetNonStopType((old_flags & 8) ? ONSF_NO_STOP_AT_ANY_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); - } else { - this->SetNonStopType((old_flags & 8) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE); - } - - switch (this->GetType()) { - /* Only a few types need the other savegame conversions. */ - case OT_GOTO_DEPOT: case OT_GOTO_STATION: case OT_LOADING: break; - default: return; - } - - if (this->GetType() != OT_GOTO_DEPOT) { - /* Then the load flags */ - if ((old_flags & 2) != 0) { // OFB_UNLOAD - this->SetLoadType(OLFB_NO_LOAD); - } else if ((old_flags & 4) == 0) { // !OFB_FULL_LOAD - this->SetLoadType(OLF_LOAD_IF_POSSIBLE); - } else { - this->SetLoadType(_settings_client.gui.sg_full_load_any ? OLF_FULL_LOAD_ANY : OLFB_FULL_LOAD); - } - - /* Finally fix the unload flags */ - if ((old_flags & 1) != 0) { // OFB_TRANSFER - this->SetUnloadType(OUFB_TRANSFER); - } else if ((old_flags & 2) != 0) { // OFB_UNLOAD - this->SetUnloadType(OUFB_UNLOAD); - } else { - this->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE); - } - } else { - /* Then the depot action flags */ - this->SetDepotActionType(((old_flags & 6) == 4) ? ODATFB_HALT : ODATF_SERVICE_ONLY); - - /* Finally fix the depot type flags */ - uint t = ((old_flags & 6) == 6) ? ODTFB_SERVICE : ODTF_MANUAL; - if ((old_flags & 2) != 0) t |= ODTFB_PART_OF_ORDERS; - this->SetDepotOrderType((OrderDepotTypeFlags)t); - } -} - -/** - * - * Unpacks a order from savegames with version 4 and lower - * - */ -static Order UnpackVersion4Order(uint16 packed) -{ - return Order(GB(packed, 8, 8) << 16 | GB(packed, 4, 4) << 8 | GB(packed, 0, 4)); -} - -/** - * - * Unpacks a order from savegames made with TTD(Patch) - * - */ -Order UnpackOldOrder(uint16 packed) -{ - Order order = UnpackVersion4Order(packed); - - /* - * Sanity check - * TTD stores invalid orders as OT_NOTHING with non-zero flags/station - */ - if (!order.IsValid() && packed != 0) order.MakeDummy(); - - return order; -} - /** * * Updates the widgets of a vehicle which contains the order-data @@ -1898,118 +1821,3 @@ void InitializeOrders() _backup_orders_tile = 0; } - -const SaveLoad *GetOrderDescription() { -static const SaveLoad _order_desc[] = { - SLE_VAR(Order, type, SLE_UINT8), - SLE_VAR(Order, flags, SLE_UINT8), - SLE_VAR(Order, dest, SLE_UINT16), - SLE_REF(Order, next, REF_ORDER), - SLE_CONDVAR(Order, refit_cargo, SLE_UINT8, 36, SL_MAX_VERSION), - SLE_CONDVAR(Order, refit_subtype, SLE_UINT8, 36, SL_MAX_VERSION), - SLE_CONDVAR(Order, wait_time, SLE_UINT16, 67, SL_MAX_VERSION), - SLE_CONDVAR(Order, travel_time, SLE_UINT16, 67, SL_MAX_VERSION), - - /* Leftover from the minor savegame version stuff - * We will never use those free bytes, but we have to keep this line to allow loading of old savegames */ - SLE_CONDNULL(10, 5, 35), - SLE_END() -}; - return _order_desc; -} - -static void Save_ORDR() -{ - Order *order; - - FOR_ALL_ORDERS(order) { - SlSetArrayIndex(order->index); - SlObject(order, GetOrderDescription()); - } -} - -static void Load_ORDR() -{ - if (CheckSavegameVersionOldStyle(5, 2)) { - /* Version older than 5.2 did not have a ->next pointer. Convert them - (in the old days, the orderlist was 5000 items big) */ - size_t len = SlGetFieldLength(); - uint i; - - if (CheckSavegameVersion(5)) { - /* Pre-version 5 had an other layout for orders - (uint16 instead of uint32) */ - len /= sizeof(uint16); - uint16 *orders = MallocT<uint16>(len + 1); - - SlArray(orders, len, SLE_UINT16); - - for (i = 0; i < len; ++i) { - Order *order = new (i) Order(); - order->AssignOrder(UnpackVersion4Order(orders[i])); - } - - free(orders); - } else if (CheckSavegameVersionOldStyle(5, 2)) { - len /= sizeof(uint16); - uint16 *orders = MallocT<uint16>(len + 1); - - SlArray(orders, len, SLE_UINT32); - - for (i = 0; i < len; ++i) { - new (i) Order(orders[i]); - } - - free(orders); - } - - /* Update all the next pointer */ - for (i = 1; i < len; ++i) { - /* The orders were built like this: - * While the order is valid, set the previous will get it's next pointer set - * We start with index 1 because no order will have the first in it's next pointer */ - if (GetOrder(i)->IsValid()) - GetOrder(i - 1)->next = GetOrder(i); - } - } else { - int index; - - while ((index = SlIterateArray()) != -1) { - Order *order = new (index) Order(); - SlObject(order, GetOrderDescription()); - } - } -} - -const SaveLoad *GetOrderListDescription() { -static const SaveLoad _orderlist_desc[] = { - SLE_REF(OrderList, first, REF_ORDER), - SLE_END() -}; - return _orderlist_desc; -} - -static void Save_ORDL() -{ - OrderList *list; - - FOR_ALL_ORDER_LISTS(list) { - SlSetArrayIndex(list->index); - SlObject(list, GetOrderListDescription()); - } -} - -static void Load_ORDL() -{ - int index; - - while ((index = SlIterateArray()) != -1) { - OrderList *list = new (index) OrderList(); - SlObject(list, GetOrderListDescription()); - } -} - -extern const ChunkHandler _order_chunk_handlers[] = { - { 'ORDR', Save_ORDR, Load_ORDR, CH_ARRAY}, - { 'ORDL', Save_ORDL, Load_ORDL, CH_ARRAY | CH_LAST}, -}; diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp new file mode 100644 index 000000000..c4ecb664a --- /dev/null +++ b/src/saveload/afterload.cpp @@ -0,0 +1,1704 @@ +/* $Id$ */ + +/** @file afterload.cpp Code updating data after game load */ + +#include "../stdafx.h" +#include "../strings_type.h" +#include "../tile_type.h" +#include "../tile_map.h" +#include "../map_type.h" +#include "../road_map.h" +#include "../town.h" +#include "../void_map.h" +#include "../signs_base.h" +#include "../window_func.h" +#include "../station_func.h" +#include "../company_base.h" +#include "../fios.h" +#include "../date_func.h" +#include "../engine_func.h" +#include "../train.h" +#include "../string_func.h" +#include "../newgrf_config.h" +#include "../gamelog.h" +#include "../waypoint.h" +#include "../station_map.h" +#include "../station_base.h" +#include "../tunnelbridge_map.h" +#include "../debug.h" +#include "../network/network.h" +#include "../openttd.h" +#include "../gfxinit.h" +#include "../gfx_func.h" +#include "../functions.h" +#include "../industry_map.h" +#include "../town_map.h" +#include "../clear_map.h" +#include "../engine_base.h" +#include "../landscape.h" +#include "../vehicle_func.h" +#include "../newgrf_station.h" +#include "../yapf/yapf.hpp" +#include "../elrail_func.h" +#include "../signs_func.h" +#include "../newgrf_house.h" +#include "../aircraft.h" +#include "../unmovable_map.h" +#include "../tree_map.h" +#include "../company_func.h" +#include "../command_func.h" +#include "../road_cmd.h" + +#include "table/strings.h" + +#include "saveload.h" +#include "saveload_internal.h" + +#include <signal.h> + +extern StringID _switch_mode_errorstr; +extern Company *DoStartupNewCompany(bool is_ai); +extern void InitializeRailGUI(); + +/** + * Makes a tile canal or water depending on the surroundings. + * + * Must only be used for converting old savegames. Use WaterClass now. + * + * This as for example docks and shipdepots do not store + * whether the tile used to be canal or 'normal' water. + * @param t the tile to change. + * @param o the owner of the new tile. + * @param include_invalid_water_class Also consider WATER_CLASS_INVALID, i.e. industry tiles on land + */ +void SetWaterClassDependingOnSurroundings(TileIndex t, bool include_invalid_water_class) +{ + /* If the slope is not flat, we always assume 'land' (if allowed). Also for one-corner-raised-shores. + * Note: Wrt. autosloping under industry tiles this is the most fool-proof behaviour. */ + if (GetTileSlope(t, NULL) != SLOPE_FLAT) { + if (include_invalid_water_class) { + SetWaterClass(t, WATER_CLASS_INVALID); + return; + } else { + NOT_REACHED(); + } + } + + /* Mark tile dirty in all cases */ + MarkTileDirtyByTile(t); + + if (TileX(t) == 0 || TileY(t) == 0 || TileX(t) == MapMaxX() - 1 || TileY(t) == MapMaxY() - 1) { + /* tiles at map borders are always WATER_CLASS_SEA */ + SetWaterClass(t, WATER_CLASS_SEA); + return; + } + + bool has_water = false; + bool has_canal = false; + bool has_river = false; + + for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { + TileIndex neighbour = TileAddByDiagDir(t, dir); + switch (GetTileType(neighbour)) { + case MP_WATER: + /* clear water and shipdepots have already a WaterClass associated */ + if (IsCoast(neighbour)) { + has_water = true; + } else if (!IsLock(neighbour)) { + switch (GetWaterClass(neighbour)) { + case WATER_CLASS_SEA: has_water = true; break; + case WATER_CLASS_CANAL: has_canal = true; break; + case WATER_CLASS_RIVER: has_river = true; break; + default: NOT_REACHED(); + } + } + break; + + case MP_RAILWAY: + /* Shore or flooded halftile */ + has_water |= (GetRailGroundType(neighbour) == RAIL_GROUND_WATER); + break; + + case MP_TREES: + /* trees on shore */ + has_water |= (GetTreeGround(neighbour) == TREE_GROUND_SHORE); + break; + + default: break; + } + } + + if (!has_water && !has_canal && !has_river && include_invalid_water_class) { + SetWaterClass(t, WATER_CLASS_INVALID); + return; + } + + if (has_river && !has_canal) { + SetWaterClass(t, WATER_CLASS_RIVER); + } else if (has_canal || !has_water) { + SetWaterClass(t, WATER_CLASS_CANAL); + } else { + SetWaterClass(t, WATER_CLASS_SEA); + } +} + +static void ConvertTownOwner() +{ + for (TileIndex tile = 0; tile != MapSize(); tile++) { + switch (GetTileType(tile)) { + case MP_ROAD: + if (GB(_m[tile].m5, 4, 2) == ROAD_TILE_CROSSING && HasBit(_m[tile].m3, 7)) { + _m[tile].m3 = OWNER_TOWN; + } + /* FALLTHROUGH */ + + case MP_TUNNELBRIDGE: + if (GetTileOwner(tile) & 0x80) SetTileOwner(tile, OWNER_TOWN); + break; + + default: break; + } + } +} + +/* since savegame version 4.1, exclusive transport rights are stored at towns */ +static void UpdateExclusiveRights() +{ + Town *t; + + FOR_ALL_TOWNS(t) { + t->exclusivity = INVALID_COMPANY; + } + + /* FIXME old exclusive rights status is not being imported (stored in s->blocked_months_obsolete) + * could be implemented this way: + * 1.) Go through all stations + * Build an array town_blocked[ town_id ][ company_id ] + * that stores if at least one station in that town is blocked for a company + * 2.) Go through that array, if you find a town that is not blocked for + * one company, but for all others, then give him exclusivity. + */ +} + +static const byte convert_currency[] = { + 0, 1, 12, 8, 3, + 10, 14, 19, 4, 5, + 9, 11, 13, 6, 17, + 16, 22, 21, 7, 15, + 18, 2, 20, +}; + +/* since savegame version 4.2 the currencies are arranged differently */ +static void UpdateCurrencies() +{ + _settings_game.locale.currency = convert_currency[_settings_game.locale.currency]; +} + +/* Up to revision 1413 the invisible tiles at the southern border have not been + * MP_VOID, even though they should have. This is fixed by this function + */ +static void UpdateVoidTiles() +{ + uint i; + + for (i = 0; i < MapMaxY(); ++i) MakeVoid(i * MapSizeX() + MapMaxX()); + for (i = 0; i < MapSizeX(); ++i) MakeVoid(MapSizeX() * MapMaxY() + i); +} + +/* since savegame version 6.0 each sign has an "owner", signs without owner (from old games are set to 255) */ +static void UpdateSignOwner() +{ + Sign *si; + + FOR_ALL_SIGNS(si) si->owner = OWNER_NONE; +} + +static inline RailType UpdateRailType(RailType rt, RailType min) +{ + return rt >= min ? (RailType)(rt + 1): rt; +} + +/** + * Initialization of the windows and several kinds of caches. + * This is not done directly in AfterLoadGame because these + * functions require that all saveload conversions have been + * done. As people tend to add savegame conversion stuff after + * the intialization of the windows and caches quite some bugs + * had been made. + * Moving this out of there is both cleaner and less bug-prone. + * + * @return true if everything went according to plan, otherwise false. + */ +static bool InitializeWindowsAndCaches() +{ + /* Initialize windows */ + ResetWindowSystem(); + SetupColorsAndInitialWindow(); + + ResetViewportAfterLoadGame(); + + /* Update coordinates of the signs. */ + UpdateAllStationVirtCoord(); + UpdateAllSignVirtCoords(); + UpdateAllTownVirtCoords(); + UpdateAllWaypointSigns(); + + Company *c; + FOR_ALL_COMPANIES(c) { + /* For each company, verify (while loading a scenario) that the inauguration date is the current year and set it + * accordingly if it is not the case. No need to set it on companies that are not been used already, + * thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */ + if (_file_to_saveload.filetype == FT_SCENARIO && c->inaugurated_year != MIN_YEAR) { + c->inaugurated_year = _cur_year; + } + } + + SetCachedEngineCounts(); + + /* Towns have a noise controlled number of airports system + * So each airport's noise value must be added to the town->noise_reached value + * Reset each town's noise_reached value to '0' before. */ + UpdateAirportsNoise(); + + CheckTrainsLengths(); + + return true; +} + +/** + * Signal handler used to give a user a more useful report for crashes during + * the savegame loading process; especially when there's problems with the + * NewGRFs that are required by the savegame. + * @param unused well... unused + */ +void CDECL HandleSavegameLoadCrash(int unused) +{ + char buffer[8192]; + char *p = buffer; + p += seprintf(p, lastof(buffer), + "Loading your savegame caused OpenTTD to crash.\n" + "This is most likely caused by a missing NewGRF or a NewGRF that has been\n" + "loaded as replacement for a missing NewGRF. OpenTTD cannot easily\n" + "determine whether a replacement NewGRF is of a newer or older version.\n" + "It will load a NewGRF with the same GRF ID as the missing NewGRF. This\n" + "means that if the author makes incompatible NewGRFs with the same GRF ID\n" + "OpenTTD cannot magically do the right thing. In most cases OpenTTD will\n" + "load the savegame and not crash, but this is an exception.\n" + "Please load the savegame with the appropriate NewGRFs. When loading a\n" + "savegame still crashes when all NewGRFs are found you should file a\n" + "bug report. The missing NewGRFs are:\n"); + + for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { + if (HasBit(c->flags, GCF_COMPATIBLE)) { + char buf[40]; + md5sumToString(buf, lastof(buf), c->md5sum); + p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s. Tried another NewGRF with same GRF ID\n", BSWAP32(c->grfid), c->filename, buf); + } + if (c->status == GCS_NOT_FOUND) { + char buf[40]; + md5sumToString(buf, lastof(buf), c->md5sum); + p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s\n", BSWAP32(c->grfid), c->filename, buf); + } + } + + ShowInfo(buffer); +} + + +bool AfterLoadGame() +{ + typedef void (CDECL *SignalHandlerPointer)(int); + SignalHandlerPointer prev_segfault = signal(SIGSEGV, HandleSavegameLoadCrash); + SignalHandlerPointer prev_abort = signal(SIGABRT, HandleSavegameLoadCrash); + + TileIndex map_size = MapSize(); + Company *c; + + if (CheckSavegameVersion(98)) GamelogOldver(); + + GamelogTestRevision(); + GamelogTestMode(); + + if (CheckSavegameVersion(98)) GamelogGRFAddList(_grfconfig); + + /* in very old versions, size of train stations was stored differently */ + if (CheckSavegameVersion(2)) { + Station *st; + FOR_ALL_STATIONS(st) { + if (st->train_tile != 0 && st->trainst_h == 0) { + extern SavegameType _savegame_type; + uint n = _savegame_type == SGT_OTTD ? 4 : 3; // OTTD uses 4 bits per dimensions, TTD 3 bits + uint w = GB(st->trainst_w, n, n); + uint h = GB(st->trainst_w, 0, n); + + if (GetRailStationAxis(st->train_tile) != AXIS_X) Swap(w, h); + + st->trainst_w = w; + st->trainst_h = h; + + assert(GetStationIndex(st->train_tile + TileDiffXY(w - 1, h - 1)) == st->index); + } + } + } + + /* in version 2.1 of the savegame, town owner was unified. */ + if (CheckSavegameVersionOldStyle(2, 1)) ConvertTownOwner(); + + /* from version 4.1 of the savegame, exclusive rights are stored at towns */ + if (CheckSavegameVersionOldStyle(4, 1)) UpdateExclusiveRights(); + + /* from version 4.2 of the savegame, currencies are in a different order */ + if (CheckSavegameVersionOldStyle(4, 2)) UpdateCurrencies(); + + /* from version 6.1 of the savegame, signs have an "owner" */ + if (CheckSavegameVersionOldStyle(6, 1)) UpdateSignOwner(); + + /* In old version there seems to be a problem that water is owned by + * OWNER_NONE, not OWNER_WATER.. I can't replicate it for the current + * (4.3) version, so I just check when versions are older, and then + * walk through the whole map.. */ + if (CheckSavegameVersionOldStyle(4, 3)) { + for (TileIndex t = 0; t < map_size; t++) { + if (IsTileType(t, MP_WATER) && GetTileOwner(t) >= MAX_COMPANIES) { + SetTileOwner(t, OWNER_WATER); + } + } + } + + if (CheckSavegameVersion(84)) { + FOR_ALL_COMPANIES(c) { + c->name = CopyFromOldName(c->name_1); + if (c->name != NULL) c->name_1 = STR_SV_UNNAMED; + c->president_name = CopyFromOldName(c->president_name_1); + if (c->president_name != NULL) c->president_name_1 = SPECSTR_PRESIDENT_NAME; + } + + Station *st; + FOR_ALL_STATIONS(st) { + st->name = CopyFromOldName(st->string_id); + /* generating new name would be too much work for little effect, use the station name fallback */ + if (st->name != NULL) st->string_id = STR_SV_STNAME_FALLBACK; + } + + Town *t; + FOR_ALL_TOWNS(t) { + t->name = CopyFromOldName(t->townnametype); + if (t->name != NULL) t->townnametype = SPECSTR_TOWNNAME_START + _settings_game.game_creation.town_name; + } + + Waypoint *wp; + FOR_ALL_WAYPOINTS(wp) { + wp->name = CopyFromOldName(wp->string); + wp->string = STR_EMPTY; + } + + for (uint i = 0; i < GetSignPoolSize(); i++) { + /* invalid signs are determined by si->ower == INVALID_COMPANY now */ + Sign *si = GetSign(i); + if (!si->IsValid() && si->name != NULL) { + si->owner = OWNER_NONE; + } + } + } + + /* From this point the old names array is cleared. */ + ResetOldNames(); + + if (CheckSavegameVersion(106)) { + /* no station is determined by 'tile == INVALID_TILE' now (instead of '0') */ + Station *st; + FOR_ALL_STATIONS(st) { + if (st->airport_tile == 0) st->airport_tile = INVALID_TILE; + if (st->dock_tile == 0) st->dock_tile = INVALID_TILE; + if (st->train_tile == 0) st->train_tile = INVALID_TILE; + } + + /* the same applies to Company::location_of_HQ */ + Company *c; + FOR_ALL_COMPANIES(c) { + if (c->location_of_HQ == 0 || (CheckSavegameVersion(4) && c->location_of_HQ == 0xFFFF)) { + c->location_of_HQ = INVALID_TILE; + } + } + } + + /* convert road side to my format. */ + if (_settings_game.vehicle.road_side) _settings_game.vehicle.road_side = 1; + + /* Check if all NewGRFs are present, we are very strict in MP mode */ + GRFListCompatibility gcf_res = IsGoodGRFConfigList(); + if (_networking && gcf_res != GLC_ALL_GOOD) { + SetSaveLoadError(STR_NETWORK_ERR_CLIENT_NEWGRF_MISMATCH); + /* Restore the signals */ + signal(SIGSEGV, prev_segfault); + signal(SIGABRT, prev_abort); + return false; + } + + switch (gcf_res) { + case GLC_COMPATIBLE: _switch_mode_errorstr = STR_NEWGRF_COMPATIBLE_LOAD_WARNING; break; + case GLC_NOT_FOUND: _switch_mode_errorstr = STR_NEWGRF_DISABLED_WARNING; _pause_game = -1; break; + default: break; + } + + /* Update current year + * must be done before loading sprites as some newgrfs check it */ + SetDate(_date); + + /* Force dynamic engines off when loading older savegames */ + if (CheckSavegameVersion(95)) _settings_game.vehicle.dynamic_engines = 0; + + /* Load the sprites */ + GfxLoadSprites(); + LoadStringWidthTable(); + + /* Copy temporary data to Engine pool */ + CopyTempEngineData(); + + /* Connect front and rear engines of multiheaded trains and converts + * subtype to the new format */ + if (CheckSavegameVersionOldStyle(17, 1)) ConvertOldMultiheadToNew(); + + /* Connect front and rear engines of multiheaded trains */ + ConnectMultiheadedTrains(); + + /* reinit the landscape variables (landscape might have changed) */ + InitializeLandscapeVariables(true); + + /* Update all vehicles */ + AfterLoadVehicles(true); + + /* Update all waypoints */ + if (CheckSavegameVersion(12)) FixOldWaypoints(); + + /* in version 2.2 of the savegame, we have new airports */ + if (CheckSavegameVersionOldStyle(2, 2)) UpdateOldAircraft(); + + AfterLoadTown(); + + /* make sure there is a town in the game */ + if (_game_mode == GM_NORMAL && !ClosestTownFromTile(0, UINT_MAX)) { + SetSaveLoadError(STR_NO_TOWN_IN_SCENARIO); + /* Restore the signals */ + signal(SIGSEGV, prev_segfault); + signal(SIGABRT, prev_abort); + return false; + } + + /* The void tiles on the southern border used to belong to a wrong class (pre 4.3). + * This problem appears in savegame version 21 too, see r3455. But after loading the + * savegame and saving again, the buggy map array could be converted to new savegame + * version. It didn't show up before r12070. */ + if (CheckSavegameVersion(87)) UpdateVoidTiles(); + + /* If Load Scenario / New (Scenario) Game is used, + * a company does not exist yet. So create one here. + * 1 exeption: network-games. Those can have 0 companies + * But this exeption is not true for non dedicated network_servers! */ + if (!IsValidCompanyID(COMPANY_FIRST) && (!_networking || (_networking && _network_server && !_network_dedicated))) + DoStartupNewCompany(false); + + if (CheckSavegameVersion(72)) { + /* Locks/shiplifts in very old savegames had OWNER_WATER as owner */ + for (TileIndex t = 0; t < MapSize(); t++) { + switch (GetTileType(t)) { + default: break; + + case MP_WATER: + if (GetWaterTileType(t) == WATER_TILE_LOCK && GetTileOwner(t) == OWNER_WATER) SetTileOwner(t, OWNER_NONE); + break; + + case MP_STATION: { + if (HasBit(_m[t].m6, 3)) SetBit(_m[t].m6, 2); + StationGfx gfx = GetStationGfx(t); + StationType st; + if ( IsInsideMM(gfx, 0, 8)) { // Railway station + st = STATION_RAIL; + SetStationGfx(t, gfx - 0); + } else if (IsInsideMM(gfx, 8, 67)) { // Airport + st = STATION_AIRPORT; + SetStationGfx(t, gfx - 8); + } else if (IsInsideMM(gfx, 67, 71)) { // Truck + st = STATION_TRUCK; + SetStationGfx(t, gfx - 67); + } else if (IsInsideMM(gfx, 71, 75)) { // Bus + st = STATION_BUS; + SetStationGfx(t, gfx - 71); + } else if (gfx == 75) { // Oil rig + st = STATION_OILRIG; + SetStationGfx(t, gfx - 75); + } else if (IsInsideMM(gfx, 76, 82)) { // Dock + st = STATION_DOCK; + SetStationGfx(t, gfx - 76); + } else if (gfx == 82) { // Buoy + st = STATION_BUOY; + SetStationGfx(t, gfx - 82); + } else if (IsInsideMM(gfx, 83, 168)) { // Extended airport + st = STATION_AIRPORT; + SetStationGfx(t, gfx - 83 + 67 - 8); + } else if (IsInsideMM(gfx, 168, 170)) { // Drive through truck + st = STATION_TRUCK; + SetStationGfx(t, gfx - 168 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET); + } else if (IsInsideMM(gfx, 170, 172)) { // Drive through bus + st = STATION_BUS; + SetStationGfx(t, gfx - 170 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET); + } else { + /* Restore the signals */ + signal(SIGSEGV, prev_segfault); + signal(SIGABRT, prev_abort); + return false; + } + SB(_m[t].m6, 3, 3, st); + } break; + } + } + } + + for (TileIndex t = 0; t < map_size; t++) { + switch (GetTileType(t)) { + case MP_STATION: { + Station *st = GetStationByTile(t); + + /* Set up station spread; buoys do not have one */ + if (!IsBuoy(t)) st->rect.BeforeAddTile(t, StationRect::ADD_FORCE); + + switch (GetStationType(t)) { + case STATION_TRUCK: + case STATION_BUS: + if (CheckSavegameVersion(6)) { + /* From this version on there can be multiple road stops of the + * same type per station. Convert the existing stops to the new + * internal data structure. */ + RoadStop *rs = new RoadStop(t); + if (rs == NULL) error("Too many road stops in savegame"); + + RoadStop **head = + IsTruckStop(t) ? &st->truck_stops : &st->bus_stops; + *head = rs; + } + break; + + case STATION_OILRIG: { + /* Very old savegames sometimes have phantom oil rigs, i.e. + * an oil rig which got shut down, but not completly removed from + * the map + */ + TileIndex t1 = TILE_ADDXY(t, 0, 1); + if (IsTileType(t1, MP_INDUSTRY) && + GetIndustryGfx(t1) == GFX_OILRIG_1) { + /* The internal encoding of oil rigs was changed twice. + * It was 3 (till 2.2) and later 5 (till 5.1). + * Setting it unconditionally does not hurt. + */ + GetStationByTile(t)->airport_type = AT_OILRIG; + } else { + DeleteOilRig(t); + } + break; + } + + default: break; + } + break; + } + + default: break; + } + } + + /* In version 6.1 we put the town index in the map-array. To do this, we need + * to use m2 (16bit big), so we need to clean m2, and that is where this is + * all about ;) */ + if (CheckSavegameVersionOldStyle(6, 1)) { + for (TileIndex t = 0; t < map_size; t++) { + switch (GetTileType(t)) { + case MP_HOUSE: + _m[t].m4 = _m[t].m2; + SetTownIndex(t, CalcClosestTownFromTile(t, UINT_MAX)->index); + break; + + case MP_ROAD: + _m[t].m4 |= (_m[t].m2 << 4); + if ((GB(_m[t].m5, 4, 2) == ROAD_TILE_CROSSING ? (Owner)_m[t].m3 : GetTileOwner(t)) == OWNER_TOWN) { + SetTownIndex(t, CalcClosestTownFromTile(t, UINT_MAX)->index); + } else { + SetTownIndex(t, 0); + } + break; + + default: break; + } + } + } + + /* From version 9.0, we update the max passengers of a town (was sometimes negative + * before that. */ + if (CheckSavegameVersion(9)) { + Town *t; + FOR_ALL_TOWNS(t) UpdateTownMaxPass(t); + } + + /* From version 16.0, we included autorenew on engines, which are now saved, but + * of course, we do need to initialize them for older savegames. */ + if (CheckSavegameVersion(16)) { + FOR_ALL_COMPANIES(c) { + c->engine_renew_list = NULL; + c->engine_renew = false; + c->engine_renew_months = -6; + c->engine_renew_money = 100000; + } + + /* When loading a game, _local_company is not yet set to the correct value. + * However, in a dedicated server we are a spectator, so nothing needs to + * happen. In case we are not a dedicated server, the local company always + * becomes company 0, unless we are in the scenario editor where all the + * companies are 'invalid'. + */ + if (!_network_dedicated && IsValidCompanyID(COMPANY_FIRST)) { + c = GetCompany(COMPANY_FIRST); + c->engine_renew = _settings_client.gui.autorenew; + c->engine_renew_months = _settings_client.gui.autorenew_months; + c->engine_renew_money = _settings_client.gui.autorenew_money; + } + } + + if (CheckSavegameVersion(48)) { + for (TileIndex t = 0; t < map_size; t++) { + switch (GetTileType(t)) { + case MP_RAILWAY: + if (IsPlainRailTile(t)) { + /* Swap ground type and signal type for plain rail tiles, so the + * ground type uses the same bits as for depots and waypoints. */ + uint tmp = GB(_m[t].m4, 0, 4); + SB(_m[t].m4, 0, 4, GB(_m[t].m2, 0, 4)); + SB(_m[t].m2, 0, 4, tmp); + } else if (HasBit(_m[t].m5, 2)) { + /* Split waypoint and depot rail type and remove the subtype. */ + ClrBit(_m[t].m5, 2); + ClrBit(_m[t].m5, 6); + } + break; + + case MP_ROAD: + /* Swap m3 and m4, so the track type for rail crossings is the + * same as for normal rail. */ + Swap(_m[t].m3, _m[t].m4); + break; + + default: break; + } + } + } + + if (CheckSavegameVersion(61)) { + /* Added the RoadType */ + bool old_bridge = CheckSavegameVersion(42); + for (TileIndex t = 0; t < map_size; t++) { + switch(GetTileType(t)) { + case MP_ROAD: + SB(_m[t].m5, 6, 2, GB(_m[t].m5, 4, 2)); + switch (GetRoadTileType(t)) { + default: NOT_REACHED(); + case ROAD_TILE_NORMAL: + SB(_m[t].m4, 0, 4, GB(_m[t].m5, 0, 4)); + SB(_m[t].m4, 4, 4, 0); + SB(_m[t].m6, 2, 4, 0); + break; + case ROAD_TILE_CROSSING: + SB(_m[t].m4, 5, 2, GB(_m[t].m5, 2, 2)); + break; + case ROAD_TILE_DEPOT: break; + } + SetRoadTypes(t, ROADTYPES_ROAD); + break; + + case MP_STATION: + if (IsRoadStop(t)) SetRoadTypes(t, ROADTYPES_ROAD); + break; + + case MP_TUNNELBRIDGE: + /* Middle part of "old" bridges */ + if (old_bridge && IsBridge(t) && HasBit(_m[t].m5, 6)) break; + if (((old_bridge && IsBridge(t)) ? (TransportType)GB(_m[t].m5, 1, 2) : GetTunnelBridgeTransportType(t)) == TRANSPORT_ROAD) { + SetRoadTypes(t, ROADTYPES_ROAD); + } + break; + + default: break; + } + } + } + + if (CheckSavegameVersion(42)) { + Vehicle* v; + + for (TileIndex t = 0; t < map_size; t++) { + if (MayHaveBridgeAbove(t)) ClearBridgeMiddle(t); + if (IsBridgeTile(t)) { + if (HasBit(_m[t].m5, 6)) { // middle part + Axis axis = (Axis)GB(_m[t].m5, 0, 1); + + if (HasBit(_m[t].m5, 5)) { // transport route under bridge? + if (GB(_m[t].m5, 3, 2) == TRANSPORT_RAIL) { + MakeRailNormal( + t, + GetTileOwner(t), + axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X, + GetRailType(t) + ); + } else { + TownID town = IsTileOwner(t, OWNER_TOWN) ? ClosestTownFromTile(t, UINT_MAX)->index : 0; + + MakeRoadNormal( + t, + axis == AXIS_X ? ROAD_Y : ROAD_X, + ROADTYPES_ROAD, + town, + GetTileOwner(t), OWNER_NONE, OWNER_NONE + ); + } + } else { + if (GB(_m[t].m5, 3, 2) == 0) { + MakeClear(t, CLEAR_GRASS, 3); + } else { + if (GetTileSlope(t, NULL) != SLOPE_FLAT) { + MakeShore(t); + } else { + if (GetTileOwner(t) == OWNER_WATER) { + MakeWater(t); + } else { + MakeCanal(t, GetTileOwner(t), Random()); + } + } + } + } + SetBridgeMiddle(t, axis); + } else { // ramp + Axis axis = (Axis)GB(_m[t].m5, 0, 1); + uint north_south = GB(_m[t].m5, 5, 1); + DiagDirection dir = ReverseDiagDir(XYNSToDiagDir(axis, north_south)); + TransportType type = (TransportType)GB(_m[t].m5, 1, 2); + + _m[t].m5 = 1 << 7 | type << 2 | dir; + } + } + } + + FOR_ALL_VEHICLES(v) { + if (v->type != VEH_TRAIN && v->type != VEH_ROAD) continue; + if (IsBridgeTile(v->tile)) { + DiagDirection dir = GetTunnelBridgeDirection(v->tile); + + if (dir != DirToDiagDir(v->direction)) continue; + switch (dir) { + default: NOT_REACHED(); + case DIAGDIR_NE: if ((v->x_pos & 0xF) != 0) continue; break; + case DIAGDIR_SE: if ((v->y_pos & 0xF) != TILE_SIZE - 1) continue; break; + case DIAGDIR_SW: if ((v->x_pos & 0xF) != TILE_SIZE - 1) continue; break; + case DIAGDIR_NW: if ((v->y_pos & 0xF) != 0) continue; break; + } + } else if (v->z_pos > GetSlopeZ(v->x_pos, v->y_pos)) { + v->tile = GetNorthernBridgeEnd(v->tile); + } else { + continue; + } + if (v->type == VEH_TRAIN) { + v->u.rail.track = TRACK_BIT_WORMHOLE; + } else { + v->u.road.state = RVSB_WORMHOLE; + } + } + } + + /* Elrails got added in rev 24 */ + if (CheckSavegameVersion(24)) { + Vehicle *v; + RailType min_rail = RAILTYPE_ELECTRIC; + + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_TRAIN) { + RailType rt = RailVehInfo(v->engine_type)->railtype; + + v->u.rail.railtype = rt; + if (rt == RAILTYPE_ELECTRIC) min_rail = RAILTYPE_RAIL; + } + } + + /* .. so we convert the entire map from normal to elrail (so maintain "fairness") */ + for (TileIndex t = 0; t < map_size; t++) { + switch (GetTileType(t)) { + case MP_RAILWAY: + SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); + break; + + case MP_ROAD: + if (IsLevelCrossing(t)) { + SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); + } + break; + + case MP_STATION: + if (IsRailwayStation(t)) { + SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); + } + break; + + case MP_TUNNELBRIDGE: + if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) { + SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); + } + break; + + default: + break; + } + } + + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) TrainConsistChanged(v, true); + } + + } + + /* In version 16.1 of the savegame a company can decide if trains, which get + * replaced, shall keep their old length. In all prior versions, just default + * to false */ + if (CheckSavegameVersionOldStyle(16, 1)) { + FOR_ALL_COMPANIES(c) c->renew_keep_length = false; + } + + /* In version 17, ground type is moved from m2 to m4 for depots and + * waypoints to make way for storing the index in m2. The custom graphics + * id which was stored in m4 is now saved as a grf/id reference in the + * waypoint struct. */ + if (CheckSavegameVersion(17)) { + Waypoint *wp; + + FOR_ALL_WAYPOINTS(wp) { + if (wp->deleted == 0) { + const StationSpec *statspec = NULL; + + if (HasBit(_m[wp->xy].m3, 4)) + statspec = GetCustomStationSpec(STAT_CLASS_WAYP, _m[wp->xy].m4 + 1); + + if (statspec != NULL) { + wp->stat_id = _m[wp->xy].m4 + 1; + wp->grfid = statspec->grffile->grfid; + wp->localidx = statspec->localidx; + } else { + /* No custom graphics set, so set to default. */ + wp->stat_id = 0; + wp->grfid = 0; + wp->localidx = 0; + } + + /* Move ground type bits from m2 to m4. */ + _m[wp->xy].m4 = GB(_m[wp->xy].m2, 0, 4); + /* Store waypoint index in the tile. */ + _m[wp->xy].m2 = wp->index; + } + } + } else { + /* As of version 17, we recalculate the custom graphic ID of waypoints + * from the GRF ID / station index. */ + AfterLoadWaypoints(); + } + + /* From version 15, we moved a semaphore bit from bit 2 to bit 3 in m4, making + * room for PBS. Now in version 21 move it back :P. */ + if (CheckSavegameVersion(21) && !CheckSavegameVersion(15)) { + for (TileIndex t = 0; t < map_size; t++) { + switch (GetTileType(t)) { + case MP_RAILWAY: + if (HasSignals(t)) { + /* convert PBS signals to combo-signals */ + if (HasBit(_m[t].m2, 2)) SetSignalType(t, TRACK_X, SIGTYPE_COMBO); + + /* move the signal variant back */ + SetSignalVariant(t, TRACK_X, HasBit(_m[t].m2, 3) ? SIG_SEMAPHORE : SIG_ELECTRIC); + ClrBit(_m[t].m2, 3); + } + + /* Clear PBS reservation on track */ + if (!IsRailDepotTile(t)) { + SB(_m[t].m4, 4, 4, 0); + } else { + ClrBit(_m[t].m3, 6); + } + break; + + case MP_ROAD: /* Clear PBS reservation on crossing */ + if (IsLevelCrossing(t)) ClrBit(_m[t].m5, 0); + break; + + case MP_STATION: /* Clear PBS reservation on station */ + ClrBit(_m[t].m3, 6); + break; + + default: break; + } + } + } + + if (CheckSavegameVersion(25)) { + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_ROAD) { + v->vehstatus &= ~0x40; + v->u.road.slot = NULL; + v->u.road.slot_age = 0; + } + } + } else { + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_ROAD && v->u.road.slot != NULL) v->u.road.slot->num_vehicles++; + } + } + + if (CheckSavegameVersion(26)) { + Station *st; + FOR_ALL_STATIONS(st) { + st->last_vehicle_type = VEH_INVALID; + } + } + + YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK); + + if (CheckSavegameVersion(34)) FOR_ALL_COMPANIES(c) ResetCompanyLivery(c); + + FOR_ALL_COMPANIES(c) { + c->avail_railtypes = GetCompanyRailtypes(c->index); + c->avail_roadtypes = GetCompanyRoadtypes(c->index); + } + + if (!CheckSavegameVersion(27)) AfterLoadStations(); + + /* Time starts at 0 instead of 1920. + * Account for this in older games by adding an offset */ + if (CheckSavegameVersion(31)) { + Station *st; + Waypoint *wp; + Engine *e; + Industry *i; + Vehicle *v; + + _date += DAYS_TILL_ORIGINAL_BASE_YEAR; + _cur_year += ORIGINAL_BASE_YEAR; + + FOR_ALL_STATIONS(st) st->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR; + FOR_ALL_WAYPOINTS(wp) wp->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR; + FOR_ALL_ENGINES(e) e->intro_date += DAYS_TILL_ORIGINAL_BASE_YEAR; + FOR_ALL_COMPANIES(c) c->inaugurated_year += ORIGINAL_BASE_YEAR; + FOR_ALL_INDUSTRIES(i) i->last_prod_year += ORIGINAL_BASE_YEAR; + + FOR_ALL_VEHICLES(v) { + v->date_of_last_service += DAYS_TILL_ORIGINAL_BASE_YEAR; + v->build_year += ORIGINAL_BASE_YEAR; + } + } + + /* From 32 on we save the industry who made the farmland. + * To give this prettyness to old savegames, we remove all farmfields and + * plant new ones. */ + if (CheckSavegameVersion(32)) { + Industry *i; + + for (TileIndex t = 0; t < map_size; t++) { + if (IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_FIELDS)) { + /* remove fields */ + MakeClear(t, CLEAR_GRASS, 3); + } else if (IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES)) { + /* remove fences around fields */ + SetFenceSE(t, 0); + SetFenceSW(t, 0); + } + } + + FOR_ALL_INDUSTRIES(i) { + uint j; + + if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) { + for (j = 0; j != 50; j++) PlantRandomFarmField(i); + } + } + } + + /* Setting no refit flags to all orders in savegames from before refit in orders were added */ + if (CheckSavegameVersion(36)) { + Order *order; + Vehicle *v; + + FOR_ALL_ORDERS(order) { + order->SetRefit(CT_NO_REFIT); + } + + FOR_ALL_VEHICLES(v) { + v->current_order.SetRefit(CT_NO_REFIT); + } + } + + /* from version 38 we have optional elrails, since we cannot know the + * preference of a user, let elrails enabled; it can be disabled manually */ + if (CheckSavegameVersion(38)) _settings_game.vehicle.disable_elrails = false; + /* do the same as when elrails were enabled/disabled manually just now */ + SettingsDisableElrail(_settings_game.vehicle.disable_elrails); + InitializeRailGUI(); + + /* From version 53, the map array was changed for house tiles to allow + * space for newhouses grf features. A new byte, m7, was also added. */ + if (CheckSavegameVersion(53)) { + for (TileIndex t = 0; t < map_size; t++) { + if (IsTileType(t, MP_HOUSE)) { + if (GB(_m[t].m3, 6, 2) != TOWN_HOUSE_COMPLETED) { + /* Move the construction stage from m3[7..6] to m5[5..4]. + * The construction counter does not have to move. */ + SB(_m[t].m5, 3, 2, GB(_m[t].m3, 6, 2)); + SB(_m[t].m3, 6, 2, 0); + + /* The "house is completed" bit is now in m6[2]. */ + SetHouseCompleted(t, false); + } else { + /* The "lift has destination" bit has been moved from + * m5[7] to m7[0]. */ + SB(_me[t].m7, 0, 1, HasBit(_m[t].m5, 7)); + ClrBit(_m[t].m5, 7); + + /* The "lift is moving" bit has been removed, as it does + * the same job as the "lift has destination" bit. */ + ClrBit(_m[t].m1, 7); + + /* The position of the lift goes from m1[7..0] to m6[7..2], + * making m1 totally free, now. The lift position does not + * have to be a full byte since the maximum value is 36. */ + SetLiftPosition(t, GB(_m[t].m1, 0, 6 )); + + _m[t].m1 = 0; + _m[t].m3 = 0; + SetHouseCompleted(t, true); + } + } + } + } + + /* Check and update house and town values */ + UpdateHousesAndTowns(); + + if (CheckSavegameVersion(43)) { + for (TileIndex t = 0; t < map_size; t++) { + if (IsTileType(t, MP_INDUSTRY)) { + switch (GetIndustryGfx(t)) { + case GFX_POWERPLANT_SPARKS: + SetIndustryAnimationState(t, GB(_m[t].m1, 2, 5)); + break; + + case GFX_OILWELL_ANIMATED_1: + case GFX_OILWELL_ANIMATED_2: + case GFX_OILWELL_ANIMATED_3: + SetIndustryAnimationState(t, GB(_m[t].m1, 0, 2)); + break; + + case GFX_COAL_MINE_TOWER_ANIMATED: + case GFX_COPPER_MINE_TOWER_ANIMATED: + case GFX_GOLD_MINE_TOWER_ANIMATED: + SetIndustryAnimationState(t, _m[t].m1); + break; + + default: /* No animation states to change */ + break; + } + } + } + } + + if (CheckSavegameVersion(44)) { + Vehicle *v; + /* If we remove a station while cargo from it is still enroute, payment calculation will assume + * 0, 0 to be the source of the cargo, resulting in very high payments usually. v->source_xy + * stores the coordinates, preserving them even if the station is removed. However, if a game is loaded + * where this situation exists, the cargo-source information is lost. in this case, we set the source + * to the current tile of the vehicle to prevent excessive profits + */ + FOR_ALL_VEHICLES(v) { + const CargoList::List *packets = v->cargo.Packets(); + for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) { + CargoPacket *cp = *it; + cp->source_xy = IsValidStationID(cp->source) ? GetStation(cp->source)->xy : v->tile; + cp->loaded_at_xy = cp->source_xy; + } + v->cargo.InvalidateCache(); + } + + /* Store position of the station where the goods come from, so there + * are no very high payments when stations get removed. However, if the + * station where the goods came from is already removed, the source + * information is lost. In that case we set it to the position of this + * station */ + Station *st; + FOR_ALL_STATIONS(st) { + for (CargoID c = 0; c < NUM_CARGO; c++) { + GoodsEntry *ge = &st->goods[c]; + + const CargoList::List *packets = ge->cargo.Packets(); + for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) { + CargoPacket *cp = *it; + cp->source_xy = IsValidStationID(cp->source) ? GetStation(cp->source)->xy : st->xy; + cp->loaded_at_xy = cp->source_xy; + } + } + } + } + + if (CheckSavegameVersion(45)) { + Vehicle *v; + /* Originally just the fact that some cargo had been paid for was + * stored to stop people cheating and cashing in several times. This + * wasn't enough though as it was cleared when the vehicle started + * loading again, even if it didn't actually load anything, so now the + * amount of cargo that has been paid for is stored. */ + FOR_ALL_VEHICLES(v) { + const CargoList::List *packets = v->cargo.Packets(); + for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) { + CargoPacket *cp = *it; + cp->paid_for = HasBit(v->vehicle_flags, 2); + } + ClrBit(v->vehicle_flags, 2); + v->cargo.InvalidateCache(); + } + } + + /* Buoys do now store the owner of the previous water tile, which can never + * be OWNER_NONE. So replace OWNER_NONE with OWNER_WATER. */ + if (CheckSavegameVersion(46)) { + Station *st; + FOR_ALL_STATIONS(st) { + if (st->IsBuoy() && IsTileOwner(st->xy, OWNER_NONE) && TileHeight(st->xy) == 0) SetTileOwner(st->xy, OWNER_WATER); + } + } + + if (CheckSavegameVersion(50)) { + Vehicle *v; + /* Aircraft units changed from 8 mph to 1 km/h */ + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_AIRCRAFT && v->subtype <= AIR_AIRCRAFT) { + const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type); + v->cur_speed *= 129; + v->cur_speed /= 10; + v->max_speed = avi->max_speed; + v->acceleration = avi->acceleration; + } + } + } + + if (CheckSavegameVersion(49)) FOR_ALL_COMPANIES(c) c->face = ConvertFromOldCompanyManagerFace(c->face); + + if (CheckSavegameVersion(52)) { + for (TileIndex t = 0; t < map_size; t++) { + if (IsStatueTile(t)) { + _m[t].m2 = CalcClosestTownFromTile(t, UINT_MAX)->index; + } + } + } + + /* A patch option containing the proportion of towns that grow twice as + * fast was added in version 54. From version 56 this is now saved in the + * town as cities can be built specifically in the scenario editor. */ + if (CheckSavegameVersion(56)) { + Town *t; + + FOR_ALL_TOWNS(t) { + if (_settings_game.economy.larger_towns != 0 && (t->index % _settings_game.economy.larger_towns) == 0) { + t->larger_town = true; + } + } + } + + if (CheckSavegameVersion(57)) { + Vehicle *v; + /* Added a FIFO queue of vehicles loading at stations */ + FOR_ALL_VEHICLES(v) { + if ((v->type != VEH_TRAIN || IsFrontEngine(v)) && // for all locs + !(v->vehstatus & (VS_STOPPED | VS_CRASHED)) && // not stopped or crashed + v->current_order.IsType(OT_LOADING)) { // loading + GetStation(v->last_station_visited)->loading_vehicles.push_back(v); + + /* The loading finished flag is *only* set when actually completely + * finished. Because the vehicle is loading, it is not finished. */ + ClrBit(v->vehicle_flags, VF_LOADING_FINISHED); + } + } + } else if (CheckSavegameVersion(59)) { + /* For some reason non-loading vehicles could be in the station's loading vehicle list */ + + Station *st; + FOR_ALL_STATIONS(st) { + std::list<Vehicle *>::iterator iter; + for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end();) { + Vehicle *v = *iter; + iter++; + if (!v->current_order.IsType(OT_LOADING)) st->loading_vehicles.remove(v); + } + } + } + + if (CheckSavegameVersion(58)) { + /* patch difficulty number_industries other than zero get bumped to +1 + * since a new option (very low at position1) has been added */ + if (_settings_game.difficulty.number_industries > 0) { + _settings_game.difficulty.number_industries++; + } + + /* Same goes for number of towns, although no test is needed, just an increment */ + _settings_game.difficulty.number_towns++; + } + + if (CheckSavegameVersion(64)) { + /* copy the signal type/variant and move signal states bits */ + for (TileIndex t = 0; t < map_size; t++) { + if (IsTileType(t, MP_RAILWAY) && HasSignals(t)) { + SetSignalStates(t, GB(_m[t].m2, 4, 4)); + SetSignalVariant(t, INVALID_TRACK, GetSignalVariant(t, TRACK_X)); + SetSignalType(t, INVALID_TRACK, GetSignalType(t, TRACK_X)); + ClrBit(_m[t].m2, 7); + } + } + } + + if (CheckSavegameVersion(69)) { + /* In some old savegames a bit was cleared when it should not be cleared */ + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_ROAD && (v->u.road.state == 250 || v->u.road.state == 251)) { + SetBit(v->u.road.state, RVS_IS_STOPPING); + } + } + } + + if (CheckSavegameVersion(70)) { + /* Added variables to support newindustries */ + Industry *i; + FOR_ALL_INDUSTRIES(i) i->founder = OWNER_NONE; + } + + /* From version 82, old style canals (above sealevel (0), WATER owner) are no longer supported. + Replace the owner for those by OWNER_NONE. */ + if (CheckSavegameVersion(82)) { + for (TileIndex t = 0; t < map_size; t++) { + if (IsTileType(t, MP_WATER) && + GetWaterTileType(t) == WATER_TILE_CLEAR && + GetTileOwner(t) == OWNER_WATER && + TileHeight(t) != 0) { + SetTileOwner(t, OWNER_NONE); + } + } + } + + /* + * Add the 'previous' owner to the ship depots so we can reset it with + * the correct values when it gets destroyed. This prevents that + * someone can remove canals owned by somebody else and it prevents + * making floods using the removal of ship depots. + */ + if (CheckSavegameVersion(83)) { + for (TileIndex t = 0; t < map_size; t++) { + if (IsTileType(t, MP_WATER) && IsShipDepot(t)) { + _m[t].m4 = (TileHeight(t) == 0) ? OWNER_WATER : OWNER_NONE; + } + } + } + + if (CheckSavegameVersion(74)) { + Station *st; + FOR_ALL_STATIONS(st) { + for (CargoID c = 0; c < NUM_CARGO; c++) { + st->goods[c].last_speed = 0; + if (st->goods[c].cargo.Count() != 0) SetBit(st->goods[c].acceptance_pickup, GoodsEntry::PICKUP); + } + } + } + + if (CheckSavegameVersion(78)) { + Industry *i; + uint j; + FOR_ALL_INDUSTRIES(i) { + const IndustrySpec *indsp = GetIndustrySpec(i->type); + for (j = 0; j < lengthof(i->produced_cargo); j++) { + i->produced_cargo[j] = indsp->produced_cargo[j]; + } + for (j = 0; j < lengthof(i->accepts_cargo); j++) { + i->accepts_cargo[j] = indsp->accepts_cargo[j]; + } + } + } + + /* Before version 81, the density of grass was always stored as zero, and + * grassy trees were always drawn fully grassy. Furthermore, trees on rough + * land used to have zero density, now they have full density. Therefore, + * make all grassy/rough land trees have a density of 3. */ + if (CheckSavegameVersion(81)) { + for (TileIndex t = 0; t < map_size; t++) { + if (GetTileType(t) == MP_TREES) { + TreeGround groundType = GetTreeGround(t); + if (groundType != TREE_GROUND_SNOW_DESERT) SetTreeGroundDensity(t, groundType, 3); + } + } + } + + + if (CheckSavegameVersion(93)) { + /* Rework of orders. */ + Order *order; + FOR_ALL_ORDERS(order) order->ConvertFromOldSavegame(); + + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->orders.list != NULL && v->orders.list->GetFirstOrder() != NULL && !v->orders.list->GetFirstOrder()->IsValid()) { + v->orders.list->FreeChain(); + v->orders.list = NULL; + } + + v->current_order.ConvertFromOldSavegame(); + if (v->type == VEH_ROAD && v->IsPrimaryVehicle() && v->FirstShared() == v) { + FOR_VEHICLE_ORDERS(v, order) order->SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); + } + } + } else if (CheckSavegameVersion(94)) { + /* Unload and transfer are now mutual exclusive. */ + Order *order; + FOR_ALL_ORDERS(order) { + if ((order->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == (OUFB_UNLOAD | OUFB_TRANSFER)) { + order->SetUnloadType(OUFB_TRANSFER); + order->SetLoadType(OLFB_NO_LOAD); + } + } + + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if ((v->current_order.GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == (OUFB_UNLOAD | OUFB_TRANSFER)) { + v->current_order.SetUnloadType(OUFB_TRANSFER); + v->current_order.SetLoadType(OLFB_NO_LOAD); + } + } + } + + if (CheckSavegameVersion(84)) { + /* Update go to buoy orders because they are just waypoints */ + Order *order; + FOR_ALL_ORDERS(order) { + if (order->IsType(OT_GOTO_STATION) && GetStation(order->GetDestination())->IsBuoy()) { + order->SetLoadType(OLF_LOAD_IF_POSSIBLE); + order->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE); + } + } + + /* Set all share owners to INVALID_COMPANY for + * 1) all inactive companies + * (when inactive companies were stored in the savegame - TTD, TTDP and some + * *really* old revisions of OTTD; else it is already set in InitializeCompanies()) + * 2) shares that are owned by inactive companies or self + * (caused by cheating clients in earlier revisions) */ + FOR_ALL_COMPANIES(c) { + for (uint i = 0; i < 4; i++) { + CompanyID company = c->share_owners[i]; + if (company == INVALID_COMPANY) continue; + if (!IsValidCompanyID(company) || company == c->index) c->share_owners[i] = INVALID_COMPANY; + } + } + } + + if (CheckSavegameVersion(86)) { + for (TileIndex t = 0; t < map_size; t++) { + /* Move river flag and update canals to use water class */ + if (IsTileType(t, MP_WATER)) { + if (GetWaterClass(t) != WATER_CLASS_RIVER) { + if (IsWater(t)) { + Owner o = GetTileOwner(t); + if (o == OWNER_WATER) { + MakeWater(t); + } else { + MakeCanal(t, o, Random()); + } + } else if (IsShipDepot(t)) { + Owner o = (Owner)_m[t].m4; // Original water owner + SetWaterClass(t, o == OWNER_WATER ? WATER_CLASS_SEA : WATER_CLASS_CANAL); + } + } + } + } + + /* Update locks, depots, docks and buoys to have a water class based + * on its neighbouring tiles. Done after river and canal updates to + * ensure neighbours are correct. */ + for (TileIndex t = 0; t < map_size; t++) { + if (GetTileSlope(t, NULL) != SLOPE_FLAT) continue; + + if (IsTileType(t, MP_WATER) && IsLock(t)) SetWaterClassDependingOnSurroundings(t, false); + if (IsTileType(t, MP_STATION) && (IsDock(t) || IsBuoy(t))) SetWaterClassDependingOnSurroundings(t, false); + } + } + + if (CheckSavegameVersion(87)) { + for (TileIndex t = 0; t < map_size; t++) { + /* skip oil rigs at borders! */ + if ((IsTileType(t, MP_WATER) || IsBuoyTile(t)) && + (TileX(t) == 0 || TileY(t) == 0 || TileX(t) == MapMaxX() - 1 || TileY(t) == MapMaxY() - 1)) { + /* Some version 86 savegames have wrong water class at map borders (under buoy, or after removing buoy). + * This conversion has to be done before buoys with invalid owner are removed. */ + SetWaterClass(t, WATER_CLASS_SEA); + } + + if (IsBuoyTile(t) || IsDriveThroughStopTile(t) || IsTileType(t, MP_WATER)) { + Owner o = GetTileOwner(t); + if (o < MAX_COMPANIES && !IsValidCompanyID(o)) { + _current_company = o; + ChangeTileOwner(t, o, INVALID_OWNER); + } + if (IsBuoyTile(t)) { + /* reset buoy owner to OWNER_NONE in the station struct + * (even if it is owned by active company) */ + GetStationByTile(t)->owner = OWNER_NONE; + } + } else if (IsTileType(t, MP_ROAD)) { + /* works for all RoadTileType */ + for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { + /* update even non-existing road types to update tile owner too */ + Owner o = GetRoadOwner(t, rt); + if (o < MAX_COMPANIES && !IsValidCompanyID(o)) SetRoadOwner(t, rt, OWNER_NONE); + } + if (IsLevelCrossing(t)) { + Owner o = GetTileOwner(t); + if (!IsValidCompanyID(o)) { + /* remove leftover rail piece from crossing (from very old savegames) */ + _current_company = o; + DoCommand(t, 0, GetCrossingRailTrack(t), DC_EXEC | DC_BANKRUPT, CMD_REMOVE_SINGLE_RAIL); + } + } + } + } + + /* Convert old PF settings to new */ + if (_settings_game.pf.yapf.rail_use_yapf || CheckSavegameVersion(28)) { + _settings_game.pf.pathfinder_for_trains = VPF_YAPF; + } else { + _settings_game.pf.pathfinder_for_trains = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_NTP); + } + + if (_settings_game.pf.yapf.road_use_yapf || CheckSavegameVersion(28)) { + _settings_game.pf.pathfinder_for_roadvehs = VPF_YAPF; + } else { + _settings_game.pf.pathfinder_for_roadvehs = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_OPF); + } + + if (_settings_game.pf.yapf.ship_use_yapf) { + _settings_game.pf.pathfinder_for_ships = VPF_YAPF; + } else { + _settings_game.pf.pathfinder_for_ships = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_OPF); + } + } + + if (CheckSavegameVersion(88)) { + /* Profits are now with 8 bit fract */ + Vehicle *v; + FOR_ALL_VEHICLES(v) { + v->profit_this_year <<= 8; + v->profit_last_year <<= 8; + v->running_ticks = 0; + } + } + + if (CheckSavegameVersion(91)) { + /* Increase HouseAnimationFrame from 5 to 7 bits */ + for (TileIndex t = 0; t < map_size; t++) { + if (IsTileType(t, MP_HOUSE) && GetHouseType(t) >= NEW_HOUSE_OFFSET) { + SetHouseAnimationFrame(t, GB(_m[t].m6, 3, 5)); + } + } + } + + if (CheckSavegameVersion(62)) { + /* Remove all trams from savegames without tram support. + * There would be trams without tram track under causing crashes sooner or later. */ + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_ROAD && v->First() == v && + HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM)) { + if (_switch_mode_errorstr == INVALID_STRING_ID || _switch_mode_errorstr == STR_NEWGRF_COMPATIBLE_LOAD_WARNING) { + _switch_mode_errorstr = STR_LOADGAME_REMOVED_TRAMS; + } + delete v; + } + } + } + + if (CheckSavegameVersion(99)) { + for (TileIndex t = 0; t < map_size; t++) { + /* Set newly introduced WaterClass of industry tiles */ + if (IsTileType(t, MP_STATION) && IsOilRig(t)) { + SetWaterClassDependingOnSurroundings(t, true); + } + if (IsTileType(t, MP_INDUSTRY)) { + if ((GetIndustrySpec(GetIndustryType(t))->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) { + SetWaterClassDependingOnSurroundings(t, true); + } else { + SetWaterClass(t, WATER_CLASS_INVALID); + } + } + + /* Replace "house construction year" with "house age" */ + if (IsTileType(t, MP_HOUSE) && IsHouseCompleted(t)) { + _m[t].m5 = Clamp(_cur_year - (_m[t].m5 + ORIGINAL_BASE_YEAR), 0, 0xFF); + } + } + } + + /* Move the signal variant back up one bit for PBS. We don't convert the old PBS + * format here, as an old layout wouldn't work properly anyway. To be safe, we + * clear any possible PBS reservations as well. */ + if (CheckSavegameVersion(100)) { + for (TileIndex t = 0; t < map_size; t++) { + switch (GetTileType(t)) { + case MP_RAILWAY: + if (HasSignals(t)) { + /* move the signal variant */ + SetSignalVariant(t, TRACK_UPPER, HasBit(_m[t].m2, 2) ? SIG_SEMAPHORE : SIG_ELECTRIC); + SetSignalVariant(t, TRACK_LOWER, HasBit(_m[t].m2, 6) ? SIG_SEMAPHORE : SIG_ELECTRIC); + ClrBit(_m[t].m2, 2); + ClrBit(_m[t].m2, 6); + } + + /* Clear PBS reservation on track */ + if (IsRailDepot(t) ||IsRailWaypoint(t)) { + SetDepotWaypointReservation(t, false); + } else { + SetTrackReservation(t, TRACK_BIT_NONE); + } + break; + + case MP_ROAD: /* Clear PBS reservation on crossing */ + if (IsLevelCrossing(t)) SetCrossingReservation(t, false); + break; + + case MP_STATION: /* Clear PBS reservation on station */ + if (IsRailwayStation(t)) SetRailwayStationReservation(t, false); + break; + + case MP_TUNNELBRIDGE: /* Clear PBS reservation on tunnels/birdges */ + if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) SetTunnelBridgeReservation(t, false); + break; + + default: break; + } + } + } + + /* Reserve all tracks trains are currently on. */ + if (CheckSavegameVersion(101)) { + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_TRAIN) { + if ((v->u.rail.track & TRACK_BIT_WORMHOLE) == TRACK_BIT_WORMHOLE) { + TryReserveRailTrack(v->tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(v->tile))); + } else if ((v->u.rail.track & TRACK_BIT_MASK) != TRACK_BIT_NONE) { + TryReserveRailTrack(v->tile, TrackBitsToTrack(v->u.rail.track)); + } + } + } + + /* Give owners to waypoints, based on rail tracks it is sitting on. + * If none is available, specify OWNER_NONE */ + Waypoint *wp; + FOR_ALL_WAYPOINTS(wp) { + Owner owner = (IsRailWaypointTile(wp->xy) ? GetTileOwner(wp->xy) : OWNER_NONE); + wp->owner = IsValidCompanyID(owner) ? owner : OWNER_NONE; + } + } + + if (CheckSavegameVersion(102)) { + for (TileIndex t = 0; t < map_size; t++) { + /* Now all crossings should be in correct state */ + if (IsLevelCrossingTile(t)) UpdateLevelCrossing(t, false); + } + } + + if (CheckSavegameVersion(103)) { + /* Non-town-owned roads now store the closest town */ + UpdateNearestTownForRoadTiles(false); + + /* signs with invalid owner left from older savegames */ + Sign *si; + FOR_ALL_SIGNS(si) { + if (si->owner != OWNER_NONE && !IsValidCompanyID(si->owner)) si->owner = OWNER_NONE; + } + + /* Station can get named based on an industry type, but the current ones + * are not, so mark them as if they are not named by an industry. */ + Station *st; + FOR_ALL_STATIONS(st) { + st->indtype = IT_INVALID; + } + } + + if (CheckSavegameVersion(104)) { + Vehicle *v; + FOR_ALL_VEHICLES(v) { + /* Set engine_type of shadow and rotor */ + if (v->type == VEH_AIRCRAFT && !IsNormalAircraft(v)) { + v->engine_type = v->First()->engine_type; + } + } + + /* More companies ... */ + Company *c; + FOR_ALL_COMPANIES(c) { + if (c->bankrupt_asked == 0xFF) c->bankrupt_asked = 0xFFFF; + } + + Engine *e; + FOR_ALL_ENGINES(e) { + if (e->company_avail == 0xFF) e->company_avail = 0xFFFF; + } + + Town *t; + FOR_ALL_TOWNS(t) { + if (t->have_ratings == 0xFF) t->have_ratings = 0xFFFF; + for (uint i = 8; i != MAX_COMPANIES; i++) t->ratings[i] = RATING_INITIAL; + } + } + + GamelogPrintDebug(1); + + bool ret = InitializeWindowsAndCaches(); + /* Restore the signals */ + signal(SIGSEGV, prev_segfault); + signal(SIGABRT, prev_abort); + return ret; +} + +/** Reload all NewGRF files during a running game. This is a cut-down + * version of AfterLoadGame(). + * XXX - We need to reset the vehicle position hash because with a non-empty + * hash AfterLoadVehicles() will loop infinitely. We need AfterLoadVehicles() + * to recalculate vehicle data as some NewGRF vehicle sets could have been + * removed or added and changed statistics */ +void ReloadNewGRFData() +{ + /* reload grf data */ + GfxLoadSprites(); + LoadStringWidthTable(); + ResetEconomy(); + /* reload vehicles */ + ResetVehiclePosHash(); + AfterLoadVehicles(false); + StartupEngines(); + SetCachedEngineCounts(); + /* update station and waypoint graphics */ + AfterLoadWaypoints(); + AfterLoadStations(); + /* Check and update house and town values */ + UpdateHousesAndTowns(); + /* Update livery selection windows */ + for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) InvalidateWindowData(WC_COMPANY_COLOR, i, _loaded_newgrf_features.has_2CC); + /* redraw the whole screen */ + MarkWholeScreenDirty(); + CheckTrainsLengths(); +} diff --git a/src/saveload/ai_sl.cpp b/src/saveload/ai_sl.cpp new file mode 100644 index 000000000..b4d16a6b5 --- /dev/null +++ b/src/saveload/ai_sl.cpp @@ -0,0 +1,79 @@ +/* $Id$ */ + +/** @file ai_sl.cpp Code handling saving and loading of old AI + new AI initialisation after game load */ + +#include "../stdafx.h" +#include "../ai/ai.h" +#include "../ai/default/default.h" + +#include "saveload.h" + +static const SaveLoad _company_ai_desc[] = { + SLE_VAR(CompanyAI, state, SLE_UINT8), + SLE_VAR(CompanyAI, tick, SLE_UINT8), + SLE_CONDVAR(CompanyAI, state_counter, SLE_FILE_U16 | SLE_VAR_U32, 0, 12), + SLE_CONDVAR(CompanyAI, state_counter, SLE_UINT32, 13, SL_MAX_VERSION), + SLE_VAR(CompanyAI, timeout_counter, SLE_UINT16), + + SLE_VAR(CompanyAI, state_mode, SLE_UINT8), + SLE_VAR(CompanyAI, banned_tile_count, SLE_UINT8), + SLE_VAR(CompanyAI, railtype_to_use, SLE_UINT8), + + SLE_VAR(CompanyAI, cargo_type, SLE_UINT8), + SLE_VAR(CompanyAI, num_wagons, SLE_UINT8), + SLE_VAR(CompanyAI, build_kind, SLE_UINT8), + SLE_VAR(CompanyAI, num_build_rec, SLE_UINT8), + SLE_VAR(CompanyAI, num_loco_to_build, SLE_UINT8), + SLE_VAR(CompanyAI, num_want_fullload, SLE_UINT8), + + SLE_VAR(CompanyAI, route_type_mask, SLE_UINT8), + + SLE_CONDVAR(CompanyAI, start_tile_a, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(CompanyAI, start_tile_a, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(CompanyAI, cur_tile_a, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(CompanyAI, cur_tile_a, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_VAR(CompanyAI, start_dir_a, SLE_UINT8), + SLE_VAR(CompanyAI, cur_dir_a, SLE_UINT8), + + SLE_CONDVAR(CompanyAI, start_tile_b, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(CompanyAI, start_tile_b, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(CompanyAI, cur_tile_b, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(CompanyAI, cur_tile_b, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_VAR(CompanyAI, start_dir_b, SLE_UINT8), + SLE_VAR(CompanyAI, cur_dir_b, SLE_UINT8), + + SLE_REF(CompanyAI, cur_veh, REF_VEHICLE), + + SLE_ARR(CompanyAI, wagon_list, SLE_UINT16, 9), + SLE_ARR(CompanyAI, order_list_blocks, SLE_UINT8, 20), + SLE_ARR(CompanyAI, banned_tiles, SLE_UINT16, 16), + + SLE_CONDNULL(64, 2, SL_MAX_VERSION), + SLE_END() +}; + +static const SaveLoad _company_ai_build_rec_desc[] = { + SLE_CONDVAR(AiBuildRec, spec_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(AiBuildRec, spec_tile, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(AiBuildRec, use_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(AiBuildRec, use_tile, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_VAR(AiBuildRec, rand_rng, SLE_UINT8), + SLE_VAR(AiBuildRec, cur_building_rule, SLE_UINT8), + SLE_VAR(AiBuildRec, unk6, SLE_UINT8), + SLE_VAR(AiBuildRec, unk7, SLE_UINT8), + SLE_VAR(AiBuildRec, buildcmd_a, SLE_UINT8), + SLE_VAR(AiBuildRec, buildcmd_b, SLE_UINT8), + SLE_VAR(AiBuildRec, direction, SLE_UINT8), + SLE_VAR(AiBuildRec, cargo, SLE_UINT8), + SLE_END() +}; + + +void SaveLoad_AI(CompanyID company) +{ + CompanyAI *cai = &_companies_ai[company]; + SlObject(cai, _company_ai_desc); + for (int i = 0; i != cai->num_build_rec; i++) { + SlObject(&cai->src + i, _company_ai_build_rec_desc); + } +} diff --git a/src/saveload/animated_tile_sl.cpp b/src/saveload/animated_tile_sl.cpp new file mode 100644 index 000000000..ba3f519db --- /dev/null +++ b/src/saveload/animated_tile_sl.cpp @@ -0,0 +1,56 @@ +/* $Id$ */ + +/** @file animated_tile_sl.cpp Code handling saving and loading of animated tiles */ + +#include "../stdafx.h" +#include "../tile_type.h" +#include "../core/alloc_func.hpp" + +#include "saveload.h" + +extern TileIndex *_animated_tile_list; +extern uint _animated_tile_count; +extern uint _animated_tile_allocated; + +/** + * Save the ANIT chunk. + */ +static void Save_ANIT() +{ + SlSetLength(_animated_tile_count * sizeof(*_animated_tile_list)); + SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32); +} + +/** + * Load the ANIT chunk; the chunk containing the animated tiles. + */ +static void Load_ANIT() +{ + /* Before version 80 we did NOT have a variable length animated tile table */ + if (CheckSavegameVersion(80)) { + /* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */ + SlArray(_animated_tile_list, 256, CheckSavegameVersion(6) ? (SLE_FILE_U16 | SLE_VAR_U32) : SLE_UINT32); + + for (_animated_tile_count = 0; _animated_tile_count < 256; _animated_tile_count++) { + if (_animated_tile_list[_animated_tile_count] == 0) break; + } + return; + } + + _animated_tile_count = (uint)SlGetFieldLength() / sizeof(*_animated_tile_list); + + /* Determine a nice rounded size for the amount of allocated tiles */ + _animated_tile_allocated = 256; + while (_animated_tile_allocated < _animated_tile_count) _animated_tile_allocated *= 2; + + _animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, _animated_tile_allocated); + SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32); +} + +/** + * "Definition" imported by the saveload code to be able to load and save + * the animated tile table. + */ +extern const ChunkHandler _animated_tile_chunk_handlers[] = { + { 'ANIT', Save_ANIT, Load_ANIT, CH_RIFF | CH_LAST}, +}; diff --git a/src/saveload/autoreplace_sl.cpp b/src/saveload/autoreplace_sl.cpp new file mode 100644 index 000000000..d24c290a8 --- /dev/null +++ b/src/saveload/autoreplace_sl.cpp @@ -0,0 +1,51 @@ +/* $Id$ */ + +/** @file autoreplace_sl.cpp Code handling saving and loading of autoreplace rules */ + +#include "../stdafx.h" +#include "../autoreplace_type.h" +#include "../engine_type.h" +#include "../group_type.h" +#include "../autoreplace_base.h" + +#include "saveload.h" + +static const SaveLoad _engine_renew_desc[] = { + SLE_VAR(EngineRenew, from, SLE_UINT16), + SLE_VAR(EngineRenew, to, SLE_UINT16), + + SLE_REF(EngineRenew, next, REF_ENGINE_RENEWS), + SLE_CONDVAR(EngineRenew, group_id, SLE_UINT16, 60, SL_MAX_VERSION), + SLE_END() +}; + +static void Save_ERNW() +{ + EngineRenew *er; + + FOR_ALL_ENGINE_RENEWS(er) { + SlSetArrayIndex(er->index); + SlObject(er, _engine_renew_desc); + } +} + +static void Load_ERNW() +{ + int index; + + while ((index = SlIterateArray()) != -1) { + EngineRenew *er = new (index) EngineRenew(); + SlObject(er, _engine_renew_desc); + + /* Advanced vehicle lists, ungrouped vehicles got added */ + if (CheckSavegameVersion(60)) { + er->group_id = ALL_GROUP; + } else if (CheckSavegameVersion(71)) { + if (er->group_id == DEFAULT_GROUP) er->group_id = ALL_GROUP; + } + } +} + +extern const ChunkHandler _autoreplace_chunk_handlers[] = { + { 'ERNW', Save_ERNW, Load_ERNW, CH_ARRAY | CH_LAST}, +}; diff --git a/src/saveload/cargopacket_sl.cpp b/src/saveload/cargopacket_sl.cpp new file mode 100644 index 000000000..d38e4e22e --- /dev/null +++ b/src/saveload/cargopacket_sl.cpp @@ -0,0 +1,45 @@ +/* $Id$ */ + +/** @file cargopacket_sl.cpp Code handling saving and loading of cargo packets */ + +#include "../stdafx.h" +#include "../openttd.h" +#include "../cargopacket.h" + +#include "saveload.h" + +static const SaveLoad _cargopacket_desc[] = { + SLE_VAR(CargoPacket, source, SLE_UINT16), + SLE_VAR(CargoPacket, source_xy, SLE_UINT32), + SLE_VAR(CargoPacket, loaded_at_xy, SLE_UINT32), + SLE_VAR(CargoPacket, count, SLE_UINT16), + SLE_VAR(CargoPacket, days_in_transit, SLE_UINT8), + SLE_VAR(CargoPacket, feeder_share, SLE_INT64), + SLE_VAR(CargoPacket, paid_for, SLE_BOOL), + + SLE_END() +}; + +static void Save_CAPA() +{ + CargoPacket *cp; + + FOR_ALL_CARGOPACKETS(cp) { + SlSetArrayIndex(cp->index); + SlObject(cp, _cargopacket_desc); + } +} + +static void Load_CAPA() +{ + int index; + + while ((index = SlIterateArray()) != -1) { + CargoPacket *cp = new (index) CargoPacket(); + SlObject(cp, _cargopacket_desc); + } +} + +extern const ChunkHandler _cargopacket_chunk_handlers[] = { + { 'CAPA', Save_CAPA, Load_CAPA, CH_ARRAY | CH_LAST}, +}; diff --git a/src/saveload/cheat_sl.cpp b/src/saveload/cheat_sl.cpp new file mode 100644 index 000000000..a8c939fed --- /dev/null +++ b/src/saveload/cheat_sl.cpp @@ -0,0 +1,37 @@ +/* $Id$ */ + +/** @file cheat_sl.cpp Code handling saving and loading of cheats */ + +#include "../stdafx.h" +#include "../cheat_type.h" + +#include "saveload.h" + +static void Save_CHTS() +{ + /* Cannot use lengthof because _cheats is of type Cheats, not Cheat */ + byte count = sizeof(_cheats) / sizeof(Cheat); + Cheat *cht = (Cheat*) &_cheats; + Cheat *cht_last = &cht[count]; + + SlSetLength(count * 2); + for (; cht != cht_last; cht++) { + SlWriteByte(cht->been_used); + SlWriteByte(cht->value); + } +} + +static void Load_CHTS() +{ + Cheat *cht = (Cheat*)&_cheats; + size_t count = SlGetFieldLength() / 2; + + for (uint i = 0; i < count; i++) { + cht[i].been_used = (SlReadByte() != 0); + cht[i].value = (SlReadByte() != 0); + } +} + +extern const ChunkHandler _cheat_chunk_handlers[] = { + { 'CHTS', Save_CHTS, Load_CHTS, CH_RIFF | CH_LAST} +}; diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp new file mode 100644 index 000000000..933cc0bde --- /dev/null +++ b/src/saveload/company_sl.cpp @@ -0,0 +1,240 @@ +/* $Id$ */ + +/** @file company_sl.cpp Code handling saving and loading of company data */ + +#include "../stdafx.h" +#include "../company_base.h" +#include "../company_func.h" +#include "../network/network.h" +#include "../ai/ai.h" +#include "../ai/trolly/trolly.h" +#include "../company_manager_face.h" + +#include "saveload.h" + +/** + * Converts an old company manager's face format to the new company manager's face format + * + * Meaning of the bits in the old face (some bits are used in several times): + * - 4 and 5: chin + * - 6 to 9: eyebrows + * - 10 to 13: nose + * - 13 to 15: lips (also moustache for males) + * - 16 to 19: hair + * - 20 to 22: eye color + * - 20 to 27: tie, ear rings etc. + * - 28 to 30: glasses + * - 19, 26 and 27: race (bit 27 set and bit 19 equal to bit 26 = black, otherwise white) + * - 31: gender (0 = male, 1 = female) + * + * @param face the face in the old format + * @return the face in the new format + */ +CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32 face) +{ + CompanyManagerFace cmf = 0; + GenderEthnicity ge = GE_WM; + + if (HasBit(face, 31)) SetBit(ge, GENDER_FEMALE); + if (HasBit(face, 27) && (HasBit(face, 26) == HasBit(face, 19))) SetBit(ge, ETHNICITY_BLACK); + + SetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, ge, ge); + SetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge, GB(face, 28, 3) <= 1); + SetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR, ge, HasBit(ge, ETHNICITY_BLACK) ? 0 : ClampU(GB(face, 20, 3), 5, 7) - 5); + SetCompanyManagerFaceBits(cmf, CMFV_CHIN, ge, ScaleCompanyManagerFaceValue(CMFV_CHIN, ge, GB(face, 4, 2))); + SetCompanyManagerFaceBits(cmf, CMFV_EYEBROWS, ge, ScaleCompanyManagerFaceValue(CMFV_EYEBROWS, ge, GB(face, 6, 4))); + SetCompanyManagerFaceBits(cmf, CMFV_HAIR, ge, ScaleCompanyManagerFaceValue(CMFV_HAIR, ge, GB(face, 16, 4))); + SetCompanyManagerFaceBits(cmf, CMFV_JACKET, ge, ScaleCompanyManagerFaceValue(CMFV_JACKET, ge, GB(face, 20, 2))); + SetCompanyManagerFaceBits(cmf, CMFV_COLLAR, ge, ScaleCompanyManagerFaceValue(CMFV_COLLAR, ge, GB(face, 22, 2))); + SetCompanyManagerFaceBits(cmf, CMFV_GLASSES, ge, GB(face, 28, 1)); + + uint lips = GB(face, 10, 4); + if (!HasBit(ge, GENDER_FEMALE) && lips < 4) { + SetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE, ge, true); + SetCompanyManagerFaceBits(cmf, CMFV_MOUSTACHE, ge, max(lips, 1U) - 1); + } else { + if (!HasBit(ge, GENDER_FEMALE)) { + lips = lips * 15 / 16; + lips -= 3; + if (HasBit(ge, ETHNICITY_BLACK) && lips > 8) lips = 0; + } else { + lips = ScaleCompanyManagerFaceValue(CMFV_LIPS, ge, lips); + } + SetCompanyManagerFaceBits(cmf, CMFV_LIPS, ge, lips); + + uint nose = GB(face, 13, 3); + if (ge == GE_WF) { + nose = (nose * 3 >> 3) * 3 >> 2; // There is 'hole' in the nose sprites for females + } else { + nose = ScaleCompanyManagerFaceValue(CMFV_NOSE, ge, nose); + } + SetCompanyManagerFaceBits(cmf, CMFV_NOSE, ge, nose); + } + + uint tie_earring = GB(face, 24, 4); + if (!HasBit(ge, GENDER_FEMALE) || tie_earring < 3) { // Not all females have an earring + if (HasBit(ge, GENDER_FEMALE)) SetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge, true); + SetCompanyManagerFaceBits(cmf, CMFV_TIE_EARRING, ge, HasBit(ge, GENDER_FEMALE) ? tie_earring : ScaleCompanyManagerFaceValue(CMFV_TIE_EARRING, ge, tie_earring / 2)); + } + + return cmf; +} + + + +/* Save/load of companies */ +static const SaveLoad _company_desc[] = { + SLE_VAR(Company, name_2, SLE_UINT32), + SLE_VAR(Company, name_1, SLE_STRINGID), + SLE_CONDSTR(Company, name, SLE_STR, 0, 84, SL_MAX_VERSION), + + SLE_VAR(Company, president_name_1, SLE_UINT16), + SLE_VAR(Company, president_name_2, SLE_UINT32), + SLE_CONDSTR(Company, president_name, SLE_STR, 0, 84, SL_MAX_VERSION), + + SLE_VAR(Company, face, SLE_UINT32), + + /* money was changed to a 64 bit field in savegame version 1. */ + SLE_CONDVAR(Company, money, SLE_VAR_I64 | SLE_FILE_I32, 0, 0), + SLE_CONDVAR(Company, money, SLE_INT64, 1, SL_MAX_VERSION), + + SLE_CONDVAR(Company, current_loan, SLE_VAR_I64 | SLE_FILE_I32, 0, 64), + SLE_CONDVAR(Company, current_loan, SLE_INT64, 65, SL_MAX_VERSION), + + SLE_VAR(Company, colour, SLE_UINT8), + SLE_VAR(Company, money_fraction, SLE_UINT8), + SLE_CONDVAR(Company, avail_railtypes, SLE_UINT8, 0, 57), + SLE_VAR(Company, block_preview, SLE_UINT8), + + SLE_CONDVAR(Company, cargo_types, SLE_FILE_U16 | SLE_VAR_U32, 0, 93), + SLE_CONDVAR(Company, cargo_types, SLE_UINT32, 94, SL_MAX_VERSION), + SLE_CONDVAR(Company, location_of_HQ, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Company, location_of_HQ, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(Company, last_build_coordinate, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Company, last_build_coordinate, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(Company, inaugurated_year, SLE_FILE_U8 | SLE_VAR_I32, 0, 30), + SLE_CONDVAR(Company, inaugurated_year, SLE_INT32, 31, SL_MAX_VERSION), + + SLE_ARR(Company, share_owners, SLE_UINT8, 4), + + SLE_VAR(Company, num_valid_stat_ent, SLE_UINT8), + + SLE_VAR(Company, quarters_of_bankrupcy, SLE_UINT8), + SLE_CONDVAR(Company, bankrupt_asked, SLE_FILE_U8 | SLE_VAR_U16, 0, 103), + SLE_CONDVAR(Company, bankrupt_asked, SLE_UINT16, 104, SL_MAX_VERSION), + SLE_VAR(Company, bankrupt_timeout, SLE_INT16), + SLE_CONDVAR(Company, bankrupt_value, SLE_VAR_I64 | SLE_FILE_I32, 0, 64), + SLE_CONDVAR(Company, bankrupt_value, SLE_INT64, 65, SL_MAX_VERSION), + + /* yearly expenses was changed to 64-bit in savegame version 2. */ + SLE_CONDARR(Company, yearly_expenses, SLE_FILE_I32 | SLE_VAR_I64, 3 * 13, 0, 1), + SLE_CONDARR(Company, yearly_expenses, SLE_INT64, 3 * 13, 2, SL_MAX_VERSION), + + SLE_CONDVAR(Company, is_ai, SLE_BOOL, 2, SL_MAX_VERSION), + SLE_CONDNULL(1, 4, 99), + + /* Engine renewal settings */ + SLE_CONDNULL(512, 16, 18), + SLE_CONDREF(Company, engine_renew_list, REF_ENGINE_RENEWS, 19, SL_MAX_VERSION), + SLE_CONDVAR(Company, engine_renew, SLE_BOOL, 16, SL_MAX_VERSION), + SLE_CONDVAR(Company, engine_renew_months, SLE_INT16, 16, SL_MAX_VERSION), + SLE_CONDVAR(Company, engine_renew_money, SLE_UINT32, 16, SL_MAX_VERSION), + SLE_CONDVAR(Company, renew_keep_length, SLE_BOOL, 2, SL_MAX_VERSION), // added with 16.1, but was blank since 2 + + /* reserve extra space in savegame here. (currently 63 bytes) */ + SLE_CONDNULL(63, 2, SL_MAX_VERSION), + + SLE_END() +}; + +static const SaveLoad _company_economy_desc[] = { + /* these were changed to 64-bit in savegame format 2 */ + SLE_CONDVAR(CompanyEconomyEntry, income, SLE_FILE_I32 | SLE_VAR_I64, 0, 1), + SLE_CONDVAR(CompanyEconomyEntry, income, SLE_INT64, 2, SL_MAX_VERSION), + SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_FILE_I32 | SLE_VAR_I64, 0, 1), + SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_INT64, 2, SL_MAX_VERSION), + SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_FILE_I32 | SLE_VAR_I64, 0, 1), + SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_INT64, 2, SL_MAX_VERSION), + + SLE_VAR(CompanyEconomyEntry, delivered_cargo, SLE_INT32), + SLE_VAR(CompanyEconomyEntry, performance_history, SLE_INT32), + + SLE_END() +}; + +static const SaveLoad _company_livery_desc[] = { + SLE_CONDVAR(Livery, in_use, SLE_BOOL, 34, SL_MAX_VERSION), + SLE_CONDVAR(Livery, colour1, SLE_UINT8, 34, SL_MAX_VERSION), + SLE_CONDVAR(Livery, colour2, SLE_UINT8, 34, SL_MAX_VERSION), + SLE_END() +}; + +static void SaveLoad_PLYR(Company *c) +{ + int i; + + SlObject(c, _company_desc); + + /* Write AI? */ + if (!IsHumanCompany(c->index)) { + extern void SaveLoad_AI(CompanyID company); + SaveLoad_AI(c->index); + } + + /* Write economy */ + SlObject(&c->cur_economy, _company_economy_desc); + + /* Write old economy entries. */ + for (i = 0; i < c->num_valid_stat_ent; i++) { + SlObject(&c->old_economy[i], _company_economy_desc); + } + + /* Write each livery entry. */ + int num_liveries = CheckSavegameVersion(63) ? LS_END - 4 : (CheckSavegameVersion(85) ? LS_END - 2: LS_END); + for (i = 0; i < num_liveries; i++) { + SlObject(&c->livery[i], _company_livery_desc); + } + + if (num_liveries < LS_END) { + /* We want to insert some liveries somewhere in between. This means some have to be moved. */ + memmove(&c->livery[LS_FREIGHT_WAGON], &c->livery[LS_PASSENGER_WAGON_MONORAIL], (LS_END - LS_FREIGHT_WAGON) * sizeof(c->livery[0])); + c->livery[LS_PASSENGER_WAGON_MONORAIL] = c->livery[LS_MONORAIL]; + c->livery[LS_PASSENGER_WAGON_MAGLEV] = c->livery[LS_MAGLEV]; + } + + if (num_liveries == LS_END - 4) { + /* Copy bus/truck liveries over to trams */ + c->livery[LS_PASSENGER_TRAM] = c->livery[LS_BUS]; + c->livery[LS_FREIGHT_TRAM] = c->livery[LS_TRUCK]; + } +} + +static void Save_PLYR() +{ + Company *c; + FOR_ALL_COMPANIES(c) { + SlSetArrayIndex(c->index); + SlAutolength((AutolengthProc*)SaveLoad_PLYR, c); + } +} + +static void Load_PLYR() +{ + int index; + while ((index = SlIterateArray()) != -1) { + Company *c = new (index) Company(); + SaveLoad_PLYR(c); + _company_colours[index] = c->colour; + + /* This is needed so an AI is attached to a loaded AI */ + if (c->is_ai && (!_networking || _network_server) && _ai.enabled) { + /* Clear the memory of the new AI, otherwise we might be doing wrong things. */ + memset(&_companies_ainew[index], 0, sizeof(CompanyAiNew)); + AI_StartNewAI(c->index); + } + } +} + +extern const ChunkHandler _company_chunk_handlers[] = { + { 'PLYR', Save_PLYR, Load_PLYR, CH_ARRAY | CH_LAST}, +}; diff --git a/src/saveload/depot_sl.cpp b/src/saveload/depot_sl.cpp new file mode 100644 index 000000000..fb546ef73 --- /dev/null +++ b/src/saveload/depot_sl.cpp @@ -0,0 +1,39 @@ +/* $Id$ */ + +/** @file depot_sl.cpp Code handling saving and loading of depots */ + +#include "../stdafx.h" +#include "../depot_base.h" + +#include "saveload.h" + +static const SaveLoad _depot_desc[] = { + SLE_CONDVAR(Depot, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Depot, xy, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_VAR(Depot, town_index, SLE_UINT16), + SLE_END() +}; + +static void Save_DEPT() +{ + Depot *depot; + + FOR_ALL_DEPOTS(depot) { + SlSetArrayIndex(depot->index); + SlObject(depot, _depot_desc); + } +} + +static void Load_DEPT() +{ + int index; + + while ((index = SlIterateArray()) != -1) { + Depot *depot = new (index) Depot(); + SlObject(depot, _depot_desc); + } +} + +extern const ChunkHandler _depot_chunk_handlers[] = { + { 'DEPT', Save_DEPT, Load_DEPT, CH_ARRAY | CH_LAST}, +}; diff --git a/src/saveload/economy_sl.cpp b/src/saveload/economy_sl.cpp new file mode 100644 index 000000000..99f306f52 --- /dev/null +++ b/src/saveload/economy_sl.cpp @@ -0,0 +1,58 @@ +/* $Id$ */ + +/** @file economy_sl.cpp Code handling saving and loading of economy data */ + +#include "../stdafx.h" +#include "../economy_func.h" + +#include "saveload.h" + +/** Prices */ +static void SaveLoad_PRIC() +{ + int vt = CheckSavegameVersion(65) ? (SLE_FILE_I32 | SLE_VAR_I64) : SLE_INT64; + SlArray(&_price, NUM_PRICES, vt); + SlArray(&_price_frac, NUM_PRICES, SLE_UINT16); +} + +/** Cargo payment rates */ +static void SaveLoad_CAPR() +{ + uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO; + int vt = CheckSavegameVersion(65) ? (SLE_FILE_I32 | SLE_VAR_I64) : SLE_INT64; + SlArray(&_cargo_payment_rates, num_cargo, vt); + SlArray(&_cargo_payment_rates_frac, num_cargo, SLE_UINT16); +} + +static const SaveLoad _economy_desc[] = { + SLE_CONDVAR(Economy, max_loan, SLE_FILE_I32 | SLE_VAR_I64, 0, 64), + SLE_CONDVAR(Economy, max_loan, SLE_INT64, 65, SL_MAX_VERSION), + SLE_CONDVAR(Economy, max_loan_unround, SLE_FILE_I32 | SLE_VAR_I64, 0, 64), + SLE_CONDVAR(Economy, max_loan_unround, SLE_INT64, 65, SL_MAX_VERSION), + SLE_CONDVAR(Economy, max_loan_unround_fract, SLE_UINT16, 70, SL_MAX_VERSION), + SLE_VAR(Economy, fluct, SLE_INT16), + SLE_VAR(Economy, interest_rate, SLE_UINT8), + SLE_VAR(Economy, infl_amount, SLE_UINT8), + SLE_VAR(Economy, infl_amount_pr, SLE_UINT8), + SLE_CONDVAR(Economy, industry_daily_change_counter, SLE_UINT32, 102, SL_MAX_VERSION), + SLE_END() +}; + +/** Economy variables */ +static void Save_ECMY() +{ + SlObject(&_economy, _economy_desc); +} + +/** Economy variables */ +static void Load_ECMY() +{ + SlObject(&_economy, _economy_desc); + StartupIndustryDailyChanges(CheckSavegameVersion(102)); // old savegames will need to be initialized +} + +extern const ChunkHandler _economy_chunk_handlers[] = { + { 'PRIC', SaveLoad_PRIC, SaveLoad_PRIC, CH_RIFF | CH_AUTO_LENGTH}, + { 'CAPR', SaveLoad_CAPR, SaveLoad_CAPR, CH_RIFF | CH_AUTO_LENGTH}, + { 'ECMY', Save_ECMY, Load_ECMY, CH_RIFF | CH_LAST}, +}; diff --git a/src/saveload/engine_sl.cpp b/src/saveload/engine_sl.cpp new file mode 100644 index 000000000..6dc47c56a --- /dev/null +++ b/src/saveload/engine_sl.cpp @@ -0,0 +1,118 @@ +/* $Id$ */ + +/** @file engine_sl.cpp Code handling saving and loading of engines */ + +#include "../stdafx.h" +#include "saveload.h" +#include "saveload_internal.h" +#include "../engine_base.h" +#include <map> + +static const SaveLoad _engine_desc[] = { + SLE_CONDVAR(Engine, intro_date, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), + SLE_CONDVAR(Engine, intro_date, SLE_INT32, 31, SL_MAX_VERSION), + SLE_CONDVAR(Engine, age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), + SLE_CONDVAR(Engine, age, SLE_INT32, 31, SL_MAX_VERSION), + SLE_VAR(Engine, reliability, SLE_UINT16), + SLE_VAR(Engine, reliability_spd_dec, SLE_UINT16), + SLE_VAR(Engine, reliability_start, SLE_UINT16), + SLE_VAR(Engine, reliability_max, SLE_UINT16), + SLE_VAR(Engine, reliability_final, SLE_UINT16), + SLE_VAR(Engine, duration_phase_1, SLE_UINT16), + SLE_VAR(Engine, duration_phase_2, SLE_UINT16), + SLE_VAR(Engine, duration_phase_3, SLE_UINT16), + + SLE_VAR(Engine, lifelength, SLE_UINT8), + SLE_VAR(Engine, flags, SLE_UINT8), + SLE_VAR(Engine, preview_company_rank,SLE_UINT8), + SLE_VAR(Engine, preview_wait, SLE_UINT8), + SLE_CONDNULL(1, 0, 44), + SLE_CONDVAR(Engine, company_avail, SLE_FILE_U8 | SLE_VAR_U16, 0, 103), + SLE_CONDVAR(Engine, company_avail, SLE_UINT16, 104, SL_MAX_VERSION), + SLE_CONDSTR(Engine, name, SLE_STR, 0, 84, SL_MAX_VERSION), + + /* reserve extra space in savegame here. (currently 16 bytes) */ + SLE_CONDNULL(16, 2, SL_MAX_VERSION), + + SLE_END() +}; + +static std::map<EngineID, Engine> _temp_engine; + +Engine *GetTempDataEngine(EngineID index) +{ + return &_temp_engine[index]; +} + +static void Save_ENGN() +{ + Engine *e; + FOR_ALL_ENGINES(e) { + SlSetArrayIndex(e->index); + SlObject(e, _engine_desc); + } +} + +static void Load_ENGN() +{ + /* As engine data is loaded before engines are initialized we need to load + * this information into a temporary array. This is then copied into the + * engine pool after processing NewGRFs by CopyTempEngineData(). */ + int index; + while ((index = SlIterateArray()) != -1) { + Engine *e = GetTempDataEngine(index); + SlObject(e, _engine_desc); + } +} + +/** + * Copy data from temporary engine array into the real engine pool. + */ +void CopyTempEngineData() +{ + Engine *e; + FOR_ALL_ENGINES(e) { + if (e->index >= _temp_engine.size()) break; + + const Engine *se = GetTempDataEngine(e->index); + e->intro_date = se->intro_date; + e->age = se->age; + e->reliability = se->reliability; + e->reliability_spd_dec = se->reliability_spd_dec; + e->reliability_start = se->reliability_start; + e->reliability_max = se->reliability_max; + e->reliability_final = se->reliability_final; + e->duration_phase_1 = se->duration_phase_1; + e->duration_phase_2 = se->duration_phase_2; + e->duration_phase_3 = se->duration_phase_3; + e->lifelength = se->lifelength; + e->flags = se->flags; + e->preview_company_rank= se->preview_company_rank; + e->preview_wait = se->preview_wait; + e->company_avail = se->company_avail; + if (se->name != NULL) e->name = strdup(se->name); + } + + /* Get rid of temporary data */ + _temp_engine.clear(); +} + +static void Load_ENGS() +{ + /* Load old separate String ID list into a temporary array. This + * was always 256 entries. */ + StringID names[256]; + + SlArray(names, lengthof(names), SLE_STRINGID); + + /* Copy each string into the temporary engine array. */ + for (EngineID engine = 0; engine < lengthof(names); engine++) { + Engine *e = GetTempDataEngine(engine); + e->name = CopyFromOldName(names[engine]); + } +} + +extern const ChunkHandler _engine_chunk_handlers[] = { + { 'ENGN', Save_ENGN, Load_ENGN, CH_ARRAY }, + { 'ENGS', NULL, Load_ENGS, CH_RIFF | CH_LAST }, +}; diff --git a/src/saveload/gamelog_sl.cpp b/src/saveload/gamelog_sl.cpp new file mode 100644 index 000000000..7364602bb --- /dev/null +++ b/src/saveload/gamelog_sl.cpp @@ -0,0 +1,161 @@ +/* $Id$ */ + +/** @file gamelog_sl.cpp Code handling saving and loading of gamelog data */ + +#include "../stdafx.h" +#include "../gamelog.h" +#include "../gamelog_internal.h" +#include "../core/alloc_func.hpp" + +#include "saveload.h" + +static const SaveLoad _glog_action_desc[] = { + SLE_VAR(LoggedAction, tick, SLE_UINT16), + SLE_END() +}; + +static const SaveLoad _glog_mode_desc[] = { + SLE_VAR(LoggedChange, mode.mode, SLE_UINT8), + SLE_VAR(LoggedChange, mode.landscape, SLE_UINT8), + SLE_END() +}; + +static const SaveLoad _glog_revision_desc[] = { + SLE_ARR(LoggedChange, revision.text, SLE_UINT8, NETWORK_REVISION_LENGTH), + SLE_VAR(LoggedChange, revision.newgrf, SLE_UINT32), + SLE_VAR(LoggedChange, revision.slver, SLE_UINT16), + SLE_VAR(LoggedChange, revision.modified, SLE_UINT8), + SLE_END() +}; + +static const SaveLoad _glog_oldver_desc[] = { + SLE_VAR(LoggedChange, oldver.type, SLE_UINT32), + SLE_VAR(LoggedChange, oldver.version, SLE_UINT32), + SLE_END() +}; + +static const SaveLoad _glog_patch_desc[] = { + SLE_STR(LoggedChange, patch.name, SLE_STR, 128), + SLE_VAR(LoggedChange, patch.oldval, SLE_INT32), + SLE_VAR(LoggedChange, patch.newval, SLE_INT32), + SLE_END() +}; + +static const SaveLoad _glog_grfadd_desc[] = { + SLE_VAR(LoggedChange, grfadd.grfid, SLE_UINT32 ), + SLE_ARR(LoggedChange, grfadd.md5sum, SLE_UINT8, 16), + SLE_END() +}; + +static const SaveLoad _glog_grfrem_desc[] = { + SLE_VAR(LoggedChange, grfrem.grfid, SLE_UINT32), + SLE_END() +}; + +static const SaveLoad _glog_grfcompat_desc[] = { + SLE_VAR(LoggedChange, grfcompat.grfid, SLE_UINT32 ), + SLE_ARR(LoggedChange, grfcompat.md5sum, SLE_UINT8, 16), + SLE_END() +}; + +static const SaveLoad _glog_grfparam_desc[] = { + SLE_VAR(LoggedChange, grfparam.grfid, SLE_UINT32), + SLE_END() +}; + +static const SaveLoad _glog_grfmove_desc[] = { + SLE_VAR(LoggedChange, grfmove.grfid, SLE_UINT32), + SLE_VAR(LoggedChange, grfmove.offset, SLE_INT32), + SLE_END() +}; + +static const SaveLoad _glog_grfbug_desc[] = { + SLE_VAR(LoggedChange, grfbug.data, SLE_UINT64), + SLE_VAR(LoggedChange, grfbug.grfid, SLE_UINT32), + SLE_VAR(LoggedChange, grfbug.bug, SLE_UINT8), + SLE_END() +}; + +static const SaveLoad *_glog_desc[] = { + _glog_mode_desc, + _glog_revision_desc, + _glog_oldver_desc, + _glog_patch_desc, + _glog_grfadd_desc, + _glog_grfrem_desc, + _glog_grfcompat_desc, + _glog_grfparam_desc, + _glog_grfmove_desc, + _glog_grfbug_desc, +}; + +assert_compile(lengthof(_glog_desc) == GLCT_END); + +static void Load_GLOG() +{ + assert(_gamelog_action == NULL); + assert(_gamelog_actions == 0); + + GamelogActionType at; + while ((at = (GamelogActionType)SlReadByte()) != GLAT_NONE) { + _gamelog_action = ReallocT(_gamelog_action, _gamelog_actions + 1); + LoggedAction *la = &_gamelog_action[_gamelog_actions++]; + + la->at = at; + + SlObject(la, _glog_action_desc); // has to be saved after 'DATE'! + la->change = NULL; + la->changes = 0; + + GamelogChangeType ct; + while ((ct = (GamelogChangeType)SlReadByte()) != GLCT_NONE) { + la->change = ReallocT(la->change, la->changes + 1); + + LoggedChange *lc = &la->change[la->changes++]; + /* for SLE_STR, pointer has to be valid! so make it NULL */ + memset(lc, 0, sizeof(*lc)); + lc->ct = ct; + + assert((uint)ct < GLCT_END); + + SlObject(lc, _glog_desc[ct]); + } + } +} + +static void Save_GLOG() +{ + const LoggedAction *laend = &_gamelog_action[_gamelog_actions]; + size_t length = 0; + + for (const LoggedAction *la = _gamelog_action; la != laend; la++) { + const LoggedChange *lcend = &la->change[la->changes]; + for (LoggedChange *lc = la->change; lc != lcend; lc++) { + assert((uint)lc->ct < lengthof(_glog_desc)); + length += SlCalcObjLength(lc, _glog_desc[lc->ct]) + 1; + } + length += 4; + } + length++; + + SlSetLength(length); + + for (LoggedAction *la = _gamelog_action; la != laend; la++) { + SlWriteByte(la->at); + SlObject(la, _glog_action_desc); + + const LoggedChange *lcend = &la->change[la->changes]; + for (LoggedChange *lc = la->change; lc != lcend; lc++) { + SlWriteByte(lc->ct); + assert((uint)lc->ct < GLCT_END); + SlObject(lc, _glog_desc[lc->ct]); + } + SlWriteByte(GLCT_NONE); + } + SlWriteByte(GLAT_NONE); +} + + +extern const ChunkHandler _gamelog_chunk_handlers[] = { + { 'GLOG', Save_GLOG, Load_GLOG, CH_RIFF | CH_LAST } +}; diff --git a/src/saveload/group_sl.cpp b/src/saveload/group_sl.cpp new file mode 100644 index 000000000..66e3585b4 --- /dev/null +++ b/src/saveload/group_sl.cpp @@ -0,0 +1,43 @@ +/* $Id$ */ + +/** @file group_sl.cpp Code handling saving and loading of economy data */ + +#include "../stdafx.h" +#include "../group.h" + +#include "saveload.h" + +static const SaveLoad _group_desc[] = { + SLE_CONDVAR(Group, name, SLE_NAME, 0, 83), + SLE_CONDSTR(Group, name, SLE_STR, 0, 84, SL_MAX_VERSION), + SLE_VAR(Group, num_vehicle, SLE_UINT16), + SLE_VAR(Group, owner, SLE_UINT8), + SLE_VAR(Group, vehicle_type, SLE_UINT8), + SLE_VAR(Group, replace_protection, SLE_BOOL), + SLE_END() +}; + +static void Save_GRPS(void) +{ + Group *g; + + FOR_ALL_GROUPS(g) { + SlSetArrayIndex(g->index); + SlObject(g, _group_desc); + } +} + + +static void Load_GRPS(void) +{ + int index; + + while ((index = SlIterateArray()) != -1) { + Group *g = new (index) Group(); + SlObject(g, _group_desc); + } +} + +extern const ChunkHandler _group_chunk_handlers[] = { + { 'GRPS', Save_GRPS, Load_GRPS, CH_ARRAY | CH_LAST}, +}; diff --git a/src/saveload/industry_sl.cpp b/src/saveload/industry_sl.cpp new file mode 100644 index 000000000..2b8aea788 --- /dev/null +++ b/src/saveload/industry_sl.cpp @@ -0,0 +1,155 @@ +/* $Id$ */ + +/** @file industry_sl.cpp Code handling saving and loading of industries */ + +#include "../stdafx.h" +#include "../tile_type.h" +#include "../strings_type.h" +#include "../company_type.h" +#include "../industry.h" +#include "../newgrf_commons.h" + +#include "saveload.h" + +static const SaveLoad _industry_desc[] = { + SLE_CONDVAR(Industry, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Industry, xy, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_VAR(Industry, width, SLE_UINT8), + SLE_VAR(Industry, height, SLE_UINT8), + SLE_REF(Industry, town, REF_TOWN), + SLE_CONDNULL( 2, 0, 60), ///< used to be industry's produced_cargo + SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 2, 78, SL_MAX_VERSION), + SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 3, 70, SL_MAX_VERSION), + SLE_ARR(Industry, produced_cargo_waiting, SLE_UINT16, 2), + SLE_ARR(Industry, production_rate, SLE_UINT8, 2), + SLE_CONDNULL( 3, 0, 60), ///< used to be industry's accepts_cargo + SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 3, 78, SL_MAX_VERSION), + SLE_VAR(Industry, prod_level, SLE_UINT8), + SLE_ARR(Industry, this_month_production, SLE_UINT16, 2), + SLE_ARR(Industry, this_month_transported, SLE_UINT16, 2), + SLE_ARR(Industry, last_month_pct_transported, SLE_UINT8, 2), + SLE_ARR(Industry, last_month_production, SLE_UINT16, 2), + SLE_ARR(Industry, last_month_transported, SLE_UINT16, 2), + + SLE_VAR(Industry, counter, SLE_UINT16), + + SLE_VAR(Industry, type, SLE_UINT8), + SLE_VAR(Industry, owner, SLE_UINT8), + SLE_VAR(Industry, random_color, SLE_UINT8), + SLE_CONDVAR(Industry, last_prod_year, SLE_FILE_U8 | SLE_VAR_I32, 0, 30), + SLE_CONDVAR(Industry, last_prod_year, SLE_INT32, 31, SL_MAX_VERSION), + SLE_VAR(Industry, was_cargo_delivered, SLE_UINT8), + + SLE_CONDVAR(Industry, founder, SLE_UINT8, 70, SL_MAX_VERSION), + SLE_CONDVAR(Industry, construction_date, SLE_INT32, 70, SL_MAX_VERSION), + SLE_CONDVAR(Industry, construction_type, SLE_UINT8, 70, SL_MAX_VERSION), + SLE_CONDVAR(Industry, last_cargo_accepted_at, SLE_INT32, 70, SL_MAX_VERSION), + SLE_CONDVAR(Industry, selected_layout, SLE_UINT8, 73, SL_MAX_VERSION), + + SLE_CONDARRX(cpp_offsetof(Industry, psa) + cpp_offsetof(Industry::PersistentStorage, storage), SLE_UINT32, 16, 76, SL_MAX_VERSION), + + SLE_CONDVAR(Industry, random_triggers, SLE_UINT8, 82, SL_MAX_VERSION), + SLE_CONDVAR(Industry, random, SLE_UINT16, 82, SL_MAX_VERSION), + + /* reserve extra space in savegame here. (currently 32 bytes) */ + SLE_CONDNULL(32, 2, SL_MAX_VERSION), + + SLE_END() +}; + +static void Save_INDY() +{ + Industry *ind; + + /* Write the industries */ + FOR_ALL_INDUSTRIES(ind) { + SlSetArrayIndex(ind->index); + SlObject(ind, _industry_desc); + } +} + +/* Save and load the mapping between the industry/tile id on the map, and the grf file + * it came from. */ +static const SaveLoad _industries_id_mapping_desc[] = { + SLE_VAR(EntityIDMapping, grfid, SLE_UINT32), + SLE_VAR(EntityIDMapping, entity_id, SLE_UINT8), + SLE_VAR(EntityIDMapping, substitute_id, SLE_UINT8), + SLE_END() +}; + +static void Save_IIDS() +{ + uint i; + uint j = _industry_mngr.GetMaxMapping(); + + for (i = 0; i < j; i++) { + SlSetArrayIndex(i); + SlObject(&_industry_mngr.mapping_ID[i], _industries_id_mapping_desc); + } +} + +static void Save_TIDS() +{ + uint i; + uint j = _industile_mngr.GetMaxMapping(); + + for (i = 0; i < j; i++) { + SlSetArrayIndex(i); + SlObject(&_industile_mngr.mapping_ID[i], _industries_id_mapping_desc); + } +} + +static void Load_INDY() +{ + int index; + + ResetIndustryCounts(); + + while ((index = SlIterateArray()) != -1) { + Industry *i = new (index) Industry(); + SlObject(i, _industry_desc); + IncIndustryTypeCount(i->type); + } +} + +static void Load_IIDS() +{ + int index; + uint max_id; + + /* clear the current mapping stored. + * This will create the manager if ever it is not yet done */ + _industry_mngr.ResetMapping(); + + /* get boundary for the temporary map loader NUM_INDUSTRYTYPES? */ + max_id = _industry_mngr.GetMaxMapping(); + + while ((index = SlIterateArray()) != -1) { + if ((uint)index >= max_id) break; + SlObject(&_industry_mngr.mapping_ID[index], _industries_id_mapping_desc); + } +} + +static void Load_TIDS() +{ + int index; + uint max_id; + + /* clear the current mapping stored. + * This will create the manager if ever it is not yet done */ + _industile_mngr.ResetMapping(); + + /* get boundary for the temporary map loader NUM_INDUSTILES? */ + max_id = _industile_mngr.GetMaxMapping(); + + while ((index = SlIterateArray()) != -1) { + if ((uint)index >= max_id) break; + SlObject(&_industile_mngr.mapping_ID[index], _industries_id_mapping_desc); + } +} + +extern const ChunkHandler _industry_chunk_handlers[] = { + { 'INDY', Save_INDY, Load_INDY, CH_ARRAY}, + { 'IIDS', Save_IIDS, Load_IIDS, CH_ARRAY}, + { 'TIDS', Save_TIDS, Load_TIDS, CH_ARRAY | CH_LAST}, +}; diff --git a/src/saveload/map_sl.cpp b/src/saveload/map_sl.cpp new file mode 100644 index 000000000..6025f0fca --- /dev/null +++ b/src/saveload/map_sl.cpp @@ -0,0 +1,249 @@ +/* $Id$ */ + +/** @file map_sl.cpp Code handling saving and loading of map */ + +#include "../stdafx.h" +#include "../tile_type.h" +#include "../map_func.h" +#include "../core/alloc_type.hpp" +#include "../core/bitmath_func.hpp" + +#include "saveload.h" + +static uint32 _map_dim_x; +static uint32 _map_dim_y; + +static const SaveLoadGlobVarList _map_dimensions[] = { + SLEG_CONDVAR(_map_dim_x, SLE_UINT32, 6, SL_MAX_VERSION), + SLEG_CONDVAR(_map_dim_y, SLE_UINT32, 6, SL_MAX_VERSION), + SLEG_END() +}; + +static void Save_MAPS() +{ + _map_dim_x = MapSizeX(); + _map_dim_y = MapSizeY(); + SlGlobList(_map_dimensions); +} + +static void Load_MAPS() +{ + SlGlobList(_map_dimensions); + AllocateMap(_map_dim_x, _map_dim_y); +} + +enum { + MAP_SL_BUF_SIZE = 4096 +}; + +static void Load_MAPT() +{ + SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].type_height = buf[j]; + } +} + +static void Save_MAPT() +{ + SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + SlSetLength(size); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].type_height; + SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + } +} + +static void Load_MAP1() +{ + SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m1 = buf[j]; + } +} + +static void Save_MAP1() +{ + SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + SlSetLength(size); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m1; + SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + } +} + +static void Load_MAP2() +{ + SmallStackSafeStackAlloc<uint16, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlArray(buf, MAP_SL_BUF_SIZE, + /* In those versions the m2 was 8 bits */ + CheckSavegameVersion(5) ? SLE_FILE_U8 | SLE_VAR_U16 : SLE_UINT16 + ); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m2 = buf[j]; + } +} + +static void Save_MAP2() +{ + SmallStackSafeStackAlloc<uint16, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + SlSetLength(size * sizeof(uint16)); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m2; + SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT16); + } +} + +static void Load_MAP3() +{ + SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m3 = buf[j]; + } +} + +static void Save_MAP3() +{ + SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + SlSetLength(size); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m3; + SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + } +} + +static void Load_MAP4() +{ + SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m4 = buf[j]; + } +} + +static void Save_MAP4() +{ + SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + SlSetLength(size); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m4; + SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + } +} + +static void Load_MAP5() +{ + SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m5 = buf[j]; + } +} + +static void Save_MAP5() +{ + SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + SlSetLength(size); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m5; + SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + } +} + +static void Load_MAP6() +{ + SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + if (CheckSavegameVersion(42)) { + for (TileIndex i = 0; i != size;) { + /* 1024, otherwise we overflow on 64x64 maps! */ + SlArray(buf, 1024, SLE_UINT8); + for (uint j = 0; j != 1024; j++) { + _m[i++].m6 = GB(buf[j], 0, 2); + _m[i++].m6 = GB(buf[j], 2, 2); + _m[i++].m6 = GB(buf[j], 4, 2); + _m[i++].m6 = GB(buf[j], 6, 2); + } + } + } else { + for (TileIndex i = 0; i != size;) { + SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m6 = buf[j]; + } + } +} + +static void Save_MAP6() +{ + SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + SlSetLength(size); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m6; + SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + } +} + +static void Load_MAP7() +{ + SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + for (TileIndex i = 0; i != size;) { + SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m7 = buf[j]; + } +} + +static void Save_MAP7() +{ + SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf; + TileIndex size = MapSize(); + + SlSetLength(size); + for (TileIndex i = 0; i != size;) { + for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m7; + SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + } +} + +extern const ChunkHandler _map_chunk_handlers[] = { + { 'MAPS', Save_MAPS, Load_MAPS, CH_RIFF }, + { 'MAPT', Save_MAPT, Load_MAPT, CH_RIFF }, + { 'MAPO', Save_MAP1, Load_MAP1, CH_RIFF }, + { 'MAP2', Save_MAP2, Load_MAP2, CH_RIFF }, + { 'M3LO', Save_MAP3, Load_MAP3, CH_RIFF }, + { 'M3HI', Save_MAP4, Load_MAP4, CH_RIFF }, + { 'MAP5', Save_MAP5, Load_MAP5, CH_RIFF }, + { 'MAPE', Save_MAP6, Load_MAP6, CH_RIFF }, + { 'MAP7', Save_MAP7, Load_MAP7, CH_RIFF }, +}; diff --git a/src/saveload/misc_sl.cpp b/src/saveload/misc_sl.cpp new file mode 100644 index 000000000..4b8e8b2c7 --- /dev/null +++ b/src/saveload/misc_sl.cpp @@ -0,0 +1,105 @@ +/* $Id$ */ + +/** @file misc_sl.cpp Saving and loading of things that didn't fit anywhere else */ + +#include "../stdafx.h" +#include "../date_func.h" +#include "../variables.h" +#include "../core/random_func.hpp" +#include "../openttd.h" +#include "../tile_type.h" +#include "../zoom_func.h" +#include "../vehicle_func.h" +#include "../window_gui.h" +#include "../window_func.h" +#include "../viewport_func.h" +#include "../gfx_func.h" + +#include "saveload.h" + +extern TileIndex _cur_tileloop_tile; + +/* Keep track of current game position */ +int _saved_scrollpos_x; +int _saved_scrollpos_y; + +void SaveViewportBeforeSaveGame() +{ + const Window *w = FindWindowById(WC_MAIN_WINDOW, 0); + + if (w != NULL) { + _saved_scrollpos_x = w->viewport->scrollpos_x; + _saved_scrollpos_y = w->viewport->scrollpos_y; + _saved_scrollpos_zoom = w->viewport->zoom; + } +} + +void ResetViewportAfterLoadGame() +{ + Window *w = FindWindowById(WC_MAIN_WINDOW, 0); + + w->viewport->scrollpos_x = _saved_scrollpos_x; + w->viewport->scrollpos_y = _saved_scrollpos_y; + w->viewport->dest_scrollpos_x = _saved_scrollpos_x; + w->viewport->dest_scrollpos_y = _saved_scrollpos_y; + + ViewPort *vp = w->viewport; + vp->zoom = min(_saved_scrollpos_zoom, ZOOM_LVL_MAX); + vp->virtual_width = ScaleByZoom(vp->width, vp->zoom); + vp->virtual_height = ScaleByZoom(vp->height, vp->zoom); + + DoZoomInOutWindow(ZOOM_NONE, w); // update button status + MarkWholeScreenDirty(); +} + + +static const SaveLoadGlobVarList _date_desc[] = { + SLEG_CONDVAR(_date, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), + SLEG_CONDVAR(_date, SLE_INT32, 31, SL_MAX_VERSION), + SLEG_VAR(_date_fract, SLE_UINT16), + SLEG_VAR(_tick_counter, SLE_UINT16), + SLEG_VAR(_vehicle_id_ctr_day, SLE_UINT16), + SLEG_VAR(_age_cargo_skip_counter, SLE_UINT8), + SLE_CONDNULL(1, 0, 45), + SLEG_CONDVAR(_cur_tileloop_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLEG_CONDVAR(_cur_tileloop_tile, SLE_UINT32, 6, SL_MAX_VERSION), + SLEG_VAR(_disaster_delay, SLE_UINT16), + SLEG_VAR(_station_tick_ctr, SLE_UINT16), + SLEG_VAR(_random.state[0], SLE_UINT32), + SLEG_VAR(_random.state[1], SLE_UINT32), + SLEG_CONDVAR(_cur_town_ctr, SLE_FILE_U8 | SLE_VAR_U32, 0, 9), + SLEG_CONDVAR(_cur_town_ctr, SLE_UINT32, 10, SL_MAX_VERSION), + SLEG_VAR(_cur_company_tick_index, SLE_FILE_U8 | SLE_VAR_U32), + SLEG_VAR(_next_competitor_start, SLE_FILE_U16 | SLE_VAR_U32), + SLEG_VAR(_trees_tick_ctr, SLE_UINT8), + SLEG_CONDVAR(_pause_game, SLE_UINT8, 4, SL_MAX_VERSION), + SLEG_CONDVAR(_cur_town_iter, SLE_UINT32, 11, SL_MAX_VERSION), + SLEG_END() +}; + +/* Save load date related variables as well as persistent tick counters + * XXX: currently some unrelated stuff is just put here */ +static void SaveLoad_DATE() +{ + SlGlobList(_date_desc); +} + + +static const SaveLoadGlobVarList _view_desc[] = { + SLEG_CONDVAR(_saved_scrollpos_x, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), + SLEG_CONDVAR(_saved_scrollpos_x, SLE_INT32, 6, SL_MAX_VERSION), + SLEG_CONDVAR(_saved_scrollpos_y, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), + SLEG_CONDVAR(_saved_scrollpos_y, SLE_INT32, 6, SL_MAX_VERSION), + SLEG_VAR(_saved_scrollpos_zoom, SLE_UINT8), + SLEG_END() +}; + +static void SaveLoad_VIEW() +{ + SlGlobList(_view_desc); +} + +extern const ChunkHandler _misc_chunk_handlers[] = { + { 'DATE', SaveLoad_DATE, SaveLoad_DATE, CH_RIFF}, + { 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, CH_RIFF | CH_LAST}, +}; diff --git a/src/saveload/newgrf_sl.cpp b/src/saveload/newgrf_sl.cpp new file mode 100644 index 000000000..5269f235d --- /dev/null +++ b/src/saveload/newgrf_sl.cpp @@ -0,0 +1,52 @@ +/* $Id$ */ + +/** @file newgrf_sl.cpp Code handling saving and loading of newgrf config */ + +#include "../stdafx.h" +#include "../newgrf_config.h" +#include "../core/bitmath_func.hpp" +#include "../core/alloc_func.hpp" +#include "../gfx_func.h" + +#include "saveload.h" + +static const SaveLoad _grfconfig_desc[] = { + SLE_STR(GRFConfig, filename, SLE_STR, 0x40), + SLE_VAR(GRFConfig, grfid, SLE_UINT32), + SLE_ARR(GRFConfig, md5sum, SLE_UINT8, 16), + SLE_ARR(GRFConfig, param, SLE_UINT32, 0x80), + SLE_VAR(GRFConfig, num_params, SLE_UINT8), + SLE_CONDVAR(GRFConfig, windows_paletted, SLE_BOOL, 101, SL_MAX_VERSION), + SLE_END() +}; + + +static void Save_NGRF() +{ + int index = 0; + + for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { + if (HasBit(c->flags, GCF_STATIC)) continue; + SlSetArrayIndex(index++); + SlObject(c, _grfconfig_desc); + } +} + + +static void Load_NGRF() +{ + ClearGRFConfigList(&_grfconfig); + while (SlIterateArray() != -1) { + GRFConfig *c = CallocT<GRFConfig>(1); + SlObject(c, _grfconfig_desc); + if (CheckSavegameVersion(101)) c->windows_paletted = (_use_palette == PAL_WINDOWS); + AppendToGRFConfigList(&_grfconfig, c); + } + + /* Append static NewGRF configuration */ + AppendStaticGRFConfigs(&_grfconfig); +} + +extern const ChunkHandler _newgrf_chunk_handlers[] = { + { 'NGRF', Save_NGRF, Load_NGRF, CH_ARRAY | CH_LAST } +}; diff --git a/src/oldloader.cpp b/src/saveload/oldloader.cpp index 2a02f069e..532d58f8c 100644 --- a/src/oldloader.cpp +++ b/src/saveload/oldloader.cpp @@ -2,34 +2,36 @@ /** @file oldloader.cpp Loading of old TTD(patch) savegames. */ -#include "stdafx.h" -#include "openttd.h" -#include "station_map.h" -#include "town.h" -#include "industry.h" -#include "company_func.h" -#include "company_base.h" -#include "aircraft.h" -#include "roadveh.h" -#include "ship.h" -#include "train.h" -#include "signs_base.h" -#include "debug.h" -#include "depot_base.h" -#include "newgrf_config.h" -#include "ai/ai.h" -#include "ai/default/default.h" -#include "zoom_func.h" -#include "functions.h" -#include "date_func.h" -#include "vehicle_func.h" -#include "variables.h" -#include "saveload.h" -#include "strings_func.h" -#include "effectvehicle_base.h" +#include "../stdafx.h" +#include "../openttd.h" +#include "../station_map.h" +#include "../town.h" +#include "../industry.h" +#include "../company_func.h" +#include "../company_base.h" +#include "../aircraft.h" +#include "../roadveh.h" +#include "../ship.h" +#include "../train.h" +#include "../signs_base.h" +#include "../debug.h" +#include "../depot_base.h" +#include "../newgrf_config.h" +#include "../ai/ai.h" +#include "../ai/default/default.h" +#include "../zoom_func.h" +#include "../functions.h" +#include "../date_func.h" +#include "../vehicle_func.h" +#include "../variables.h" +#include "../strings_func.h" +#include "../effectvehicle_base.h" #include "table/strings.h" +#include "saveload.h" +#include "saveload_internal.h" + enum { HEADER_SIZE = 49, BUFFER_SIZE = 4096, diff --git a/src/saveload/order_sl.cpp b/src/saveload/order_sl.cpp new file mode 100644 index 000000000..ef11056ed --- /dev/null +++ b/src/saveload/order_sl.cpp @@ -0,0 +1,203 @@ +/* $Id$ */ + +/** @file order_sl.cpp Code handling saving and loading of orders */ + +#include "../stdafx.h" +#include "../order_base.h" +#include "../core/alloc_func.hpp" +#include "../settings_type.h" + +#include "saveload.h" + +void Order::ConvertFromOldSavegame() +{ + uint8 old_flags = this->flags; + this->flags = 0; + + /* First handle non-stop */ + if (_settings_client.gui.sg_new_nonstop) { + /* OFB_NON_STOP */ + this->SetNonStopType((old_flags & 8) ? ONSF_NO_STOP_AT_ANY_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); + } else { + this->SetNonStopType((old_flags & 8) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE); + } + + switch (this->GetType()) { + /* Only a few types need the other savegame conversions. */ + case OT_GOTO_DEPOT: case OT_GOTO_STATION: case OT_LOADING: break; + default: return; + } + + if (this->GetType() != OT_GOTO_DEPOT) { + /* Then the load flags */ + if ((old_flags & 2) != 0) { // OFB_UNLOAD + this->SetLoadType(OLFB_NO_LOAD); + } else if ((old_flags & 4) == 0) { // !OFB_FULL_LOAD + this->SetLoadType(OLF_LOAD_IF_POSSIBLE); + } else { + this->SetLoadType(_settings_client.gui.sg_full_load_any ? OLF_FULL_LOAD_ANY : OLFB_FULL_LOAD); + } + + /* Finally fix the unload flags */ + if ((old_flags & 1) != 0) { // OFB_TRANSFER + this->SetUnloadType(OUFB_TRANSFER); + } else if ((old_flags & 2) != 0) { // OFB_UNLOAD + this->SetUnloadType(OUFB_UNLOAD); + } else { + this->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE); + } + } else { + /* Then the depot action flags */ + this->SetDepotActionType(((old_flags & 6) == 4) ? ODATFB_HALT : ODATF_SERVICE_ONLY); + + /* Finally fix the depot type flags */ + uint t = ((old_flags & 6) == 6) ? ODTFB_SERVICE : ODTF_MANUAL; + if ((old_flags & 2) != 0) t |= ODTFB_PART_OF_ORDERS; + this->SetDepotOrderType((OrderDepotTypeFlags)t); + } +} + +/** Unpacks a order from savegames with version 4 and lower + * @param packed packed order + * @return unpacked order + */ +static Order UnpackVersion4Order(uint16 packed) +{ + return Order(GB(packed, 8, 8) << 16 | GB(packed, 4, 4) << 8 | GB(packed, 0, 4)); +} + +/** Unpacks a order from savegames made with TTD(Patch) + * @param packed packed order + * @return unpacked order + */ +Order UnpackOldOrder(uint16 packed) +{ + Order order = UnpackVersion4Order(packed); + + /* + * Sanity check + * TTD stores invalid orders as OT_NOTHING with non-zero flags/station + */ + if (!order.IsValid() && packed != 0) order.MakeDummy(); + + return order; +} + +const SaveLoad *GetOrderDescription() +{ + static const SaveLoad _order_desc[] = { + SLE_VAR(Order, type, SLE_UINT8), + SLE_VAR(Order, flags, SLE_UINT8), + SLE_VAR(Order, dest, SLE_UINT16), + SLE_REF(Order, next, REF_ORDER), + SLE_CONDVAR(Order, refit_cargo, SLE_UINT8, 36, SL_MAX_VERSION), + SLE_CONDVAR(Order, refit_subtype, SLE_UINT8, 36, SL_MAX_VERSION), + SLE_CONDVAR(Order, wait_time, SLE_UINT16, 67, SL_MAX_VERSION), + SLE_CONDVAR(Order, travel_time, SLE_UINT16, 67, SL_MAX_VERSION), + + /* Leftover from the minor savegame version stuff + * We will never use those free bytes, but we have to keep this line to allow loading of old savegames */ + SLE_CONDNULL(10, 5, 35), + SLE_END() + }; + + return _order_desc; +} + +static void Save_ORDR() +{ + Order *order; + + FOR_ALL_ORDERS(order) { + SlSetArrayIndex(order->index); + SlObject(order, GetOrderDescription()); + } +} + +static void Load_ORDR() +{ + if (CheckSavegameVersionOldStyle(5, 2)) { + /* Version older than 5.2 did not have a ->next pointer. Convert them + (in the old days, the orderlist was 5000 items big) */ + size_t len = SlGetFieldLength(); + uint i; + + if (CheckSavegameVersion(5)) { + /* Pre-version 5 had an other layout for orders + (uint16 instead of uint32) */ + len /= sizeof(uint16); + uint16 *orders = MallocT<uint16>(len + 1); + + SlArray(orders, len, SLE_UINT16); + + for (i = 0; i < len; ++i) { + Order *order = new (i) Order(); + order->AssignOrder(UnpackVersion4Order(orders[i])); + } + + free(orders); + } else if (CheckSavegameVersionOldStyle(5, 2)) { + len /= sizeof(uint16); + uint16 *orders = MallocT<uint16>(len + 1); + + SlArray(orders, len, SLE_UINT32); + + for (i = 0; i < len; ++i) { + new (i) Order(orders[i]); + } + + free(orders); + } + + /* Update all the next pointer */ + for (i = 1; i < len; ++i) { + /* The orders were built like this: + * While the order is valid, set the previous will get it's next pointer set + * We start with index 1 because no order will have the first in it's next pointer */ + if (GetOrder(i)->IsValid()) + GetOrder(i - 1)->next = GetOrder(i); + } + } else { + int index; + + while ((index = SlIterateArray()) != -1) { + Order *order = new (index) Order(); + SlObject(order, GetOrderDescription()); + } + } +} + +const SaveLoad *GetOrderListDescription() +{ + static const SaveLoad _orderlist_desc[] = { + SLE_REF(OrderList, first, REF_ORDER), + SLE_END() + }; + + return _orderlist_desc; +} + +static void Save_ORDL() +{ + OrderList *list; + + FOR_ALL_ORDER_LISTS(list) { + SlSetArrayIndex(list->index); + SlObject(list, GetOrderListDescription()); + } +} + +static void Load_ORDL() +{ + int index; + + while ((index = SlIterateArray()) != -1) { + OrderList *list = new (index) OrderList(); + SlObject(list, GetOrderListDescription()); + } +} + +extern const ChunkHandler _order_chunk_handlers[] = { + { 'ORDR', Save_ORDR, Load_ORDR, CH_ARRAY}, + { 'ORDL', Save_ORDL, Load_ORDL, CH_ARRAY | CH_LAST}, +}; diff --git a/src/saveload.cpp b/src/saveload/saveload.cpp index eb46fe094..0a6585ce8 100644 --- a/src/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -13,32 +13,35 @@ * <li>repeat this until everything is done, and flush any remaining output to file * </ol> */ -#include "stdafx.h" -#include "openttd.h" -#include "debug.h" -#include "station_base.h" -#include "thread.h" -#include "town.h" -#include "saveload.h" -#include "network/network.h" -#include "variables.h" -#include "window_func.h" -#include "strings_func.h" -#include "gfx_func.h" -#include "core/alloc_func.hpp" -#include "functions.h" -#include "core/endian_func.hpp" -#include "vehicle_base.h" -#include "company_func.h" -#include "date_func.h" -#include "autoreplace_base.h" -#include "statusbar_gui.h" -#include "fileio_func.h" -#include <list> -#include "gamelog.h" +#include "../stdafx.h" +#include "../openttd.h" +#include "../debug.h" +#include "../station_base.h" +#include "../thread.h" +#include "../town.h" +#include "../network/network.h" +#include "../variables.h" +#include "../window_func.h" +#include "../strings_func.h" +#include "../gfx_func.h" +#include "../core/alloc_func.hpp" +#include "../functions.h" +#include "../core/endian_func.hpp" +#include "../vehicle_base.h" +#include "../company_func.h" +#include "../date_func.h" +#include "../autoreplace_base.h" +#include "../statusbar_gui.h" +#include "../fileio_func.h" +#include "../gamelog.h" #include "table/strings.h" +#include "saveload.h" +#include "saveload_internal.h" + +#include <list> + extern const uint16 SAVEGAME_VERSION = 105; SavegameType _savegame_type; ///< type of savegame we are loading @@ -1069,7 +1072,7 @@ static void SlLoadChunks() *******************************************/ #define LZO_SIZE 8192 -#include "minilzo.h" +#include "../minilzo.h" static size_t ReadLZO() { @@ -1157,8 +1160,8 @@ static void UninitNoComp() ********** START OF MEMORY CODE (in ram)**** ********************************************/ -#include "table/sprites.h" -#include "gui.h" +#include "../table/sprites.h" +#include "../gui.h" struct ThreadedSave { uint count; @@ -1298,6 +1301,7 @@ static void UninitWriteZlib() /* these define the chunks */ extern const ChunkHandler _gamelog_chunk_handlers[]; +extern const ChunkHandler _map_chunk_handlers[]; extern const ChunkHandler _misc_chunk_handlers[]; extern const ChunkHandler _name_chunk_handlers[]; extern const ChunkHandler _cheat_chunk_handlers[] ; @@ -1313,6 +1317,7 @@ extern const ChunkHandler _sign_chunk_handlers[]; extern const ChunkHandler _station_chunk_handlers[]; extern const ChunkHandler _industry_chunk_handlers[]; extern const ChunkHandler _economy_chunk_handlers[]; +extern const ChunkHandler _subsidy_chunk_handlers[]; extern const ChunkHandler _animated_tile_chunk_handlers[]; extern const ChunkHandler _newgrf_chunk_handlers[]; extern const ChunkHandler _group_chunk_handlers[]; @@ -1321,6 +1326,7 @@ extern const ChunkHandler _autoreplace_chunk_handlers[]; static const ChunkHandler * const _chunk_handlers[] = { _gamelog_chunk_handlers, + _map_chunk_handlers, _misc_chunk_handlers, _name_chunk_handlers, _cheat_chunk_handlers, @@ -1331,6 +1337,7 @@ static const ChunkHandler * const _chunk_handlers[] = { _order_chunk_handlers, _industry_chunk_handlers, _economy_chunk_handlers, + _subsidy_chunk_handlers, _engine_chunk_handlers, _town_chunk_handlers, _sign_chunk_handlers, @@ -1501,7 +1508,6 @@ static const SaveLoadFormat *GetSavegameFormat(const char *s) /* actual loader/saver function */ void InitializeGame(uint size_x, uint size_y, bool reset_date); extern bool AfterLoadGame(); -extern void SaveViewportBeforeSaveGame(); extern bool LoadOldSaveGame(const char *file); /** Small helper function to close the to be loaded savegame an signal error */ diff --git a/src/saveload.h b/src/saveload/saveload.h index 6585230a9..f71b0dec4 100644 --- a/src/saveload.h +++ b/src/saveload/saveload.h @@ -5,7 +5,7 @@ #ifndef SAVELOAD_H #define SAVELOAD_H -#include "fileio_type.h" +#include "../fileio_type.h" #ifdef SIZE_MAX #undef SIZE_MAX diff --git a/src/saveload/saveload_internal.h b/src/saveload/saveload_internal.h new file mode 100644 index 000000000..7bb865d81 --- /dev/null +++ b/src/saveload/saveload_internal.h @@ -0,0 +1,40 @@ +/* $Id$ */ + +/** @file saveload_internal.h Declaration of functions used in more save/load files */ + +#ifndef SAVELOAD_INTERNAL_H +#define SAVELOAD_INTERNAL_H + +#include "../strings_type.h" +#include "../company_manager_face.h" +#include "../order_base.h" + +void InitializeOldNames(); +StringID RemapOldStringID(StringID s); +char *CopyFromOldName(StringID id); +void ResetOldNames(); + +void FixOldWaypoints(); + +void AfterLoadWaypoints(); +void AfterLoadVehicles(bool part_of_load); +void AfterLoadStations(); +void AfterLoadTown(); +void UpdateHousesAndTowns(); + +void UpdateOldAircraft(); + +void SaveViewportBeforeSaveGame(); +void ResetViewportAfterLoadGame(); + +void ConvertOldMultiheadToNew(); +void ConnectMultiheadedTrains(); + +extern int32 _saved_scrollpos_x; +extern int32 _saved_scrollpos_y; + +CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32 face); + +Order UnpackOldOrder(uint16 packed); + +#endif /* SAVELOAD_INTERNAL_H */ diff --git a/src/saveload/signs_sl.cpp b/src/saveload/signs_sl.cpp new file mode 100644 index 000000000..ef4530dcd --- /dev/null +++ b/src/saveload/signs_sl.cpp @@ -0,0 +1,49 @@ +/* $Id$ */ + +/** @file signs_sl.cpp Code handling saving and loading of economy data */ + +#include "../stdafx.h" +#include "../strings_func.h" +#include "../company_func.h" +#include "../signs_base.h" +#include "../signs_func.h" + +#include "saveload_internal.h" +#include "saveload.h" + +static const SaveLoad _sign_desc[] = { + SLE_CONDVAR(Sign, name, SLE_NAME, 0, 83), + SLE_CONDSTR(Sign, name, SLE_STR, 0, 84, SL_MAX_VERSION), + SLE_CONDVAR(Sign, x, SLE_FILE_I16 | SLE_VAR_I32, 0, 4), + SLE_CONDVAR(Sign, y, SLE_FILE_I16 | SLE_VAR_I32, 0, 4), + SLE_CONDVAR(Sign, x, SLE_INT32, 5, SL_MAX_VERSION), + SLE_CONDVAR(Sign, y, SLE_INT32, 5, SL_MAX_VERSION), + SLE_CONDVAR(Sign, owner, SLE_UINT8, 6, SL_MAX_VERSION), + SLE_VAR(Sign, z, SLE_UINT8), + SLE_END() +}; + +/** Save all signs */ +static void Save_SIGN() +{ + Sign *si; + + FOR_ALL_SIGNS(si) { + SlSetArrayIndex(si->index); + SlObject(si, _sign_desc); + } +} + +/** Load all signs */ +static void Load_SIGN() +{ + int index; + while ((index = SlIterateArray()) != -1) { + Sign *si = new (index) Sign(); + SlObject(si, _sign_desc); + } +} + +extern const ChunkHandler _sign_chunk_handlers[] = { + { 'SIGN', Save_SIGN, Load_SIGN, CH_ARRAY | CH_LAST}, +}; diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp new file mode 100644 index 000000000..b03e59c7d --- /dev/null +++ b/src/saveload/station_sl.cpp @@ -0,0 +1,227 @@ +/* $Id$ */ + +/** @file station_sl.cpp Code handling saving and loading of economy data */ + +#include "../stdafx.h" +#include "../station_base.h" +#include "../core/bitmath_func.hpp" +#include "../core/alloc_func.hpp" +#include "../variables.h" +#include "../newgrf_station.h" + +#include "saveload.h" + + +void AfterLoadStations() +{ + /* Update the speclists of all stations to point to the currently loaded custom stations. */ + Station *st; + FOR_ALL_STATIONS(st) { + for (uint i = 0; i < st->num_specs; i++) { + if (st->speclist[i].grfid == 0) continue; + + st->speclist[i].spec = GetCustomStationSpecByGrf(st->speclist[i].grfid, st->speclist[i].localidx); + } + + for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache(); + + StationUpdateAnimTriggers(st); + } +} + +static const SaveLoad _roadstop_desc[] = { + SLE_VAR(RoadStop, xy, SLE_UINT32), + SLE_CONDNULL(1, 0, 44), + SLE_VAR(RoadStop, status, SLE_UINT8), + /* Index was saved in some versions, but this is not needed */ + SLE_CONDNULL(4, 0, 8), + SLE_CONDNULL(2, 0, 44), + SLE_CONDNULL(1, 0, 25), + + SLE_REF(RoadStop, next, REF_ROADSTOPS), + SLE_CONDNULL(2, 0, 44), + + SLE_CONDNULL(4, 0, 24), + SLE_CONDNULL(1, 25, 25), + + SLE_END() +}; + +static const SaveLoad _station_desc[] = { + SLE_CONDVAR(Station, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Station, xy, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDNULL(4, 0, 5), ///< bus/lorry tile + SLE_CONDVAR(Station, train_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Station, train_tile, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(Station, airport_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Station, airport_tile, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(Station, dock_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Station, dock_tile, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_REF(Station, town, REF_TOWN), + SLE_VAR(Station, trainst_w, SLE_UINT8), + SLE_CONDVAR(Station, trainst_h, SLE_UINT8, 2, SL_MAX_VERSION), + + SLE_CONDNULL(1, 0, 3), ///< alpha_order + + SLE_VAR(Station, string_id, SLE_STRINGID), + SLE_CONDSTR(Station, name, SLE_STR, 0, 84, SL_MAX_VERSION), + SLE_CONDVAR(Station, indtype, SLE_UINT8, 103, SL_MAX_VERSION), + SLE_VAR(Station, had_vehicle_of_type, SLE_UINT16), + + SLE_VAR(Station, time_since_load, SLE_UINT8), + SLE_VAR(Station, time_since_unload, SLE_UINT8), + SLE_VAR(Station, delete_ctr, SLE_UINT8), + SLE_VAR(Station, owner, SLE_UINT8), + SLE_VAR(Station, facilities, SLE_UINT8), + SLE_VAR(Station, airport_type, SLE_UINT8), + + SLE_CONDNULL(2, 0, 5), ///< Truck/bus stop status + SLE_CONDNULL(1, 0, 4), ///< Blocked months + + SLE_CONDVAR(Station, airport_flags, SLE_VAR_U64 | SLE_FILE_U16, 0, 2), + SLE_CONDVAR(Station, airport_flags, SLE_VAR_U64 | SLE_FILE_U32, 3, 45), + SLE_CONDVAR(Station, airport_flags, SLE_UINT64, 46, SL_MAX_VERSION), + + SLE_CONDNULL(2, 0, 25), ///< last-vehicle + SLE_CONDVAR(Station, last_vehicle_type, SLE_UINT8, 26, SL_MAX_VERSION), + + SLE_CONDNULL(2, 3, 25), ///< custom station class and id + SLE_CONDVAR(Station, build_date, SLE_FILE_U16 | SLE_VAR_I32, 3, 30), + SLE_CONDVAR(Station, build_date, SLE_INT32, 31, SL_MAX_VERSION), + + SLE_CONDREF(Station, bus_stops, REF_ROADSTOPS, 6, SL_MAX_VERSION), + SLE_CONDREF(Station, truck_stops, REF_ROADSTOPS, 6, SL_MAX_VERSION), + + /* Used by newstations for graphic variations */ + SLE_CONDVAR(Station, random_bits, SLE_UINT16, 27, SL_MAX_VERSION), + SLE_CONDVAR(Station, waiting_triggers, SLE_UINT8, 27, SL_MAX_VERSION), + SLE_CONDVAR(Station, num_specs, SLE_UINT8, 27, SL_MAX_VERSION), + + SLE_CONDLST(Station, loading_vehicles, REF_VEHICLE, 57, SL_MAX_VERSION), + + /* reserve extra space in savegame here. (currently 32 bytes) */ + SLE_CONDNULL(32, 2, SL_MAX_VERSION), + + SLE_END() +}; + +static uint16 _waiting_acceptance; +static uint16 _cargo_source; +static uint32 _cargo_source_xy; +static uint16 _cargo_days; +static Money _cargo_feeder_share; + +static const SaveLoad _station_speclist_desc[] = { + SLE_CONDVAR(StationSpecList, grfid, SLE_UINT32, 27, SL_MAX_VERSION), + SLE_CONDVAR(StationSpecList, localidx, SLE_UINT8, 27, SL_MAX_VERSION), + + SLE_END() +}; + + +void SaveLoad_STNS(Station *st) +{ + static const SaveLoad _goods_desc[] = { + SLEG_CONDVAR( _waiting_acceptance, SLE_UINT16, 0, 67), + SLE_CONDVAR(GoodsEntry, acceptance_pickup, SLE_UINT8, 68, SL_MAX_VERSION), + SLE_CONDNULL(2, 51, 67), + SLE_VAR(GoodsEntry, days_since_pickup, SLE_UINT8), + SLE_VAR(GoodsEntry, rating, SLE_UINT8), + SLEG_CONDVAR( _cargo_source, SLE_FILE_U8 | SLE_VAR_U16, 0, 6), + SLEG_CONDVAR( _cargo_source, SLE_UINT16, 7, 67), + SLEG_CONDVAR( _cargo_source_xy, SLE_UINT32, 44, 67), + SLEG_CONDVAR( _cargo_days, SLE_UINT8, 0, 67), + SLE_VAR(GoodsEntry, last_speed, SLE_UINT8), + SLE_VAR(GoodsEntry, last_age, SLE_UINT8), + SLEG_CONDVAR( _cargo_feeder_share, SLE_FILE_U32 | SLE_VAR_I64, 14, 64), + SLEG_CONDVAR( _cargo_feeder_share, SLE_INT64, 65, 67), + SLE_CONDLST(GoodsEntry, cargo.packets, REF_CARGO_PACKET, 68, SL_MAX_VERSION), + + SLE_END() + }; + + + SlObject(st, _station_desc); + + _waiting_acceptance = 0; + + uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO; + for (CargoID i = 0; i < num_cargo; i++) { + GoodsEntry *ge = &st->goods[i]; + SlObject(ge, _goods_desc); + if (CheckSavegameVersion(68)) { + SB(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15)); + if (GB(_waiting_acceptance, 0, 12) != 0) { + /* Don't construct the packet with station here, because that'll fail with old savegames */ + CargoPacket *cp = new CargoPacket(); + /* In old versions, enroute_from used 0xFF as INVALID_STATION */ + cp->source = (CheckSavegameVersion(7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source; + cp->count = GB(_waiting_acceptance, 0, 12); + cp->days_in_transit = _cargo_days; + cp->feeder_share = _cargo_feeder_share; + cp->source_xy = _cargo_source_xy; + cp->days_in_transit = _cargo_days; + cp->feeder_share = _cargo_feeder_share; + SB(ge->acceptance_pickup, GoodsEntry::PICKUP, 1, 1); + ge->cargo.Append(cp); + } + } + } + + if (st->num_specs != 0) { + /* Allocate speclist memory when loading a game */ + if (st->speclist == NULL) st->speclist = CallocT<StationSpecList>(st->num_specs); + for (uint i = 0; i < st->num_specs; i++) { + SlObject(&st->speclist[i], _station_speclist_desc); + } + } +} + +static void Save_STNS() +{ + Station *st; + /* Write the stations */ + FOR_ALL_STATIONS(st) { + SlSetArrayIndex(st->index); + SlAutolength((AutolengthProc*)SaveLoad_STNS, st); + } +} + +static void Load_STNS() +{ + int index; + while ((index = SlIterateArray()) != -1) { + Station *st = new (index) Station(); + + SaveLoad_STNS(st); + } + + /* This is to ensure all pointers are within the limits of _stations_size */ + if (_station_tick_ctr > GetMaxStationIndex()) _station_tick_ctr = 0; +} + +static void Save_ROADSTOP() +{ + RoadStop *rs; + + FOR_ALL_ROADSTOPS(rs) { + SlSetArrayIndex(rs->index); + SlObject(rs, _roadstop_desc); + } +} + +static void Load_ROADSTOP() +{ + int index; + + while ((index = SlIterateArray()) != -1) { + RoadStop *rs = new (index) RoadStop(INVALID_TILE); + + SlObject(rs, _roadstop_desc); + } +} + +extern const ChunkHandler _station_chunk_handlers[] = { + { 'STNS', Save_STNS, Load_STNS, CH_ARRAY }, + { 'ROAD', Save_ROADSTOP, Load_ROADSTOP, CH_ARRAY | CH_LAST}, +}; diff --git a/src/saveload/strings_sl.cpp b/src/saveload/strings_sl.cpp new file mode 100644 index 000000000..f436bdedf --- /dev/null +++ b/src/saveload/strings_sl.cpp @@ -0,0 +1,126 @@ +/* $Id$ */ + +/** @file strings_sl.cpp Code handling saving and loading of strings */ + +#include "../stdafx.h" +#include "../strings_type.h" +#include "../core/math_func.hpp" +#include "../core/bitmath_func.hpp" +#include "../core/alloc_func.hpp" +#include "../string_func.h" + +#include "table/strings.h" + +#include "saveload.h" + +/** + * Remap a string ID from the old format to the new format + * @param s StringID that requires remapping + * @return translated ID + */ +StringID RemapOldStringID(StringID s) +{ + switch (s) { + case 0x0006: return STR_SV_EMPTY; + case 0x7000: return STR_SV_UNNAMED; + case 0x70E4: return SPECSTR_PLAYERNAME_ENGLISH; + case 0x70E9: return SPECSTR_PLAYERNAME_ENGLISH; + case 0x8864: return STR_SV_TRAIN_NAME; + case 0x902B: return STR_SV_ROADVEH_NAME; + case 0x9830: return STR_SV_SHIP_NAME; + case 0xA02F: return STR_SV_AIRCRAFT_NAME; + + default: + if (IsInsideMM(s, 0x300F, 0x3030)) { + return s - 0x300F + STR_SV_STNAME; + } else { + return s; + } + } +} + +/** Location to load the old names to. */ +char *_old_name_array = NULL; + +/** + * Copy and convert old custom names to UTF-8. + * They were all stored in a 512 by 32 long string array and are + * now stored with stations, waypoints and other places with names. + * @param id the StringID of the custom name to clone. + * @return the clones custom name. + */ +char *CopyFromOldName(StringID id) +{ + /* Is this name an (old) custom name? */ + if (GB(id, 11, 5) != 15) return NULL; + + if (CheckSavegameVersion(37)) { + /* Old names were 32 characters long, so 128 characters should be + * plenty to allow for expansion when converted to UTF-8. */ + char tmp[128]; + const char *strfrom = &_old_name_array[32 * GB(id, 0, 9)]; + char *strto = tmp; + + for (; *strfrom != '\0'; strfrom++) { + WChar c = (byte)*strfrom; + + /* Map from non-ISO8859-15 characters to UTF-8. */ + switch (c) { + case 0xA4: c = 0x20AC; break; // Euro + case 0xA6: c = 0x0160; break; // S with caron + case 0xA8: c = 0x0161; break; // s with caron + case 0xB4: c = 0x017D; break; // Z with caron + case 0xB8: c = 0x017E; break; // z with caron + case 0xBC: c = 0x0152; break; // OE ligature + case 0xBD: c = 0x0153; break; // oe ligature + case 0xBE: c = 0x0178; break; // Y with diaresis + default: break; + } + + /* Check character will fit into our buffer. */ + if (strto + Utf8CharLen(c) > lastof(tmp)) break; + + strto += Utf8Encode(strto, c); + } + + /* Terminate the new string and copy it back to the name array */ + *strto = '\0'; + + return strdup(tmp); + } else { + /* Name will already be in UTF-8. */ + return strdup(&_old_name_array[32 * GB(id, 0, 9)]); + } +} + +/** + * Free the memory of the old names array. + * Should be called once the old names have all been converted. + */ +void ResetOldNames() +{ + free(_old_name_array); + _old_name_array = NULL; +} + +/** + * Initialize the old names table memory. + */ +void InitializeOldNames() +{ + free(_old_name_array); + _old_name_array = CallocT<char>(512 * 32); +} + +static void Load_NAME() +{ + int index; + + while ((index = SlIterateArray()) != -1) { + SlArray(&_old_name_array[32 * index], SlGetFieldLength(), SLE_UINT8); + } +} + +extern const ChunkHandler _name_chunk_handlers[] = { + { 'NAME', NULL, Load_NAME, CH_ARRAY | CH_LAST}, +}; diff --git a/src/saveload/subsidy_sl.cpp b/src/saveload/subsidy_sl.cpp new file mode 100644 index 000000000..95fac25c7 --- /dev/null +++ b/src/saveload/subsidy_sl.cpp @@ -0,0 +1,43 @@ +/* $Id$ */ + +/** @file subsidy_sl.cpp Code handling saving and loading of subsidies */ + +#include "../stdafx.h" +#include "../economy_func.h" + +#include "saveload.h" + +static const SaveLoad _subsidies_desc[] = { + SLE_VAR(Subsidy, cargo_type, SLE_UINT8), + SLE_VAR(Subsidy, age, SLE_UINT8), + SLE_CONDVAR(Subsidy, from, SLE_FILE_U8 | SLE_VAR_U16, 0, 4), + SLE_CONDVAR(Subsidy, from, SLE_UINT16, 5, SL_MAX_VERSION), + SLE_CONDVAR(Subsidy, to, SLE_FILE_U8 | SLE_VAR_U16, 0, 4), + SLE_CONDVAR(Subsidy, to, SLE_UINT16, 5, SL_MAX_VERSION), + SLE_END() +}; + +void Save_SUBS() +{ + int i; + Subsidy *s; + + for (i = 0; i != lengthof(_subsidies); i++) { + s = &_subsidies[i]; + if (s->cargo_type != CT_INVALID) { + SlSetArrayIndex(i); + SlObject(s, _subsidies_desc); + } + } +} + +void Load_SUBS() +{ + int index; + while ((index = SlIterateArray()) != -1) + SlObject(&_subsidies[index], _subsidies_desc); +} + +extern const ChunkHandler _subsidy_chunk_handlers[] = { + { 'SUBS', Save_SUBS, Load_SUBS, CH_ARRAY}, +}; diff --git a/src/saveload/town_sl.cpp b/src/saveload/town_sl.cpp new file mode 100644 index 000000000..eaa3edaa3 --- /dev/null +++ b/src/saveload/town_sl.cpp @@ -0,0 +1,210 @@ +/* $Id$ */ + +/** @file town_sl.cpp Code handling saving and loading of towns and houses */ + +#include "../stdafx.h" +#include "../town.h" +#include "../newgrf_house.h" +#include "../newgrf_commons.h" +#include "../variables.h" +#include "../tile_map.h" +#include "../town_map.h" + +#include "saveload.h" + +extern uint _total_towns; + +/** + * Check and update town and house values. + * + * Checked are the HouseIDs. Updated are the + * town population the number of houses per + * town, the town radius and the max passengers + * of the town. + */ +void UpdateHousesAndTowns() +{ + Town *town; + InitializeBuildingCounts(); + + /* Reset town population and num_houses */ + FOR_ALL_TOWNS(town) { + town->population = 0; + town->num_houses = 0; + } + + for (TileIndex t = 0; t < MapSize(); t++) { + HouseID house_id; + + if (!IsTileType(t, MP_HOUSE)) continue; + + house_id = GetHouseType(t); + if (!GetHouseSpecs(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) { + /* The specs for this type of house are not available any more, so + * replace it with the substitute original house type. */ + house_id = _house_mngr.GetSubstituteID(house_id); + SetHouseType(t, house_id); + } + + town = GetTownByTile(t); + IncreaseBuildingCount(town, house_id); + if (IsHouseCompleted(t)) town->population += GetHouseSpecs(house_id)->population; + + /* Increase the number of houses for every house, but only once. */ + if (GetHouseNorthPart(house_id) == 0) town->num_houses++; + } + + /* Update the population and num_house dependant values */ + FOR_ALL_TOWNS(town) { + UpdateTownRadius(town); + UpdateTownMaxPass(town); + } +} + +/** Save and load of towns. */ +static const SaveLoad _town_desc[] = { + SLE_CONDVAR(Town, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Town, xy, SLE_UINT32, 6, SL_MAX_VERSION), + + SLE_CONDNULL(2, 0, 2), ///< population, no longer in use + SLE_CONDNULL(4, 3, 84), ///< population, no longer in use + SLE_CONDNULL(2, 0, 91), ///< num_houses, no longer in use + + SLE_CONDVAR(Town, townnamegrfid, SLE_UINT32, 66, SL_MAX_VERSION), + SLE_VAR(Town, townnametype, SLE_UINT16), + SLE_VAR(Town, townnameparts, SLE_UINT32), + SLE_CONDSTR(Town, name, SLE_STR, 0, 84, SL_MAX_VERSION), + + SLE_VAR(Town, flags12, SLE_UINT8), + SLE_CONDVAR(Town, statues, SLE_FILE_U8 | SLE_VAR_U16, 0, 103), + SLE_CONDVAR(Town, statues, SLE_UINT16, 104, SL_MAX_VERSION), + + SLE_CONDNULL(1, 0, 1), ///< sort_index, no longer in use + + SLE_CONDVAR(Town, have_ratings, SLE_FILE_U8 | SLE_VAR_U16, 0, 103), + SLE_CONDVAR(Town, have_ratings, SLE_UINT16, 104, SL_MAX_VERSION), + SLE_CONDARR(Town, ratings, SLE_INT16, 8, 0, 103), + SLE_CONDARR(Town, ratings, SLE_INT16, MAX_COMPANIES, 104, SL_MAX_VERSION), + /* failed bribe attempts are stored since savegame format 4 */ + SLE_CONDARR(Town, unwanted, SLE_INT8, 8, 4, 103), + SLE_CONDARR(Town, unwanted, SLE_INT8, MAX_COMPANIES, 104, SL_MAX_VERSION), + + SLE_CONDVAR(Town, max_pass, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), + SLE_CONDVAR(Town, max_mail, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), + SLE_CONDVAR(Town, new_max_pass, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), + SLE_CONDVAR(Town, new_max_mail, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), + SLE_CONDVAR(Town, act_pass, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), + SLE_CONDVAR(Town, act_mail, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), + SLE_CONDVAR(Town, new_act_pass, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), + SLE_CONDVAR(Town, new_act_mail, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), + + SLE_CONDVAR(Town, max_pass, SLE_UINT32, 9, SL_MAX_VERSION), + SLE_CONDVAR(Town, max_mail, SLE_UINT32, 9, SL_MAX_VERSION), + SLE_CONDVAR(Town, new_max_pass, SLE_UINT32, 9, SL_MAX_VERSION), + SLE_CONDVAR(Town, new_max_mail, SLE_UINT32, 9, SL_MAX_VERSION), + SLE_CONDVAR(Town, act_pass, SLE_UINT32, 9, SL_MAX_VERSION), + SLE_CONDVAR(Town, act_mail, SLE_UINT32, 9, SL_MAX_VERSION), + SLE_CONDVAR(Town, new_act_pass, SLE_UINT32, 9, SL_MAX_VERSION), + SLE_CONDVAR(Town, new_act_mail, SLE_UINT32, 9, SL_MAX_VERSION), + + SLE_VAR(Town, pct_pass_transported, SLE_UINT8), + SLE_VAR(Town, pct_mail_transported, SLE_UINT8), + + SLE_VAR(Town, act_food, SLE_UINT16), + SLE_VAR(Town, act_water, SLE_UINT16), + SLE_VAR(Town, new_act_food, SLE_UINT16), + SLE_VAR(Town, new_act_water, SLE_UINT16), + + SLE_CONDVAR(Town, time_until_rebuild, SLE_UINT8, 0, 53), + SLE_CONDVAR(Town, grow_counter, SLE_UINT8, 0, 53), + SLE_CONDVAR(Town, growth_rate, SLE_UINT8, 0, 53), + + SLE_CONDVAR(Town, time_until_rebuild, SLE_UINT16, 54, SL_MAX_VERSION), + SLE_CONDVAR(Town, grow_counter, SLE_UINT16, 54, SL_MAX_VERSION), + SLE_CONDVAR(Town, growth_rate, SLE_INT16, 54, SL_MAX_VERSION), + + SLE_VAR(Town, fund_buildings_months, SLE_UINT8), + SLE_VAR(Town, road_build_months, SLE_UINT8), + + SLE_CONDVAR(Town, exclusivity, SLE_UINT8, 2, SL_MAX_VERSION), + SLE_CONDVAR(Town, exclusive_counter, SLE_UINT8, 2, SL_MAX_VERSION), + + SLE_CONDVAR(Town, larger_town, SLE_BOOL, 56, SL_MAX_VERSION), + + /* reserve extra space in savegame here. (currently 30 bytes) */ + SLE_CONDNULL(30, 2, SL_MAX_VERSION), + + SLE_END() +}; + +/* Save and load the mapping between the house id on the map, and the grf file + * it came from. */ +static const SaveLoad _house_id_mapping_desc[] = { + SLE_VAR(EntityIDMapping, grfid, SLE_UINT32), + SLE_VAR(EntityIDMapping, entity_id, SLE_UINT8), + SLE_VAR(EntityIDMapping, substitute_id, SLE_UINT8), + SLE_END() +}; + +static void Save_HOUSEIDS() +{ + uint j = _house_mngr.GetMaxMapping(); + + for (uint i = 0; i < j; i++) { + SlSetArrayIndex(i); + SlObject(&_house_mngr.mapping_ID[i], _house_id_mapping_desc); + } +} + +static void Load_HOUSEIDS() +{ + int index; + + _house_mngr.ResetMapping(); + uint max_id = _house_mngr.GetMaxMapping(); + + while ((index = SlIterateArray()) != -1) { + if ((uint)index >= max_id) break; + SlObject(&_house_mngr.mapping_ID[index], _house_id_mapping_desc); + } +} + +static void Save_TOWN() +{ + Town *t; + + FOR_ALL_TOWNS(t) { + SlSetArrayIndex(t->index); + SlObject(t, _town_desc); + } +} + +static void Load_TOWN() +{ + int index; + + _total_towns = 0; + + while ((index = SlIterateArray()) != -1) { + Town *t = new (index) Town(); + SlObject(t, _town_desc); + + _total_towns++; + } + + /* This is to ensure all pointers are within the limits of + * the size of the TownPool */ + if (_cur_town_ctr > GetMaxTownIndex()) + _cur_town_ctr = 0; +} + +void AfterLoadTown() +{ + Town *t; + FOR_ALL_TOWNS(t) t->InitializeLayout(); +} + +extern const ChunkHandler _town_chunk_handlers[] = { + { 'HIDS', Save_HOUSEIDS, Load_HOUSEIDS, CH_ARRAY }, + { 'CITY', Save_TOWN, Load_TOWN, CH_ARRAY | CH_LAST}, +}; diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp new file mode 100644 index 000000000..33f043b45 --- /dev/null +++ b/src/saveload/vehicle_sl.cpp @@ -0,0 +1,670 @@ +/* $Id$ */ + +/** @file vehicle_sl.cpp Code handling saving and loading of vehicles */ + +#include "../stdafx.h" +#include "../vehicle_base.h" +#include "../vehicle_func.h" +#include "../train.h" +#include "../roadveh.h" +#include "../ship.h" +#include "../aircraft.h" +#include "../effectvehicle_base.h" + +#include "saveload.h" + +#include <map> + +/* + * Link front and rear multiheaded engines to each other + * This is done when loading a savegame + */ +void ConnectMultiheadedTrains() +{ + Vehicle *v; + + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_TRAIN) { + v->u.rail.other_multiheaded_part = NULL; + } + } + + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) { + /* Two ways to associate multiheaded parts to each other: + * sequential-matching: Trains shall be arranged to look like <..>..<..>..<..>.. + * bracket-matching: Free vehicle chains shall be arranged to look like ..<..<..>..<..>..>.. + * + * Note: Old savegames might contain chains which do not comply with these rules, e.g. + * - the front and read parts have invalid orders + * - different engine types might be combined + * - there might be different amounts of front and rear parts. + * + * Note: The multiheaded parts need to be matched exactly like they are matched on the server, else desyncs will occur. + * This is why two matching strategies are needed. + */ + + bool sequential_matching = IsFrontEngine(v); + + for (Vehicle *u = v; u != NULL; u = GetNextVehicle(u)) { + if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one + + if (IsMultiheaded(u)) { + if (!IsTrainEngine(u)) { + /* we got a rear car without a front car. We will convert it to a front one */ + SetTrainEngine(u); + u->spritenum--; + } + + /* Find a matching back part */ + EngineID eid = u->engine_type; + Vehicle *w; + if (sequential_matching) { + for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) { + if (w->engine_type != eid || w->u.rail.other_multiheaded_part != NULL || !IsMultiheaded(w)) continue; + + /* we found a car to partner with this engine. Now we will make sure it face the right way */ + if (IsTrainEngine(w)) { + ClearTrainEngine(w); + w->spritenum++; + } + break; + } + } else { + uint stack_pos = 0; + for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) { + if (w->engine_type != eid || w->u.rail.other_multiheaded_part != NULL || !IsMultiheaded(w)) continue; + + if (IsTrainEngine(w)) { + stack_pos++; + } else { + if (stack_pos == 0) break; + stack_pos--; + } + } + } + + if (w != NULL) { + w->u.rail.other_multiheaded_part = u; + u->u.rail.other_multiheaded_part = w; + } else { + /* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */ + ClearMultiheaded(u); + } + } + } + } + } +} + +/** + * Converts all trains to the new subtype format introduced in savegame 16.2 + * It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found + */ +void ConvertOldMultiheadToNew() +{ + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_TRAIN) { + SetBit(v->subtype, 7); // indicates that it's the old format and needs to be converted in the next loop + } + } + + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_TRAIN) { + if (HasBit(v->subtype, 7) && ((v->subtype & ~0x80) == 0 || (v->subtype & ~0x80) == 4)) { + for (Vehicle *u = v; u != NULL; u = u->Next()) { + const RailVehicleInfo *rvi = RailVehInfo(u->engine_type); + + ClrBit(u->subtype, 7); + switch (u->subtype) { + case 0: /* TS_Front_Engine */ + if (rvi->railveh_type == RAILVEH_MULTIHEAD) SetMultiheaded(u); + SetFrontEngine(u); + SetTrainEngine(u); + break; + + case 1: /* TS_Artic_Part */ + u->subtype = 0; + SetArticulatedPart(u); + break; + + case 2: /* TS_Not_First */ + u->subtype = 0; + if (rvi->railveh_type == RAILVEH_WAGON) { + // normal wagon + SetTrainWagon(u); + break; + } + if (rvi->railveh_type == RAILVEH_MULTIHEAD && rvi->image_index == u->spritenum - 1) { + // rear end of a multiheaded engine + SetMultiheaded(u); + break; + } + if (rvi->railveh_type == RAILVEH_MULTIHEAD) SetMultiheaded(u); + SetTrainEngine(u); + break; + + case 4: /* TS_Free_Car */ + u->subtype = 0; + SetTrainWagon(u); + SetFreeWagon(u); + break; + default: NOT_REACHED(); break; + } + } + } + } + } +} + + +/** need to be called to load aircraft from old version */ +void UpdateOldAircraft() +{ + /* set airport_flags to 0 for all airports just to be sure */ + Station *st; + FOR_ALL_STATIONS(st) { + st->airport_flags = 0; // reset airport + } + + Vehicle *v_oldstyle; + FOR_ALL_VEHICLES(v_oldstyle) { + /* airplane has another vehicle with subtype 4 (shadow), helicopter also has 3 (rotor) + * skip those */ + if (v_oldstyle->type == VEH_AIRCRAFT && IsNormalAircraft(v_oldstyle)) { + /* airplane in terminal stopped doesn't hurt anyone, so goto next */ + if (v_oldstyle->vehstatus & VS_STOPPED && v_oldstyle->u.air.state == 0) { + v_oldstyle->u.air.state = HANGAR; + continue; + } + + AircraftLeaveHangar(v_oldstyle); // make airplane visible if it was in a depot for example + v_oldstyle->vehstatus &= ~VS_STOPPED; // make airplane moving + v_oldstyle->u.air.state = FLYING; + AircraftNextAirportPos_and_Order(v_oldstyle); // move it to the entry point of the airport + GetNewVehiclePosResult gp = GetNewVehiclePos(v_oldstyle); + v_oldstyle->tile = 0; // aircraft in air is tile=0 + + /* correct speed of helicopter-rotors */ + if (v_oldstyle->subtype == AIR_HELICOPTER) v_oldstyle->Next()->Next()->cur_speed = 32; + + /* set new position x,y,z */ + SetAircraftPosition(v_oldstyle, gp.x, gp.y, GetAircraftFlyingAltitude(v_oldstyle)); + } + } +} + +/** Called after load to update coordinates */ +void AfterLoadVehicles(bool part_of_load) +{ + Vehicle *v; + + FOR_ALL_VEHICLES(v) { + /* Reinstate the previous pointer */ + if (v->Next() != NULL) v->Next()->previous = v; + if (v->NextShared() != NULL) v->NextShared()->previous_shared = v; + + v->UpdateDeltaXY(v->direction); + + if (part_of_load) v->fill_percent_te_id = INVALID_TE_ID; + v->first = NULL; + if (v->type == VEH_TRAIN) v->u.rail.first_engine = INVALID_ENGINE; + if (v->type == VEH_ROAD) v->u.road.first_engine = INVALID_ENGINE; + + v->cargo.InvalidateCache(); + } + + /* AfterLoadVehicles may also be called in case of NewGRF reload, in this + * case we may not convert orders again. */ + if (part_of_load) { + /* Create shared vehicle chain for very old games (pre 5,2) and create + * OrderList from shared vehicle chains. For this to work correctly, the + * following conditions must be fulfilled: + * a) both next_shared and previous_shared are not set for pre 5,2 games + * b) both next_shared and previous_shared are set for later games + */ + std::map<Order*, OrderList*> mapping; + + FOR_ALL_VEHICLES(v) { + if (v->orders.old != NULL) { + if (CheckSavegameVersion(105)) { // Pre-105 didn't save an OrderList + if (mapping[v->orders.old] == NULL) { + /* This adds the whole shared vehicle chain for case b */ + v->orders.list = mapping[v->orders.old] = new OrderList(v->orders.old, v); + } else { + v->orders.list = mapping[v->orders.old]; + /* For old games (case a) we must create the shared vehicle chain */ + if (CheckSavegameVersionOldStyle(5, 2)) { + v->AddToShared(v->orders.list->GetFirstSharedVehicle()); + } + } + } else { // OrderList was saved as such, only recalculate not saved values + if (v->PreviousShared() == NULL) { + new (v->orders.list) OrderList(v->orders.list->GetFirstOrder(), v); + } + } + } + } + } + + FOR_ALL_VEHICLES(v) { + /* Fill the first pointers */ + if (v->Previous() == NULL) { + for (Vehicle *u = v; u != NULL; u = u->Next()) { + u->first = v; + } + } + } + + FOR_ALL_VEHICLES(v) { + assert(v->first != NULL); + + if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) { + if (IsFrontEngine(v)) v->u.rail.last_speed = v->cur_speed; // update displayed train speed + TrainConsistChanged(v, false); + } else if (v->type == VEH_ROAD && IsRoadVehFront(v)) { + RoadVehUpdateCache(v); + } + } + + /* Stop non-front engines */ + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_TRAIN && IsTrainEngine(v) && !IsFrontEngine(v)) v->vehstatus |= VS_STOPPED; + } + + FOR_ALL_VEHICLES(v) { + switch (v->type) { + case VEH_ROAD: + v->u.road.roadtype = HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD; + v->u.road.compatible_roadtypes = RoadTypeToRoadTypes(v->u.road.roadtype); + /* FALL THROUGH */ + case VEH_TRAIN: + case VEH_SHIP: + v->cur_image = v->GetImage(v->direction); + break; + + case VEH_AIRCRAFT: + if (IsNormalAircraft(v)) { + v->cur_image = v->GetImage(v->direction); + + /* The plane's shadow will have the same image as the plane */ + Vehicle *shadow = v->Next(); + shadow->cur_image = v->cur_image; + + /* In the case of a helicopter we will update the rotor sprites */ + if (v->subtype == AIR_HELICOPTER) { + Vehicle *rotor = shadow->Next(); + rotor->cur_image = GetRotorImage(v); + } + + UpdateAircraftCache(v); + } + break; + default: break; + } + + v->left_coord = INVALID_COORD; + VehiclePositionChanged(v); + } +} + +static uint8 _cargo_days; +static uint16 _cargo_source; +static uint32 _cargo_source_xy; +static uint16 _cargo_count; +static uint16 _cargo_paid_for; +static Money _cargo_feeder_share; +static uint32 _cargo_loaded_at_xy; + +/** + * Make it possible to make the saveload tables "friends" of other classes. + * @param vt the vehicle type. Can be VEH_END for the common vehicle description data + * @return the saveload description + */ +const SaveLoad *GetVehicleDescription(VehicleType vt) +{ + /** Save and load of vehicles */ + static const SaveLoad _common_veh_desc[] = { + SLE_VAR(Vehicle, subtype, SLE_UINT8), + + SLE_REF(Vehicle, next, REF_VEHICLE_OLD), + SLE_CONDVAR(Vehicle, name, SLE_NAME, 0, 83), + SLE_CONDSTR(Vehicle, name, SLE_STR, 0, 84, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, unitnumber, SLE_FILE_U8 | SLE_VAR_U16, 0, 7), + SLE_CONDVAR(Vehicle, unitnumber, SLE_UINT16, 8, SL_MAX_VERSION), + SLE_VAR(Vehicle, owner, SLE_UINT8), + SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Vehicle, tile, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, dest_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Vehicle, dest_tile, SLE_UINT32, 6, SL_MAX_VERSION), + + SLE_CONDVAR(Vehicle, x_pos, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Vehicle, x_pos, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, y_pos, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Vehicle, y_pos, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_VAR(Vehicle, z_pos, SLE_UINT8), + SLE_VAR(Vehicle, direction, SLE_UINT8), + + SLE_CONDNULL(2, 0, 57), + SLE_VAR(Vehicle, spritenum, SLE_UINT8), + SLE_CONDNULL(5, 0, 57), + SLE_VAR(Vehicle, engine_type, SLE_UINT16), + + SLE_VAR(Vehicle, max_speed, SLE_UINT16), + SLE_VAR(Vehicle, cur_speed, SLE_UINT16), + SLE_VAR(Vehicle, subspeed, SLE_UINT8), + SLE_VAR(Vehicle, acceleration, SLE_UINT8), + SLE_VAR(Vehicle, progress, SLE_UINT8), + + SLE_VAR(Vehicle, vehstatus, SLE_UINT8), + SLE_CONDVAR(Vehicle, last_station_visited, SLE_FILE_U8 | SLE_VAR_U16, 0, 4), + SLE_CONDVAR(Vehicle, last_station_visited, SLE_UINT16, 5, SL_MAX_VERSION), + + SLE_VAR(Vehicle, cargo_type, SLE_UINT8), + SLE_CONDVAR(Vehicle, cargo_subtype, SLE_UINT8, 35, SL_MAX_VERSION), + SLEG_CONDVAR( _cargo_days, SLE_UINT8, 0, 67), + SLEG_CONDVAR( _cargo_source, SLE_FILE_U8 | SLE_VAR_U16, 0, 6), + SLEG_CONDVAR( _cargo_source, SLE_UINT16, 7, 67), + SLEG_CONDVAR( _cargo_source_xy, SLE_UINT32, 44, 67), + SLE_VAR(Vehicle, cargo_cap, SLE_UINT16), + SLEG_CONDVAR( _cargo_count, SLE_UINT16, 0, 67), + SLE_CONDLST(Vehicle, cargo, REF_CARGO_PACKET, 68, SL_MAX_VERSION), + + SLE_VAR(Vehicle, day_counter, SLE_UINT8), + SLE_VAR(Vehicle, tick_counter, SLE_UINT8), + SLE_CONDVAR(Vehicle, running_ticks, SLE_UINT8, 88, SL_MAX_VERSION), + + SLE_VAR(Vehicle, cur_order_index, SLE_UINT8), + /* num_orders is now part of OrderList and is not saved but counted */ + SLE_CONDNULL(1, 0, 104), + + /* This next line is for version 4 and prior compatibility.. it temporarily reads + type and flags (which were both 4 bits) into type. Later on this is + converted correctly */ + SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, type), SLE_UINT8, 0, 4), + SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_FILE_U8 | SLE_VAR_U16, 0, 4), + + /* Orders for version 5 and on */ + SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, type), SLE_UINT8, 5, SL_MAX_VERSION), + SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, flags), SLE_UINT8, 5, SL_MAX_VERSION), + SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_UINT16, 5, SL_MAX_VERSION), + + /* Refit in current order */ + SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, refit_cargo), SLE_UINT8, 36, SL_MAX_VERSION), + SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, refit_subtype), SLE_UINT8, 36, SL_MAX_VERSION), + + /* Timetable in current order */ + SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, wait_time), SLE_UINT16, 67, SL_MAX_VERSION), + SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, travel_time), SLE_UINT16, 67, SL_MAX_VERSION), + + SLE_CONDREF(Vehicle, orders, REF_ORDER, 0, 104), + SLE_CONDREF(Vehicle, orders, REF_ORDERLIST, 105, SL_MAX_VERSION), + + SLE_CONDVAR(Vehicle, age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), + SLE_CONDVAR(Vehicle, age, SLE_INT32, 31, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, max_age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), + SLE_CONDVAR(Vehicle, max_age, SLE_INT32, 31, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, date_of_last_service, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), + SLE_CONDVAR(Vehicle, date_of_last_service, SLE_INT32, 31, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, service_interval, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), + SLE_CONDVAR(Vehicle, service_interval, SLE_INT32, 31, SL_MAX_VERSION), + SLE_VAR(Vehicle, reliability, SLE_UINT16), + SLE_VAR(Vehicle, reliability_spd_dec, SLE_UINT16), + SLE_VAR(Vehicle, breakdown_ctr, SLE_UINT8), + SLE_VAR(Vehicle, breakdown_delay, SLE_UINT8), + SLE_VAR(Vehicle, breakdowns_since_last_service, SLE_UINT8), + SLE_VAR(Vehicle, breakdown_chance, SLE_UINT8), + SLE_CONDVAR(Vehicle, build_year, SLE_FILE_U8 | SLE_VAR_I32, 0, 30), + SLE_CONDVAR(Vehicle, build_year, SLE_INT32, 31, SL_MAX_VERSION), + + SLE_VAR(Vehicle, load_unload_time_rem, SLE_UINT16), + SLEG_CONDVAR( _cargo_paid_for, SLE_UINT16, 45, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, vehicle_flags, SLE_UINT8, 40, SL_MAX_VERSION), + + SLE_CONDVAR(Vehicle, profit_this_year, SLE_FILE_I32 | SLE_VAR_I64, 0, 64), + SLE_CONDVAR(Vehicle, profit_this_year, SLE_INT64, 65, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, profit_last_year, SLE_FILE_I32 | SLE_VAR_I64, 0, 64), + SLE_CONDVAR(Vehicle, profit_last_year, SLE_INT64, 65, SL_MAX_VERSION), + SLEG_CONDVAR( _cargo_feeder_share, SLE_FILE_I32 | SLE_VAR_I64, 51, 64), + SLEG_CONDVAR( _cargo_feeder_share, SLE_INT64, 65, 67), + SLEG_CONDVAR( _cargo_loaded_at_xy, SLE_UINT32, 51, 67), + SLE_CONDVAR(Vehicle, value, SLE_FILE_I32 | SLE_VAR_I64, 0, 64), + SLE_CONDVAR(Vehicle, value, SLE_INT64, 65, SL_MAX_VERSION), + + SLE_CONDVAR(Vehicle, random_bits, SLE_UINT8, 2, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, waiting_triggers, SLE_UINT8, 2, SL_MAX_VERSION), + + SLE_CONDREF(Vehicle, next_shared, REF_VEHICLE, 2, SL_MAX_VERSION), + SLE_CONDNULL(2, 2, 68), + SLE_CONDNULL(4, 69, 100), + + SLE_CONDVAR(Vehicle, group_id, SLE_UINT16, 60, SL_MAX_VERSION), + + SLE_CONDVAR(Vehicle, current_order_time, SLE_UINT32, 67, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, lateness_counter, SLE_INT32, 67, SL_MAX_VERSION), + + /* reserve extra space in savegame here. (currently 10 bytes) */ + SLE_CONDNULL(10, 2, SL_MAX_VERSION), + + SLE_END() + }; + + + static const SaveLoad _train_desc[] = { + SLE_WRITEBYTE(Vehicle, type, VEH_TRAIN), + SLE_VEH_INCLUDEX(), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, crash_anim_pos), SLE_UINT16), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, force_proceed), SLE_UINT8), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, railtype), SLE_UINT8), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, track), SLE_UINT8), + + SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, flags), SLE_FILE_U8 | SLE_VAR_U16, 2, 99), + SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, flags), SLE_UINT16, 100, SL_MAX_VERSION), + SLE_CONDNULL(2, 2, 59), + + SLE_CONDNULL(2, 2, 19), + /* reserve extra space in savegame here. (currently 11 bytes) */ + SLE_CONDNULL(11, 2, SL_MAX_VERSION), + + SLE_END() + }; + + static const SaveLoad _roadveh_desc[] = { + SLE_WRITEBYTE(Vehicle, type, VEH_ROAD), + SLE_VEH_INCLUDEX(), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, state), SLE_UINT8), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, frame), SLE_UINT8), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, blocked_ctr), SLE_UINT16), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, overtaking), SLE_UINT8), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, overtaking_ctr), SLE_UINT8), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, crashed_ctr), SLE_UINT16), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, reverse_ctr), SLE_UINT8), + + SLE_CONDREFX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, slot), REF_ROADSTOPS, 6, SL_MAX_VERSION), + SLE_CONDNULL(1, 6, SL_MAX_VERSION), + SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, slot_age), SLE_UINT8, 6, SL_MAX_VERSION), + /* reserve extra space in savegame here. (currently 16 bytes) */ + SLE_CONDNULL(16, 2, SL_MAX_VERSION), + + SLE_END() + }; + + static const SaveLoad _ship_desc[] = { + SLE_WRITEBYTE(Vehicle, type, VEH_SHIP), + SLE_VEH_INCLUDEX(), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleShip, state), SLE_UINT8), + + /* reserve extra space in savegame here. (currently 16 bytes) */ + SLE_CONDNULL(16, 2, SL_MAX_VERSION), + + SLE_END() + }; + + static const SaveLoad _aircraft_desc[] = { + SLE_WRITEBYTE(Vehicle, type, VEH_AIRCRAFT), + SLE_VEH_INCLUDEX(), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, crashed_counter), SLE_UINT16), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, pos), SLE_UINT8), + + SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, targetairport), SLE_FILE_U8 | SLE_VAR_U16, 0, 4), + SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, targetairport), SLE_UINT16, 5, SL_MAX_VERSION), + + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, state), SLE_UINT8), + + SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, previous_pos), SLE_UINT8, 2, SL_MAX_VERSION), + + /* reserve extra space in savegame here. (currently 15 bytes) */ + SLE_CONDNULL(15, 2, SL_MAX_VERSION), + + SLE_END() + }; + + static const SaveLoad _special_desc[] = { + SLE_WRITEBYTE(Vehicle, type, VEH_EFFECT), + + SLE_VAR(Vehicle, subtype, SLE_UINT8), + + SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Vehicle, tile, SLE_UINT32, 6, SL_MAX_VERSION), + + SLE_CONDVAR(Vehicle, x_pos, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), + SLE_CONDVAR(Vehicle, x_pos, SLE_INT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, y_pos, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), + SLE_CONDVAR(Vehicle, y_pos, SLE_INT32, 6, SL_MAX_VERSION), + SLE_VAR(Vehicle, z_pos, SLE_UINT8), + + SLE_VAR(Vehicle, cur_image, SLE_UINT16), + SLE_CONDNULL(5, 0, 57), + SLE_VAR(Vehicle, progress, SLE_UINT8), + SLE_VAR(Vehicle, vehstatus, SLE_UINT8), + + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleEffect, animation_state), SLE_UINT16), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleEffect, animation_substate), SLE_UINT8), + + SLE_CONDVAR(Vehicle, spritenum, SLE_UINT8, 2, SL_MAX_VERSION), + + /* reserve extra space in savegame here. (currently 15 bytes) */ + SLE_CONDNULL(15, 2, SL_MAX_VERSION), + + SLE_END() + }; + + static const SaveLoad _disaster_desc[] = { + SLE_WRITEBYTE(Vehicle, type, VEH_DISASTER), + + SLE_REF(Vehicle, next, REF_VEHICLE_OLD), + + SLE_VAR(Vehicle, subtype, SLE_UINT8), + SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Vehicle, tile, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, dest_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Vehicle, dest_tile, SLE_UINT32, 6, SL_MAX_VERSION), + + SLE_CONDVAR(Vehicle, x_pos, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), + SLE_CONDVAR(Vehicle, x_pos, SLE_INT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, y_pos, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), + SLE_CONDVAR(Vehicle, y_pos, SLE_INT32, 6, SL_MAX_VERSION), + SLE_VAR(Vehicle, z_pos, SLE_UINT8), + SLE_VAR(Vehicle, direction, SLE_UINT8), + + SLE_CONDNULL(5, 0, 57), + SLE_VAR(Vehicle, owner, SLE_UINT8), + SLE_VAR(Vehicle, vehstatus, SLE_UINT8), + SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_FILE_U8 | SLE_VAR_U16, 0, 4), + SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_UINT16, 5, SL_MAX_VERSION), + + SLE_VAR(Vehicle, cur_image, SLE_UINT16), + SLE_CONDVAR(Vehicle, age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), + SLE_CONDVAR(Vehicle, age, SLE_INT32, 31, SL_MAX_VERSION), + SLE_VAR(Vehicle, tick_counter, SLE_UINT8), + + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, image_override), SLE_UINT16), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, big_ufo_destroyer_target), SLE_UINT16), + + /* reserve extra space in savegame here. (currently 16 bytes) */ + SLE_CONDNULL(16, 2, SL_MAX_VERSION), + + SLE_END() + }; + + + static const SaveLoad *_veh_descs[] = { + _train_desc, + _roadveh_desc, + _ship_desc, + _aircraft_desc, + _special_desc, + _disaster_desc, + _common_veh_desc, + }; + + return _veh_descs[vt]; +} + +/** Will be called when the vehicles need to be saved. */ +static void Save_VEHS() +{ + Vehicle *v; + /* Write the vehicles */ + FOR_ALL_VEHICLES(v) { + SlSetArrayIndex(v->index); + SlObject(v, GetVehicleDescription(v->type)); + } +} + +/** Will be called when vehicles need to be loaded. */ +void Load_VEHS() +{ + int index; + + _cargo_count = 0; + + while ((index = SlIterateArray()) != -1) { + Vehicle *v; + VehicleType vtype = (VehicleType)SlReadByte(); + + switch (vtype) { + case VEH_TRAIN: v = new (index) Train(); break; + case VEH_ROAD: v = new (index) RoadVehicle(); break; + case VEH_SHIP: v = new (index) Ship(); break; + case VEH_AIRCRAFT: v = new (index) Aircraft(); break; + case VEH_EFFECT: v = new (index) EffectVehicle(); break; + case VEH_DISASTER: v = new (index) DisasterVehicle(); break; + case VEH_INVALID: v = new (index) InvalidVehicle(); break; + default: NOT_REACHED(); + } + + SlObject(v, GetVehicleDescription(vtype)); + + if (_cargo_count != 0 && IsCompanyBuildableVehicleType(v)) { + /* Don't construct the packet with station here, because that'll fail with old savegames */ + CargoPacket *cp = new CargoPacket(); + cp->source = _cargo_source; + cp->source_xy = _cargo_source_xy; + cp->count = _cargo_count; + cp->days_in_transit = _cargo_days; + cp->feeder_share = _cargo_feeder_share; + cp->loaded_at_xy = _cargo_loaded_at_xy; + v->cargo.Append(cp); + } + + /* Old savegames used 'last_station_visited = 0xFF' */ + if (CheckSavegameVersion(5) && v->last_station_visited == 0xFF) + v->last_station_visited = INVALID_STATION; + + if (CheckSavegameVersion(5)) { + /* Convert the current_order.type (which is a mix of type and flags, because + * in those versions, they both were 4 bits big) to type and flags */ + v->current_order.flags = GB(v->current_order.type, 4, 4); + v->current_order.type &= 0x0F; + } + + /* Advanced vehicle lists got added */ + if (CheckSavegameVersion(60)) v->group_id = DEFAULT_GROUP; + } +} + +extern const ChunkHandler _veh_chunk_handlers[] = { + { 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY | CH_LAST}, +}; diff --git a/src/saveload/waypoint_sl.cpp b/src/saveload/waypoint_sl.cpp new file mode 100644 index 000000000..e8a8bf949 --- /dev/null +++ b/src/saveload/waypoint_sl.cpp @@ -0,0 +1,96 @@ +/* $Id$ */ + +/** @file waypoint_sl.cpp Code handling saving and loading of waypoints */ + +#include "../stdafx.h" +#include "../waypoint.h" +#include "../newgrf_station.h" +#include "../town.h" + +#include "table/strings.h" + +#include "saveload.h" + +/** + * Update waypoint graphics id against saved GRFID/localidx. + * This is to ensure the chosen graphics are correct if GRF files are changed. + */ +void AfterLoadWaypoints() +{ + Waypoint *wp; + + FOR_ALL_WAYPOINTS(wp) { + uint i; + + if (wp->grfid == 0) continue; + + for (i = 0; i < GetNumCustomStations(STAT_CLASS_WAYP); i++) { + const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, i); + if (statspec != NULL && statspec->grffile->grfid == wp->grfid && statspec->localidx == wp->localidx) { + wp->stat_id = i; + break; + } + } + } +} + +/** + * Fix savegames which stored waypoints in their old format + */ +void FixOldWaypoints() +{ + Waypoint *wp; + + /* Convert the old 'town_or_string', to 'string' / 'town' / 'town_cn' */ + FOR_ALL_WAYPOINTS(wp) { + wp->town_index = ClosestTownFromTile(wp->xy, UINT_MAX)->index; + wp->town_cn = 0; + if (wp->string & 0xC000) { + wp->town_cn = wp->string & 0x3F; + wp->string = STR_NULL; + } + } +} + +static const SaveLoad _waypoint_desc[] = { + SLE_CONDVAR(Waypoint, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Waypoint, xy, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(Waypoint, town_index, SLE_UINT16, 12, SL_MAX_VERSION), + SLE_CONDVAR(Waypoint, town_cn, SLE_FILE_U8 | SLE_VAR_U16, 12, 88), + SLE_CONDVAR(Waypoint, town_cn, SLE_UINT16, 89, SL_MAX_VERSION), + SLE_CONDVAR(Waypoint, string, SLE_STRINGID, 0, 83), + SLE_CONDSTR(Waypoint, name, SLE_STR, 0, 84, SL_MAX_VERSION), + SLE_VAR(Waypoint, deleted, SLE_UINT8), + + SLE_CONDVAR(Waypoint, build_date, SLE_FILE_U16 | SLE_VAR_I32, 3, 30), + SLE_CONDVAR(Waypoint, build_date, SLE_INT32, 31, SL_MAX_VERSION), + SLE_CONDVAR(Waypoint, localidx, SLE_UINT8, 3, SL_MAX_VERSION), + SLE_CONDVAR(Waypoint, grfid, SLE_UINT32, 17, SL_MAX_VERSION), + SLE_CONDVAR(Waypoint, owner, SLE_UINT8, 101, SL_MAX_VERSION), + + SLE_END() +}; + +static void Save_WAYP() +{ + Waypoint *wp; + + FOR_ALL_WAYPOINTS(wp) { + SlSetArrayIndex(wp->index); + SlObject(wp, _waypoint_desc); + } +} + +static void Load_WAYP() +{ + int index; + + while ((index = SlIterateArray()) != -1) { + Waypoint *wp = new (index) Waypoint(); + SlObject(wp, _waypoint_desc); + } +} + +extern const ChunkHandler _waypoint_chunk_handlers[] = { + { 'CHKP', Save_WAYP, Load_WAYP, CH_ARRAY | CH_LAST}, +}; diff --git a/src/screenshot.cpp b/src/screenshot.cpp index ced474d91..4fd62c4dd 100644 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -17,7 +17,7 @@ #include "core/alloc_func.hpp" #include "core/endian_func.hpp" #include "map_func.h" -#include "saveload.h" +#include "saveload/saveload.h" #include "company_func.h" #include "table/strings.h" diff --git a/src/settings.cpp b/src/settings.cpp index 53fafaf9b..a7bea9cf0 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -29,7 +29,6 @@ #include "settings_internal.h" #include "command_func.h" #include "console_func.h" -#include "saveload.h" #include "npf.h" #include "yapf/yapf.h" #include "newgrf.h" diff --git a/src/settings_internal.h b/src/settings_internal.h index 73357451c..20cd4eca5 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -5,7 +5,7 @@ #ifndef SETTINGS_INTERNAL_H #define SETTINGS_INTERNAL_H -#include "saveload.h" +#include "saveload/saveload.h" #include "settings_type.h" /** Convention/Type of settings. This is then further specified if necessary diff --git a/src/signs.cpp b/src/signs.cpp index 1c2d846cd..7866783c7 100644 --- a/src/signs.cpp +++ b/src/signs.cpp @@ -8,7 +8,6 @@ #include "company_func.h" #include "signs_base.h" #include "signs_func.h" -#include "saveload.h" #include "command_func.h" #include "variables.h" #include "strings_func.h" @@ -56,17 +55,12 @@ static void UpdateSignVirtCoords(Sign *si) UpdateViewportSignPos(&si->sign, pt.x, pt.y - 6, STR_2806); } -/** - * - * Update the coordinates of all signs - * - */ +/** Update the coordinates of all signs */ void UpdateAllSignVirtCoords() { Sign *si; FOR_ALL_SIGNS(si) UpdateSignVirtCoords(si); - } /** @@ -203,48 +197,3 @@ void InitializeSigns() _Sign_pool.CleanPool(); _Sign_pool.AddBlockToPool(); } - -static const SaveLoad _sign_desc[] = { - SLE_CONDVAR(Sign, name, SLE_NAME, 0, 83), - SLE_CONDSTR(Sign, name, SLE_STR, 0, 84, SL_MAX_VERSION), - SLE_CONDVAR(Sign, x, SLE_FILE_I16 | SLE_VAR_I32, 0, 4), - SLE_CONDVAR(Sign, y, SLE_FILE_I16 | SLE_VAR_I32, 0, 4), - SLE_CONDVAR(Sign, x, SLE_INT32, 5, SL_MAX_VERSION), - SLE_CONDVAR(Sign, y, SLE_INT32, 5, SL_MAX_VERSION), - SLE_CONDVAR(Sign, owner, SLE_UINT8, 6, SL_MAX_VERSION), - SLE_VAR(Sign, z, SLE_UINT8), - SLE_END() -}; - -/** - * - * Save all signs - * - */ -static void Save_SIGN() -{ - Sign *si; - - FOR_ALL_SIGNS(si) { - SlSetArrayIndex(si->index); - SlObject(si, _sign_desc); - } -} - -/** - * - * Load all signs - * - */ -static void Load_SIGN() -{ - int index; - while ((index = SlIterateArray()) != -1) { - Sign *si = new (index) Sign(); - SlObject(si, _sign_desc); - } -} - -extern const ChunkHandler _sign_chunk_handlers[] = { - { 'SIGN', Save_SIGN, Load_SIGN, CH_ARRAY | CH_LAST}, -}; diff --git a/src/signs_base.h b/src/signs_base.h index 1c25656e2..52737a833 100644 --- a/src/signs_base.h +++ b/src/signs_base.h @@ -7,6 +7,7 @@ #include "signs_type.h" #include "viewport_type.h" +#include "tile_type.h" #include "oldpool.h" DECLARE_OLD_POOL(Sign, Sign, 2, 16000) diff --git a/src/station.cpp b/src/station.cpp index 672c3d320..df256adb3 100644 --- a/src/station.cpp +++ b/src/station.cpp @@ -9,7 +9,6 @@ #include "station_map.h" #include "station_base.h" #include "town.h" -#include "saveload.h" #include "company_func.h" #include "airport.h" #include "sprite.h" diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 1923ebd61..7abdd0d2d 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -15,7 +15,6 @@ #include "command_func.h" #include "town.h" #include "news_func.h" -#include "saveload.h" #include "airport.h" #include "sprite.h" #include "train.h" @@ -3185,24 +3184,6 @@ void InitializeStations() _station_tick_ctr = 0; } - -void AfterLoadStations() -{ - /* Update the speclists of all stations to point to the currently loaded custom stations. */ - Station *st; - FOR_ALL_STATIONS(st) { - for (uint i = 0; i < st->num_specs; i++) { - if (st->speclist[i].grfid == 0) continue; - - st->speclist[i].spec = GetCustomStationSpecByGrf(st->speclist[i].grfid, st->speclist[i].localidx); - } - - for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache(); - - StationUpdateAnimTriggers(st); - } -} - static CommandCost TerraformTile_Station(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new) { if (_settings_game.construction.build_on_slopes && AutoslopeEnabled()) { @@ -3255,200 +3236,3 @@ extern const TileTypeProcs _tile_type_station_procs = { GetFoundation_Station, /* get_foundation_proc */ TerraformTile_Station, /* terraform_tile_proc */ }; - -static const SaveLoad _roadstop_desc[] = { - SLE_VAR(RoadStop, xy, SLE_UINT32), - SLE_CONDNULL(1, 0, 44), - SLE_VAR(RoadStop, status, SLE_UINT8), - /* Index was saved in some versions, but this is not needed */ - SLE_CONDNULL(4, 0, 8), - SLE_CONDNULL(2, 0, 44), - SLE_CONDNULL(1, 0, 25), - - SLE_REF(RoadStop, next, REF_ROADSTOPS), - SLE_CONDNULL(2, 0, 44), - - SLE_CONDNULL(4, 0, 24), - SLE_CONDNULL(1, 25, 25), - - SLE_END() -}; - -static const SaveLoad _station_desc[] = { - SLE_CONDVAR(Station, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Station, xy, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDNULL(4, 0, 5), ///< bus/lorry tile - SLE_CONDVAR(Station, train_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Station, train_tile, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(Station, airport_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Station, airport_tile, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(Station, dock_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Station, dock_tile, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_REF(Station, town, REF_TOWN), - SLE_VAR(Station, trainst_w, SLE_UINT8), - SLE_CONDVAR(Station, trainst_h, SLE_UINT8, 2, SL_MAX_VERSION), - - SLE_CONDNULL(1, 0, 3), ///< alpha_order - - SLE_VAR(Station, string_id, SLE_STRINGID), - SLE_CONDSTR(Station, name, SLE_STR, 0, 84, SL_MAX_VERSION), - SLE_CONDVAR(Station, indtype, SLE_UINT8, 103, SL_MAX_VERSION), - SLE_VAR(Station, had_vehicle_of_type, SLE_UINT16), - - SLE_VAR(Station, time_since_load, SLE_UINT8), - SLE_VAR(Station, time_since_unload, SLE_UINT8), - SLE_VAR(Station, delete_ctr, SLE_UINT8), - SLE_VAR(Station, owner, SLE_UINT8), - SLE_VAR(Station, facilities, SLE_UINT8), - SLE_VAR(Station, airport_type, SLE_UINT8), - - SLE_CONDNULL(2, 0, 5), ///< Truck/bus stop status - SLE_CONDNULL(1, 0, 4), ///< Blocked months - - SLE_CONDVAR(Station, airport_flags, SLE_VAR_U64 | SLE_FILE_U16, 0, 2), - SLE_CONDVAR(Station, airport_flags, SLE_VAR_U64 | SLE_FILE_U32, 3, 45), - SLE_CONDVAR(Station, airport_flags, SLE_UINT64, 46, SL_MAX_VERSION), - - SLE_CONDNULL(2, 0, 25), ///< last-vehicle - SLE_CONDVAR(Station, last_vehicle_type, SLE_UINT8, 26, SL_MAX_VERSION), - - SLE_CONDNULL(2, 3, 25), ///< custom station class and id - SLE_CONDVAR(Station, build_date, SLE_FILE_U16 | SLE_VAR_I32, 3, 30), - SLE_CONDVAR(Station, build_date, SLE_INT32, 31, SL_MAX_VERSION), - - SLE_CONDREF(Station, bus_stops, REF_ROADSTOPS, 6, SL_MAX_VERSION), - SLE_CONDREF(Station, truck_stops, REF_ROADSTOPS, 6, SL_MAX_VERSION), - - /* Used by newstations for graphic variations */ - SLE_CONDVAR(Station, random_bits, SLE_UINT16, 27, SL_MAX_VERSION), - SLE_CONDVAR(Station, waiting_triggers, SLE_UINT8, 27, SL_MAX_VERSION), - SLE_CONDVAR(Station, num_specs, SLE_UINT8, 27, SL_MAX_VERSION), - - SLE_CONDLST(Station, loading_vehicles, REF_VEHICLE, 57, SL_MAX_VERSION), - - /* reserve extra space in savegame here. (currently 32 bytes) */ - SLE_CONDNULL(32, 2, SL_MAX_VERSION), - - SLE_END() -}; - -static uint16 _waiting_acceptance; -static uint16 _cargo_source; -static uint32 _cargo_source_xy; -static uint16 _cargo_days; -static Money _cargo_feeder_share; - -static const SaveLoad _station_speclist_desc[] = { - SLE_CONDVAR(StationSpecList, grfid, SLE_UINT32, 27, SL_MAX_VERSION), - SLE_CONDVAR(StationSpecList, localidx, SLE_UINT8, 27, SL_MAX_VERSION), - - SLE_END() -}; - - -void SaveLoad_STNS(Station *st) -{ - static const SaveLoad _goods_desc[] = { - SLEG_CONDVAR( _waiting_acceptance, SLE_UINT16, 0, 67), - SLE_CONDVAR(GoodsEntry, acceptance_pickup, SLE_UINT8, 68, SL_MAX_VERSION), - SLE_CONDNULL(2, 51, 67), - SLE_VAR(GoodsEntry, days_since_pickup, SLE_UINT8), - SLE_VAR(GoodsEntry, rating, SLE_UINT8), - SLEG_CONDVAR( _cargo_source, SLE_FILE_U8 | SLE_VAR_U16, 0, 6), - SLEG_CONDVAR( _cargo_source, SLE_UINT16, 7, 67), - SLEG_CONDVAR( _cargo_source_xy, SLE_UINT32, 44, 67), - SLEG_CONDVAR( _cargo_days, SLE_UINT8, 0, 67), - SLE_VAR(GoodsEntry, last_speed, SLE_UINT8), - SLE_VAR(GoodsEntry, last_age, SLE_UINT8), - SLEG_CONDVAR( _cargo_feeder_share, SLE_FILE_U32 | SLE_VAR_I64, 14, 64), - SLEG_CONDVAR( _cargo_feeder_share, SLE_INT64, 65, 67), - SLE_CONDLST(GoodsEntry, cargo.packets, REF_CARGO_PACKET, 68, SL_MAX_VERSION), - - SLE_END() -}; - - - SlObject(st, _station_desc); - - _waiting_acceptance = 0; - - uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO; - for (CargoID i = 0; i < num_cargo; i++) { - GoodsEntry *ge = &st->goods[i]; - SlObject(ge, _goods_desc); - if (CheckSavegameVersion(68)) { - SB(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15)); - if (GB(_waiting_acceptance, 0, 12) != 0) { - /* Don't construct the packet with station here, because that'll fail with old savegames */ - CargoPacket *cp = new CargoPacket(); - /* In old versions, enroute_from used 0xFF as INVALID_STATION */ - cp->source = (CheckSavegameVersion(7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source; - cp->count = GB(_waiting_acceptance, 0, 12); - cp->days_in_transit = _cargo_days; - cp->feeder_share = _cargo_feeder_share; - cp->source_xy = _cargo_source_xy; - cp->days_in_transit = _cargo_days; - cp->feeder_share = _cargo_feeder_share; - SB(ge->acceptance_pickup, GoodsEntry::PICKUP, 1, 1); - ge->cargo.Append(cp); - } - } - } - - if (st->num_specs != 0) { - /* Allocate speclist memory when loading a game */ - if (st->speclist == NULL) st->speclist = CallocT<StationSpecList>(st->num_specs); - for (uint i = 0; i < st->num_specs; i++) { - SlObject(&st->speclist[i], _station_speclist_desc); - } - } -} - -static void Save_STNS() -{ - Station *st; - /* Write the stations */ - FOR_ALL_STATIONS(st) { - SlSetArrayIndex(st->index); - SlAutolength((AutolengthProc*)SaveLoad_STNS, st); - } -} - -static void Load_STNS() -{ - int index; - while ((index = SlIterateArray()) != -1) { - Station *st = new (index) Station(); - - SaveLoad_STNS(st); - } - - /* This is to ensure all pointers are within the limits of _stations_size */ - if (_station_tick_ctr > GetMaxStationIndex()) _station_tick_ctr = 0; -} - -static void Save_ROADSTOP() -{ - RoadStop *rs; - - FOR_ALL_ROADSTOPS(rs) { - SlSetArrayIndex(rs->index); - SlObject(rs, _roadstop_desc); - } -} - -static void Load_ROADSTOP() -{ - int index; - - while ((index = SlIterateArray()) != -1) { - RoadStop *rs = new (index) RoadStop(INVALID_TILE); - - SlObject(rs, _roadstop_desc); - } -} - -extern const ChunkHandler _station_chunk_handlers[] = { - { 'STNS', Save_STNS, Load_STNS, CH_ARRAY }, - { 'ROAD', Save_ROADSTOP, Load_ROADSTOP, CH_ARRAY | CH_LAST}, -}; diff --git a/src/station_func.h b/src/station_func.h index ebb41a40d..9f47cfb38 100644 --- a/src/station_func.h +++ b/src/station_func.h @@ -25,7 +25,6 @@ StationSet FindStationsAroundTiles(TileIndex tile, int w_prod, int h_prod); void ShowStationViewWindow(StationID station); void UpdateAllStationVirtCoord(); -void AfterLoadStations(); void GetProductionAroundTiles(AcceptedCargo produced, TileIndex tile, int w, int h, int rad); void GetAcceptanceAroundTiles(AcceptedCargo accepts, TileIndex tile, int w, int h, int rad); diff --git a/src/strings.cpp b/src/strings.cpp index a03354ae5..5aa15fe0f 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -39,7 +39,6 @@ #include "video/video_driver.hpp" #include "engine_func.h" #include "engine_base.h" -#include "saveload.h" #include "strgen/strgen.h" #include "table/strings.h" @@ -1593,114 +1592,3 @@ void CheckForMissingGlyphsInLoadedLanguagePack() /* --- Handling of saving/loading string IDs from old savegames --- */ -/** - * Remap a string ID from the old format to the new format - * @param s StringID that requires remapping - * @return translated ID - */ -StringID RemapOldStringID(StringID s) -{ - switch (s) { - case 0x0006: return STR_SV_EMPTY; - case 0x7000: return STR_SV_UNNAMED; - case 0x70E4: return SPECSTR_PLAYERNAME_ENGLISH; - case 0x70E9: return SPECSTR_PLAYERNAME_ENGLISH; - case 0x8864: return STR_SV_TRAIN_NAME; - case 0x902B: return STR_SV_ROADVEH_NAME; - case 0x9830: return STR_SV_SHIP_NAME; - case 0xA02F: return STR_SV_AIRCRAFT_NAME; - - default: - if (IsInsideMM(s, 0x300F, 0x3030)) { - return s - 0x300F + STR_SV_STNAME; - } else { - return s; - } - } -} - -/** Location to load the old names to. */ -char *_old_name_array = NULL; - -/** - * Copy and convert old custom names to UTF-8. - * They were all stored in a 512 by 32 long string array and are - * now stored with stations, waypoints and other places with names. - * @param id the StringID of the custom name to clone. - * @return the clones custom name. - */ -char *CopyFromOldName(StringID id) -{ - /* Is this name an (old) custom name? */ - if (GB(id, 11, 5) != 15) return NULL; - - if (CheckSavegameVersion(37)) { - /* Old names were 32 characters long, so 128 characters should be - * plenty to allow for expansion when converted to UTF-8. */ - char tmp[128]; - const char *strfrom = &_old_name_array[32 * GB(id, 0, 9)]; - char *strto = tmp; - - for (; *strfrom != '\0'; strfrom++) { - WChar c = (byte)*strfrom; - - /* Map from non-ISO8859-15 characters to UTF-8. */ - switch (c) { - case 0xA4: c = 0x20AC; break; // Euro - case 0xA6: c = 0x0160; break; // S with caron - case 0xA8: c = 0x0161; break; // s with caron - case 0xB4: c = 0x017D; break; // Z with caron - case 0xB8: c = 0x017E; break; // z with caron - case 0xBC: c = 0x0152; break; // OE ligature - case 0xBD: c = 0x0153; break; // oe ligature - case 0xBE: c = 0x0178; break; // Y with diaresis - default: break; - } - - /* Check character will fit into our buffer. */ - if (strto + Utf8CharLen(c) > lastof(tmp)) break; - - strto += Utf8Encode(strto, c); - } - - /* Terminate the new string and copy it back to the name array */ - *strto = '\0'; - - return strdup(tmp); - } else { - /* Name will already be in UTF-8. */ - return strdup(&_old_name_array[32 * GB(id, 0, 9)]); - } -} - -/** - * Free the memory of the old names array. - * Should be called once the old names have all been converted. - */ -void ResetOldNames() -{ - free(_old_name_array); - _old_name_array = NULL; -} - -/** - * Initialize the old names table memory. - */ -void InitializeOldNames() -{ - free(_old_name_array); - _old_name_array = CallocT<char>(512 * 32); -} - -static void Load_NAME() -{ - int index; - - while ((index = SlIterateArray()) != -1) { - SlArray(&_old_name_array[32 * index], SlGetFieldLength(), SLE_UINT8); - } -} - -extern const ChunkHandler _name_chunk_handlers[] = { - { 'NAME', NULL, Load_NAME, CH_ARRAY | CH_LAST}, -}; diff --git a/src/strings_func.h b/src/strings_func.h index 2c53bac8c..a1b090195 100644 --- a/src/strings_func.h +++ b/src/strings_func.h @@ -68,7 +68,4 @@ struct StringIDCompare void CheckForMissingGlyphsInLoadedLanguagePack(); -StringID RemapOldStringID(StringID s); -char *CopyFromOldName(StringID id); - #endif /* STRINGS_TYPE_H */ diff --git a/src/town.h b/src/town.h index 0e2b2221b..1d9fb3380 100644 --- a/src/town.h +++ b/src/town.h @@ -362,7 +362,6 @@ extern int _cleared_town_rating; void ResetHouses(); void ClearTownHouse(Town *t, TileIndex tile); -void AfterLoadTown(); void UpdateTownMaxPass(Town *t); void UpdateTownRadius(Town *t); bool CheckIfAuthorityAllows(TileIndex tile); diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 218f4d9c7..c666442c7 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -19,7 +19,6 @@ #include "station_base.h" #include "company_base.h" #include "news_func.h" -#include "saveload.h" #include "gui.h" #include "unmovable_map.h" #include "water_map.h" @@ -2676,155 +2675,6 @@ extern const TileTypeProcs _tile_type_town_procs = { TerraformTile_Town, // terraform_tile_proc }; - -/** Save and load of towns. */ -static const SaveLoad _town_desc[] = { - SLE_CONDVAR(Town, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Town, xy, SLE_UINT32, 6, SL_MAX_VERSION), - - SLE_CONDNULL(2, 0, 2), ///< population, no longer in use - SLE_CONDNULL(4, 3, 84), ///< population, no longer in use - SLE_CONDNULL(2, 0, 91), ///< num_houses, no longer in use - - SLE_CONDVAR(Town, townnamegrfid, SLE_UINT32, 66, SL_MAX_VERSION), - SLE_VAR(Town, townnametype, SLE_UINT16), - SLE_VAR(Town, townnameparts, SLE_UINT32), - SLE_CONDSTR(Town, name, SLE_STR, 0, 84, SL_MAX_VERSION), - - SLE_VAR(Town, flags12, SLE_UINT8), - SLE_CONDVAR(Town, statues, SLE_FILE_U8 | SLE_VAR_U16, 0, 103), - SLE_CONDVAR(Town, statues, SLE_UINT16, 104, SL_MAX_VERSION), - - SLE_CONDNULL(1, 0, 1), ///< sort_index, no longer in use - - SLE_CONDVAR(Town, have_ratings, SLE_FILE_U8 | SLE_VAR_U16, 0, 103), - SLE_CONDVAR(Town, have_ratings, SLE_UINT16, 104, SL_MAX_VERSION), - SLE_CONDARR(Town, ratings, SLE_INT16, 8, 0, 103), - SLE_CONDARR(Town, ratings, SLE_INT16, MAX_COMPANIES, 104, SL_MAX_VERSION), - /* failed bribe attempts are stored since savegame format 4 */ - SLE_CONDARR(Town, unwanted, SLE_INT8, 8, 4, 103), - SLE_CONDARR(Town, unwanted, SLE_INT8, MAX_COMPANIES, 104, SL_MAX_VERSION), - - SLE_CONDVAR(Town, max_pass, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), - SLE_CONDVAR(Town, max_mail, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), - SLE_CONDVAR(Town, new_max_pass, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), - SLE_CONDVAR(Town, new_max_mail, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), - SLE_CONDVAR(Town, act_pass, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), - SLE_CONDVAR(Town, act_mail, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), - SLE_CONDVAR(Town, new_act_pass, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), - SLE_CONDVAR(Town, new_act_mail, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), - - SLE_CONDVAR(Town, max_pass, SLE_UINT32, 9, SL_MAX_VERSION), - SLE_CONDVAR(Town, max_mail, SLE_UINT32, 9, SL_MAX_VERSION), - SLE_CONDVAR(Town, new_max_pass, SLE_UINT32, 9, SL_MAX_VERSION), - SLE_CONDVAR(Town, new_max_mail, SLE_UINT32, 9, SL_MAX_VERSION), - SLE_CONDVAR(Town, act_pass, SLE_UINT32, 9, SL_MAX_VERSION), - SLE_CONDVAR(Town, act_mail, SLE_UINT32, 9, SL_MAX_VERSION), - SLE_CONDVAR(Town, new_act_pass, SLE_UINT32, 9, SL_MAX_VERSION), - SLE_CONDVAR(Town, new_act_mail, SLE_UINT32, 9, SL_MAX_VERSION), - - SLE_VAR(Town, pct_pass_transported, SLE_UINT8), - SLE_VAR(Town, pct_mail_transported, SLE_UINT8), - - SLE_VAR(Town, act_food, SLE_UINT16), - SLE_VAR(Town, act_water, SLE_UINT16), - SLE_VAR(Town, new_act_food, SLE_UINT16), - SLE_VAR(Town, new_act_water, SLE_UINT16), - - SLE_CONDVAR(Town, time_until_rebuild, SLE_UINT8, 0, 53), - SLE_CONDVAR(Town, grow_counter, SLE_UINT8, 0, 53), - SLE_CONDVAR(Town, growth_rate, SLE_UINT8, 0, 53), - - SLE_CONDVAR(Town, time_until_rebuild, SLE_UINT16, 54, SL_MAX_VERSION), - SLE_CONDVAR(Town, grow_counter, SLE_UINT16, 54, SL_MAX_VERSION), - SLE_CONDVAR(Town, growth_rate, SLE_INT16, 54, SL_MAX_VERSION), - - SLE_VAR(Town, fund_buildings_months, SLE_UINT8), - SLE_VAR(Town, road_build_months, SLE_UINT8), - - SLE_CONDVAR(Town, exclusivity, SLE_UINT8, 2, SL_MAX_VERSION), - SLE_CONDVAR(Town, exclusive_counter, SLE_UINT8, 2, SL_MAX_VERSION), - - SLE_CONDVAR(Town, larger_town, SLE_BOOL, 56, SL_MAX_VERSION), - - /* reserve extra space in savegame here. (currently 30 bytes) */ - SLE_CONDNULL(30, 2, SL_MAX_VERSION), - - SLE_END() -}; - -/* Save and load the mapping between the house id on the map, and the grf file - * it came from. */ -static const SaveLoad _house_id_mapping_desc[] = { - SLE_VAR(EntityIDMapping, grfid, SLE_UINT32), - SLE_VAR(EntityIDMapping, entity_id, SLE_UINT8), - SLE_VAR(EntityIDMapping, substitute_id, SLE_UINT8), - SLE_END() -}; - -static void Save_HOUSEIDS() -{ - uint j = _house_mngr.GetMaxMapping(); - - for (uint i = 0; i < j; i++) { - SlSetArrayIndex(i); - SlObject(&_house_mngr.mapping_ID[i], _house_id_mapping_desc); - } -} - -static void Load_HOUSEIDS() -{ - int index; - - _house_mngr.ResetMapping(); - uint max_id = _house_mngr.GetMaxMapping(); - - while ((index = SlIterateArray()) != -1) { - if ((uint)index >= max_id) break; - SlObject(&_house_mngr.mapping_ID[index], _house_id_mapping_desc); - } -} - -static void Save_TOWN() -{ - Town *t; - - FOR_ALL_TOWNS(t) { - SlSetArrayIndex(t->index); - SlObject(t, _town_desc); - } -} - -static void Load_TOWN() -{ - int index; - - _total_towns = 0; - - while ((index = SlIterateArray()) != -1) { - Town *t = new (index) Town(); - SlObject(t, _town_desc); - - _total_towns++; - } - - /* This is to ensure all pointers are within the limits of - * the size of the TownPool */ - if (_cur_town_ctr > GetMaxTownIndex()) - _cur_town_ctr = 0; -} - -void AfterLoadTown() -{ - Town *t; - FOR_ALL_TOWNS(t) t->InitializeLayout(); -} - -extern const ChunkHandler _town_chunk_handlers[] = { - { 'HIDS', Save_HOUSEIDS, Load_HOUSEIDS, CH_ARRAY }, - { 'CITY', Save_TOWN, Load_TOWN, CH_ARRAY | CH_LAST}, -}; - void ResetHouses() { memset(&_house_specs, 0, sizeof(_house_specs)); diff --git a/src/train.h b/src/train.h index 5e57bdb2d..0adcc69cc 100644 --- a/src/train.h +++ b/src/train.h @@ -287,9 +287,6 @@ static inline Vehicle *GetPrevUnit(const Vehicle *v) return w; } -void ConvertOldMultiheadToNew(); -void ConnectMultiheadedTrains(); - void CcBuildLoco(bool success, TileIndex tile, uint32 p1, uint32 p2); void CcBuildWagon(bool success, TileIndex tile, uint32 p1, uint32 p2); diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 432ef9e8e..9960b1be7 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -4500,146 +4500,3 @@ void InitializeTrains() { _age_cargo_skip_counter = 1; } - -/* - * Link front and rear multiheaded engines to each other - * This is done when loading a savegame - */ -void ConnectMultiheadedTrains() -{ - Vehicle *v; - - FOR_ALL_VEHICLES(v) { - if (v->type == VEH_TRAIN) { - v->u.rail.other_multiheaded_part = NULL; - } - } - - FOR_ALL_VEHICLES(v) { - if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) { - /* Two ways to associate multiheaded parts to each other: - * sequential-matching: Trains shall be arranged to look like <..>..<..>..<..>.. - * bracket-matching: Free vehicle chains shall be arranged to look like ..<..<..>..<..>..>.. - * - * Note: Old savegames might contain chains which do not comply with these rules, e.g. - * - the front and read parts have invalid orders - * - different engine types might be combined - * - there might be different amounts of front and rear parts. - * - * Note: The multiheaded parts need to be matched exactly like they are matched on the server, else desyncs will occur. - * This is why two matching strategies are needed. - */ - - bool sequential_matching = IsFrontEngine(v); - - for (Vehicle *u = v; u != NULL; u = GetNextVehicle(u)) { - if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one - - if (IsMultiheaded(u)) { - if (!IsTrainEngine(u)) { - /* we got a rear car without a front car. We will convert it to a front one */ - SetTrainEngine(u); - u->spritenum--; - } - - /* Find a matching back part */ - EngineID eid = u->engine_type; - Vehicle *w; - if (sequential_matching) { - for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) { - if (w->engine_type != eid || w->u.rail.other_multiheaded_part != NULL || !IsMultiheaded(w)) continue; - - /* we found a car to partner with this engine. Now we will make sure it face the right way */ - if (IsTrainEngine(w)) { - ClearTrainEngine(w); - w->spritenum++; - } - break; - } - } else { - uint stack_pos = 0; - for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) { - if (w->engine_type != eid || w->u.rail.other_multiheaded_part != NULL || !IsMultiheaded(w)) continue; - - if (IsTrainEngine(w)) { - stack_pos++; - } else { - if (stack_pos == 0) break; - stack_pos--; - } - } - } - - if (w != NULL) { - w->u.rail.other_multiheaded_part = u; - u->u.rail.other_multiheaded_part = w; - } else { - /* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */ - ClearMultiheaded(u); - } - } - } - } - } -} - -/** - * Converts all trains to the new subtype format introduced in savegame 16.2 - * It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found - */ -void ConvertOldMultiheadToNew() -{ - Vehicle *v; - FOR_ALL_VEHICLES(v) { - if (v->type == VEH_TRAIN) { - SetBit(v->subtype, 7); // indicates that it's the old format and needs to be converted in the next loop - } - } - - FOR_ALL_VEHICLES(v) { - if (v->type == VEH_TRAIN) { - if (HasBit(v->subtype, 7) && ((v->subtype & ~0x80) == 0 || (v->subtype & ~0x80) == 4)) { - for (Vehicle *u = v; u != NULL; u = u->Next()) { - const RailVehicleInfo *rvi = RailVehInfo(u->engine_type); - - ClrBit(u->subtype, 7); - switch (u->subtype) { - case 0: /* TS_Front_Engine */ - if (rvi->railveh_type == RAILVEH_MULTIHEAD) SetMultiheaded(u); - SetFrontEngine(u); - SetTrainEngine(u); - break; - - case 1: /* TS_Artic_Part */ - u->subtype = 0; - SetArticulatedPart(u); - break; - - case 2: /* TS_Not_First */ - u->subtype = 0; - if (rvi->railveh_type == RAILVEH_WAGON) { - // normal wagon - SetTrainWagon(u); - break; - } - if (rvi->railveh_type == RAILVEH_MULTIHEAD && rvi->image_index == u->spritenum - 1) { - // rear end of a multiheaded engine - SetMultiheaded(u); - break; - } - if (rvi->railveh_type == RAILVEH_MULTIHEAD) SetMultiheaded(u); - SetTrainEngine(u); - break; - - case 4: /* TS_Free_Car */ - u->subtype = 0; - SetTrainWagon(u); - SetFreeWagon(u); - break; - default: NOT_REACHED(); break; - } - } - } - } - } -} diff --git a/src/variables.h b/src/variables.h index c69d400fa..cd8c16e33 100644 --- a/src/variables.h +++ b/src/variables.h @@ -33,10 +33,6 @@ VARDEF uint _next_competitor_start; /* Determines how often to run the tree loop */ VARDEF byte _trees_tick_ctr; -/* Keep track of current game position */ -VARDEF int _saved_scrollpos_x; -VARDEF int _saved_scrollpos_y; - /* NOSAVE: Used in palette animations only, not really important. */ VARDEF int _palette_animation_counter; diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 4f620e5f0..108ccb8d7 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -15,7 +15,7 @@ #include "gfx_func.h" #include "news_func.h" #include "command_func.h" -#include "saveload.h" +#include "saveload/saveload.h" #include "company_func.h" #include "debug.h" #include "vehicle_gui.h" @@ -59,9 +59,6 @@ #include "table/sprites.h" #include "table/strings.h" -#include <map> - -#define INVALID_COORD (0x7fffffff) #define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6)) VehicleID _vehicle_id_ctr_day; @@ -222,120 +219,6 @@ void VehiclePositionChanged(Vehicle *v) v->bottom_coord = pt.y + spr->height + 2; } -/** Called after load to update coordinates */ -void AfterLoadVehicles(bool part_of_load) -{ - Vehicle *v; - - FOR_ALL_VEHICLES(v) { - /* Reinstate the previous pointer */ - if (v->Next() != NULL) v->Next()->previous = v; - if (v->NextShared() != NULL) v->NextShared()->previous_shared = v; - - v->UpdateDeltaXY(v->direction); - - if (part_of_load) v->fill_percent_te_id = INVALID_TE_ID; - v->first = NULL; - if (v->type == VEH_TRAIN) v->u.rail.first_engine = INVALID_ENGINE; - if (v->type == VEH_ROAD) v->u.road.first_engine = INVALID_ENGINE; - - v->cargo.InvalidateCache(); - } - - /* AfterLoadVehicles may also be called in case of NewGRF reload, in this - * case we may not convert orders again. */ - if (part_of_load) { - /* Create shared vehicle chain for very old games (pre 5,2) and create - * OrderList from shared vehicle chains. For this to work correctly, the - * following conditions must be fulfilled: - * a) both next_shared and previous_shared are not set for pre 5,2 games - * b) both next_shared and previous_shared are set for later games - */ - std::map<Order*, OrderList*> mapping; - - FOR_ALL_VEHICLES(v) { - if (v->orders.old != NULL) { - if (CheckSavegameVersion(105)) { // Pre-105 didn't save an OrderList - if (mapping[v->orders.old] == NULL) { - /* This adds the whole shared vehicle chain for case b */ - v->orders.list = mapping[v->orders.old] = new OrderList(v->orders.old, v); - } else { - v->orders.list = mapping[v->orders.old]; - /* For old games (case a) we must create the shared vehicle chain */ - if (CheckSavegameVersionOldStyle(5, 2)) { - v->AddToShared(v->orders.list->GetFirstSharedVehicle()); - } - } - } else { // OrderList was saved as such, only recalculate not saved values - if (v->PreviousShared() == NULL) { - new (v->orders.list) OrderList(v->orders.list->GetFirstOrder(), v); - } - } - } - } - } - - FOR_ALL_VEHICLES(v) { - /* Fill the first pointers */ - if (v->Previous() == NULL) { - for (Vehicle *u = v; u != NULL; u = u->Next()) { - u->first = v; - } - } - } - - FOR_ALL_VEHICLES(v) { - assert(v->first != NULL); - - if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) { - if (IsFrontEngine(v)) v->u.rail.last_speed = v->cur_speed; // update displayed train speed - TrainConsistChanged(v, false); - } else if (v->type == VEH_ROAD && IsRoadVehFront(v)) { - RoadVehUpdateCache(v); - } - } - - /* Stop non-front engines */ - FOR_ALL_VEHICLES(v) { - if (v->type == VEH_TRAIN && IsTrainEngine(v) && !IsFrontEngine(v)) v->vehstatus |= VS_STOPPED; - } - - FOR_ALL_VEHICLES(v) { - switch (v->type) { - case VEH_ROAD: - v->u.road.roadtype = HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD; - v->u.road.compatible_roadtypes = RoadTypeToRoadTypes(v->u.road.roadtype); - /* FALL THROUGH */ - case VEH_TRAIN: - case VEH_SHIP: - v->cur_image = v->GetImage(v->direction); - break; - - case VEH_AIRCRAFT: - if (IsNormalAircraft(v)) { - v->cur_image = v->GetImage(v->direction); - - /* The plane's shadow will have the same image as the plane */ - Vehicle *shadow = v->Next(); - shadow->cur_image = v->cur_image; - - /* In the case of a helicopter we will update the rotor sprites */ - if (v->subtype == AIR_HELICOPTER) { - Vehicle *rotor = shadow->Next(); - rotor->cur_image = GetRotorImage(v); - } - - UpdateAircraftCache(v); - } - break; - default: break; - } - - v->left_coord = INVALID_COORD; - VehiclePositionChanged(v); - } -} - Vehicle::Vehicle() { this->type = VEH_INVALID; @@ -622,11 +505,19 @@ void ResetVehicleColorMap() FOR_ALL_VEHICLES(v) { v->colormap = PAL_NONE; } } +/** + * List of vehicles that should check for autoreplace this tick. + * Mapping of vehicle -> leave depot immediatelly after autoreplace. + */ +typedef SmallMap<Vehicle *, bool, 4> AutoreplaceMap; +static AutoreplaceMap _vehicles_to_autoreplace; + void InitializeVehicles() { _Vehicle_pool.CleanPool(); _Vehicle_pool.AddBlockToPool(); + _vehicles_to_autoreplace.Reset(); ResetVehiclePosHash(); } @@ -739,13 +630,6 @@ Vehicle::~Vehicle() new (this) InvalidVehicle(); } -/** - * List of vehicles that should check for autoreplace this tick. - * Mapping of vehicle -> leave depot immediatelly after autoreplace. - */ -typedef SmallMap<Vehicle *, bool, 4> AutoreplaceMap; -static AutoreplaceMap _vehicles_to_autoreplace; - /** Adds a vehicle to the list of vehicles, that visited a depot this tick * @param *v vehicle to add */ @@ -2128,367 +2012,6 @@ SpriteID GetVehiclePalette(const Vehicle *v) return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v); } -static uint8 _cargo_days; -static uint16 _cargo_source; -static uint32 _cargo_source_xy; -static uint16 _cargo_count; -static uint16 _cargo_paid_for; -static Money _cargo_feeder_share; -static uint32 _cargo_loaded_at_xy; - -/** - * Make it possible to make the saveload tables "friends" of other classes. - * @param vt the vehicle type. Can be VEH_END for the common vehicle description data - * @return the saveload description - */ -const SaveLoad *GetVehicleDescription(VehicleType vt) -{ -/** Save and load of vehicles */ -static const SaveLoad _common_veh_desc[] = { - SLE_VAR(Vehicle, subtype, SLE_UINT8), - - SLE_REF(Vehicle, next, REF_VEHICLE_OLD), - SLE_CONDVAR(Vehicle, name, SLE_NAME, 0, 83), - SLE_CONDSTR(Vehicle, name, SLE_STR, 0, 84, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, unitnumber, SLE_FILE_U8 | SLE_VAR_U16, 0, 7), - SLE_CONDVAR(Vehicle, unitnumber, SLE_UINT16, 8, SL_MAX_VERSION), - SLE_VAR(Vehicle, owner, SLE_UINT8), - SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Vehicle, tile, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, dest_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Vehicle, dest_tile, SLE_UINT32, 6, SL_MAX_VERSION), - - SLE_CONDVAR(Vehicle, x_pos, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Vehicle, x_pos, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, y_pos, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Vehicle, y_pos, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_VAR(Vehicle, z_pos, SLE_UINT8), - SLE_VAR(Vehicle, direction, SLE_UINT8), - - SLE_CONDNULL(2, 0, 57), - SLE_VAR(Vehicle, spritenum, SLE_UINT8), - SLE_CONDNULL(5, 0, 57), - SLE_VAR(Vehicle, engine_type, SLE_UINT16), - - SLE_VAR(Vehicle, max_speed, SLE_UINT16), - SLE_VAR(Vehicle, cur_speed, SLE_UINT16), - SLE_VAR(Vehicle, subspeed, SLE_UINT8), - SLE_VAR(Vehicle, acceleration, SLE_UINT8), - SLE_VAR(Vehicle, progress, SLE_UINT8), - - SLE_VAR(Vehicle, vehstatus, SLE_UINT8), - SLE_CONDVAR(Vehicle, last_station_visited, SLE_FILE_U8 | SLE_VAR_U16, 0, 4), - SLE_CONDVAR(Vehicle, last_station_visited, SLE_UINT16, 5, SL_MAX_VERSION), - - SLE_VAR(Vehicle, cargo_type, SLE_UINT8), - SLE_CONDVAR(Vehicle, cargo_subtype, SLE_UINT8, 35, SL_MAX_VERSION), - SLEG_CONDVAR( _cargo_days, SLE_UINT8, 0, 67), - SLEG_CONDVAR( _cargo_source, SLE_FILE_U8 | SLE_VAR_U16, 0, 6), - SLEG_CONDVAR( _cargo_source, SLE_UINT16, 7, 67), - SLEG_CONDVAR( _cargo_source_xy, SLE_UINT32, 44, 67), - SLE_VAR(Vehicle, cargo_cap, SLE_UINT16), - SLEG_CONDVAR( _cargo_count, SLE_UINT16, 0, 67), - SLE_CONDLST(Vehicle, cargo, REF_CARGO_PACKET, 68, SL_MAX_VERSION), - - SLE_VAR(Vehicle, day_counter, SLE_UINT8), - SLE_VAR(Vehicle, tick_counter, SLE_UINT8), - SLE_CONDVAR(Vehicle, running_ticks, SLE_UINT8, 88, SL_MAX_VERSION), - - SLE_VAR(Vehicle, cur_order_index, SLE_UINT8), - /* num_orders is now part of OrderList and is not saved but counted */ - SLE_CONDNULL(1, 0, 104), - - /* This next line is for version 4 and prior compatibility.. it temporarily reads - type and flags (which were both 4 bits) into type. Later on this is - converted correctly */ - SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, type), SLE_UINT8, 0, 4), - SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_FILE_U8 | SLE_VAR_U16, 0, 4), - - /* Orders for version 5 and on */ - SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, type), SLE_UINT8, 5, SL_MAX_VERSION), - SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, flags), SLE_UINT8, 5, SL_MAX_VERSION), - SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_UINT16, 5, SL_MAX_VERSION), - - /* Refit in current order */ - SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, refit_cargo), SLE_UINT8, 36, SL_MAX_VERSION), - SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, refit_subtype), SLE_UINT8, 36, SL_MAX_VERSION), - - /* Timetable in current order */ - SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, wait_time), SLE_UINT16, 67, SL_MAX_VERSION), - SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, travel_time), SLE_UINT16, 67, SL_MAX_VERSION), - - SLE_CONDREF(Vehicle, orders, REF_ORDER, 0, 104), - SLE_CONDREF(Vehicle, orders, REF_ORDERLIST, 105, SL_MAX_VERSION), - - SLE_CONDVAR(Vehicle, age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), - SLE_CONDVAR(Vehicle, age, SLE_INT32, 31, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, max_age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), - SLE_CONDVAR(Vehicle, max_age, SLE_INT32, 31, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, date_of_last_service, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), - SLE_CONDVAR(Vehicle, date_of_last_service, SLE_INT32, 31, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, service_interval, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), - SLE_CONDVAR(Vehicle, service_interval, SLE_INT32, 31, SL_MAX_VERSION), - SLE_VAR(Vehicle, reliability, SLE_UINT16), - SLE_VAR(Vehicle, reliability_spd_dec, SLE_UINT16), - SLE_VAR(Vehicle, breakdown_ctr, SLE_UINT8), - SLE_VAR(Vehicle, breakdown_delay, SLE_UINT8), - SLE_VAR(Vehicle, breakdowns_since_last_service, SLE_UINT8), - SLE_VAR(Vehicle, breakdown_chance, SLE_UINT8), - SLE_CONDVAR(Vehicle, build_year, SLE_FILE_U8 | SLE_VAR_I32, 0, 30), - SLE_CONDVAR(Vehicle, build_year, SLE_INT32, 31, SL_MAX_VERSION), - - SLE_VAR(Vehicle, load_unload_time_rem, SLE_UINT16), - SLEG_CONDVAR( _cargo_paid_for, SLE_UINT16, 45, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, vehicle_flags, SLE_UINT8, 40, SL_MAX_VERSION), - - SLE_CONDVAR(Vehicle, profit_this_year, SLE_FILE_I32 | SLE_VAR_I64, 0, 64), - SLE_CONDVAR(Vehicle, profit_this_year, SLE_INT64, 65, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, profit_last_year, SLE_FILE_I32 | SLE_VAR_I64, 0, 64), - SLE_CONDVAR(Vehicle, profit_last_year, SLE_INT64, 65, SL_MAX_VERSION), - SLEG_CONDVAR( _cargo_feeder_share, SLE_FILE_I32 | SLE_VAR_I64,51, 64), - SLEG_CONDVAR( _cargo_feeder_share, SLE_INT64, 65, 67), - SLEG_CONDVAR( _cargo_loaded_at_xy, SLE_UINT32, 51, 67), - SLE_CONDVAR(Vehicle, value, SLE_FILE_I32 | SLE_VAR_I64, 0, 64), - SLE_CONDVAR(Vehicle, value, SLE_INT64, 65, SL_MAX_VERSION), - - SLE_CONDVAR(Vehicle, random_bits, SLE_UINT8, 2, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, waiting_triggers, SLE_UINT8, 2, SL_MAX_VERSION), - - SLE_CONDREF(Vehicle, next_shared, REF_VEHICLE, 2, SL_MAX_VERSION), - SLE_CONDNULL(2, 2, 68), - SLE_CONDNULL(4, 69, 100), - - SLE_CONDVAR(Vehicle, group_id, SLE_UINT16, 60, SL_MAX_VERSION), - - SLE_CONDVAR(Vehicle, current_order_time, SLE_UINT32, 67, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, lateness_counter, SLE_INT32, 67, SL_MAX_VERSION), - - /* reserve extra space in savegame here. (currently 10 bytes) */ - SLE_CONDNULL(10, 2, SL_MAX_VERSION), - - SLE_END() -}; - - -static const SaveLoad _train_desc[] = { - SLE_WRITEBYTE(Vehicle, type, VEH_TRAIN), - SLE_VEH_INCLUDEX(), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, crash_anim_pos), SLE_UINT16), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, force_proceed), SLE_UINT8), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, railtype), SLE_UINT8), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, track), SLE_UINT8), - - SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, flags), SLE_FILE_U8 | SLE_VAR_U16, 2, 99), - SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, flags), SLE_UINT16,100, SL_MAX_VERSION), - SLE_CONDNULL(2, 2, 59), - - SLE_CONDNULL(2, 2, 19), - /* reserve extra space in savegame here. (currently 11 bytes) */ - SLE_CONDNULL(11, 2, SL_MAX_VERSION), - - SLE_END() -}; - -static const SaveLoad _roadveh_desc[] = { - SLE_WRITEBYTE(Vehicle, type, VEH_ROAD), - SLE_VEH_INCLUDEX(), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, state), SLE_UINT8), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, frame), SLE_UINT8), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, blocked_ctr), SLE_UINT16), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, overtaking), SLE_UINT8), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, overtaking_ctr), SLE_UINT8), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, crashed_ctr), SLE_UINT16), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, reverse_ctr), SLE_UINT8), - - SLE_CONDREFX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, slot), REF_ROADSTOPS, 6, SL_MAX_VERSION), - SLE_CONDNULL(1, 6, SL_MAX_VERSION), - SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, slot_age), SLE_UINT8, 6, SL_MAX_VERSION), - /* reserve extra space in savegame here. (currently 16 bytes) */ - SLE_CONDNULL(16, 2, SL_MAX_VERSION), - - SLE_END() -}; - -static const SaveLoad _ship_desc[] = { - SLE_WRITEBYTE(Vehicle, type, VEH_SHIP), - SLE_VEH_INCLUDEX(), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleShip, state), SLE_UINT8), - - /* reserve extra space in savegame here. (currently 16 bytes) */ - SLE_CONDNULL(16, 2, SL_MAX_VERSION), - - SLE_END() -}; - -static const SaveLoad _aircraft_desc[] = { - SLE_WRITEBYTE(Vehicle, type, VEH_AIRCRAFT), - SLE_VEH_INCLUDEX(), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, crashed_counter), SLE_UINT16), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, pos), SLE_UINT8), - - SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, targetairport), SLE_FILE_U8 | SLE_VAR_U16, 0, 4), - SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, targetairport), SLE_UINT16, 5, SL_MAX_VERSION), - - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, state), SLE_UINT8), - - SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, previous_pos), SLE_UINT8, 2, SL_MAX_VERSION), - - /* reserve extra space in savegame here. (currently 15 bytes) */ - SLE_CONDNULL(15, 2, SL_MAX_VERSION), - - SLE_END() -}; - -static const SaveLoad _special_desc[] = { - SLE_WRITEBYTE(Vehicle, type, VEH_EFFECT), - - SLE_VAR(Vehicle, subtype, SLE_UINT8), - - SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Vehicle, tile, SLE_UINT32, 6, SL_MAX_VERSION), - - SLE_CONDVAR(Vehicle, x_pos, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), - SLE_CONDVAR(Vehicle, x_pos, SLE_INT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, y_pos, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), - SLE_CONDVAR(Vehicle, y_pos, SLE_INT32, 6, SL_MAX_VERSION), - SLE_VAR(Vehicle, z_pos, SLE_UINT8), - - SLE_VAR(Vehicle, cur_image, SLE_UINT16), - SLE_CONDNULL(5, 0, 57), - SLE_VAR(Vehicle, progress, SLE_UINT8), - SLE_VAR(Vehicle, vehstatus, SLE_UINT8), - - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleEffect, animation_state), SLE_UINT16), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleEffect, animation_substate), SLE_UINT8), - - SLE_CONDVAR(Vehicle, spritenum, SLE_UINT8, 2, SL_MAX_VERSION), - - /* reserve extra space in savegame here. (currently 15 bytes) */ - SLE_CONDNULL(15, 2, SL_MAX_VERSION), - - SLE_END() -}; - -static const SaveLoad _disaster_desc[] = { - SLE_WRITEBYTE(Vehicle, type, VEH_DISASTER), - - SLE_REF(Vehicle, next, REF_VEHICLE_OLD), - - SLE_VAR(Vehicle, subtype, SLE_UINT8), - SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Vehicle, tile, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, dest_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Vehicle, dest_tile, SLE_UINT32, 6, SL_MAX_VERSION), - - SLE_CONDVAR(Vehicle, x_pos, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), - SLE_CONDVAR(Vehicle, x_pos, SLE_INT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(Vehicle, y_pos, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), - SLE_CONDVAR(Vehicle, y_pos, SLE_INT32, 6, SL_MAX_VERSION), - SLE_VAR(Vehicle, z_pos, SLE_UINT8), - SLE_VAR(Vehicle, direction, SLE_UINT8), - - SLE_CONDNULL(5, 0, 57), - SLE_VAR(Vehicle, owner, SLE_UINT8), - SLE_VAR(Vehicle, vehstatus, SLE_UINT8), - SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_FILE_U8 | SLE_VAR_U16, 0, 4), - SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_UINT16, 5, SL_MAX_VERSION), - - SLE_VAR(Vehicle, cur_image, SLE_UINT16), - SLE_CONDVAR(Vehicle, age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), - SLE_CONDVAR(Vehicle, age, SLE_INT32, 31, SL_MAX_VERSION), - SLE_VAR(Vehicle, tick_counter, SLE_UINT8), - - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, image_override), SLE_UINT16), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, big_ufo_destroyer_target), SLE_UINT16), - - /* reserve extra space in savegame here. (currently 16 bytes) */ - SLE_CONDNULL(16, 2, SL_MAX_VERSION), - - SLE_END() -}; - - -static const SaveLoad *_veh_descs[] = { - _train_desc, - _roadveh_desc, - _ship_desc, - _aircraft_desc, - _special_desc, - _disaster_desc, - _common_veh_desc, -}; - - return _veh_descs[vt]; -} - -/** Will be called when the vehicles need to be saved. */ -static void Save_VEHS() -{ - Vehicle *v; - /* Write the vehicles */ - FOR_ALL_VEHICLES(v) { - SlSetArrayIndex(v->index); - SlObject(v, GetVehicleDescription(v->type)); - } -} - -/** Will be called when vehicles need to be loaded. */ -void Load_VEHS() -{ - _vehicles_to_autoreplace.Reset(); - - int index; - - _cargo_count = 0; - - while ((index = SlIterateArray()) != -1) { - Vehicle *v; - VehicleType vtype = (VehicleType)SlReadByte(); - - switch (vtype) { - case VEH_TRAIN: v = new (index) Train(); break; - case VEH_ROAD: v = new (index) RoadVehicle(); break; - case VEH_SHIP: v = new (index) Ship(); break; - case VEH_AIRCRAFT: v = new (index) Aircraft(); break; - case VEH_EFFECT: v = new (index) EffectVehicle(); break; - case VEH_DISASTER: v = new (index) DisasterVehicle(); break; - case VEH_INVALID: v = new (index) InvalidVehicle(); break; - default: NOT_REACHED(); - } - - SlObject(v, GetVehicleDescription(vtype)); - - if (_cargo_count != 0 && IsCompanyBuildableVehicleType(v)) { - /* Don't construct the packet with station here, because that'll fail with old savegames */ - CargoPacket *cp = new CargoPacket(); - cp->source = _cargo_source; - cp->source_xy = _cargo_source_xy; - cp->count = _cargo_count; - cp->days_in_transit = _cargo_days; - cp->feeder_share = _cargo_feeder_share; - cp->loaded_at_xy = _cargo_loaded_at_xy; - v->cargo.Append(cp); - } - - /* Old savegames used 'last_station_visited = 0xFF' */ - if (CheckSavegameVersion(5) && v->last_station_visited == 0xFF) - v->last_station_visited = INVALID_STATION; - - if (CheckSavegameVersion(5)) { - /* Convert the current_order.type (which is a mix of type and flags, because - * in those versions, they both were 4 bits big) to type and flags */ - v->current_order.flags = GB(v->current_order.type, 4, 4); - v->current_order.type &= 0x0F; - } - - /* Advanced vehicle lists got added */ - if (CheckSavegameVersion(60)) v->group_id = DEFAULT_GROUP; - } -} - -extern const ChunkHandler _veh_chunk_handlers[] = { - { 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY | CH_LAST}, -}; void Vehicle::BeginLoading() { diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 42fd3d44d..7d6a9985d 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -194,7 +194,6 @@ DECLARE_OLD_POOL(Vehicle, Vehicle, 9, 125) /* Some declarations of functions, so we can make them friendly */ struct SaveLoad; extern const SaveLoad *GetVehicleDescription(VehicleType vt); -extern void AfterLoadVehicles(bool part_of_load); struct LoadgameState; extern bool LoadOldVehicle(LoadgameState *ls, int num); @@ -712,4 +711,6 @@ Trackdir GetVehicleTrackdir(const Vehicle* v); void CheckVehicle32Day(Vehicle *v); +static const int32 INVALID_COORD = 0x7fffffff; + #endif /* VEHICLE_BASE_H */ diff --git a/src/viewport.cpp b/src/viewport.cpp index 0622f85a3..0d97d8cd0 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -2785,33 +2785,3 @@ void ResetObjectToPlace() { SetObjectToPlace(SPR_CURSOR_MOUSE, PAL_NONE, VHM_NONE, WC_MAIN_WINDOW, 0); } - - -void SaveViewportBeforeSaveGame() -{ - const Window *w = FindWindowById(WC_MAIN_WINDOW, 0); - - if (w != NULL) { - _saved_scrollpos_x = w->viewport->scrollpos_x; - _saved_scrollpos_y = w->viewport->scrollpos_y; - _saved_scrollpos_zoom = w->viewport->zoom; - } -} - -void ResetViewportAfterLoadGame() -{ - Window *w = FindWindowById(WC_MAIN_WINDOW, 0); - - w->viewport->scrollpos_x = _saved_scrollpos_x; - w->viewport->scrollpos_y = _saved_scrollpos_y; - w->viewport->dest_scrollpos_x = _saved_scrollpos_x; - w->viewport->dest_scrollpos_y = _saved_scrollpos_y; - - ViewPort *vp = w->viewport; - vp->zoom = min(_saved_scrollpos_zoom, ZOOM_LVL_MAX); - vp->virtual_width = ScaleByZoom(vp->width, vp->zoom); - vp->virtual_height = ScaleByZoom(vp->height, vp->zoom); - - DoZoomInOutWindow(ZOOM_NONE, w); // update button status - MarkWholeScreenDirty(); -} diff --git a/src/water.h b/src/water.h index e54d2e1ea..2fa063b3c 100644 --- a/src/water.h +++ b/src/water.h @@ -15,6 +15,5 @@ void DrawWaterClassGround(const struct TileInfo *ti); void DrawShoreTile(Slope tileh); void MakeWaterKeepingClass(TileIndex tile, Owner o); -void SetWaterClassDependingOnSurroundings(TileIndex t, bool include_invalid_water_class); #endif /* WATER_H */ diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index 0c7907f20..6735d2231 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -101,88 +101,6 @@ static void MarkCanalsAndRiversAroundDirty(TileIndex tile) } } -/** - * Makes a tile canal or water depending on the surroundings. - * - * Must only be used for converting old savegames. Use WaterClass now. - * - * This as for example docks and shipdepots do not store - * whether the tile used to be canal or 'normal' water. - * @param t the tile to change. - * @param o the owner of the new tile. - * @param include_invalid_water_class Also consider WATER_CLASS_INVALID, i.e. industry tiles on land - */ -void SetWaterClassDependingOnSurroundings(TileIndex t, bool include_invalid_water_class) -{ - /* If the slope is not flat, we always assume 'land' (if allowed). Also for one-corner-raised-shores. - * Note: Wrt. autosloping under industry tiles this is the most fool-proof behaviour. */ - if (GetTileSlope(t, NULL) != SLOPE_FLAT) { - if (include_invalid_water_class) { - SetWaterClass(t, WATER_CLASS_INVALID); - return; - } else { - NOT_REACHED(); - } - } - - /* Mark tile dirty in all cases */ - MarkTileDirtyByTile(t); - - if (TileX(t) == 0 || TileY(t) == 0 || TileX(t) == MapMaxX() - 1 || TileY(t) == MapMaxY() - 1) { - /* tiles at map borders are always WATER_CLASS_SEA */ - SetWaterClass(t, WATER_CLASS_SEA); - return; - } - - bool has_water = false; - bool has_canal = false; - bool has_river = false; - - for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { - TileIndex neighbour = TileAddByDiagDir(t, dir); - switch (GetTileType(neighbour)) { - case MP_WATER: - /* clear water and shipdepots have already a WaterClass associated */ - if (IsCoast(neighbour)) { - has_water = true; - } else if (!IsLock(neighbour)) { - switch (GetWaterClass(neighbour)) { - case WATER_CLASS_SEA: has_water = true; break; - case WATER_CLASS_CANAL: has_canal = true; break; - case WATER_CLASS_RIVER: has_river = true; break; - default: NOT_REACHED(); - } - } - break; - - case MP_RAILWAY: - /* Shore or flooded halftile */ - has_water |= (GetRailGroundType(neighbour) == RAIL_GROUND_WATER); - break; - - case MP_TREES: - /* trees on shore */ - has_water |= (GetTreeGround(neighbour) == TREE_GROUND_SHORE); - break; - - default: break; - } - } - - if (!has_water && !has_canal && !has_river && include_invalid_water_class) { - SetWaterClass(t, WATER_CLASS_INVALID); - return; - } - - if (has_river && !has_canal) { - SetWaterClass(t, WATER_CLASS_RIVER); - } else if (has_canal || !has_water) { - SetWaterClass(t, WATER_CLASS_CANAL); - } else { - SetWaterClass(t, WATER_CLASS_SEA); - } -} - /** Build a ship depot. * @param tile tile where ship depot is built diff --git a/src/waypoint.cpp b/src/waypoint.cpp index 81d7d9563..888d2d795 100644 --- a/src/waypoint.cpp +++ b/src/waypoint.cpp @@ -11,7 +11,6 @@ #include "rail_map.h" #include "rail.h" #include "bridge_map.h" -#include "saveload.h" #include "station_base.h" #include "town.h" #include "waypoint.h" @@ -157,29 +156,6 @@ static Waypoint *FindDeletedWaypointCloseTo(TileIndex tile) return best; } -/** - * Update waypoint graphics id against saved GRFID/localidx. - * This is to ensure the chosen graphics are correct if GRF files are changed. - */ -void AfterLoadWaypoints() -{ - Waypoint *wp; - - FOR_ALL_WAYPOINTS(wp) { - uint i; - - if (wp->grfid == 0) continue; - - for (i = 0; i < GetNumCustomStations(STAT_CLASS_WAYP); i++) { - const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, i); - if (statspec != NULL && statspec->grffile->grfid == wp->grfid && statspec->localidx == wp->localidx) { - wp->stat_id = i; - break; - } - } - } -} - /** Convert existing rail to waypoint. Eg build a waypoint station over * piece of rail * @param tile tile where waypoint will be built @@ -463,69 +439,8 @@ Waypoint::~Waypoint() this->xy = INVALID_TILE; } -/** - * Fix savegames which stored waypoints in their old format - */ -void FixOldWaypoints() -{ - Waypoint *wp; - - /* Convert the old 'town_or_string', to 'string' / 'town' / 'town_cn' */ - FOR_ALL_WAYPOINTS(wp) { - wp->town_index = ClosestTownFromTile(wp->xy, UINT_MAX)->index; - wp->town_cn = 0; - if (wp->string & 0xC000) { - wp->town_cn = wp->string & 0x3F; - wp->string = STR_NULL; - } - } -} - void InitializeWaypoints() { _Waypoint_pool.CleanPool(); _Waypoint_pool.AddBlockToPool(); } - -static const SaveLoad _waypoint_desc[] = { - SLE_CONDVAR(Waypoint, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Waypoint, xy, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(Waypoint, town_index, SLE_UINT16, 12, SL_MAX_VERSION), - SLE_CONDVAR(Waypoint, town_cn, SLE_FILE_U8 | SLE_VAR_U16, 12, 88), - SLE_CONDVAR(Waypoint, town_cn, SLE_UINT16, 89, SL_MAX_VERSION), - SLE_CONDVAR(Waypoint, string, SLE_STRINGID, 0, 83), - SLE_CONDSTR(Waypoint, name, SLE_STR, 0, 84, SL_MAX_VERSION), - SLE_VAR(Waypoint, deleted, SLE_UINT8), - - SLE_CONDVAR(Waypoint, build_date, SLE_FILE_U16 | SLE_VAR_I32, 3, 30), - SLE_CONDVAR(Waypoint, build_date, SLE_INT32, 31, SL_MAX_VERSION), - SLE_CONDVAR(Waypoint, localidx, SLE_UINT8, 3, SL_MAX_VERSION), - SLE_CONDVAR(Waypoint, grfid, SLE_UINT32, 17, SL_MAX_VERSION), - SLE_CONDVAR(Waypoint, owner, SLE_UINT8, 101, SL_MAX_VERSION), - - SLE_END() -}; - -static void Save_WAYP() -{ - Waypoint *wp; - - FOR_ALL_WAYPOINTS(wp) { - SlSetArrayIndex(wp->index); - SlObject(wp, _waypoint_desc); - } -} - -static void Load_WAYP() -{ - int index; - - while ((index = SlIterateArray()) != -1) { - Waypoint *wp = new (index) Waypoint(); - SlObject(wp, _waypoint_desc); - } -} - -extern const ChunkHandler _waypoint_chunk_handlers[] = { - { 'CHKP', Save_WAYP, Load_WAYP, CH_ARRAY | CH_LAST}, -}; diff --git a/src/waypoint.h b/src/waypoint.h index 8b07bdbac..e4af9c1a1 100644 --- a/src/waypoint.h +++ b/src/waypoint.h @@ -12,6 +12,7 @@ #include "station_type.h" #include "town_type.h" #include "viewport_type.h" +#include "date_type.h" DECLARE_OLD_POOL(Waypoint, Waypoint, 3, 8000) @@ -63,8 +64,6 @@ CommandCost RemoveTrainWaypoint(TileIndex tile, uint32 flags, bool justremove); Station *ComposeWaypointStation(TileIndex tile); void ShowWaypointWindow(const Waypoint *wp); void DrawWaypointSprite(int x, int y, int stat_id, RailType railtype); -void FixOldWaypoints(); void UpdateAllWaypointSigns(); -void AfterLoadWaypoints(); #endif /* WAYPOINT_H */ diff --git a/src/win32.cpp b/src/win32.cpp index 98d626094..338253194 100644 --- a/src/win32.cpp +++ b/src/win32.cpp @@ -5,7 +5,7 @@ #include "stdafx.h" #include "openttd.h" #include "debug.h" -#include "saveload.h" +#include "saveload/saveload.h" #include "gfx_func.h" #include "textbuf_gui.h" #include "fileio_func.h" |