1
0
Fork 0

Finally POC

pull/12767/head
Andrii Dokhniak 2024-06-02 21:33:42 +02:00
parent 4f332d77ad
commit 924c14b849
11 changed files with 135 additions and 82 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
/.vs /.vs
/.cache/*
/build* /build*
CMakeSettings.json CMakeSettings.json
docs/aidocs/* docs/aidocs/*

Binary file not shown.

View File

@ -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_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 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? 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. 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; Money bankrupt_value;

View File

@ -15,6 +15,7 @@
#include "core/pool_type.hpp" #include "core/pool_type.hpp"
#include "newgrf_commons.h" #include "newgrf_commons.h"
#include "timer/timer_game_calendar.h" #include "timer/timer_game_calendar.h"
#include <cstdint>
struct WagonOverride { struct WagonOverride {
std::vector<EngineID> engines; std::vector<EngineID> 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_2; ///< Second reliability phase in months, keeping #reliability_max.
uint16_t duration_phase_3; ///< Third reliability phase in months, decaying to #reliability_final. uint16_t duration_phase_3; ///< Third reliability phase in months, decaying to #reliability_final.
uint8_t flags; ///< Flags of the engine. @see EngineFlags uint8_t flags; ///< Flags of the engine. @see EngineFlags
CompanyMask preview_asked; ///< Bit for each company which has already been offered a preview. 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. 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. 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. 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. 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 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. VehicleType type; ///< %Vehicle type, ie #VEH_ROAD, #VEH_TRAIN, etc.

View File

@ -63,11 +63,14 @@
#include "../timer/timer_game_economy.h" #include "../timer/timer_game_economy.h"
#include "../timer/timer_game_tick.h" #include "../timer/timer_game_tick.h"
#include "saveload/saveload.h"
#include "saveload_internal.h" #include "saveload_internal.h"
#include <signal.h> #include <signal.h>
#include "../safeguards.h" #include "../safeguards.h"
#include "tile_map.h"
#include "tile_type.h"
extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY); extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY);
@ -163,7 +166,7 @@ static void ConvertTownOwner()
[[fallthrough]]; [[fallthrough]];
case MP_TUNNELBRIDGE: case MP_TUNNELBRIDGE:
if (tile.m1() & 0x80) SetTileOwner(tile, OWNER_TOWN); if (tile.m1() & 0x80) OldSetTileOwner(tile, OWNER_TOWN);
break; break;
default: break; default: break;
@ -421,7 +424,7 @@ static void CDECL HandleSavegameLoadCrash(int signum)
*/ */
static void FixOwnerOfRailTrack(Tile t) 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) */ /* remove leftover rail piece from crossing (from very old savegames) */
Train *v = nullptr; Train *v = nullptr;
@ -434,7 +437,7 @@ static void FixOwnerOfRailTrack(Tile t)
if (v != nullptr) { if (v != nullptr) {
/* when there is a train on crossing (it could happen in TTD), set owner of crossing to train owner */ /* 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; return;
} }
@ -443,15 +446,15 @@ static void FixOwnerOfRailTrack(Tile t)
TileIndex tt = t + TileOffsByDiagDir(dd); TileIndex tt = t + TileOffsByDiagDir(dd);
if (GetTileTrackStatus(t, TRANSPORT_RAIL, 0, dd) != 0 && if (GetTileTrackStatus(t, TRANSPORT_RAIL, 0, dd) != 0 &&
GetTileTrackStatus(tt, TRANSPORT_RAIL, 0, ReverseDiagDir(dd)) != 0 && GetTileTrackStatus(tt, TRANSPORT_RAIL, 0, ReverseDiagDir(dd)) != 0 &&
Company::IsValidID(GetTileOwner(tt))) { Company::IsValidID(OldGetTileOwner(tt))) {
SetTileOwner(t, GetTileOwner(tt)); OldSetTileOwner(t, OldGetTileOwner(tt));
return; return;
} }
} }
if (IsLevelCrossingTile(t)) { if (IsLevelCrossingTile(t)) {
/* else change the crossing to normal road (road vehicles won't care) */ /* 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); Owner tram = GetRoadOwner(t, RTT_TRAM);
RoadBits bits = GetCrossingRoadBits(t); RoadBits bits = GetCrossingRoadBits(t);
bool hasroad = HasBit(t.m7(), 6); bool hasroad = HasBit(t.m7(), 6);
@ -459,7 +462,7 @@ static void FixOwnerOfRailTrack(Tile t)
/* MakeRoadNormal */ /* MakeRoadNormal */
SetTileType(t, MP_ROAD); SetTileType(t, MP_ROAD);
SetTileOwner(t, road); OldSetTileOwner(t, road);
t.m3() = (hasroad ? bits : 0); t.m3() = (hasroad ? bits : 0);
t.m5() = (hastram ? bits : 0) | ROAD_TILE_NORMAL << 6; t.m5() = (hastram ? bits : 0) | ROAD_TILE_NORMAL << 6;
SB(t.m6(), 2, 4, 0); SB(t.m6(), 2, 4, 0);
@ -471,6 +474,7 @@ static void FixOwnerOfRailTrack(Tile t)
MakeClear(t, CLEAR_GRASS, 0); MakeClear(t, CLEAR_GRASS, 0);
} }
/** /**
* Fixes inclination of a vehicle. Older OpenTTD versions didn't update the bits correctly. * Fixes inclination of a vehicle. Older OpenTTD versions didn't update the bits correctly.
* @param v vehicle * @param v vehicle
@ -656,8 +660,8 @@ bool AfterLoadGame()
* walk through the whole map.. */ * walk through the whole map.. */
if (IsSavegameVersionBefore(SLV_4, 3)) { if (IsSavegameVersionBefore(SLV_4, 3)) {
for (auto t : Map::Iterate()) { for (auto t : Map::Iterate()) {
if (IsTileType(t, MP_WATER) && GetTileOwner(t) >= OLD_MAX_COMPANIES) { if (IsTileType(t, MP_WATER) && OldGetTileOwner(t) >= OLD_MAX_COMPANIES) {
SetTileOwner(t, OWNER_WATER); OldSetTileOwner(t, OWNER_WATER);
} }
} }
} }
@ -858,7 +862,7 @@ bool AfterLoadGame()
default: break; default: break;
case MP_WATER: 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; break;
case MP_STATION: { case MP_STATION: {
@ -913,7 +917,7 @@ bool AfterLoadGame()
BaseStation *bst = BaseStation::GetByTile(t); BaseStation *bst = BaseStation::GetByTile(t);
/* Sanity check */ /* 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 */ /* Set up station spread */
bst->rect.BeforeAddTile(t, StationRect::ADD_FORCE); bst->rect.BeforeAddTile(t, StationRect::ADD_FORCE);
@ -986,7 +990,7 @@ bool AfterLoadGame()
case MP_ROAD: case MP_ROAD:
t.m4() |= (t.m2() << 4); 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); SetTownIndex(t, CalcClosestTownFromTile(t)->index);
} else { } else {
SetTownIndex(t, 0); SetTownIndex(t, 0);
@ -1139,7 +1143,7 @@ bool AfterLoadGame()
if (!IsRoadStop(t)) break; if (!IsRoadStop(t)) break;
if (fix_roadtypes) SB(t.m7(), 6, 2, (RoadTypes)GB(t.m3(), 0, 3)); 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()); SB(t.m3(), 4, 4, t.m1());
t.m4() = 0; t.m4() = 0;
break; break;
@ -1149,7 +1153,7 @@ bool AfterLoadGame()
if (((old_bridge && IsBridge(t)) ? (TransportType)GB(t.m5(), 1, 2) : GetTunnelBridgeTransportType(t)) == TRANSPORT_ROAD) { 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)); 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.m7(), 0, 5, o); // road owner
SB(t.m3(), 4, 4, o == OLD_OWNER_NONE ? OWNER_TOWN : o); // tram 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) { if (GB(t.m5(), 3, 2) == TRANSPORT_RAIL) {
MakeRailNormal( MakeRailNormal(
t, t,
GetTileOwner(t), OldGetTileOwner(t),
axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X, axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X,
GetRailType(t) GetRailType(t)
); );
@ -1231,10 +1235,10 @@ bool AfterLoadGame()
if (!IsTileFlat(t)) { if (!IsTileFlat(t)) {
MakeShore(t); MakeShore(t);
} else { } else {
if (GetTileOwner(t) == OWNER_WATER) { if (OldGetTileOwner(t) == OWNER_WATER) {
MakeSea(t); MakeSea(t);
} else { } 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. */ * be OWNER_NONE. So replace OWNER_NONE with OWNER_WATER. */
if (IsSavegameVersionBefore(SLV_46)) { if (IsSavegameVersionBefore(SLV_46)) {
for (Waypoint *wp : Waypoint::Iterate()) { 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()) { for (auto t : Map::Iterate()) {
if (IsTileType(t, MP_WATER) && if (IsTileType(t, MP_WATER) &&
GetWaterTileType(t) == WATER_TILE_CLEAR && GetWaterTileType(t) == WATER_TILE_CLEAR &&
GetTileOwner(t) == OWNER_WATER && OldGetTileOwner(t) == OWNER_WATER &&
TileHeight(t) != 0) { TileHeight(t) != 0) {
SetTileOwner(t, OWNER_NONE); OldSetTileOwner(t, OWNER_NONE);
} }
} }
} }
@ -1828,7 +1832,7 @@ bool AfterLoadGame()
if (IsTileType(t, MP_WATER)) { if (IsTileType(t, MP_WATER)) {
if (GetWaterClass(t) != WATER_CLASS_RIVER) { if (GetWaterClass(t) != WATER_CLASS_RIVER) {
if (IsWater(t)) { if (IsWater(t)) {
Owner o = GetTileOwner(t); Owner o = OldGetTileOwner(t);
if (o == OWNER_WATER) { if (o == OWNER_WATER) {
MakeSea(t); MakeSea(t);
} else { } else {
@ -1864,7 +1868,7 @@ bool AfterLoadGame()
} }
if (IsBuoyTile(t) || IsDriveThroughStopTile(t) || IsTileType(t, MP_WATER)) { 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)) { if (o < OLD_MAX_COMPANIES && !Company::IsValidID(o)) {
Backup<CompanyID> cur_company(_current_company, o); Backup<CompanyID> cur_company(_current_company, o);
ChangeTileOwner(t, o, INVALID_OWNER); 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 (o < OLD_MAX_COMPANIES && !Company::IsValidID(o)) SetRoadOwner(t, rtt, OWNER_NONE);
} }
if (IsLevelCrossing(t)) { if (IsLevelCrossing(t)) {
if (!Company::IsValidID(GetTileOwner(t))) FixOwnerOfRailTrack(t); if (!Company::IsValidID(OldGetTileOwner(t))) FixOwnerOfRailTrack(t);
} }
} else if (IsPlainRailTile(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. */ /* Add (random) colour to all objects. */
if (IsSavegameVersionBefore(SLV_148)) { if (IsSavegameVersionBefore(SLV_148)) {
for (Object *o : Object::Iterate()) { 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<Colours>(GB(Random(), 0, 4)) : Company::Get(owner)->livery->colour1; o->colour = (owner == OLD_OWNER_NONE) ? static_cast<Colours>(GB(Random(), 0, 4)) : Company::Get(owner)->livery->colour1;
} }
} }
@ -2841,7 +2845,7 @@ bool AfterLoadGame()
if (IsSavegameVersionBefore(SLV_172)) { if (IsSavegameVersionBefore(SLV_172)) {
for (auto t : Map::Iterate()) { for (auto t : Map::Iterate()) {
if (!IsBayRoadStopTile(t)) continue; if (!IsBayRoadStopTile(t)) continue;
Owner o = GetTileOwner(t); Owner o = OldGetTileOwner(t);
SetRoadOwner(t, RTT_ROAD, o); SetRoadOwner(t, RTT_ROAD, o);
SetRoadOwner(t, RTT_TRAM, o); SetRoadOwner(t, RTT_TRAM, o);
} }
@ -3262,6 +3266,15 @@ bool AfterLoadGame()
if (IsSavegameVersionBefore(SLV_SCRIPT_RANDOMIZER)) { if (IsSavegameVersionBefore(SLV_SCRIPT_RANDOMIZER)) {
ScriptObject::InitializeRandomizers(); 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()) { for (Company *c : Company::Iterate()) {
UpdateCompanyLiveries(c); UpdateCompanyLiveries(c);

View File

@ -476,8 +476,10 @@ static const SaveLoad _company_desc[] = {
SLE_CONDVAR(CompanyProperties, num_valid_stat_ent, SLE_UINT8, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH), SLE_CONDVAR(CompanyProperties, num_valid_stat_ent, SLE_UINT8, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
SLE_VAR(CompanyProperties, months_of_bankruptcy, SLE_UINT8), SLE_VAR(CompanyProperties, months_of_bankruptcy, SLE_UINT8),
// MYTODO: Fix all the compat issues SLE_CONDVARNAME(CompanyProperties, old_bankrupt_asked, "bankrupt_asked", SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104),
SLE_CONDCOMPMASK(CompanyProperties, bankrupt_asked, SLE_UINT8, COMPANY_SIZE_BITS, SLV_179, SL_MAX_VERSION), 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_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_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_65),
SLE_CONDVAR(CompanyProperties, bankrupt_value, SLE_INT64, SLV_65, SL_MAX_VERSION), SLE_CONDVAR(CompanyProperties, bankrupt_value, SLE_INT64, SLV_65, SL_MAX_VERSION),
@ -520,6 +522,9 @@ struct PLYRChunkHandler : ChunkHandler {
Company *c = new (index) Company(); Company *c = new (index) Company();
SlObject(c, slt); SlObject(c, slt);
_company_colours[index] = c->colour; _company_colours[index] = c->colour;
if (IsSavegameVersionBefore(SLV_MORE_COMPANIES)) {
c->bankrupt_asked = owner_from_int(c->old_bankrupt_asked);
}
} }
} }

View File

@ -33,11 +33,19 @@ static const SaveLoad _engine_desc[] = {
SLE_VAR(Engine, duration_phase_2, SLE_UINT16), SLE_VAR(Engine, duration_phase_2, SLE_UINT16),
SLE_VAR(Engine, duration_phase_3, SLE_UINT16), SLE_VAR(Engine, duration_phase_3, SLE_UINT16),
SLE_VAR(Engine, flags, SLE_UINT8), SLE_VAR(Engine, flags, SLE_UINT8),
SLE_CONDCOMPMASK(Engine, preview_asked, SLE_UINT8, COMPANY_SIZE_BITS, SLV_179, SL_MAX_VERSION),
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_CONDVAR(Engine, preview_company, SLE_UINT8, SLV_179, SL_MAX_VERSION),
SLE_VAR(Engine, preview_wait, SLE_UINT8), 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_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), 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_company = INVALID_COMPANY;
e->preview_asked = MAX_UVALUE(CompanyMask); 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);
}
} }
} }
}; };

View File

@ -44,8 +44,10 @@
#include "../fios.h" #include "../fios.h"
#include "../error.h" #include "../error.h"
#include "company_type.h" #include "company_type.h"
#include "core/bitmath_func.hpp"
#include <atomic> #include <atomic>
#include <bitset> #include <bitset>
#include <cassert>
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
@ -1114,61 +1116,56 @@ static void SlArray(void *array, size_t length, VarType conv)
// MYTODO: Put this somewhere it belongs // MYTODO: Put this somewhere it belongs
std::vector<uint8_t> bitset_to_bytes(const CompanyMask& bs) std::vector<uint8_t> bitset_to_bytes(const CompanyMask& mask)
{ {
int N = COMPANY_SIZE_BITS; std::vector<unsigned char> result((MAX_COMPANIES + 7) >> 3);
std::vector<unsigned char> result((N + 7) >> 3); for (int j = 0; j < MAX_COMPANIES; j++)
for (int j=0; j<int(N); j++) result[j>>3] |= (mask[j] << (j & 7));
result[j>>3] |= (bs[j] << (j & 7));
return result; return result;
} }
CompanyMask bitset_from_bytes(const std::vector<uint8_t>& buf) CompanyMask bitset_from_bytes(const std::vector<uint8_t>& buf) {
{
size_t N = COMPANY_SIZE_BITS;
assert(buf.size() == ((N + 7) >> 3));
CompanyMask result; CompanyMask result;
for (int j=0; j<int(N); j++) for (int j=0; j < MAX_COMPANIES; j++)
result[j] = ((buf[j>>3] >> (j & 7)) & 1); result[j] = ((buf[j>>3] >> (j & 7)) & 1);
return result; 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. * Save/Load the length of the bitset followed by the array of SL_VAR bits.
* @param array The array being manipulated * @param array The array being manipulated
* @param length The length of the bitset in bytes, * @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) { switch (_sl.action) {
case SLA_SAVE: { case SLA_SAVE: {
CompanyMask *bs = static_cast<CompanyMask *>(array); CompanyMask *bs = static_cast<CompanyMask *>(array);
// We don't save the number of bits in the company mask,
// because it's incompatible with other versions anyway
std::vector<uint8_t> bytes = bitset_to_bytes(*bs); std::vector<uint8_t> bytes = bitset_to_bytes(*bs);
uint8_t *bytes_arr = &bytes[0]; uint8_t *bytes_arr = &bytes[0];
SlWriteArrayLength(bytes.size());
SlArray(bytes_arr, bytes.size(), conv); SlArray(bytes_arr, bytes.size(), conv);
return; return;
} }
case SLA_LOAD_CHECK: case SLA_LOAD_CHECK:
case SLA_LOAD: { case SLA_LOAD: {
assert(byte_length == (MAX_COMPANIES + 7) >> 3);
std::vector<uint8_t> buff(length); std::vector<uint8_t> 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<CompanyMask *>(array); CompanyMask *bs = static_cast<CompanyMask *>(array);
for (int i = 0; i < COMPANY_SIZE_BITS; i++) { *bs = bitset_from_bytes(buff); // we don't want to write direc
(*bs)[i] = res[i];
}
return; return;
} }
@ -2248,10 +2245,12 @@ static void SlLoadCheckChunks()
const ChunkHandler *ch; const ChunkHandler *ch;
for (id = SlReadUint32(); id != 0; id = SlReadUint32()) { 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); ch = SlFindChunkHandler(id);
if (ch == nullptr) SlErrorCorrupt("Unknown chunk type"); if (ch == nullptr) {
SlErrorCorrupt("Unknown chunk type");
}
SlLoadCheckChunk(*ch); SlLoadCheckChunk(*ch);
} }
} }

View File

@ -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_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_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 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) #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. * Storage of a company mask bitset of #MAX_COMPANIES bits in some savegame versions.
* @param base Name of the class or struct containing the array. * @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 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 bit_length Number of bits in the serialized form.
* @param length Number of elements in the array.
* @param from First savegame version that has the array. * @param from First savegame version that has the array.
* @param to Last 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. * 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<SaveLoad> SlTableHeader(const SaveLoadTable &slt); std::vector<SaveLoad> SlTableHeader(const SaveLoadTable &slt);
std::vector<SaveLoad> SlCompatTableHeader(const SaveLoadTable &slt, const SaveLoadCompatTable &slct); std::vector<SaveLoad> SlCompatTableHeader(const SaveLoadTable &slt, const SaveLoadCompatTable &slct);
void SlObject(void *object, const SaveLoadTable &slt); void SlObject(void *object, const SaveLoadTable &slt);
CompanyMask owner_from_int(uint16_t old_owner);
bool SaveloadCrashWithMissingNewGRFs(); bool SaveloadCrashWithMissingNewGRFs();

View File

@ -215,11 +215,14 @@ static const SaveLoad _town_desc[] = {
SLE_CONDSSTR(Town, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), SLE_CONDSSTR(Town, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION),
SLE_VAR(Town, flags, SLE_UINT8), SLE_VAR(Town, flags, SLE_UINT8),
// MYTODO: Fix all the compat SLE_CONDVARNAME(Town, old_statues, "statues", SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104),
SLE_CONDCOMPMASK(Town, statues, SLE_UINT8, COMPANY_SIZE_BITS, SLV_179, SL_MAX_VERSION), 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, 8, SL_MIN_VERSION, SLV_104),
SLE_CONDARR(Town, ratings, SLE_INT16, MAX_COMPANIES, SLV_104, SL_MAX_VERSION), SLE_CONDARR(Town, ratings, SLE_INT16, MAX_COMPANIES, SLV_104, SL_MAX_VERSION),
SLE_CONDARR(Town, unwanted, SLE_INT8, 8, SLV_4, SLV_104), 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) { 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"); 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);
}
} }
} }

View File

@ -16,6 +16,7 @@
#include "subsidy_type.h" #include "subsidy_type.h"
#include "newgrf_storage.h" #include "newgrf_storage.h"
#include "cargotype.h" #include "cargotype.h"
#include <cstdint>
template <typename T> template <typename T>
struct BuildingCounts { 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 uint16_t noise_reached; ///< level of noise that all the airports are generating
CompanyMask statues; ///< which companies have a statue? CompanyMask statues; ///< which companies have a statue?
uint16_t old_statues;
/* Company ratings. */ /* Company ratings. */
CompanyMask have_ratings; ///< which companies have a rating 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) uint8_t unwanted[MAX_COMPANIES]; ///< how many months companies aren't wanted by towns (bribe)
CompanyID exclusivity; ///< which company has exclusivity CompanyID exclusivity; ///< which company has exclusivity
uint8_t exclusive_counter; ///< months till the exclusivity expires uint8_t exclusive_counter; ///< months till the exclusivity expires