Update to 14.0-beta1

This commit is contained in:
dP
2024-02-04 02:18:17 +05:30
parent 79037e2c65
commit 33ef333b57
1325 changed files with 138465 additions and 70987 deletions

View File

@@ -44,4 +44,5 @@ add_files(
town_sl.cpp
vehicle_sl.cpp
waypoint_sl.cpp
water_regions_sl.cpp
)

File diff suppressed because it is too large Load Diff

View File

@@ -66,7 +66,7 @@ struct AIPLChunkHandler : ChunkHandler {
/* Free all current data */
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(nullptr);
AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(std::nullopt);
}
CompanyID index;
@@ -85,13 +85,13 @@ struct AIPLChunkHandler : ChunkHandler {
AIConfig *config = AIConfig::GetConfig(index, AIConfig::SSS_FORCE_GAME);
if (_ai_saveload_name.empty()) {
/* A random AI. */
config->Change(nullptr, -1, false, true);
config->Change(std::nullopt, -1, false, true);
} else {
config->Change(_ai_saveload_name.c_str(), _ai_saveload_version, false, _ai_saveload_is_random);
config->Change(_ai_saveload_name, _ai_saveload_version, false, _ai_saveload_is_random);
if (!config->HasScript()) {
/* No version of the AI available that can load the data. Try to load the
* latest version of the AI instead. */
config->Change(_ai_saveload_name.c_str(), -1, false, _ai_saveload_is_random);
config->Change(_ai_saveload_name, -1, false, _ai_saveload_is_random);
if (!config->HasScript()) {
if (_ai_saveload_name.compare("%_dummy") != 0) {
Debug(script, 0, "The savegame has an AI by the name '{}', version {} which is no longer available.", _ai_saveload_name, _ai_saveload_version);

View File

@@ -13,8 +13,6 @@
#include "compat/animated_tile_sl_compat.h"
#include "../tile_type.h"
#include "../core/alloc_func.hpp"
#include "../core/smallvec_type.hpp"
#include "../safeguards.h"

View File

@@ -19,7 +19,7 @@
/** Temporary storage of cargo monitoring data for loading or saving it. */
struct TempStorage {
CargoMonitorID number;
uint32 amount;
uint32_t amount;
};
/** Description of the #TempStorage structure for the purpose of load and save. */
@@ -81,7 +81,7 @@ struct CMDLChunkHandler : ChunkHandler {
if (fix) storage.number = FixupCargoMonitor(storage.number);
std::pair<CargoMonitorID, uint32> p(storage.number, storage.amount);
std::pair<CargoMonitorID, uint32_t> p(storage.number, storage.amount);
_cargo_deliveries.insert(p);
}
}
@@ -125,7 +125,7 @@ struct CMPUChunkHandler : ChunkHandler {
if (fix) storage.number = FixupCargoMonitor(storage.number);
std::pair<CargoMonitorID, uint32> p(storage.number, storage.amount);
std::pair<CargoMonitorID, uint32_t> p(storage.number, storage.amount);
_cargo_pickups.insert(p);
}
}

View File

@@ -33,8 +33,7 @@
const CargoPacketList *packets = v->cargo.Packets();
for (VehicleCargoList::ConstIterator it(packets->begin()); it != packets->end(); it++) {
CargoPacket *cp = *it;
cp->source_xy = Station::IsValidID(cp->source) ? Station::Get(cp->source)->xy : v->tile;
cp->loaded_at_xy = cp->source_xy;
cp->source_xy = Station::IsValidID(cp->first_station) ? Station::Get(cp->first_station)->xy : v->tile;
}
}
@@ -44,14 +43,11 @@
* information is lost. In that case we set it to the position of this
* station */
for (Station *st : Station::Iterate()) {
for (CargoID c = 0; c < NUM_CARGO; c++) {
GoodsEntry *ge = &st->goods[c];
const StationCargoPacketMap *packets = ge->cargo.Packets();
for (GoodsEntry &ge : st->goods) {
const StationCargoPacketMap *packets = ge.cargo.Packets();
for (StationCargoList::ConstIterator it(packets->begin()); it != packets->end(); it++) {
CargoPacket *cp = *it;
cp->source_xy = Station::IsValidID(cp->source) ? Station::Get(cp->source)->xy : st->xy;
cp->loaded_at_xy = cp->source_xy;
cp->source_xy = Station::IsValidID(cp->first_station) ? Station::Get(cp->first_station)->xy : st->xy;
}
}
}
@@ -60,7 +56,7 @@
if (IsSavegameVersionBefore(SLV_120)) {
/* CargoPacket's source should be either INVALID_STATION or a valid station */
for (CargoPacket *cp : CargoPacket::Iterate()) {
if (!Station::IsValidID(cp->source)) cp->source = INVALID_STATION;
if (!Station::IsValidID(cp->first_station)) cp->first_station = INVALID_STATION;
}
}
@@ -71,13 +67,48 @@
for (Vehicle *v : Vehicle::Iterate()) v->cargo.InvalidateCache();
for (Station *st : Station::Iterate()) {
for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache();
for (GoodsEntry &ge : st->goods) ge.cargo.InvalidateCache();
}
}
if (IsSavegameVersionBefore(SLV_181)) {
for (Vehicle *v : Vehicle::Iterate()) v->cargo.KeepAll();
}
/* Before this version, we didn't track how far cargo actually traveled in vehicles. Make best-effort estimates of this. */
if (IsSavegameVersionBefore(SLV_CARGO_TRAVELLED)) {
/* Update the cargo-traveled in stations as if they arrived from the source tile. */
for (Station *st : Station::Iterate()) {
for (GoodsEntry &ge : st->goods) {
for (auto it = ge.cargo.Packets()->begin(); it != ge.cargo.Packets()->end(); ++it) {
for (CargoPacket *cp : it->second) {
if (cp->source_xy != INVALID_TILE && cp->source_xy != st->xy) {
cp->travelled.x = TileX(cp->source_xy) - TileX(st->xy);
cp->travelled.y = TileY(cp->source_xy) - TileY(st->xy);
}
}
}
}
}
/* Update the cargo-traveled in vehicles as if they were loaded at the source tile. */
for (Vehicle *v : Vehicle::Iterate()) {
for (auto it = v->cargo.Packets()->begin(); it != v->cargo.Packets()->end(); it++) {
if ((*it)->source_xy != INVALID_TILE) {
(*it)->UpdateLoadingTile((*it)->source_xy);
}
}
}
}
#ifdef WITH_ASSERT
/* in_vehicle is a NOSAVE; it tells if cargo is in a vehicle or not. Restore the value in here. */
for (Vehicle *v : Vehicle::Iterate()) {
for (auto it = v->cargo.Packets()->begin(); it != v->cargo.Packets()->end(); it++) {
(*it)->in_vehicle = true;
}
}
#endif /* WITH_ASSERT */
}
/**
@@ -88,14 +119,19 @@
SaveLoadTable GetCargoPacketDesc()
{
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_CONDVAR(CargoPacket, source_type, SLE_UINT8, SLV_125, SL_MAX_VERSION),
SLE_CONDVAR(CargoPacket, source_id, SLE_UINT16, SLV_125, SL_MAX_VERSION),
SLE_VARNAME(CargoPacket, first_station, "source", SLE_UINT16),
SLE_VAR(CargoPacket, source_xy, SLE_UINT32),
SLE_CONDVARNAME(CargoPacket, next_hop, "loaded_at_xy", SLE_FILE_U32 | SLE_VAR_U16, SL_MIN_VERSION, SLV_REMOVE_LOADED_AT_XY),
SLE_CONDVARNAME(CargoPacket, next_hop, "loaded_at_xy", SLE_UINT16, SLV_REMOVE_LOADED_AT_XY, SL_MAX_VERSION),
SLE_VAR(CargoPacket, count, SLE_UINT16),
SLE_CONDVARNAME(CargoPacket, periods_in_transit, "days_in_transit", SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_MORE_CARGO_AGE),
SLE_CONDVARNAME(CargoPacket, periods_in_transit, "days_in_transit", SLE_UINT16, SLV_MORE_CARGO_AGE, SLV_PERIODS_IN_TRANSIT_RENAME),
SLE_CONDVAR(CargoPacket, periods_in_transit, SLE_UINT16, SLV_PERIODS_IN_TRANSIT_RENAME, SL_MAX_VERSION),
SLE_VAR(CargoPacket, feeder_share, SLE_INT64),
SLE_CONDVAR(CargoPacket, source_type, SLE_UINT8, SLV_125, SL_MAX_VERSION),
SLE_CONDVAR(CargoPacket, source_id, SLE_UINT16, SLV_125, SL_MAX_VERSION),
SLE_CONDVAR(CargoPacket, travelled.x, SLE_INT16, SLV_CARGO_TRAVELLED, SL_MAX_VERSION),
SLE_CONDVAR(CargoPacket, travelled.y, SLE_INT16, SLV_CARGO_TRAVELLED, SL_MAX_VERSION),
};
return _cargopacket_desc;
}

View File

@@ -33,6 +33,8 @@ static const SaveLoad _cheats_desc[] = {
SLE_VAR(Cheats, setup_prod.value, SLE_BOOL),
SLE_VAR(Cheats, edit_max_hl.been_used, SLE_BOOL),
SLE_VAR(Cheats, edit_max_hl.value, SLE_BOOL),
SLE_CONDVAR(Cheats, station_rating.been_used, SLE_BOOL, SLV_STATION_RATING_CHEAT, SL_MAX_VERSION),
SLE_CONDVAR(Cheats, station_rating.value, SLE_BOOL, SLV_STATION_RATING_CHEAT, SL_MAX_VERSION),
};

View File

@@ -42,7 +42,7 @@
* @param face the face in the old format
* @return the face in the new format
*/
CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32 face)
CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32_t face)
{
CompanyManagerFace cmf = 0;
GenderEthnicity ge = GE_WM;
@@ -106,7 +106,7 @@ void AfterLoadCompanyStats()
}
Company *c;
for (TileIndex tile = 0; tile < MapSize(); tile++) {
for (TileIndex tile = 0; tile < Map::Size(); tile++) {
switch (GetTileType(tile)) {
case MP_RAILWAY:
c = Company::GetIfValid(GetTileOwner(tile));
@@ -186,7 +186,7 @@ void AfterLoadCompanyStats()
}
}
}
FALLTHROUGH;
[[fallthrough]];
case MP_OBJECT:
if (GetWaterClass(tile) == WATER_CLASS_CANAL) {
@@ -240,7 +240,7 @@ void AfterLoadCompanyStats()
/* We do need to read this single value, as the bigger it gets, the more data is stored */
struct CompanyOldAI {
uint8 num_build_rec;
uint8_t num_build_rec;
};
class SlCompanyOldAIBuildRec : public DefaultSaveLoadHandler<SlCompanyOldAIBuildRec, CompanyOldAI> {
@@ -364,7 +364,7 @@ public:
void Load(CompanyProperties *c) const override
{
if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) {
c->num_valid_stat_ent = (uint8)SlGetStructListLength(UINT8_MAX);
c->num_valid_stat_ent = (uint8_t)SlGetStructListLength(UINT8_MAX);
}
if (c->num_valid_stat_ent > lengthof(c->old_economy)) SlErrorCorrupt("Too many old economy entries");
@@ -458,6 +458,7 @@ static const SaveLoad _company_desc[] = {
SLE_CONDVAR(CompanyProperties, current_loan, SLE_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_65),
SLE_CONDVAR(CompanyProperties, current_loan, SLE_INT64, SLV_65, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, max_loan, SLE_INT64, SLV_MAX_LOAN_FOR_COMPANY, SL_MAX_VERSION),
SLE_VAR(CompanyProperties, colour, SLE_UINT8),
SLE_VAR(CompanyProperties, money_fraction, SLE_UINT8),
@@ -470,8 +471,6 @@ static const SaveLoad _company_desc[] = {
SLE_CONDVAR(CompanyProperties, inaugurated_year, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
SLE_CONDVAR(CompanyProperties, inaugurated_year, SLE_INT32, SLV_31, SL_MAX_VERSION),
SLE_ARR(CompanyProperties, share_owners, SLE_UINT8, 4),
SLE_CONDVAR(CompanyProperties, num_valid_stat_ent, SLE_UINT8, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
SLE_VAR(CompanyProperties, months_of_bankruptcy, SLE_UINT8),
@@ -518,7 +517,7 @@ struct PLYRChunkHandler : ChunkHandler {
while ((index = SlIterateArray()) != -1) {
Company *c = new (index) Company();
SlObject(c, slt);
_company_colours[index] = (Colours)c->colour;
_company_colours[index] = c->colour;
}
}
@@ -529,8 +528,8 @@ struct PLYRChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
CompanyProperties *cprops = new CompanyProperties();
SlObject(cprops, slt);
std::unique_ptr<CompanyProperties> cprops = std::make_unique<CompanyProperties>();
SlObject(cprops.get(), slt);
/* We do not load old custom names */
if (IsSavegameVersionBefore(SLV_84)) {
@@ -550,7 +549,9 @@ struct PLYRChunkHandler : ChunkHandler {
cprops->name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE;
}
if (!_load_check_data.companies.Insert(index, cprops)) delete cprops;
if (_load_check_data.companies.count(index) == 0) {
_load_check_data.companies[index] = std::move(cprops);
}
}
}

View File

@@ -106,7 +106,7 @@ const SaveLoadCompat _company_sl_compat[] = {
SLC_VAR("location_of_HQ"),
SLC_VAR("last_build_coordinate"),
SLC_VAR("inaugurated_year"),
SLC_VAR("share_owners"),
SLC_NULL(4, SL_MIN_VERSION, SLV_TABLE_CHUNKS),
SLC_VAR("num_valid_stat_ent"),
SLC_VAR("months_of_bankruptcy"),
SLC_VAR("bankrupt_asked"),

View File

@@ -12,6 +12,23 @@
#include "../saveload.h"
const SaveLoadCompat _industry_accepts_sl_compat[] = {
SLC_VAR("cargo"),
SLC_VAR("waiting"),
SLC_VAR("last_accepted"),
};
const SaveLoadCompat _industry_produced_history_sl_compat[] = {
SLC_VAR("production"),
SLC_VAR("transported"),
};
const SaveLoadCompat _industry_produced_sl_compat[] = {
SLC_VAR("cargo"),
SLC_VAR("waiting"),
SLC_VAR("rate"),
};
/** Original field order for _industry_desc. */
const SaveLoadCompat _industry_sl_compat[] = {
SLC_VAR("location.tile"),
@@ -29,7 +46,8 @@ const SaveLoadCompat _industry_sl_compat[] = {
SLC_VAR("prod_level"),
SLC_VAR("this_month_production"),
SLC_VAR("this_month_transported"),
SLC_VAR("last_month_pct_transported"),
SLC_NULL(2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLC_NULL(16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLC_VAR("last_month_production"),
SLC_VAR("last_month_transported"),
SLC_VAR("counter"),

View File

@@ -154,15 +154,15 @@ const SaveLoadCompat _settings_sl_compat[] = {
SLC_NULL(4, SL_MIN_VERSION, SLV_105),
SLC_VAR("game_creation.ending_year"),
SLC_VAR("economy.type"),
SLC_VAR("economy.allow_shares"),
SLC_VAR("economy.min_years_for_shares"),
SLC_NULL(1, SL_MIN_VERSION, SLV_TABLE_CHUNKS),
SLC_NULL(1, SLV_TRADING_AGE, SLV_TABLE_CHUNKS),
SLC_VAR("economy.feeder_payment_share"),
SLC_VAR("economy.town_growth_rate"),
SLC_VAR("economy.larger_towns"),
SLC_VAR("economy.initial_city_size"),
SLC_VAR("economy.mod_road_rebuild"),
SLC_NULL(1, SL_MIN_VERSION, SLV_107),
SLC_VAR("script.settings_profile"),
SLC_NULL(1, SLV_178, SLV_TABLE_CHUNKS),
SLC_VAR("ai.ai_in_multiplayer"),
SLC_VAR("ai.ai_disable_veh_train"),
SLC_VAR("ai.ai_disable_veh_roadveh"),

View File

@@ -32,6 +32,12 @@ const SaveLoadCompat _station_spec_list_sl_compat[] = {
SLC_VAR("localidx"),
};
/** Nominal field order for SlRoadStopSpecList. */
const SaveLoadCompat _station_road_stop_spec_list_sl_compat[] = {
SLC_VAR("grfid"),
SLC_VAR("localidx"),
};
/** Original field order for SlStationCargo. */
const SaveLoadCompat _station_cargo_sl_compat[] = {
SLC_VAR("first"),

View File

@@ -82,7 +82,7 @@ const SaveLoadCompat _vehicle_common_sl_compat[] = {
SLC_VAR("profit_this_year"),
SLC_VAR("profit_last_year"),
SLC_VAR("cargo_feeder_share"),
SLC_VAR("cargo_loaded_at_xy"),
SLC_NULL(4, SLV_51, SLV_68),
SLC_VAR("value"),
SLC_VAR("random_bits"),
SLC_VAR("waiting_triggers"),

View File

@@ -23,7 +23,7 @@ struct PRICChunkHandler : ChunkHandler {
void Load() const override
{
/* Old games store 49 base prices, very old games store them as int32 */
/* Old games store 49 base prices, very old games store them as int32_t */
int vt = IsSavegameVersionBefore(SLV_65) ? SLE_FILE_I32 : SLE_FILE_I64;
SlCopy(nullptr, 49, vt | SLE_VAR_NULL);
SlCopy(nullptr, 49, SLE_FILE_U16 | SLE_VAR_NULL);

View File

@@ -15,7 +15,6 @@
#include "saveload_internal.h"
#include "../engine_base.h"
#include "../string_func.h"
#include <vector>
#include "../safeguards.h"
@@ -49,9 +48,9 @@ static std::vector<Engine*> _temp_engine;
* The allocated Engine must be freed using FreeEngine;
* @return Allocated engine.
*/
static Engine* CallocEngine()
static Engine *CallocEngine()
{
uint8 *zero = CallocT<uint8>(sizeof(Engine));
uint8_t *zero = CallocT<uint8_t>(sizeof(Engine));
Engine *engine = new (zero) Engine();
return engine;
}
@@ -110,7 +109,7 @@ struct ENGNChunkHandler : ChunkHandler {
* Just cancel any previews. */
e->flags &= ~4; // ENGINE_OFFER_WINDOW_OPEN
e->preview_company = INVALID_COMPANY;
e->preview_asked = (CompanyMask)-1;
e->preview_asked = MAX_UVALUE(CompanyMask);
}
}
}

View File

@@ -34,7 +34,7 @@ static const SaveLoad _game_script_desc[] = {
SLEG_VAR("is_random", _game_saveload_is_random, SLE_BOOL),
};
static void SaveReal_GSDT(int *index_ptr)
static void SaveReal_GSDT(int *)
{
GameConfig *config = GameConfig::GetConfig();
@@ -62,7 +62,7 @@ struct GSDTChunkHandler : ChunkHandler {
const std::vector<SaveLoad> slt = SlCompatTableHeader(_game_script_desc, _game_script_sl_compat);
/* Free all current data */
GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME)->Change(nullptr);
GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME)->Change(std::nullopt);
if (SlIterateArray() == -1) return;
@@ -77,11 +77,11 @@ struct GSDTChunkHandler : ChunkHandler {
GameConfig *config = GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME);
if (!_game_saveload_name.empty()) {
config->Change(_game_saveload_name.c_str(), _game_saveload_version, false, _game_saveload_is_random);
config->Change(_game_saveload_name, _game_saveload_version, false, _game_saveload_is_random);
if (!config->HasScript()) {
/* No version of the GameScript available that can load the data. Try to load the
* latest version of the GameScript instead. */
config->Change(_game_saveload_name.c_str(), -1, false, _game_saveload_is_random);
config->Change(_game_saveload_name, -1, false, _game_saveload_is_random);
if (!config->HasScript()) {
if (_game_saveload_name.compare("%_dummy") != 0) {
Debug(script, 0, "The savegame has an GameScript by the name '{}', version {} which is no longer available.", _game_saveload_name, _game_saveload_version);
@@ -119,7 +119,7 @@ struct GSDTChunkHandler : ChunkHandler {
extern GameStrings *_current_data;
static std::string _game_saveload_string;
static uint32 _game_saveload_strings;
static uint32_t _game_saveload_strings;
class SlGameLanguageString : public DefaultSaveLoadHandler<SlGameLanguageString, LanguageStrings> {
public:
@@ -140,9 +140,9 @@ public:
void Load(LanguageStrings *ls) const override
{
uint32 length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _game_saveload_strings : (uint32)SlGetStructListLength(UINT32_MAX);
uint32_t length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _game_saveload_strings : (uint32_t)SlGetStructListLength(UINT32_MAX);
for (uint32 i = 0; i < length; i++) {
for (uint32_t i = 0; i < length; i++) {
SlObject(nullptr, this->GetLoadDescription());
ls->lines.emplace_back(_game_saveload_string);
}
@@ -172,7 +172,7 @@ struct GSTRChunkHandler : ChunkHandler {
}
/* If there were no strings in the savegame, set GameStrings to nullptr */
if (_current_data->raw_strings.size() == 0) {
if (_current_data->raw_strings.empty()) {
delete _current_data;
_current_data = nullptr;
return;

View File

@@ -14,6 +14,7 @@
#include "../gamelog_internal.h"
#include "../fios.h"
#include "../string_func.h"
#include "../safeguards.h"
@@ -21,8 +22,8 @@
class SlGamelogMode : public DefaultSaveLoadHandler<SlGamelogMode, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, mode.mode, SLE_UINT8),
SLE_VAR(LoggedChange, mode.landscape, SLE_UINT8),
SLE_VARNAME(LoggedChangeMode, mode, "mode.mode", SLE_UINT8),
SLE_VARNAME(LoggedChangeMode, landscape, "mode.landscape", SLE_UINT8),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_mode_sl_compat;
@@ -43,11 +44,15 @@ public:
class SlGamelogRevision : public DefaultSaveLoadHandler<SlGamelogRevision, LoggedChange> {
public:
static const size_t GAMELOG_REVISION_LENGTH = 15;
static char revision_text[GAMELOG_REVISION_LENGTH];
inline static const SaveLoad description[] = {
SLE_ARR(LoggedChange, revision.text, SLE_UINT8, GAMELOG_REVISION_LENGTH),
SLE_VAR(LoggedChange, revision.newgrf, SLE_UINT32),
SLE_VAR(LoggedChange, revision.slver, SLE_UINT16),
SLE_VAR(LoggedChange, revision.modified, SLE_UINT8),
SLEG_CONDARR("revision.text", SlGamelogRevision::revision_text, SLE_UINT8, GAMELOG_REVISION_LENGTH, SL_MIN_VERSION, SLV_STRING_GAMELOG),
SLE_CONDSSTRNAME(LoggedChangeRevision, text, "revision.text", SLE_STR, SLV_STRING_GAMELOG, SL_MAX_VERSION),
SLE_VARNAME(LoggedChangeRevision, newgrf, "revision.newgrf", SLE_UINT32),
SLE_VARNAME(LoggedChangeRevision, slver, "revision.slver", SLE_UINT16),
SLE_VARNAME(LoggedChangeRevision, modified, "revision.modified", SLE_UINT8),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_revision_sl_compat;
@@ -61,16 +66,22 @@ public:
{
if (lc->ct != GLCT_REVISION) return;
SlObject(lc, this->GetLoadDescription());
if (IsSavegameVersionBefore(SLV_STRING_GAMELOG)) {
static_cast<LoggedChangeRevision *>(lc)->text = StrMakeValid(std::string_view(SlGamelogRevision::revision_text, lengthof(SlGamelogRevision::revision_text)));
}
}
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
/* static */ char SlGamelogRevision::revision_text[GAMELOG_REVISION_LENGTH];
class SlGamelogOldver : public DefaultSaveLoadHandler<SlGamelogOldver, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, oldver.type, SLE_UINT32),
SLE_VAR(LoggedChange, oldver.version, SLE_UINT32),
SLE_VARNAME(LoggedChangeOldVersion, type, "oldver.type", SLE_UINT32),
SLE_VARNAME(LoggedChangeOldVersion, version, "oldver.version", SLE_UINT32),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_oldver_sl_compat;
@@ -92,9 +103,9 @@ public:
class SlGamelogSetting : public DefaultSaveLoadHandler<SlGamelogSetting, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_STR(LoggedChange, setting.name, SLE_STR, 128),
SLE_VAR(LoggedChange, setting.oldval, SLE_INT32),
SLE_VAR(LoggedChange, setting.newval, SLE_INT32),
SLE_SSTRNAME(LoggedChangeSettingChanged, name, "setting.name", SLE_STR),
SLE_VARNAME(LoggedChangeSettingChanged, oldval, "setting.oldval", SLE_INT32),
SLE_VARNAME(LoggedChangeSettingChanged, newval, "setting.newval", SLE_INT32),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_setting_sl_compat;
@@ -116,8 +127,8 @@ public:
class SlGamelogGrfadd : public DefaultSaveLoadHandler<SlGamelogGrfadd, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfadd.grfid, SLE_UINT32 ),
SLE_ARR(LoggedChange, grfadd.md5sum, SLE_UINT8, 16),
SLE_VARNAME(LoggedChangeGRFAdd, grfid, "grfadd.grfid", SLE_UINT32 ),
SLE_ARRNAME(LoggedChangeGRFAdd, md5sum, "grfadd.md5sum", SLE_UINT8, 16),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfadd_sl_compat;
@@ -139,7 +150,7 @@ public:
class SlGamelogGrfrem : public DefaultSaveLoadHandler<SlGamelogGrfrem, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfrem.grfid, SLE_UINT32),
SLE_VARNAME(LoggedChangeGRFRemoved, grfid, "grfrem.grfid", SLE_UINT32),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfrem_sl_compat;
@@ -161,8 +172,8 @@ public:
class SlGamelogGrfcompat : public DefaultSaveLoadHandler<SlGamelogGrfcompat, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfcompat.grfid, SLE_UINT32 ),
SLE_ARR(LoggedChange, grfcompat.md5sum, SLE_UINT8, 16),
SLE_VARNAME(LoggedChangeGRFChanged, grfid, "grfcompat.grfid", SLE_UINT32 ),
SLE_ARRNAME(LoggedChangeGRFChanged, md5sum, "grfcompat.md5sum", SLE_UINT8, 16),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfcompat_sl_compat;
@@ -184,7 +195,7 @@ public:
class SlGamelogGrfparam : public DefaultSaveLoadHandler<SlGamelogGrfparam, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfparam.grfid, SLE_UINT32),
SLE_VARNAME(LoggedChangeGRFParameterChanged, grfid, "grfparam.grfid", SLE_UINT32),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfparam_sl_compat;
@@ -206,8 +217,8 @@ public:
class SlGamelogGrfmove : public DefaultSaveLoadHandler<SlGamelogGrfmove, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfmove.grfid, SLE_UINT32),
SLE_VAR(LoggedChange, grfmove.offset, SLE_INT32),
SLE_VARNAME(LoggedChangeGRFMoved, grfid, "grfmove.grfid", SLE_UINT32),
SLE_VARNAME(LoggedChangeGRFMoved, offset, "grfmove.offset", SLE_INT32),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfmove_sl_compat;
@@ -229,9 +240,9 @@ public:
class SlGamelogGrfbug : public DefaultSaveLoadHandler<SlGamelogGrfbug, LoggedChange> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(LoggedChange, grfbug.data, SLE_UINT64),
SLE_VAR(LoggedChange, grfbug.grfid, SLE_UINT32),
SLE_VAR(LoggedChange, grfbug.bug, SLE_UINT8),
SLE_VARNAME(LoggedChangeGRFBug, data, "grfbug.data", SLE_UINT64),
SLE_VARNAME(LoggedChangeGRFBug, grfid, "grfbug.grfid", SLE_UINT32),
SLE_VARNAME(LoggedChangeGRFBug, bug, "grfbug.bug", SLE_UINT8),
};
inline const static SaveLoadCompatTable compat_description = _gamelog_grfbug_sl_compat;
@@ -278,6 +289,27 @@ public:
void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
};
static std::unique_ptr<LoggedChange> MakeLoggedChange(GamelogChangeType type)
{
switch (type) {
case GLCT_MODE: return std::make_unique<LoggedChangeMode>();
case GLCT_REVISION: return std::make_unique<LoggedChangeRevision>();
case GLCT_OLDVER: return std::make_unique<LoggedChangeOldVersion>();
case GLCT_SETTING: return std::make_unique<LoggedChangeSettingChanged>();
case GLCT_GRFADD: return std::make_unique<LoggedChangeGRFAdd>();
case GLCT_GRFREM: return std::make_unique<LoggedChangeGRFRemoved>();
case GLCT_GRFCOMPAT: return std::make_unique<LoggedChangeGRFChanged>();
case GLCT_GRFPARAM: return std::make_unique<LoggedChangeGRFParameterChanged>();
case GLCT_GRFMOVE: return std::make_unique<LoggedChangeGRFMoved>();
case GLCT_GRFBUG: return std::make_unique<LoggedChangeGRFBug>();
case GLCT_EMERGENCY: return std::make_unique<LoggedChangeEmergencySave>();
case GLCT_END:
case GLCT_NONE:
default:
SlErrorCorrupt("Invalid gamelog action type");
}
}
class SlGamelogAction : public DefaultSaveLoadHandler<SlGamelogAction, LoggedAction> {
public:
inline static const SaveLoad description[] = {
@@ -298,44 +330,37 @@ public:
void Save(LoggedAction *la) const override
{
SlSetStructListLength(la->changes);
SlSetStructListLength(la->change.size());
const LoggedChange *lcend = &la->change[la->changes];
for (LoggedChange *lc = la->change; lc != lcend; lc++) {
assert((uint)lc->ct < GLCT_END);
SlObject(lc, this->GetDescription());
for (auto &lc : la->change) {
assert(lc->ct < GLCT_END);
SlObject(lc.get(), this->GetDescription());
}
}
void LoadChange(LoggedAction *la, GamelogChangeType type) const
{
std::unique_ptr<LoggedChange> lc = MakeLoggedChange(type);
SlObject(lc.get(), this->GetLoadDescription());
la->change.push_back(std::move(lc));
}
void Load(LoggedAction *la) const override
{
if (IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY)) {
byte type;
while ((type = SlReadByte()) != GLCT_NONE) {
if (type >= GLCT_END) SlErrorCorrupt("Invalid gamelog change type");
GamelogChangeType ct = (GamelogChangeType)type;
la->change = ReallocT(la->change, la->changes + 1);
LoggedChange *lc = &la->change[la->changes++];
memset(lc, 0, sizeof(*lc));
lc->ct = ct;
SlObject(lc, this->GetLoadDescription());
LoadChange(la, (GamelogChangeType)type);
}
return;
}
size_t length = SlGetStructListLength(UINT32_MAX);
la->change = ReallocT(la->change, length);
la->changes = (uint32)length;
la->change.reserve(length);
for (size_t i = 0; i < length; i++) {
LoggedChange *lc = &la->change[i];
memset(lc, 0, sizeof(*lc));
lc->ct = (GamelogChangeType)SlReadByte();
SlObject(lc, this->GetLoadDescription());
LoadChange(la, (GamelogChangeType)SlReadByte());
}
}
@@ -352,10 +377,9 @@ static const SaveLoad _gamelog_desc[] = {
struct GLOGChunkHandler : ChunkHandler {
GLOGChunkHandler() : ChunkHandler('GLOG', CH_TABLE) {}
void LoadCommon(LoggedAction *&gamelog_action, uint &gamelog_actions) const
void LoadCommon(Gamelog &gamelog) const
{
assert(gamelog_action == nullptr);
assert(gamelog_actions == 0);
assert(gamelog.data->action.empty());
const std::vector<SaveLoad> slt = SlCompatTableHeader(_gamelog_desc, _gamelog_sl_compat);
@@ -364,22 +388,16 @@ struct GLOGChunkHandler : ChunkHandler {
while ((type = SlReadByte()) != GLAT_NONE) {
if (type >= GLAT_END) SlErrorCorrupt("Invalid gamelog action type");
gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1);
LoggedAction *la = &gamelog_action[gamelog_actions++];
memset(la, 0, sizeof(*la));
la->at = (GamelogActionType)type;
SlObject(la, slt);
LoggedAction &la = gamelog.data->action.emplace_back();
la.at = (GamelogActionType)type;
SlObject(&la, slt);
}
return;
}
while (SlIterateArray() != -1) {
gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1);
LoggedAction *la = &gamelog_action[gamelog_actions++];
memset(la, 0, sizeof(*la));
SlObject(la, slt);
LoggedAction &la = gamelog.data->action.emplace_back();
SlObject(&la, slt);
}
}
@@ -387,23 +405,21 @@ struct GLOGChunkHandler : ChunkHandler {
{
SlTableHeader(_gamelog_desc);
const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
uint i = 0;
for (LoggedAction *la = _gamelog_action; la != laend; la++, i++) {
SlSetArrayIndex(i);
SlObject(la, _gamelog_desc);
for (LoggedAction &la : _gamelog.data->action) {
SlSetArrayIndex(i++);
SlObject(&la, _gamelog_desc);
}
}
void Load() const override
{
this->LoadCommon(_gamelog_action, _gamelog_actions);
this->LoadCommon(_gamelog);
}
void LoadCheck(size_t) const override
{
this->LoadCommon(_load_check_data.gamelog_action, _load_check_data.gamelog_actions);
this->LoadCommon(_load_check_data.gamelog);
}
};

View File

@@ -17,12 +17,12 @@
#include "../safeguards.h"
static const SaveLoad _goals_desc[] = {
SLE_VAR(Goal, company, SLE_FILE_U16 | SLE_VAR_U8),
SLE_VAR(Goal, type, SLE_FILE_U16 | SLE_VAR_U8),
SLE_VAR(Goal, dst, SLE_UINT32),
SLE_STR(Goal, text, SLE_STR | SLF_ALLOW_CONTROL, 0),
SLE_CONDSTR(Goal, progress, SLE_STR | SLF_ALLOW_CONTROL, 0, SLV_182, SL_MAX_VERSION),
SLE_CONDVAR(Goal, completed, SLE_BOOL, SLV_182, SL_MAX_VERSION),
SLE_VAR(Goal, company, SLE_FILE_U16 | SLE_VAR_U8),
SLE_VAR(Goal, type, SLE_FILE_U16 | SLE_VAR_U8),
SLE_VAR(Goal, dst, SLE_UINT32),
SLE_SSTR(Goal, text, SLE_STR | SLF_ALLOW_CONTROL),
SLE_CONDSSTR(Goal, progress, SLE_STR | SLF_ALLOW_CONTROL, SLV_182, SL_MAX_VERSION),
SLE_CONDVAR(Goal, completed, SLE_BOOL, SLV_182, SL_MAX_VERSION),
};
struct GOALChunkHandler : ChunkHandler {

View File

@@ -19,6 +19,125 @@
static OldPersistentStorage _old_ind_persistent_storage;
class SlIndustryAccepted : public DefaultSaveLoadHandler<SlIndustryAccepted, Industry> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(Industry::AcceptedCargo, cargo, SLE_UINT8),
SLE_VAR(Industry::AcceptedCargo, waiting, SLE_UINT16),
SLE_VAR(Industry::AcceptedCargo, last_accepted, SLE_INT32),
};
inline const static SaveLoadCompatTable compat_description = _industry_accepts_sl_compat;
void Save(Industry *i) const override
{
SlSetStructListLength(i->accepted.size());
for (auto &a : i->accepted) {
SlObject(&a, this->GetDescription());
}
}
void Load(Industry *i) const override
{
size_t len = SlGetStructListLength(i->accepted.size());
for (auto &a : i->accepted) {
if (--len > i->accepted.size()) break; // unsigned so wraps after hitting zero.
SlObject(&a, this->GetDescription());
}
}
/* Old array structure used for savegames before SLV_INDUSTRY_CARGO_REORGANISE. */
static CargoID old_cargo[INDUSTRY_NUM_INPUTS];
static uint16_t old_waiting[INDUSTRY_NUM_INPUTS];
static TimerGameEconomy::Date old_last_accepted[INDUSTRY_NUM_INPUTS];
};
/* static */ CargoID SlIndustryAccepted::old_cargo[INDUSTRY_NUM_INPUTS];
/* static */ uint16_t SlIndustryAccepted::old_waiting[INDUSTRY_NUM_INPUTS];
/* static */ TimerGameEconomy::Date SlIndustryAccepted::old_last_accepted[INDUSTRY_NUM_INPUTS];
class SlIndustryProducedHistory : public DefaultSaveLoadHandler<SlIndustryProducedHistory, Industry::ProducedCargo> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(Industry::ProducedHistory, production, SLE_UINT16),
SLE_VAR(Industry::ProducedHistory, transported, SLE_UINT16),
};
inline const static SaveLoadCompatTable compat_description = _industry_produced_history_sl_compat;
void Save(Industry::ProducedCargo *p) const override
{
if (!IsValidCargoID(p->cargo)) {
/* Don't save any history if cargo slot isn't used. */
SlSetStructListLength(0);
return;
}
SlSetStructListLength(p->history.size());
for (auto &h : p->history) {
SlObject(&h, this->GetDescription());
}
}
void Load(Industry::ProducedCargo *p) const override
{
size_t len = SlGetStructListLength(p->history.size());
for (auto &h : p->history) {
if (--len > p->history.size()) break; // unsigned so wraps after hitting zero.
SlObject(&h, this->GetDescription());
}
}
};
class SlIndustryProduced : public DefaultSaveLoadHandler<SlIndustryProduced, Industry> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(Industry::ProducedCargo, cargo, SLE_UINT8),
SLE_VAR(Industry::ProducedCargo, waiting, SLE_UINT16),
SLE_VAR(Industry::ProducedCargo, rate, SLE_UINT8),
SLEG_STRUCTLIST("history", SlIndustryProducedHistory),
};
inline const static SaveLoadCompatTable compat_description = _industry_produced_sl_compat;
void Save(Industry *i) const override
{
SlSetStructListLength(i->produced.size());
for (auto &p : i->produced) {
SlObject(&p, this->GetDescription());
}
}
void Load(Industry *i) const override
{
size_t len = SlGetStructListLength(i->produced.size());
for (auto &p : i->produced) {
if (--len > i->produced.size()) break; // unsigned so wraps after hitting zero.
SlObject(&p, this->GetDescription());
}
}
/* Old array structure used for savegames before SLV_INDUSTRY_CARGO_REORGANISE. */
static CargoID old_cargo[INDUSTRY_NUM_OUTPUTS];
static uint16_t old_waiting[INDUSTRY_NUM_OUTPUTS];
static uint8_t old_rate[INDUSTRY_NUM_OUTPUTS];
static uint16_t old_this_month_production[INDUSTRY_NUM_OUTPUTS];
static uint16_t old_this_month_transported[INDUSTRY_NUM_OUTPUTS];
static uint16_t old_last_month_production[INDUSTRY_NUM_OUTPUTS];
static uint16_t old_last_month_transported[INDUSTRY_NUM_OUTPUTS];
};
/* static */ CargoID SlIndustryProduced::old_cargo[INDUSTRY_NUM_OUTPUTS];
/* static */ uint16_t SlIndustryProduced::old_waiting[INDUSTRY_NUM_OUTPUTS];
/* static */ uint8_t SlIndustryProduced::old_rate[INDUSTRY_NUM_OUTPUTS];
/* static */ uint16_t SlIndustryProduced::old_this_month_production[INDUSTRY_NUM_OUTPUTS];
/* static */ uint16_t SlIndustryProduced::old_this_month_transported[INDUSTRY_NUM_OUTPUTS];
/* static */ uint16_t SlIndustryProduced::old_last_month_production[INDUSTRY_NUM_OUTPUTS];
/* static */ uint16_t SlIndustryProduced::old_last_month_transported[INDUSTRY_NUM_OUTPUTS];
static const SaveLoad _industry_desc[] = {
SLE_CONDVAR(Industry, location.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
SLE_CONDVAR(Industry, location.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
@@ -26,27 +145,25 @@ static const SaveLoad _industry_desc[] = {
SLE_VAR(Industry, location.h, SLE_FILE_U8 | SLE_VAR_U16),
SLE_REF(Industry, town, REF_TOWN),
SLE_CONDREF(Industry, neutral_station, REF_STATION, SLV_SERVE_NEUTRAL_INDUSTRIES, SL_MAX_VERSION),
SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 2, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 3, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, production_rate, SLE_UINT8, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, production_rate, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 3, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLEG_CONDARR("produced_cargo", SlIndustryProduced::old_cargo, SLE_UINT8, 2, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("produced_cargo", SlIndustryProduced::old_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLEG_CONDARR("incoming_cargo_waiting", SlIndustryAccepted::old_waiting, SLE_UINT16, 3, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("incoming_cargo_waiting", SlIndustryAccepted::old_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLEG_CONDARR("produced_cargo_waiting", SlIndustryProduced::old_waiting, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("produced_cargo_waiting", SlIndustryProduced::old_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLEG_CONDARR("production_rate", SlIndustryProduced::old_rate, SLE_UINT8, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("production_rate", SlIndustryProduced::old_rate, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLEG_CONDARR("accepts_cargo", SlIndustryAccepted::old_cargo, SLE_UINT8, 3, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("accepts_cargo", SlIndustryAccepted::old_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_VAR(Industry, prod_level, SLE_UINT8),
SLE_CONDARR(Industry, this_month_production, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, this_month_production, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, this_month_transported, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, this_month_transported, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, last_month_pct_transported, SLE_UINT8, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, last_month_pct_transported, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, last_month_production, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, last_month_production, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, last_month_transported, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, last_month_transported, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLEG_CONDARR("this_month_production", SlIndustryProduced::old_this_month_production, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("this_month_production", SlIndustryProduced::old_this_month_production, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLEG_CONDARR("this_month_transported", SlIndustryProduced::old_this_month_transported, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("this_month_transported", SlIndustryProduced::old_this_month_transported, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLEG_CONDARR("last_month_production", SlIndustryProduced::old_last_month_production, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("last_month_production", SlIndustryProduced::old_last_month_production, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLEG_CONDARR("last_month_transported", SlIndustryProduced::old_last_month_transported, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("last_month_transported", SlIndustryProduced::old_last_month_transported, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_VAR(Industry, counter, SLE_UINT16),
@@ -61,8 +178,8 @@ static const SaveLoad _industry_desc[] = {
SLE_CONDVAR(Industry, founder, SLE_UINT8, SLV_70, SL_MAX_VERSION),
SLE_CONDVAR(Industry, construction_date, SLE_INT32, SLV_70, SL_MAX_VERSION),
SLE_CONDVAR(Industry, construction_type, SLE_UINT8, SLV_70, SL_MAX_VERSION),
SLE_CONDVAR(Industry, last_cargo_accepted_at[0], SLE_INT32, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, last_cargo_accepted_at, SLE_INT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLEG_CONDVAR("last_cargo_accepted_at[0]", SlIndustryAccepted::old_last_accepted[0], SLE_INT32, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("last_cargo_accepted_at", SlIndustryAccepted::old_last_accepted, SLE_INT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_CONDVAR(Industry, selected_layout, SLE_UINT8, SLV_73, SL_MAX_VERSION),
SLE_CONDVAR(Industry, exclusive_supplier, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION),
SLE_CONDVAR(Industry, exclusive_consumer, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION),
@@ -72,6 +189,9 @@ static const SaveLoad _industry_desc[] = {
SLE_CONDVAR(Industry, random, SLE_UINT16, SLV_82, SL_MAX_VERSION),
SLE_CONDSSTR(Industry, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_INDUSTRY_TEXT, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST("accepted", SlIndustryAccepted, SLV_INDUSTRY_CARGO_REORGANISE, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST("produced", SlIndustryProduced, SLV_INDUSTRY_CARGO_REORGANISE, SL_MAX_VERSION),
};
struct INDYChunkHandler : ChunkHandler {
@@ -88,6 +208,27 @@ struct INDYChunkHandler : ChunkHandler {
}
}
void LoadMoveAcceptsProduced(Industry *i) const
{
for (uint j = 0; j != INDUSTRY_NUM_INPUTS; ++j) {
auto &a = i->accepted[j];
a.cargo = SlIndustryAccepted::old_cargo[j];
a.waiting = SlIndustryAccepted::old_waiting[j];
a.last_accepted = SlIndustryAccepted::old_last_accepted[j];
}
for (uint j = 0; j != INDUSTRY_NUM_OUTPUTS; ++j) {
auto &p = i->produced[j];
p.cargo = SlIndustryProduced::old_cargo[j];
p.waiting = SlIndustryProduced::old_waiting[j];
p.rate = SlIndustryProduced::old_rate[j];
p.history[THIS_MONTH].production = SlIndustryProduced::old_this_month_production[j];
p.history[THIS_MONTH].transported = SlIndustryProduced::old_this_month_transported[j];
p.history[LAST_MONTH].production = SlIndustryProduced::old_last_month_production[j];
p.history[LAST_MONTH].transported = SlIndustryProduced::old_last_month_transported[j];
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_industry_desc, _industry_sl_compat);
@@ -105,8 +246,9 @@ struct INDYChunkHandler : ChunkHandler {
/* Store the old persistent storage. The GRFID will be added later. */
assert(PersistentStorage::CanAllocateItem());
i->psa = new PersistentStorage(0, 0, 0);
memcpy(i->psa->storage, _old_ind_persistent_storage.storage, sizeof(_old_ind_persistent_storage.storage));
std::copy(std::begin(_old_ind_persistent_storage.storage), std::end(_old_ind_persistent_storage.storage), std::begin(i->psa->storage));
}
if (IsSavegameVersionBefore(SLV_INDUSTRY_CARGO_REORGANISE)) LoadMoveAcceptsProduced(i);
Industry::IncIndustryTypeCount(i->type);
}
}

View File

@@ -29,7 +29,7 @@ static bool NeedRailTypeConversion()
{
for (uint i = 0; i < _railtype_list.size(); i++) {
if ((RailType)i < RAILTYPE_END) {
const RailtypeInfo *rti = GetRailTypeInfo((RailType)i);
const RailTypeInfo *rti = GetRailTypeInfo((RailType)i);
if (rti->label != _railtype_list[i]) return true;
} else {
if (_railtype_list[i] != 0) return true;
@@ -52,7 +52,7 @@ void AfterLoadLabelMaps()
railtype_conversion_map.push_back(r);
}
for (TileIndex t = 0; t < MapSize(); t++) {
for (TileIndex t = 0; t < Map::Size(); t++) {
switch (GetTileType(t)) {
case MP_RAILWAY:
SetRailType(t, railtype_conversion_map[GetRailType(t)]);
@@ -92,7 +92,7 @@ void ResetLabelMaps()
/** Container for a label for SaveLoad system */
struct LabelObject {
uint32 label;
uint32_t label;
};
static const SaveLoad _label_object_desc[] = {

View File

@@ -16,13 +16,14 @@
#include "../safeguards.h"
static const SaveLoad _league_table_elements_desc[] = {
SLE_VAR(LeagueTableElement, table, SLE_UINT8),
SLE_VAR(LeagueTableElement, rating, SLE_FILE_U64 | SLE_VAR_I64),
SLE_VAR(LeagueTableElement, company, SLE_UINT8),
SLE_SSTR(LeagueTableElement, text, SLE_STR | SLF_ALLOW_CONTROL),
SLE_SSTR(LeagueTableElement, score, SLE_STR | SLF_ALLOW_CONTROL),
SLE_VAR(LeagueTableElement, link.type, SLE_UINT8),
SLE_VAR(LeagueTableElement, link.target, SLE_UINT32),
SLE_VAR(LeagueTableElement, table, SLE_UINT8),
SLE_CONDVAR(LeagueTableElement, rating, SLE_FILE_U64 | SLE_VAR_I64, SL_MIN_VERSION, SLV_LINKGRAPH_EDGES),
SLE_CONDVAR(LeagueTableElement, rating, SLE_INT64, SLV_LINKGRAPH_EDGES, SL_MAX_VERSION),
SLE_VAR(LeagueTableElement, company, SLE_UINT8),
SLE_SSTR(LeagueTableElement, text, SLE_STR | SLF_ALLOW_CONTROL),
SLE_SSTR(LeagueTableElement, score, SLE_STR | SLF_ALLOW_CONTROL),
SLE_VAR(LeagueTableElement, link.type, SLE_UINT8),
SLE_VAR(LeagueTableElement, link.target, SLE_UINT32),
};
struct LEAEChunkHandler : ChunkHandler {

View File

@@ -24,7 +24,7 @@
typedef LinkGraph::BaseNode Node;
typedef LinkGraph::BaseEdge Edge;
static uint16 _num_nodes;
static uint16_t _num_nodes;
static LinkGraph *_linkgraph; ///< Contains the current linkgraph being saved/loaded.
static NodeID _linkgraph_from; ///< Contains the current "from" node being saved/loaded.
@@ -36,47 +36,60 @@ public:
SLE_CONDVAR(Edge, travel_time_sum, SLE_UINT64, SLV_LINKGRAPH_TRAVEL_TIME, SL_MAX_VERSION),
SLE_VAR(Edge, last_unrestricted_update, SLE_INT32),
SLE_CONDVAR(Edge, last_restricted_update, SLE_INT32, SLV_187, SL_MAX_VERSION),
SLE_VAR(Edge, next_edge, SLE_UINT16),
SLE_VAR(Edge, dest_node, SLE_UINT16),
SLE_CONDVARNAME(Edge, dest_node, "next_edge", SLE_UINT16, SL_MIN_VERSION, SLV_LINKGRAPH_EDGES),
};
inline const static SaveLoadCompatTable compat_description = _linkgraph_edge_sl_compat;
void Save(Node *bn) const override
{
uint16 size = 0;
for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) {
size++;
}
SlSetStructListLength(size);
for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) {
SlObject(&_linkgraph->edges[_linkgraph_from][to], this->GetDescription());
SlSetStructListLength(bn->edges.size());
for (Edge &e : bn->edges) {
SlObject(&e, this->GetDescription());
}
}
void Load(Node *bn) const override
{
uint16 max_size = _linkgraph->Size();
if (IsSavegameVersionBefore(SLV_LINKGRAPH_EDGES)) {
uint16_t max_size = _linkgraph->Size();
std::vector<Edge> edges(max_size);
if (IsSavegameVersionBefore(SLV_191)) {
/* We used to save the full matrix ... */
for (NodeID to = 0; to < max_size; ++to) {
SlObject(&_linkgraph->edges[_linkgraph_from][to], this->GetLoadDescription());
if (IsSavegameVersionBefore(SLV_191)) {
/* We used to save the full matrix ... */
for (NodeID to = 0; to < max_size; ++to) {
SlObject(&edges[to], this->GetLoadDescription());
}
} else {
size_t used_size = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? max_size : SlGetStructListLength(UINT16_MAX);
/* ... but as that wasted a lot of space we save a sparse matrix now. */
for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = edges[to].dest_node) {
if (used_size == 0) SlErrorCorrupt("Link graph structure overflow");
used_size--;
if (to >= max_size) SlErrorCorrupt("Link graph structure overflow");
SlObject(&edges[to], this->GetLoadDescription());
}
if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) && used_size > 0) SlErrorCorrupt("Corrupted link graph");
}
/* Build edge list from edge matrix. */
for (NodeID to = edges[_linkgraph_from].dest_node; to != INVALID_NODE; to = edges[to].dest_node) {
bn->edges.push_back(edges[to]);
bn->edges.back().dest_node = to;
}
/* Sort by destination. */
std::sort(bn->edges.begin(), bn->edges.end());
} else {
/* Edge data is now a simple vector and not any kind of matrix. */
size_t size = SlGetStructListLength(UINT16_MAX);
for (size_t i = 0; i < size; i++) {
bn->edges.emplace_back();
SlObject(&bn->edges.back(), this->GetLoadDescription());
}
return;
}
size_t used_size = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? max_size : SlGetStructListLength(UINT16_MAX);
/* ... but as that wasted a lot of space we save a sparse matrix now. */
for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) {
if (used_size == 0) SlErrorCorrupt("Link graph structure overflow");
used_size--;
if (to >= max_size) SlErrorCorrupt("Link graph structure overflow");
SlObject(&_linkgraph->edges[_linkgraph_from][to], this->GetLoadDescription());
}
if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) && used_size > 0) SlErrorCorrupt("Corrupted link graph");
}
};
@@ -107,7 +120,7 @@ public:
{
_linkgraph = lg;
uint16 length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _num_nodes : (uint16)SlGetStructListLength(UINT16_MAX);
uint16_t length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _num_nodes : (uint16_t)SlGetStructListLength(UINT16_MAX);
lg->Init(length);
for (NodeID from = 0; from < length; ++from) {
_linkgraph_from = from;
@@ -184,7 +197,7 @@ SaveLoadTable GetLinkGraphJobDesc()
static SaveLoadAddrProc * const proc = [](void *b, size_t extra) -> void * { return const_cast<void *>(static_cast<const void *>(reinterpret_cast<const char *>(std::addressof(static_cast<LinkGraphJob *>(b)->settings)) + extra)); };
/* Build the SaveLoad array on first call and don't touch it later on */
if (saveloads.size() == 0) {
if (saveloads.empty()) {
GetSaveLoadFromSettingTable(_linkgraph_settings, saveloads);
for (auto &sl : saveloads) {
@@ -221,7 +234,7 @@ void AfterLoadLinkGraphs()
if (IsSavegameVersionBefore(SLV_191)) {
for (LinkGraph *lg : LinkGraph::Iterate()) {
for (NodeID node_id = 0; node_id < lg->Size(); ++node_id) {
const Station *st = Station::GetIfValid((*lg)[node_id].Station());
const Station *st = Station::GetIfValid((*lg)[node_id].station);
if (st != nullptr) (*lg)[node_id].UpdateLocation(st->xy);
}
}
@@ -229,7 +242,7 @@ void AfterLoadLinkGraphs()
for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) {
LinkGraph *lg = &(const_cast<LinkGraph &>(lgj->Graph()));
for (NodeID node_id = 0; node_id < lg->Size(); ++node_id) {
const Station *st = Station::GetIfValid((*lg)[node_id].Station());
const Station *st = Station::GetIfValid((*lg)[node_id].station);
if (st != nullptr) (*lg)[node_id].UpdateLocation(st->xy);
}
}

View File

@@ -15,12 +15,11 @@
#include "../map_func.h"
#include "../core/bitmath_func.hpp"
#include "../fios.h"
#include <array>
#include "../safeguards.h"
static uint32 _map_dim_x;
static uint32 _map_dim_y;
static uint32_t _map_dim_x;
static uint32_t _map_dim_y;
static const SaveLoad _map_desc[] = {
SLEG_CONDVAR("dim_x", _map_dim_x, SLE_UINT32, SLV_6, SL_MAX_VERSION),
@@ -34,8 +33,8 @@ struct MAPSChunkHandler : ChunkHandler {
{
SlTableHeader(_map_desc);
_map_dim_x = MapSizeX();
_map_dim_y = MapSizeY();
_map_dim_x = Map::SizeX();
_map_dim_y = Map::SizeY();
SlSetArrayIndex(0);
SlGlobList(_map_desc);
@@ -49,7 +48,7 @@ struct MAPSChunkHandler : ChunkHandler {
SlGlobList(slt);
if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many MAPS entries");
AllocateMap(_map_dim_x, _map_dim_y);
Map::Allocate(_map_dim_x, _map_dim_y);
}
void LoadCheck(size_t) const override
@@ -73,22 +72,22 @@ struct MAPTChunkHandler : ChunkHandler {
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].type = buf[j];
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) Tile(i++).type() = buf[j];
}
}
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].type;
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = Tile(i++).type();
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
}
@@ -100,22 +99,22 @@ struct MAPHChunkHandler : ChunkHandler {
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].height = buf[j];
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) Tile(i++).height() = buf[j];
}
}
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].height;
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = Tile(i++).height();
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
}
@@ -127,22 +126,22 @@ struct MAPOChunkHandler : ChunkHandler {
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m1 = buf[j];
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) Tile(i++).m1() = buf[j];
}
}
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m1;
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = Tile(i++).m1();
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
}
@@ -153,26 +152,26 @@ struct MAP2ChunkHandler : ChunkHandler {
void Load() const override
{
std::array<uint16, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
std::array<uint16_t, MAP_SL_BUF_SIZE> buf;
uint size = Map::Size();
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE,
/* In those versions the m2 was 8 bits */
IsSavegameVersionBefore(SLV_5) ? SLE_FILE_U8 | SLE_VAR_U16 : SLE_UINT16
);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m2 = buf[j];
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) Tile(i++).m2() = buf[j];
}
}
void Save() const override
{
std::array<uint16, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
std::array<uint16_t, MAP_SL_BUF_SIZE> buf;
uint size = Map::Size();
SlSetLength(size * sizeof(uint16));
SlSetLength(static_cast<uint32_t>(size) * sizeof(uint16_t));
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m2;
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = Tile(i++).m2();
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16);
}
}
@@ -184,22 +183,22 @@ struct M3LOChunkHandler : ChunkHandler {
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m3 = buf[j];
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) Tile(i++).m3() = buf[j];
}
}
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m3;
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = Tile(i++).m3();
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
}
@@ -211,22 +210,22 @@ struct M3HIChunkHandler : ChunkHandler {
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m4 = buf[j];
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) Tile(i++).m4() = buf[j];
}
}
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m4;
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = Tile(i++).m4();
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
}
@@ -238,22 +237,22 @@ struct MAP5ChunkHandler : ChunkHandler {
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m5 = buf[j];
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) Tile(i++).m5() = buf[j];
}
}
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m5;
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = Tile(i++).m5();
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
}
@@ -265,23 +264,23 @@ struct MAPEChunkHandler : ChunkHandler {
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
if (IsSavegameVersionBefore(SLV_42)) {
for (TileIndex i = 0; i != size;) {
/* 1024, otherwise we overflow on 64x64 maps! */
SlCopy(buf.data(), 1024, SLE_UINT8);
for (uint j = 0; j != 1024; j++) {
_me[i++].m6 = GB(buf[j], 0, 2);
_me[i++].m6 = GB(buf[j], 2, 2);
_me[i++].m6 = GB(buf[j], 4, 2);
_me[i++].m6 = GB(buf[j], 6, 2);
Tile(i++).m6() = GB(buf[j], 0, 2);
Tile(i++).m6() = GB(buf[j], 2, 2);
Tile(i++).m6() = GB(buf[j], 4, 2);
Tile(i++).m6() = GB(buf[j], 6, 2);
}
}
} else {
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m6 = buf[j];
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) Tile(i++).m6() = buf[j];
}
}
}
@@ -289,11 +288,11 @@ struct MAPEChunkHandler : ChunkHandler {
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m6;
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = Tile(i++).m6();
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
}
@@ -305,22 +304,22 @@ struct MAP7ChunkHandler : ChunkHandler {
void Load() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m7 = buf[j];
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) Tile(i++).m7() = buf[j];
}
}
void Save() const override
{
std::array<byte, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
uint size = Map::Size();
SlSetLength(size);
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m7;
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = Tile(i++).m7();
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8);
}
}
@@ -331,23 +330,23 @@ struct MAP8ChunkHandler : ChunkHandler {
void Load() const override
{
std::array<uint16, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
std::array<uint16_t, MAP_SL_BUF_SIZE> buf;
uint size = Map::Size();
for (TileIndex i = 0; i != size;) {
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16);
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m8 = buf[j];
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) Tile(i++).m8() = buf[j];
}
}
void Save() const override
{
std::array<uint16, MAP_SL_BUF_SIZE> buf;
TileIndex size = MapSize();
std::array<uint16_t, MAP_SL_BUF_SIZE> buf;
uint size = Map::Size();
SlSetLength(size * sizeof(uint16));
SlSetLength(static_cast<uint32_t>(size) * sizeof(uint16_t));
for (TileIndex i = 0; i != size;) {
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m8;
for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = Tile(i++).m8();
SlCopy(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16);
}
}

View File

@@ -12,7 +12,8 @@
#include "saveload.h"
#include "compat/misc_sl_compat.h"
#include "../date_func.h"
#include "../timer/timer_game_calendar.h"
#include "../timer/timer_game_economy.h"
#include "../zoom_func.h"
#include "../window_gui.h"
#include "../window_func.h"
@@ -20,12 +21,15 @@
#include "../gfx_func.h"
#include "../core/random_func.hpp"
#include "../fios.h"
#include "../timer/timer.h"
#include "../timer/timer_game_tick.h"
#include "../safeguards.h"
extern TileIndex _cur_tileloop_tile;
extern uint16 _disaster_delay;
extern uint16_t _disaster_delay;
extern byte _trees_tick_ctr;
extern std::string _savegame_id;
/* Keep track of current game position */
int _saved_scrollpos_x;
@@ -34,9 +38,14 @@ ZoomLevel _saved_scrollpos_zoom;
void SaveViewportBeforeSaveGame()
{
/* Don't use GetMainWindow() in case the window does not exist. */
const Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
if (w != nullptr) {
if (w == nullptr || w->viewport == nullptr) {
/* Ensure saved position is clearly invalid. */
_saved_scrollpos_x = INT_MAX;
_saved_scrollpos_y = INT_MAX;
_saved_scrollpos_zoom = ZOOM_LVL_END;
} else {
_saved_scrollpos_x = w->viewport->scrollpos_x;
_saved_scrollpos_y = w->viewport->scrollpos_y;
_saved_scrollpos_zoom = w->viewport->zoom;
@@ -45,7 +54,7 @@ void SaveViewportBeforeSaveGame()
void ResetViewportAfterLoadGame()
{
Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
Window *w = GetMainWindow();
w->viewport->scrollpos_x = _saved_scrollpos_x;
w->viewport->scrollpos_y = _saved_scrollpos_y;
@@ -69,13 +78,17 @@ void ResetViewportAfterLoadGame()
}
byte _age_cargo_skip_counter; ///< Skip aging of cargo? Used before savegame version 162.
extern TimeoutTimer<TimerGameTick> _new_competitor_timeout;
static const SaveLoad _date_desc[] = {
SLEG_CONDVAR("date", _date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
SLEG_CONDVAR("date", _date, SLE_INT32, SLV_31, SL_MAX_VERSION),
SLEG_VAR("date_fract", _date_fract, SLE_UINT16),
SLEG_CONDVAR("tick_counter", _tick_counter, SLE_FILE_U16 | SLE_VAR_U64, SL_MIN_VERSION, SLV_U64_TICK_COUNTER),
SLEG_CONDVAR("tick_counter", _tick_counter, SLE_UINT64, SLV_U64_TICK_COUNTER, SL_MAX_VERSION),
SLEG_CONDVAR("date", TimerGameCalendar::date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
SLEG_CONDVAR("date", TimerGameCalendar::date, SLE_INT32, SLV_31, SL_MAX_VERSION),
SLEG_VAR("date_fract", TimerGameCalendar::date_fract, SLE_UINT16),
SLEG_CONDVAR("tick_counter", TimerGameTick::counter, SLE_FILE_U16 | SLE_VAR_U64, SL_MIN_VERSION, SLV_U64_TICK_COUNTER),
SLEG_CONDVAR("tick_counter", TimerGameTick::counter, SLE_UINT64, SLV_U64_TICK_COUNTER, SL_MAX_VERSION),
SLEG_CONDVAR("economy_date", TimerGameEconomy::date, SLE_INT32, SLV_ECONOMY_DATE, SL_MAX_VERSION),
SLEG_CONDVAR("economy_date_fract", TimerGameEconomy::date_fract, SLE_UINT16, SLV_ECONOMY_DATE, SL_MAX_VERSION),
SLEG_CONDVAR("calendar_sub_date_fract", TimerGameCalendar::sub_date_fract, SLE_UINT16, SLV_CALENDAR_SUB_DATE_FRACT, SL_MAX_VERSION),
SLEG_CONDVAR("age_cargo_skip_counter", _age_cargo_skip_counter, SLE_UINT8, SL_MIN_VERSION, SLV_162),
SLEG_CONDVAR("cur_tileloop_tile", _cur_tileloop_tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
SLEG_CONDVAR("cur_tileloop_tile", _cur_tileloop_tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
@@ -83,10 +96,15 @@ static const SaveLoad _date_desc[] = {
SLEG_VAR("random_state[0]", _random.state[0], SLE_UINT32),
SLEG_VAR("random_state[1]", _random.state[1], SLE_UINT32),
SLEG_VAR("company_tick_counter", _cur_company_tick_index, SLE_FILE_U8 | SLE_VAR_U32),
SLEG_CONDVAR("next_competitor_start", _next_competitor_start, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_109),
SLEG_CONDVAR("next_competitor_start", _next_competitor_start, SLE_UINT32, SLV_109, SL_MAX_VERSION),
SLEG_VAR("trees_tick_counter", _trees_tick_ctr, SLE_UINT8),
SLEG_CONDVAR("pause_mode", _pause_mode, SLE_UINT8, SLV_4, SL_MAX_VERSION),
SLEG_CONDSSTR("id", _savegame_id, SLE_STR, SLV_SAVEGAME_ID, SL_MAX_VERSION),
/* For older savegames, we load the current value as the "period"; afterload will set the "fired" and "elapsed". */
SLEG_CONDVAR("next_competitor_start", _new_competitor_timeout.period, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_109),
SLEG_CONDVAR("next_competitor_start", _new_competitor_timeout.period, SLE_UINT32, SLV_109, SLV_AI_START_DATE),
SLEG_CONDVAR("competitors_interval", _new_competitor_timeout.period, SLE_UINT32, SLV_AI_START_DATE, SL_MAX_VERSION),
SLEG_CONDVAR("competitors_interval_elapsed", _new_competitor_timeout.storage.elapsed, SLE_UINT32, SLV_AI_START_DATE, SL_MAX_VERSION),
SLEG_CONDVAR("competitors_interval_fired", _new_competitor_timeout.fired, SLE_BOOL, SLV_AI_START_DATE, SL_MAX_VERSION),
};
static const SaveLoad _date_check_desc[] = {
@@ -127,7 +145,7 @@ struct DATEChunkHandler : ChunkHandler {
this->LoadCommon(_date_check_desc, _date_check_sl_compat);
if (IsSavegameVersionBefore(SLV_31)) {
_load_check_data.current_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
_load_check_data.current_date += CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
}
}
};

View File

@@ -20,8 +20,10 @@
/** Save and load the mapping between a spec and the NewGRF it came from. */
static const SaveLoad _newgrf_mapping_desc[] = {
SLE_VAR(EntityIDMapping, grfid, SLE_UINT32),
SLE_VAR(EntityIDMapping, entity_id, SLE_UINT8),
SLE_VAR(EntityIDMapping, substitute_id, SLE_UINT8),
SLE_CONDVAR(EntityIDMapping, entity_id, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_EXTEND_ENTITY_MAPPING),
SLE_CONDVAR(EntityIDMapping, entity_id, SLE_UINT16, SLV_EXTEND_ENTITY_MAPPING, SL_MAX_VERSION),
SLE_CONDVAR(EntityIDMapping, substitute_id, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_EXTEND_ENTITY_MAPPING),
SLE_CONDVAR(EntityIDMapping, substitute_id, SLE_UINT16, SLV_EXTEND_ENTITY_MAPPING, SL_MAX_VERSION),
};
/**
@@ -32,10 +34,10 @@ void NewGRFMappingChunkHandler::Save() const
SlTableHeader(_newgrf_mapping_desc);
for (uint i = 0; i < this->mapping.GetMaxMapping(); i++) {
if (this->mapping.mapping_ID[i].grfid == 0 &&
this->mapping.mapping_ID[i].entity_id == 0) continue;
if (this->mapping.mappings[i].grfid == 0 &&
this->mapping.mappings[i].entity_id == 0) continue;
SlSetArrayIndex(i);
SlObject(&this->mapping.mapping_ID[i], _newgrf_mapping_desc);
SlObject(&this->mapping.mappings[i], _newgrf_mapping_desc);
}
}
@@ -55,13 +57,13 @@ void NewGRFMappingChunkHandler::Load() const
int index;
while ((index = SlIterateArray()) != -1) {
if ((uint)index >= max_id) SlErrorCorrupt("Too many NewGRF entity mappings");
SlObject(&this->mapping.mapping_ID[index], slt);
SlObject(&this->mapping.mappings[index], slt);
}
}
static const SaveLoad _grfconfig_desc[] = {
SLE_STR(GRFConfig, filename, SLE_STR, 0x40),
SLE_SSTR(GRFConfig, filename, SLE_STR),
SLE_VAR(GRFConfig, ident.grfid, SLE_UINT32),
SLE_ARR(GRFConfig, ident.md5sum, SLE_UINT8, 16),
SLE_CONDVAR(GRFConfig, version, SLE_UINT32, SLV_151, SL_MAX_VERSION),

View File

@@ -15,7 +15,7 @@
struct NewGRFMappingChunkHandler : ChunkHandler {
OverrideManagerBase &mapping;
NewGRFMappingChunkHandler(uint32 id, OverrideManagerBase &mapping) : ChunkHandler(id, CH_TABLE), mapping(mapping) {}
NewGRFMappingChunkHandler(uint32_t id, OverrideManagerBase &mapping) : ChunkHandler(id, CH_TABLE), mapping(mapping) {}
void Save() const override;
void Load() const override;
};

View File

@@ -19,14 +19,15 @@
#include "saveload_internal.h"
#include "oldloader.h"
#include <exception>
#include "../safeguards.h"
static const int TTO_HEADER_SIZE = 41;
static const int TTD_HEADER_SIZE = 49;
/** The size of the checksum in the name/header of the TTD/TTO savegames. */
static const int HEADER_CHECKSUM_SIZE = 2;
uint32 _bump_assert_value;
uint32_t _bump_assert_value;
static inline OldChunkType GetOldChunkType(OldChunkType type) {return (OldChunkType)GB(type, 0, 4);}
static inline OldChunkType GetOldChunkVarType(OldChunkType type) {return (OldChunkType)(GB(type, 8, 8) << 8);}
@@ -82,7 +83,7 @@ byte ReadByte(LoadgameState *ls)
if (ls->chunk_size == 0) {
/* Read new chunk */
int8 new_byte = ReadByteFromFile(ls);
int8_t new_byte = ReadByteFromFile(ls);
if (new_byte < 0) {
/* Repeat next char for new_byte times */
@@ -137,15 +138,15 @@ bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks)
default: break;
}
} else {
uint64 res = 0;
uint64_t res = 0;
/* Reading from the file: bits 16 to 23 have the FILE type */
switch (GetOldChunkFileType(chunk->type)) {
case OC_FILE_I8: res = (int8)ReadByte(ls); break;
case OC_FILE_I8: res = (int8_t)ReadByte(ls); break;
case OC_FILE_U8: res = ReadByte(ls); break;
case OC_FILE_I16: res = (int16)ReadUint16(ls); break;
case OC_FILE_I16: res = (int16_t)ReadUint16(ls); break;
case OC_FILE_U16: res = ReadUint16(ls); break;
case OC_FILE_I32: res = (int32)ReadUint32(ls); break;
case OC_FILE_I32: res = (int32_t)ReadUint32(ls); break;
case OC_FILE_U32: res = ReadUint32(ls); break;
default: NOT_REACHED();
}
@@ -158,14 +159,14 @@ bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks)
/* Write the data */
switch (GetOldChunkVarType(chunk->type)) {
case OC_VAR_I8: *(int8 *)ptr = GB(res, 0, 8); break;
case OC_VAR_U8: *(uint8 *)ptr = GB(res, 0, 8); break;
case OC_VAR_I16:*(int16 *)ptr = GB(res, 0, 16); break;
case OC_VAR_U16:*(uint16*)ptr = GB(res, 0, 16); break;
case OC_VAR_I32:*(int32 *)ptr = res; break;
case OC_VAR_U32:*(uint32*)ptr = res; break;
case OC_VAR_I64:*(int64 *)ptr = res; break;
case OC_VAR_U64:*(uint64*)ptr = res; break;
case OC_VAR_I8: *(int8_t *)ptr = GB(res, 0, 8); break;
case OC_VAR_U8: *(uint8_t *)ptr = GB(res, 0, 8); break;
case OC_VAR_I16:*(int16_t *)ptr = GB(res, 0, 16); break;
case OC_VAR_U16:*(uint16_t*)ptr = GB(res, 0, 16); break;
case OC_VAR_I32:*(int32_t *)ptr = res; break;
case OC_VAR_U32:*(uint32_t*)ptr = res; break;
case OC_VAR_I64:*(int64_t *)ptr = res; break;
case OC_VAR_U64:*(uint64_t*)ptr = res; break;
default: NOT_REACHED();
}
@@ -205,66 +206,40 @@ static void InitLoading(LoadgameState *ls)
* @param title title and checksum
* @param len the length of the title to read/checksum
* @return true iff the title is valid
* @note the title (incl. checksum) has to be at least 41/49 (HEADER_SIZE) bytes long!
*/
static bool VerifyOldNameChecksum(char *title, uint len)
{
uint16 sum = 0;
for (uint i = 0; i < len - 2; i++) {
uint16_t sum = 0;
for (uint i = 0; i < len - HEADER_CHECKSUM_SIZE; i++) {
sum += title[i];
sum = ROL(sum, 1);
sum = std::rotl(sum, 1);
}
sum ^= 0xAAAA; // computed checksum
uint16 sum2 = title[len - 2]; // checksum in file
SB(sum2, 8, 8, title[len - 1]);
uint16_t sum2 = title[len - HEADER_CHECKSUM_SIZE]; // checksum in file
SB(sum2, 8, 8, title[len - HEADER_CHECKSUM_SIZE + 1]);
return sum == sum2;
}
static inline bool CheckOldSavegameType(FILE *f, char *temp, const char *last, uint len)
static std::tuple<SavegameType, std::string> DetermineOldSavegameTypeAndName(FILE *f)
{
assert(last - temp + 1 >= (int)len);
if (fread(temp, 1, len, f) != len) {
temp[0] = '\0'; // if reading failed, make the name empty
return false;
}
bool ret = VerifyOldNameChecksum(temp, len);
temp[len - 2] = '\0'; // name is null-terminated in savegame, but it's better to be sure
StrMakeValidInPlace(temp, last);
return ret;
}
static SavegameType DetermineOldSavegameType(FILE *f, char *title, const char *last)
{
static_assert(TTD_HEADER_SIZE >= TTO_HEADER_SIZE);
char temp[TTD_HEADER_SIZE] = "Unknown";
SavegameType type = SGT_TTO;
/* Can't fseek to 0 as in tar files that is not correct */
long pos = ftell(f);
if (pos >= 0 && !CheckOldSavegameType(f, temp, lastof(temp), TTO_HEADER_SIZE)) {
type = SGT_TTD;
if (fseek(f, pos, SEEK_SET) < 0 || !CheckOldSavegameType(f, temp, lastof(temp), TTD_HEADER_SIZE)) {
type = SGT_INVALID;
}
char buffer[std::max(TTO_HEADER_SIZE, TTD_HEADER_SIZE)];
if (pos < 0 || fread(buffer, 1, lengthof(buffer), f) != lengthof(buffer)) {
return { SGT_INVALID, "(broken) Unable to read file" };
}
if (title != nullptr) {
switch (type) {
case SGT_TTO: title = strecpy(title, "(TTO) ", last); break;
case SGT_TTD: title = strecpy(title, "(TTD) ", last); break;
default: title = strecpy(title, "(broken) ", last); break;
}
strecpy(title, temp, last);
if (VerifyOldNameChecksum(buffer, TTO_HEADER_SIZE) && fseek(f, pos + TTO_HEADER_SIZE, SEEK_SET) == 0) {
return { SGT_TTO, "(TTO)" + StrMakeValid({buffer, TTO_HEADER_SIZE - HEADER_CHECKSUM_SIZE}) };
}
return type;
if (VerifyOldNameChecksum(buffer, TTD_HEADER_SIZE) && fseek(f, pos + TTD_HEADER_SIZE, SEEK_SET) == 0) {
return { SGT_TTD, "(TTD)" + StrMakeValid({buffer, TTD_HEADER_SIZE - HEADER_CHECKSUM_SIZE}) };
}
return { SGT_INVALID, "(broken) Unknown" };
}
typedef bool LoadOldMainProc(LoadgameState *ls);
@@ -285,14 +260,17 @@ bool LoadOldSaveGame(const std::string &file)
return false;
}
SavegameType type = DetermineOldSavegameType(ls.file, nullptr, nullptr);
SavegameType type;
std::tie(type, std::ignore) = DetermineOldSavegameTypeAndName(ls.file);
LoadOldMainProc *proc = nullptr;
switch (type) {
case SGT_TTO: proc = &LoadTTOMain; break;
case SGT_TTD: proc = &LoadTTDMain; break;
default: break;
default:
Debug(oldloader, 0, "Unknown savegame type; cannot be loaded");
break;
}
_savegame_type = type;
@@ -315,16 +293,13 @@ bool LoadOldSaveGame(const std::string &file)
return true;
}
void GetOldSaveGameName(const std::string &file, char *title, const char *last)
std::string GetOldSaveGameName(const std::string &file)
{
FILE *f = FioFOpenFile(file, "rb", NO_DIRECTORY);
if (f == nullptr) return {};
if (f == nullptr) {
*title = '\0';
return;
}
DetermineOldSavegameType(f, title, last);
std::string name;
std::tie(std::ignore, name) = DetermineOldSavegameTypeAndName(f);
fclose(f);
return name;
}

View File

@@ -14,7 +14,7 @@
#include "../tile_type.h"
static const uint BUFFER_SIZE = 4096;
static const uint OLD_MAP_SIZE = 256 * 256;
static const uint OLD_MAP_SIZE = 256;
struct LoadgameState {
FILE *file;
@@ -86,16 +86,13 @@ typedef void *OffsetProc(void *base);
struct OldChunks {
OldChunkType type; ///< Type of field
uint32 amount; ///< Amount of fields
uint32_t amount; ///< Amount of fields
void *ptr; ///< Pointer where to save the data (takes precedence over #offset)
OffsetProc *offset; ///< Pointer to function that returns the actual memory address of a member (ignored if #ptr is not nullptr)
OldChunkProc *proc; ///< Pointer to function that is called with OC_CHUNK
};
/* If it fails, check lines above.. */
static_assert(sizeof(TileIndex) == 4);
extern uint _bump_assert_value;
byte ReadByte(LoadgameState *ls);
bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks);
@@ -103,15 +100,15 @@ bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks);
bool LoadTTDMain(LoadgameState *ls);
bool LoadTTOMain(LoadgameState *ls);
static inline uint16 ReadUint16(LoadgameState *ls)
inline uint16_t ReadUint16(LoadgameState *ls)
{
byte x = ReadByte(ls);
return x | ReadByte(ls) << 8;
}
static inline uint32 ReadUint32(LoadgameState *ls)
inline uint32_t ReadUint32(LoadgameState *ls)
{
uint16 x = ReadUint16(ls);
uint16_t x = ReadUint16(ls);
return x | ReadUint16(ls) << 16;
}

View File

@@ -20,16 +20,18 @@
#include "../subsidy_base.h"
#include "../debug.h"
#include "../depot_base.h"
#include "../date_func.h"
#include "../timer/timer_game_calendar.h"
#include "../timer/timer_game_calendar.h"
#include "../vehicle_func.h"
#include "../effectvehicle_base.h"
#include "../engine_func.h"
#include "../company_base.h"
#include "../disaster_vehicle.h"
#include "../core/smallvec_type.hpp"
#include "../timer/timer.h"
#include "../timer/timer_game_tick.h"
#include "../timer/timer_game_calendar.h"
#include "saveload_internal.h"
#include "oldloader.h"
#include <array>
#include "table/strings.h"
#include "../table/engines.h"
@@ -38,64 +40,54 @@
#include "../safeguards.h"
static bool _read_ttdpatch_flags; ///< Have we (tried to) read TTDPatch extra flags?
static uint16 _old_extra_chunk_nums; ///< Number of extra TTDPatch chunks
static uint16_t _old_extra_chunk_nums; ///< Number of extra TTDPatch chunks
static byte _old_vehicle_multiplier; ///< TTDPatch vehicle multiplier
static uint8 *_old_map3;
void FixOldMapArray()
{
/* TTO/TTD/TTDP savegames could have buoys at tile 0
* (without assigned station struct) */
MemSetT(&_m[0], 0);
SetTileType(0, MP_WATER);
SetTileOwner(0, OWNER_WATER);
MakeSea(0);
}
static void FixTTDMapArray()
{
/* _old_map3 is moved to _m::m3 and _m::m4 */
for (TileIndex t = 0; t < OLD_MAP_SIZE; t++) {
_m[t].m3 = _old_map3[t * 2];
_m[t].m4 = _old_map3[t * 2 + 1];
}
for (TileIndex t = 0; t < OLD_MAP_SIZE; t++) {
switch (GetTileType(t)) {
for (auto tile : Map::Iterate()) {
switch (GetTileType(tile)) {
case MP_STATION:
_m[t].m4 = 0; // We do not understand this TTDP station mapping (yet)
switch (_m[t].m5) {
tile.m4() = 0; // We do not understand this TTDP station mapping (yet)
switch (tile.m5()) {
/* We have drive through stops at a totally different place */
case 0x53: case 0x54: _m[t].m5 += 170 - 0x53; break; // Bus drive through
case 0x57: case 0x58: _m[t].m5 += 168 - 0x57; break; // Truck drive through
case 0x55: case 0x56: _m[t].m5 += 170 - 0x55; break; // Bus tram stop
case 0x59: case 0x5A: _m[t].m5 += 168 - 0x59; break; // Truck tram stop
case 0x53: case 0x54: tile.m5() += 170 - 0x53; break; // Bus drive through
case 0x57: case 0x58: tile.m5() += 168 - 0x57; break; // Truck drive through
case 0x55: case 0x56: tile.m5() += 170 - 0x55; break; // Bus tram stop
case 0x59: case 0x5A: tile.m5() += 168 - 0x59; break; // Truck tram stop
default: break;
}
break;
case MP_RAILWAY:
/* We save presignals different from TTDPatch, convert them */
if (GB(_m[t].m5, 6, 2) == 1) { // RAIL_TILE_SIGNALS
if (GB(tile.m5(), 6, 2) == 1) { // RAIL_TILE_SIGNALS
/* This byte is always zero in TTD for this type of tile */
if (_m[t].m4) { // Convert the presignals to our own format
_m[t].m4 = (_m[t].m4 >> 1) & 7;
if (tile.m4()) { // Convert the presignals to our own format
tile.m4() = (tile.m4() >> 1) & 7;
}
}
/* TTDPatch stores PBS things in L6 and all elsewhere; so we'll just
* clear it for ourselves and let OTTD's rebuild PBS itself */
_m[t].m4 &= 0xF; // Only keep the lower four bits; upper four is PBS
tile.m4() &= 0xF; // Only keep the lower four bits; upper four is PBS
break;
case MP_WATER:
/* if water class == 3, make river there */
if (GB(_m[t].m3, 0, 2) == 3) {
SetTileType(t, MP_WATER);
SetTileOwner(t, OWNER_WATER);
_m[t].m2 = 0;
_m[t].m3 = 2; // WATER_CLASS_RIVER
_m[t].m4 = Random();
_m[t].m5 = 0;
if (GB(tile.m3(), 0, 2) == 3) {
SetTileType(tile, MP_WATER);
SetTileOwner(tile, OWNER_WATER);
tile.m2() = 0;
tile.m3() = 2; // WATER_CLASS_RIVER
tile.m4() = Random();
tile.m5() = 0;
}
break;
@@ -119,7 +111,7 @@ static void FixTTDDepots()
#define FIXNUM(x, y, z) (((((x) << 16) / (y)) + 1) << z)
static uint32 RemapOldTownName(uint32 townnameparts, byte old_town_name_type)
static uint32_t RemapOldTownName(uint32_t townnameparts, byte old_town_name_type)
{
switch (old_town_name_type) {
case 0: case 3: // English, American
@@ -194,7 +186,8 @@ void FixOldVehicles()
RoadVehicle *rv = RoadVehicle::From(v);
if (rv->state != RVSB_IN_DEPOT && rv->state != RVSB_WORMHOLE) {
ClrBit(rv->state, 2);
if (IsTileType(rv->tile, MP_STATION) && _m[rv->tile].m5 >= 168) {
Tile tile(rv->tile);
if (IsTileType(tile, MP_STATION) && tile.m5() >= 168) {
/* Update the vehicle's road state to show we're in a drive through road stop. */
SetBit(rv->state, RVS_IN_DT_ROAD_STOP);
}
@@ -219,14 +212,14 @@ void FixOldVehicles()
static bool FixTTOMapArray()
{
for (TileIndex t = 0; t < OLD_MAP_SIZE; t++) {
TileType tt = GetTileType(t);
for (auto tile : Map::Iterate()) {
TileType tt = GetTileType(tile);
if (tt == 11) {
/* TTO has a different way of storing monorail.
* Instead of using bits in m3 it uses a different tile type. */
_m[t].m3 = 1; // rail type = monorail (in TTD)
SetTileType(t, MP_RAILWAY);
_m[t].m2 = 1; // set monorail ground to RAIL_GROUND_GRASS
tile.m3() = 1; // rail type = monorail (in TTD)
SetTileType(tile, MP_RAILWAY);
tile.m2() = 1; // set monorail ground to RAIL_GROUND_GRASS
tt = MP_RAILWAY;
}
@@ -235,18 +228,18 @@ static bool FixTTOMapArray()
break;
case MP_RAILWAY:
switch (GB(_m[t].m5, 6, 2)) {
switch (GB(tile.m5(), 6, 2)) {
case 0: // RAIL_TILE_NORMAL
break;
case 1: // RAIL_TILE_SIGNALS
_m[t].m4 = (~_m[t].m5 & 1) << 2; // signal variant (present only in OTTD)
SB(_m[t].m2, 6, 2, GB(_m[t].m5, 3, 2)); // signal status
_m[t].m3 |= 0xC0; // both signals are present
_m[t].m5 = HasBit(_m[t].m5, 5) ? 2 : 1; // track direction (only X or Y)
_m[t].m5 |= 0x40; // RAIL_TILE_SIGNALS
tile.m4() = (~tile.m5() & 1) << 2; // signal variant (present only in OTTD)
SB(tile.m2(), 6, 2, GB(tile.m5(), 3, 2)); // signal status
tile.m3() |= 0xC0; // both signals are present
tile.m5() = HasBit(tile.m5(), 5) ? 2 : 1; // track direction (only X or Y)
tile.m5() |= 0x40; // RAIL_TILE_SIGNALS
break;
case 3: // RAIL_TILE_DEPOT
_m[t].m2 = 0;
tile.m2() = 0;
break;
default:
return false;
@@ -254,12 +247,12 @@ static bool FixTTOMapArray()
break;
case MP_ROAD: // road (depot) or level crossing
switch (GB(_m[t].m5, 4, 4)) {
switch (GB(tile.m5(), 4, 4)) {
case 0: // ROAD_TILE_NORMAL
if (_m[t].m2 == 4) _m[t].m2 = 5; // 'small trees' -> ROADSIDE_TREES
if (tile.m2() == 4) tile.m2() = 5; // 'small trees' -> ROADSIDE_TREES
break;
case 1: // ROAD_TILE_CROSSING (there aren't monorail crossings in TTO)
_m[t].m3 = _m[t].m1; // set owner of road = owner of rail
tile.m3() = tile.m1(); // set owner of road = owner of rail
break;
case 2: // ROAD_TILE_DEPOT
break;
@@ -269,69 +262,69 @@ static bool FixTTOMapArray()
break;
case MP_HOUSE:
_m[t].m3 = _m[t].m2 & 0xC0; // construction stage
_m[t].m2 &= 0x3F; // building type
if (_m[t].m2 >= 5) _m[t].m2++; // skip "large office block on snow"
tile.m3() = tile.m2() & 0xC0; // construction stage
tile.m2() &= 0x3F; // building type
if (tile.m2() >= 5) tile.m2()++; // skip "large office block on snow"
break;
case MP_TREES:
_m[t].m3 = GB(_m[t].m5, 3, 3); // type of trees
_m[t].m5 &= 0xC7; // number of trees and growth status
tile.m3() = GB(tile.m5(), 3, 3); // type of trees
tile.m5() &= 0xC7; // number of trees and growth status
break;
case MP_STATION:
_m[t].m3 = (_m[t].m5 >= 0x08 && _m[t].m5 <= 0x0F) ? 1 : 0; // monorail -> 1, others 0 (rail, road, airport, dock)
if (_m[t].m5 >= 8) _m[t].m5 -= 8; // shift for monorail
if (_m[t].m5 >= 0x42) _m[t].m5++; // skip heliport
tile.m3() = (tile.m5() >= 0x08 && tile.m5() <= 0x0F) ? 1 : 0; // monorail -> 1, others 0 (rail, road, airport, dock)
if (tile.m5() >= 8) tile.m5() -= 8; // shift for monorail
if (tile.m5() >= 0x42) tile.m5()++; // skip heliport
break;
case MP_WATER:
_m[t].m3 = _m[t].m2 = 0;
tile.m3() = tile.m2() = 0;
break;
case MP_VOID:
_m[t].m2 = _m[t].m3 = _m[t].m5 = 0;
tile.m2() = tile.m3() = tile.m5() = 0;
break;
case MP_INDUSTRY:
_m[t].m3 = 0;
switch (_m[t].m5) {
tile.m3() = 0;
switch (tile.m5()) {
case 0x24: // farm silo
_m[t].m5 = 0x25;
tile.m5() = 0x25;
break;
case 0x25: case 0x27: // farm
case 0x28: case 0x29: case 0x2A: case 0x2B: // factory
_m[t].m5--;
tile.m5()--;
break;
default:
if (_m[t].m5 >= 0x2C) _m[t].m5 += 3; // iron ore mine, steel mill or bank
if (tile.m5() >= 0x2C) tile.m5() += 3; // iron ore mine, steel mill or bank
break;
}
break;
case MP_TUNNELBRIDGE:
if (HasBit(_m[t].m5, 7)) { // bridge
byte m5 = _m[t].m5;
_m[t].m5 = m5 & 0xE1; // copy bits 7..5, 1
if (GB(m5, 1, 2) == 1) _m[t].m5 |= 0x02; // road bridge
if (GB(m5, 1, 2) == 3) _m[t].m2 |= 0xA0; // monorail bridge -> tubular, steel bridge
if (HasBit(tile.m5(), 7)) { // bridge
byte m5 = tile.m5();
tile.m5() = m5 & 0xE1; // copy bits 7..5, 1
if (GB(m5, 1, 2) == 1) tile.m5() |= 0x02; // road bridge
if (GB(m5, 1, 2) == 3) tile.m2() |= 0xA0; // monorail bridge -> tubular, steel bridge
if (!HasBit(m5, 6)) { // bridge head
_m[t].m3 = (GB(m5, 1, 2) == 3) ? 1 : 0; // track subtype (1 for monorail, 0 for others)
tile.m3() = (GB(m5, 1, 2) == 3) ? 1 : 0; // track subtype (1 for monorail, 0 for others)
} else { // middle bridge part
_m[t].m3 = HasBit(m5, 2) ? 0x10 : 0; // track subtype on bridge
if (GB(m5, 3, 2) == 3) _m[t].m3 |= 1; // track subtype under bridge
if (GB(m5, 3, 2) == 1) _m[t].m5 |= 0x08; // set for road/water under (0 for rail/clear)
tile.m3() = HasBit(m5, 2) ? 0x10 : 0; // track subtype on bridge
if (GB(m5, 3, 2) == 3) tile.m3() |= 1; // track subtype under bridge
if (GB(m5, 3, 2) == 1) tile.m5() |= 0x08; // set for road/water under (0 for rail/clear)
}
} else { // tunnel entrance/exit
_m[t].m2 = 0;
_m[t].m3 = HasBit(_m[t].m5, 3); // monorail
_m[t].m5 &= HasBit(_m[t].m5, 3) ? 0x03 : 0x07 ; // direction, transport type (== 0 for rail)
tile.m2() = 0;
tile.m3() = HasBit(tile.m5(), 3); // monorail
tile.m5() &= HasBit(tile.m5(), 3) ? 0x03 : 0x07 ; // direction, transport type (== 0 for rail)
}
break;
case MP_OBJECT:
_m[t].m2 = 0;
_m[t].m3 = 0;
tile.m2() = 0;
tile.m3() = 0;
break;
default:
@@ -386,13 +379,16 @@ static bool FixTTOEngines()
}
/* Load the default engine set. Many of them will be overridden later */
uint j = 0;
for (uint i = 0; i < lengthof(_orig_rail_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_TRAIN, i);
for (uint i = 0; i < lengthof(_orig_road_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_ROAD, i);
for (uint i = 0; i < lengthof(_orig_ship_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_SHIP, i);
for (uint i = 0; i < lengthof(_orig_aircraft_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_AIRCRAFT, i);
{
uint j = 0;
for (uint i = 0; i < lengthof(_orig_rail_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_TRAIN, i);
for (uint i = 0; i < lengthof(_orig_road_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_ROAD, i);
for (uint i = 0; i < lengthof(_orig_ship_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_SHIP, i);
for (uint i = 0; i < lengthof(_orig_aircraft_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_AIRCRAFT, i);
}
Date aging_date = std::min(_date + DAYS_TILL_ORIGINAL_BASE_YEAR, ConvertYMDToDate(2050, 0, 1));
TimerGameCalendar::Date aging_date = std::min(TimerGameCalendar::date + CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR, TimerGameCalendar::ConvertYMDToDate(2050, 0, 1));
TimerGameCalendar::YearMonthDay aging_ymd = TimerGameCalendar::ConvertDateToYMD(aging_date);
for (EngineID i = 0; i < 256; i++) {
int oi = ttd_to_tto[i];
@@ -400,17 +396,17 @@ static bool FixTTOEngines()
if (oi == 255) {
/* Default engine is used */
_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
StartupOneEngine(e, aging_date, 0);
TimerGameCalendar::date += CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
StartupOneEngine(e, aging_ymd, 0);
CalcEngineReliability(e, false);
e->intro_date -= DAYS_TILL_ORIGINAL_BASE_YEAR;
_date -= DAYS_TILL_ORIGINAL_BASE_YEAR;
e->intro_date -= CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
TimerGameCalendar::date -= CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
/* Make sure for example monorail and maglev are available when they should be */
if (_date >= e->intro_date && HasBit(e->info.climates, 0)) {
if (TimerGameCalendar::date >= e->intro_date && HasBit(e->info.climates, 0)) {
e->flags |= ENGINE_AVAILABLE;
e->company_avail = (CompanyMask)0xFF;
e->age = _date > e->intro_date ? (_date - e->intro_date) / 30 : 0;
e->company_avail = MAX_UVALUE(CompanyMask);
e->age = TimerGameCalendar::date > e->intro_date ? (TimerGameCalendar::date - e->intro_date).base() / 30 : 0;
}
} else {
/* Using data from TTO savegame */
@@ -434,7 +430,7 @@ static bool FixTTOEngines()
* if at least one of them was available. */
for (uint j = 0; j < lengthof(tto_to_ttd); j++) {
if (tto_to_ttd[j] == i && _old_engines[j].company_avail != 0) {
e->company_avail = (CompanyMask)0xFF;
e->company_avail = MAX_UVALUE(CompanyMask);
e->flags |= ENGINE_AVAILABLE;
break;
}
@@ -444,7 +440,7 @@ static bool FixTTOEngines()
}
e->preview_company = INVALID_COMPANY;
e->preview_asked = (CompanyMask)-1;
e->preview_asked = MAX_UVALUE(CompanyMask);
e->preview_wait = 0;
e->name = std::string{};
}
@@ -459,10 +455,10 @@ static void FixTTOCompanies()
}
}
static inline byte RemapTTOColour(byte tto)
static inline Colours RemapTTOColour(Colours tto)
{
/** Lossy remapping of TTO colours to TTD colours. SVXConverter uses the same conversion. */
static const byte tto_colour_remap[] = {
static const Colours tto_colour_remap[] = {
COLOUR_DARK_BLUE, COLOUR_GREY, COLOUR_YELLOW, COLOUR_RED,
COLOUR_PURPLE, COLOUR_DARK_GREEN, COLOUR_ORANGE, COLOUR_PALE_GREEN,
COLOUR_BLUE, COLOUR_GREEN, COLOUR_CREAM, COLOUR_BROWN,
@@ -485,11 +481,32 @@ static inline uint RemapOrderIndex(uint x)
}
extern std::vector<TileIndex> _animated_tiles;
extern TimeoutTimer<TimerGameTick> _new_competitor_timeout;
extern char *_old_name_array;
static uint32 _old_town_index;
static uint16 _old_string_id;
static uint16 _old_string_id_2;
static uint32_t _old_town_index;
static uint16_t _old_string_id;
static uint16_t _old_string_id_2;
static void ClearOldMap3(TileIndex t)
{
Tile tile(t);
tile.m3() = 0;
tile.m4() = 0;
}
static Town *RemapTown(TileIndex fallback)
{
/* In some cases depots, industries and stations could refer to a missing town. */
Town *t = Town::GetIfValid(RemapTownIndex(_old_town_index));
if (t == nullptr) {
/* In case the town that was refered to does not exist, find the closest.
* However, this needs the kd-tree to be present. */
RebuildTownKdtree();
t = CalcClosestTownFromTile(fallback);
}
return t;
}
static void ReadTTDPatchFlags()
{
@@ -505,8 +522,8 @@ static void ReadTTDPatchFlags()
if (_savegame_type == SGT_TTO) return;
/* TTDPatch misuses _old_map3 for flags.. read them! */
_old_vehicle_multiplier = _old_map3[0];
/* TTDPatch misuses old map3 (now m3/m4) for flags.. read them! */
_old_vehicle_multiplier = Tile(0).m3();
/* Somehow.... there was an error in some savegames, so 0 becomes 1
* and 1 becomes 2. The rest of the values are okay */
if (_old_vehicle_multiplier < 2) _old_vehicle_multiplier++;
@@ -520,18 +537,26 @@ static void ReadTTDPatchFlags()
* 1 vehicle == 128 bytes */
_bump_assert_value = (_old_vehicle_multiplier - 1) * 850 * 128;
for (uint i = 0; i < 17; i++) { // check tile 0, too
if (_old_map3[i] != 0) _savegame_type = SGT_TTDP1;
/* The first 17 bytes are used by TTDP1, which translates to the first 9 m3s and first 8 m4s. */
for (TileIndex i = 0; i <= 8; i++) { // check tile 0, too
Tile tile(i);
if (tile.m3() != 0 || (i != 8 && tile.m4() != 0)) _savegame_type = SGT_TTDP1;
}
/* Check if we have a modern TTDPatch savegame (has extra data all around) */
if (memcmp(&_old_map3[0x1FFFA], "TTDp", 4) == 0) _savegame_type = SGT_TTDP2;
Tile ttdp2_header_first(Map::Size() - 3);
Tile ttdp2_header_second(Map::Size() - 2);
if (ttdp2_header_first.m3() == 'T' && ttdp2_header_first.m4() == 'T' &&
ttdp2_header_second.m3() == 'D' && ttdp2_header_second.m4() == 'p') {
_savegame_type = SGT_TTDP2;
}
_old_extra_chunk_nums = _old_map3[_savegame_type == SGT_TTDP2 ? 0x1FFFE : 0x2];
Tile extra_chunk_tile = Tile(_savegame_type == SGT_TTDP2 ? Map::Size() - 1 : 1);
_old_extra_chunk_nums = extra_chunk_tile.m3() | extra_chunk_tile.m4() << 8;
/* Clean the misused places */
for (uint i = 0; i < 17; i++) _old_map3[i] = 0;
for (uint i = 0x1FE00; i < 0x20000; i++) _old_map3[i] = 0;
for (TileIndex i = 0; i < 9; i++) ClearOldMap3(i);
for (TileIndex i = TileXY(0, Map::MaxY()); i < Map::Size(); i++) ClearOldMap3(i);
if (_savegame_type == SGT_TTDP2) Debug(oldloader, 2, "Found TTDPatch game");
@@ -576,10 +601,10 @@ static const OldChunks town_chunk[] = {
OCL_NULL( 2 ), ///< pct_pass_transported / pct_mail_transported, now computed on the fly
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_FOOD].new_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_WATER].new_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_FOOD].old_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_WATER].old_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TAE_FOOD].new_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TAE_WATER].new_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TAE_FOOD].old_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TAE_WATER].old_act ),
OCL_SVAR( OC_UINT8, Town, road_build_months ),
OCL_SVAR( OC_UINT8, Town, fund_buildings_months ),
@@ -606,7 +631,7 @@ static bool LoadOldTown(LoadgameState *ls, int num)
return true;
}
static uint16 _old_order;
static uint16_t _old_order;
static const OldChunks order_chunk[] = {
OCL_VAR ( OC_UINT16, 1, &_old_order ),
OCL_END()
@@ -631,7 +656,7 @@ static bool LoadOldOrder(LoadgameState *ls, int num)
return true;
}
static bool LoadOldAnimTileList(LoadgameState *ls, int num)
static bool LoadOldAnimTileList(LoadgameState *ls, int)
{
TileIndex anim_list[256];
const OldChunks anim_chunk[] = {
@@ -662,10 +687,7 @@ static bool LoadOldDepot(LoadgameState *ls, int num)
if (!LoadChunk(ls, d, depot_chunk)) return false;
if (d->xy != 0) {
/* In some cases, there could be depots referencing invalid town. */
Town *t = Town::GetIfValid(RemapTownIndex(_old_town_index));
if (t == nullptr) t = Town::GetRandom();
d->town = t;
d->town = RemapTown(d->xy);
} else {
delete d;
}
@@ -674,16 +696,16 @@ static bool LoadOldDepot(LoadgameState *ls, int num)
}
static StationID _current_station_id;
static uint16 _waiting_acceptance;
static uint8 _cargo_source;
static uint8 _cargo_days;
static uint16_t _waiting_acceptance;
static uint8_t _cargo_source;
static uint8_t _cargo_periods;
static const OldChunks goods_chunk[] = {
OCL_VAR ( OC_UINT16, 1, &_waiting_acceptance ),
OCL_SVAR( OC_UINT8, GoodsEntry, time_since_pickup ),
OCL_SVAR( OC_UINT8, GoodsEntry, rating ),
OCL_VAR ( OC_UINT8, 1, &_cargo_source ),
OCL_VAR ( OC_UINT8, 1, &_cargo_days ),
OCL_VAR ( OC_UINT8, 1, &_cargo_periods ),
OCL_SVAR( OC_UINT8, GoodsEntry, last_speed ),
OCL_SVAR( OC_UINT8, GoodsEntry, last_age ),
@@ -703,7 +725,7 @@ static bool LoadOldGood(LoadgameState *ls, int num)
SB(ge->status, GoodsEntry::GES_ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15));
SB(ge->status, GoodsEntry::GES_RATING, 1, _cargo_source != 0xFF);
if (GB(_waiting_acceptance, 0, 12) != 0 && CargoPacket::CanAllocateItem()) {
ge->cargo.Append(new CargoPacket(GB(_waiting_acceptance, 0, 12), _cargo_days, (_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source, 0, 0),
ge->cargo.Append(new CargoPacket(GB(_waiting_acceptance, 0, 12), _cargo_periods, (_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source, INVALID_TILE, 0),
INVALID_STATION);
}
@@ -755,7 +777,7 @@ static bool LoadOldStation(LoadgameState *ls, int num)
if (!LoadChunk(ls, st, station_chunk)) return false;
if (st->xy != 0) {
st->town = Town::Get(RemapTownIndex(_old_town_index));
st->town = RemapTown(st->xy);
if (_savegame_type == SGT_TTO) {
if (IsInsideBS(_old_string_id, 0x180F, 32)) {
@@ -788,30 +810,29 @@ static const OldChunks industry_chunk[] = {
OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Industry, location.h ),
OCL_NULL( 2 ), ///< used to be industry's produced_cargo
OCL_SVAR( OC_TTD | OC_UINT16, Industry, produced_cargo_waiting[0] ),
OCL_SVAR( OC_TTD | OC_UINT16, Industry, produced_cargo_waiting[1] ),
OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, produced_cargo_waiting[0] ),
OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, produced_cargo_waiting[1] ),
OCL_SVAR( OC_TTD | OC_UINT16, Industry, produced[0].waiting ),
OCL_SVAR( OC_TTD | OC_UINT16, Industry, produced[1].waiting ),
OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, produced[0].waiting ),
OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, produced[1].waiting ),
OCL_SVAR( OC_UINT8, Industry, production_rate[0] ),
OCL_SVAR( OC_UINT8, Industry, production_rate[1] ),
OCL_SVAR( OC_UINT8, Industry, produced[0].rate ),
OCL_SVAR( OC_UINT8, Industry, produced[1].rate ),
OCL_NULL( 3 ), ///< used to be industry's accepts_cargo
OCL_SVAR( OC_UINT8, Industry, prod_level ),
OCL_SVAR( OC_UINT16, Industry, this_month_production[0] ),
OCL_SVAR( OC_UINT16, Industry, this_month_production[1] ),
OCL_SVAR( OC_UINT16, Industry, this_month_transported[0] ),
OCL_SVAR( OC_UINT16, Industry, this_month_transported[1] ),
OCL_SVAR( OC_UINT16, Industry, produced[0].history[THIS_MONTH].production ),
OCL_SVAR( OC_UINT16, Industry, produced[1].history[THIS_MONTH].production ),
OCL_SVAR( OC_UINT16, Industry, produced[0].history[THIS_MONTH].transported ),
OCL_SVAR( OC_UINT16, Industry, produced[1].history[THIS_MONTH].transported ),
OCL_SVAR( OC_UINT8, Industry, last_month_pct_transported[0] ),
OCL_SVAR( OC_UINT8, Industry, last_month_pct_transported[1] ),
OCL_NULL( 2 ), ///< last_month_pct_transported, now computed on the fly
OCL_SVAR( OC_UINT16, Industry, last_month_production[0] ),
OCL_SVAR( OC_UINT16, Industry, last_month_production[1] ),
OCL_SVAR( OC_UINT16, Industry, last_month_transported[0] ),
OCL_SVAR( OC_UINT16, Industry, last_month_transported[1] ),
OCL_SVAR( OC_UINT16, Industry, produced[0].history[LAST_MONTH].production ),
OCL_SVAR( OC_UINT16, Industry, produced[1].history[LAST_MONTH].production ),
OCL_SVAR( OC_UINT16, Industry, produced[0].history[LAST_MONTH].transported ),
OCL_SVAR( OC_UINT16, Industry, produced[1].history[LAST_MONTH].transported ),
OCL_SVAR( OC_UINT8, Industry, type ),
OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, counter ),
@@ -832,14 +853,13 @@ static bool LoadOldIndustry(LoadgameState *ls, int num)
if (!LoadChunk(ls, i, industry_chunk)) return false;
if (i->location.tile != 0) {
i->town = Town::Get(RemapTownIndex(_old_town_index));
i->town = RemapTown(i->location.tile);
if (_savegame_type == SGT_TTO) {
if (i->type > 0x06) i->type++; // Printing Works were added
if (i->type == 0x0A) i->type = 0x12; // Iron Ore Mine has different ID
YearMonthDay ymd;
ConvertDateToYMD(_date, &ymd);
TimerGameEconomy::YearMonthDay ymd = TimerGameEconomy::ConvertDateToYMD(TimerGameEconomy::date);
i->last_prod_year = ymd.year;
i->random_colour = RemapTTOColour(i->random_colour);
@@ -854,7 +874,7 @@ static bool LoadOldIndustry(LoadgameState *ls, int num)
}
static CompanyID _current_company_id;
static int32 _old_yearly;
static int32_t _old_yearly;
static const OldChunks _company_yearly_chunk[] = {
OCL_VAR( OC_INT32, 1, &_old_yearly ),
@@ -888,7 +908,7 @@ static const OldChunks _company_economy_chunk[] = {
OCL_END()
};
static bool LoadOldCompanyEconomy(LoadgameState *ls, int num)
static bool LoadOldCompanyEconomy(LoadgameState *ls, int)
{
Company *c = Company::Get(_current_company_id);
@@ -941,12 +961,10 @@ static const OldChunks _company_chunk[] = {
OCL_CNULL( OC_TTD, 1 ), // Old AI
OCL_CNULL( OC_TTD, 1 ), // avail_railtypes
OCL_SVAR( OC_TILE, Company, location_of_HQ ),
OCL_SVAR( OC_TTD | OC_UINT8, Company, share_owners[0] ),
OCL_SVAR( OC_TTD | OC_UINT8, Company, share_owners[1] ),
OCL_SVAR( OC_TTD | OC_UINT8, Company, share_owners[2] ),
OCL_SVAR( OC_TTD | OC_UINT8, Company, share_owners[3] ),
OCL_CNULL( OC_TTD, 8 ), ///< junk at end of chunk
OCL_CNULL( OC_TTD, 4 ), // Shares
OCL_CNULL( OC_TTD, 8 ), // junk at end of chunk
OCL_END()
};
@@ -1015,14 +1033,14 @@ static bool LoadOldCompany(LoadgameState *ls, int num)
if (c->money == 893288) c->money = c->current_loan = 100000;
}
_company_colours[num] = (Colours)c->colour;
c->inaugurated_year -= ORIGINAL_BASE_YEAR;
_company_colours[num] = c->colour;
c->inaugurated_year -= EconomyTime::ORIGINAL_BASE_YEAR;
return true;
}
static uint32 _old_order_ptr;
static uint16 _old_next_ptr;
static uint32_t _old_order_ptr;
static uint16_t _old_next_ptr;
static VehicleID _current_vehicle_id;
static const OldChunks vehicle_train_chunk[] = {
@@ -1093,7 +1111,7 @@ static const OldChunks vehicle_empty_chunk[] = {
OCL_END()
};
static bool LoadOldVehicleUnion(LoadgameState *ls, int num)
static bool LoadOldVehicleUnion(LoadgameState *ls, int)
{
Vehicle *v = Vehicle::GetIfValid(_current_vehicle_id);
uint temp = ls->total_read;
@@ -1122,7 +1140,7 @@ static bool LoadOldVehicleUnion(LoadgameState *ls, int num)
return res;
}
static uint16 _cargo_count;
static uint16_t _cargo_count;
static const OldChunks vehicle_chunk[] = {
OCL_SVAR( OC_UINT8, Vehicle, subtype ),
@@ -1171,7 +1189,7 @@ static const OldChunks vehicle_chunk[] = {
OCL_VAR ( OC_TTD | OC_UINT16, 1, &_cargo_count ),
OCL_VAR ( OC_TTO | OC_FILE_U8 | OC_VAR_U16, 1, &_cargo_count ),
OCL_VAR ( OC_UINT8, 1, &_cargo_source ),
OCL_VAR ( OC_UINT8, 1, &_cargo_days ),
OCL_VAR ( OC_UINT8, 1, &_cargo_periods ),
OCL_SVAR( OC_TTO | OC_UINT8, Vehicle, tick_counter ),
@@ -1340,12 +1358,16 @@ bool LoadOldVehicle(LoadgameState *ls, int num)
}
v->current_order.AssignOrder(UnpackOldOrder(_old_order));
if (v->type == VEH_DISASTER) {
DisasterVehicle::From(v)->state = UnpackOldOrder(_old_order).GetDestination();
}
v->next = (Vehicle *)(size_t)_old_next_ptr;
if (_cargo_count != 0 && CargoPacket::CanAllocateItem()) {
StationID source = (_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source;
TileIndex source_xy = (source != INVALID_STATION) ? Station::Get(source)->xy : (TileIndex)0;
v->cargo.Append(new CargoPacket(_cargo_count, _cargo_days, source, source_xy, source_xy));
v->cargo.Append(new CargoPacket(_cargo_count, _cargo_periods, source, source_xy, 0));
}
}
@@ -1431,7 +1453,7 @@ static bool LoadOldSubsidy(LoadgameState *ls, int num)
{
Subsidy *s = new (num) Subsidy();
bool ret = LoadChunk(ls, s, subsidy_chunk);
if (s->cargo_type == CT_INVALID) delete s;
if (!IsValidCargoID(s->cargo_type)) delete s;
return ret;
}
@@ -1456,7 +1478,7 @@ static const OldChunks game_difficulty_chunk[] = {
OCL_END()
};
static bool LoadOldGameDifficulty(LoadgameState *ls, int num)
static bool LoadOldGameDifficulty(LoadgameState *ls, int)
{
bool ret = LoadChunk(ls, &_settings_game.difficulty, game_difficulty_chunk);
_settings_game.difficulty.max_loan *= 1000;
@@ -1464,60 +1486,56 @@ static bool LoadOldGameDifficulty(LoadgameState *ls, int num)
}
static bool LoadOldMapPart1(LoadgameState *ls, int num)
static bool LoadOldMapPart1(LoadgameState *ls, int)
{
if (_savegame_type == SGT_TTO) {
MemSetT(_m, 0, OLD_MAP_SIZE);
MemSetT(_me, 0, OLD_MAP_SIZE);
Map::Allocate(OLD_MAP_SIZE, OLD_MAP_SIZE);
}
for (uint i = 0; i < OLD_MAP_SIZE; i++) {
_m[i].m1 = ReadByte(ls);
for (auto t : Map::Iterate()) {
t.m1() = ReadByte(ls);
}
for (uint i = 0; i < OLD_MAP_SIZE; i++) {
_m[i].m2 = ReadByte(ls);
for (auto t : Map::Iterate()) {
t.m2() = ReadByte(ls);
}
if (_savegame_type != SGT_TTO) {
for (uint i = 0; i < OLD_MAP_SIZE; i++) {
_old_map3[i * 2] = ReadByte(ls);
_old_map3[i * 2 + 1] = ReadByte(ls);
/* old map3 is split into to m3 and m4 */
for (auto t : Map::Iterate()) {
t.m3() = ReadByte(ls);
t.m4() = ReadByte(ls);
}
for (uint i = 0; i < OLD_MAP_SIZE / 4; i++) {
auto range = Map::Iterate();
for (auto it = range.begin(); it != range.end(); /* nothing. */) {
byte b = ReadByte(ls);
_me[i * 4 + 0].m6 = GB(b, 0, 2);
_me[i * 4 + 1].m6 = GB(b, 2, 2);
_me[i * 4 + 2].m6 = GB(b, 4, 2);
_me[i * 4 + 3].m6 = GB(b, 6, 2);
for (int i = 0; i < 8; i += 2, ++it) (*it).m6() = GB(b, i, 2);
}
}
return true;
}
static bool LoadOldMapPart2(LoadgameState *ls, int num)
static bool LoadOldMapPart2(LoadgameState *ls, int)
{
uint i;
for (i = 0; i < OLD_MAP_SIZE; i++) {
_m[i].type = ReadByte(ls);
for (auto t : Map::Iterate()) {
t.type() = ReadByte(ls);
}
for (i = 0; i < OLD_MAP_SIZE; i++) {
_m[i].m5 = ReadByte(ls);
for (auto t : Map::Iterate()) {
t.m5() = ReadByte(ls);
}
return true;
}
static bool LoadTTDPatchExtraChunks(LoadgameState *ls, int num)
static bool LoadTTDPatchExtraChunks(LoadgameState *ls, int)
{
ReadTTDPatchFlags();
Debug(oldloader, 2, "Found {} extra chunk(s)", _old_extra_chunk_nums);
for (int i = 0; i != _old_extra_chunk_nums; i++) {
uint16 id = ReadUint16(ls);
uint32 len = ReadUint32(ls);
uint16_t id = ReadUint16(ls);
uint32_t len = ReadUint32(ls);
switch (id) {
/* List of GRFIDs, used in the savegame. 0x8004 is the new ID
@@ -1529,7 +1547,7 @@ static bool LoadTTDPatchExtraChunks(LoadgameState *ls, int num)
ClearGRFConfigList(&_grfconfig);
while (len != 0) {
uint32 grfid = ReadUint32(ls);
uint32_t grfid = ReadUint32(ls);
if (ReadByte(ls) == 1) {
GRFConfig *c = new GRFConfig("TTDP game, no information");
@@ -1566,16 +1584,16 @@ static bool LoadTTDPatchExtraChunks(LoadgameState *ls, int num)
}
extern TileIndex _cur_tileloop_tile;
extern uint16 _disaster_delay;
extern uint16_t _disaster_delay;
extern byte _trees_tick_ctr;
extern byte _age_cargo_skip_counter; // From misc_sl.cpp
extern uint8 _old_diff_level;
extern uint8 _old_units;
extern uint8_t _old_diff_level;
extern uint8_t _old_units;
static const OldChunks main_chunk[] = {
OCL_ASSERT( OC_TTD, 0 ),
OCL_ASSERT( OC_TTO, 0 ),
OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_date ),
OCL_VAR ( OC_UINT16, 1, &_date_fract ),
OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &TimerGameCalendar::date ),
OCL_VAR ( OC_UINT16, 1, &TimerGameCalendar::date_fract ),
OCL_NULL( 600 ), ///< TextEffects
OCL_VAR ( OC_UINT32, 2, &_random.state ),
@@ -1610,7 +1628,7 @@ static const OldChunks main_chunk[] = {
OCL_NULL( 2 ), ///< land_code, no longer in use
OCL_VAR ( OC_FILE_U16 | OC_VAR_U8, 1, &_age_cargo_skip_counter ),
OCL_VAR ( OC_FILE_U16 | OC_VAR_U64, 1, &_tick_counter ),
OCL_VAR ( OC_FILE_U16 | OC_VAR_U64, 1, &TimerGameTick::counter ),
OCL_VAR ( OC_TILE, 1, &_cur_tileloop_tile ),
OCL_ASSERT( OC_TTO, 0x3A2E ),
@@ -1674,7 +1692,7 @@ static const OldChunks main_chunk[] = {
OCL_ASSERT( OC_TTO, 0x496CE ),
OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_next_competitor_start ),
OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_new_competitor_timeout.period ),
OCL_CNULL( OC_TTO, 2 ), ///< available monorail bitmask
@@ -1748,8 +1766,6 @@ bool LoadTTDMain(LoadgameState *ls)
_read_ttdpatch_flags = false;
/* Load the biggest chunk */
std::array<byte, OLD_MAP_SIZE * 2> map3;
_old_map3 = map3.data();
_old_vehicle_names = nullptr;
try {
if (!LoadChunk(ls, nullptr, main_chunk)) {

View File

@@ -25,7 +25,7 @@
*/
void Order::ConvertFromOldSavegame()
{
uint8 old_flags = this->flags;
uint8_t old_flags = this->flags;
this->flags = 0;
/* First handle non-stop - use value from savegame if possible, else use value from config file */
@@ -79,7 +79,7 @@ void Order::ConvertFromOldSavegame()
* @param packed packed order
* @return unpacked order
*/
static Order UnpackVersion4Order(uint16 packed)
static Order UnpackVersion4Order(uint16_t packed)
{
return Order(GB(packed, 8, 8) << 16 | GB(packed, 4, 4) << 8 | GB(packed, 0, 4));
}
@@ -89,7 +89,7 @@ static Order UnpackVersion4Order(uint16 packed)
* @param packed packed order
* @return unpacked order
*/
Order UnpackOldOrder(uint16 packed)
Order UnpackOldOrder(uint16_t packed)
{
Order order = UnpackVersion4Order(packed);
@@ -141,29 +141,25 @@ struct ORDRChunkHandler : ChunkHandler {
if (IsSavegameVersionBefore(SLV_5)) {
/* Pre-version 5 had another layout for orders
* (uint16 instead of uint32) */
len /= sizeof(uint16);
uint16 *orders = MallocT<uint16>(len + 1);
* (uint16_t instead of uint32_t) */
len /= sizeof(uint16_t);
std::vector<uint16_t> orders(len);
SlCopy(orders, len, SLE_UINT16);
SlCopy(&orders[0], len, SLE_UINT16);
for (size_t i = 0; i < len; ++i) {
Order *o = new (i) Order();
o->AssignOrder(UnpackVersion4Order(orders[i]));
}
free(orders);
} else if (IsSavegameVersionBefore(SLV_5, 2)) {
len /= sizeof(uint32);
uint32 *orders = MallocT<uint32>(len + 1);
len /= sizeof(uint32_t);
std::vector<uint32_t> orders(len);
SlCopy(orders, len, SLE_UINT32);
SlCopy(&orders[0], len, SLE_UINT32);
for (size_t i = 0; i < len; ++i) {
new (i) Order(orders[i]);
}
free(orders);
}
/* Update all the next pointer */
@@ -261,7 +257,8 @@ SaveLoadTable GetOrderBackupDescription()
SLE_CONDVAR(OrderBackup, cur_implicit_order_index, SLE_UINT8, SLV_176, SL_MAX_VERSION),
SLE_CONDVAR(OrderBackup, current_order_time, SLE_UINT32, SLV_176, SL_MAX_VERSION),
SLE_CONDVAR(OrderBackup, lateness_counter, SLE_INT32, SLV_176, SL_MAX_VERSION),
SLE_CONDVAR(OrderBackup, timetable_start, SLE_INT32, SLV_176, SL_MAX_VERSION),
SLE_CONDVAR(OrderBackup, timetable_start, SLE_FILE_I32 | SLE_VAR_U64, SLV_176, SLV_TIMETABLE_START_TICKS_FIX),
SLE_CONDVAR(OrderBackup, timetable_start, SLE_UINT64, SLV_TIMETABLE_START_TICKS_FIX, SL_MAX_VERSION),
SLE_CONDVAR(OrderBackup, vehicle_flags, SLE_FILE_U8 | SLE_VAR_U16, SLV_176, SLV_180),
SLE_CONDVAR(OrderBackup, vehicle_flags, SLE_UINT16, SLV_180, SL_MAX_VERSION),
SLE_REF(OrderBackup, orders, REF_ORDER),

File diff suppressed because it is too large Load Diff

View File

@@ -10,13 +10,9 @@
#ifndef SAVELOAD_H
#define SAVELOAD_H
#include "saveload_error.hpp"
#include "../fileio_type.h"
#include "../fios.h"
#include "../strings_type.h"
#include "../core/span_type.hpp"
#include <optional>
#include <string>
#include <vector>
/** SaveLoad versions
* Previous savegame versions, the trunk revision where they were
@@ -31,7 +27,7 @@
*
* Note that this list must not be reordered.
*/
enum SaveLoadVersion : uint16 {
enum SaveLoadVersion : uint16_t {
SL_MIN_VERSION, ///< First savegame version
SLV_1, ///< 1.0 0.1.x, 0.2.x
@@ -285,7 +281,7 @@ enum SaveLoadVersion : uint16 {
SLV_198, ///< 198 PR#6763 Switch town growth rate and counter to actual game ticks
SLV_EXTEND_CARGOTYPES, ///< 199 PR#6802 Extend cargotypes to 64
SLV_EXTEND_RAILTYPES, ///< 200 PR#6805 Extend railtypes to 64, adding uint16 to map array.
SLV_EXTEND_RAILTYPES, ///< 200 PR#6805 Extend railtypes to 64, adding uint16_t to map array.
SLV_EXTEND_PERSISTENT_STORAGE, ///< 201 PR#6885 Extend NewGRF persistent storages.
SLV_EXTEND_INDUSTRY_CARGO_SLOTS, ///< 202 PR#6867 Increase industry cargo slots to 16 in, 16 out
SLV_SHIP_PATH_CACHE, ///< 203 PR#7072 Add path cache for ships
@@ -341,9 +337,44 @@ enum SaveLoadVersion : uint16 {
SLV_DOCK_DOCKINGTILES, ///< 298 PR#9578 All tiles around docks may be docking tiles.
SLV_REPAIR_OBJECT_DOCKING_TILES, ///< 299 PR#9594 v12.0 Fixing issue with docking tiles overlapping objects.
SLV_U64_TICK_COUNTER, ///< 300 PR#10035 Make _tick_counter 64bit to avoid wrapping.
SLV_U64_TICK_COUNTER, ///< 300 PR#10035 Make tick counter 64bit to avoid wrapping.
SLV_LAST_LOADING_TICK, ///< 301 PR#9693 Store tick of last loading for vehicles.
SLV_MULTITRACK_LEVEL_CROSSINGS, ///< 302 PR#9931 v13.0 Multi-track level crossings.
SLV_NEWGRF_ROAD_STOPS, ///< 303 PR#10144 NewGRF road stops.
SLV_LINKGRAPH_EDGES, ///< 304 PR#10314 Explicitly store link graph edges destination, PR#10471 int64_t instead of uint64_t league rating
SLV_VELOCITY_NAUTICAL, ///< 305 PR#10594 Separation of land and nautical velocity (knots!)
SLV_CONSISTENT_PARTIAL_Z, ///< 306 PR#10570 Conversion from an inconsistent partial Z calculation for slopes, to one that is (more) consistent.
SLV_MORE_CARGO_AGE, ///< 307 PR#10596 Track cargo age for a longer period.
SLV_LINKGRAPH_SECONDS, ///< 308 PR#10610 Store linkgraph update intervals in seconds instead of days.
SLV_AI_START_DATE, ///< 309 PR#10653 Removal of individual AI start dates and added a generic one.
SLV_EXTEND_VEHICLE_RANDOM, ///< 310 PR#10701 Extend vehicle random bits.
SLV_EXTEND_ENTITY_MAPPING, ///< 311 PR#10672 Extend entity mapping range.
SLV_DISASTER_VEH_STATE, ///< 312 PR#10798 Explicit storage of disaster vehicle state.
SLV_SAVEGAME_ID, ///< 313 PR#10719 Add an unique ID to every savegame (used to deduplicate surveys).
SLV_STRING_GAMELOG, ///< 314 PR#10801 Use std::string in gamelog.
SLV_INDUSTRY_CARGO_REORGANISE, ///< 315 PR#10853 Industry accepts/produced data reorganised.
SLV_PERIODS_IN_TRANSIT_RENAME, ///< 316 PR#11112 Rename days in transit to (cargo) periods in transit.
SLV_NEWGRF_LAST_SERVICE, ///< 317 PR#11124 Added stable date_of_last_service to avoid NewGRF trouble.
SLV_REMOVE_LOADED_AT_XY, ///< 318 PR#11276 Remove loaded_at_xy variable from CargoPacket.
SLV_CARGO_TRAVELLED, ///< 319 PR#11283 CargoPacket now tracks how far it travelled inside a vehicle.
SLV_STATION_RATING_CHEAT, ///< 320 PR#11346 Add cheat to fix station ratings at 100%.
SLV_TIMETABLE_START_TICKS, ///< 321 PR#11468 Convert timetable start from a date to ticks.
SLV_TIMETABLE_START_TICKS_FIX, ///< 322 PR#11557 Fix for missing convert timetable start from a date to ticks.
SLV_TIMETABLE_TICKS_TYPE, ///< 323 PR#11435 Convert timetable current order time to ticks.
SLV_WATER_REGIONS, ///< 324 PR#10543 Water Regions for ship pathfinder.
SLV_WATER_REGION_EVAL_SIMPLIFIED, ///< 325 PR#11750 Simplified Water Region evaluation.
SLV_ECONOMY_DATE, ///< 326 PR#10700 Split calendar and economy timers and dates.
SLV_ECONOMY_MODE_TIMEKEEPING_UNITS, ///< 327 PR#11341 Mode to display economy measurements in wallclock units.
SLV_CALENDAR_SUB_DATE_FRACT, ///< 328 PR#11428 Add sub_date_fract to measure calendar days.
SLV_SHIP_ACCELERATION, ///< 329 PR#10734 Start using Vehicle's acceleration field for ships too.
SLV_MAX_LOAN_FOR_COMPANY, ///< 330 PR#11224 Separate max loan for each company.
SLV_DEPOT_UNBUNCHING, ///< 330 PR#11945 Allow unbunching shared order vehicles at a depot.
SL_MAX_VERSION, ///< Highest possible saveload version
};
@@ -357,16 +388,15 @@ enum SaveOrLoadResult {
/** Deals with the type of the savegame, independent of extension */
struct FileToSaveLoad {
SaveLoadOperation file_op; ///< File operation to perform.
SaveLoadOperation file_op; ///< File operation to perform.
DetailedFileType detail_ftype; ///< Concrete file type (PNG, BMP, old save, etc).
AbstractFileType abstract_ftype; ///< Abstract type of file (scenario, heightmap, etc).
std::string name; ///< Name of the file.
char title[255]; ///< Internal name of the game.
std::string title; ///< Internal name of the game.
void SetMode(FiosType ft);
void SetMode(SaveLoadOperation fop, AbstractFileType aft, DetailedFileType dft);
void SetName(const char *name);
void SetTitle(const char *title);
void Set(const FiosItem &item);
};
/** Types of save games. */
@@ -381,7 +411,7 @@ enum SavegameType {
extern FileToSaveLoad _file_to_saveload;
void GenerateDefaultSaveName(char *buf, const char *last);
std::string GenerateDefaultSaveName();
void SetSaveLoadError(StringID str);
const char *GetSaveLoadErrorString();
SaveOrLoadResult SaveOrLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, Subdirectory sb, bool threaded = true);
@@ -410,12 +440,12 @@ enum ChunkType {
/** Handlers and description of chunk. */
struct ChunkHandler {
uint32 id; ///< Unique ID (4 letters).
uint32_t id; ///< Unique ID (4 letters).
ChunkType type; ///< Type of the chunk. @see ChunkType
ChunkHandler(uint32 id, ChunkType type) : id(id), type(type) {}
ChunkHandler(uint32_t id, ChunkType type) : id(id), type(type) {}
virtual ~ChunkHandler() {}
virtual ~ChunkHandler() = default;
/**
* Save the chunk.
@@ -443,50 +473,59 @@ struct ChunkHandler {
* @param len Number of bytes to skip.
*/
virtual void LoadCheck(size_t len = 0) const;
std::string GetName() const
{
return std::string()
+ static_cast<char>(this->id >> 24)
+ static_cast<char>(this->id >> 16)
+ static_cast<char>(this->id >> 8)
+ static_cast<char>(this->id);
}
};
/** A reference to ChunkHandler. */
using ChunkHandlerRef = std::reference_wrapper<const ChunkHandler>;
/** A table of ChunkHandler entries. */
using ChunkHandlerTable = span<const ChunkHandlerRef>;
using ChunkHandlerTable = std::span<const ChunkHandlerRef>;
/** A table of SaveLoad entries. */
using SaveLoadTable = span<const struct SaveLoad>;
using SaveLoadTable = std::span<const struct SaveLoad>;
/** A table of SaveLoadCompat entries. */
using SaveLoadCompatTable = span<const struct SaveLoadCompat>;
using SaveLoadCompatTable = std::span<const struct SaveLoadCompat>;
/** Handler for saving/loading an object to/from disk. */
class SaveLoadHandler {
public:
std::optional<std::vector<SaveLoad>> load_description;
virtual ~SaveLoadHandler() {}
virtual ~SaveLoadHandler() = default;
/**
* Save the object to disk.
* @param object The object to store.
*/
virtual void Save(void *object) const {}
virtual void Save([[maybe_unused]] void *object) const {}
/**
* Load the object from disk.
* @param object The object to load.
*/
virtual void Load(void *object) const {}
virtual void Load([[maybe_unused]] void *object) const {}
/**
* Similar to load, but used only to validate savegames.
* @param object The object to load.
*/
virtual void LoadCheck(void *object) const {}
virtual void LoadCheck([[maybe_unused]] void *object) const {}
/**
* A post-load callback to fix #SL_REF integers into pointers.
* @param object The object to fix.
*/
virtual void FixPointers(void *object) const {}
virtual void FixPointers([[maybe_unused]] void *object) const {}
/**
* Get the description of the fields in the savegame.
@@ -523,16 +562,16 @@ public:
SaveLoadTable GetDescription() const override { return static_cast<const TImpl *>(this)->description; }
SaveLoadCompatTable GetCompatDescription() const override { return static_cast<const TImpl *>(this)->compat_description; }
virtual void Save(TObject *object) const {}
virtual void Save([[maybe_unused]] TObject *object) const {}
void Save(void *object) const override { this->Save(static_cast<TObject *>(object)); }
virtual void Load(TObject *object) const {}
virtual void Load([[maybe_unused]] TObject *object) const {}
void Load(void *object) const override { this->Load(static_cast<TObject *>(object)); }
virtual void LoadCheck(TObject *object) const {}
virtual void LoadCheck([[maybe_unused]] TObject *object) const {}
void LoadCheck(void *object) const override { this->LoadCheck(static_cast<TObject *>(object)); }
virtual void FixPointers(TObject *object) const {}
virtual void FixPointers([[maybe_unused]] TObject *object) const {}
void FixPointers(void *object) const override { this->FixPointers(static_cast<TObject *>(object)); }
};
@@ -591,7 +630,6 @@ enum VarTypes {
SLE_VAR_I64 = 7 << 4,
SLE_VAR_U64 = 8 << 4,
SLE_VAR_NULL = 9 << 4, ///< useful to write zeros in savegame.
SLE_VAR_STRB = 10 << 4, ///< string (with pre-allocated buffer)
SLE_VAR_STR = 12 << 4, ///< string pointer
SLE_VAR_STRQ = 13 << 4, ///< string pointer enclosed in quotes
SLE_VAR_NAME = 14 << 4, ///< old custom name to be converted to a char pointer
@@ -614,7 +652,6 @@ enum VarTypes {
SLE_UINT64 = SLE_FILE_U64 | SLE_VAR_U64,
SLE_CHAR = SLE_FILE_I8 | SLE_VAR_CHAR,
SLE_STRINGID = SLE_FILE_STRINGID | SLE_VAR_U32,
SLE_STRINGBUF = SLE_FILE_STRING | SLE_VAR_STRB,
SLE_STRING = SLE_FILE_STRING | SLE_VAR_STR,
SLE_STRINGQUOTE = SLE_FILE_STRING | SLE_VAR_STRQ,
SLE_NAME = SLE_FILE_STRINGID | SLE_VAR_NAME,
@@ -622,7 +659,6 @@ enum VarTypes {
/* Shortcut values */
SLE_UINT = SLE_UINT32,
SLE_INT = SLE_INT32,
SLE_STRB = SLE_STRINGBUF,
SLE_STR = SLE_STRING,
SLE_STRQ = SLE_STRINGQUOTE,
@@ -632,7 +668,7 @@ enum VarTypes {
SLF_ALLOW_NEWLINE = 1 << 9, ///< Allow new lines in the strings.
};
typedef uint32 VarType;
typedef uint32_t VarType;
/** Type of data saved. */
enum SaveLoadType : byte {
@@ -640,7 +676,6 @@ enum SaveLoadType : byte {
SL_REF = 1, ///< Save/load a reference.
SL_STRUCT = 2, ///< Save/load a struct.
SL_STR = 3, ///< Save/load a string.
SL_STDSTR = 4, ///< Save/load a \c std::string.
SL_ARR = 5, ///< Save/load a fixed-size array of #SL_VAR elements.
@@ -660,7 +695,7 @@ struct SaveLoad {
std::string name; ///< Name of this field (optional, used for tables).
SaveLoadType cmd; ///< The action to take with the saved/loaded type, All types need different action.
VarType conv; ///< Type of the variable to be saved; this field combines both FileVarType and MemVarType.
uint16 length; ///< (Conditional) length of the variable (eg. arrays) (max array size is 65536 elements).
uint16_t length; ///< (Conditional) length of the variable (eg. arrays) (max array size is 65536 elements).
SaveLoadVersion version_from; ///< Save/load the variable starting from this savegame version.
SaveLoadVersion version_to; ///< Save/load the variable before this savegame version.
size_t size; ///< The sizeof size.
@@ -679,23 +714,124 @@ struct SaveLoad {
*/
struct SaveLoadCompat {
std::string name; ///< Name of the field.
uint16 length; ///< Length of the NULL field.
uint16_t length; ///< Length of the NULL field.
SaveLoadVersion version_from; ///< Save/load the variable starting from this savegame version.
SaveLoadVersion version_to; ///< Save/load the variable before this savegame version.
};
/**
* Get the NumberType of a setting. This describes the integer type
* as it is represented in memory
* @param type VarType holding information about the variable-type
* @return the SLE_VAR_* part of a variable-type description
*/
inline constexpr VarType GetVarMemType(VarType type)
{
return GB(type, 4, 4) << 4;
}
/**
* Get the FileType of a setting. This describes the integer type
* as it is represented in a savegame/file
* @param type VarType holding information about the file-type
* @return the SLE_FILE_* part of a variable-type description
*/
inline constexpr VarType GetVarFileType(VarType type)
{
return GB(type, 0, 4);
}
/**
* Check if the given saveload type is a numeric type.
* @param conv the type to check
* @return True if it's a numeric type.
*/
inline constexpr bool IsNumericType(VarType conv)
{
return GetVarMemType(conv) <= SLE_VAR_U64;
}
/**
* Return expect size in bytes of a VarType
* @param type VarType to get size of.
* @return size of type in bytes.
*/
inline constexpr size_t SlVarSize(VarType type)
{
switch (GetVarMemType(type)) {
case SLE_VAR_BL: return sizeof(bool);
case SLE_VAR_I8: return sizeof(int8_t);
case SLE_VAR_U8: return sizeof(uint8_t);
case SLE_VAR_I16: return sizeof(int16_t);
case SLE_VAR_U16: return sizeof(uint16_t);
case SLE_VAR_I32: return sizeof(int32_t);
case SLE_VAR_U32: return sizeof(uint32_t);
case SLE_VAR_I64: return sizeof(int64_t);
case SLE_VAR_U64: return sizeof(uint64_t);
case SLE_VAR_NULL: return sizeof(void *);
case SLE_VAR_STR: return sizeof(std::string);
case SLE_VAR_STRQ: return sizeof(std::string);
case SLE_VAR_NAME: return sizeof(std::string);
default: NOT_REACHED();
}
}
/**
* Check if a saveload cmd/type/length entry matches the size of the variable.
* @param cmd SaveLoadType of entry.
* @param type VarType of entry.
* @param length Array length of entry.
* @param size Actual size of variable.
* @return true iff the sizes match.
*/
inline constexpr bool SlCheckVarSize(SaveLoadType cmd, VarType type, size_t length, size_t size)
{
switch (cmd) {
case SL_VAR: return SlVarSize(type) == size;
case SL_REF: return sizeof(void *) == size;
case SL_STDSTR: return SlVarSize(type) == size;
case SL_ARR: return SlVarSize(type) * length <= size; // Partial load of array is permitted.
case SL_DEQUE: return sizeof(std::deque<void *>) == size;
case SL_VECTOR: return sizeof(std::vector<void *>) == size;
case SL_REFLIST: return sizeof(std::list<void *>) == size;
case SL_SAVEBYTE: return true;
default: NOT_REACHED();
}
}
/**
* Storage of simple variables, references (pointers), and arrays.
* @param cmd Load/save type. @see SaveLoadType
* @param name Field name for table chunks.
* @param base Name of the class or struct containing the variable.
* @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 from First savegame version that has the field.
* @param to Last savegame version that has the field.
* @param extra Extra data to pass to the address callback function.
* @note In general, it is better to use one of the SLE_* macros below.
*/
#define SLE_GENERAL(cmd, base, variable, type, length, from, to, extra) SaveLoad {#variable, cmd, type, length, from, to, cpp_sizeof(base, variable), [] (void *b, size_t) -> void * { assert(b != nullptr); return const_cast<void *>(static_cast<const void *>(std::addressof(static_cast<base *>(b)->variable))); }, extra, nullptr}
#define SLE_GENERAL_NAME(cmd, name, base, variable, type, length, from, to, extra) \
SaveLoad {name, cmd, type, length, from, to, cpp_sizeof(base, variable), [] (void *b, size_t) -> void * { \
static_assert(SlCheckVarSize(cmd, type, length, sizeof(static_cast<base *>(b)->variable))); \
assert(b != nullptr); \
return const_cast<void *>(static_cast<const void *>(std::addressof(static_cast<base *>(b)->variable))); \
}, extra, nullptr}
/**
* Storage of simple variables, references (pointers), and arrays with a custom name.
* @param cmd Load/save type. @see SaveLoadType
* @param base Name of the class or struct containing the variable.
* @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 from First savegame version that has the field.
* @param to Last savegame version that has the field.
* @param extra Extra data to pass to the address callback function.
* @note In general, it is better to use one of the SLE_* macros below.
*/
#define SLE_GENERAL(cmd, base, variable, type, length, from, to, extra) SLE_GENERAL_NAME(cmd, #variable, base, variable, type, length, from, to, extra)
/**
* Storage of a variable in some savegame versions.
@@ -707,6 +843,17 @@ struct SaveLoadCompat {
*/
#define SLE_CONDVAR(base, variable, type, from, to) SLE_GENERAL(SL_VAR, base, variable, type, 0, from, to, 0)
/**
* Storage of a variable in some savegame versions.
* @param base Name of the class or struct containing the variable.
* @param variable Name of the variable in the class or struct referenced by \a base.
* @param name Field name for table chunks.
* @param type Storage of the data in memory and in the savegame.
* @param from First savegame version that has the field.
* @param to Last savegame version that has the field.
*/
#define SLE_CONDVARNAME(base, variable, name, type, from, to) SLE_GENERAL_NAME(SL_VAR, name, base, variable, type, 0, from, to, 0)
/**
* Storage of a reference in some savegame versions.
* @param base Name of the class or struct containing the variable.
@@ -728,6 +875,18 @@ struct SaveLoadCompat {
*/
#define SLE_CONDARR(base, variable, type, length, from, to) SLE_GENERAL(SL_ARR, base, variable, type, length, from, to, 0)
/**
* 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.
* @param variable Name of the variable in the class or struct referenced by \a base.
* @param name Field name for table chunks.
* @param type Storage of the data in memory and in the savegame.
* @param length Number of elements in the array.
* @param from First savegame version that has the array.
* @param to Last savegame version that has the array.
*/
#define SLE_CONDARRNAME(base, variable, name, type, length, from, to) SLE_GENERAL_NAME(SL_ARR, name, base, variable, type, length, from, to, 0)
/**
* Storage of a string in some savegame versions.
* @param base Name of the class or struct containing the string.
@@ -749,6 +908,17 @@ struct SaveLoadCompat {
*/
#define SLE_CONDSSTR(base, variable, type, from, to) SLE_GENERAL(SL_STDSTR, base, variable, type, 0, from, to, 0)
/**
* Storage of a \c std::string in some savegame versions.
* @param base Name of the class or struct containing the string.
* @param variable Name of the variable in the class or struct referenced by \a base.
* @param name Field name for table chunks.
* @param type Storage of the data in memory and in the savegame.
* @param from First savegame version that has the string.
* @param to Last savegame version that has the string.
*/
#define SLE_CONDSSTRNAME(base, variable, name, type, from, to) SLE_GENERAL_NAME(SL_STDSTR, name, base, variable, type, 0, from, to, 0)
/**
* Storage of a list of #SL_REF elements in some savegame versions.
* @param base Name of the class or struct containing the list.
@@ -777,6 +947,15 @@ struct SaveLoadCompat {
*/
#define SLE_VAR(base, variable, type) SLE_CONDVAR(base, variable, type, SL_MIN_VERSION, SL_MAX_VERSION)
/**
* Storage of a variable in every version of a savegame.
* @param base Name of the class or struct containing the variable.
* @param variable Name of the variable in the class or struct referenced by \a base.
* @param name Field name for table chunks.
* @param type Storage of the data in memory and in the savegame.
*/
#define SLE_VARNAME(base, variable, name, type) SLE_CONDVARNAME(base, variable, name, type, SL_MIN_VERSION, SL_MAX_VERSION)
/**
* Storage of a reference in every version of a savegame.
* @param base Name of the class or struct containing the variable.
@@ -795,13 +974,14 @@ struct SaveLoadCompat {
#define SLE_ARR(base, variable, type, length) SLE_CONDARR(base, variable, type, length, SL_MIN_VERSION, SL_MAX_VERSION)
/**
* Storage of a string in every savegame version.
* @param base Name of the class or struct containing the string.
* Storage of fixed-size array of #SL_VAR elements in every version of a savegame.
* @param base Name of the class or struct containing the array.
* @param variable Name of the variable in the class or struct referenced by \a base.
* @param name Field name for table chunks.
* @param type Storage of the data in memory and in the savegame.
* @param length Number of elements in the string (only used for fixed size buffers).
* @param length Number of elements in the array.
*/
#define SLE_STR(base, variable, type, length) SLE_CONDSTR(base, variable, 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 \c std::string in every savegame version.
@@ -811,6 +991,15 @@ struct SaveLoadCompat {
*/
#define SLE_SSTR(base, variable, type) SLE_CONDSSTR(base, variable, type, SL_MIN_VERSION, SL_MAX_VERSION)
/**
* Storage of a \c std::string in every savegame version.
* @param base Name of the class or struct containing the string.
* @param variable Name of the variable in the class or struct referenced by \a base.
* @param name Field name for table chunks.
* @param type Storage of the data in memory and in the savegame.
*/
#define SLE_SSTRNAME(base, variable, name, type) SLE_CONDSSTRNAME(base, variable, name, type, SL_MIN_VERSION, SL_MAX_VERSION)
/**
* Storage of a list of #SL_REF elements in every savegame version.
* @param base Name of the class or struct containing the list.
@@ -842,7 +1031,10 @@ struct SaveLoadCompat {
* @param extra Extra data to pass to the address callback function.
* @note In general, it is better to use one of the SLEG_* macros below.
*/
#define SLEG_GENERAL(name, cmd, variable, type, length, from, to, extra) SaveLoad {name, cmd, type, length, from, to, sizeof(variable), [] (void *, size_t) -> void * { return static_cast<void *>(std::addressof(variable)); }, extra, nullptr}
#define SLEG_GENERAL(name, cmd, variable, type, length, from, to, extra) \
SaveLoad {name, cmd, type, length, from, to, sizeof(variable), [] (void *, size_t) -> void * { \
static_assert(SlCheckVarSize(cmd, type, length, sizeof(variable))); \
return static_cast<void *>(std::addressof(variable)); }, extra, nullptr}
/**
* Storage of a global variable in some savegame versions.
@@ -875,17 +1067,6 @@ struct SaveLoadCompat {
*/
#define SLEG_CONDARR(name, variable, type, length, from, to) SLEG_GENERAL(name, SL_ARR, variable, type, length, from, to, 0)
/**
* Storage of a global string in some savegame versions.
* @param name The name of the field.
* @param variable Name of the global variable.
* @param type Storage of the data in memory and in the savegame.
* @param length Number of elements in the string (only used for fixed size buffers).
* @param from First savegame version that has the string.
* @param to Last savegame version that has the string.
*/
#define SLEG_CONDSTR(name, variable, type, length, from, to) SLEG_GENERAL(name, SL_STR, variable, type, length, from, to, 0)
/**
* Storage of a global \c std::string in some savegame versions.
* @param name The name of the field.
@@ -958,14 +1139,6 @@ struct SaveLoadCompat {
*/
#define SLEG_ARR(name, variable, type) SLEG_CONDARR(name, variable, type, lengthof(variable), SL_MIN_VERSION, SL_MAX_VERSION)
/**
* Storage of a global string in every savegame version.
* @param name The name of the field.
* @param variable Name of the global variable.
* @param type Storage of the data in memory and in the savegame.
*/
#define SLEG_STR(name, variable, type) SLEG_CONDSTR(name, variable, type, sizeof(variable), SL_MIN_VERSION, SL_MAX_VERSION)
/**
* Storage of a global \c std::string in every savegame version.
* @param name The name of the field.
@@ -1027,7 +1200,7 @@ struct SaveLoadCompat {
* @param minor Minor number of the version to check against. If \a minor is 0 or not specified, only the major number is checked.
* @return Savegame version is earlier than the specified version.
*/
static inline bool IsSavegameVersionBefore(SaveLoadVersion major, byte minor = 0)
inline bool IsSavegameVersionBefore(SaveLoadVersion major, byte minor = 0)
{
extern SaveLoadVersion _sl_version;
extern byte _sl_minor_version;
@@ -1041,7 +1214,7 @@ static inline bool IsSavegameVersionBefore(SaveLoadVersion major, byte minor = 0
* @param major Major number of the version to check against.
* @return Savegame version is at most the specified version.
*/
static inline bool IsSavegameVersionBeforeOrAt(SaveLoadVersion major)
inline bool IsSavegameVersionBeforeOrAt(SaveLoadVersion major)
{
extern SaveLoadVersion _sl_version;
return _sl_version <= major;
@@ -1054,50 +1227,18 @@ static inline bool IsSavegameVersionBeforeOrAt(SaveLoadVersion major)
* @param version_to Exclusive savegame version upper bound. SL_MAX_VERSION if no upper bound.
* @return Active savegame version falls within the given range.
*/
static inline bool SlIsObjectCurrentlyValid(SaveLoadVersion version_from, SaveLoadVersion version_to)
inline bool SlIsObjectCurrentlyValid(SaveLoadVersion version_from, SaveLoadVersion version_to)
{
extern const SaveLoadVersion SAVEGAME_VERSION;
return version_from <= SAVEGAME_VERSION && SAVEGAME_VERSION < version_to;
}
/**
* Get the NumberType of a setting. This describes the integer type
* as it is represented in memory
* @param type VarType holding information about the variable-type
* @return the SLE_VAR_* part of a variable-type description
*/
static inline VarType GetVarMemType(VarType type)
{
return type & 0xF0; // GB(type, 4, 4) << 4;
}
/**
* Get the FileType of a setting. This describes the integer type
* as it is represented in a savegame/file
* @param type VarType holding information about the file-type
* @return the SLE_FILE_* part of a variable-type description
*/
static inline VarType GetVarFileType(VarType type)
{
return type & 0xF; // GB(type, 0, 4);
}
/**
* Check if the given saveload type is a numeric type.
* @param conv the type to check
* @return True if it's a numeric type.
*/
static inline bool IsNumericType(VarType conv)
{
return GetVarMemType(conv) <= SLE_VAR_U64;
}
/**
* Get the address of the variable. Null-variables don't have an address,
* everything else has a callback function that returns the address based
* on the saveload data and the current object for non-globals.
*/
static inline void *GetVariableAddress(const void *object, const SaveLoad &sld)
inline void *GetVariableAddress(const void *object, const SaveLoad &sld)
{
/* Entry is a null-variable, mostly used to read old savegames etc. */
if (GetVarMemType(sld.conv) == SLE_VAR_NULL) {
@@ -1110,8 +1251,8 @@ static inline void *GetVariableAddress(const void *object, const SaveLoad &sld)
return sld.address_proc(const_cast<void *>(object), sld.extra_data);
}
int64 ReadValue(const void *ptr, VarType conv);
void WriteValue(void *ptr, VarType conv, int64 val);
int64_t ReadValue(const void *ptr, VarType conv);
void WriteValue(void *ptr, VarType conv, int64_t val);
void SlSetArrayIndex(uint index);
int SlIterateArray();
@@ -1133,9 +1274,6 @@ void SlCopy(void *object, size_t length, VarType conv);
std::vector<SaveLoad> SlTableHeader(const SaveLoadTable &slt);
std::vector<SaveLoad> SlCompatTableHeader(const SaveLoadTable &slt, const SaveLoadCompatTable &slct);
void SlObject(void *object, const SaveLoadTable &slt);
void NORETURN SlError(StringID string, const char *extra_msg = nullptr);
void NORETURN SlErrorCorrupt(const char *msg);
void NORETURN SlErrorCorruptFmt(const char *format, ...) WARN_FORMAT(1, 2);
bool SaveloadCrashWithMissingNewGRFs();
@@ -1144,7 +1282,7 @@ bool SaveloadCrashWithMissingNewGRFs();
* anything with them, discarding them in effect
* @param length The amount of bytes that is being treated this way
*/
static inline void SlSkipBytes(size_t length)
inline void SlSkipBytes(size_t length)
{
for (; length != 0; length--) SlReadByte();
}

View File

@@ -0,0 +1,33 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file saveload.h Functions/types related to errors from savegames. */
#ifndef SAVELOAD_ERROR_HPP
#define SAVELOAD_ERROR_HPP
#include "../3rdparty/fmt/format.h"
#include "../strings_type.h"
[[noreturn]] void SlError(StringID string, const std::string &extra_msg = {});
[[noreturn]] void SlErrorCorrupt(const std::string &msg);
/**
* Issue an SlErrorCorrupt with a format string.
* @param format_string The formatting string to tell what to do with the remaining arguments.
* @param fmt_args The arguments to be passed to fmt.
* @tparam Args The types of the fmt arguments.
* @note This function does never return as it throws an exception to
* break out of all the saveload code.
*/
template <typename ... Args>
[[noreturn]] inline void SlErrorCorruptFmt(const fmt::format_string<Args...> format, Args&&... fmt_args)
{
SlErrorCorrupt(fmt::format(format, std::forward<Args>(fmt_args)...));
}
#endif /* SAVELOAD_ERROR_HPP */

View File

@@ -47,15 +47,15 @@ void ResetTempEngineData();
Engine *GetTempDataEngine(EngineID index);
void CopyTempEngineData();
extern int32 _saved_scrollpos_x;
extern int32 _saved_scrollpos_y;
extern int32_t _saved_scrollpos_x;
extern int32_t _saved_scrollpos_y;
extern ZoomLevel _saved_scrollpos_zoom;
extern SavegameType _savegame_type;
extern uint32 _ttdp_version;
extern uint32_t _ttdp_version;
CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32 face);
CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32_t face);
Order UnpackOldOrder(uint16 packed);
Order UnpackOldOrder(uint16_t packed);
#endif /* SAVELOAD_INTERNAL_H */

View File

@@ -63,7 +63,7 @@ void HandleOldDiffCustom(bool savegame)
continue;
}
int32 value = (int32)((name == "max_loan" ? 1000 : 1) * _old_diff_custom[i++]);
int32_t value = (int32_t)((name == "max_loan" ? 1000 : 1) * _old_diff_custom[i++]);
sd->AsIntSetting()->MakeValueValidAndWrite(savegame ? &_settings_game : &_settings_newgame, value);
}
}

View File

@@ -17,6 +17,8 @@
#include "../roadstop_base.h"
#include "../vehicle_base.h"
#include "../newgrf_station.h"
#include "../newgrf_roadstop.h"
#include "../timer/timer_game_calendar.h"
#include "table/strings.h"
@@ -66,7 +68,7 @@ void MoveBuoysToWaypoints()
Town *town = st->town;
StringID string_id = st->string_id;
std::string name = st->name;
Date build_date = st->build_date;
TimerGameCalendar::Date build_date = st->build_date;
/* TTDPatch could use "buoys with rail station" for rail waypoints */
bool train = st->train_station.tile != INVALID_TILE;
TileArea train_st = st->train_station;
@@ -90,9 +92,10 @@ void MoveBuoysToWaypoints()
if (train) {
/* When we make a rail waypoint of the station, convert the map as well. */
for (TileIndex t : train_st) {
if (!IsTileType(t, MP_STATION) || GetStationIndex(t) != index) continue;
Tile tile(t);
if (!IsTileType(tile, MP_STATION) || GetStationIndex(tile) != index) continue;
SB(_me[t].m6, 3, 3, STATION_WAYPOINT);
SB(tile.m6(), 3, 3, STATION_WAYPOINT);
wp->rect.BeforeAddTile(t, StationRect::ADD_FORCE);
}
@@ -114,6 +117,11 @@ void AfterLoadStations()
st->speclist[i].spec = StationClass::GetByGrf(st->speclist[i].grfid, st->speclist[i].localidx, nullptr);
}
for (uint i = 0; i < st->roadstop_speclist.size(); i++) {
if (st->roadstop_speclist[i].grfid == 0) continue;
st->roadstop_speclist[i].spec = RoadStopClass::GetByGrf(st->roadstop_speclist[i].grfid, st->roadstop_speclist[i].localidx, nullptr);
}
if (Station::IsExpected(st)) {
Station *sta = Station::From(st);
@@ -122,6 +130,7 @@ void AfterLoadStations()
}
StationUpdateCachedTriggers(st);
RoadStopUpdateCachedTriggers(st);
}
}
@@ -149,21 +158,21 @@ static const SaveLoad _roadstop_desc[] = {
SLE_REF(RoadStop, next, REF_ROADSTOPS),
};
static uint16 _waiting_acceptance;
static uint32 _old_num_flows;
static uint16 _cargo_source;
static uint32 _cargo_source_xy;
static uint8 _cargo_days;
static uint16_t _waiting_acceptance;
static uint32_t _old_num_flows;
static uint16_t _cargo_source;
static uint32_t _cargo_source_xy;
static uint8_t _cargo_periods;
static Money _cargo_feeder_share;
std::list<CargoPacket *> _packets;
uint32 _old_num_dests;
uint32_t _old_num_dests;
struct FlowSaveLoad {
FlowSaveLoad() : source(0), via(0), share(0), restricted(false) {}
StationID source;
StationID via;
uint32 share;
uint32_t share;
bool restricted;
};
@@ -196,12 +205,13 @@ static void SwapPackets(GoodsEntry *ge)
class SlStationSpecList : public DefaultSaveLoadHandler<SlStationSpecList, BaseStation> {
public:
inline static const SaveLoad description[] = {
SLE_CONDVAR(StationSpecList, grfid, SLE_UINT32, SLV_27, SL_MAX_VERSION),
SLE_CONDVAR(StationSpecList, localidx, SLE_UINT8, SLV_27, SL_MAX_VERSION),
SLE_CONDVAR(StationSpecList, grfid, SLE_UINT32, SLV_27, SL_MAX_VERSION),
SLE_CONDVAR(StationSpecList, localidx, SLE_FILE_U8 | SLE_VAR_U16, SLV_27, SLV_EXTEND_ENTITY_MAPPING),
SLE_CONDVAR(StationSpecList, localidx, SLE_UINT16, SLV_EXTEND_ENTITY_MAPPING, SL_MAX_VERSION),
};
inline const static SaveLoadCompatTable compat_description = _station_spec_list_sl_compat;
static uint8 last_num_specs; ///< Number of specs of the last loaded station.
static uint8_t last_num_specs; ///< Number of specs of the last loaded station.
void Save(BaseStation *bst) const override
{
@@ -213,7 +223,7 @@ public:
void Load(BaseStation *bst) const override
{
uint8 num_specs = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? last_num_specs : (uint8)SlGetStructListLength(UINT8_MAX);
uint8_t num_specs = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? last_num_specs : (uint8_t)SlGetStructListLength(UINT8_MAX);
bst->speclist.resize(num_specs);
for (uint i = 0; i < num_specs; i++) {
@@ -222,7 +232,35 @@ public:
}
};
uint8 SlStationSpecList::last_num_specs;
uint8_t SlStationSpecList::last_num_specs;
class SlRoadStopSpecList : public DefaultSaveLoadHandler<SlRoadStopSpecList, BaseStation> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(RoadStopSpecList, grfid, SLE_UINT32),
SLE_CONDVAR(RoadStopSpecList, localidx, SLE_FILE_U8 | SLE_VAR_U16, SLV_27, SLV_EXTEND_ENTITY_MAPPING),
SLE_CONDVAR(RoadStopSpecList, localidx, SLE_UINT16, SLV_EXTEND_ENTITY_MAPPING, SL_MAX_VERSION),
};
inline const static SaveLoadCompatTable compat_description = _station_road_stop_spec_list_sl_compat;
void Save(BaseStation *bst) const override
{
SlSetStructListLength(bst->roadstop_speclist.size());
for (uint i = 0; i < bst->roadstop_speclist.size(); i++) {
SlObject(&bst->roadstop_speclist[i], this->GetDescription());
}
}
void Load(BaseStation *bst) const override
{
uint8_t num_specs = (uint8_t)SlGetStructListLength(UINT8_MAX);
bst->roadstop_speclist.resize(num_specs);
for (uint i = 0; i < num_specs; i++) {
SlObject(&bst->roadstop_speclist[i], this->GetLoadDescription());
}
}
};
class SlStationCargo : public DefaultSaveLoadHandler<SlStationCargo, GoodsEntry> {
public:
@@ -272,22 +310,22 @@ public:
void Save(GoodsEntry *ge) const override
{
uint32 num_flows = 0;
for (FlowStatMap::const_iterator it(ge->flows.begin()); it != ge->flows.end(); ++it) {
num_flows += (uint32)it->second.GetShares()->size();
size_t num_flows = 0;
for (const auto &it : ge->flows) {
num_flows += it.second.GetShares()->size();
}
SlSetStructListLength(num_flows);
for (FlowStatMap::const_iterator outer_it(ge->flows.begin()); outer_it != ge->flows.end(); ++outer_it) {
const FlowStat::SharesMap *shares = outer_it->second.GetShares();
uint32 sum_shares = 0;
for (const auto &outer_it : ge->flows) {
const FlowStat::SharesMap *shares = outer_it.second.GetShares();
uint32_t sum_shares = 0;
FlowSaveLoad flow;
flow.source = outer_it->first;
for (FlowStat::SharesMap::const_iterator inner_it(shares->begin()); inner_it != shares->end(); ++inner_it) {
flow.via = inner_it->second;
flow.share = inner_it->first - sum_shares;
flow.restricted = inner_it->first > outer_it->second.GetUnrestricted();
sum_shares = inner_it->first;
flow.source = outer_it.first;
for (auto &inner_it : *shares) {
flow.via = inner_it.second;
flow.share = inner_it.first - sum_shares;
flow.restricted = inner_it.first > outer_it.second.GetUnrestricted();
sum_shares = inner_it.first;
assert(flow.share > 0);
SlObject(&flow, this->GetDescription());
}
@@ -301,7 +339,7 @@ public:
FlowSaveLoad flow;
FlowStat *fs = nullptr;
StationID prev_source = INVALID_STATION;
for (uint32 j = 0; j < num_flows; ++j) {
for (uint32_t j = 0; j < num_flows; ++j) {
SlObject(&flow, this->GetLoadDescription());
if (fs == nullptr || prev_source != flow.source) {
fs = &(ge->flows.insert(std::make_pair(flow.source, FlowStat(flow.via, flow.share, flow.restricted))).first->second);
@@ -333,7 +371,7 @@ public:
SLEG_CONDVAR("cargo_source", _cargo_source, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_7),
SLEG_CONDVAR("cargo_source", _cargo_source, SLE_UINT16, SLV_7, SLV_68),
SLEG_CONDVAR("cargo_source_xy", _cargo_source_xy, SLE_UINT32, SLV_44, SLV_68),
SLEG_CONDVAR("cargo_days", _cargo_days, SLE_UINT8, SL_MIN_VERSION, SLV_68),
SLEG_CONDVAR("cargo_days", _cargo_periods, SLE_UINT8, SL_MIN_VERSION, SLV_68),
SLE_VAR(GoodsEntry, last_speed, SLE_UINT8),
SLE_VAR(GoodsEntry, last_age, SLE_UINT8),
SLEG_CONDVAR("cargo_feeder_share", _cargo_feeder_share, SLE_FILE_U32 | SLE_VAR_I64, SLV_14, SLV_65),
@@ -374,8 +412,8 @@ public:
SlSetStructListLength(NUM_CARGO);
for (CargoID i = 0; i < NUM_CARGO; i++) {
SlObject(&st->goods[i], this->GetDescription());
for (GoodsEntry &ge : st->goods) {
SlObject(&ge, this->GetDescription());
}
}
@@ -388,18 +426,18 @@ public:
/* Store the old persistent storage. The GRFID will be added later. */
assert(PersistentStorage::CanAllocateItem());
st->airport.psa = new PersistentStorage(0, 0, 0);
memcpy(st->airport.psa->storage, _old_st_persistent_storage.storage, sizeof(_old_st_persistent_storage.storage));
std::copy(std::begin(_old_st_persistent_storage.storage), std::end(_old_st_persistent_storage.storage), std::begin(st->airport.psa->storage));
}
size_t num_cargo = this->GetNumCargo();
for (CargoID i = 0; i < num_cargo; i++) {
GoodsEntry *ge = &st->goods[i];
SlObject(ge, this->GetLoadDescription());
auto end = std::next(std::begin(st->goods), std::min(this->GetNumCargo(), std::size(st->goods)));
for (auto it = std::begin(st->goods); it != end; ++it) {
GoodsEntry &ge = *it;
SlObject(&ge, this->GetLoadDescription());
if (IsSavegameVersionBefore(SLV_183)) {
SwapPackets(ge);
SwapPackets(&ge);
}
if (IsSavegameVersionBefore(SLV_68)) {
SB(ge->status, GoodsEntry::GES_ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15));
SB(ge.status, GoodsEntry::GES_ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15));
if (GB(_waiting_acceptance, 0, 12) != 0) {
/* In old versions, enroute_from used 0xFF as INVALID_STATION */
StationID source = (IsSavegameVersionBefore(SLV_7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source;
@@ -411,9 +449,9 @@ public:
assert(CargoPacket::CanAllocateItem());
/* Don't construct the packet with station here, because that'll fail with old savegames */
CargoPacket *cp = new CargoPacket(GB(_waiting_acceptance, 0, 12), _cargo_days, source, _cargo_source_xy, _cargo_source_xy, _cargo_feeder_share);
ge->cargo.Append(cp, INVALID_STATION);
SB(ge->status, GoodsEntry::GES_RATING, 1, 1);
CargoPacket *cp = new CargoPacket(GB(_waiting_acceptance, 0, 12), _cargo_periods, source, _cargo_source_xy, _cargo_feeder_share);
ge.cargo.Append(cp, INVALID_STATION);
SB(ge.status, GoodsEntry::GES_RATING, 1, 1);
}
}
}
@@ -423,15 +461,16 @@ public:
{
Station *st = Station::From(bst);
uint num_cargo = IsSavegameVersionBefore(SLV_55) ? 12 : IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
for (CargoID i = 0; i < num_cargo; i++) {
GoodsEntry *ge = &st->goods[i];
size_t num_cargo = IsSavegameVersionBefore(SLV_55) ? 12 : IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
auto end = std::next(std::begin(st->goods), std::min(num_cargo, std::size(st->goods)));
for (auto it = std::begin(st->goods); it != end; ++it) {
GoodsEntry &ge = *it;
if (IsSavegameVersionBefore(SLV_183)) {
SwapPackets(ge); // We have to swap back again to be in the format pre-183 expects.
SlObject(ge, this->GetDescription());
SwapPackets(ge);
SwapPackets(&ge); // We have to swap back again to be in the format pre-183 expects.
SlObject(&ge, this->GetDescription());
SwapPackets(&ge);
} else {
SlObject(ge, this->GetDescription());
SlObject(&ge, this->GetDescription());
}
}
}
@@ -491,7 +530,7 @@ struct STNSChunkHandler : ChunkHandler {
const std::vector<SaveLoad> slt = SlCompatTableHeader(_old_station_desc, _old_station_sl_compat);
_cargo_source_xy = 0;
_cargo_days = 0;
_cargo_periods = 0;
_cargo_feeder_share = 0;
int index;
@@ -516,6 +555,35 @@ struct STNSChunkHandler : ChunkHandler {
}
};
class SlRoadStopTileData : public DefaultSaveLoadHandler<SlRoadStopTileData, BaseStation> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(RoadStopTileData, tile, SLE_UINT32),
SLE_VAR(RoadStopTileData, random_bits, SLE_UINT8),
SLE_VAR(RoadStopTileData, animation_frame, SLE_UINT8),
};
inline const static SaveLoadCompatTable compat_description = {};
static uint8_t last_num_specs; ///< Number of specs of the last loaded station.
void Save(BaseStation *bst) const override
{
SlSetStructListLength(bst->custom_roadstop_tile_data.size());
for (uint i = 0; i < bst->custom_roadstop_tile_data.size(); i++) {
SlObject(&bst->custom_roadstop_tile_data[i], this->GetDescription());
}
}
void Load(BaseStation *bst) const override
{
uint32_t num_tiles = (uint32_t)SlGetStructListLength(UINT32_MAX);
bst->custom_roadstop_tile_data.resize(num_tiles);
for (uint i = 0; i < num_tiles; i++) {
SlObject(&bst->custom_roadstop_tile_data[i], this->GetLoadDescription());
}
}
};
/**
* SaveLoad handler for the BaseStation, which all other stations / waypoints
* make use of.
@@ -593,23 +661,24 @@ public:
SLE_REFLIST(Station, loading_vehicles, REF_VEHICLE),
SLE_CONDVAR(Station, always_accepted, SLE_FILE_U32 | SLE_VAR_U64, SLV_127, SLV_EXTEND_CARGOTYPES),
SLE_CONDVAR(Station, always_accepted, SLE_UINT64, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST("speclist", SlRoadStopTileData, SLV_NEWGRF_ROAD_STOPS, SL_MAX_VERSION),
SLEG_STRUCTLIST("goods", SlStationGoods),
};
inline const static SaveLoadCompatTable compat_description = _station_normal_sl_compat;
void Save(BaseStation *bst) const
void Save(BaseStation *bst) const override
{
if ((bst->facilities & FACIL_WAYPOINT) != 0) return;
SlObject(bst, this->GetDescription());
}
void Load(BaseStation *bst) const
void Load(BaseStation *bst) const override
{
if ((bst->facilities & FACIL_WAYPOINT) != 0) return;
SlObject(bst, this->GetLoadDescription());
}
void FixPointers(BaseStation *bst) const
void FixPointers(BaseStation *bst) const override
{
if ((bst->facilities & FACIL_WAYPOINT) != 0) return;
SlObject(bst, this->GetDescription());
@@ -628,19 +697,19 @@ public:
};
inline const static SaveLoadCompatTable compat_description = _station_waypoint_sl_compat;
void Save(BaseStation *bst) const
void Save(BaseStation *bst) const override
{
if ((bst->facilities & FACIL_WAYPOINT) == 0) return;
SlObject(bst, this->GetDescription());
}
void Load(BaseStation *bst) const
void Load(BaseStation *bst) const override
{
if ((bst->facilities & FACIL_WAYPOINT) == 0) return;
SlObject(bst, this->GetLoadDescription());
}
void FixPointers(BaseStation *bst) const
void FixPointers(BaseStation *bst) const override
{
if ((bst->facilities & FACIL_WAYPOINT) == 0) return;
SlObject(bst, this->GetDescription());
@@ -652,6 +721,7 @@ static const SaveLoad _station_desc[] = {
SLEG_STRUCT("normal", SlStationNormal),
SLEG_STRUCT("waypoint", SlStationWaypoint),
SLEG_CONDSTRUCTLIST("speclist", SlStationSpecList, SLV_27, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST("roadstopspeclist", SlRoadStopSpecList, SLV_NEWGRF_ROAD_STOPS, SL_MAX_VERSION),
};
struct STNNChunkHandler : ChunkHandler {

View File

@@ -35,7 +35,7 @@ static const SaveLoad _story_page_elements_desc[] = {
SLE_CONDVAR(StoryPageElement, type, SLE_FILE_U16 | SLE_VAR_U8, SL_MIN_VERSION, SLV_185),
SLE_CONDVAR(StoryPageElement, type, SLE_UINT8, SLV_185, SL_MAX_VERSION),
SLE_VAR(StoryPageElement, referenced_id, SLE_UINT32),
SLE_STR(StoryPageElement, text, SLE_STR | SLF_ALLOW_CONTROL, 0),
SLE_SSTR(StoryPageElement, text, SLE_STR | SLF_ALLOW_CONTROL),
};
struct STPEChunkHandler : ChunkHandler {
@@ -56,7 +56,7 @@ struct STPEChunkHandler : ChunkHandler {
const std::vector<SaveLoad> slt = SlCompatTableHeader(_story_page_elements_desc, _story_page_elements_sl_compat);
int index;
uint32 max_sort_value = 0;
uint32_t max_sort_value = 0;
while ((index = SlIterateArray()) != -1) {
StoryPageElement *s = new (index) StoryPageElement();
SlObject(s, slt);
@@ -77,7 +77,7 @@ static const SaveLoad _story_pages_desc[] = {
SLE_VAR(StoryPage, date, SLE_UINT32),
SLE_CONDVAR(StoryPage, company, SLE_FILE_U16 | SLE_VAR_U8, SL_MIN_VERSION, SLV_185),
SLE_CONDVAR(StoryPage, company, SLE_UINT8, SLV_185, SL_MAX_VERSION),
SLE_STR(StoryPage, title, SLE_STR | SLF_ALLOW_CONTROL, 0),
SLE_SSTR(StoryPage, title, SLE_STR | SLF_ALLOW_CONTROL),
};
struct STPAChunkHandler : ChunkHandler {
@@ -98,7 +98,7 @@ struct STPAChunkHandler : ChunkHandler {
const std::vector<SaveLoad> slt = SlCompatTableHeader(_story_pages_desc, _story_pages_sl_compat);
int index;
uint32 max_sort_value = 0;
uint32_t max_sort_value = 0;
while ((index = SlIterateArray()) != -1) {
StoryPage *s = new (index) StoryPage();
SlObject(s, slt);

View File

@@ -8,6 +8,7 @@
/** @file strings_sl.cpp Code handling saving and loading of strings */
#include "../stdafx.h"
#include "../core/alloc_func.hpp"
#include "../string_func.h"
#include "../strings_func.h"
#include "saveload_internal.h"
@@ -69,7 +70,7 @@ std::string CopyFromOldName(StringID id)
std::ostringstream tmp;
std::ostreambuf_iterator<char> strto(tmp);
for (; *strfrom != '\0'; strfrom++) {
WChar c = (byte)*strfrom;
char32_t c = (byte)*strfrom;
/* Map from non-ISO8859-15 characters to UTF-8. */
switch (c) {

View File

@@ -38,7 +38,7 @@ void RebuildTownCaches()
town->cache.num_houses = 0;
}
for (TileIndex t = 0; t < MapSize(); t++) {
for (TileIndex t = 0; t < Map::Size(); t++) {
if (!IsTileType(t, MP_HOUSE)) continue;
HouseID house_id = GetHouseType(t);
@@ -66,7 +66,7 @@ void RebuildTownCaches()
*/
void UpdateHousesAndTowns()
{
for (TileIndex t = 0; t < MapSize(); t++) {
for (TileIndex t = 0; t < Map::Size(); t++) {
if (!IsTileType(t, MP_HOUSE)) continue;
HouseID house_id = GetCleanHouseType(t);
@@ -79,7 +79,7 @@ void UpdateHousesAndTowns()
}
/* Check for cases when a NewGRF has set a wrong house substitute type. */
for (TileIndex t = 0; t < MapSize(); t++) {
for (TileIndex t = 0; t < Map::Size(); t++) {
if (!IsTileType(t, MP_HOUSE)) continue;
HouseID house_type = GetCleanHouseType(t);
@@ -118,10 +118,10 @@ void UpdateHousesAndTowns()
class SlTownSupplied : public DefaultSaveLoadHandler<SlTownSupplied, Town> {
public:
inline static const SaveLoad description[] = {
SLE_CONDVAR(TransportedCargoStat<uint32>, old_max, SLE_UINT32, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint32>, new_max, SLE_UINT32, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint32>, old_act, SLE_UINT32, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint32>, new_act, SLE_UINT32, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint32_t>, old_max, SLE_UINT32, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint32_t>, new_max, SLE_UINT32, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint32_t>, old_act, SLE_UINT32, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint32_t>, new_act, SLE_UINT32, SLV_165, SL_MAX_VERSION),
};
inline const static SaveLoadCompatTable compat_description = _town_supplied_sl_compat;
@@ -139,16 +139,16 @@ public:
void Save(Town *t) const override
{
SlSetStructListLength(NUM_CARGO);
for (CargoID i = 0; i < NUM_CARGO; i++) {
SlObject(&t->supplied[i], this->GetDescription());
SlSetStructListLength(std::size(t->supplied));
for (auto &supplied : t->supplied) {
SlObject(&supplied, this->GetDescription());
}
}
void Load(Town *t) const override
{
size_t num_cargo = this->GetNumCargo();
for (CargoID i = 0; i < num_cargo; i++) {
for (size_t i = 0; i < num_cargo; i++) {
SlObject(&t->supplied[i], this->GetLoadDescription());
}
}
@@ -157,24 +157,24 @@ public:
class SlTownReceived : public DefaultSaveLoadHandler<SlTownReceived, Town> {
public:
inline static const SaveLoad description[] = {
SLE_CONDVAR(TransportedCargoStat<uint16>, old_max, SLE_UINT16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16>, new_max, SLE_UINT16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16>, old_act, SLE_UINT16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16>, new_act, SLE_UINT16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16_t>, old_max, SLE_UINT16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16_t>, new_max, SLE_UINT16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16_t>, old_act, SLE_UINT16, SLV_165, SL_MAX_VERSION),
SLE_CONDVAR(TransportedCargoStat<uint16_t>, new_act, SLE_UINT16, SLV_165, SL_MAX_VERSION),
};
inline const static SaveLoadCompatTable compat_description = _town_received_sl_compat;
void Save(Town *t) const override
{
SlSetStructListLength(NUM_TE);
for (size_t i = TE_BEGIN; i < TE_END; i++) {
SlObject(&t->received[i], this->GetDescription());
SlSetStructListLength(std::size(t->received));
for (auto &received : t->received) {
SlObject(&received, this->GetDescription());
}
}
void Load(Town *t) const override
{
size_t length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? (size_t)TE_END : SlGetStructListLength(TE_END);
size_t length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? (size_t)TAE_END : SlGetStructListLength(TAE_END);
for (size_t i = 0; i < length; i++) {
SlObject(&t->received[i], this->GetLoadDescription());
}
@@ -190,7 +190,7 @@ public:
};
inline const static SaveLoadCompatTable compat_description = _town_acceptance_matrix_sl_compat;
void Load(Town *t) const override
void Load(Town *) const override
{
/* Discard now unused acceptance matrix. */
AcceptanceMatrix dummy;
@@ -239,12 +239,12 @@ static const SaveLoad _town_desc[] = {
SLE_CONDVAR(Town, supplied[CT_MAIL].new_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_MAIL].new_act, SLE_UINT32, SLV_9, SLV_165),
SLE_CONDVAR(Town, received[TE_FOOD].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVAR(Town, received[TE_WATER].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVAR(Town, received[TE_FOOD].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVAR(Town, received[TE_WATER].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVARNAME(Town, received[TAE_FOOD].old_act, "received[TE_FOOD].old_act", SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVARNAME(Town, received[TAE_WATER].old_act, "received[TE_WATER].old_act", SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVARNAME(Town, received[TAE_FOOD].new_act, "received[TE_FOOD].new_act", SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVARNAME(Town, received[TAE_WATER].new_act, "received[TE_WATER].new_act", SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDARR(Town, goal, SLE_UINT32, NUM_TE, SLV_165, SL_MAX_VERSION),
SLE_CONDARR(Town, goal, SLE_UINT32, NUM_TAE, SLV_165, SL_MAX_VERSION),
SLE_CONDSSTR(Town, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_168, SL_MAX_VERSION),

View File

@@ -17,13 +17,13 @@
#include "../roadveh.h"
#include "../ship.h"
#include "../aircraft.h"
#include "../timetable.h"
#include "../station_base.h"
#include "../effectvehicle_base.h"
#include "../company_base.h"
#include "../company_func.h"
#include "../disaster_vehicle.h"
#include <map>
#include "../economy_base.h"
#include "../safeguards.h"
@@ -199,6 +199,19 @@ void UpdateOldAircraft()
SetAircraftPosition(a, gp.x, gp.y, GetAircraftFlightLevel(a));
}
}
/* Clear aircraft from loading vehicles, if we bumped them into the air. */
for (Station *st : Station::Iterate()) {
for (auto iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end(); /* nothing */) {
Vehicle *v = *iter;
if (v->type == VEH_AIRCRAFT && !v->current_order.IsType(OT_LOADING)) {
iter = st->loading_vehicles.erase(iter);
delete v->cargo_payment;
} else {
++iter;
}
}
}
}
/**
@@ -375,6 +388,16 @@ void AfterLoadVehicles(bool part_of_load)
s->rotation_y_pos = s->y_pos;
}
}
if (IsSavegameVersionBefore(SLV_TIMETABLE_START_TICKS)) {
/* Convert timetable start from a date to an absolute tick in TimerGameTick::counter. */
for (Vehicle *v : Vehicle::Iterate()) {
/* If the start date is 0, the vehicle is not waiting to start and can be ignored. */
if (v->timetable_start == 0) continue;
v->timetable_start = GetStartTickFromDate(v->timetable_start);
}
}
}
CheckValidVehicles();
@@ -456,13 +479,17 @@ void AfterLoadVehicles(bool part_of_load)
if (Aircraft::From(v)->IsNormalAircraft()) {
v->GetImage(v->direction, EIT_ON_MAP, &v->sprite_cache.sprite_seq);
/* The plane's shadow will have the same image as the plane, but no colour */
/* The aircraft's shadow will have the same image as the aircraft, but no colour */
Vehicle *shadow = v->Next();
if (shadow == nullptr) SlErrorCorrupt("Missing shadow for aircraft");
shadow->sprite_cache.sprite_seq.CopyWithoutPalette(v->sprite_cache.sprite_seq);
/* In the case of a helicopter we will update the rotor sprites */
if (v->subtype == AIR_HELICOPTER) {
Vehicle *rotor = shadow->Next();
if (rotor == nullptr) SlErrorCorrupt("Missing rotor for helicopter");
GetRotorImage(Aircraft::From(v), EIT_ON_MAP, &rotor->sprite_cache.sprite_seq);
}
@@ -569,13 +596,12 @@ void FixupTrainLengths()
}
}
static uint8 _cargo_days;
static uint16 _cargo_source;
static uint32 _cargo_source_xy;
static uint16 _cargo_count;
static uint16 _cargo_paid_for;
static uint8_t _cargo_periods;
static uint16_t _cargo_source;
static uint32_t _cargo_source_xy;
static uint16_t _cargo_count;
static uint16_t _cargo_paid_for;
static Money _cargo_feeder_share;
static uint32 _cargo_loaded_at_xy;
class SlVehicleCommon : public DefaultSaveLoadHandler<SlVehicleCommon, Vehicle> {
public:
@@ -626,7 +652,7 @@ public:
SLE_VAR(Vehicle, cargo_type, SLE_UINT8),
SLE_CONDVAR(Vehicle, cargo_subtype, SLE_UINT8, SLV_35, SL_MAX_VERSION),
SLEG_CONDVAR("cargo_days", _cargo_days, SLE_UINT8, SL_MIN_VERSION, SLV_68),
SLEG_CONDVAR("cargo_days", _cargo_periods, SLE_UINT8, SL_MIN_VERSION, SLV_68),
SLEG_CONDVAR("cargo_source", _cargo_source, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_7),
SLEG_CONDVAR("cargo_source", _cargo_source, SLE_UINT16, SLV_7, SLV_68),
SLEG_CONDVAR("cargo_source_xy", _cargo_source_xy, SLE_UINT32, SLV_44, SLV_68),
@@ -662,7 +688,8 @@ public:
SLE_CONDVAR(Vehicle, current_order.wait_time, SLE_UINT16, SLV_67, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, current_order.travel_time, SLE_UINT16, SLV_67, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, current_order.max_speed, SLE_UINT16, SLV_174, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, timetable_start, SLE_INT32, SLV_129, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, timetable_start, SLE_FILE_I32 | SLE_VAR_U64, SLV_129, SLV_TIMETABLE_START_TICKS),
SLE_CONDVAR(Vehicle, timetable_start, SLE_UINT64, SLV_TIMETABLE_START_TICKS, SL_MAX_VERSION),
SLE_CONDREF(Vehicle, orders, REF_ORDER, SL_MIN_VERSION, SLV_105),
SLE_CONDREF(Vehicle, orders, REF_ORDERLIST, SLV_105, SL_MAX_VERSION),
@@ -673,6 +700,7 @@ public:
SLE_CONDVAR(Vehicle, max_age, SLE_INT32, SLV_31, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, date_of_last_service, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
SLE_CONDVAR(Vehicle, date_of_last_service, SLE_INT32, SLV_31, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, date_of_last_service_newgrf, SLE_INT32, SLV_NEWGRF_LAST_SERVICE, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, service_interval, SLE_UINT16, SL_MIN_VERSION, SLV_31),
SLE_CONDVAR(Vehicle, service_interval, SLE_FILE_U32 | SLE_VAR_U16, SLV_31, SLV_180),
SLE_CONDVAR(Vehicle, service_interval, SLE_UINT16, SLV_180, SL_MAX_VERSION),
@@ -696,19 +724,24 @@ public:
SLE_CONDVAR(Vehicle, profit_last_year, SLE_INT64, SLV_65, SL_MAX_VERSION),
SLEG_CONDVAR("cargo_feeder_share", _cargo_feeder_share, SLE_FILE_I32 | SLE_VAR_I64, SLV_51, SLV_65),
SLEG_CONDVAR("cargo_feeder_share", _cargo_feeder_share, SLE_INT64, SLV_65, SLV_68),
SLEG_CONDVAR("cargo_loaded_at_xy", _cargo_loaded_at_xy, SLE_UINT32, SLV_51, SLV_68),
SLE_CONDVAR(Vehicle, value, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_65),
SLE_CONDVAR(Vehicle, value, SLE_INT64, SLV_65, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, random_bits, SLE_UINT8, SLV_2, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, random_bits, SLE_FILE_U8 | SLE_VAR_U16, SLV_2, SLV_EXTEND_VEHICLE_RANDOM),
SLE_CONDVAR(Vehicle, random_bits, SLE_UINT16, SLV_EXTEND_VEHICLE_RANDOM, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, waiting_triggers, SLE_UINT8, SLV_2, SL_MAX_VERSION),
SLE_CONDREF(Vehicle, next_shared, REF_VEHICLE, SLV_2, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, group_id, SLE_UINT16, SLV_60, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, current_order_time, SLE_UINT32, SLV_67, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, current_order_time, SLE_FILE_U32 | SLE_VAR_I32, SLV_67, SLV_TIMETABLE_TICKS_TYPE),
SLE_CONDVAR(Vehicle, current_order_time, SLE_INT32, SLV_TIMETABLE_TICKS_TYPE, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, last_loading_tick, SLE_UINT64, SLV_LAST_LOADING_TICK, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, lateness_counter, SLE_INT32, SLV_67, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, depot_unbunching_last_departure, SLE_UINT64, SLV_DEPOT_UNBUNCHING, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, depot_unbunching_next_departure, SLE_UINT64, SLV_DEPOT_UNBUNCHING, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, round_trip_time, SLE_INT32, SLV_DEPOT_UNBUNCHING, SL_MAX_VERSION),
};
#if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916)
return description;
@@ -948,8 +981,9 @@ public:
SLE_VAR(Vehicle, owner, SLE_UINT8),
SLE_VAR(Vehicle, vehstatus, SLE_UINT8),
SLE_CONDVAR(Vehicle, current_order.dest, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5),
SLE_CONDVAR(Vehicle, current_order.dest, SLE_UINT16, SLV_5, SL_MAX_VERSION),
SLE_CONDVARNAME(DisasterVehicle, state, "current_order.dest", SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5),
SLE_CONDVARNAME(DisasterVehicle, state, "current_order.dest", SLE_UINT16, SLV_5, SLV_DISASTER_VEH_STATE),
SLE_CONDVAR(DisasterVehicle, state, SLE_UINT16, SLV_DISASTER_VEH_STATE, SL_MAX_VERSION),
SLE_VAR(Vehicle, sprite_cache.sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32),
SLE_CONDVAR(Vehicle, age, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
@@ -1038,7 +1072,7 @@ struct VEHSChunkHandler : ChunkHandler {
if (_cargo_count != 0 && IsCompanyBuildableVehicleType(v) && CargoPacket::CanAllocateItem()) {
/* Don't construct the packet with station here, because that'll fail with old savegames */
CargoPacket *cp = new CargoPacket(_cargo_count, _cargo_days, _cargo_source, _cargo_source_xy, _cargo_loaded_at_xy, _cargo_feeder_share);
CargoPacket *cp = new CargoPacket(_cargo_count, _cargo_periods, _cargo_source, _cargo_source_xy, _cargo_feeder_share);
v->cargo.Append(cp);
}

View File

@@ -0,0 +1,32 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file water_regions_sl.cpp Handles saving and loading of water region data */
#include "../stdafx.h"
#include "saveload.h"
#include "../safeguards.h"
extern void SlSkipArray();
/* Water Region savegame data is no longer used, but still needed for old savegames to load without errors. */
struct WaterRegionChunkHandler : ChunkHandler {
WaterRegionChunkHandler() : ChunkHandler('WRGN', CH_READONLY)
{}
void Load() const override
{
SlTableHeader({});
SlSkipArray();
};
};
static const WaterRegionChunkHandler WRGN;
static const ChunkHandlerRef water_region_chunk_handlers[] = { WRGN };
extern const ChunkHandlerTable _water_region_chunk_handlers(water_region_chunk_handlers);

View File

@@ -14,6 +14,7 @@
#include "../vehicle_base.h"
#include "../town.h"
#include "../newgrf.h"
#include "../timer/timer_game_calendar.h"
#include "table/strings.h"
@@ -27,13 +28,13 @@ struct OldWaypoint {
TileIndex xy;
TownID town_index;
Town *town;
uint16 town_cn;
uint16_t town_cn;
StringID string_id;
std::string name;
uint8 delete_ctr;
Date build_date;
uint8 localidx;
uint32 grfid;
uint8_t delete_ctr;
TimerGameCalendar::Date build_date;
uint8_t localidx;
uint32_t grfid;
const StationSpec *spec;
Owner owner;
@@ -74,17 +75,18 @@ void MoveWaypointsToBaseStations()
if (wp.delete_ctr != 0) continue; // The waypoint was deleted
/* Waypoint indices were not added to the map prior to this. */
_m[wp.xy].m2 = (StationID)wp.index;
Tile tile = wp.xy;
tile.m2() = (StationID)wp.index;
if (HasBit(_m[wp.xy].m3, 4)) {
wp.spec = StationClass::Get(STAT_CLASS_WAYP)->GetSpec(_m[wp.xy].m4 + 1);
if (HasBit(tile.m3(), 4)) {
wp.spec = StationClass::Get(STAT_CLASS_WAYP)->GetSpec(tile.m4() + 1);
}
}
} else {
/* As of version 17, we recalculate the custom graphic ID of waypoints
* from the GRF ID / station index. */
for (OldWaypoint &wp : _old_waypoints) {
StationClass* stclass = StationClass::Get(STAT_CLASS_WAYP);
StationClass *stclass = StationClass::Get(STAT_CLASS_WAYP);
for (uint i = 0; i < stclass->GetSpecCount(); i++) {
const StationSpec *statspec = stclass->GetSpec(i);
if (statspec != nullptr && statspec->grf_prop.grffile->grfid == wp.grfid && statspec->grf_prop.local_id == wp.localidx) {
@@ -102,16 +104,16 @@ void MoveWaypointsToBaseStations()
TileIndex t = wp.xy;
/* Sometimes waypoint (sign) locations became disconnected from their actual location in
* the map array. If this is the case, try to locate the actual location in the map array */
if (!IsTileType(t, MP_RAILWAY) || GetRailTileType(t) != 2 /* RAIL_TILE_WAYPOINT */ || _m[t].m2 != wp.index) {
if (!IsTileType(t, MP_RAILWAY) || GetRailTileType(t) != 2 /* RAIL_TILE_WAYPOINT */ || Tile(t).m2() != wp.index) {
Debug(sl, 0, "Found waypoint tile {} with invalid position", t);
for (t = 0; t < MapSize(); t++) {
if (IsTileType(t, MP_RAILWAY) && GetRailTileType(t) == 2 /* RAIL_TILE_WAYPOINT */ && _m[t].m2 == wp.index) {
for (t = 0; t < Map::Size(); t++) {
if (IsTileType(t, MP_RAILWAY) && GetRailTileType(t) == 2 /* RAIL_TILE_WAYPOINT */ && Tile(t).m2() == wp.index) {
Debug(sl, 0, "Found actual waypoint position at {}", t);
break;
}
}
}
if (t == MapSize()) {
if (t == Map::Size()) {
SlErrorCorrupt("Waypoint with invalid tile");
}
@@ -125,19 +127,20 @@ void MoveWaypointsToBaseStations()
new_wp->string_id = STR_SV_STNAME_WAYPOINT;
/* The tile might've been reserved! */
bool reserved = !IsSavegameVersionBefore(SLV_100) && HasBit(_m[t].m5, 4);
Tile tile(t);
bool reserved = !IsSavegameVersionBefore(SLV_100) && HasBit(tile.m5(), 4);
/* The tile really has our waypoint, so reassign the map array */
MakeRailWaypoint(t, GetTileOwner(t), new_wp->index, (Axis)GB(_m[t].m5, 0, 1), 0, GetRailType(t));
MakeRailWaypoint(tile, GetTileOwner(tile), new_wp->index, (Axis)GB(tile.m5(), 0, 1), 0, GetRailType(tile));
new_wp->facilities |= FACIL_TRAIN;
new_wp->owner = GetTileOwner(t);
new_wp->owner = GetTileOwner(tile);
SetRailStationReservation(t, reserved);
SetRailStationReservation(tile, reserved);
if (wp.spec != nullptr) {
SetCustomStationSpecIndex(t, AllocateSpecToStation(wp.spec, new_wp, true));
SetCustomStationSpecIndex(tile, AllocateSpecToStation(wp.spec, new_wp, true));
}
new_wp->rect.BeforeAddTile(t, StationRect::ADD_FORCE);
new_wp->rect.BeforeAddTile(tile, StationRect::ADD_FORCE);
wp.new_index = new_wp->index;
}