From 924c14b84990c3ddedb1a9a7ff0ed9af18839696 Mon Sep 17 00:00:00 2001 From: Andrii Dokhniak Date: Sun, 2 Jun 2024 21:33:42 +0200 Subject: [PATCH] Finally POC --- .gitignore | 1 + media/baseset/opntitle_testing.dat | Bin 0 -> 31732 bytes src/company_base.h | 1 + src/engine_base.h | 9 ++++ src/saveload/afterload.cpp | 65 +++++++++++++++++------------ src/saveload/company_sl.cpp | 11 +++-- src/saveload/engine_sl.cpp | 49 ++++++++++++++-------- src/saveload/saveload.cpp | 51 +++++++++++----------- src/saveload/saveload.h | 12 +++--- src/saveload/town_sl.cpp | 15 +++++-- src/town.h | 3 ++ 11 files changed, 135 insertions(+), 82 deletions(-) create mode 100644 media/baseset/opntitle_testing.dat diff --git a/.gitignore b/.gitignore index 3d0376aa94..38765312bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.vs +/.cache/* /build* CMakeSettings.json docs/aidocs/* diff --git a/media/baseset/opntitle_testing.dat b/media/baseset/opntitle_testing.dat new file mode 100644 index 0000000000000000000000000000000000000000..b43b3f6cd3c46d01198be0b25580dc2595f5227d GIT binary patch literal 31732 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 b00GDM0pj@(r(eJSJ}?c70ssI200CKAdH29D literal 0 HcmV?d00001 diff --git a/src/company_base.h b/src/company_base.h index 814665777b..8173fdda4e 100644 --- a/src/company_base.h +++ b/src/company_base.h @@ -96,6 +96,7 @@ struct CompanyProperties { uint8_t months_empty = 0; ///< NOSAVE: Number of months this company has not had a client in multiplayer. uint8_t months_of_bankruptcy; ///< Number of months that the company is unable to pay its debts CompanyMask bankrupt_asked; ///< which companies were asked about buying it? + uint16_t old_bankrupt_asked; int16_t bankrupt_timeout; ///< If bigger than \c 0, amount of time to wait for an answer on an offer to buy this company. Money bankrupt_value; diff --git a/src/engine_base.h b/src/engine_base.h index de552bd9a7..4f545a7bd3 100644 --- a/src/engine_base.h +++ b/src/engine_base.h @@ -15,6 +15,7 @@ #include "core/pool_type.hpp" #include "newgrf_commons.h" #include "timer/timer_game_calendar.h" +#include struct WagonOverride { std::vector engines; @@ -47,11 +48,19 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> { uint16_t duration_phase_2; ///< Second reliability phase in months, keeping #reliability_max. uint16_t duration_phase_3; ///< Third reliability phase in months, decaying to #reliability_final. uint8_t flags; ///< Flags of the engine. @see EngineFlags + CompanyMask preview_asked; ///< Bit for each company which has already been offered a preview. + uint16_t old_preview_asked; + CompanyID preview_company; ///< Company which is currently being offered a preview \c INVALID_COMPANY means no company. uint8_t preview_wait; ///< Daily countdown timer for timeout of offering the engine to the #preview_company company. + CompanyMask company_avail; ///< Bit for each company whether the engine is available for that company. + uint16_t old_company_avail; + CompanyMask company_hidden; ///< Bit for each company whether the engine is normally hidden in the build gui for that company. + uint16_t old_company_hidden; + uint8_t original_image_index; ///< Original vehicle image index, thus the image index of the overridden vehicle VehicleType type; ///< %Vehicle type, ie #VEH_ROAD, #VEH_TRAIN, etc. diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index e092960f66..bf1d2c1486 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -63,11 +63,14 @@ #include "../timer/timer_game_economy.h" #include "../timer/timer_game_tick.h" +#include "saveload/saveload.h" #include "saveload_internal.h" #include #include "../safeguards.h" +#include "tile_map.h" +#include "tile_type.h" extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY); @@ -163,7 +166,7 @@ static void ConvertTownOwner() [[fallthrough]]; case MP_TUNNELBRIDGE: - if (tile.m1() & 0x80) SetTileOwner(tile, OWNER_TOWN); + if (tile.m1() & 0x80) OldSetTileOwner(tile, OWNER_TOWN); break; default: break; @@ -421,7 +424,7 @@ static void CDECL HandleSavegameLoadCrash(int signum) */ static void FixOwnerOfRailTrack(Tile t) { - assert(!Company::IsValidID(GetTileOwner(t)) && (IsLevelCrossingTile(t) || IsPlainRailTile(t))); + assert(!Company::IsValidID(OldGetTileOwner(t)) && (IsLevelCrossingTile(t) || IsPlainRailTile(t))); /* remove leftover rail piece from crossing (from very old savegames) */ Train *v = nullptr; @@ -434,7 +437,7 @@ static void FixOwnerOfRailTrack(Tile t) if (v != nullptr) { /* when there is a train on crossing (it could happen in TTD), set owner of crossing to train owner */ - SetTileOwner(t, v->owner); + OldSetTileOwner(t, v->owner); return; } @@ -443,15 +446,15 @@ static void FixOwnerOfRailTrack(Tile t) TileIndex tt = t + TileOffsByDiagDir(dd); if (GetTileTrackStatus(t, TRANSPORT_RAIL, 0, dd) != 0 && GetTileTrackStatus(tt, TRANSPORT_RAIL, 0, ReverseDiagDir(dd)) != 0 && - Company::IsValidID(GetTileOwner(tt))) { - SetTileOwner(t, GetTileOwner(tt)); + Company::IsValidID(OldGetTileOwner(tt))) { + OldSetTileOwner(t, OldGetTileOwner(tt)); return; } } if (IsLevelCrossingTile(t)) { /* else change the crossing to normal road (road vehicles won't care) */ - Owner road = GetRoadOwner(t, RTT_ROAD); // TODO: m9 + Owner road = GetRoadOwner(t, RTT_ROAD); Owner tram = GetRoadOwner(t, RTT_TRAM); RoadBits bits = GetCrossingRoadBits(t); bool hasroad = HasBit(t.m7(), 6); @@ -459,7 +462,7 @@ static void FixOwnerOfRailTrack(Tile t) /* MakeRoadNormal */ SetTileType(t, MP_ROAD); - SetTileOwner(t, road); + OldSetTileOwner(t, road); t.m3() = (hasroad ? bits : 0); t.m5() = (hastram ? bits : 0) | ROAD_TILE_NORMAL << 6; SB(t.m6(), 2, 4, 0); @@ -471,6 +474,7 @@ static void FixOwnerOfRailTrack(Tile t) MakeClear(t, CLEAR_GRASS, 0); } + /** * Fixes inclination of a vehicle. Older OpenTTD versions didn't update the bits correctly. * @param v vehicle @@ -656,8 +660,8 @@ bool AfterLoadGame() * walk through the whole map.. */ if (IsSavegameVersionBefore(SLV_4, 3)) { for (auto t : Map::Iterate()) { - if (IsTileType(t, MP_WATER) && GetTileOwner(t) >= OLD_MAX_COMPANIES) { - SetTileOwner(t, OWNER_WATER); + if (IsTileType(t, MP_WATER) && OldGetTileOwner(t) >= OLD_MAX_COMPANIES) { + OldSetTileOwner(t, OWNER_WATER); } } } @@ -858,7 +862,7 @@ bool AfterLoadGame() default: break; case MP_WATER: - if (GetWaterTileType(t) == WATER_TILE_LOCK && GetTileOwner(t) == OWNER_WATER) SetTileOwner(t, OWNER_NONE); + if (GetWaterTileType(t) == WATER_TILE_LOCK && OldGetTileOwner(t) == OWNER_WATER) OldSetTileOwner(t, OWNER_NONE); break; case MP_STATION: { @@ -913,7 +917,7 @@ bool AfterLoadGame() BaseStation *bst = BaseStation::GetByTile(t); /* Sanity check */ - if (!IsBuoy(t) && bst->owner != GetTileOwner(t)) SlErrorCorrupt("Wrong owner for station tile"); + if (!IsBuoy(t) && bst->owner != OldGetTileOwner(t)) SlErrorCorrupt("Wrong owner for station tile"); /* Set up station spread */ bst->rect.BeforeAddTile(t, StationRect::ADD_FORCE); @@ -986,7 +990,7 @@ bool AfterLoadGame() case MP_ROAD: t.m4() |= (t.m2() << 4); - if ((GB(t.m5(), 4, 2) == ROAD_TILE_CROSSING ? (Owner)t.m3() : GetTileOwner(t)) == OLD_OWNER_TOWN) { + if ((GB(t.m5(), 4, 2) == ROAD_TILE_CROSSING ? (Owner)t.m3() : OldGetTileOwner(t)) == OLD_OWNER_TOWN) { SetTownIndex(t, CalcClosestTownFromTile(t)->index); } else { SetTownIndex(t, 0); @@ -1139,7 +1143,7 @@ bool AfterLoadGame() if (!IsRoadStop(t)) break; if (fix_roadtypes) SB(t.m7(), 6, 2, (RoadTypes)GB(t.m3(), 0, 3)); - SB(t.m7(), 0, 5, HasBit(t.m6(), 2) ? OWNER_TOWN : GetTileOwner(t)); + SB(t.m7(), 0, 5, HasBit(t.m6(), 2) ? OWNER_TOWN : OldGetTileOwner(t)); SB(t.m3(), 4, 4, t.m1()); t.m4() = 0; break; @@ -1149,7 +1153,7 @@ bool AfterLoadGame() if (((old_bridge && IsBridge(t)) ? (TransportType)GB(t.m5(), 1, 2) : GetTunnelBridgeTransportType(t)) == TRANSPORT_ROAD) { if (fix_roadtypes) SB(t.m7(), 6, 2, (RoadTypes)GB(t.m3(), 0, 3)); - Owner o = GetTileOwner(t); + Owner o = OldGetTileOwner(t); SB(t.m7(), 0, 5, o); // road owner SB(t.m3(), 4, 4, o == OLD_OWNER_NONE ? OWNER_TOWN : o); // tram owner } @@ -1208,7 +1212,7 @@ bool AfterLoadGame() if (GB(t.m5(), 3, 2) == TRANSPORT_RAIL) { MakeRailNormal( t, - GetTileOwner(t), + OldGetTileOwner(t), axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X, GetRailType(t) ); @@ -1231,10 +1235,10 @@ bool AfterLoadGame() if (!IsTileFlat(t)) { MakeShore(t); } else { - if (GetTileOwner(t) == OWNER_WATER) { + if (OldGetTileOwner(t) == OWNER_WATER) { MakeSea(t); } else { - MakeCanal(t, GetTileOwner(t), Random()); + MakeCanal(t, OldGetTileOwner(t), Random()); } } } @@ -1568,7 +1572,7 @@ bool AfterLoadGame() * be OWNER_NONE. So replace OWNER_NONE with OWNER_WATER. */ if (IsSavegameVersionBefore(SLV_46)) { for (Waypoint *wp : Waypoint::Iterate()) { - if ((wp->facilities & FACIL_DOCK) != 0 && IsTileOwner(wp->xy, OLD_OWNER_NONE) && TileHeight(wp->xy) == 0) SetTileOwner(wp->xy, OWNER_WATER); + if ((wp->facilities & FACIL_DOCK) != 0 && IsTileOwner(wp->xy, OLD_OWNER_NONE) && TileHeight(wp->xy) == 0) OldSetTileOwner(wp->xy, OWNER_WATER); } } @@ -1678,9 +1682,9 @@ bool AfterLoadGame() for (auto t : Map::Iterate()) { if (IsTileType(t, MP_WATER) && GetWaterTileType(t) == WATER_TILE_CLEAR && - GetTileOwner(t) == OWNER_WATER && + OldGetTileOwner(t) == OWNER_WATER && TileHeight(t) != 0) { - SetTileOwner(t, OWNER_NONE); + OldSetTileOwner(t, OWNER_NONE); } } } @@ -1828,7 +1832,7 @@ bool AfterLoadGame() if (IsTileType(t, MP_WATER)) { if (GetWaterClass(t) != WATER_CLASS_RIVER) { if (IsWater(t)) { - Owner o = GetTileOwner(t); + Owner o = OldGetTileOwner(t); if (o == OWNER_WATER) { MakeSea(t); } else { @@ -1864,7 +1868,7 @@ bool AfterLoadGame() } if (IsBuoyTile(t) || IsDriveThroughStopTile(t) || IsTileType(t, MP_WATER)) { - Owner o = GetTileOwner(t); + Owner o = OldGetTileOwner(t); if (o < OLD_MAX_COMPANIES && !Company::IsValidID(o)) { Backup cur_company(_current_company, o); ChangeTileOwner(t, o, INVALID_OWNER); @@ -1883,10 +1887,10 @@ bool AfterLoadGame() if (o < OLD_MAX_COMPANIES && !Company::IsValidID(o)) SetRoadOwner(t, rtt, OWNER_NONE); } if (IsLevelCrossing(t)) { - if (!Company::IsValidID(GetTileOwner(t))) FixOwnerOfRailTrack(t); + if (!Company::IsValidID(OldGetTileOwner(t))) FixOwnerOfRailTrack(t); } } else if (IsPlainRailTile(t)) { - if (!Company::IsValidID(GetTileOwner(t))) FixOwnerOfRailTrack(t); + if (!Company::IsValidID(OldGetTileOwner(t))) FixOwnerOfRailTrack(t); } } } @@ -2473,7 +2477,7 @@ bool AfterLoadGame() /* Add (random) colour to all objects. */ if (IsSavegameVersionBefore(SLV_148)) { for (Object *o : Object::Iterate()) { - Owner owner = GetTileOwner(o->location.tile); + Owner owner = OldGetTileOwner(o->location.tile); o->colour = (owner == OLD_OWNER_NONE) ? static_cast(GB(Random(), 0, 4)) : Company::Get(owner)->livery->colour1; } } @@ -2841,7 +2845,7 @@ bool AfterLoadGame() if (IsSavegameVersionBefore(SLV_172)) { for (auto t : Map::Iterate()) { if (!IsBayRoadStopTile(t)) continue; - Owner o = GetTileOwner(t); + Owner o = OldGetTileOwner(t); SetRoadOwner(t, RTT_ROAD, o); SetRoadOwner(t, RTT_TRAM, o); } @@ -3262,6 +3266,15 @@ bool AfterLoadGame() if (IsSavegameVersionBefore(SLV_SCRIPT_RANDOMIZER)) { ScriptObject::InitializeRandomizers(); } + if (IsSavegameVersionBefore(SLV_MORE_COMPANIES)) { + for (auto t : Map::Iterate()) { + if (IsValidTile(t) + && !IsTileType(t, MP_HOUSE) + && !IsTileType(t, MP_INDUSTRY)) { + SetTileOwner(t, OldGetTileOwner(t)); + } + } + } for (Company *c : Company::Iterate()) { UpdateCompanyLiveries(c); diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp index a4e5a35e7b..e56a674b40 100644 --- a/src/saveload/company_sl.cpp +++ b/src/saveload/company_sl.cpp @@ -475,9 +475,11 @@ static const SaveLoad _company_desc[] = { SLE_CONDVAR(CompanyProperties, num_valid_stat_ent, SLE_UINT8, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH), - SLE_VAR(CompanyProperties, months_of_bankruptcy, SLE_UINT8), - // MYTODO: Fix all the compat issues - SLE_CONDCOMPMASK(CompanyProperties, bankrupt_asked, SLE_UINT8, COMPANY_SIZE_BITS, SLV_179, SL_MAX_VERSION), + SLE_VAR(CompanyProperties, months_of_bankruptcy, SLE_UINT8), +SLE_CONDVARNAME(CompanyProperties, old_bankrupt_asked, "bankrupt_asked", SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104), +SLE_CONDVARNAME(CompanyProperties, old_bankrupt_asked, "bankrupt_asked", SLE_UINT16, SLV_104, SLV_MORE_COMPANIES), +SLE_CONDCOMPMASK(CompanyProperties, bankrupt_asked, MAX_COMPANIES, SLV_MORE_COMPANIES, SL_MAX_VERSION), + SLE_VAR(CompanyProperties, bankrupt_timeout, SLE_INT16), SLE_CONDVAR(CompanyProperties, bankrupt_value, SLE_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_65), SLE_CONDVAR(CompanyProperties, bankrupt_value, SLE_INT64, SLV_65, SL_MAX_VERSION), @@ -520,6 +522,9 @@ struct PLYRChunkHandler : ChunkHandler { Company *c = new (index) Company(); SlObject(c, slt); _company_colours[index] = c->colour; + if (IsSavegameVersionBefore(SLV_MORE_COMPANIES)) { + c->bankrupt_asked = owner_from_int(c->old_bankrupt_asked); + } } } diff --git a/src/saveload/engine_sl.cpp b/src/saveload/engine_sl.cpp index 599803f74d..d6e78d6638 100644 --- a/src/saveload/engine_sl.cpp +++ b/src/saveload/engine_sl.cpp @@ -20,24 +20,32 @@ #include "../safeguards.h" static const SaveLoad _engine_desc[] = { - SLE_CONDVAR(Engine, intro_date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), - SLE_CONDVAR(Engine, intro_date, SLE_INT32, SLV_31, SL_MAX_VERSION), - SLE_CONDVAR(Engine, age, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), - SLE_CONDVAR(Engine, age, SLE_INT32, SLV_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, flags, SLE_UINT8), - SLE_CONDCOMPMASK(Engine, preview_asked, SLE_UINT8, COMPANY_SIZE_BITS, SLV_179, SL_MAX_VERSION), - SLE_CONDVAR(Engine, preview_company, SLE_UINT8, SLV_179, SL_MAX_VERSION), - SLE_VAR(Engine, preview_wait, SLE_UINT8), -// MYTODO: Fix all the compatibility here - SLE_CONDCOMPMASK(Engine, company_avail, SLE_UINT8, COMPANY_SIZE_BITS, SLV_179, SL_MAX_VERSION), + SLE_CONDVAR(Engine, intro_date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), + SLE_CONDVAR(Engine, intro_date, SLE_INT32, SLV_31, SL_MAX_VERSION), + SLE_CONDVAR(Engine, age, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), + SLE_CONDVAR(Engine, age, SLE_INT32, SLV_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, flags, SLE_UINT8), + + SLE_CONDVARNAME(Engine, old_preview_asked, "preview_asked", SLE_UINT16, SLV_179, SLV_MORE_COMPANIES), +SLE_CONDCOMPMASK(Engine, preview_asked, MAX_COMPANIES, SLV_MORE_COMPANIES, SL_MAX_VERSION), + + SLE_CONDVAR(Engine, preview_company, SLE_UINT8, SLV_179, SL_MAX_VERSION), + SLE_VAR(Engine, preview_wait, SLE_UINT8), + + SLE_CONDVARNAME(Engine, old_company_avail, "company_avail", SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104), + SLE_CONDVARNAME(Engine, old_company_avail, "company_avail", SLE_UINT16, SLV_104, SLV_MORE_COMPANIES), +SLE_CONDCOMPMASK(Engine, company_avail, MAX_COMPANIES, SLV_MORE_COMPANIES, SL_MAX_VERSION), + +SLE_CONDCOMPMASK(Engine, company_hidden, MAX_COMPANIES, SLV_MORE_COMPANIES, SL_MAX_VERSION), + SLE_CONDVARNAME(Engine, old_company_hidden, "company_hidden", SLE_UINT16, SLV_193, SLV_MORE_COMPANIES), SLE_CONDSSTR(Engine, name, SLE_STR, SLV_84, SL_MAX_VERSION), }; @@ -111,6 +119,11 @@ struct ENGNChunkHandler : ChunkHandler { e->preview_company = INVALID_COMPANY; e->preview_asked = MAX_UVALUE(CompanyMask); } + if (IsSavegameVersionBefore(SLV_MORE_COMPANIES)) { + e->preview_asked = owner_from_int(e->old_preview_asked); + e->company_avail = owner_from_int(e->old_company_avail); + e->company_hidden = owner_from_int(e->old_company_hidden); + } } } }; diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 7e524cfa6e..d3c1a7f308 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -44,8 +44,10 @@ #include "../fios.h" #include "../error.h" #include "company_type.h" +#include "core/bitmath_func.hpp" #include #include +#include #include #include #ifdef __EMSCRIPTEN__ @@ -1114,61 +1116,56 @@ static void SlArray(void *array, size_t length, VarType conv) // MYTODO: Put this somewhere it belongs -std::vector bitset_to_bytes(const CompanyMask& bs) +std::vector bitset_to_bytes(const CompanyMask& mask) { - int N = COMPANY_SIZE_BITS; - std::vector result((N + 7) >> 3); - for (int j=0; j>3] |= (bs[j] << (j & 7)); + std::vector result((MAX_COMPANIES + 7) >> 3); + for (int j = 0; j < MAX_COMPANIES; j++) + result[j>>3] |= (mask[j] << (j & 7)); return result; } -CompanyMask bitset_from_bytes(const std::vector& buf) -{ - size_t N = COMPANY_SIZE_BITS; - assert(buf.size() == ((N + 7) >> 3)); +CompanyMask bitset_from_bytes(const std::vector& buf) { CompanyMask result; - for (int j=0; j>3] >> (j & 7)) & 1); return result; } +CompanyMask owner_from_int(uint16_t old_owner) { + CompanyMask result; + for (int i = 0; i < 16; i++) { + result[i] = GB(old_owner, i, 1) & 1; + } + return result; +} + /** * Save/Load the length of the bitset followed by the array of SL_VAR bits. * @param array The array being manipulated * @param length The length of the bitset in bytes, */ -static void SlCompanyMask(void *array, size_t length, VarType conv) +static void SlCompanyMask(void *array, size_t byte_length, VarType conv) { switch (_sl.action) { case SLA_SAVE: { CompanyMask *bs = static_cast(array); - // We don't save the number of bits in the company mask, - // because it's incompatible with other versions anyway std::vector bytes = bitset_to_bytes(*bs); uint8_t *bytes_arr = &bytes[0]; - - SlWriteArrayLength(bytes.size()); SlArray(bytes_arr, bytes.size(), conv); - return; } case SLA_LOAD_CHECK: case SLA_LOAD: { + assert(byte_length == (MAX_COMPANIES + 7) >> 3); - std::vector buff(length); + std::vector buff((MAX_COMPANIES + 7) >> 3); + SlArray(&buff[0], byte_length, conv); - SlArray(&buff[0], length, conv); - - CompanyMask res = bitset_from_bytes(buff); CompanyMask *bs = static_cast(array); - for (int i = 0; i < COMPANY_SIZE_BITS; i++) { - (*bs)[i] = res[i]; - } - + *bs = bitset_from_bytes(buff); // we don't want to write direc return; } @@ -2248,10 +2245,12 @@ static void SlLoadCheckChunks() const ChunkHandler *ch; for (id = SlReadUint32(); id != 0; id = SlReadUint32()) { - Debug(sl, 2, "Loading chunk {:c}{:c}{:c}{:c}", id >> 24, id >> 16, id >> 8, id); + Debug(sl, 2, "Loading chunk (for checking) {:c}{:c}{:c}{:c}", id >> 24, id >> 16, id >> 8, id); ch = SlFindChunkHandler(id); - if (ch == nullptr) SlErrorCorrupt("Unknown chunk type"); + if (ch == nullptr) { + SlErrorCorrupt("Unknown chunk type"); + } SlLoadCheckChunk(*ch); } } diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index f9b8b06905..28c128b0ed 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -381,6 +381,7 @@ enum SaveLoadVersion : uint16_t { SLV_COMPANY_ALLOW_LIST, ///< 335 PR#12337 Saving of list of client keys that are allowed to join this company. SLV_GROUP_NUMBERS, ///< 336 PR#12297 Add per-company group numbers. + SLV_MORE_COMPANIES, /// Added more companies MYTODO: Fix this comment SL_MAX_VERSION, ///< Highest possible saveload version }; @@ -1003,16 +1004,16 @@ inline constexpr bool SlCheckVarSize(SaveLoadType cmd, VarType type, size_t leng */ #define SLE_ARRNAME(base, variable, name, type, length) SLE_CONDARRNAME(base, variable, name, type, length, SL_MIN_VERSION, SL_MAX_VERSION) + /** - * Storage of a fixed-size array of #SL_VAR elements in some savegame versions. - * @param base Name of the class or struct containing the array. + * Storage of a company mask bitset of #MAX_COMPANIES bits in some savegame versions. + * @param base Name of the class or struct containing the company mask. * @param variable Name of the variable in the class or struct referenced by \a base. - * @param type Storage of the data in memory and in the savegame. - * @param length Number of elements in the array. + * @param bit_length Number of bits in the serialized form. * @param from First savegame version that has the array. * @param to Last savegame version that has the array. */ -#define SLE_CONDCOMPMASK(base, variable, type, length, from, to) SLE_GENERAL(SL_COMPANY_MASK, base, variable, type, length, from, to, 0) +#define SLE_CONDCOMPMASK(base, variable, bit_length, from, to) SLE_GENERAL(SL_COMPANY_MASK, base, variable, SLE_CHAR, (bit_length + 7) >> 3, from, to, 0) /** * Storage of a \c std::string in every savegame version. @@ -1313,6 +1314,7 @@ void SlCopy(void *object, size_t length, VarType conv); std::vector SlTableHeader(const SaveLoadTable &slt); std::vector SlCompatTableHeader(const SaveLoadTable &slt, const SaveLoadCompatTable &slct); void SlObject(void *object, const SaveLoadTable &slt); +CompanyMask owner_from_int(uint16_t old_owner); bool SaveloadCrashWithMissingNewGRFs(); diff --git a/src/saveload/town_sl.cpp b/src/saveload/town_sl.cpp index 2dc3c1162c..ea024634f7 100644 --- a/src/saveload/town_sl.cpp +++ b/src/saveload/town_sl.cpp @@ -215,11 +215,14 @@ static const SaveLoad _town_desc[] = { SLE_CONDSSTR(Town, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), SLE_VAR(Town, flags, SLE_UINT8), - // MYTODO: Fix all the compat -SLE_CONDCOMPMASK(Town, statues, SLE_UINT8, COMPANY_SIZE_BITS, SLV_179, SL_MAX_VERSION), +SLE_CONDVARNAME(Town, old_statues, "statues", SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104), +SLE_CONDVARNAME(Town, old_statues, "statues", SLE_UINT16, SLV_104, SLV_MORE_COMPANIES), +SLE_CONDCOMPMASK(Town, statues, MAX_COMPANIES, SLV_MORE_COMPANIES, SL_MAX_VERSION), + +SLE_CONDCOMPMASK(Town, have_ratings, MAX_COMPANIES, SLV_MORE_COMPANIES, SL_MAX_VERSION), +SLE_CONDVARNAME(Town, old_have_ratings, "have_ratings", SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104), +SLE_CONDVARNAME(Town, old_have_ratings, "have_ratings", SLE_UINT16, SLV_104, SLV_MORE_COMPANIES), - // MYTODO: Fix all the compat -SLE_CONDCOMPMASK(Town, have_ratings, SLE_UINT8, COMPANY_SIZE_BITS, SLV_179, SL_MAX_VERSION), SLE_CONDARR(Town, ratings, SLE_INT16, 8, SL_MIN_VERSION, SLV_104), SLE_CONDARR(Town, ratings, SLE_INT16, MAX_COMPANIES, SLV_104, SL_MAX_VERSION), SLE_CONDARR(Town, unwanted, SLE_INT8, 8, SLV_4, SLV_104), @@ -306,6 +309,10 @@ struct CITYChunkHandler : ChunkHandler { if (t->townnamegrfid == 0 && !IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1) && GetStringTab(t->townnametype) != TEXT_TAB_OLD_CUSTOM) { SlErrorCorrupt("Invalid town name generator"); } + if (IsSavegameVersionBefore(SLV_MORE_COMPANIES)) { + t->statues = owner_from_int(t->old_statues); + t->have_ratings = owner_from_int(t->old_have_ratings); + } } } diff --git a/src/town.h b/src/town.h index ce930bb180..d8512d1db1 100644 --- a/src/town.h +++ b/src/town.h @@ -16,6 +16,7 @@ #include "subsidy_type.h" #include "newgrf_storage.h" #include "cargotype.h" +#include template struct BuildingCounts { @@ -68,9 +69,11 @@ struct Town : TownPool::PoolItem<&_town_pool> { uint16_t noise_reached; ///< level of noise that all the airports are generating CompanyMask statues; ///< which companies have a statue? + uint16_t old_statues; /* Company ratings. */ CompanyMask have_ratings; ///< which companies have a rating + uint16_t old_have_ratings; uint8_t unwanted[MAX_COMPANIES]; ///< how many months companies aren't wanted by towns (bribe) CompanyID exclusivity; ///< which company has exclusivity uint8_t exclusive_counter; ///< months till the exclusivity expires