Changeset - r26194:f7347205838e
[Not reviewed]
Ruby Dennington (Theleruby) - 2 years ago 2022-03-20 13:57:20
theleruby@gmail.com
Ginever.net OpenTTD Patchpack 6.0.0
87 files changed:
Changeset was too big and was cut off... Show full diff anyway
0 comments (0 inline, 0 general)
.gitignore
Show inline comments
 
@@ -5,3 +5,6 @@ docs/aidocs/*
 
docs/gamedocs/*
 
docs/source/*
 
/out
 
/.ottdrev-gpp
 
/media/baseset/openttd.grf
 
/media/baseset/orig_extra.grf
 
\ No newline at end of file
cmake/scripts/FindVersion.cmake
Show inline comments
 
@@ -103,6 +103,20 @@ if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_
 

	
 
    # Restore LC_ALL
 
    set(ENV{LC_ALL} "${SAVED_LC_ALL}")
 
elseif(EXISTS "${CMAKE_SOURCE_DIR}/versiondump.py")
 
    execute_process(COMMAND py -3 versiondump.py
 
                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
 
    )
 
    file(READ "${CMAKE_SOURCE_DIR}/.ottdrev-gpp" OTTDREV)
 
    string(REPLACE "\n" "" OTTDREV "${OTTDREV}")
 
    string(REPLACE "\t" ";" OTTDREV "${OTTDREV}")
 
    list(GET OTTDREV 0 REV_VERSION)
 
    list(GET OTTDREV 1 REV_ISODATE)
 
    list(GET OTTDREV 2 REV_MODIFIED)
 
    list(GET OTTDREV 3 REV_HASH)
 
    list(GET OTTDREV 4 REV_ISTAG)
 
    list(GET OTTDREV 5 REV_ISSTABLETAG)
 
    list(GET OTTDREV 6 REV_YEAR)
 
elseif(EXISTS "${CMAKE_SOURCE_DIR}/.ottdrev")
 
    file(READ "${CMAKE_SOURCE_DIR}/.ottdrev" OTTDREV)
 
    string(REPLACE "\n" "" OTTDREV "${OTTDREV}")
media/baseset/openttd.grf
Show inline comments
 
deleted file
 
binary diff not shown
media/baseset/orig_extra.grf
Show inline comments
 
deleted file
 
binary diff not shown
src/CMakeLists.txt
Show inline comments
 
@@ -407,6 +407,7 @@ add_files(
 
    string.cpp
 
    string_base.h
 
    string_func.h
 
    string_func_extra.h
 
    string_type.h
 
    stringfilter.cpp
 
    stringfilter_type.h
src/aircraft.h
Show inline comments
 
@@ -57,6 +57,7 @@ void UpdateAircraftCache(Aircraft *v, bo
 
void AircraftLeaveHangar(Aircraft *v, Direction exit_dir);
 
void AircraftNextAirportPos_and_Order(Aircraft *v);
 
void SetAircraftPosition(Aircraft *v, int x, int y, int z);
 
void FindBreakdownDestination(Aircraft *v);
 

	
 
void GetAircraftFlightLevelBounds(const Vehicle *v, int *min, int *max);
 
template <class T>
src/aircraft_cmd.cpp
Show inline comments
 
@@ -149,8 +149,8 @@ static StationID FindNearestHangar(const
 
		/* don't crash the plane if we know it can't land at the airport */
 
		if ((afc->flags & AirportFTAClass::SHORT_STRIP) && (avi->subtype & AIR_FAST) && !_cheats.no_jetcrash.value) continue;
 

	
 
		/* the plane won't land at any helicopter station */
 
		if (!(afc->flags & AirportFTAClass::AIRPLANES) && (avi->subtype & AIR_CTOL)) continue;
 
		/* the plane won't land at any helicopter station and vice versa*/
 
		if (!CanVehicleUseStation(v, st)) continue;
 

	
 
		/* Check if our last and next destinations can be reached from the depot airport. */
 
		if (max_range != 0) {
 
@@ -326,6 +326,9 @@ CommandCost CmdBuildAircraft(DoCommandFl
 

	
 
		v->reliability = e->reliability;
 
		v->reliability_spd_dec = e->reliability_spd_dec;
 
		/* higher speed means higher breakdown chance */
 
		/* to somewhat compensate for the fact that fast aircraft spend less time in the air */
 
		v->breakdown_chance = Clamp(64 + (AircraftVehInfo(v->engine_type)->max_speed >> 3), 0, 255);
 
		v->max_age = e->GetLifeLengthInDays();
 

	
 
		v->pos = GetVehiclePosOnBuild(tile);
 
@@ -437,6 +440,7 @@ Money Aircraft::GetRunningCost() const
 
{
 
	const Engine *e = this->GetEngine();
 
	uint cost_factor = GetVehicleProperty(this, PROP_AIRCRAFT_RUNNING_COST_FACTOR, e->u.air.running_cost);
 
	cost_factor *= _settings_game.economy.running_cost_multiplier_air;
 
	return GetPrice(PR_RUNNING_AIRCRAFT, cost_factor, e->GetGRF());
 
}
 

	
 
@@ -607,7 +611,7 @@ void UpdateAircraftCache(Aircraft *v, bo
 

	
 
	/* Update aircraft range. */
 
	if (update_range) {
 
		v->acache.cached_max_range = GetVehicleProperty(v, PROP_AIRCRAFT_RANGE, AircraftVehInfo(v->engine_type)->max_range);
 
		v->acache.cached_max_range = (GetVehicleProperty(v, PROP_AIRCRAFT_RANGE, AircraftVehInfo(v->engine_type)->max_range) * _settings_game.vehicle.plane_range_multiplier);
 
		/* Squared it now so we don't have to do it later all the time. */
 
		v->acache.cached_max_range_sqr = v->acache.cached_max_range * v->acache.cached_max_range;
 
	}
 
@@ -649,9 +653,17 @@ static int UpdateAircraftSpeed(Aircraft 
 
	speed_limit *= _settings_game.vehicle.plane_speed;
 

	
 
	/* adjust speed for broken vehicles */
 
	if (v->vehstatus & VS_AIRCRAFT_BROKEN) {
 
		if (SPEED_LIMIT_BROKEN < speed_limit) hard_limit = false;
 
		speed_limit = std::min<uint>(speed_limit, SPEED_LIMIT_BROKEN);
 
	if (v->breakdown_ctr == 1 && v->breakdown_type == BREAKDOWN_AIRCRAFT_SPEED) {
 
		if (v->breakdown_severity < 10)
 
		{
 
			// stupid workaround for fixing old saves with severity 0, also FGSP
 
			v->breakdown_severity = 10;
 
		}
 
		uint percentage_speed_limit = v->breakdown_severity;
 
		uint cached_max_speed = v->vcache.cached_max_speed;
 
		uint broken_down_max_speed = ((cached_max_speed * percentage_speed_limit) + 99) / 100;
 
		if (broken_down_max_speed < speed_limit) hard_limit = false;
 
		speed_limit = std::min<uint>(speed_limit, broken_down_max_speed);
 
	}
 

	
 
	if (v->vcache.cached_max_speed < speed_limit) {
 
@@ -1156,6 +1168,39 @@ static bool AircraftController(Aircraft 
 
}
 

	
 
/**
 
 * Send a broken plane that needs to visit a depot to the correct location.
 
 * @param v The airplane in question
 
 */
 
void FindBreakdownDestination(Aircraft *v)
 
{
 
	assert(v->type == VEH_AIRCRAFT && v->breakdown_ctr == 1);
 

	
 
	DestinationID destination = INVALID_STATION;
 
	if (v->breakdown_type == BREAKDOWN_AIRCRAFT_DEPOT) {
 
		/* Go to a hangar, if possible at our current destination */
 
		v->FindClosestDepot(NULL, &destination, NULL);
 
	} else if (v->breakdown_type == BREAKDOWN_AIRCRAFT_EM_LANDING) {
 
		/* Go to the nearest airport with a hangar */
 
		destination = FindNearestHangar(v);
 
	} else {
 
		NOT_REACHED();
 
	}
 

	
 
	if(destination != INVALID_STATION) {
 
		if(destination != v->current_order.GetDestination()) {
 
			v->current_order.MakeGoToDepot(destination, ODTFB_BREAKDOWN);
 
			AircraftNextAirportPos_and_Order(v);
 
		} else {
 
			v->current_order.MakeGoToDepot(destination, ODTFB_BREAKDOWN);
 
		}
 
	} else {
 
		/* If no hangar was found, crash */
 
		v->targetairport = INVALID_STATION;
 
		CrashAirplane(v);
 
	}
 
}
 

	
 
/**
 
 * Handle crashed aircraft \a v.
 
 * @param v Crashed aircraft.
 
 */
 
@@ -1235,8 +1280,9 @@ static void HandleAircraftSmoke(Aircraft
 

	
 
	if (!(v->vehstatus & VS_AIRCRAFT_BROKEN)) return;
 

	
 
	/* Stop smoking when landed */
 
	if (v->cur_speed < 10) {
 
	/* breakdown-related speed limits are lifted when we are on the ground */
 
	if(v->state != FLYING && v->state != LANDING && v->breakdown_type == BREAKDOWN_AIRCRAFT_SPEED) {
 
		/* Stop smoking when landed */
 
		v->vehstatus &= ~VS_AIRCRAFT_BROKEN;
 
		v->breakdown_ctr = 0;
 
		return;
 
@@ -1365,8 +1411,12 @@ static void MaybeCrashAirplane(Aircraft 
 
			(AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
 
			!_cheats.no_jetcrash.value) {
 
		prob = 3276;
 
	} else if (_settings_game.vehicle.plane_crashes == 0) {
 
		return;
 
	} else if (_settings_game.vehicle.improved_breakdowns && v->breakdown_ctr == 1 && v->breakdown_type == BREAKDOWN_AIRCRAFT_EM_LANDING) {
 
		/* Airplanes that are attempting an emergency landing have a 2% chance to crash */
 
		prob = 0x10000 / 50;
 
	} else {
 
		if (_settings_game.vehicle.plane_crashes == 0) return;
 
		prob = (0x4000 << _settings_game.vehicle.plane_crashes) / 1500;
 
	}
 

	
src/clear_cmd.cpp
Show inline comments
 
@@ -34,7 +34,7 @@ static CommandCost ClearTile_Clear(TileI
 
		PR_CLEAR_ROUGH,
 
		PR_CLEAR_ROUGH,
 
	};
 
	CommandCost price(EXPENSES_CONSTRUCTION);
 
	CommandCost price(EXPENSES_T_DEMOLITION);
 

	
 
	if (!IsClearGround(tile, CLEAR_GRASS) || GetClearDensity(tile) != 0) {
 
		price.AddCost(_price[clear_price_table[GetClearGround(tile)]]);
src/command_type.h
Show inline comments
 
@@ -22,7 +22,7 @@ struct GRFFile;
 
 * a possible error message/state together.
 
 */
 
class CommandCost {
 
	ExpensesType expense_type; ///< the type of expence as shown on the finances view
 
public: ExpensesType expense_type; ///< the type of expence as shown on the finances view
 
	Money cost;       ///< The cost of this action
 
	StringID message; ///< Warning message for when success is unset
 
	bool success;     ///< Whether the comment went fine up to this moment
src/company_cmd.cpp
Show inline comments
 
@@ -580,6 +580,8 @@ Company *DoStartupNewCompany(bool is_ai,
 
	AI::BroadcastNewEvent(new ScriptEventCompanyNew(c->index), c->index);
 
	Game::NewEvent(new ScriptEventCompanyNew(c->index));
 

	
 
	if (!is_ai) UpdateAllTownVirtCoords();
 

	
 
	return c;
 
}
 

	
src/company_gui.cpp
Show inline comments
 
@@ -70,6 +70,16 @@ static ExpensesType _expenses_list_1[] =
 
	EXPENSES_SHIP_INC,
 
	EXPENSES_LOAN_INT,
 
	EXPENSES_OTHER,
 
	EXPENSES_T_TRAIN_CON,
 
	EXPENSES_T_ROAD_CON,
 
	EXPENSES_T_AIRCRAFT_CON,
 
	EXPENSES_T_SHIP_CON,
 
	EXPENSES_T_TREES_CON,
 
	EXPENSES_T_SCENERY_CON,
 
	EXPENSES_T_LANDSCAPING,
 
	EXPENSES_T_DEMOLITION,
 
	EXPENSES_T_REWARD_INC,
 
	EXPENSES_T_DILAPIDATION,
 
};
 

	
 
/** Grouped list of expenses. */
 
@@ -78,16 +88,26 @@ static ExpensesType _expenses_list_2[] =
 
	EXPENSES_ROADVEH_INC,
 
	EXPENSES_AIRCRAFT_INC,
 
	EXPENSES_SHIP_INC,
 
	EXPENSES_T_REWARD_INC,
 
	INVALID_EXPENSES,
 
	EXPENSES_TRAIN_RUN,
 
	EXPENSES_ROADVEH_RUN,
 
	EXPENSES_AIRCRAFT_RUN,
 
	EXPENSES_SHIP_RUN,
 
	EXPENSES_PROPERTY,
 
	EXPENSES_T_DILAPIDATION,
 
	EXPENSES_LOAN_INT,
 
	INVALID_EXPENSES,
 
	EXPENSES_T_TRAIN_CON,
 
	EXPENSES_T_ROAD_CON,
 
	EXPENSES_T_AIRCRAFT_CON,
 
	EXPENSES_T_SHIP_CON,
 
	EXPENSES_T_TREES_CON,
 
	EXPENSES_T_SCENERY_CON,
 
	EXPENSES_CONSTRUCTION,
 
	EXPENSES_NEW_VEHICLES,
 
	EXPENSES_T_LANDSCAPING,
 
	EXPENSES_T_DEMOLITION,
 
	EXPENSES_OTHER,
 
	INVALID_EXPENSES,
 
};
src/company_type.h
Show inline comments
 
@@ -36,7 +36,7 @@ enum Owner : byte {
 
};
 
DECLARE_POSTFIX_INCREMENT(Owner)
 

	
 
static const uint MAX_LENGTH_PRESIDENT_NAME_CHARS = 32; ///< The maximum length of a president name in characters including '\0'
 
static const uint MAX_LENGTH_PRESIDENT_NAME_CHARS = 48; ///< The maximum length of a president name in characters including '\0'
 
static const uint MAX_LENGTH_COMPANY_NAME_CHARS   = 32; ///< The maximum length of a company name in characters including '\0'
 

	
 
static const uint MAX_HISTORY_QUARTERS            = 24; ///< The maximum number of quarters kept as performance's history
src/core/bitmath_func.hpp
Show inline comments
 
@@ -375,14 +375,33 @@ private:
 
	 * (since it will use hardware swapping if available).
 
	 * Even though they should return uint16 and uint32, we get
 
	 * warnings if we don't cast those (why?) */
 
#	define BSWAP64(x) (static_cast<uint64>(CFSwapInt64(x)))
 
#	define BSWAP32(x) (static_cast<uint32>(CFSwapInt32(x)))
 
#	define BSWAP16(x) (static_cast<uint16>(CFSwapInt16(x)))
 
#elif defined(_MSC_VER)
 
	/* MSVC has intrinsics for swapping, resulting in faster code */
 
#	define BSWAP64(x) (_byteswap_uint64(x))
 
#	define BSWAP32(x) (_byteswap_ulong(x))
 
#	define BSWAP16(x) (_byteswap_ushort(x))
 
#else
 
	/**
 
	 * Perform a 64 bits endianness bitswap on x.
 
	 * @param x the variable to bitswap
 
	 * @return the bitswapped value.
 
	 */
 
	static inline uint64 BSWAP64(uint64 x)
 
	{
 
#if !defined(__ICC) && (defined(__GNUC__) || defined(__clang__))
 
		/* GCC >= 4.3 provides a builtin, resulting in faster code */
 
		return (uint64)__builtin_bswap64((uint64)x);
 
#else
 
		return ((x >> 56) & 0xFFULL) | ((x >> 40) & 0xFF00ULL) | ((x >> 24) & 0xFF0000ULL) | ((x >> 8) & 0xFF000000ULL) |
 
				((x << 8) & 0xFF00000000ULL) | ((x << 24) & 0xFF0000000000ULL) | ((x << 40) & 0xFF000000000000ULL) | ((x << 56) & 0xFF00000000000000ULL);
 
				;
 
#endif /* __GNUC__ || __clang__ */
 
	}
 

	
 
	/**
 
	 * Perform a 32 bits endianness bitswap on x.
 
	 * @param x the variable to bitswap
 
	 * @return the bitswapped value.
src/core/endian_func.hpp
Show inline comments
 
@@ -17,25 +17,33 @@
 
#if TTD_ENDIAN == TTD_BIG_ENDIAN
 
#	define FROM_BE16(x) (x)
 
#	define FROM_BE32(x) (x)
 
#	define FROM_BE64(x) (x)
 
#	define TO_BE16(x)   (x)
 
#	define TO_BE32(x)   (x)
 
#	define TO_BE32X(x)  (x)
 
#	define TO_BE64(x)   (x)
 
#	define FROM_LE16(x) BSWAP16(x)
 
#	define FROM_LE32(x) BSWAP32(x)
 
#	define FROM_LE64(x) BSWAP64(x)
 
#	define TO_LE16(x)   BSWAP16(x)
 
#	define TO_LE32(x)   BSWAP32(x)
 
#	define TO_LE32X(x)  BSWAP32(x)
 
#	define TO_LE64(x)   BSWAP64(x)
 
#else
 
#	define FROM_BE16(x) BSWAP16(x)
 
#	define FROM_BE32(x) BSWAP32(x)
 
#	define FROM_BE64(x) BSWAP64(x)
 
#	define TO_BE16(x)   BSWAP16(x)
 
#	define TO_BE32(x)   BSWAP32(x)
 
#	define TO_BE32X(x)  BSWAP32(x)
 
#	define TO_BE64(x)   BSWAP64(x)
 
#	define FROM_LE16(x) (x)
 
#	define FROM_LE32(x) (x)
 
#	define FROM_LE64(x) (x)
 
#	define TO_LE16(x)   (x)
 
#	define TO_LE32(x)   (x)
 
#	define TO_LE32X(x)  (x)
 
#	define TO_LE64(x)   (x)
 
#endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
 

	
 
static inline uint16 ReadLE16Aligned(const void *x)
src/date.cpp
Show inline comments
 
@@ -36,7 +36,8 @@ uint16 _tick_counter;  ///< Ever increme
 
 */
 
void SetDate(Date date, DateFract fract)
 
{
 
	assert(fract < DAY_TICKS);
 
	//Get rid of this insane assert
 
	//assert(fract < DAY_TICKS);
 

	
 
	YearMonthDay ymd;
 

	
src/date_type.h
Show inline comments
 
@@ -25,19 +25,26 @@ typedef uint8  Day;   ///< Type for the 
 
 * 1 tick is approximately 30 ms.
 
 * 1 day is thus about 2 seconds (74 * 30 = 2220) on a machine that can run OpenTTD normally
 
 */
 
static const int DAY_TICKS         =  74; ///< ticks per day
 
static const int ORIG_DAY_TICKS    =  74; ///< unscaled ticks per day
 
static const int DAYS_IN_YEAR      = 365; ///< days per year
 
static const int DAYS_IN_LEAP_YEAR = 366; ///< sometimes, you need one day more...
 
static const int MONTHS_IN_YEAR    =  12; ///< months per year
 

	
 
/**
 
 * Day length in ticks, calculated using a configurable scale factor.
 
 */
 
#define DAY_TICKS (ORIG_DAY_TICKS * _settings_game.economy.daylength_multiplier)
 

	
 
static const int STATION_RATING_TICKS     = 185; ///< cycle duration for updating station rating
 
static const int STATION_ACCEPTANCE_TICKS = 250; ///< cycle duration for updating station acceptance
 
static const int STATION_LINKGRAPH_TICKS  = 504; ///< cycle duration for cleaning dead links
 
static const int CARGO_AGING_TICKS        = 185; ///< cycle duration for aging cargo
 
static const int INDUSTRY_PRODUCE_TICKS   = 256; ///< cycle duration for industry production
 
static const int TOWN_GROWTH_TICKS        = 70;  ///< cycle duration for towns trying to grow. (this originates from the size of the town array in TTD
 
static const int ORIG_TOWN_GROWTH_TICKS   = 70;  ///< cycle duration for towns trying to grow. (this originates from the size of the town array in TTD)
 
static const int INDUSTRY_CUT_TREE_TICKS  = INDUSTRY_PRODUCE_TICKS * 2; ///< cycle duration for lumber mill's extra action
 

	
 
#define TOWN_GROWTH_TICKS (ORIG_TOWN_GROWTH_TICKS * _settings_game.economy.town_growth_multiplier)
 

	
 

	
 
/*
 
 * ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR and DAYS_TILL_ORIGINAL_BASE_YEAR are
 
@@ -111,4 +118,7 @@ static const Year  INVALID_YEAR  = -1; /
 
static const Date  INVALID_DATE  = -1; ///< Representation of an invalid date
 
static const Ticks INVALID_TICKS = -1; ///< Representation of an invalid number of ticks
 

	
 
// daylength patch requirement
 
#include "settings_type.h"
 

	
 
#endif /* DATE_TYPE_H */
src/depot_type.h
Show inline comments
 
@@ -13,6 +13,6 @@
 
typedef uint16 DepotID; ///< Type for the unique identifier of depots.
 
struct Depot;
 

	
 
static const uint MAX_LENGTH_DEPOT_NAME_CHARS = 32; ///< The maximum length of a depot name in characters including '\0'
 
static const uint MAX_LENGTH_DEPOT_NAME_CHARS = 128; ///< The maximum length of a depot name in characters including '\0'
 

	
 
#endif /* DEPOT_TYPE_H */
src/disaster_vehicle.cpp
Show inline comments
 
@@ -362,6 +362,7 @@ static bool DisasterTick_Ufo(DisasterVeh
 
		uint dist = Delta(v->x_pos, u->x_pos) + Delta(v->y_pos, u->y_pos);
 

	
 
		if (dist < TILE_SIZE && !(u->vehstatus & VS_HIDDEN) && u->breakdown_ctr == 0) {
 
			u->breakdown_type = BREAKDOWN_CRITICAL;
 
			u->breakdown_ctr = 3;
 
			u->breakdown_delay = 140;
 
		}
 
@@ -547,6 +548,7 @@ static bool DisasterTick_Big_Ufo(Disaste
 
				if (Delta(target->x_pos, v->x_pos) + Delta(target->y_pos, v->y_pos) <= 12 * (int)TILE_SIZE) {
 
					target->breakdown_ctr = 5;
 
					target->breakdown_delay = 0xF0;
 
					target->breakdown_type = BREAKDOWN_CRITICAL;
 
				}
 
			}
 
		}
src/economy.cpp
Show inline comments
 
@@ -747,7 +747,32 @@ void RecomputePrices()
 

	
 
	/* Setup price bases */
 
	for (Price i = PR_BEGIN; i < PR_END; i++) {
 
		Money price = _price_base_specs[i].start_price;
 
		Money price;
 
		
 
		if (i == PR_INFRASTRUCTURE_RAIL)
 
		{
 
			price = _settings_game.economy.infrastructure_base_cost_rail;
 
		}
 
		else if (i == PR_INFRASTRUCTURE_ROAD)
 
		{
 
			price = _settings_game.economy.infrastructure_base_cost_road;
 
		}
 
		else if (i == PR_INFRASTRUCTURE_WATER)
 
		{
 
			price = _settings_game.economy.infrastructure_base_cost_water;
 
		}
 
		else if (i == PR_INFRASTRUCTURE_AIRPORT)
 
		{
 
			price = _settings_game.economy.infrastructure_base_cost_air;
 
		}
 
		else if (i == PR_INFRASTRUCTURE_STATION)
 
		{
 
			price = _settings_game.economy.infrastructure_base_cost_station;
 
		}
 
		else
 
		{
 
			price = _price_base_specs[i].start_price;
 
		}
 

	
 
		/* Apply difficulty settings */
 
		uint mod = 1;
src/economy_type.h
Show inline comments
 
@@ -155,7 +155,7 @@ typedef int8 PriceMultipliers[PR_END];
 

	
 
/** Types of expenses. */
 
enum ExpensesType : byte {
 
	EXPENSES_CONSTRUCTION =  0,   ///< Construction costs.
 
	EXPENSES_CONSTRUCTION =  0,   ///< Construction costs. [miscellaneous/unsorted]
 
	EXPENSES_NEW_VEHICLES,        ///< New vehicles.
 
	EXPENSES_TRAIN_RUN,           ///< Running costs trains.
 
	EXPENSES_ROADVEH_RUN,         ///< Running costs road vehicles.
 
@@ -168,6 +168,16 @@ enum ExpensesType : byte {
 
	EXPENSES_SHIP_INC,            ///< Income from ships.
 
	EXPENSES_LOAN_INT,            ///< Interest payments over the loan.
 
	EXPENSES_OTHER,               ///< Other expenses.
 
	EXPENSES_T_TRAIN_CON,
 
	EXPENSES_T_ROAD_CON,
 
	EXPENSES_T_AIRCRAFT_CON,
 
	EXPENSES_T_SHIP_CON,
 
	EXPENSES_T_TREES_CON,
 
	EXPENSES_T_SCENERY_CON,
 
	EXPENSES_T_LANDSCAPING,
 
	EXPENSES_T_DEMOLITION,
 
	EXPENSES_T_REWARD_INC,
 
	EXPENSES_T_DILAPIDATION,
 
	EXPENSES_END,                 ///< Number of expense types.
 
	INVALID_EXPENSES      = 0xFF, ///< Invalid expense type.
 
};
src/engine.cpp
Show inline comments
 
@@ -276,22 +276,26 @@ Money Engine::GetRunningCost() const
 
			base_price = this->u.road.running_cost_class;
 
			if (base_price == INVALID_PRICE) return 0;
 
			cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_RUNNING_COST_FACTOR, this->u.road.running_cost);
 
			cost_factor *= _settings_game.economy.running_cost_multiplier_road;
 
			break;
 

	
 
		case VEH_TRAIN:
 
			base_price = this->u.rail.running_cost_class;
 
			if (base_price == INVALID_PRICE) return 0;
 
			cost_factor = GetEngineProperty(this->index, PROP_TRAIN_RUNNING_COST_FACTOR, this->u.rail.running_cost);
 
			cost_factor *= _settings_game.economy.running_cost_multiplier_rail;
 
			break;
 

	
 
		case VEH_SHIP:
 
			base_price = PR_RUNNING_SHIP;
 
			cost_factor = GetEngineProperty(this->index, PROP_SHIP_RUNNING_COST_FACTOR, this->u.ship.running_cost);
 
			cost_factor *= _settings_game.economy.running_cost_multiplier_water;
 
			break;
 

	
 
		case VEH_AIRCRAFT:
 
			base_price = PR_RUNNING_AIRCRAFT;
 
			cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_RUNNING_COST_FACTOR, this->u.air.running_cost);
 
			cost_factor *= _settings_game.economy.running_cost_multiplier_air;
 
			break;
 

	
 
		default: NOT_REACHED();
 
@@ -443,7 +447,7 @@ uint16 Engine::GetRange() const
 
{
 
	switch (this->type) {
 
		case VEH_AIRCRAFT:
 
			return GetEngineProperty(this->index, PROP_AIRCRAFT_RANGE, this->u.air.max_range);
 
			return (GetEngineProperty(this->index, PROP_AIRCRAFT_RANGE, this->u.air.max_range) * _settings_game.vehicle.plane_range_multiplier);
 

	
 
		default: NOT_REACHED();
 
	}
src/engine_type.h
Show inline comments
 
@@ -170,7 +170,7 @@ enum EngineFlags {
 
	ENGINE_EXCLUSIVE_PREVIEW = 2, ///< This vehicle is in the exclusive preview stage, either being used or being offered to a company.
 
};
 

	
 
static const uint MAX_LENGTH_ENGINE_NAME_CHARS = 32; ///< The maximum length of an engine name in characters including '\0'
 
static const uint MAX_LENGTH_ENGINE_NAME_CHARS = 128; ///< The maximum length of an engine name in characters including '\0'
 

	
 
static const EngineID INVALID_ENGINE = 0xFFFF; ///< Constant denoting an invalid engine.
 

	
src/fios.h
Show inline comments
 
@@ -23,6 +23,12 @@ enum SaveLoadInvalidateWindowData {
 
	SLIWD_FILTER_CHANGES,        ///< The filename filter has changed (via the editbox)
 
};
 

	
 
enum PatchpackSaveExtensionType {
 
	PSXT_NONE,
 
	PSXT_MODIFIED,
 
	PSXT_EXTENDED
 
};
 

	
 
typedef SmallMap<uint, CompanyProperties *> CompanyPropertiesMap;
 

	
 
/**
 
@@ -45,6 +51,9 @@ struct LoadCheckData {
 

	
 
	struct LoggedAction *gamelog_action;          ///< Gamelog actions
 
	uint gamelog_actions;                         ///< Number of gamelog actions
 
	uint16 save_version;                          ///< Save version
 
	PatchpackSaveExtensionType save_ext_type;     ///< Extension type
 
	std::string save_version_label;               ///< Save version label
 

	
 
	LoadCheckData() : error_data(nullptr), grfconfig(nullptr),
 
			grf_compatibility(GLC_NOT_FOUND), gamelog_action(nullptr), gamelog_actions(0)
src/fios_gui.cpp
Show inline comments
 
@@ -54,6 +54,9 @@ void LoadCheckData::Clear()
 

	
 
	this->map_size_x = this->map_size_y = 256; // Default for old savegames which do not store mapsize.
 
	this->current_date = 0;
 
	this->save_version = SL_MIN_VERSION;
 
	this->save_ext_type = PSXT_NONE;
 
	this->save_version_label = "";
 
	this->settings = {};
 

	
 
	for (auto &pair : this->companies) {
 
@@ -471,6 +474,19 @@ public:
 
				uint y_max = r.bottom - FONT_HEIGHT_NORMAL - WD_FRAMERECT_BOTTOM;
 

	
 
				if (y > y_max) break;
 
				if (_load_check_data.checkable) {
 
					SetDParam(0, _load_check_data.save_version);
 
					SetDParamStr(1, _load_check_data.save_ext_type == PSXT_EXTENDED ? "X" : _load_check_data.save_ext_type == PSXT_MODIFIED ? "M"  : "");
 
					DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_SAVELOAD_VERSION_WITH_EXTENSION);
 
					y += FONT_HEIGHT_NORMAL;
 
					if (_load_check_data.save_version_label.length() > 0)
 
					{
 
						SetDParamStr(0, _load_check_data.save_version_label.c_str());
 
						DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_SAVELOAD_VERSION_LABEL);
 
						y += FONT_HEIGHT_NORMAL;
 
					}
 
					y += FONT_HEIGHT_NORMAL;
 
				}
 
				if (!_load_check_data.checkable) {
 
					/* Old savegame, no information available */
 
					DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_SAVELOAD_DETAIL_NOT_AVAILABLE);
src/gamelog.cpp
Show inline comments
 
@@ -51,8 +51,8 @@ static const char * GetGamelogRevisionSt
 
		return _openttd_revision;
 
	} else if (gamelog_revision[0] == 0) {
 
		/* Prefix character indication revision status */
 
		assert(_openttd_revision_modified < 3);
 
		gamelog_revision[0] = "gum"[_openttd_revision_modified]; // g = "git", u = "unknown", m = "modified"
 
		assert(_openttd_revision_modified < 5);
 
		gamelog_revision[0] = "gumhh"[_openttd_revision_modified]; // g = "git", u = "unknown", m = "modified", "h" = "hg"
 
		/* Append the revision hash */
 
		strecat(gamelog_revision, _openttd_revision_hash, lastof(gamelog_revision));
 
		/* Truncate string to GAMELOG_REVISION_LENGTH bytes */
src/ground_vehicle.cpp
Show inline comments
 
@@ -28,12 +28,9 @@ void GroundVehicle<T, Type>::PowerChange
 
	uint32 number_of_parts = 0;
 
	uint16 max_track_speed = this->vcache.cached_max_speed; // Max track speed in internal units.
 

	
 
	this->CalculatePower(total_power, max_te, false);
 
	
 
	for (const T *u = v; u != nullptr; u = u->Next()) {
 
		uint32 current_power = u->GetPower() + u->GetPoweredPartPower(u);
 
		total_power += current_power;
 

	
 
		/* Only powered parts add tractive effort. */
 
		if (current_power > 0) max_te += u->GetWeight() * u->GetTractiveEffort();
 
		number_of_parts++;
 

	
 
		/* Get minimum max speed for this track. */
 
@@ -56,8 +53,6 @@ void GroundVehicle<T, Type>::PowerChange
 

	
 
	this->gcache.cached_air_drag = air_drag + 3 * air_drag * number_of_parts / 20;
 

	
 
	max_te *= GROUND_ACCELERATION; // Tractive effort in (tonnes * 1000 * 9.8 =) N.
 
	max_te /= 256;  // Tractive effort is a [0-255] coefficient.
 
	if (this->gcache.cached_power != total_power || this->gcache.cached_max_te != max_te) {
 
		/* Stop the vehicle if it has no power. */
 
		if (total_power == 0) this->vehstatus |= VS_STOPPED;
 
@@ -71,6 +66,30 @@ void GroundVehicle<T, Type>::PowerChange
 
	this->gcache.cached_max_track_speed = max_track_speed;
 
}
 

	
 
template <class T, VehicleType Type>
 
void GroundVehicle<T, Type>::CalculatePower(uint32& total_power, uint32& max_te, bool breakdowns) const {
 

	
 
	total_power = 0;
 
	max_te = 0;
 
    
 
	const T *v = T::From(this);
 

	
 
	for (const T *u = v; u != NULL; u = u->Next()) {
 
		uint32 current_power = u->GetPower() + u->GetPoweredPartPower(u);
 
		total_power += current_power;
 

	
 
		/* Only powered parts add tractive effort. */
 
		if (current_power > 0) max_te += u->GetWeight() * u->GetTractiveEffort();
 
		
 
		if (breakdowns && u->breakdown_ctr == 1 && u->breakdown_type == BREAKDOWN_LOW_POWER) {
 
			total_power = total_power * u->breakdown_severity / 256;
 
                }
 
	}
 

	
 
	max_te *= GROUND_ACCELERATION; // Tractive effort in (tonnes * 1000 * 9.8 =) N.
 
	max_te /= 256;   // Tractive effort is a [0-255] coefficient.
 
}
 

	
 
/**
 
 * Recalculates the cached weight of a vehicle and its parts. Should be called each time the cargo on
 
 * the consist changes.
 
@@ -102,7 +121,7 @@ void GroundVehicle<T, Type>::CargoChange
 
 * @return Current acceleration of the vehicle.
 
 */
 
template <class T, VehicleType Type>
 
int GroundVehicle<T, Type>::GetAcceleration() const
 
int GroundVehicle<T, Type>::GetAcceleration()
 
{
 
	/* Templated class used for function calls for performance reasons. */
 
	const T *v = T::From(this);
 
@@ -117,6 +136,7 @@ int GroundVehicle<T, Type>::GetAccelerat
 
	 * and km/h to m/s conversion below result in a maximum of
 
	 * about 1.1E11, way more than 4.3E9 of int32. */
 
	int64 power = this->gcache.cached_power * 746ll;
 
	uint32 max_te = this->gcache.cached_max_te; // [N]
 

	
 
	/* This is constructed from:
 
	 *  - axle resistance:  U16 power * 10 for 128 vehicles.
 
@@ -148,7 +168,16 @@ int GroundVehicle<T, Type>::GetAccelerat
 
	/* This value allows to know if the vehicle is accelerating or braking. */
 
	AccelStatus mode = v->GetAccelerationStatus();
 

	
 
	const int max_te = this->gcache.cached_max_te; // [N]
 
	/* handle breakdown power reduction */
 
	//TODO
 
	if(  Type == VEH_TRAIN  && mode == AS_ACCEL && HasBit(Train::From(this)->flags, VRF_BREAKDOWN_POWER)) {
 
		/* We'd like to cache this, but changing cached_power has too many unwanted side-effects */
 
		uint32 power_temp;
 
		this->CalculatePower(power_temp, max_te, true);
 
		power = power_temp * 74611;
 
	}
 
	
 
		
 
	/* Constructued from power, with need to multiply by 18 and assuming
 
	 * low speed, it needs to be a 64 bit integer too. */
 
	int64 force;
 
@@ -156,7 +185,7 @@ int GroundVehicle<T, Type>::GetAccelerat
 
		if (!maglev) {
 
			/* Conversion factor from km/h to m/s is 5/18 to get [N] in the end. */
 
			force = power * 18 / (speed * 5);
 
			if (mode == AS_ACCEL && force > max_te) force = max_te;
 
			if (mode == AS_ACCEL && force > (int)max_te) force = max_te;
 
		} else {
 
			force = power / 25;
 
		}
 
@@ -166,6 +195,34 @@ int GroundVehicle<T, Type>::GetAccelerat
 
		force = std::max(force, (mass * 8) + resistance);
 
	}
 

	
 
	/* If power is 0 because of a breakdown, we make the force 0 if accelerating */
 
	if ( Type == VEH_TRAIN && mode == AS_ACCEL && HasBit(Train::From(this)->flags, VRF_BREAKDOWN_POWER) && power == 0) {
 
		force = 0;
 
	}
 

	
 
	/* Calculate the breakdown chance */
 
	if (_settings_game.vehicle.improved_breakdowns) {
 
		assert(this->gcache.cached_max_track_speed > 0);
 
		/** First, calculate (resistance / force * current speed / max speed) << 16.
 
		 * This yields a number x on a 0-1 scale, but shifted 16 bits to the left.
 
		 * We then calculate 64 + 128x, clamped to 0-255, but still shifted 16 bits to the left.
 
		 * Then we apply a correction for multiengine trains, and in the end we shift it 16 bits to the right to get a 0-255 number.
 
		 * @note A seperate correction for multiheaded engines is done in CheckVehicleBreakdown. We can't do that here because it would affect the whole consist.
 
		 */
 
		uint64 breakdown_factor = (uint64)abs(resistance) * (uint64)(this->cur_speed << 16);
 
		breakdown_factor /= (std::max<uint64>(force, (int64)100) * this->gcache.cached_max_track_speed);
 
		breakdown_factor = std::min<uint64>((64 << 16) + (breakdown_factor * 128), 255 << 16);
 
		if ( Type == VEH_TRAIN && Train::From(this)->tcache.cached_num_engines > 1) {
 
			/* For multiengine trains, breakdown chance is multiplied by 3 / (num_engines + 2) */
 
			breakdown_factor *= 3;
 
			breakdown_factor /= (Train::From(this)->tcache.cached_num_engines + 2);
 
		}
 
		/* breakdown_chance is at least 5 (5 / 128 = ~4% of the normal chance) */
 
		this->breakdown_chance = (uint8) std::max<uint64>(breakdown_factor >> 16, (uint64)5);
 
	} else {
 
		this->breakdown_chance = 128;
 
	}
 

	
 
	if (mode == AS_ACCEL) {
 
		/* Easy way out when there is no acceleration. */
 
		if (force == resistance) return 0;
 
@@ -176,7 +233,27 @@ int GroundVehicle<T, Type>::GetAccelerat
 
		 * a hill will never speed up enough to (eventually) get back to the
 
		 * same (maximum) speed. */
 
		int accel = ClampToI32((force - resistance) / (mass * 4));
 
		return force < resistance ? std::min(-1, accel) : std::max(1, accel);
 
		accel = force < resistance ? std::min(-1, accel) : std::max(1, accel);
 
		if (this->type == VEH_TRAIN ) {
 
			if(_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL &&
 
				HasBit(Train::From(this)->flags, VRF_BREAKDOWN_POWER)) {
 
				/* We need to apply the power reducation for non-realistic acceleration here */
 
				uint32 power;
 
				CalculatePower(power, max_te, true);
 
				accel = accel * power / this->gcache.cached_power;
 
				accel -= this->acceleration >> 1;
 
			}
 

	
 

	
 
			if ( this->IsFrontEngine() && !(this->current_order_time & 0x1FF) &&
 
				!(this->current_order.IsType(OT_LOADING)) &&
 
				!(Train::From(this)->flags & (VRF_IS_BROKEN | (1 << VRF_TRAIN_STUCK))) &&
 
				this->cur_speed < 3 && accel < 5) {
 
				SetBit(Train::From(this)->flags, VRF_TO_HEAVY);
 
			}
 
		}
 

	
 
		return accel;
 
	} else {
 
		return ClampToI32(std::min<int64>(-force - resistance, -10000) / mass);
 
	}
src/ground_vehicle.hpp
Show inline comments
 
@@ -89,9 +89,11 @@ struct GroundVehicle : public Specialize
 

	
 
	void PowerChanged();
 
	void CargoChanged();
 
	int GetAcceleration() const;
 
	int GetAcceleration();
 
	bool IsChainInDepot() const override;
 

	
 
	void CalculatePower(uint32& power, uint32& max_te, bool breakdowns) const;
 

	
 
	/**
 
	 * Common code executed for crashed ground vehicles
 
	 * @param flooded was this vehicle flooded?
 
@@ -367,7 +369,22 @@ protected:
 

	
 
		/* When we are going faster than the maximum speed, reduce the speed
 
		 * somewhat gradually. But never lower than the maximum speed. */
 
		int tempmax = max_speed;
 
		int tempmax = ((this->breakdown_ctr == 1) ? this->cur_speed : max_speed);
 
		
 
		if (this->breakdown_ctr == 1) {
 
			if (this->breakdown_type == BREAKDOWN_LOW_POWER) {
 
				if((this->tick_counter & 0x7) == 0) {
 
					if(this->cur_speed > (this->breakdown_severity * max_speed) >> 8) {
 
						tempmax = this->cur_speed - (this->cur_speed / 10) - 1;
 
					} else {
 
						tempmax = (this->breakdown_severity * max_speed) >> 8;
 
					}
 
				}
 
			}
 
			if(this->breakdown_type == BREAKDOWN_LOW_SPEED)
 
				tempmax = std::min<int>(max_speed, this->breakdown_severity);
 
		}
 

	
 
		if (this->cur_speed > max_speed) {
 
			tempmax = std::max(this->cur_speed - (this->cur_speed / 10) - 1, max_speed);
 
		}
src/group_gui.cpp
Show inline comments
 
@@ -207,7 +207,7 @@ private:
 
		this->tiny_step_height = this->column_size[VGC_FOLD].height;
 

	
 
		this->column_size[VGC_NAME] = maxdim(GetStringBoundingBox(STR_GROUP_DEFAULT_TRAINS + this->vli.vtype), GetStringBoundingBox(STR_GROUP_ALL_TRAINS + this->vli.vtype));
 
		this->column_size[VGC_NAME].width = std::max(170u, this->column_size[VGC_NAME].width);
 
		this->column_size[VGC_NAME].width = std::max(450u, this->column_size[VGC_NAME].width);
 
		this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_NAME].height);
 

	
 
		this->column_size[VGC_PROTECT] = GetSpriteSize(SPR_GROUP_REPLACE_PROTECT);
 
@@ -1084,14 +1084,14 @@ public:
 

	
 

	
 
static WindowDesc _other_group_desc(
 
	WDP_AUTO, "list_groups", 460, 246,
 
	WDP_AUTO, "list_groups", 940, 246,
 
	WC_INVALID, WC_NONE,
 
	0,
 
	_nested_group_widgets, lengthof(_nested_group_widgets)
 
);
 

	
 
static WindowDesc _train_group_desc(
 
	WDP_AUTO, "list_groups_train", 525, 246,
 
	WDP_AUTO, "list_groups_train", 1005, 246,
 
	WC_TRAINS_LIST, WC_NONE,
 
	0,
 
	_nested_group_widgets, lengthof(_nested_group_widgets)
src/group_type.h
Show inline comments
 
@@ -17,7 +17,7 @@ static const GroupID ALL_GROUP     = 0xF
 
static const GroupID DEFAULT_GROUP = 0xFFFE; ///< Ungrouped vehicles are in this group.
 
static const GroupID INVALID_GROUP = 0xFFFF; ///< Sentinel for invalid groups.
 

	
 
static const uint MAX_LENGTH_GROUP_NAME_CHARS = 32; ///< The maximum length of a group name in characters including '\0'
 
static const uint MAX_LENGTH_GROUP_NAME_CHARS = 128; ///< The maximum length of a group name in characters including '\0'
 

	
 
struct Group;
 

	
src/industry_cmd.cpp
Show inline comments
 
@@ -520,7 +520,7 @@ static CommandCost ClearTile_Industry(Ti
 
		Game::NewEvent(new ScriptEventIndustryClose(i->index));
 
		delete i;
 
	}
 
	return CommandCost(EXPENSES_CONSTRUCTION, indspec->GetRemovalCost());
 
	return CommandCost(EXPENSES_T_DEMOLITION, indspec->GetRemovalCost());
 
}
 

	
 
/**
 
@@ -2054,7 +2054,7 @@ CommandCost CmdBuildIndustry(DoCommandFl
 
		AdvertiseIndustryOpening(ind);
 
	}
 

	
 
	return CommandCost(EXPENSES_OTHER, indspec->GetConstructionCost());
 
	return CommandCost(EXPENSES_CONSTRUCTION, indspec->GetConstructionCost());
 
}
 

	
 
/**
src/landscape.cpp
Show inline comments
 
@@ -690,7 +690,7 @@ void ClearSnowLine()
 
 */
 
CommandCost CmdLandscapeClear(DoCommandFlag flags, TileIndex tile)
 
{
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_DEMOLITION);
 
	bool do_clear = false;
 
	/* Test for stuff which results in water when cleared. Then add the cost to also clear the water. */
 
	if ((flags & DC_FORCE_CLEAR_TILE) && HasTileWaterClass(tile) && IsTileOnWater(tile) && !IsWaterTile(tile) && !IsCoastTile(tile)) {
 
@@ -741,7 +741,7 @@ std::tuple<CommandCost, Money> CmdClearA
 
	if (start_tile >= MapSize()) return { CMD_ERROR, 0 };
 

	
 
	Money money = GetAvailableMoneyForCommand();
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_DEMOLITION);
 
	CommandCost last_error = CMD_ERROR;
 
	bool had_success = false;
 

	
src/lang/english.txt
Show inline comments
 
@@ -304,6 +304,7 @@ STR_SORT_BY_WAITING_TOTAL               
 
STR_SORT_BY_WAITING_AVAILABLE                                   :Available waiting cargo
 
STR_SORT_BY_RATING_MAX                                          :Highest cargo rating
 
STR_SORT_BY_RATING_MIN                                          :Lowest cargo rating
 
STR_SORT_BY_DILAPIDATION                                        :Dilapidation
 
STR_SORT_BY_ENGINE_ID                                           :EngineID (classic sort)
 
STR_SORT_BY_COST                                                :Cost
 
STR_SORT_BY_POWER                                               :Power
 
@@ -1233,6 +1234,9 @@ STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HE
 
STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS                           :Vehicle breakdowns: {STRING2}
 
STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT                  :Control how often inadequately serviced vehicles may break down
 

	
 
STR_CONFIG_SETTING_IMPROVED_BREAKDOWNS                          :Enable improved breakdowns: {STRING}
 
STR_CONFIG_SETTING_IMPROVED_BREAKDOWNS_HELPTEXT                 :If enabled, different type of breakdowns can occur: emergency stop, temporary speed reduction, temporary power loss or a classic breakdown. Aircrafts may travel with reduced speed or have a mandatory service at the destination airport or have an emergency landing at the closest airport. Breakdown possibility is similar to classic breakdowns, but the impact to vehicles and the network is reduced.
 

	
 
STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER                           :Subsidy multiplier: {STRING2}
 
STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT                  :Set how much is paid for subsidised connections
 

	
 
@@ -1359,6 +1363,9 @@ STR_CONFIG_SETTING_AUTOSCROLL_EVERY_VIEW
 
STR_CONFIG_SETTING_BRIBE                                        :Allow bribing of the local authority: {STRING2}
 
STR_CONFIG_SETTING_BRIBE_HELPTEXT                               :Allow companies to try bribing the local town authority. If the bribe is noticed by an inspector, the company will not be able to act in the town for six months
 

	
 
STR_CONFIG_SETTING_BRIBE_RISKY                                  :Bribing can be caught by an inspector: {STRING2}
 
STR_CONFIG_SETTING_BRIBE_RISKY_HELPTEXT                         :Whether or not bribing towns can be noticed by an inspector
 

	
 
STR_CONFIG_SETTING_ALLOW_EXCLUSIVE                              :Allow buying exclusive transport rights: {STRING2}
 
STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT                     :If a company buys exclusive transport rights for a town, opponents' stations (passenger and cargo) won't receive any cargo for a whole year
 

	
 
@@ -1441,6 +1448,9 @@ STR_CONFIG_SETTING_HOVER_DELAY_DISABLED 
 
STR_CONFIG_SETTING_POPULATION_IN_LABEL                          :Show town population in the town name label: {STRING2}
 
STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT                 :Display the population of towns in their label on the map
 

	
 
STR_CONFIG_SETTING_RATING_COLOUR_IN_LABEL                       :Colour town names based on company rating: {STRING2}
 
STR_CONFIG_SETTING_RATING_COLOUR_IN_LABEL_HELPTEXT              :Colour towns based on company rating in their label on the map
 

	
 
STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS                         :Thickness of lines in graphs: {STRING2}
 
STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT                :Width of the line in the graphs. A thin line is more precisely readable, a thicker line is easier to see and colours are easier to distinguish
 

	
 
@@ -1862,6 +1872,63 @@ STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HEL
 
###length 2
 
STR_CONFIG_SETTING_TOWN_CARGOGENMODE_ORIGINAL                   :Quadratic (original)
 
STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT                   :Linear
 
STR_CONFIG_SETTING_DAYLENGTH_FACTOR                             :Day length multiplier: {STRING2}
 
STR_CONFIG_SETTING_DAYLENGTH_FACTOR_HELPTEXT                    :Adjusts the length of a day in OpenTTD. A multiplier of 1 is equivalent to classic TTD (each day lasts 74 ticks or 2.22 seconds)
 
STR_CONFIG_SETTING_TOWN_GROWTH_FACTOR                           :Town growth interval multiplier: {STRING2}
 
STR_CONFIG_SETTING_TOWN_GROWTH_FACTOR_HELPTEXT                  :Adjusts the length of time between town growth ticks, intended to be used alongside day length multiplier. Larger values will result in town growth happening more slowly
 
STR_CONFIG_SETTING_PLANE_RANGE_MULTIPLIER                       :Aircraft range multiplier: {STRING2}
 
STR_CONFIG_SETTING_PLANE_RANGE_MULTIPLIER_HELPTEXT              :Adjusts the maximum range of all aircraft
 
STR_CONFIG_SETTING_NAME_STATIONS_BY_INDUSTRIES                  :Station naming convention: {STRING2}
 
STR_CONFIG_SETTING_NAME_STATIONS_BY_INDUSTRIES_HELPTEXT         :Determines how stations will be named when placed; affects all players
 
STR_CONFIG_SETTING_NAME_STATIONS_BY_INDUSTRIES_SELECTION_0      :Use classic station names only
 
STR_CONFIG_SETTING_NAME_STATIONS_BY_INDUSTRIES_SELECTION_1      :Use NewGRF station names where appropriate
 
STR_CONFIG_SETTING_NAME_STATIONS_BY_INDUSTRIES_SELECTION_2      :Name stations based on nearby industries
 
STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_RAIL                :Rail infrastructure base cost: {STRING2}
 
STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_RAIL_HELPTEXT       :Adjusts the base infrastructure maintenance cost of rail tiles
 
STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_ROAD                :Road infrastructure base cost: {STRING2}
 
STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_ROAD_HELPTEXT       :Adjusts the base infrastructure maintenance cost of road tiles
 
STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_WATER               :Water infrastructure base cost: {STRING2}
 
STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_WATER_HELPTEXT      :Adjusts the base infrastructure maintenance cost of water tiles
 
STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_AIR                 :Air infrastructure base cost: {STRING2}
 
STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_AIR_HELPTEXT        :Adjusts the base infrastructure maintenance cost of airports
 
STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_STATION             :Station infrastructure base cost: {STRING2}
 
STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_STATION_HELPTEXT    :Adjusts the base infrastructure maintenance cost of station tiles
 
STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_RAIL                 :Rail running cost multiplier: {STRING2}
 
STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_RAIL_HELPTEXT        :Adjusts the running cost of rail vehicles, intended to be used alongside day length multiplier
 
STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_ROAD                 :Road running cost multiplier: {STRING2}
 
STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_ROAD_HELPTEXT        :Adjusts the running cost of road vehicles, intended to be used alongside day length multiplier
 
STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_WATER                :Water running cost multiplier: {STRING2}
 
STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_WATER_HELPTEXT       :Adjusts the running cost of water vehicles, intended to be used alongside day length multiplier
 
STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_AIR                  :Air running cost multiplier: {STRING2}
 
STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_AIR_HELPTEXT         :Adjusts the running cost of air vehicles, intended to be used alongside day length multiplier
 
STR_CONFIG_SETTING_VEHICLE_BREAKDOWN_SCALER                     :Vehicle breakdown scaler: {STRING2}
 
STR_CONFIG_SETTING_VEHICLE_BREAKDOWN_SCALER_HELPTEXT            :This is an additional breakdown chance scaler. Whenever a vehicle would normally break down in OTTD, a random 24-bit number will instead be generated (between 0 and 16777215). If it is greater than this scaler, the breakdown will be cancelled. (Setting to maximum value will behave like this scaler didn't exist)
 

	
 
STR_CONFIG_SETTING_DILAPIDATION_MAX_AMOUNT                      :Maximum station dilapidation: {STRING2}
 
STR_CONFIG_SETTING_DILAPIDATION_MAX_AMOUNT_HELPTEXT             :Every time the rating is updated (around once every 2.5 days) the amount of dilapidation at the station will be adjusted, being increased if there are excessive numbers of waiting passengers and being decreased otherwise. The more a station is dilapidated at the start of each month, the higher the amount your company will be fined. This setting controls the maximum amount of dilapidation that can be at a station. Setting to zero will disable this feature
 
STR_CONFIG_SETTING_DILAPIDATION_INCREASE                        :Dilapidation increase: {STRING2}
 
STR_CONFIG_SETTING_DILAPIDATION_INCREASE_HELPTEXT               :This is the amount by which station dilapidation will be increased if there are excessive numbers of waiting passengers
 
STR_CONFIG_SETTING_DILAPIDATION_DECREASE                        :Dilapidation decrease: {STRING2}
 
STR_CONFIG_SETTING_DILAPIDATION_DECREASE_HELPTEXT               :This is the amount by which station dilapidation will be decreased if there are not excessive numbers of waiting passengers
 
STR_CONFIG_SETTING_DILAPIDATION_POP_RAIL                        :Train station excessive passenger count: {STRING2}
 
STR_CONFIG_SETTING_DILAPIDATION_POP_RAIL_HELPTEXT               :Train stations are allowed to have this many passengers waiting before the number is considered excessive. For multi-type stations the highest value is used
 
STR_CONFIG_SETTING_DILAPIDATION_POP_ROAD                        :Road stop excessive passenger count: {STRING2}
 
STR_CONFIG_SETTING_DILAPIDATION_POP_ROAD_HELPTEXT               :Road stops are allowed to have this many passengers waiting before the number is considered excessive. For multi-type stations the highest value is used
 
STR_CONFIG_SETTING_DILAPIDATION_POP_WATER                       :Dock excessive passenger count: {STRING2}
 
STR_CONFIG_SETTING_DILAPIDATION_POP_WATER_HELPTEXT              :Docks are allowed to have this many passengers waiting before the number is considered excessive. For multi-type stations the highest value is used
 
STR_CONFIG_SETTING_DILAPIDATION_POP_AIR                         :Airport/helipad excessive passenger count: {STRING2}
 
STR_CONFIG_SETTING_DILAPIDATION_POP_AIR_HELPTEXT                :Airports and helipads are allowed to have this many passengers waiting before the number is considered excessive. For multi-type stations the highest value is used
 
STR_CONFIG_SETTING_DILAPIDATION_FINE_RAIL                       :Fine per train station dilapidation point: {STRING2}
 
STR_CONFIG_SETTING_DILAPIDATION_FINE_RAIL_HELPTEXT              :You will be fined this amount of money each month for each dilapidation point at each train station. For multi-type stations the highest value is used
 
STR_CONFIG_SETTING_DILAPIDATION_FINE_ROAD                       :Fine per road stop dilapidation point: {STRING2}
 
STR_CONFIG_SETTING_DILAPIDATION_FINE_ROAD_HELPTEXT              :You will be fined this amount of money each month for each dilapidation point at each road stop. For multi-type stations the highest value is used
 
STR_CONFIG_SETTING_DILAPIDATION_FINE_WATER                      :Fine per dock dilapidation point: {STRING2}
 
STR_CONFIG_SETTING_DILAPIDATION_FINE_WATER_HELPTEXT             :You will be fined this amount of money each month for each dilapidation point at each docks. For multi-type stations the highest value is used
 
STR_CONFIG_SETTING_DILAPIDATION_FINE_AIR                        :Fine per airport/helipad dilapidation point: {STRING2}
 
STR_CONFIG_SETTING_DILAPIDATION_FINE_AIR_HELPTEXT               :You will be fined this amount of money each month for each dilapidation point at each airport or helipad. For multi-type stations the highest value is used
 

	
 
STR_CONFIG_SETTING_LOAD_LEGACY_PATCHPACK_DATA                   :Attempt to load legacy patch data: {STRING2}
 
STR_CONFIG_SETTING_LOAD_LEGACY_PATCHPACK_DATA_HELPTEXT          :Causes the save loader to try to load legacy patch data for save files that might be from patchpack 5.x or earlier. Generally safe to leave enabled. Not all old saves are supported yet
 

	
 
STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT                         :In game placement of trees: {STRING2}
 
STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT                :Control random appearance of trees during the game. This might affect industries which rely on tree growth, for example lumber mills
 
@@ -2018,6 +2085,9 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST
 
STR_CONFIG_SETTING_AI                                           :{ORANGE}Competitors
 
STR_CONFIG_SETTING_AI_NPC                                       :{ORANGE}Computer players
 
STR_CONFIG_SETTING_NETWORK                                      :{ORANGE}Network
 
STR_CONFIG_SETTING_PATCHPACK                                    :{ORANGE}Patchpack configuration
 
STR_CONFIG_SETTING_PATCHPACK_DAYLENGTH                          :{ORANGE}Economy multipliers
 
STR_CONFIG_SETTING_PATCHPACK_DILAPIDATION                       :{ORANGE}Station dilapidation
 

	
 
STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS                        :Pathfinder for trains: {STRING2}
 
STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS_HELPTEXT               :Path finder to use for trains
 
@@ -2058,7 +2128,7 @@ STR_VIDEO_DRIVER_ERROR                  
 
STR_VIDEO_DRIVER_ERROR_NO_HARDWARE_ACCELERATION                 :{WHITE}... no compatible GPU found. Hardware acceleration disabled
 

	
 
# Intro window
 
STR_INTRO_CAPTION                                               :{WHITE}OpenTTD {REV}
 
STR_INTRO_CAPTION                                               :{WHITE}Ginever.net OpenTTD Patchpack :: {REV}
 

	
 
STR_INTRO_NEW_GAME                                              :{BLACK}New Game
 
STR_INTRO_LOAD_GAME                                             :{BLACK}Load Game
 
@@ -3033,7 +3103,7 @@ STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED
 
# About OpenTTD window
 
STR_ABOUT_OPENTTD                                               :{WHITE}About OpenTTD
 
STR_ABOUT_ORIGINAL_COPYRIGHT                                    :{BLACK}Original copyright {COPYRIGHT} 1995 Chris Sawyer, All rights reserved
 
STR_ABOUT_VERSION                                               :{BLACK}OpenTTD version {REV}
 
STR_ABOUT_VERSION                                               :{BLACK}Ginever.net OpenTTD Patchpack :: {REV}
 
STR_ABOUT_COPYRIGHT_OPENTTD                                     :{BLACK}OpenTTD {COPYRIGHT} 2002-{RAW_STRING} The OpenTTD team
 

	
 
# Framerate display window
 
@@ -3124,6 +3194,9 @@ STR_SAVELOAD_PARENT_DIRECTORY           
 

	
 
STR_SAVELOAD_OSKTITLE                                           :{BLACK}Enter a name for the savegame
 

	
 
STR_SAVELOAD_VERSION_WITH_EXTENSION                             :{SILVER}Save format version: {WHITE}{NUM}{RAW_STRING}
 
STR_SAVELOAD_VERSION_LABEL                                      :{SILVER}Saved by: {WHITE}{RAW_STRING}
 

	
 
# World generation
 
STR_MAPGEN_WORLD_GENERATION_CAPTION                             :{WHITE}World Generation
 
STR_MAPGEN_MAPSIZE                                              :{BLACK}Map size:
 
@@ -3529,6 +3602,7 @@ STR_STATION_LIST_TOOLTIP                
 
STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE                        :{BLACK}Hold Ctrl to select more than one item
 
STR_STATION_LIST_CAPTION                                        :{WHITE}{COMPANY} - {COMMA} Station{P "" s}
 
STR_STATION_LIST_STATION                                        :{YELLOW}{STATION} {STATION_FEATURES}
 
STR_STATION_LIST_STATION_WITH_DILAPIDATION                      :{YELLOW}{STATION} {STATION_FEATURES} {WHITE}({NUM})
 
STR_STATION_LIST_WAYPOINT                                       :{YELLOW}{WAYPOINT}
 
STR_STATION_LIST_NONE                                           :{YELLOW}- None -
 
STR_STATION_LIST_SELECT_ALL_FACILITIES                          :{BLACK}Select all facilities
 
@@ -3552,6 +3626,8 @@ STR_STATION_VIEW_RATINGS_TOOLTIP        
 
STR_STATION_VIEW_SUPPLY_RATINGS_TITLE                           :{BLACK}Monthly supply and local rating:
 
STR_STATION_VIEW_CARGO_SUPPLY_RATING                            :{WHITE}{STRING}: {YELLOW}{COMMA} / {STRING} ({COMMA}%)
 

	
 
STR_STATION_VIEW_DILAPIDATION                                   :{BLACK}Station dilapidation: {YELLOW}{NUM} / {NUM}
 

	
 
STR_STATION_VIEW_GROUP                                          :{BLACK}Group by
 
STR_STATION_VIEW_WAITING_STATION                                :Station: Waiting
 
STR_STATION_VIEW_WAITING_AMOUNT                                 :Amount: Waiting
 
@@ -3612,8 +3688,8 @@ STR_FINANCES_CAPTION                    
 
STR_FINANCES_EXPENDITURE_INCOME_TITLE                           :{WHITE}Expenditure/Income
 
STR_FINANCES_YEAR                                               :{WHITE}{NUM}
 

	
 
###length 13
 
STR_FINANCES_SECTION_CONSTRUCTION                               :{GOLD}Construction
 
###length 23
 
STR_FINANCES_SECTION_CONSTRUCTION                               :{GOLD}Misc Construction
 
STR_FINANCES_SECTION_NEW_VEHICLES                               :{GOLD}New Vehicles
 
STR_FINANCES_SECTION_TRAIN_RUNNING_COSTS                        :{GOLD}Train Running Costs
 
STR_FINANCES_SECTION_ROAD_VEHICLE_RUNNING_COSTS                 :{GOLD}Road Vehicle Running Costs
 
@@ -3626,6 +3702,16 @@ STR_FINANCES_SECTION_AIRCRAFT_INCOME    
 
STR_FINANCES_SECTION_SHIP_INCOME                                :{GOLD}Ship Income
 
STR_FINANCES_SECTION_LOAN_INTEREST                              :{GOLD}Loan Interest
 
STR_FINANCES_SECTION_OTHER                                      :{GOLD}Other
 
STR_FINANCES_SECTION_T_TRAIN_CON                                :{GOLD}Railway Construction
 
STR_FINANCES_SECTION_T_ROAD_CON                                 :{GOLD}Road Construction
 
STR_FINANCES_SECTION_T_AIRCRAFT_CON                             :{GOLD}Airport Construction
 
STR_FINANCES_SECTION_T_SHIP_CON                                 :{GOLD}Waterways Construction
 
STR_FINANCES_SECTION_T_TREES_CON                                :{GOLD}Tree Construction
 
STR_FINANCES_SECTION_T_SCENERY_CON                              :{GOLD}Object Construction
 
STR_FINANCES_SECTION_T_LANDSCAPING                              :{GOLD}Landscaping
 
STR_FINANCES_SECTION_T_DEMOLITION                               :{GOLD}Demolition
 
STR_FINANCES_SECTION_T_REWARD_INC                               :{GOLD}Reward Income
 
STR_FINANCES_SECTION_T_DILAPIDATION                             :{GOLD}Station Dilapidation
 

	
 
STR_FINANCES_NEGATIVE_INCOME                                    :{BLACK}-{CURRENCY_LONG}
 
STR_FINANCES_POSITIVE_INCOME                                    :{BLACK}+{CURRENCY_LONG}
 
@@ -4137,11 +4223,20 @@ STR_VEHICLE_STATUS_LEAVING              
 
STR_VEHICLE_STATUS_CRASHED                                      :{RED}Crashed!
 
STR_VEHICLE_STATUS_BROKEN_DOWN                                  :{RED}Broken down
 
STR_VEHICLE_STATUS_STOPPED                                      :{RED}Stopped
 
STR_VEHICLE_STATUS_BROKEN_DOWN_VEL                              :{RED}Broken down - {STRING1}, {LTBLUE} {VELOCITY}
 
STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL                           :{RED}Stopping, {VELOCITY}
 
STR_VEHICLE_STATUS_TRAIN_NO_POWER                               :{RED}No power
 
STR_VEHICLE_STATUS_TRAIN_STUCK                                  :{ORANGE}Waiting for free path
 
STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR                             :{ORANGE}Too far to next destination
 

	
 
STR_BREAKDOWN_TYPE_CRITICAL                                     :Mechanical failure
 
STR_BREAKDOWN_TYPE_EM_STOP                                      :Emergency stop
 
STR_BREAKDOWN_TYPE_LOW_SPEED                                    :Limited to {VELOCITY}
 
STR_BREAKDOWN_TYPE_LOW_POWER                                    :{COMMA}% Power
 
STR_BREAKDOWN_TYPE_DEPOT                                        :Heading to {STATION} Hangar for repairs
 
STR_BREAKDOWN_TYPE_LANDING                                      :Heading to {STATION} for emergency landing
 
STR_ERROR_TRAIN_TOO_HEAVY                                       :{WHITE}{VEHICLE} is too heavy
 

	
 
STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL                      :{LTBLUE}Heading for {STATION}, {VELOCITY}
 
STR_VEHICLE_STATUS_NO_ORDERS_VEL                                :{LTBLUE}No orders, {VELOCITY}
 
STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL                     :{LTBLUE}Heading for {WAYPOINT}, {VELOCITY}
 
@@ -4172,6 +4267,11 @@ STR_VEHICLE_DETAILS_SHIP_RENAME         
 
STR_VEHICLE_DETAILS_AIRCRAFT_RENAME                             :{BLACK}Name aircraft
 

	
 
STR_VEHICLE_INFO_AGE_RUNNING_COST_YR                            :{BLACK}Age: {LTBLUE}{STRING2}{BLACK}   Running Cost: {LTBLUE}{CURRENCY_LONG}/yr
 

	
 
STR_RUNNING                                                     :{LTBLUE}Running
 
STR_NEED_REPAIR                                                 :{ORANGE}Train needs repair - max speed reduced to {VELOCITY}
 
STR_CURRENT_STATUS                                              :{BLACK}Current status: {STRING2}
 

	
 
STR_VEHICLE_INFO_AGE                                            :{COMMA} year{P "" s} ({COMMA})
 
STR_VEHICLE_INFO_AGE_RED                                        :{RED}{COMMA} year{P "" s} ({COMMA})
 

	
 
@@ -4210,7 +4310,9 @@ STR_QUERY_RENAME_AIRCRAFT_CAPTION       
 

	
 
# Extra buttons for train details windows
 
STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE                :{LTBLUE}{ENGINE}{BLACK}   Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG}
 
STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE_AND_SPEED      :{LTBLUE}{ENGINE}{BLACK}   Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG} {BLACK}Max. speed: {LTBLUE}{VELOCITY}
 
STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE                           :{LTBLUE}{ENGINE}{BLACK}   Value: {LTBLUE}{CURRENCY_LONG}
 
STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE_AND_SPEED                 :{LTBLUE}{ENGINE}{BLACK}   Value: {LTBLUE}{CURRENCY_LONG} {BLACK}Max. speed: {LTBLUE}{VELOCITY}
 

	
 
STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT                   :{BLACK}Total cargo capacity of this train:
 
STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY                        :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT})
 
@@ -4615,12 +4717,13 @@ STR_ERROR_GAME_SAVE_FAILED              
 
STR_ERROR_UNABLE_TO_DELETE_FILE                                 :{WHITE}Unable to delete file
 
STR_ERROR_GAME_LOAD_FAILED                                      :{WHITE}Game Load Failed{}{STRING1}
 
STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR                   :Internal error: {RAW_STRING}
 
STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME                         :Broken savegame - {RAW_STRING}
 
STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME                        :Savegame is made with newer version
 
STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME                         :Save file contains incompatible patch data ({RAW_STRING})
 
STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME                        :Save file contains incompatible patch data
 
STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE                       :File not readable
 
STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE                      :File not writeable
 
STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED             :Data integrity check failed
 
STR_GAME_SAVELOAD_ERROR_PATCHPACK                               :Savegame is made with a modified version
 
STR_GAME_SAVELOAD_ERROR_UNSUPPORTED_GPP                         :The legacy save loader doesn't currently support loading saves from this version
 
STR_GAME_SAVELOAD_NOT_AVAILABLE                                 :<not available>
 
STR_WARNING_LOADGAME_REMOVED_TRAMS                              :{WHITE}Game was saved in version without tram support. All trams have been removed
 

	
 
@@ -5467,9 +5570,24 @@ STR_SAVEGAME_NAME_DEFAULT               
 
STR_SAVEGAME_NAME_SPECTATOR                                     :Spectator, {1:STRING1}
 

	
 
# Viewport strings
 
STR_VIEWPORT_TOWN_POP_VERY_POOR_RATING                          :{RED}{TOWN} ({COMMA})
 
STR_VIEWPORT_TOWN_POP_MEDIOCRE_RATING                           :{ORANGE}{TOWN} ({COMMA})
 
STR_VIEWPORT_TOWN_POP_GOOD_RATING                               :{YELLOW}{TOWN} ({COMMA})
 
STR_VIEWPORT_TOWN_POP_NORMAL_RATING                             :{GREEN}{TOWN} ({COMMA})
 
STR_VIEWPORT_TOWN_POP_EXCELLENT_RATING                          :{LTBLUE}{TOWN} ({COMMA})
 
STR_VIEWPORT_TOWN_POP                                           :{WHITE}{TOWN} ({COMMA})
 
STR_VIEWPORT_TOWN_VERY_POOR_RATING                              :{RED}{TOWN}
 
STR_VIEWPORT_TOWN_MEDIOCRE_RATING                               :{ORANGE}{TOWN}
 
STR_VIEWPORT_TOWN_GOOD_RATING                                   :{YELLOW}{TOWN}
 
STR_VIEWPORT_TOWN_NORMAL_RATING                                 :{GREEN}{TOWN}
 
STR_VIEWPORT_TOWN_EXCELLENT_RATING                              :{LTBLUE}{TOWN}
 
STR_VIEWPORT_TOWN                                               :{WHITE}{TOWN}
 
STR_VIEWPORT_TOWN_TINY_BLACK                                    :{TINY_FONT}{BLACK}{TOWN}
 
STR_VIEWPORT_TOWN_TINY_VERY_POOR_RATING                         :{TINY_FONT}{RED}{TOWN}
 
STR_VIEWPORT_TOWN_TINY_MEDIOCRE_RATING                          :{TINY_FONT}{ORANGE}{TOWN}
 
STR_VIEWPORT_TOWN_TINY_GOOD_RATING                              :{TINY_FONT}{YELLOW}{TOWN}
 
STR_VIEWPORT_TOWN_TINY_NORMAL_RATING                            :{TINY_FONT}{GREEN}{TOWN}
 
STR_VIEWPORT_TOWN_TINY_EXCELLENT_RATING                         :{TINY_FONT}{LTBLUE}{TOWN}
 
STR_VIEWPORT_TOWN_TINY_WHITE                                    :{TINY_FONT}{WHITE}{TOWN}
 

	
 
STR_VIEWPORT_SIGN_SMALL_BLACK                                   :{TINY_FONT}{BLACK}{SIGN}
src/lang/english_AU.txt
Show inline comments
 
@@ -3247,7 +3247,7 @@ STR_FINANCES_EXPENDITURE_INCOME_TITLE   
 
STR_FINANCES_YEAR                                               :{WHITE}{NUM}
 

	
 
###length 13
 
STR_FINANCES_SECTION_CONSTRUCTION                               :{GOLD}Construction
 
STR_FINANCES_SECTION_CONSTRUCTION                               :{GOLD}Misc Construction
 
STR_FINANCES_SECTION_NEW_VEHICLES                               :{GOLD}New Vehicles
 
STR_FINANCES_SECTION_TRAIN_RUNNING_COSTS                        :{GOLD}Train Running Costs
 
STR_FINANCES_SECTION_ROAD_VEHICLE_RUNNING_COSTS                 :{GOLD}Road Vehicle Running Costs
src/lang/english_US.txt
Show inline comments
 
@@ -3613,7 +3613,7 @@ STR_FINANCES_EXPENDITURE_INCOME_TITLE   
 
STR_FINANCES_YEAR                                               :{WHITE}{NUM}
 

	
 
###length 13
 
STR_FINANCES_SECTION_CONSTRUCTION                               :{GOLD}Construction
 
STR_FINANCES_SECTION_CONSTRUCTION                               :{GOLD}Misc Construction
 
STR_FINANCES_SECTION_NEW_VEHICLES                               :{GOLD}New Vehicles
 
STR_FINANCES_SECTION_TRAIN_RUNNING_COSTS                        :{GOLD}Train Running Costs
 
STR_FINANCES_SECTION_ROAD_VEHICLE_RUNNING_COSTS                 :{GOLD}Road Vehicle Running Costs
src/misc_gui.cpp
Show inline comments
 
@@ -408,6 +408,15 @@ static const char * const _credits[] = {
 
	u8"Original design by Chris Sawyer",
 
	u8"Original graphics by Simon Foster",
 
	u8"",
 
	u8"Ginever.net OpenTTD Patchpack team:",
 
	u8"  Ruby Dennington (Theleruby) - Patch implementation",
 
	u8"  Paul Dennington (Paulicus25) - Lead tester",
 
	u8"  Assorted testers from Ginever Entertainment",
 
	u8"",
 
	u8"The latest version of this patchpack can be obtained from:",
 
	u8"  https://hg.ginever.net/public/openttd  (source)",
 
	u8"  https://hg.ginever.net/public/openttd-binaries  (Windows binaries)",
 
	u8"",
 
	u8"The OpenTTD team (in alphabetical order):",
 
	u8"  Grzegorz Duczy\u0144ski (adf88) - General coding (since 1.7.2)",
 
	u8"  Albert Hofkamp (Alberth) - GUI expert (since 0.7)",
src/network/core/game_info.cpp
Show inline comments
 
@@ -46,7 +46,7 @@ std::string_view GetNetworkRevisionStrin
 

	
 
	if (network_revision.empty()) {
 
		network_revision = _openttd_revision;
 
		if (_openttd_revision_tagged) {
 
		if (_openttd_revision_tagged || _openttd_revision_modified == 3 || _openttd_revision_modified == 4) {
 
			/* Tagged; do not mangle further, though ensure it's not too long. */
 
			if (network_revision.size() >= NETWORK_REVISION_LENGTH) network_revision.resize(NETWORK_REVISION_LENGTH - 1);
 
		} else {
src/network/network_func.h
Show inline comments
 
@@ -74,6 +74,8 @@ bool NetworkServerStart();
 
void NetworkServerNewCompany(const Company *company, NetworkClientInfo *ci);
 
bool NetworkServerChangeClientName(ClientID client_id, const std::string &new_name);
 

	
 
void NetworkSavePassword();
 
void NetworkLoadPassword();
 

	
 
void NetworkServerDoMove(ClientID client_id, CompanyID company_id);
 
void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const std::string &string);
src/network/network_server.cpp
Show inline comments
 
@@ -34,6 +34,7 @@
 
#include <mutex>
 
#include <condition_variable>
 

	
 
#include "../fileio_func.h"
 
#include "../safeguards.h"
 

	
 

	
 
@@ -1566,6 +1567,9 @@ static void NetworkAutoCleanCompanies()
 
				IConsolePrint(CC_INFO, "Auto-removed protection from company #{}.", c->index + 1);
 
				_network_company_states[c->index].months_empty = 0;
 
				NetworkServerUpdateCompanyPassworded(c->index, false);
 
				if (_settings_client.network.save_password) {
 
					NetworkSavePassword();
 
				}
 
			}
 
			/* Is the company empty for autoclean_novehicles-months, and has no vehicles? */
 
			if (_settings_client.network.autoclean_novehicles != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_novehicles && vehicles_in_company[c->index] == 0) {
 
@@ -1659,6 +1663,10 @@ void NetworkServerSetCompanyPassword(Com
 
	}
 

	
 
	NetworkServerUpdateCompanyPassworded(company_id, !_network_company_states[company_id].password.empty());
 

	
 
	if (_settings_client.network.save_password) {
 
		NetworkSavePassword();
 
	}
 
}
 

	
 
/**
 
@@ -2076,6 +2084,9 @@ void NetworkServerNewCompany(const Compa
 
	_network_company_states[c->index].months_empty = 0;
 
	_network_company_states[c->index].password.clear();
 
	NetworkServerUpdateCompanyPassworded(c->index, false);
 
	if (_settings_client.network.save_password) {
 
		NetworkSavePassword();
 
	}
 

	
 
	if (ci != nullptr) {
 
		/* ci is nullptr when replaying, or for AIs. In neither case there is a client. */
 
@@ -2094,3 +2105,41 @@ void NetworkServerNewCompany(const Compa
 
		NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, c->index + 1);
 
	}
 
}
 

	
 
void NetworkSavePassword()
 
{
 
	std::string password_file_name = std::to_string(_settings_game.game_creation.generation_seed) + ".pwd";
 
	Debug(net, 0, "Saving company passwords to %s", password_file_name);
 
	FILE* file_pointer = FioFOpenFile(password_file_name, "wb", SAVE_DIR);
 
	if (file_pointer != nullptr) {
 
		for (CompanyID l_company = (CompanyID)0; l_company < MAX_COMPANIES; l_company++) {
 
			if (NetworkCompanyIsPassworded(l_company)) {
 
				const char* password = _network_company_states[l_company].password.c_str();
 
				fwrite(password, strlen(password), 1, file_pointer);
 
			}
 
			fwrite("\n", 1, 1, file_pointer);
 
		}
 
		fclose(file_pointer);
 
	}
 
}
 

	
 
void NetworkLoadPassword()
 
{
 
	std::string password_file_name = std::to_string(_settings_game.game_creation.generation_seed) + ".pwd";
 
	FILE* file_pointer = FioFOpenFile(password_file_name, "rb", SAVE_DIR);
 
	if (file_pointer != nullptr) {
 
		Debug(net, 0, "Loading company passwords from %s", password_file_name);
 
		for (CompanyID l_company = (CompanyID)0; l_company < MAX_COMPANIES; l_company++) {
 
			char password[NETWORK_PASSWORD_LENGTH] = { '\0' };
 
			fgets(password, NETWORK_PASSWORD_LENGTH, file_pointer);
 
			if (strlen(password) > 1) {
 
				_network_company_states[l_company].password = password;
 
				NetworkServerUpdateCompanyPassworded(l_company, !_network_company_states[l_company].password.empty());
 
				fseek(file_pointer, 1L, SEEK_CUR);
 
			}
 
		}
 
	}
 
	else {
 
		Debug(net, 0, "Password file %s not found", password_file_name);
 
	}
 
}
src/object_cmd.cpp
Show inline comments
 
@@ -205,7 +205,7 @@ static CommandCost ClearTile_Object(Tile
 
 */
 
CommandCost CmdBuildObject(DoCommandFlag flags, TileIndex tile, ObjectType type, uint8 view)
 
{
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_SCENERY_CON);
 

	
 
	if (type >= NUM_OBJECTS) return CMD_ERROR;
 
	const ObjectSpec *spec = ObjectSpec::Get(type);
 
@@ -478,7 +478,7 @@ static CommandCost ClearTile_Object(Tile
 
	ObjectType type = o->type;
 
	const ObjectSpec *spec = ObjectSpec::Get(type);
 

	
 
	CommandCost cost(EXPENSES_CONSTRUCTION, spec->GetClearCost() * ta.w * ta.h / 5);
 
	CommandCost cost(EXPENSES_T_DEMOLITION, spec->GetClearCost() * ta.w * ta.h / 5);
 
	if (spec->flags & OBJECT_FLAG_CLEAR_INCOME) cost.MultiplyCost(-1); // They get an income!
 

	
 
	/* Towns can't remove any objects. */
 
@@ -525,7 +525,7 @@ static CommandCost ClearTile_Object(Tile
 
			}
 

	
 
			/* cost of relocating company is 1% of company value */
 
			cost = CommandCost(EXPENSES_CONSTRUCTION, CalculateCompanyValue(c) / 100);
 
			cost = CommandCost(EXPENSES_T_SCENERY_CON, CalculateCompanyValue(c) / 100);
 
			break;
 
		}
 

	
src/openttd.cpp
Show inline comments
 
@@ -254,7 +254,20 @@ static void WriteSavegameInfo(const char
 
	char buf[8192];
 
	char *p = buf;
 
	p += seprintf(p, lastof(buf), "Name:         %s\n", name);
 
	p += seprintf(p, lastof(buf), "Savegame ver: %d\n", _sl_version);
 
	const char *type = "";
 
	extern SaveLoadVersion _sl_is_faked_ext;
 
	extern bool _sl_is_ext_version;
 
	if (_sl_is_faked_ext != SL_MIN_VERSION) {
 
		type = " (fake extended)";
 
	} else if (_sl_is_ext_version) {
 
		type = " (extended)";
 
	}
 
	p += seprintf(p, lastof(buf), "Savegame ver: %d%s\n", _sl_version, type);
 
	for (size_t i = 0; i < XSLFI_SIZE; i++) {
 
		if (_sl_xv_feature_versions[i] > 0) {
 
			p += seprintf(p, lastof(buf), "    Feature: %s = %d\n", SlXvGetFeatureName((SlXvFeatureIndex) i), _sl_xv_feature_versions[i]);
 
		}
 
	}
 
	p += seprintf(p, lastof(buf), "NewGRF ver:   0x%08X\n", last_ottd_rev);
 
	p += seprintf(p, lastof(buf), "Modified:     %d\n", ever_modified);
 

	
 
@@ -1047,6 +1060,9 @@ void SwitchToMode(SwitchMode new_mode)
 
				OnStartGame(_network_dedicated);
 
				/* Decrease pause counter (was increased from opening load dialog) */
 
				Command<CMD_PAUSE>::Post(PM_PAUSED_SAVELOAD, false);
 
				if (_is_network_server && _settings_client.network.save_password) {
 
					NetworkLoadPassword();
 
				}
 
			}
 
			break;
 
		}
src/order_type.h
Show inline comments
 
@@ -94,6 +94,7 @@ enum OrderDepotTypeFlags {
 
	ODTF_MANUAL          = 0,      ///< Manually initiated order.
 
	ODTFB_SERVICE        = 1 << 0, ///< This depot order is because of the servicing limit.
 
	ODTFB_PART_OF_ORDERS = 1 << 1, ///< This depot order is because of a regular order.
 
	ODTFB_BREAKDOWN      = 1 << 2, ///< This depot order is because of a breakdown.
 
};
 

	
 
/**
src/rail_cmd.cpp
Show inline comments
 
@@ -415,7 +415,7 @@ static CommandCost CheckRailSlope(Slope 
 
	}
 

	
 
	Foundation f_old = GetRailFoundation(tileh, existing);
 
	return CommandCost(EXPENSES_CONSTRUCTION, f_new != f_old ? _price[PR_BUILD_FOUNDATION] : (Money)0);
 
	return CommandCost(EXPENSES_T_TRAIN_CON, f_new != f_old ? _price[PR_BUILD_FOUNDATION] : (Money)0);
 
}
 

	
 
/* Validate functions for rail building */
 
@@ -435,7 +435,7 @@ static inline bool ValParamTrackOrientat
 
 */
 
CommandCost CmdBuildSingleRail(DoCommandFlag flags, TileIndex tile, RailType railtype, Track track, bool auto_remove_signals)
 
{
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_TRAIN_CON);
 

	
 
	if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
 

	
 
@@ -618,7 +618,7 @@ CommandCost CmdBuildSingleRail(DoCommand
 
 */
 
CommandCost CmdRemoveSingleRail(DoCommandFlag flags, TileIndex tile, Track track)
 
{
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_TRAIN_CON);
 
	bool crossing = false;
 

	
 
	if (!ValParamTrackOrientation(track)) return CMD_ERROR;
 
@@ -877,7 +877,7 @@ static CommandCost ValidateAutoDrag(Trac
 
 */
 
static CommandCost CmdRailTrackHelper(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, RailType railtype, Track track, bool remove, bool auto_remove_signals, bool fail_on_obstacle)
 
{
 
	CommandCost total_cost(EXPENSES_CONSTRUCTION);
 
	CommandCost total_cost(EXPENSES_T_TRAIN_CON);
 

	
 
	if ((!remove && !ValParamRailtype(railtype)) || !ValParamTrackOrientation(track)) return CMD_ERROR;
 
	if (end_tile >= MapSize()) return CMD_ERROR;
 
@@ -1061,17 +1061,17 @@ CommandCost CmdBuildSingleSignal(DoComma
 
	CommandCost cost;
 
	if (!HasSignalOnTrack(tile, track)) {
 
		/* build new signals */
 
		cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
 
		cost = CommandCost(EXPENSES_T_TRAIN_CON, _price[PR_BUILD_SIGNALS]);
 
	} else {
 
		if (signals_copy != 0 && sigvar != GetSignalVariant(tile, track)) {
 
			/* convert signals <-> semaphores */
 
			cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
 
			cost = CommandCost(EXPENSES_T_TRAIN_CON, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
 

	
 
		} else if (convert_signal) {
 
			/* convert button pressed */
 
			if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
 
				/* convert electric <-> semaphore */
 
				cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
 
				cost = CommandCost(EXPENSES_T_TRAIN_CON, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
 
			} else {
 
				/* it is free to change signal type: normal-pre-exit-combo */
 
				cost = CommandCost();
 
@@ -1239,7 +1239,7 @@ static bool AdvanceSignalAutoFill(TileIn
 
 */
 
static CommandCost CmdSignalTrackHelper(DoCommandFlag flags, TileIndex tile, TileIndex end_tile, Track track, SignalType sigtype, SignalVariant sigvar, bool mode, bool remove, bool autofill, bool minimise_gaps, int signal_density)
 
{
 
	CommandCost total_cost(EXPENSES_CONSTRUCTION);
 
	CommandCost total_cost(EXPENSES_T_TRAIN_CON);
 

	
 
	if (end_tile >= MapSize() || !ValParamTrackOrientation(track)) return CMD_ERROR;
 
	if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
 
@@ -1492,7 +1492,7 @@ CommandCost CmdRemoveSingleSignal(DoComm
 
		MarkTileDirtyByTile(tile);
 
	}
 

	
 
	return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_SIGNALS]);
 
	return CommandCost(EXPENSES_T_TRAIN_CON, _price[PR_CLEAR_SIGNALS]);
 
}
 

	
 
/**
 
@@ -1541,7 +1541,7 @@ CommandCost CmdConvertRail(DoCommandFlag
 

	
 
	TrainList affected_trains;
 

	
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_TRAIN_CON);
 
	CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK); // by default, there is no track to convert.
 
	bool found_convertible_track = false; // whether we actually did convert some track (see bug #7633)
 

	
 
@@ -1777,12 +1777,12 @@ static CommandCost RemoveTrainDepot(Tile
 
		if (v != nullptr) TryPathReserve(v, true);
 
	}
 

	
 
	return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
 
	return CommandCost(EXPENSES_T_TRAIN_CON, _price[PR_CLEAR_DEPOT_TRAIN]);
 
}
 

	
 
static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
 
{
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_DEMOLITION);
 

	
 
	if (flags & DC_AUTO) {
 
		if (!IsTileOwner(tile, _current_company)) {
 
@@ -2997,7 +2997,7 @@ static CommandCost TestAutoslopeOnRailTi
 
		/* Surface slope must not be changed */
 
		default:
 
			if (z_old != z_new || tileh_old != tileh_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
 
			return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
			return CommandCost(EXPENSES_T_TRAIN_CON, _price[PR_BUILD_FOUNDATION]);
 
	}
 

	
 
	/* The height of the track_corner must not be changed. The rest ensures GetRailFoundation() already. */
 
@@ -3005,7 +3005,7 @@ static CommandCost TestAutoslopeOnRailTi
 
	z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
 
	if (z_old != z_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
 

	
 
	CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
	CommandCost cost = CommandCost(EXPENSES_T_TRAIN_CON, _price[PR_BUILD_FOUNDATION]);
 
	/* Make the ground dirty, if surface slope has changed */
 
	if (tileh_old != tileh_new) {
 
		/* If there is flat water on the lower halftile add the cost for clearing it */
 
@@ -3063,10 +3063,10 @@ static CommandCost TerraformTile_Track(T
 
		if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
 

	
 
		/* allow terraforming */
 
		return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
 
		return CommandCost(EXPENSES_T_TRAIN_CON, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
 
	} else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
 
			AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
 
		return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
		return CommandCost(EXPENSES_T_TRAIN_CON, _price[PR_BUILD_FOUNDATION]);
 
	}
 
	return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
 
}
src/rev.cpp.in
Show inline comments
 
@@ -38,7 +38,15 @@ bool IsReleasedVersion()
 
const char _openttd_revision[] = "${REV_VERSION}";
 

	
 
/**
 
 * The text version of OpenTTD's build date.
 
 * The text version of OpenTTD's build date in short format (without the time).
 
 * Updating the build date in this file is the safest as it generally gets
 
 * updated for each revision in contrary to most other files that only see
 
 * updates when they are actually changed themselves.
 
 */
 
const char _openttd_build_date_short[] = __DATE__;
 

	
 
/**
 
 * The text version of OpenTTD's build date and time.
 
 * Updating the build date in this file is the safest as it generally gets
 
 * updated for each revision in contrary to most other files that only see
 
 * updates when they are actually changed themselves.
 
@@ -62,6 +70,8 @@ const char _openttd_revision_year[] = "$
 
 * Value 0 means no modification, 1 is for unknown state
 
 * (compiling from sources without any version control software)
 
 * and 2 is for modified revision.
 
 *
 
 * Ginever patchpack uses value 3 for hg unmodified and 4 for hg modified
 
 */
 
const byte _openttd_revision_modified = ${REV_MODIFIED};
 

	
src/rev.h
Show inline comments
 
@@ -12,6 +12,7 @@
 

	
 
extern const char _openttd_revision[];
 
extern const char _openttd_build_date[];
 
extern const char _openttd_build_date_short[];
 
extern const char _openttd_revision_hash[];
 
extern const char _openttd_revision_year[];
 
extern const byte _openttd_revision_modified;
src/road_cmd.cpp
Show inline comments
 
@@ -370,7 +370,7 @@ static CommandCost RemoveRoad(TileIndex 
 
		/* If it's the last roadtype, just clear the whole tile */
 
		if (GetRoadType(tile, OtherRoadTramType(rtt)) == INVALID_ROADTYPE) return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
 

	
 
		CommandCost cost(EXPENSES_CONSTRUCTION);
 
		CommandCost cost(EXPENSES_T_ROAD_CON);
 
		if (IsTileType(tile, MP_TUNNELBRIDGE)) {
 
			/* Removing any roadbit in the bridge axis removes the roadtype (that's the behaviour remove-long-roads needs) */
 
			if ((AxisToRoadBits(DiagDirToAxis(GetTunnelBridgeDirection(tile))) & pieces) == ROAD_NONE) return_cmd_error((rtt == RTT_TRAM) ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD);
 
@@ -489,7 +489,7 @@ static CommandCost RemoveRoad(TileIndex 
 
				}
 
			}
 

	
 
			CommandCost cost(EXPENSES_CONSTRUCTION, CountBits(pieces) * RoadClearCost(existing_rt));
 
			CommandCost cost(EXPENSES_T_ROAD_CON, CountBits(pieces) * RoadClearCost(existing_rt));
 
			/* If we build a foundation we have to pay for it. */
 
			if (f == FOUNDATION_NONE && GetRoadFoundation(tileh, present) != FOUNDATION_NONE) cost.AddCost(_price[PR_BUILD_FOUNDATION]);
 

	
 
@@ -525,7 +525,7 @@ static CommandCost RemoveRoad(TileIndex 
 
				MarkTileDirtyByTile(tile);
 
				YapfNotifyTrackLayoutChange(tile, railtrack);
 
			}
 
			return CommandCost(EXPENSES_CONSTRUCTION, RoadClearCost(existing_rt) * 2);
 
			return CommandCost(EXPENSES_T_ROAD_CON, RoadClearCost(existing_rt) * 2);
 
		}
 

	
 
		default:
 
@@ -569,7 +569,7 @@ static CommandCost CheckRoadSlope(Slope 
 
	if (_settings_game.construction.build_on_slopes && (_invalid_tileh_slopes_road[0][tileh] & (other | type_bits)) == ROAD_NONE) {
 

	
 
		/* If we add leveling we've got to pay for it */
 
		if ((other | existing) == ROAD_NONE) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
		if ((other | existing) == ROAD_NONE) return CommandCost(EXPENSES_T_ROAD_CON, _price[PR_BUILD_FOUNDATION]);
 

	
 
		return CommandCost();
 
	}
 
@@ -589,12 +589,12 @@ static CommandCost CheckRoadSlope(Slope 
 
			if (_settings_game.construction.build_on_slopes) {
 

	
 
				/* If we add foundation we've got to pay for it */
 
				if ((other | existing) == ROAD_NONE) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
				if ((other | existing) == ROAD_NONE) return CommandCost(EXPENSES_T_ROAD_CON, _price[PR_BUILD_FOUNDATION]);
 

	
 
				return CommandCost();
 
			}
 
		} else {
 
			if (HasExactlyOneBit(existing) && GetRoadFoundation(tileh, existing) == FOUNDATION_NONE) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
			if (HasExactlyOneBit(existing) && GetRoadFoundation(tileh, existing) == FOUNDATION_NONE) return CommandCost(EXPENSES_T_ROAD_CON, _price[PR_BUILD_FOUNDATION]);
 
			return CommandCost();
 
		}
 
	}
 
@@ -614,7 +614,7 @@ static CommandCost CheckRoadSlope(Slope 
 
CommandCost CmdBuildRoad(DoCommandFlag flags, TileIndex tile, RoadBits pieces, RoadType rt, DisallowedRoadDirections toggle_drd, TownID town_id)
 
{
 
	CompanyID company = _current_company;
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_ROAD_CON);
 

	
 
	RoadBits existing = ROAD_NONE;
 
	RoadBits other_bits = ROAD_NONE;
 
@@ -782,7 +782,7 @@ CommandCost CmdBuildRoad(DoCommandFlag f
 
				UpdateLevelCrossing(tile, false);
 
				MarkTileDirtyByTile(tile);
 
			}
 
			return CommandCost(EXPENSES_CONSTRUCTION, 2 * RoadBuildCost(rt));
 
			return CommandCost(EXPENSES_T_ROAD_CON, 2 * RoadBuildCost(rt));
 
		}
 

	
 
		case MP_STATION: {
 
@@ -999,7 +999,7 @@ CommandCost CmdBuildLongRoad(DoCommandFl
 
	 * when you just 'click' on one tile to build them. */
 
	if ((drd == DRD_NORTHBOUND || drd == DRD_SOUTHBOUND) && (axis == AXIS_Y) == (start_tile == end_tile && start_half == end_half)) drd ^= DRD_BOTH;
 

	
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_ROAD_CON);
 
	CommandCost last_error = CMD_ERROR;
 
	TileIndex tile = start_tile;
 
	bool had_bridge = false;
 
@@ -1072,7 +1072,7 @@ CommandCost CmdBuildLongRoad(DoCommandFl
 
 */
 
std::tuple<CommandCost, Money> CmdRemoveLongRoad(DoCommandFlag flags, TileIndex start_tile, TileIndex end_tile, RoadType rt, Axis axis, bool start_half, bool end_half)
 
{
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_ROAD_CON);
 

	
 
	if (end_tile >= MapSize()) return { CMD_ERROR, 0 };
 
	if (!ValParamRoadType(rt) || !IsValidAxis(axis)) return { CMD_ERROR, 0 };
 
@@ -1204,7 +1204,7 @@ static CommandCost RemoveRoadDepot(TileI
 
		DoClearSquare(tile);
 
	}
 

	
 
	return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_ROAD]);
 
	return CommandCost(EXPENSES_T_ROAD_CON, _price[PR_CLEAR_DEPOT_ROAD]);
 
}
 

	
 
static CommandCost ClearTile_Road(TileIndex tile, DoCommandFlag flags)
 
@@ -1215,7 +1215,7 @@ static CommandCost ClearTile_Road(TileIn
 

	
 
			/* Clear the road if only one piece is on the tile OR we are not using the DC_AUTO flag */
 
			if ((HasExactlyOneBit(b) && GetRoadBits(tile, RTT_TRAM) == ROAD_NONE) || !(flags & DC_AUTO)) {
 
				CommandCost ret(EXPENSES_CONSTRUCTION);
 
				CommandCost ret(EXPENSES_T_DEMOLITION);
 
				for (RoadTramType rtt : _roadtramtypes) {
 
					if (!MayHaveRoad(tile) || GetRoadType(tile, rtt) == INVALID_ROADTYPE) continue;
 

	
 
@@ -1229,7 +1229,7 @@ static CommandCost ClearTile_Road(TileIn
 
		}
 

	
 
		case ROAD_TILE_CROSSING: {
 
			CommandCost ret(EXPENSES_CONSTRUCTION);
 
			CommandCost ret(EXPENSES_T_DEMOLITION);
 

	
 
			if (flags & DC_AUTO) return_cmd_error(STR_ERROR_MUST_REMOVE_ROAD_FIRST);
 

	
 
@@ -1650,7 +1650,6 @@ static void DrawTile_Road(TileInfo *ti)
 
			if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
 

	
 
			Axis axis = GetCrossingRailAxis(ti->tile);
 

	
 
			const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
 

	
 
			RoadType road_rt = GetRoadTypeRoad(ti->tile);
 
@@ -2226,11 +2225,11 @@ static CommandCost TerraformTile_Road(Ti
 
	if (_settings_game.construction.build_on_slopes && AutoslopeEnabled()) {
 
		switch (GetRoadTileType(tile)) {
 
			case ROAD_TILE_CROSSING:
 
				if (!IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new)) && HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
				if (!IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new)) && HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh_new)) return CommandCost(EXPENSES_T_ROAD_CON, _price[PR_BUILD_FOUNDATION]);
 
				break;
 

	
 
			case ROAD_TILE_DEPOT:
 
				if (AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRoadDepotDirection(tile))) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
				if (AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRoadDepotDirection(tile))) return CommandCost(EXPENSES_T_ROAD_CON, _price[PR_BUILD_FOUNDATION]);
 
				break;
 

	
 
			case ROAD_TILE_NORMAL: {
 
@@ -2248,7 +2247,7 @@ static CommandCost TerraformTile_Road(Ti
 
						z_new += ApplyFoundationToSlope(GetRoadFoundation(tileh_new, bits), &tileh_new);
 

	
 
						/* The surface slope must not be changed */
 
						if ((z_old == z_new) && (tileh_old == tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
						if ((z_old == z_new) && (tileh_old == tileh_new)) return CommandCost(EXPENSES_T_ROAD_CON, _price[PR_BUILD_FOUNDATION]);
 
					}
 
				}
 
				break;
src/roadveh.h
Show inline comments
 
@@ -184,6 +184,8 @@ protected: // These functions should not
 
		if (!this->IsArticulatedPart()) {
 
			/* Road vehicle weight is in units of 1/4 t. */
 
			weight += GetVehicleProperty(this, PROP_ROADVEH_WEIGHT, RoadVehInfo(this->engine_type)->weight) / 4;
 
			//DIRTY HACK
 
			if ( !weight ) weight = 1; //at least 1 for realistic accelerate
 
		}
 

	
 
		return weight;
src/roadveh_cmd.cpp
Show inline comments
 
@@ -294,6 +294,7 @@ CommandCost CmdBuildRoadVehicle(DoComman
 

	
 
		v->reliability = e->reliability;
 
		v->reliability_spd_dec = e->reliability_spd_dec;
 
		v->breakdown_chance = 128;
 
		v->max_age = e->GetLifeLengthInDays();
 

	
 
		v->SetServiceInterval(Company::Get(v->owner)->settings.vehicle.servint_roadveh);
 
@@ -375,7 +376,6 @@ CommandCost CmdTurnRoadVeh(DoCommandFlag
 

	
 
	if ((v->vehstatus & VS_STOPPED) ||
 
			(v->vehstatus & VS_CRASHED) ||
 
			v->breakdown_ctr != 0 ||
 
			v->overtaking != 0 ||
 
			v->state == RVSB_WORMHOLE ||
 
			v->IsInDepot() ||
 
@@ -812,6 +812,9 @@ static void RoadVehCheckOvertake(RoadVeh
 
	/* For now, articulated road vehicles can't overtake anything. */
 
	if (v->HasArticulatedPart()) return;
 

	
 
	/* Don't overtake if the vehicle is broken or about to break down */
 
	if (v->breakdown_ctr != 0) return;
 

	
 
	/* Vehicles are not driving in same direction || direction is not a diagonal direction */
 
	if (v->direction != u->direction || !(v->direction & 1)) return;
 

	
 
@@ -1573,8 +1576,7 @@ static bool RoadVehController(RoadVehicl
 
	}
 

	
 
	/* road vehicle has broken down? */
 
	if (v->HandleBreakdown()) return true;
 
	if (v->vehstatus & VS_STOPPED) {
 
	if (v->HandleBreakdown() || v->vehstatus & VS_STOPPED) {
 
		v->SetLastSpeed();
 
		return true;
 
	}
 
@@ -1634,6 +1636,7 @@ Money RoadVehicle::GetRunningCost() cons
 
	if (e->u.road.running_cost_class == INVALID_PRICE) return 0;
 

	
 
	uint cost_factor = GetVehicleProperty(this, PROP_ROADVEH_RUNNING_COST_FACTOR, e->u.road.running_cost);
 
	cost_factor *= _settings_game.economy.running_cost_multiplier_road;
 
	if (cost_factor == 0) return 0;
 

	
 
	return GetPrice(e->u.road.running_cost_class, cost_factor, e->GetGRF());
src/saveload/CMakeLists.txt
Show inline comments
 
@@ -13,6 +13,8 @@ add_files(
 
    depot_sl.cpp
 
    economy_sl.cpp
 
    engine_sl.cpp
 
    extended_ver_sl.cpp
 
    extended_ver_sl.h
 
    game_sl.cpp
 
    gamelog_sl.cpp
 
    goal_sl.cpp
 
@@ -31,6 +33,7 @@ add_files(
 
    order_sl.cpp
 
    saveload.cpp
 
    saveload.h
 
    saveload_buffer.h
 
    saveload_filter.h
 
    saveload_internal.h
 
    settings_sl.cpp
src/saveload/afterload.cpp
Show inline comments
 
@@ -59,6 +59,7 @@
 

	
 

	
 
#include "saveload_internal.h"
 
#include "extended_ver_sl.h"
 

	
 
#include <signal.h>
 

	
 
@@ -750,6 +751,9 @@ bool AfterLoadGame()
 
		_settings_game.construction.max_bridge_length = 64;
 
		_settings_game.construction.max_tunnel_length = 64;
 
	}
 
	if (SlXvIsFeatureMissing(XSLFI_DAYLENGTH)) {
 
		_settings_game.economy.daylength_multiplier = 1;
 
	}
 
	if (IsSavegameVersionBefore(SLV_166))  _settings_game.economy.infrastructure_maintenance = false;
 
	if (IsSavegameVersionBefore(SLV_183)) {
 
		_settings_game.linkgraph.distribution_pax = DT_MANUAL;
 
@@ -757,6 +761,9 @@ bool AfterLoadGame()
 
		_settings_game.linkgraph.distribution_armoured = DT_MANUAL;
 
		_settings_game.linkgraph.distribution_default = DT_MANUAL;
 
	}
 
	if (SlXvIsFeatureMissing(XSLFI_TOWN_IMPROVEMENTS)) {
 
		_settings_game.economy.town_growth_multiplier = _settings_game.economy.daylength_multiplier;
 
	}
 

	
 
	if (IsSavegameVersionBefore(SLV_ENDING_YEAR)) {
 
		_settings_game.game_creation.ending_year = DEF_END_YEAR;
 
@@ -2419,6 +2426,23 @@ bool AfterLoadGame()
 
		for (Depot *d : Depot::Iterate()) d->build_date = _date;
 
	}
 

	
 
	if (!SlXvIsFeaturePresent(XSLFI_EXTRA_EXPENSES, 2, 2))
 
	{
 
		// expenses size isn't currently 23. fix the array which now contains broken data
 

	
 
		bool first_extension_present = SlXvIsFeaturePresent(XSLFI_EXTRA_EXPENSES, 1, 1);
 
		int old_expenses_size = first_extension_present ? 22 : 13;
 
		int new_expenses_size = 23;
 
		int second_expenses_offset = old_expenses_size - (new_expenses_size - old_expenses_size);
 

	
 
		for (Company* c : Company::Iterate()) {
 
			std::copy_backward(&c->yearly_expenses[1][second_expenses_offset], &c->yearly_expenses[1][second_expenses_offset] + old_expenses_size, &c->yearly_expenses[2][0] + old_expenses_size);
 
			std::copy_backward(&c->yearly_expenses[0][old_expenses_size], &c->yearly_expenses[0][old_expenses_size] + old_expenses_size, &c->yearly_expenses[1][0] + old_expenses_size);
 
			std::fill_n(&c->yearly_expenses[0][old_expenses_size], new_expenses_size - old_expenses_size, 0);
 
			std::fill_n(&c->yearly_expenses[1][old_expenses_size], new_expenses_size - old_expenses_size, 0);
 
		}
 
	}
 

	
 
	/* In old versions it was possible to remove an airport while a plane was
 
	 * taking off or landing. This gives all kind of problems when building
 
	 * another airport in the same station so we don't allow that anymore.
 
@@ -2822,6 +2846,37 @@ bool AfterLoadGame()
 
	 * which is done by StartupEngines(). */
 
	if (gcf_res != GLC_ALL_GOOD) StartupEngines();
 

	
 
	/* Set some breakdown-related variables to the correct values. */
 
	if (SlXvIsFeatureMissing(XSLFI_IMPROVED_BREAKDOWNS)) {
 

	
 
		for (Vehicle *v : Vehicle::Iterate()) {
 
			switch(v->type) {
 
				case VEH_TRAIN: {
 
					if (Train::From(v)->IsFrontEngine()) {
 
						if (v->breakdown_ctr == 1) SetBit(Train::From(v)->flags, VRF_BREAKDOWN_STOPPED);
 
					} else if (Train::From(v)->IsEngine() || Train::From(v)->IsMultiheaded()) {
 
						/** Non-front engines could have a reliability of 0.
 
						 * Set it to the reliability of the front engine or the maximum, whichever is lower. */
 
						const Engine *e = Engine::Get(v->engine_type);
 
						v->reliability_spd_dec = e->reliability_spd_dec;
 
						v->reliability = std::min(v->First()->reliability, e->reliability);
 
					}
 
				}
 
				case VEH_ROAD:
 
					v->breakdown_chance = 128;
 
					break;
 
				case VEH_SHIP:
 
					v->breakdown_chance = 64;
 
					break;
 
				case VEH_AIRCRAFT:
 
					v->breakdown_chance = Clamp(64 + (AircraftVehInfo(v->engine_type)->max_speed >> 3), 0, 255);
 
					v->breakdown_severity = 40;
 
					break;
 
				default: break;
 
			}
 
		}
 
	}
 

	
 
	/* The road owner of standard road stops was not properly accounted for. */
 
	if (IsSavegameVersionBefore(SLV_172)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
src/saveload/company_sl.cpp
Show inline comments
 
@@ -19,6 +19,7 @@
 
#include "../tunnelbridge.h"
 
#include "../station_base.h"
 
#include "../strings_func.h"
 
#include "../settings_func.h"
 

	
 
#include "table/strings.h"
 

	
 
@@ -481,9 +482,11 @@ static const SaveLoad _company_desc[] = 
 
	SLE_CONDVAR(CompanyProperties, bankrupt_value,        SLE_VAR_I64 | SLE_FILE_I32,  SL_MIN_VERSION, SLV_65),
 
	SLE_CONDVAR(CompanyProperties, bankrupt_value,        SLE_INT64,                  SLV_65, SL_MAX_VERSION),
 

	
 
	/* yearly expenses was changed to 64-bit in savegame version 2. */
 
	// please check afterload for XSLFI_EXTRA_EXPENSES before editing this again
 
	SLE_CONDARR(CompanyProperties, yearly_expenses,       SLE_FILE_I32 | SLE_VAR_I64, 3 * 13, SL_MIN_VERSION, SLV_2),
 
	SLE_CONDARR(CompanyProperties, yearly_expenses,       SLE_INT64, 3 * 13,                  SLV_2, SL_MAX_VERSION),
 
	SLE_CONDARR_X(CompanyProperties, yearly_expenses,       SLE_INT64, 3 * 13,                  SLV_2, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_EXTRA_EXPENSES, 0, 0)),
 
	SLE_CONDARR_X(CompanyProperties, yearly_expenses,       SLE_INT64, 3 * 22,                  SLV_2, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_EXTRA_EXPENSES, 1, 1)),
 
	SLE_CONDARR_X(CompanyProperties, yearly_expenses,       SLE_INT64, 3 * 23,                  SLV_2, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_EXTRA_EXPENSES, 2, 2)),
 

	
 
	SLE_CONDVAR(CompanyProperties, is_ai,                 SLE_BOOL,                    SLV_2, SL_MAX_VERSION),
 

	
src/saveload/compat/industry_sl_compat.h
Show inline comments
 
@@ -49,7 +49,7 @@ const SaveLoadCompat _industry_sl_compat
 
	SLC_VAR("exclusive_consumer"),
 
	SLC_VAR("storage"),
 
	SLC_VAR("psa"),
 
	SLC_NULL(1, SLV_82, SLV_197),
 
	SLC_NULL_X(1, SLV_82, SLV_197, SlXvFeatureTest(XSLFTO_AND, XSLFI_EXTRA_EXPENSES, 0, 0)),
 
	SLC_VAR("random"),
 
	SLC_VAR("text"),
 
	SLC_NULL(32, SLV_2, SLV_144),
src/saveload/compat/settings_sl_compat.h
Show inline comments
 
@@ -38,6 +38,7 @@ const SaveLoadCompat _settings_sl_compat
 
	SLC_VAR("difficulty.competitor_speed"),
 
	SLC_NULL(1, SLV_97, SLV_110),
 
	SLC_VAR("difficulty.vehicle_breakdowns"),
 
	SLC_VAR("difficulty.vehicle_breakdown_scaler"),
 
	SLC_VAR("difficulty.subsidy_multiplier"),
 
	SLC_VAR("difficulty.subsidy_duration"),
 
	SLC_VAR("difficulty.construction_cost"),
 
@@ -69,6 +70,7 @@ const SaveLoadCompat _settings_sl_compat
 
	SLC_VAR("construction.max_tunnel_length"),
 
	SLC_NULL(1, SL_MIN_VERSION, SLV_159),
 
	SLC_VAR("construction.train_signal_side"),
 
	SLC_VAR("construction.name_stations_based_on_industries"),
 
	SLC_VAR("station.never_expire_airports"),
 
	SLC_VAR("economy.town_layout"),
 
	SLC_VAR("economy.allow_town_roads"),
 
@@ -118,8 +120,10 @@ const SaveLoadCompat _settings_sl_compat
 
	SLC_VAR("vehicle.freight_trains"),
 
	SLC_NULL(1, SLV_67, SLV_159),
 
	SLC_VAR("vehicle.plane_speed"),
 
	SLC_VAR("vehicle.plane_range_multiplier"),
 
	SLC_VAR("vehicle.dynamic_engines"),
 
	SLC_VAR("vehicle.plane_crashes"),
 
	SLC_VAR("vehicle.improved_breakdowns"),
 
	SLC_NULL(1, SL_MIN_VERSION, SLV_159),
 
	SLC_VAR("gui.sg_full_load_any"),
 
	SLC_VAR("order.improved_load"),
 
@@ -142,6 +146,7 @@ const SaveLoadCompat _settings_sl_compat
 
	SLC_VAR("economy.multiple_industry_per_town"),
 
	SLC_NULL(1, SL_MIN_VERSION, SLV_141),
 
	SLC_VAR("economy.bribe"),
 
	SLC_VAR("economy.bribe_risky"),
 
	SLC_VAR("economy.exclusive_rights"),
 
	SLC_VAR("economy.fund_buildings"),
 
	SLC_VAR("economy.fund_roads"),
 
@@ -154,6 +159,8 @@ 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.daylength_multiplier"),
 
	SLC_VAR("economy.town_growth_multiplier"),
 
	SLC_VAR("economy.allow_shares"),
 
	SLC_VAR("economy.min_years_for_shares"),
 
	SLC_VAR("economy.feeder_payment_share"),
 
@@ -179,6 +186,26 @@ const SaveLoadCompat _settings_sl_compat
 
	SLC_VAR("economy.town_noise_population[1]"),
 
	SLC_VAR("economy.town_noise_population[2]"),
 
	SLC_VAR("economy.infrastructure_maintenance"),
 
	SLC_VAR("economy.infrastructure_base_cost_rail"),
 
	SLC_VAR("economy.infrastructure_base_cost_road"),
 
	SLC_VAR("economy.infrastructure_base_cost_water"),
 
	SLC_VAR("economy.infrastructure_base_cost_air"),
 
	SLC_VAR("economy.infrastructure_base_cost_station"),
 
	SLC_VAR("economy.running_cost_multiplier_rail"),
 
	SLC_VAR("economy.running_cost_multiplier_road"),
 
	SLC_VAR("economy.running_cost_multiplier_water"),
 
	SLC_VAR("economy.running_cost_multiplier_air"),
 
	SLC_VAR("economy.dilapidation_max_amount"),
 
	SLC_VAR("economy.dilapidation_increase"),
 
	SLC_VAR("economy.dilapidation_decrease"),
 
	SLC_VAR("economy.dilapidation_pop_rail"),
 
	SLC_VAR("economy.dilapidation_pop_road"),
 
	SLC_VAR("economy.dilapidation_pop_water"),
 
	SLC_VAR("economy.dilapidation_pop_air"),
 
	SLC_VAR("economy.dilapidation_fine_rail"),
 
	SLC_VAR("economy.dilapidation_fine_road"),
 
	SLC_VAR("economy.dilapidation_fine_water"),
 
	SLC_VAR("economy.dilapidation_fine_air"),
 
	SLC_VAR("pf.wait_for_pbs_path"),
 
	SLC_VAR("pf.reserve_paths"),
 
	SLC_VAR("pf.path_backoff_interval"),
src/saveload/compat/station_sl_compat.h
Show inline comments
 
@@ -117,6 +117,7 @@ const SaveLoadCompat _station_normal_sl_
 
	SLC_VAR("had_vehicle_of_type"),
 
	SLC_VAR("loading_vehicles"),
 
	SLC_VAR("always_accepted"),
 
	SLC_VAR("dilapidation"),
 
	SLC_VAR("goods"),
 
};
 

	
src/saveload/compat/vehicle_sl_compat.h
Show inline comments
 
@@ -75,6 +75,8 @@ const SaveLoadCompat _vehicle_common_sl_
 
	SLC_VAR("breakdown_delay"),
 
	SLC_VAR("breakdowns_since_last_service"),
 
	SLC_VAR("breakdown_chance"),
 
	SLC_VAR("breakdown_type"),
 
	SLC_VAR("breakdown_severity"),
 
	SLC_VAR("build_year"),
 
	SLC_VAR("load_unload_ticks"),
 
	SLC_VAR("cargo_paid_for"),
src/saveload/extended_ver_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/*
 
 * 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 extended_ver_sl.cpp Functions related to handling save/load extended version info.
 
 *
 
 * Known extended features are stored in _sl_xv_feature_versions, features which are currently enabled/in use and their versions are stored in the savegame.
 
 * On load, the list of features and their versions are loaded from the savegame. If the savegame contains a feature which is either unknown, or has too high a version,
 
 * loading can be either aborted, or the feature can be ignored if the the feature flags in the savegame indicate that it can be ignored. The savegame may also list any additional
 
 * chunk IDs which are associated with an extended feature, these can be discarded if the feature is discarded.
 
 * This information is stored in the SLXI chunk, the contents of which has the following format:
 
 *
 
 * uint32                               chunk version
 
 * uint32                               chunk flags
 
 * uint32                               number of sub chunks/features
 
 *     For each of N sub chunk/feature:
 
 *     uint32                           feature flags (SlxiSubChunkFlags)
 
 *     uint16                           feature version
 
 *     SLE_STR                          feature name
 
 *     uint32*                          extra data length [only present iff feature flags & XSCF_EXTRA_DATA_PRESENT]
 
 *         N bytes                      extra data
 
 *     uint32*                          chunk ID list count [only present iff feature flags & XSCF_CHUNK_ID_LIST_PRESENT]
 
 *         N x uint32                   chunk ID list
 
 *
 
 * Extended features as recorded in the SLXI chunk, above, MAY add, remove, change, or otherwise modify fields in chunks
 
 * not owned by the feature and therefore not listed in the sub chunk/feature information in the SLXI chunk.
 
 * In this case the XSCF_IGNORABLE_UNKNOWN flag SHOULD NOT be set, as it is not possible to correctly load the modified chunk without
 
 * knowledge of the feature.
 
 * In the case where the modifications to other chunks vary with respect to lower feature versions, the XSCF_IGNORABLE_VERSION flag
 
 * also SHOULD NOT be set.
 
 * Use of the XSCF_IGNORABLE_UNKNOWN and XSCF_IGNORABLE_VERSION flags MUST ONLY be used in the cases where the feature and any
 
 * associated chunks can be cleanly dropped, and the savegame can be correctly loaded by a client with no knowledge of the feature.
 
 */
 

	
 
#include "../stdafx.h"
 
#include "../debug.h"
 
#include "saveload.h"
 
#include "saveload_buffer.h"
 
#include "extended_ver_sl.h"
 
#include "../rev.h"
 

	
 
#include <vector>
 
#include <string>
 

	
 
#include "../safeguards.h"
 

	
 
uint16 _sl_xv_feature_versions[XSLFI_SIZE];                 ///< array of all known feature types and their current versions
 
bool _sl_is_ext_version;                                    ///< is this an extended savegame version, with more info in the SLXI chunk?
 
bool _sl_might_be_legacy_patchpack_save;                    ///< might this be a save from an earlier version of the patchpack?
 
SaveLoadVersion _sl_is_faked_ext;                           ///< is this a faked extended savegame version, with no SLXI chunk? See: SlXvCheckSpecialSavegameVersions.
 
std::vector<uint32> _sl_xv_discardable_chunk_ids;           ///< list of chunks IDs which we can discard if no chunk loader exists
 
std::string _sl_xv_version_label;                           ///< optional SLXI version label
 

	
 
static const uint32 _sl_xv_slxi_chunk_version = 0;          ///< current version of SLXI chunk
 

	
 
static void loadVL(const SlxiSubChunkInfo* info, uint32 length);
 
static uint32 saveVL(const SlxiSubChunkInfo* info, bool dry_run);
 

	
 
const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
 
	{ XSLFI_VERSION_LABEL, XSCF_IGNORABLE_ALL, 1, 1, "version_label", saveVL, loadVL, nullptr },
 
	{ XSLFI_PATCHPACK_MAJOR_VERSION, XSCF_NULL, 6, 6, "ginever_patchpack_version", nullptr, nullptr, nullptr },
 
	{ XSLFI_DAYLENGTH, XSCF_NULL, 1, 1, "ginever_daylength", nullptr, nullptr, nullptr },
 
	{ XSLFI_STATION_NEWGRF, XSCF_NULL, 1, 1, "ginever_station_newgrf", nullptr, nullptr, nullptr },
 
	{ XSLFI_INFRASTRUCTURE, XSCF_NULL, 1, 1, "ginever_infrastructure", nullptr, nullptr, nullptr },
 
	{ XSLFI_RUNNING_COST_MULT, XSCF_NULL, 1, 1, "ginever_running_cost_mult", nullptr, nullptr, nullptr },
 
	{ XSLFI_PLANE_RANGE_MULT, XSCF_NULL, 1, 1, "ginever_plane_range_mult", nullptr, nullptr, nullptr },
 
	{ XSLFI_EXTRA_EXPENSES, XSCF_NULL, 2, 2, "ginever_extra_expenses", nullptr, nullptr, nullptr },
 
	{ XSLFI_IMPROVED_BREAKDOWNS, XSCF_NULL, 1, 1, "ginever_improved_breakdowns", nullptr, nullptr, nullptr },
 
	{ XSLFI_BREAKDOWN_SCALER, XSCF_NULL, 1, 1, "ginever_breakdown_scaler", nullptr, nullptr, nullptr },
 
	{ XSLFI_TOWN_IMPROVEMENTS, XSCF_NULL, 1, 1, "ginever_town_improvements", nullptr, nullptr, nullptr },
 
	{ XSLFI_DILAPIDATION, XSCF_NULL, 1, 1, "ginever_dilapidation", nullptr, nullptr, nullptr },
 

	
 
	{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
 
};
 

	
 
/**
 
 * Extended save/load feature test
 
 *
 
 * First performs a tradional check on the provided @p savegame_version against @p savegame_version_from and @p savegame_version_to.
 
 * Then, if the feature set in the constructor is not XSLFI_NULL, also check than the feature version is inclusively bounded by @p min_version and @p max_version,
 
 * and return the combination of the two tests using the operator defined in the constructor.
 
 * Otherwise just returns the result of the savegame version test
 
 */
 
bool SlXvFeatureTest::IsFeaturePresent(SaveLoadVersion savegame_version, SaveLoadVersion savegame_version_from, SaveLoadVersion savegame_version_to) const
 
{
 
	bool savegame_version_ok = savegame_version >= savegame_version_from && savegame_version < savegame_version_to;
 

	
 
	if (this->functor) return (*this->functor)(savegame_version, savegame_version_ok);
 

	
 
	if (this->feature == XSLFI_NULL) return savegame_version_ok;
 

	
 
	bool feature_ok = SlXvIsFeaturePresent(this->feature, this->min_version, this->max_version);
 

	
 
	switch (op) {
 
		case XSLFTO_OR:
 
			return savegame_version_ok || feature_ok;
 

	
 
		case XSLFTO_AND:
 
			return savegame_version_ok && feature_ok;
 

	
 
		default:
 
			NOT_REACHED();
 
			return false;
 
	}
 
}
 

	
 
/**
 
 * Returns true if @p feature is present and has a version inclusively bounded by @p min_version and @p max_version
 
 */
 
bool SlXvIsFeaturePresent(SlXvFeatureIndex feature, uint16 min_version, uint16 max_version)
 
{
 
	assert(feature < XSLFI_SIZE);
 
	return _sl_xv_feature_versions[feature] >= min_version && _sl_xv_feature_versions[feature] <= max_version;
 
}
 

	
 
/**
 
 * Returns true if @p feature is present and has a version inclusively bounded by @p min_version and @p max_version
 
 */
 
const char *SlXvGetFeatureName(SlXvFeatureIndex feature)
 
{
 
	const SlxiSubChunkInfo *info = _sl_xv_sub_chunk_infos;
 
	for (; info->index != XSLFI_NULL; ++info) {
 
		if (info->index == feature) {
 
			return info->name;
 
		}
 
	}
 
	return "(unknown feature)";
 
}
 

	
 
/**
 
 * Resets all extended feature versions to 0
 
 */
 
void SlXvResetState()
 
{
 
	_sl_is_ext_version = false;
 
	_sl_might_be_legacy_patchpack_save = false;
 
	_sl_is_faked_ext = SL_MIN_VERSION;
 
	_sl_xv_version_label = "";
 
	_sl_xv_discardable_chunk_ids.clear();
 
	memset(_sl_xv_feature_versions, 0, sizeof(_sl_xv_feature_versions));
 
}
 

	
 
/**
 
 * Resets all extended feature versions to their currently enabled versions, i.e. versions suitable for saving
 
 */
 
void SlXvSetCurrentState()
 
{
 
	SlXvResetState();
 
	_sl_is_ext_version = true;
 
	_sl_might_be_legacy_patchpack_save = false;
 

	
 
	const SlxiSubChunkInfo *info = _sl_xv_sub_chunk_infos;
 
	for (; info->index != XSLFI_NULL; ++info) {
 
		_sl_xv_feature_versions[info->index] = info->save_version;
 
	}
 
}
 

	
 
/**
 
 * Check for "special" savegame versions (i.e. known patchpacks) and set correct savegame version, settings, etc.
 
 * Only called if load_legacy_patchpack_savedata is enabled in settings.
 
 */
 
void SlXvCheckSpecialSavegameVersionsA()
 
{
 
	extern SaveLoadVersion _sl_version;
 
	if (_sl_version == SLV_PP1X
 
		|| _sl_version == SLV_PP2X
 
		|| _sl_version == SLV_PP3X
 
		|| _sl_version == SLV_PP4X
 
		|| _sl_version == SLV_PP5X_DAYLENGTH
 
		|| _sl_version == SLV_PP5X_HOTFIX_174
 
		|| _sl_version == SLV_PP5X_HOTFIX_175
 
		|| _sl_version == SLV_PP5X_HOTFIX_177
 
		|| _sl_version == SLV_PP5X_HOTFIX_187
 
		|| _sl_version == SLV_PP5X_STATION_NEWGRF
 
		|| _sl_version == SLV_PP5X_INFRASTRUCTURE
 
		|| _sl_version == SLV_PP5X_RUNNING_COST_MULT
 
		|| _sl_version == SLV_PP5X_PLANE_RANGE_MULT
 
		|| _sl_version == SLV_PP5X_HOTFIX_196
 
		|| _sl_version == SLV_PP5X_EXTRA_EXPENSES
 
		|| _sl_version == SLV_PP5X_HOTFIX_198
 
		|| _sl_version == SLV_PP5X_IMPROVED_BREAKDOWNS
 
		|| _sl_version == SLV_PP5X_BREAKDOWN_SCALER
 
		|| _sl_version == SLV_PP5X_TOWN_IMPROVEMENTS
 
		|| _sl_version == SLV_PP5X_DILAPIDATION
 
		|| _sl_version == SLV_PP5X_HOTFIX_222)
 
	{
 
		Debug(sl, 1, "Save version {} might be a patchpack save, flagging for save version checks", _sl_version);
 
		_sl_might_be_legacy_patchpack_save = true;
 
	}
 
}
 

	
 
/**
 
 * Check for "special" savegame versions (i.e. known patchpacks) and set correct savegame version, settings, etc.
 
 * Only called if load_legacy_patchpack_savedata is enabled in settings.
 
 */
 
void SlXvCheckSpecialSavegameVersionsB()
 
{
 
	if (!_sl_might_be_legacy_patchpack_save)
 
	{
 
		_load_check_data.save_version_label = _sl_xv_version_label;
 
		return;
 
	}
 
	_sl_might_be_legacy_patchpack_save = false;
 

	
 
	Debug(sl, 1, "Checking potential patchpack save against gamelog revision '{}'", _sl_xv_version_label);
 

	
 
	extern SaveLoadVersion _sl_version;
 
	SaveLoadVersion original_version = _sl_version;
 

	
 
	if (original_version == SLV_PP1X)
 
	{
 
		// the gamelog revision should be in the format "rXXXXXM-TTR Alp"
 
		if (_sl_xv_version_label.find("M-TTR") == 6)
 
		{
 
			_sl_is_faked_ext = original_version;
 
			_sl_xv_version_label = "ginever-1.x";
 
			_sl_version = SLV_100;
 
			_sl_xv_feature_versions[XSLFI_PATCHPACK_MAJOR_VERSION] = 1;
 
			//_sl_xv_feature_versions[XSLFI_LEGACY_DAYLENGTH] = 1;
 

	
 
			Debug(sl, 1, "Loading a patchpack 1.x savegame version {} as version {} with extensions", original_version, _sl_version);
 
			_load_check_data.save_ext_type = PSXT_MODIFIED;
 
			_load_check_data.save_version_label = _sl_xv_version_label;
 
			SlError(STR_GAME_SAVELOAD_ERROR_UNSUPPORTED_GPP); // temporary
 
			return;
 
		}
 
	}
 
	if (original_version == SLV_PP2X)
 
	{
 
		// the gamelog revision should be in the format "v2.XXXXX.YYY" or "Rev XXXXX-YYY"
 
		if (_sl_xv_version_label.find("v2.") == 0 || _sl_xv_version_label.find("-") == 9)
 
		{
 
			_sl_is_faked_ext = original_version;
 
			_sl_xv_version_label = "ginever-2.x";
 
			_sl_version = SLV_125;
 
			_sl_xv_feature_versions[XSLFI_PATCHPACK_MAJOR_VERSION] = 2;
 
			//_sl_xv_feature_versions[XSLFI_LEGACY_DAYLENGTH] = 2;
 

	
 
			Debug(sl, 1, "Loading a patchpack 2.x savegame version {} as version {} with extensions", original_version, _sl_version);
 
			_load_check_data.save_ext_type = PSXT_MODIFIED;
 
			_load_check_data.save_version_label = _sl_xv_version_label;
 
			SlError(STR_GAME_SAVELOAD_ERROR_UNSUPPORTED_GPP); // temporary
 
			return;
 
		}
 
	}
 
	if (original_version == SLV_PP3X)
 
	{
 
		// the gamelog revision should be in the format "v3.XXXXX.YYY"
 
		if (_sl_xv_version_label.find("v3.") == 0)
 
		{
 
			_sl_is_faked_ext = original_version;
 
			_sl_xv_version_label = "ginever-3.x";
 
			_sl_version = SLV_141;
 
			_sl_xv_feature_versions[XSLFI_PATCHPACK_MAJOR_VERSION] = 3;
 
			//_sl_xv_feature_versions[XSLFI_DAYLENGTH] = 1;
 
			//_sl_xv_feature_versions[XSLFI_LEGACY_CARGODIST] = 1;
 

	
 
			Debug(sl, 1, "Loading a patchpack 3.x savegame version {} as version {} with extensions", original_version, _sl_version);
 
			_load_check_data.save_ext_type = PSXT_MODIFIED;
 
			_load_check_data.save_version_label = _sl_xv_version_label;
 
			SlError(STR_GAME_SAVELOAD_ERROR_UNSUPPORTED_GPP); // temporary
 
			return;
 
		}
 
	}
 
	if (original_version == SLV_PP4X)
 
	{
 
		// the gamelog revision should be in the format "v4.XXXXX.YYY"
 
		if (_sl_xv_version_label.find("v4.") == 0)
 
		{
 
			_sl_is_faked_ext = original_version;
 
			_sl_xv_version_label = "ginever-4.x";
 
			_sl_version = SLV_142;
 
			_sl_xv_feature_versions[XSLFI_PATCHPACK_MAJOR_VERSION] = 4;
 
			//_sl_xv_feature_versions[XSLFI_DAYLENGTH] = 1;
 
			//_sl_xv_feature_versions[XSLFI_LEGACY_CARGODIST] = 2;
 

	
 
			Debug(sl, 1, "Loading a patchpack 4.x savegame version {} as version {} with extensions", original_version, _sl_version);
 
			_load_check_data.save_ext_type = PSXT_MODIFIED;
 
			_load_check_data.save_version_label = _sl_xv_version_label;
 
			SlError(STR_GAME_SAVELOAD_ERROR_UNSUPPORTED_GPP); // temporary
 
			return;
 
		}
 
	}
 
	if (original_version == SLV_PP5X_DAYLENGTH
 
		|| original_version == SLV_PP5X_HOTFIX_174
 
		|| original_version == SLV_PP5X_HOTFIX_175
 
		|| original_version == SLV_PP5X_HOTFIX_177
 
		|| original_version == SLV_PP5X_HOTFIX_187
 
		|| original_version == SLV_PP5X_STATION_NEWGRF
 
		|| original_version == SLV_PP5X_INFRASTRUCTURE
 
		|| original_version == SLV_PP5X_RUNNING_COST_MULT
 
		|| original_version == SLV_PP5X_PLANE_RANGE_MULT
 
		|| original_version == SLV_PP5X_HOTFIX_196
 
		|| original_version == SLV_PP5X_EXTRA_EXPENSES
 
		|| original_version == SLV_PP5X_HOTFIX_198
 
		|| original_version == SLV_PP5X_IMPROVED_BREAKDOWNS
 
		|| original_version == SLV_PP5X_BREAKDOWN_SCALER
 
		|| original_version == SLV_PP5X_TOWN_IMPROVEMENTS
 
		|| original_version == SLV_PP5X_DILAPIDATION
 
		|| original_version == SLV_PP5X_HOTFIX_222
 
		)
 
	{
 
		// the gamelog revision should be in the format "v5.XXXXX.YYY", but some of the newer versions have broken log messages and just printed "u"
 
		if (_sl_xv_version_label.find("v5.") == 0 || _sl_xv_version_label == "u")
 
		{
 
			_sl_xv_feature_versions[XSLFI_PATCHPACK_MAJOR_VERSION] = 5;
 
				
 
			if (original_version >= SLV_PP5X_DAYLENGTH)
 
			{
 
				_sl_is_faked_ext = original_version;
 
				_sl_xv_version_label = "ginever-5.x";
 
				_sl_version = SLV_160;
 
				_sl_xv_feature_versions[XSLFI_DAYLENGTH] = 1;
 
			}
 
			if (original_version >= SLV_PP5X_HOTFIX_174)
 
			{
 
				_sl_version = SLV_174;
 
			}
 
			if (original_version >= SLV_PP5X_HOTFIX_175)
 
			{
 
				_sl_version = SLV_175;
 
			}
 
			if (original_version >= SLV_PP5X_HOTFIX_177)
 
			{
 
				_sl_version = SLV_177;
 
			}
 
			if (original_version >= SLV_PP5X_HOTFIX_187)
 
			{
 
				_sl_version = SLV_187;
 
			}
 
			if (original_version >= SLV_PP5X_STATION_NEWGRF)
 
			{
 
				_sl_version = SLV_187;
 
				_sl_xv_feature_versions[XSLFI_STATION_NEWGRF] = 1;
 
			}
 
			if (original_version >= SLV_PP5X_INFRASTRUCTURE)
 
			{
 
				_sl_xv_feature_versions[XSLFI_INFRASTRUCTURE] = 1;
 
			}
 
			if (original_version >= SLV_PP5X_RUNNING_COST_MULT)
 
			{
 
				_sl_version = SLV_194;
 
				_sl_xv_feature_versions[XSLFI_RUNNING_COST_MULT] = 1;
 
			}
 
			if (original_version >= SLV_PP5X_PLANE_RANGE_MULT)
 
			{
 
				_sl_xv_feature_versions[XSLFI_PLANE_RANGE_MULT] = 1;
 
			}
 
			if (original_version >= SLV_PP5X_HOTFIX_196)
 
			{
 
				_sl_version = SLV_196;
 
			}
 
			if (original_version >= SLV_PP5X_EXTRA_EXPENSES)
 
			{
 
				_sl_xv_feature_versions[XSLFI_EXTRA_EXPENSES] = 1;
 
			}
 
			if (original_version >= SLV_PP5X_HOTFIX_198)
 
			{
 
				_sl_version = SLV_198;
 
			}
 
			if (original_version >= SLV_PP5X_IMPROVED_BREAKDOWNS)
 
			{
 
				_sl_version = SLV_MULTITILE_DOCKS;
 
				_sl_xv_feature_versions[XSLFI_IMPROVED_BREAKDOWNS] = 1;
 
			}
 
			if (original_version >= SLV_PP5X_BREAKDOWN_SCALER)
 
			{
 
				_sl_xv_feature_versions[XSLFI_BREAKDOWN_SCALER] = 1;
 
			}
 
			if (original_version >= SLV_PP5X_TOWN_IMPROVEMENTS)
 
			{
 
				_sl_xv_feature_versions[XSLFI_TOWN_IMPROVEMENTS] = 1;
 
			}
 
			if (original_version >= SLV_PP5X_DILAPIDATION)
 
			{
 
				_sl_xv_feature_versions[XSLFI_DILAPIDATION] = 1;
 
				_sl_xv_feature_versions[XSLFI_EXTRA_EXPENSES] = 2;
 
			}
 
			if (original_version >= SLV_PP5X_HOTFIX_222)
 
			{
 
				_sl_version = SLV_ENDING_YEAR;
 
			}
 

	
 
			Debug(sl, 1, "Loading a patchpack 5.x savegame version {} as version {} with extensions", original_version, _sl_version);
 
			_load_check_data.save_ext_type = PSXT_MODIFIED;
 
			_load_check_data.save_version_label = _sl_xv_version_label;
 
			return;
 
		}
 
	}
 

	
 
	Debug(sl, 1, "This doesn't appear to be a patchpack save");
 
	_load_check_data.save_version_label = _sl_xv_version_label;
 

	
 
	// now we have to restore the original OTTD invalid save version check for non-Ginever patchpacks since we had to previously disable it
 
	if (original_version >= SLV_START_PATCHPACKS && original_version < SLV_END_PATCHPACKS) SlError(STR_GAME_SAVELOAD_ERROR_PATCHPACK);
 
}
 

	
 
/**
 
 * Return true if this chunk has been marked as discardable
 
 */
 
bool SlXvIsChunkDiscardable(uint32 id)
 
{
 
	for (size_t i = 0; i < _sl_xv_discardable_chunk_ids.size(); i++) {
 
		if (_sl_xv_discardable_chunk_ids[i] == id) {
 
			return true;
 
		}
 
	}
 
	return false;
 
}
 

	
 
/**
 
 * Writes a chunk ID list string to the savegame, returns the number of chunks written
 
 * In dry run mode, only returns the number of chunk which would have been written
 
 */
 
static uint32 WriteChunkIdList(const char *chunk_list, bool dry_run)
 
{
 
	unsigned int chunk_count = 0;  // number of chunks output
 
	unsigned int id_offset = 0;    // how far are we into the ID
 
	for (; *chunk_list != 0; chunk_list++) {
 
		if (id_offset == 4) {
 
			assert(*chunk_list == ',');
 
			id_offset = 0;
 
		} else {
 
			if (!dry_run) {
 
				SlWriteByte(*chunk_list);
 
			}
 
			if (id_offset == 3) {
 
				chunk_count++;
 
			}
 
			id_offset++;
 
		}
 
	}
 
	assert(id_offset == 4);
 
	return chunk_count;
 
}
 

	
 
char name_buffer[256];
 

	
 
static void loadVL(const SlxiSubChunkInfo* info, uint32 length)
 
{
 
	_sl_xv_version_label.resize(length);
 
	ReadBuffer::GetCurrent()->CopyBytes(reinterpret_cast<byte*>(_sl_xv_version_label.data()), length);
 
	Debug(sl, 2, "SLXI version label: %s", _sl_xv_version_label.c_str());
 
	_load_check_data.save_version_label = _sl_xv_version_label; // allows early print of version if extension is detected
 
}
 

	
 
static uint32 saveVL(const SlxiSubChunkInfo* info, bool dry_run)
 
{
 
	const size_t length = strlen(_openttd_revision);
 
	if (!dry_run) MemoryDumper::GetCurrent()->CopyBytes(const_cast<byte*>(reinterpret_cast<const byte*>(_openttd_revision)), length);
 
	return static_cast<uint32>(length);
 
}
 

	
 
struct SLXIChunkHandler : ChunkHandler {
 
	SLXIChunkHandler() : ChunkHandler('SLXI', CH_RIFF) {}
 

	
 
	void LoadCheck(size_t len = 0) const override
 
	{
 
		Load(); // required to be able to correctly interpret other check data
 
	}
 

	
 
	void Load() const override
 
	{
 
		if (_sl_is_faked_ext != SL_MIN_VERSION || !_sl_is_ext_version || _sl_might_be_legacy_patchpack_save) {
 
			SlErrorCorrupt("SLXI chunk is unexpectedly present");
 
		}
 

	
 
		SlXvResetState();
 
		_sl_is_ext_version = true;
 

	
 
		uint32 version = SlReadUint32();
 
		if (version > _sl_xv_slxi_chunk_version) SlErrorCorruptFmt("SLXI chunk: version: %u is too new (expected max: %u)", version, _sl_xv_slxi_chunk_version);
 

	
 
		uint32 chunk_flags = SlReadUint32();
 
		// flags are not in use yet, reserve for future expansion
 
		if (chunk_flags != 0) SlErrorCorruptFmt("SLXI chunk: unknown chunk header flags: 0x%X", chunk_flags);
 

	
 
		const SaveLoad xlsi_sub_chunk_name_desc[] = {
 
			SLEG_STR("feature", name_buffer, SLE_STRB)
 
		};
 

	
 
		uint32 item_count = SlReadUint32();
 
		for (uint32 i = 0; i < item_count; i++) {
 
			SlxiSubChunkFlags flags = static_cast<SlxiSubChunkFlags>(SlReadUint32());
 
			uint16 version = SlReadUint16();
 
			SlGlobList(xlsi_sub_chunk_name_desc);
 

	
 
			// linearly scan through feature list until found name match
 
			bool found = false;
 
			const SlxiSubChunkInfo* info = _sl_xv_sub_chunk_infos;
 
			for (; info->index != XSLFI_NULL; ++info) {
 
				if (strcmp(name_buffer, info->name) == 0) {
 
					found = true;
 
					break;
 
				}
 
			}
 

	
 
			bool discard_chunks = false;
 
			if (found) {
 
				if (version > info->max_version) {
 
					if (flags & XSCF_IGNORABLE_VERSION) {
 
						// version too large but carry on regardless
 
						discard_chunks = true;
 
						if (flags & XSCF_EXTRA_DATA_PRESENT) {
 
							SlSkipBytes(SlReadUint32()); // skip extra data field
 
						}
 
						Debug(sl, 1, "SLXI chunk: too large version for feature: '{}', version: {}, max version: {}, ignoring", name_buffer, version, info->max_version);
 
					}
 
					else {
 
						SlErrorCorruptFmt("SLXI chunk: too large version for feature: '%s', version: %d, max version: %d", name_buffer, version, info->max_version);
 
					}
 
				}
 
				else {
 
					// success path :)
 

	
 
					_sl_xv_feature_versions[info->index] = version;
 
					if (flags & XSCF_EXTRA_DATA_PRESENT) {
 
						uint32 extra_data_size = SlReadUint32();
 
						if (extra_data_size) {
 
							if (info->load_proc) {
 
								size_t read = SlGetBytesRead();
 
								info->load_proc(info, extra_data_size);
 
								if (SlGetBytesRead() != read + extra_data_size) {
 
									SlErrorCorruptFmt("SLXI chunk: feature: %s, version: %d, extra data length mismatch", name_buffer, version);
 
								}
 
							}
 
							else {
 
								SlErrorCorruptFmt("SLXI chunk: feature: %s, version: %d, unexpectedly includes extra data", name_buffer, version);
 
							}
 
						}
 
					}
 

	
 
					Debug(sl, 1, "SLXI chunk: found known feature: '{}', version: {}, max version: {}", name_buffer, version, info->max_version);
 
				}
 
			}
 
			else {
 
				if (flags & XSCF_IGNORABLE_UNKNOWN) {
 
					// not found but carry on regardless
 
					discard_chunks = true;
 
					if (flags & XSCF_EXTRA_DATA_PRESENT) {
 
						SlSkipBytes(SlReadUint32()); // skip extra data field
 
					}
 
					Debug(sl, 1, "SLXI chunk: unknown feature: '{}', version: {}, ignoring", name_buffer, version);
 
				}
 
				else {
 
					SlErrorCorruptFmt("SLXI chunk: unknown feature: %s, version: %d", name_buffer, version);
 
				}
 
			}
 

	
 
			// at this point the extra data field should have been consumed
 
			// handle chunk ID list field
 
			if (flags & XSCF_CHUNK_ID_LIST_PRESENT) {
 
				uint32 chunk_count = SlReadUint32();
 
				for (uint32 j = 0; j < chunk_count; j++) {
 
					uint32 chunk_id = SlReadUint32();
 
					if (discard_chunks) {
 
						_sl_xv_discardable_chunk_ids.push_back(chunk_id);
 
						Debug(sl, 2, "SLXI chunk: unknown feature: '{}', discarding chunk: {:c}{:c}{:c}{:c}", name_buffer, chunk_id >> 24, chunk_id >> 16, chunk_id >> 8, chunk_id);
 
					}
 
				}
 
			}
 
		}
 
	}
 

	
 
	void Save() const override
 
	{
 
		SlXvSetCurrentState();
 

	
 
		static const SaveLoad _xlsi_sub_chunk_desc[] = {
 
			SLE_STR(SlxiSubChunkInfo, name,           SLE_STR, 0)
 
		};
 

	
 
		// calculate lengths
 
		uint32 item_count = 0;
 
		uint32 length = 12;
 
		std::vector<uint32> extra_data_lengths;
 
		std::vector<uint32> chunk_counts;
 
		extra_data_lengths.resize(XSLFI_SIZE);
 
		chunk_counts.resize(XSLFI_SIZE);
 
		const SlxiSubChunkInfo* info = _sl_xv_sub_chunk_infos;
 
		for (; info->index != XSLFI_NULL; ++info) {
 
			if (_sl_xv_feature_versions[info->index] > 0) {
 
				item_count++;
 
				length += 6;
 
				length += (uint32)SlCalcObjLength(info, _xlsi_sub_chunk_desc);
 
				if (info->save_proc) {
 
					uint32 extra_data_length = info->save_proc(info, true);
 
					if (extra_data_length) {
 
						extra_data_lengths[info->index] = extra_data_length;
 
						length += 4 + extra_data_length;
 
					}
 
				}
 
				if (info->chunk_list) {
 
					uint32 chunk_count = WriteChunkIdList(info->chunk_list, true);
 
					if (chunk_count) {
 
						chunk_counts[info->index] = chunk_count;
 
						length += 4 * (1 + chunk_count);
 
					}
 
				}
 
			}
 
		}
 

	
 
		// write header
 
		SlSetLength(length);
 
		SlWriteUint32(_sl_xv_slxi_chunk_version);               // chunk version
 
		SlWriteUint32(0);                                       // flags
 
		SlWriteUint32(item_count);                              // item count
 

	
 
		// write data
 
		info = _sl_xv_sub_chunk_infos;
 
		for (; info->index != XSLFI_NULL; ++info) {
 
			uint16 save_version = _sl_xv_feature_versions[info->index];
 
			if (save_version > 0) {
 
				SlxiSubChunkFlags flags = info->flags;
 
				assert(!(flags & (XSCF_EXTRA_DATA_PRESENT | XSCF_CHUNK_ID_LIST_PRESENT)));
 
				uint32 extra_data_length = extra_data_lengths[info->index];
 
				uint32 chunk_count = chunk_counts[info->index];
 
				if (extra_data_length > 0) flags |= XSCF_EXTRA_DATA_PRESENT;
 
				if (chunk_count > 0) flags |= XSCF_CHUNK_ID_LIST_PRESENT;
 
				SlWriteUint32(flags);
 
				SlWriteUint16(save_version);
 
				SlObject(const_cast<SlxiSubChunkInfo*>(info), _xlsi_sub_chunk_desc);
 

	
 
				if (extra_data_length > 0) {
 
					SlWriteUint32(extra_data_length);
 
					size_t written = SlGetBytesWritten();
 
					info->save_proc(info, false);
 
					assert(SlGetBytesWritten() == written + extra_data_length);
 
				}
 
				if (chunk_count > 0) {
 
					SlWriteUint32(chunk_count);
 
					size_t written = SlGetBytesWritten();
 
					WriteChunkIdList(info->chunk_list, false);
 
					assert(SlGetBytesWritten() == written + (chunk_count * 4));
 
				}
 
			}
 
		}
 
	}
 
};
 

	
 
static const SLXIChunkHandler SLXI;
 
static const ChunkHandlerRef version_ext_chunk_handlers[] = {
 
	SLXI,
 
};
 

	
 
extern const ChunkHandlerTable _version_ext_chunk_handlers(version_ext_chunk_handlers);
src/saveload/extended_ver_sl.h
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/*
 
 * 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 extended_ver_sl.h Functions/types related to handling save/load extended version info. */
 

	
 
#ifndef EXTENDED_VER_SL_H
 
#define EXTENDED_VER_SL_H
 

	
 
#include "../core/bitmath_func.hpp"
 

	
 
#include <vector>
 

	
 
enum SaveLoadVersion : uint16;
 

	
 
/**
 
 * List of extended features, each feature has its own (16 bit) version
 
 */
 
enum SlXvFeatureIndex {
 
	XSLFI_NULL                          = 0,      ///< Unused value, to indicate that no extended feature test is in use
 
	//===================================
 
	// COMMON EXTENDED FEATURES
 
	//===================================
 
	XSLFI_VERSION_LABEL,                          ///< Version label
 
	XSLFI_PATCHPACK_MAJOR_VERSION,                ///< Patchpack major version
 
	//===================================
 
	// PATCHPACK 5.X FEATURES
 
	//===================================
 
	XSLFI_DAYLENGTH,                              ///< Variable day length
 
	XSLFI_STATION_NEWGRF,                         ///< Station names based on industries
 
	XSLFI_INFRASTRUCTURE,                         ///< Custom infrastructure base costs
 
	XSLFI_RUNNING_COST_MULT,                      ///< Running cost multiplier
 
	XSLFI_PLANE_RANGE_MULT,                       ///< Plane range multiplier
 
	XSLFI_EXTRA_EXPENSES,                         ///< Additional expense types in the expenses window
 
	XSLFI_IMPROVED_BREAKDOWNS,                    ///< Improved breakdowns patch
 
	XSLFI_BREAKDOWN_SCALER,                       ///< Additional breakdown chance scaler
 
	XSLFI_TOWN_IMPROVEMENTS,                      ///< Configurable bribe risk and town growth factor
 
	XSLFI_DILAPIDATION,                           ///< Station dilapidation
 
	//===================================
 
	XSLFI_SIZE,                                   ///< Total count of features, including null feature
 
};
 

	
 
extern uint16 _sl_xv_feature_versions[XSLFI_SIZE];
 

	
 
/**
 
 * Operator to use when combining traditional savegame number test with an extended feature version test
 
 */
 
enum SlXvFeatureTestOperator {
 
	XSLFTO_OR                           = 0,      ///< Test if traditional savegame version is in bounds OR extended feature is in version bounds
 
	XSLFTO_AND                                    ///< Test if traditional savegame version is in bounds AND extended feature is in version bounds
 
};
 

	
 
/**
 
 * Structure to describe an extended feature version test, and how it combines with a traditional savegame version test
 
 */
 
struct SlXvFeatureTest {
 
	using TestFunctorPtr = bool (*)(uint16, bool);  ///< Return true if feature present, first parameter is standard savegame version, second is whether standard savegame version is within bounds
 

	
 
	private:
 
	uint16 min_version;
 
	uint16 max_version;
 
	SlXvFeatureIndex feature;
 
	SlXvFeatureTestOperator op;
 
	TestFunctorPtr functor = nullptr;
 

	
 
	public:
 
	SlXvFeatureTest()
 
			: min_version(0), max_version(0), feature(XSLFI_NULL), op(XSLFTO_OR) { }
 

	
 
	SlXvFeatureTest(SlXvFeatureTestOperator op_, SlXvFeatureIndex feature_, uint16 min_version_ = 1, uint16 max_version_ = 0xFFFF)
 
			: min_version(min_version_), max_version(max_version_), feature(feature_), op(op_) { }
 

	
 
	SlXvFeatureTest(TestFunctorPtr functor_)
 
			: min_version(0), max_version(0), feature(XSLFI_NULL), op(XSLFTO_OR), functor(functor_) { }
 

	
 
	bool IsFeaturePresent(SaveLoadVersion savegame_version, SaveLoadVersion savegame_version_from, SaveLoadVersion savegame_version_to) const;
 
};
 

	
 
bool SlXvIsFeaturePresent(SlXvFeatureIndex feature, uint16 min_version = 1, uint16 max_version = 0xFFFF);
 

	
 
/**
 
 * Returns true if @p feature is missing (i.e. has a version of 0)
 
 */
 
inline bool SlXvIsFeatureMissing(SlXvFeatureIndex feature)
 
{
 
	return !SlXvIsFeaturePresent(feature);
 
}
 

	
 
const char *SlXvGetFeatureName(SlXvFeatureIndex feature);
 

	
 
/**
 
 * sub chunk flags, this is saved as-is
 
 * (XSCF_EXTRA_DATA_PRESENT and XSCF_CHUNK_ID_LIST_PRESENT must only be set by the save code, and read by the load code)
 
 */
 
enum SlxiSubChunkFlags {
 
	XSCF_NULL                     = 0,       ///< zero value
 
	XSCF_IGNORABLE_UNKNOWN        = 1 << 0,  ///< the loader is free to ignore this without aborting the load if it doesn't know what it is at all
 
	XSCF_IGNORABLE_VERSION        = 1 << 1,  ///< the loader is free to ignore this without aborting the load if the version is greater than the maximum that can be loaded
 
	XSCF_EXTRA_DATA_PRESENT       = 1 << 2,  ///< extra data field is present, extra data in some sub-chunk/feature specific format, not used for anything yet
 
	XSCF_CHUNK_ID_LIST_PRESENT    = 1 << 3,  ///< chunk ID list field is present, list of chunks which this sub-chunk/feature adds to the save game, this can be used to discard the chunks if the feature is unknown
 

	
 
	XSCF_IGNORABLE_ALL            = XSCF_IGNORABLE_UNKNOWN | XSCF_IGNORABLE_VERSION, ///< all "ignorable" flags
 
};
 
DECLARE_ENUM_AS_BIT_SET(SlxiSubChunkFlags)
 

	
 
struct SlxiSubChunkInfo;
 

	
 
typedef uint32 SlxiSubChunkSaveProc(const SlxiSubChunkInfo *info, bool dry_run);  ///< sub chunk save procedure type, must return length and write no data when dry_run is true
 
typedef void SlxiSubChunkLoadProc(const SlxiSubChunkInfo *info, uint32 length);   ///< sub chunk load procedure, must consume length bytes
 

	
 
/** Handlers and description of chunk. */
 
struct SlxiSubChunkInfo {
 
	SlXvFeatureIndex index;                       ///< feature index, this is saved
 
	SlxiSubChunkFlags flags;                      ///< flags, this is saved
 
	uint16 save_version;                          ///< version to save
 
	uint16 max_version;                           ///< maximum version to accept on load
 
	const char *name;                             ///< feature name, this *IS* saved, so must be globally unique
 
	SlxiSubChunkSaveProc *save_proc;              ///< save procedure of the sub chunk, this may be nullptr in which case no extra chunk data is saved
 
	SlxiSubChunkLoadProc *load_proc;              ///< load procedure of the sub chunk, this may be nullptr in which case the extra chunk data must be missing or of 0 length
 
	const char *chunk_list;                       ///< this is a list of chunks that this feature uses, which should be written to the savegame, this must be a comma-seperated list of 4-character IDs, with no spaces, or nullptr
 
};
 

	
 
void SlXvResetState();
 

	
 
void SlXvSetCurrentState();
 

	
 
void SlXvCheckSpecialSavegameVersionsA();
 

	
 
void SlXvCheckSpecialSavegameVersionsB();
 

	
 
bool SlXvIsChunkDiscardable(uint32 id);
 

	
 
#endif /* EXTENDED_VER_SL_H */
src/saveload/gamelog_sl.cpp
Show inline comments
 
@@ -11,12 +11,15 @@
 

	
 
#include "saveload.h"
 
#include "compat/gamelog_sl_compat.h"
 
#include "extended_ver_sl.h"
 

	
 
#include "../gamelog_internal.h"
 
#include "../fios.h"
 

	
 
#include "../safeguards.h"
 

	
 
extern bool _sl_is_ext_version;
 
extern std::string _sl_xv_version_label;
 

	
 
class SlGamelogMode : public DefaultSaveLoadHandler<SlGamelogMode, LoggedChange> {
 
public:
 
@@ -61,6 +64,11 @@ public:
 
	{
 
		if (lc->ct != GLCT_REVISION) return;
 
		SlObject(lc, this->GetLoadDescription());
 
		// update revision
 
		if (!_sl_is_ext_version)
 
		{
 
			_sl_xv_version_label = lc->revision.text;
 
		}
 
	}
 

	
 
	void LoadCheck(LoggedChange *lc) const override { this->Load(lc); }
 
@@ -398,11 +406,13 @@ struct GLOGChunkHandler : ChunkHandler {
 
	void Load() const override
 
	{
 
		this->LoadCommon(_gamelog_action, _gamelog_actions);
 
		SlXvCheckSpecialSavegameVersionsB();
 
	}
 

	
 
	void LoadCheck(size_t) const override
 
	{
 
		this->LoadCommon(_load_check_data.gamelog_action, _load_check_data.gamelog_actions);
 
		SlXvCheckSpecialSavegameVersionsB();
 
	}
 
};
 

	
src/saveload/saveload.cpp
Show inline comments
 
@@ -52,6 +52,7 @@
 

	
 
#include "table/strings.h"
 

	
 
#include "saveload_buffer.h"
 
#include "saveload_internal.h"
 
#include "saveload_filter.h"
 

	
 
@@ -59,6 +60,8 @@
 

	
 
extern const SaveLoadVersion SAVEGAME_VERSION = (SaveLoadVersion)(SL_MAX_VERSION - 1); ///< Current savegame version of OpenTTD.
 

	
 
const SaveLoadVersion SAVEGAME_VERSION_EXT = (SaveLoadVersion)(0x8000); ///< Savegame extension indicator mask
 

	
 
SavegameType _savegame_type; ///< type of savegame we are loading
 
FileToSaveLoad _file_to_saveload; ///< File to save or load in the openttd loop.
 

	
 
@@ -68,6 +71,11 @@ byte   _sl_minor_version;     ///< the m
 
std::string _savegame_format; ///< how to compress savegames
 
bool _do_autosave;            ///< are we doing an autosave at the moment?
 

	
 
extern bool _sl_is_ext_version;
 
extern bool _sl_might_be_legacy_patchpack_save;
 
extern SaveLoadVersion _sl_is_faked_ext;
 
extern std::string _sl_xv_version_label;
 

	
 
/** What are we currently doing? */
 
enum SaveLoadAction {
 
	SLA_LOAD,        ///< loading
 
@@ -83,113 +91,6 @@ enum NeedLength {
 
	NL_CALCLENGTH = 2, ///< need to calculate the length
 
};
 

	
 
/** Save in chunks of 128 KiB. */
 
static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
 

	
 
/** A buffer for reading (and buffering) savegame data. */
 
struct ReadBuffer {
 
	byte buf[MEMORY_CHUNK_SIZE]; ///< Buffer we're going to read from.
 
	byte *bufp;                  ///< Location we're at reading the buffer.
 
	byte *bufe;                  ///< End of the buffer we can read from.
 
	LoadFilter *reader;          ///< The filter used to actually read.
 
	size_t read;                 ///< The amount of read bytes so far from the filter.
 

	
 
	/**
 
	 * Initialise our variables.
 
	 * @param reader The filter to actually read data.
 
	 */
 
	ReadBuffer(LoadFilter *reader) : bufp(nullptr), bufe(nullptr), reader(reader), read(0)
 
	{
 
	}
 

	
 
	inline byte ReadByte()
 
	{
 
		if (this->bufp == this->bufe) {
 
			size_t len = this->reader->Read(this->buf, lengthof(this->buf));
 
			if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
 

	
 
			this->read += len;
 
			this->bufp = this->buf;
 
			this->bufe = this->buf + len;
 
		}
 

	
 
		return *this->bufp++;
 
	}
 

	
 
	/**
 
	 * Get the size of the memory dump made so far.
 
	 * @return The size.
 
	 */
 
	size_t GetSize() const
 
	{
 
		return this->read - (this->bufe - this->bufp);
 
	}
 
};
 

	
 

	
 
/** Container for dumping the savegame (quickly) to memory. */
 
struct MemoryDumper {
 
	std::vector<byte *> blocks; ///< Buffer with blocks of allocated memory.
 
	byte *buf;                  ///< Buffer we're going to write to.
 
	byte *bufe;                 ///< End of the buffer we write to.
 

	
 
	/** Initialise our variables. */
 
	MemoryDumper() : buf(nullptr), bufe(nullptr)
 
	{
 
	}
 

	
 
	~MemoryDumper()
 
	{
 
		for (auto p : this->blocks) {
 
			free(p);
 
		}
 
	}
 

	
 
	/**
 
	 * Write a single byte into the dumper.
 
	 * @param b The byte to write.
 
	 */
 
	inline void WriteByte(byte b)
 
	{
 
		/* Are we at the end of this chunk? */
 
		if (this->buf == this->bufe) {
 
			this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
 
			this->blocks.push_back(this->buf);
 
			this->bufe = this->buf + MEMORY_CHUNK_SIZE;
 
		}
 

	
 
		*this->buf++ = b;
 
	}
 

	
 
	/**
 
	 * Flush this dumper into a writer.
 
	 * @param writer The filter we want to use.
 
	 */
 
	void Flush(SaveFilter *writer)
 
	{
 
		uint i = 0;
 
		size_t t = this->GetSize();
 

	
 
		while (t > 0) {
 
			size_t to_write = std::min(MEMORY_CHUNK_SIZE, t);
 

	
 
			writer->Write(this->blocks[i++], to_write);
 
			t -= to_write;
 
		}
 

	
 
		writer->Finish();
 
	}
 

	
 
	/**
 
	 * Get the size of the memory dump made so far.
 
	 * @return The size.
 
	 */
 
	size_t GetSize() const
 
	{
 
		return this->blocks.size() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
 
	}
 
};
 

	
 
/** The saveload struct, containing reader-writer functions, buffer, version, etc. */
 
struct SaveLoadParams {
 
	SaveLoadAction action;               ///< are we doing a save or a load atm.
 
@@ -216,9 +117,127 @@ struct SaveLoadParams {
 

	
 
static SaveLoadParams _sl; ///< Parameters used for/at saveload.
 

	
 
void ReadBuffer::SkipBytesSlowPath(size_t bytes)
 
{
 
	bytes -= (this->bufe - this->bufp);
 
	while (true) {
 
		size_t len = this->reader->Read(this->buf, lengthof(this->buf));
 
		if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
 
		this->read += len;
 
		if (len >= bytes) {
 
			this->bufp = this->buf + bytes;
 
			this->bufe = this->buf + len;
 
			return;
 
		}
 
		else {
 
			bytes -= len;
 
		}
 
	}
 
}
 

	
 
void ReadBuffer::AcquireBytes()
 
{
 
	size_t remainder = this->bufe - this->bufp;
 
	if (remainder) {
 
		memmove(this->buf, this->bufp, remainder);
 
	}
 
	size_t len = this->reader->Read(this->buf + remainder, lengthof(this->buf) - remainder);
 
	if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
 

	
 
	this->read += len;
 
	this->bufp = this->buf;
 
	this->bufe = this->buf + remainder + len;
 
}
 

	
 
void MemoryDumper::FinaliseBlock()
 
{
 
	assert(this->saved_buf == nullptr);
 
	if (!this->blocks.empty()) {
 
		size_t s = MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
 
		this->blocks.back().size = s;
 
		this->completed_block_bytes += s;
 
	}
 
	this->buf = this->bufe = nullptr;
 
}
 

	
 
void MemoryDumper::AllocateBuffer()
 
{
 
	if (this->saved_buf) {
 
		const size_t offset = this->buf - this->autolen_buf;
 
		const size_t size = (this->autolen_buf_end - this->autolen_buf) * 2;
 
		this->autolen_buf = ReallocT<byte>(this->autolen_buf, size);
 
		this->autolen_buf_end = this->autolen_buf + size;
 
		this->buf = this->autolen_buf + offset;
 
		this->bufe = this->autolen_buf_end;
 
		return;
 
	}
 
	this->FinaliseBlock();
 
	this->buf = MallocT<byte>(MEMORY_CHUNK_SIZE);
 
	this->blocks.emplace_back(this->buf);
 
	this->bufe = this->buf + MEMORY_CHUNK_SIZE;
 
}
 

	
 
/**
 
 * Flush this dumper into a writer.
 
 * @param writer The filter we want to use.
 
 */
 
void MemoryDumper::Flush(SaveFilter* writer)
 
{
 
	this->FinaliseBlock();
 

	
 
	size_t block_count = this->blocks.size();
 
	for (size_t i = 0; i < block_count; i++) {
 
		writer->Write(this->blocks[i].data, this->blocks[i].size);
 
	}
 

	
 
	writer->Finish();
 
}
 

	
 
void MemoryDumper::StartAutoLength()
 
{
 
	assert(this->saved_buf == nullptr);
 

	
 
	this->saved_buf = this->buf;
 
	this->saved_bufe = this->bufe;
 
	this->buf = this->autolen_buf;
 
	this->bufe = this->autolen_buf_end;
 
}
 

	
 
std::pair<byte*, size_t> MemoryDumper::StopAutoLength()
 
{
 
	assert(this->saved_buf != nullptr);
 
	auto res = std::make_pair(this->autolen_buf, this->buf - this->autolen_buf);
 

	
 
	this->buf = this->saved_buf;
 
	this->bufe = this->saved_bufe;
 
	this->saved_buf = this->saved_bufe = nullptr;
 
	return res;
 
}
 

	
 
/**
 
 * Get the size of the memory dump made so far.
 
 * @return The size.
 
 */
 
size_t MemoryDumper::GetSize() const
 
{
 
	assert(this->saved_buf == nullptr);
 
	return this->completed_block_bytes + (this->bufe ? (MEMORY_CHUNK_SIZE - (this->bufe - this->buf)) : 0);
 
}
 

	
 
ReadBuffer* ReadBuffer::GetCurrent()
 
{
 
	return _sl.reader;
 
}
 

	
 
MemoryDumper* MemoryDumper::GetCurrent()
 
{
 
	return _sl.dumper;
 
}
 

	
 
static const std::vector<ChunkHandlerRef> &ChunkHandlers()
 
{
 
	/* These define the chunks */
 
	extern const ChunkHandlerTable _version_ext_chunk_handlers;
 
	extern const ChunkHandlerTable _gamelog_chunk_handlers;
 
	extern const ChunkHandlerTable _map_chunk_handlers;
 
	extern const ChunkHandlerTable _misc_chunk_handlers;
 
@@ -255,6 +274,7 @@ static const std::vector<ChunkHandlerRef
 

	
 
	/** List of all chunks in a savegame. */
 
	static const ChunkHandlerTable _chunk_handler_tables[] = {
 
		_version_ext_chunk_handlers,
 
		_gamelog_chunk_handlers,
 
		_map_chunk_handlers,
 
		_misc_chunk_handlers,
 
@@ -312,6 +332,7 @@ static void SlNullPointers()
 
	 * during NULLing; especially those that try to get
 
	 * pointers from other pools. */
 
	_sl_version = SAVEGAME_VERSION;
 
	SlXvSetCurrentState();
 

	
 
	for (const ChunkHandler &ch : ChunkHandlers()) {
 
		Debug(sl, 3, "Nulling pointers for {:c}{:c}{:c}{:c}", ch.id >> 24, ch.id >> 16, ch.id >> 8, ch.id);
 
@@ -435,41 +456,60 @@ void SlWriteByte(byte b)
 
	_sl.dumper->WriteByte(b);
 
}
 

	
 
static inline int SlReadUint16()
 
int SlReadUint16()
 
{
 
	int x = SlReadByte() << 8;
 
	return x | SlReadByte();
 
	_sl.reader->CheckBytes(2);
 
	return _sl.reader->RawReadUint16();
 
}
 

	
 
static inline uint32 SlReadUint32()
 
uint32 SlReadUint32()
 
{
 
	uint32 x = SlReadUint16() << 16;
 
	return x | SlReadUint16();
 
	_sl.reader->CheckBytes(4);
 
	return _sl.reader->RawReadUint32();
 
}
 

	
 
static inline uint64 SlReadUint64()
 
uint64 SlReadUint64()
 
{
 
	uint32 x = SlReadUint32();
 
	uint32 y = SlReadUint32();
 
	return (uint64)x << 32 | y;
 
	_sl.reader->CheckBytes(8);
 
	return _sl.reader->RawReadUint64();
 
}
 

	
 
void SlWriteUint16(uint16 v)
 
{
 
	_sl.dumper->CheckBytes(2);
 
	_sl.dumper->RawWriteUint16(v);
 
}
 

	
 
static inline void SlWriteUint16(uint16 v)
 
void SlWriteUint32(uint32 v)
 
{
 
	SlWriteByte(GB(v, 8, 8));
 
	SlWriteByte(GB(v, 0, 8));
 
	_sl.dumper->CheckBytes(4);
 
	_sl.dumper->RawWriteUint32(v);
 
}
 

	
 
static inline void SlWriteUint32(uint32 v)
 
void SlWriteUint64(uint64 x)
 
{
 
	SlWriteUint16(GB(v, 16, 16));
 
	SlWriteUint16(GB(v,  0, 16));
 
	_sl.dumper->CheckBytes(8);
 
	_sl.dumper->RawWriteUint64(x);
 
}
 

	
 
static inline void SlWriteUint64(uint64 x)
 
/**
 
 * Returns number of bytes read so far
 
 * May only be called during a load/load check action
 
 */
 
size_t SlGetBytesRead()
 
{
 
	SlWriteUint32((uint32)(x >> 32));
 
	SlWriteUint32((uint32)x);
 
	assert(_sl.action == SLA_LOAD || _sl.action == SLA_LOAD_CHECK);
 
	return _sl.reader->GetSize();
 
}
 

	
 
/**
 
 * Returns number of bytes written so far
 
 * May only be called during a save action
 
 */
 
size_t SlGetBytesWritten()
 
{
 
	assert(_sl.action == SLA_SAVE);
 
	return _sl.dumper->GetSize();
 
}
 

	
 
/**
 
@@ -1060,6 +1100,9 @@ static void SlStdString(void *ptr, VarTy
 
		case SLA_LOAD_CHECK:
 
		case SLA_LOAD: {
 
			size_t len = SlReadArrayLength();
 
			if (len > 65535) {
 
				SlErrorCorrupt("String too long");
 
			}
 
			if (GetVarMemType(conv) == SLE_VAR_NULL) {
 
				SlSkipBytes(len);
 
				return;
 
@@ -1554,7 +1597,7 @@ static void SlVector(void *vector, VarTy
 
/** Are we going to save this object or not? */
 
static inline bool SlIsObjectValidInSavegame(const SaveLoad &sld)
 
{
 
	return (_sl_version >= sld.version_from && _sl_version < sld.version_to);
 
	return sld.ext_feature_test.IsFeaturePresent(_sl_version, sld.version_from, sld.version_to);
 
}
 

	
 
/**
 
@@ -2048,7 +2091,7 @@ std::vector<SaveLoad> SlCompatTableHeade
 
			/* In old savegames there can be data we no longer care for. We
 
			 * skip this by simply reading the amount of bytes indicated and
 
			 * send those to /dev/null. */
 
			saveloads.push_back({"", SL_NULL, SLE_FILE_U8 | SLE_VAR_NULL, slc.length, slc.version_from, slc.version_to, 0, nullptr, 0, nullptr});
 
			saveloads.push_back({"", SL_NULL, SLE_FILE_U8 | SLE_VAR_NULL, slc.length, slc.version_from, slc.version_to, 0, nullptr, 0, nullptr, slc.ext_feature_test});
 
		} else {
 
			auto sld_it = key_lookup.find(slc.name);
 
			/* If this branch triggers, it means that an entry in the
 
@@ -2061,6 +2104,7 @@ std::vector<SaveLoad> SlCompatTableHeade
 
				SlErrorCorrupt("Internal error with savegame compatibility");
 
			}
 
			for (auto &sld : sld_it->second) {
 
				if (!slc.ext_feature_test.IsFeaturePresent(_sl_version, SL_MIN_VERSION, SL_MAX_VERSION)) continue;
 
				saveloads.push_back(*sld);
 
			}
 
		}
 
@@ -2186,7 +2230,7 @@ static void SlLoadChunk(const ChunkHandl
 
 * If the chunkhandler is nullptr, the chunk is skipped.
 
 * @param ch The chunkhandler that will be used for the operation
 
 */
 
static void SlLoadCheckChunk(const ChunkHandler &ch)
 
static void SlLoadCheckChunk(const ChunkHandler* ch)
 
{
 
	byte m = SlReadByte();
 
	size_t len;
 
@@ -2206,11 +2250,25 @@ static void SlLoadCheckChunk(const Chunk
 
		case CH_TABLE:
 
		case CH_ARRAY:
 
			_sl.array_index = 0;
 
			ch.LoadCheck();
 
			if (ch)
 
			{
 
				ch->LoadCheck();
 
			}
 
			else
 
			{
 
				SlSkipArray();
 
			}
 
			break;
 
		case CH_SPARSE_TABLE:
 
		case CH_SPARSE_ARRAY:
 
			ch.LoadCheck();
 
			if (ch)
 
			{
 
				ch->LoadCheck();
 
			}
 
			else
 
			{
 
				SlSkipArray();
 
			}
 
			break;
 
		case CH_RIFF:
 
			/* Read length */
 
@@ -2218,7 +2276,13 @@ static void SlLoadCheckChunk(const Chunk
 
			len += SlReadUint16();
 
			_sl.obj_len = len;
 
			endoffs = _sl.reader->GetSize() + len;
 
			ch.LoadCheck(len);
 
			if (ch) {
 
				ch->LoadCheck(len);
 
			}
 
			else
 
			{
 
				SlSkipBytes(len);
 
			}
 
			if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
 
			break;
 
		default:
 
@@ -2230,6 +2294,25 @@ static void SlLoadCheckChunk(const Chunk
 
}
 

	
 
/**
 
 * Load a chunk of data for checking savegames.
 
 * @param ch The chunkhandler that will be used for the operation
 
 */
 
static void SlLoadCheckChunk(const ChunkHandler &ch)
 
{
 
	SlLoadCheckChunk(&ch);
 
}
 

	
 
/**
 
 * Skip unwanted chunk
 
 * @param id Chunk ID
 
 */
 
static void SlLoadSkipChunk(uint32 id)
 
{
 
	Debug(sl, 1, "Discarding chunk {:c}{:c}{:c}{:c}", id >> 24, id >> 16, id >> 8, id);
 
	SlLoadCheckChunk(nullptr);
 
}
 

	
 
/**
 
 * Save a chunk of data (eg. vehicles, stations, etc.). Each chunk is
 
 * prefixed by an ID identifying it, followed by data, and terminator where appropriate
 
 * @param ch The chunkhandler that will be used for the operation
 
@@ -2302,8 +2385,17 @@ static void SlLoadChunks()
 
		Debug(sl, 2, "Loading chunk {:c}{:c}{:c}{:c}", id >> 24, id >> 16, id >> 8, id);
 

	
 
		ch = SlFindChunkHandler(id);
 
		if (ch == nullptr) SlErrorCorrupt("Unknown chunk type");
 
		SlLoadChunk(*ch);
 
		if (ch == nullptr) {
 
			if (SlXvIsChunkDiscardable(id)) {
 
				SlLoadSkipChunk(id);
 
			}
 
			else {
 
				SlErrorCorrupt("Unknown chunk type");
 
			}
 
		}
 
		else {
 
			SlLoadChunk(*ch);
 
		}
 
	}
 
}
 

	
 
@@ -2317,8 +2409,17 @@ static void SlLoadCheckChunks()
 
		Debug(sl, 2, "Loading chunk {:c}{:c}{:c}{:c}", id >> 24, id >> 16, id >> 8, id);
 

	
 
		ch = SlFindChunkHandler(id);
 
		if (ch == nullptr) SlErrorCorrupt("Unknown chunk type");
 
		SlLoadCheckChunk(*ch);
 
		if (ch == nullptr) {
 
			if (SlXvIsChunkDiscardable(id)) {
 
				SlLoadSkipChunk(id);
 
			}
 
			else {
 
				SlErrorCorruptFmt("Unknown chunk type %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
 
			}
 
		}
 
		else {
 
			SlLoadCheckChunk(*ch);
 
		}
 
	}
 
}
 

	
 
@@ -2976,7 +3077,7 @@ static SaveOrLoadResult SaveFileToDisk(b
 
		const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
 

	
 
		/* We have written our stuff to memory, now write it to file! */
 
		uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
 
		uint32 hdr[2] = { fmt->tag, TO_BE32((uint32)(SAVEGAME_VERSION | SAVEGAME_VERSION_EXT) << 16) };
 
		_sl.sf->Write((byte*)hdr, sizeof(hdr));
 

	
 
		_sl.sf = fmt->init_write(_sl.sf, compression);
 
@@ -3035,6 +3136,7 @@ static SaveOrLoadResult DoSave(SaveFilte
 
	_sl.sf = writer;
 

	
 
	_sl_version = SAVEGAME_VERSION;
 
	SlXvSetCurrentState();
 

	
 
	SaveViewportBeforeSaveGame();
 
	SlSaveChunks();
 
@@ -3087,6 +3189,8 @@ static SaveOrLoadResult DoLoad(LoadFilte
 
		_load_check_data.checkable = true;
 
	}
 

	
 
	SlXvResetState();
 

	
 
	uint32 hdr[2];
 
	if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
 

	
 
@@ -3099,6 +3203,7 @@ static SaveOrLoadResult DoLoad(LoadFilte
 
			_sl.lf->Reset();
 
			_sl_version = SL_MIN_VERSION;
 
			_sl_minor_version = 0;
 
			SlXvResetState();
 

	
 
			/* Try to find the LZO savegame format; it uses 'OTTD' as tag. */
 
			fmt = _saveload_formats;
 
@@ -3121,11 +3226,18 @@ static SaveOrLoadResult DoLoad(LoadFilte
 
			 * Therefore it is loaded, but never saved (or, it saves a 0 in any scenario). */
 
			_sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
 

	
 
			Debug(sl, 1, "Loading savegame version {}", _sl_version);
 
			if (_sl_version & SAVEGAME_VERSION_EXT) {
 
				_sl_version = (SaveLoadVersion)(_sl_version & ~SAVEGAME_VERSION_EXT);
 
				_sl_is_ext_version = true;
 
			} else if (_settings_client.gui.load_legacy_patchpack_savedata ) {
 
				SlXvCheckSpecialSavegameVersionsA();
 
			}
 

	
 
			Debug(sl, 1, "Loading savegame version {}{}", _sl_version, _sl_is_ext_version ? " (extended)" : "");
 

	
 
			/* Is the version higher than the current? */
 
			if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
 
			if (_sl_version >= SLV_START_PATCHPACKS && _sl_version <= SLV_END_PATCHPACKS) SlError(STR_GAME_SAVELOAD_ERROR_PATCHPACK);
 
			if (_sl_version >= SLV_START_PATCHPACKS && _sl_version < SLV_END_PATCHPACKS && !_sl_might_be_legacy_patchpack_save) SlError(STR_GAME_SAVELOAD_ERROR_PATCHPACK);
 
			break;
 
		}
 

	
 
@@ -3182,6 +3294,8 @@ static SaveOrLoadResult DoLoad(LoadFilte
 
	if (load_check) {
 
		/* Load chunks into _load_check_data.
 
		 * No pools are loaded. References are not possible, and thus do not need resolving. */
 
		_load_check_data.save_version = _sl_is_faked_ext != SL_MIN_VERSION ? _sl_is_faked_ext : _sl_version;
 
		_load_check_data.save_ext_type = _sl_is_ext_version ? PSXT_EXTENDED : PSXT_NONE;
 
		SlLoadCheckChunks();
 
	} else {
 
		/* Load chunks and resolve references */
 
@@ -3207,6 +3321,7 @@ static SaveOrLoadResult DoLoad(LoadFilte
 
		}
 

	
 
		GamelogStopAction();
 
		SlXvSetCurrentState();
 
	}
 

	
 
	return SL_OK;
 
@@ -3263,12 +3378,14 @@ SaveOrLoadResult SaveOrLoad(const std::s
 
			if (!LoadOldSaveGame(filename)) return SL_REINIT;
 
			_sl_version = SL_MIN_VERSION;
 
			_sl_minor_version = 0;
 
			SlXvResetState();
 
			GamelogStartAction(GLAT_LOAD);
 
			if (!AfterLoadGame()) {
 
				GamelogStopAction();
 
				return SL_REINIT;
 
			}
 
			GamelogStopAction();
 
			SlXvSetCurrentState();
 
			return SL_OK;
 
		}
 

	
src/saveload/saveload.h
Show inline comments
 
@@ -18,6 +18,8 @@
 
#include <string>
 
#include <vector>
 

	
 
#include "extended_ver_sl.h"
 

	
 
/** SaveLoad versions
 
 * Previous savegame versions, the trunk revision where they were
 
 * introduced and the released version that had that particular
 
@@ -323,6 +325,30 @@ enum SaveLoadVersion : uint16 {
 
	 * its own chunk with feature toggles.
 
	 */
 
	SLV_START_PATCHPACKS,                   ///< 220  First known patchpack to use a version just above ours.
 

	
 
	// legacy patchpack version codes
 
	SLV_PP1X = 100,                         ///< 1.x
 
	SLV_PP2X = 126,                         ///< 2.x
 
	SLV_PP3X = 186,                         ///< 3.x
 
	SLV_PP4X = 189,                         ///< 4.20033.004 (conflicting with 5.x, because FGS)
 
	SLV_PP5X_DAYLENGTH = 160,               ///< 5.22434.001
 
	SLV_PP5X_HOTFIX_174 = 174,              ///< 5.23975.005b
 
	SLV_PP5X_HOTFIX_175 = 175,              ///< 5.24187.007
 
	SLV_PP5X_HOTFIX_177 = 177,              ///< 5.24771.008b
 
	SLV_PP5X_HOTFIX_187 = 187,              ///< 5.25942.009
 
	SLV_PP5X_STATION_NEWGRF = 188,          ///< 5.26167.011
 
	SLV_PP5X_INFRASTRUCTURE = 189,          ///< 5.26167.012
 
	SLV_PP5X_RUNNING_COST_MULT = 194,       ///< 5.27099.013
 
	SLV_PP5X_PLANE_RANGE_MULT = 195,        ///< 5.27500.016
 
	SLV_PP5X_HOTFIX_196 = 196,              ///< 5.27930.017
 
	SLV_PP5X_EXTRA_EXPENSES = 197,          ///< 5.27930.018
 
	SLV_PP5X_HOTFIX_198 = 198,              ///< 5.020
 
	SLV_PP5X_IMPROVED_BREAKDOWNS = 217,     ///< 5.022 dev
 
	SLV_PP5X_BREAKDOWN_SCALER = 218,        ///< 5.022 dev
 
	SLV_PP5X_TOWN_IMPROVEMENTS = 219,       ///< 5.022 dev
 
	SLV_PP5X_DILAPIDATION = 220,            ///< 5.022 final
 
	SLV_PP5X_HOTFIX_222 = 222,              ///< 5.024
 

	
 
	SLV_END_PATCHPACKS = 286,               ///< 286  Last known patchpack to use a version just above ours.
 

	
 
	SLV_GS_INDUSTRY_CONTROL,                ///< 287  PR#7912 and PR#8115 GS industry control.
 
@@ -663,6 +689,7 @@ struct SaveLoad {
 
	SaveLoadAddrProc *address_proc; ///< Callback proc the get the actual variable address in memory.
 
	size_t extra_data;              ///< Extra data for the callback proc.
 
	std::shared_ptr<SaveLoadHandler> handler; ///< Custom handler for Save/Load procs.
 
	SlXvFeatureTest ext_feature_test;  ///< extended feature test
 
};
 

	
 
/**
 
@@ -678,6 +705,7 @@ struct SaveLoadCompat {
 
	uint16 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.
 
	SlXvFeatureTest ext_feature_test;  ///< extended feature test
 
};
 

	
 
/**
 
@@ -689,9 +717,11 @@ struct SaveLoadCompat {
 
 * @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.
 
 * @param extver   Extended feature test
 
 * @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_X(cmd, base, variable, type, length, from, to, extra, extver) 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, extver}
 
#define SLE_GENERAL(cmd, base, variable, type, length, from, to, extra) SLE_GENERAL_X(cmd, base, variable, type, length, from, to, extra, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a variable in some savegame versions.
 
@@ -700,8 +730,10 @@ struct SaveLoadCompat {
 
 * @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.
 
 * @param extver   Extended feature test
 
 */
 
#define SLE_CONDVAR(base, variable, type, from, to) SLE_GENERAL(SL_VAR, base, variable, type, 0, from, to, 0)
 
#define SLE_CONDVAR_X(base, variable, type, from, to, extver) SLE_GENERAL_X(SL_VAR, base, variable, type, 0, from, to, 0, extver)
 
#define SLE_CONDVAR(base, variable, type, from, to) SLE_CONDVAR_X(base, variable, type, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a reference in some savegame versions.
 
@@ -710,8 +742,10 @@ struct SaveLoadCompat {
 
 * @param type     Type of the reference, a value from #SLRefType.
 
 * @param from     First savegame version that has the field.
 
 * @param to       Last savegame version that has the field.
 
 * @param extver   Extended feature test
 
 */
 
#define SLE_CONDREF(base, variable, type, from, to) SLE_GENERAL(SL_REF, base, variable, type, 0, from, to, 0)
 
#define SLE_CONDREF_X(base, variable, type, from, to, extver) SLE_GENERAL_X(SL_REF, base, variable, type, 0, from, to, 0, extver)
 
#define SLE_CONDREF(base, variable, type, from, to) SLE_CONDREF_X(base, variable, type, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a fixed-size array of #SL_VAR elements in some savegame versions.
 
@@ -721,8 +755,10 @@ struct SaveLoadCompat {
 
 * @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.
 
 * @param extver   Extended feature test
 
 */
 
#define SLE_CONDARR(base, variable, type, length, from, to) SLE_GENERAL(SL_ARR, base, variable, type, length, from, to, 0)
 
#define SLE_CONDARR_X(base, variable, type, length, from, to, extver) SLE_GENERAL_X(SL_ARR, base, variable, type, length, from, to, 0, extver)
 
#define SLE_CONDARR(base, variable, type, length, from, to) SLE_CONDARR_X(base, variable, type, length, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a string in some savegame versions.
 
@@ -732,8 +768,10 @@ struct SaveLoadCompat {
 
 * @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.
 
 * @param extver   Extended feature test
 
 */
 
#define SLE_CONDSTR(base, variable, type, length, from, to) SLE_GENERAL(SL_STR, base, variable, type, length, from, to, 0)
 
#define SLE_CONDSTR_X(base, variable, type, length, from, to, extver) SLE_GENERAL_X(SL_STR, base, variable, type, length, from, to, 0, extver)
 
#define SLE_CONDSTR(base, variable, type, length, from, to) SLE_CONDSTR_X(base, variable, type, length, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a \c std::string in some savegame versions.
 
@@ -742,8 +780,10 @@ struct SaveLoadCompat {
 
 * @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.
 
 * @param extver   Extended feature test
 
 */
 
#define SLE_CONDSSTR(base, variable, type, from, to) SLE_GENERAL(SL_STDSTR, base, variable, type, 0, from, to, 0)
 
#define SLE_CONDSSTR_X(base, variable, type, from, to, extver) SLE_GENERAL_X(SL_STDSTR, base, variable, type, 0, from, to, 0, extver)
 
#define SLE_CONDSSTR(base, variable, type, from, to) SLE_CONDSSTR_X(base, variable, type, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a list of #SL_REF elements in some savegame versions.
 
@@ -752,8 +792,10 @@ struct SaveLoadCompat {
 
 * @param type     Storage of the data in memory and in the savegame.
 
 * @param from     First savegame version that has the list.
 
 * @param to       Last savegame version that has the list.
 
 * @param extver   Extended feature test
 
 */
 
#define SLE_CONDREFLIST(base, variable, type, from, to) SLE_GENERAL(SL_REFLIST, base, variable, type, 0, from, to, 0)
 
#define SLE_CONDREFLIST_X(base, variable, type, from, to, extver) SLE_GENERAL_X(SL_REFLIST, base, variable, type, 0, from, to, 0, extver)
 
#define SLE_CONDREFLIST(base, variable, type, from, to) SLE_CONDREFLIST_X(base, variable, type, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a deque of #SL_VAR elements in some savegame versions.
 
@@ -762,8 +804,10 @@ struct SaveLoadCompat {
 
 * @param type     Storage of the data in memory and in the savegame.
 
 * @param from     First savegame version that has the list.
 
 * @param to       Last savegame version that has the list.
 
 * @param extver   Extended feature test
 
 */
 
#define SLE_CONDDEQUE(base, variable, type, from, to) SLE_GENERAL(SL_DEQUE, base, variable, type, 0, from, to, 0)
 
#define SLE_CONDDEQUE_X(base, variable, type, from, to, extver) SLE_GENERAL_X(SL_DEQUE, base, variable, type, 0, from, to, 0, extver)
 
#define SLE_CONDDEQUE(base, variable, type, from, to) SLE_CONDDEQUE_X(base, variable, type, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a variable in every version of a savegame.
 
@@ -837,8 +881,10 @@ struct SaveLoadCompat {
 
 * @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 SLEG_* macros below.
 
 * @param extver   Extended feature test
 
 */
 
#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_X(name, cmd, variable, type, length, from, to, extra, extver) SaveLoad {name, cmd, type, length, from, to, sizeof(variable), [] (void *, size_t) -> void * { return static_cast<void *>(std::addressof(variable)); }, extra, nullptr, extver}
 
#define SLEG_GENERAL(name, cmd, variable, type, length, from, to, extra) SLEG_GENERAL_X(name, cmd, variable, type, length, from, to, extra, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a global variable in some savegame versions.
 
@@ -847,8 +893,10 @@ struct SaveLoadCompat {
 
 * @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.
 
 * @param extver   Extended feature test
 
 */
 
#define SLEG_CONDVAR(name, variable, type, from, to) SLEG_GENERAL(name, SL_VAR, variable, type, 0, from, to, 0)
 
#define SLEG_CONDVAR_X(name, variable, type, from, to, extver) SLEG_GENERAL_X(name, SL_VAR, variable, type, 0, from, to, 0, extver)
 
#define SLEG_CONDVAR(name, variable, type, from, to) SLEG_CONDVAR_X(name, variable, type, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a global reference in some savegame versions.
 
@@ -857,8 +905,10 @@ struct SaveLoadCompat {
 
 * @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.
 
 * @param extver   Extended feature test
 
 */
 
#define SLEG_CONDREF(name, variable, type, from, to) SLEG_GENERAL(name, SL_REF, variable, type, 0, from, to, 0)
 
#define SLEG_CONDREF_X(name, variable, type, from, to, extver) SLEG_GENERAL_X(name, SL_REF, variable, type, 0, from, to, 0, extver)
 
#define SLEG_CONDREF(name, variable, type, from, to) SLEG_CONDREF_X(name, variable, type, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a global fixed-size array of #SL_VAR elements in some savegame versions.
 
@@ -868,8 +918,10 @@ struct SaveLoadCompat {
 
 * @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.
 
 * @param extver   Extended feature test
 
 */
 
#define SLEG_CONDARR(name, variable, type, length, from, to) SLEG_GENERAL(name, SL_ARR, variable, type, length, from, to, 0)
 
#define SLEG_CONDARR_X(name, variable, type, length, from, to, extver) SLEG_GENERAL_X(name, SL_ARR, variable, type, length, from, to, 0, extver)
 
#define SLEG_CONDARR(name, variable, type, length, from, to) SLEG_CONDARR_X(name, variable, type, length, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a global string in some savegame versions.
 
@@ -879,8 +931,10 @@ struct SaveLoadCompat {
 
 * @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.
 
 * @param extver   Extended feature test
 
 */
 
#define SLEG_CONDSTR(name, variable, type, length, from, to) SLEG_GENERAL(name, SL_STR, variable, type, length, from, to, 0)
 
#define SLEG_CONDSTR_X(name, variable, type, length, from, to, extver) SLEG_GENERAL_X(name, SL_STR, variable, type, length, from, to, 0, extver)
 
#define SLEG_CONDSTR(name, variable, type, length, from, to) SLEG_CONDSTR_X(name, variable, type, length, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a global \c std::string in some savegame versions.
 
@@ -889,8 +943,10 @@ struct SaveLoadCompat {
 
 * @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.
 
 * @param extver   Extended feature test
 
 */
 
#define SLEG_CONDSSTR(name, variable, type, from, to) SLEG_GENERAL(name, SL_STDSTR, variable, type, 0, from, to, 0)
 
#define SLEG_CONDSSTR_X(name, variable, type, from, to, extver) SLEG_GENERAL_X(name, SL_STDSTR, variable, type, 0, from, to, 0, extver)
 
#define SLEG_CONDSSTR(name, variable, type, from, to) SLEG_CONDSSTR_X(name, variable, type, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a structs in some savegame versions.
 
@@ -898,8 +954,10 @@ struct SaveLoadCompat {
 
 * @param handler  SaveLoadHandler for the structs.
 
 * @param from     First savegame version that has the struct.
 
 * @param to       Last savegame version that has the struct.
 
 * @param extver   Extended feature test
 
 */
 
#define SLEG_CONDSTRUCT(name, handler, from, to) SaveLoad {name, SL_STRUCT, 0, 0, from, to, 0, nullptr, 0, std::make_shared<handler>()}
 
#define SLEG_CONDSTRUCT_X(name, handler, from, to, extver) SaveLoad {name, SL_STRUCT, 0, 0, from, to, 0, nullptr, 0, std::make_shared<handler>(), extver}
 
#define SLEG_CONDSTRUCT(name, handler, from, to) SLEG_CONDSTRUCT_X(name, handler, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a global reference list in some savegame versions.
 
@@ -908,8 +966,10 @@ struct SaveLoadCompat {
 
 * @param type     Storage of the data in memory and in the savegame.
 
 * @param from     First savegame version that has the list.
 
 * @param to       Last savegame version that has the list.
 
 * @param extver   Extended feature test
 
 */
 
#define SLEG_CONDREFLIST(name, variable, type, from, to) SLEG_GENERAL(name, SL_REFLIST, variable, type, 0, from, to, 0)
 
#define SLEG_CONDREFLIST_X(name, variable, type, from, to, extver) SLEG_GENERAL_X(name, SL_REFLIST, variable, type, 0, from, to, 0, extver)
 
#define SLEG_CONDREFLIST(name, variable, type, from, to) SLEG_CONDREFLIST_X(name, variable, type, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a global vector of #SL_VAR elements in some savegame versions.
 
@@ -918,8 +978,10 @@ struct SaveLoadCompat {
 
 * @param type     Storage of the data in memory and in the savegame.
 
 * @param from     First savegame version that has the list.
 
 * @param to       Last savegame version that has the list.
 
 * @param extver   Extended feature test
 
 */
 
#define SLEG_CONDVECTOR(name, variable, type, from, to) SLEG_GENERAL(name, SL_VECTOR, variable, type, 0, from, to, 0)
 
#define SLEG_CONDVECTOR_X(name, variable, type, from, to, extver) SLEG_GENERAL_X(name, SL_VECTOR, variable, type, 0, from, to, 0, extver)
 
#define SLEG_CONDVECTOR(name, variable, type, from, to) SLEG_CONDVECTOR_X(name, variable, type, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a list of structs in some savegame versions.
 
@@ -927,8 +989,10 @@ struct SaveLoadCompat {
 
 * @param handler  SaveLoadHandler for the list of structs.
 
 * @param from     First savegame version that has the list.
 
 * @param to       Last savegame version that has the list.
 
 * @param extver   Extended feature test
 
 */
 
#define SLEG_CONDSTRUCTLIST(name, handler, from, to) SaveLoad {name, SL_STRUCTLIST, 0, 0, from, to, 0, nullptr, 0, std::make_shared<handler>()}
 
#define SLEG_CONDSTRUCTLIST_X(name, handler, from, to, extver) SaveLoad {name, SL_STRUCTLIST, 0, 0, from, to, 0, nullptr, 0, std::make_shared<handler>(), extver}
 
#define SLEG_CONDSTRUCTLIST(name, handler, from, to) SLEG_CONDSTRUCTLIST_X(name, handler, from, to, SlXvFeatureTest())
 

	
 
/**
 
 * Storage of a global variable in every savegame version.
 
@@ -1004,7 +1068,8 @@ struct SaveLoadCompat {
 
 * Field name where the real SaveLoad can be located.
 
 * @param name The name of the field.
 
 */
 
#define SLC_VAR(name) {name, 0, SL_MIN_VERSION, SL_MAX_VERSION}
 
#define SLC_VAR_X(name, extver) {name, 0, SL_MIN_VERSION, SL_MAX_VERSION, extver}
 
#define SLC_VAR(name) {name, 0, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest()}
 

	
 
/**
 
 * Empty space in every savegame version.
 
@@ -1012,10 +1077,11 @@ struct SaveLoadCompat {
 
 * @param from   First savegame version that has the empty space.
 
 * @param to     Last savegame version that has the empty space.
 
 */
 
#define SLC_NULL(length, from, to) {{}, length, from, to}
 
#define SLC_NULL_X(length, from, to, extver) {{}, length, from, to, extver}
 
#define SLC_NULL(length, from, to) {{}, length, from, to, SlXvFeatureTest()}
 

	
 
/** End marker of compat variables save or load. */
 
#define SLC_END() {{}, 0, SL_MIN_VERSION, SL_MIN_VERSION}
 
#define SLC_END() {{}, 0, SL_MIN_VERSION, SL_MIN_VERSION, SlXvFeatureTest()}
 

	
 
/**
 
 * Checks whether the savegame is below \a major.\a minor.
 
@@ -1124,6 +1190,17 @@ size_t SlCalcObjLength(const void *objec
 
byte SlReadByte();
 
void SlWriteByte(byte b);
 

	
 
int SlReadUint16();
 
uint32 SlReadUint32();
 
uint64 SlReadUint64();
 

	
 
void SlWriteUint16(uint16 v);
 
void SlWriteUint32(uint32 v);
 
void SlWriteUint64(uint64 v);
 

	
 
size_t SlGetBytesRead();
 
size_t SlGetBytesWritten();
 

	
 
void SlGlobList(const SaveLoadTable &slt);
 
void SlCopy(void *object, size_t length, VarType conv);
 
std::vector<SaveLoad> SlTableHeader(const SaveLoadTable &slt);
src/saveload/saveload_buffer.h
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/*
 
 * 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_buffer.h Functions/types related to buffers used for saving and loading games. */
 

	
 
#ifndef SAVELOAD_BUFFER_H
 
#define SAVELOAD_BUFFER_H
 

	
 
#include "../core/alloc_func.hpp"
 
#include "../core/endian_type.hpp"
 
#include "../core/endian_func.hpp"
 
#include "../core/math_func.hpp"
 

	
 
#include <vector>
 
#include <utility>
 

	
 
struct LoadFilter;
 
struct SaveFilter;
 

	
 
/** Save in chunks of 128 KiB. */
 
static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
 

	
 
/** A buffer for reading (and buffering) savegame data. */
 
struct ReadBuffer {
 
	byte buf[MEMORY_CHUNK_SIZE]; ///< Buffer we're going to read from.
 
	byte *bufp;                  ///< Location we're at reading the buffer.
 
	byte *bufe;                  ///< End of the buffer we can read from.
 
	LoadFilter *reader;          ///< The filter used to actually read.
 
	size_t read;                 ///< The amount of read bytes so far from the filter.
 

	
 
	/**
 
	 * Initialise our variables.
 
	 * @param reader The filter to actually read data.
 
	 */
 
	ReadBuffer(LoadFilter *reader) : bufp(nullptr), bufe(nullptr), reader(reader), read(0)
 
	{
 
	}
 

	
 
	static ReadBuffer *GetCurrent();
 

	
 
	void SkipBytesSlowPath(size_t bytes);
 
	void AcquireBytes();
 

	
 
	inline void SkipBytes(size_t bytes)
 
	{
 
		byte *b = this->bufp + bytes;
 
		if (likely(b <= this->bufe)) {
 
			this->bufp = b;
 
		} else {
 
			SkipBytesSlowPath(bytes);
 
		}
 
	}
 

	
 
	inline byte RawReadByte()
 
	{
 
		return *this->bufp++;
 
	}
 

	
 
	inline byte ReadByte()
 
	{
 
		if (unlikely(this->bufp == this->bufe)) {
 
			this->AcquireBytes();
 
		}
 

	
 
		return RawReadByte();
 
	}
 

	
 
	inline void CheckBytes(size_t bytes)
 
	{
 
		while (unlikely(this->bufp + bytes > this->bufe)) this->AcquireBytes();
 
	}
 

	
 
	inline int RawReadUint16()
 
	{
 
#if OTTD_ALIGNMENT == 0
 
		int x = FROM_BE16(*((const unaligned_uint16*) this->bufp));
 
		this->bufp += 2;
 
		return x;
 
#else
 
		int x = this->RawReadByte() << 8;
 
		return x | this->RawReadByte();
 
#endif
 
	}
 

	
 
	inline uint32 RawReadUint32()
 
	{
 
#if OTTD_ALIGNMENT == 0
 
		uint32 x = FROM_BE32(*((const unaligned_uint32*) this->bufp));
 
		this->bufp += 4;
 
		return x;
 
#else
 
		uint32 x = this->RawReadUint16() << 16;
 
		return x | this->RawReadUint16();
 
#endif
 
	}
 

	
 
	inline uint64 RawReadUint64()
 
	{
 
#if OTTD_ALIGNMENT == 0
 
		uint64 x = FROM_BE64(*((const unaligned_uint64*) this->bufp));
 
		this->bufp += 8;
 
		return x;
 
#else
 
		uint32 x = this->RawReadUint32();
 
		uint32 y = this->RawReadUint32();
 
		return (uint64)x << 32 | y;
 
#endif
 
	}
 

	
 
	inline void CopyBytes(byte *ptr, size_t length)
 
	{
 
		while (length) {
 
			if (unlikely(this->bufp == this->bufe)) {
 
				this->AcquireBytes();
 
			}
 
			size_t to_copy = std::min<size_t>(this->bufe - this->bufp, length);
 
			memcpy(ptr, this->bufp, to_copy);
 
			this->bufp += to_copy;
 
			ptr += to_copy;
 
			length -= to_copy;
 
		}
 
	}
 

	
 
	/**
 
	 * Get the size of the memory dump made so far.
 
	 * @return The size.
 
	 */
 
	inline size_t GetSize() const
 
	{
 
		return this->read - (this->bufe - this->bufp);
 
	}
 
};
 

	
 

	
 
/** Container for dumping the savegame (quickly) to memory. */
 
struct MemoryDumper {
 
	struct BufferInfo {
 
		byte *data;
 
		size_t size = 0;
 

	
 
		BufferInfo(byte *d) : data(d) {}
 
		~BufferInfo() { free(this->data); }
 

	
 
		BufferInfo(const BufferInfo &) = delete;
 
		BufferInfo(BufferInfo &&other) : data(other.data), size(other.size) { other.data = nullptr; };
 
	};
 

	
 
	std::vector<BufferInfo> blocks;         ///< Buffer with blocks of allocated memory.
 
	byte *buf = nullptr;                    ///< Buffer we're going to write to.
 
	byte *bufe = nullptr;                   ///< End of the buffer we write to.
 
	size_t completed_block_bytes = 0;       ///< Total byte count of completed blocks.
 

	
 
	byte *autolen_buf = nullptr;
 
	byte *autolen_buf_end = nullptr;
 
	byte *saved_buf = nullptr;
 
	byte *saved_bufe = nullptr;
 

	
 
	MemoryDumper()
 
	{
 
		const size_t size = 8192;
 
		this->autolen_buf = CallocT<byte>(size);
 
		this->autolen_buf_end = this->autolen_buf + size;
 
	}
 

	
 
	~MemoryDumper()
 
	{
 
		free(this->autolen_buf);
 
	}
 

	
 
	static MemoryDumper *GetCurrent();
 

	
 
	void FinaliseBlock();
 
	void AllocateBuffer();
 

	
 
	inline void CheckBytes(size_t bytes)
 
	{
 
		if (unlikely(this->buf + bytes > this->bufe)) this->AllocateBuffer();
 
	}
 

	
 
	/**
 
	 * Write a single byte into the dumper.
 
	 * @param b The byte to write.
 
	 */
 
	inline void WriteByte(byte b)
 
	{
 
		/* Are we at the end of this chunk? */
 
		if (unlikely(this->buf == this->bufe)) {
 
			this->AllocateBuffer();
 
		}
 

	
 
		*this->buf++ = b;
 
	}
 

	
 
	inline void CopyBytes(byte *ptr, size_t length)
 
	{
 
		while (length) {
 
			if (unlikely(this->buf == this->bufe)) {
 
				this->AllocateBuffer();
 
			}
 
			size_t to_copy = std::min<size_t>(this->bufe - this->buf, length);
 
			memcpy(this->buf, ptr, to_copy);
 
			this->buf += to_copy;
 
			ptr += to_copy;
 
			length -= to_copy;
 
		}
 
	}
 

	
 
	inline void RawWriteByte(byte b)
 
	{
 
		*this->buf++ = b;
 
	}
 

	
 
	inline void RawWriteUint16(uint16 v)
 
	{
 
#if OTTD_ALIGNMENT == 0
 
		*((unaligned_uint16 *) this->buf) = TO_BE16(v);
 
#else
 
		this->buf[0] = GB(v, 8, 8);
 
		this->buf[1] = GB(v, 0, 8);
 
#endif
 
		this->buf += 2;
 
	}
 

	
 
	inline void RawWriteUint32(uint32 v)
 
	{
 
#if OTTD_ALIGNMENT == 0
 
		*((unaligned_uint32 *) this->buf) = TO_BE32(v);
 
#else
 
		this->buf[0] = GB(v, 24, 8);
 
		this->buf[1] = GB(v, 16, 8);
 
		this->buf[2] = GB(v, 8, 8);
 
		this->buf[3] = GB(v, 0, 8);
 
#endif
 
		this->buf += 4;
 
	}
 

	
 
	inline void RawWriteUint64(uint64 v)
 
	{
 
#if OTTD_ALIGNMENT == 0
 
		*((unaligned_uint64 *) this->buf) = TO_BE64(v);
 
#else
 
		this->buf[0] = GB(v, 56, 8);
 
		this->buf[1] = GB(v, 48, 8);
 
		this->buf[2] = GB(v, 40, 8);
 
		this->buf[3] = GB(v, 32, 8);
 
		this->buf[4] = GB(v, 24, 8);
 
		this->buf[5] = GB(v, 16, 8);
 
		this->buf[6] = GB(v, 8, 8);
 
		this->buf[7] = GB(v, 0, 8);
 
#endif
 
		this->buf += 8;
 
	}
 

	
 
	void Flush(SaveFilter *writer);
 
	size_t GetSize() const;
 
	void StartAutoLength();
 
	std::pair<byte *, size_t> StopAutoLength();
 
};
 

	
 
#endif
src/saveload/station_sl.cpp
Show inline comments
 
@@ -594,6 +594,7 @@ 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),
 
	  	SLE_CONDVAR_X(Station, dilapidation,               SLE_UINT16,                 SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_DILAPIDATION)),
 
		SLEG_STRUCTLIST("goods", SlStationGoods),
 
	};
 
	inline const static SaveLoadCompatTable compat_description = _station_normal_sl_compat;
src/saveload/vehicle_sl.cpp
Show inline comments
 
@@ -680,6 +680,8 @@ public:
 
		    SLE_VAR(Vehicle, breakdown_delay,       SLE_UINT8),
 
		    SLE_VAR(Vehicle, breakdowns_since_last_service, SLE_UINT8),
 
		    SLE_VAR(Vehicle, breakdown_chance,      SLE_UINT8),
 
		 SLE_CONDVAR_X(Vehicle, breakdown_type,        SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_IMPROVED_BREAKDOWNS)),
 
		 SLE_CONDVAR_X(Vehicle, breakdown_severity,    SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_IMPROVED_BREAKDOWNS)),
 
		SLE_CONDVAR(Vehicle, build_year,            SLE_FILE_U8 | SLE_VAR_I32,    SL_MIN_VERSION,  SLV_31),
 
		SLE_CONDVAR(Vehicle, build_year,            SLE_INT32,                   SLV_31, SL_MAX_VERSION),
 

	
src/script/api/script_company.hpp
Show inline comments
 
@@ -113,6 +113,15 @@ public:
 
		EXPENSES_SHIP_INC     = ::EXPENSES_SHIP_INC,     ///< Income from ships.
 
		EXPENSES_LOAN_INT     = ::EXPENSES_LOAN_INT,     ///< Interest payments over the loan.
 
		EXPENSES_OTHER        = ::EXPENSES_OTHER,        ///< Other expenses.
 
		EXPENSES_T_TRAIN_CON  = ::EXPENSES_T_TRAIN_CON,
 
		EXPENSES_T_ROAD_CON   = ::EXPENSES_T_ROAD_CON,
 
		EXPENSES_T_AIRCRAFT_CON = ::EXPENSES_T_AIRCRAFT_CON,
 
		EXPENSES_T_SHIP_CON   = ::EXPENSES_T_SHIP_CON,
 
		EXPENSES_T_TREES_CON  = ::EXPENSES_T_TREES_CON,
 
		EXPENSES_T_SCENERY_CON = ::EXPENSES_T_SCENERY_CON,
 
		EXPENSES_T_LANDSCAPING = ::EXPENSES_T_LANDSCAPING,
 
		EXPENSES_T_DEMOLITION = ::EXPENSES_T_DEMOLITION,
 
		EXPENSES_T_REWARD_INC = ::EXPENSES_T_REWARD_INC,
 
		EXPENSES_INVALID      = ::INVALID_EXPENSES,      ///< Invalid expense type.
 
	};
 

	
src/settings_gui.cpp
Show inline comments
 
@@ -1854,6 +1854,47 @@ static SettingsContainer &GetSettingsTre
 
			network->Add(new SettingEntry("network.use_relay_service"));
 
		}
 

	
 
		SettingsPage *patchpack = main->Add(new SettingsPage(STR_CONFIG_SETTING_PATCHPACK));
 
		{
 
			SettingsPage *patchpack_daylength = patchpack->Add(new SettingsPage(STR_CONFIG_SETTING_PATCHPACK_DAYLENGTH));
 
			{
 
				patchpack_daylength->Add(new SettingEntry("economy.daylength_multiplier"));
 
				patchpack_daylength->Add(new SettingEntry("economy.town_growth_multiplier"));
 
				patchpack_daylength->Add(new SettingEntry("economy.running_cost_multiplier_rail"));
 
				patchpack_daylength->Add(new SettingEntry("economy.running_cost_multiplier_road"));
 
				patchpack_daylength->Add(new SettingEntry("economy.running_cost_multiplier_water"));
 
				patchpack_daylength->Add(new SettingEntry("economy.running_cost_multiplier_air"));
 
				patchpack_daylength->Add(new SettingEntry("economy.infrastructure_base_cost_rail"));
 
				patchpack_daylength->Add(new SettingEntry("economy.infrastructure_base_cost_road"));
 
				patchpack_daylength->Add(new SettingEntry("economy.infrastructure_base_cost_water"));
 
				patchpack_daylength->Add(new SettingEntry("economy.infrastructure_base_cost_air"));
 
				patchpack_daylength->Add(new SettingEntry("economy.infrastructure_base_cost_station"));
 
			}
 

	
 
			SettingsPage *patchpack_dilapidation = patchpack->Add(new SettingsPage(STR_CONFIG_SETTING_PATCHPACK_DILAPIDATION));
 
			{
 
				patchpack_dilapidation->Add(new SettingEntry("economy.dilapidation_max_amount"));
 
				patchpack_dilapidation->Add(new SettingEntry("economy.dilapidation_increase"));
 
				patchpack_dilapidation->Add(new SettingEntry("economy.dilapidation_decrease"));
 
				patchpack_dilapidation->Add(new SettingEntry("economy.dilapidation_pop_rail"));
 
				patchpack_dilapidation->Add(new SettingEntry("economy.dilapidation_pop_road"));
 
				patchpack_dilapidation->Add(new SettingEntry("economy.dilapidation_pop_water"));
 
				patchpack_dilapidation->Add(new SettingEntry("economy.dilapidation_pop_air"));
 
				patchpack_dilapidation->Add(new SettingEntry("economy.dilapidation_fine_rail"));
 
				patchpack_dilapidation->Add(new SettingEntry("economy.dilapidation_fine_road"));
 
				patchpack_dilapidation->Add(new SettingEntry("economy.dilapidation_fine_water"));
 
				patchpack_dilapidation->Add(new SettingEntry("economy.dilapidation_fine_air"));
 
			}
 

	
 
			patchpack->Add(new SettingEntry("gui.load_legacy_patchpack_savedata"));
 
			patchpack->Add(new SettingEntry("gui.colour_based_on_town_rating"));
 
			patchpack->Add(new SettingEntry("economy.bribe_risky"));
 
			patchpack->Add(new SettingEntry("construction.name_stations_based_on_industries"));
 
			patchpack->Add(new SettingEntry("vehicle.plane_range_multiplier"));
 
			patchpack->Add(new SettingEntry("vehicle.improved_breakdowns"));
 
			patchpack->Add(new SettingEntry("difficulty.vehicle_breakdown_scaler"));
 
		}
 

	
 
		main->Init();
 
	}
 
	return *main;
src/settings_table.cpp
Show inline comments
 
@@ -288,6 +288,22 @@ static void InvalidateCompanyLiveryWindo
 
	ResetVehicleColourMap();
 
}
 

	
 
static void PatchpackInvalidateRunningCostsOrElse(int32 new_value)
 
{
 
	InvalidateWindowClassesData(WC_AIRCRAFT_LIST);
 
	InvalidateWindowClassesData(WC_BUILD_VEHICLE);
 
	InvalidateWindowClassesData(WC_ENGINE_PREVIEW);
 
	InvalidateWindowClassesData(WC_FINANCES);
 
	InvalidateWindowClassesData(WC_PERFORMANCE_DETAIL);
 
	InvalidateWindowClassesData(WC_PERFORMANCE_HISTORY);
 
	InvalidateWindowClassesData(WC_REPLACE_VEHICLE);
 
	InvalidateWindowClassesData(WC_ROADVEH_LIST);
 
	InvalidateWindowClassesData(WC_SHIPS_LIST);
 
	InvalidateWindowClassesData(WC_TRAINS_LIST);
 
	InvalidateWindowClassesData(WC_VEHICLE_DETAILS);
 
	InvalidateWindowClassesData(WC_VEHICLE_VIEW);
 
}
 

	
 
static void DifficultyNoiseChange(int32 new_value)
 
{
 
	if (_game_mode == GM_NORMAL) {
src/settings_type.h
Show inline comments
 
@@ -81,6 +81,7 @@ struct DifficultySettings {
 
	byte   vehicle_costs;                    ///< amount of money spent on vehicle running cost
 
	byte   competitor_speed;                 ///< the speed at which the AI builds
 
	byte   vehicle_breakdowns;               ///< likelihood of vehicles breaking down
 
	uint32 vehicle_breakdown_scaler;         ///< likelihood of vehicles breaking down REDUX
 
	byte   subsidy_multiplier;               ///< payment multiplier for subsidized deliveries
 
	uint16 subsidy_duration;                 ///< duration of subsidies
 
	byte   construction_cost;                ///< how expensive is building
 
@@ -138,6 +139,7 @@ struct GUISettings {
 
	bool   autosave_on_network_disconnect;   ///< save an autosave when you get disconnected from a network game with an error?
 
	uint8  date_format_in_default_names;     ///< should the default savegame/screenshot name use long dates (31th Dec 2008), short dates (31-12-2008) or ISO dates (2008-12-31)
 
	byte   max_num_autosaves;                ///< controls how many autosavegames are made before the game starts to overwrite (names them 0 to max_num_autosaves - 1)
 
	bool   colour_based_on_town_rating;      ///< colour code the town name based on rating?
 
	bool   population_in_label;              ///< show the population of a town in its label?
 
	uint8  right_mouse_btn_emulation;        ///< should we emulate right mouse clicking?
 
	uint8  scrollwheel_scrolling;            ///< scrolling using the scroll wheel?
 
@@ -192,6 +194,8 @@ struct GUISettings {
 
	bool   newgrf_show_old_versions;         ///< whether to show old versions in the NewGRF list
 
	uint8  newgrf_default_palette;           ///< default palette to use for NewGRFs without action 14 palette information
 

	
 
	bool   load_legacy_patchpack_savedata;   ///< whether or not to handle legacy patchpack savedata from version 5.x
 

	
 
	/**
 
	 * Returns true when the user has sufficient privileges to edit newgrfs on a running game
 
	 * @return whether the user has sufficient privileges to edit newgrfs in an existing game
 
@@ -298,6 +302,7 @@ struct NetworkSettings {
 
	bool        reload_cfg;                               ///< reload the config file before restarting
 
	std::string last_joined;                              ///< Last joined server
 
	bool        no_http_content_downloads;                ///< do not do content downloads over HTTP
 
	bool   save_password;                                 ///< If password file is used
 
	UseRelayService use_relay_service;                        ///< Use relay service?
 
};
 

	
 
@@ -354,6 +359,8 @@ struct ConstructionSettings {
 
	uint16 clear_frame_burst;                ///< how many tiles may, over a short period, be cleared?
 
	uint32 tree_per_64k_frames;              ///< how many trees may, over a long period, be planted per 65536 frames?
 
	uint16 tree_frame_burst;                 ///< how many trees may, over a short period, be planted?
 

	
 
	uint8 name_stations_based_on_industries;  ///< ttr patchpack: name stations based on nearby industries?
 
};
 

	
 
/** Settings related to the AI. */
 
@@ -494,12 +501,15 @@ struct VehicleSettings {
 
	byte   extend_vehicle_life;              ///< extend vehicle life by this many years
 
	byte   road_side;                        ///< the side of the road vehicles drive on
 
	uint8  plane_crashes;                    ///< number of plane crashes, 0 = none, 1 = reduced, 2 = normal
 
	uint8  plane_range_multiplier;           ///< ttr patchpack: range multiplier
 
	bool   improved_breakdowns;		 ///< different types, chances and serverities of breakdowns
 
};
 

	
 
/** Settings related to the economy. */
 
struct EconomySettings {
 
	bool   inflation;                        ///< disable inflation
 
	bool   bribe;                            ///< enable bribing the local authority
 
	bool   bribe_risky;                      ///< ttr patchpack: whether or not there is a risk of being caught while bribing
 
	EconomyType type;                        ///< economy type (original/smooth/frozen)
 
	bool   allow_shares;                     ///< allow the buying/selling of shares
 
	uint8  min_years_for_shares;             ///< minimum age of a company for it to trade shares
 
@@ -522,6 +532,28 @@ struct EconomySettings {
 
	uint16 town_noise_population[3];         ///< population to base decision on noise evaluation (@see town_council_tolerance)
 
	bool   allow_town_level_crossings;       ///< towns are allowed to build level crossings
 
	bool   infrastructure_maintenance;       ///< enable monthly maintenance fee for owner infrastructure
 
	uint16 infrastructure_base_cost_rail;    ///< ttr patchpack: rail infrastructure cost base price
 
	uint16 infrastructure_base_cost_road;    ///< ttr patchpack: road infrastructure cost base price
 
	uint16 infrastructure_base_cost_water;   ///< ttr patchpack: water infrastructure cost base price
 
	uint16 infrastructure_base_cost_air;     ///< ttr patchpack: air infrastructure cost base price
 
	uint16 infrastructure_base_cost_station; ///< ttr patchpack: station infrastructure cost base price
 
	uint8  daylength_multiplier;             ///< ttr patchpack: day length multiplier
 
	uint8  town_growth_multiplier;           ///< ttr patchpack: town growth multiplier
 
	uint16 running_cost_multiplier_rail;     ///< ttr patchpack: rail running cost multiplier
 
	uint16 running_cost_multiplier_road;     ///< ttr patchpack: road running cost multiplier
 
	uint16 running_cost_multiplier_water;    ///< ttr patchpack: water running cost multiplier
 
	uint16 running_cost_multiplier_air;      ///< ttr patchpack: air running cost multiplier
 
	uint16 dilapidation_max_amount;          ///< ttr patchpack: maximum amount of dilapidation allowed at station
 
	uint16 dilapidation_increase;            ///< ttr patchpack: amount of dilapidation to add on ratings update if station is overcrowded
 
	uint16 dilapidation_decrease;            ///< ttr patchpack: amount of dilapidation to remove on ratings update if station is not overcrowded
 
	uint16 dilapidation_pop_rail;            ///< ttr patchpack: amount of pop allowed at rail station before it is considered dilapidated
 
	uint16 dilapidation_pop_road;            ///< ttr patchpack: amount of pop allowed at road station before it is considered dilapidated
 
	uint16 dilapidation_pop_water;           ///< ttr patchpack: amount of pop allowed at water station before it is considered dilapidated
 
	uint16 dilapidation_pop_air;             ///< ttr patchpack: amount of pop allowed at air station before it is considered dilapidated
 
	uint32 dilapidation_fine_rail;           ///< ttr patchpack: monthly fine per dilapidation point at rail stations
 
	uint32 dilapidation_fine_road;           ///< ttr patchpack: monthly fine per dilapidation point at road stations
 
	uint32 dilapidation_fine_water;          ///< ttr patchpack: monthly fine per dilapidation point at water stations
 
	uint32 dilapidation_fine_air;            ///< ttr patchpack: monthly fine per dilapidation point at air stations
 
};
 

	
 
struct LinkGraphSettings {
src/ship_cmd.cpp
Show inline comments
 
@@ -219,6 +219,7 @@ Money Ship::GetRunningCost() const
 
{
 
	const Engine *e = this->GetEngine();
 
	uint cost_factor = GetVehicleProperty(this, PROP_SHIP_RUNNING_COST_FACTOR, e->u.ship.running_cost);
 
	cost_factor *= _settings_game.economy.running_cost_multiplier_water;
 
	return GetPrice(PR_RUNNING_SHIP, cost_factor, e->GetGRF());
 
}
 

	
 
@@ -414,6 +415,18 @@ static bool ShipAccelerate(Vehicle *v)
 
	spd = std::min<uint>(v->cur_speed + 1, v->vcache.cached_max_speed);
 
	spd = std::min<uint>(spd, v->current_order.GetMaxSpeed() * 2);
 

	
 
	if(v->breakdown_ctr == 1 && v->breakdown_type == BREAKDOWN_LOW_POWER && v->cur_speed > (v->breakdown_severity * ShipVehInfo(v->engine_type)->max_speed) >> 8) {
 
		if((v->tick_counter & 0x7) == 0 && v->cur_speed > 0) {
 
			spd = v->cur_speed - 1;
 
		} else {
 
			spd = v->cur_speed;
 
		}
 
	}
 

	
 
	if(v->breakdown_ctr == 1 && v->breakdown_type == BREAKDOWN_LOW_SPEED) {
 
		spd = std::min<uint>(spd, v->breakdown_severity);
 
	}
 

	
 
	/* updates statusbar only if speed have changed to save CPU time */
 
	if (spd != v->cur_speed) {
 
		v->cur_speed = spd;
 
@@ -878,6 +891,7 @@ CommandCost CmdBuildShip(DoCommandFlag f
 

	
 
		v->reliability = e->reliability;
 
		v->reliability_spd_dec = e->reliability_spd_dec;
 
		v->breakdown_chance = 64; // ships have a 50% lower breakdown chance than normal
 
		v->max_age = e->GetLifeLengthInDays();
 

	
 
		v->state = TRACK_BIT_DEPOT;
src/signs_type.h
Show inline comments
 
@@ -16,6 +16,6 @@ struct Sign;
 

	
 
static const SignID INVALID_SIGN = 0xFFFF; ///< Sentinel for an invalid sign.
 

	
 
static const uint MAX_LENGTH_SIGN_NAME_CHARS = 32; ///< The maximum length of a sign name in characters including '\0'
 
static const uint MAX_LENGTH_SIGN_NAME_CHARS = 128; ///< The maximum length of a sign name in characters including '\0'
 

	
 
#endif /* SIGNS_TYPE_H */
src/station_base.h
Show inline comments
 
@@ -19,7 +19,6 @@
 
#include "newgrf_storage.h"
 
#include "bitmap_type.h"
 
#include <map>
 
#include <set>
 

	
 
static const byte INITIAL_STATION_RATING = 175;
 

	
 
@@ -486,6 +485,8 @@ public:
 
	IndustryList industries_near; ///< Cached list of industries near the station that can accept cargo, @see DeliverGoodsToIndustry()
 
	Industry *industry;           ///< NOSAVE: Associated industry for neutral stations. (Rebuilt on load from Industry->st)
 

	
 
	uint16 dilapidation; ///< Current amount of dilapidation at the station. Increases if too many passengers at station. Decreases if not too many. Player will be charged a fine based on how dilapidated the station is
 

	
 
	Station(TileIndex tile = INVALID_TILE);
 
	~Station();
 

	
src/station_cmd.cpp
Show inline comments
 
@@ -64,6 +64,8 @@
 

	
 
#include "safeguards.h"
 

	
 
#include "company_func.h"
 

	
 
/**
 
 * Static instance of FlowStat::SharesMap.
 
 * Note: This instance is created on task start.
 
@@ -238,23 +240,9 @@ static bool FindNearIndustryName(TileInd
 
	return !sni->indtypes[indtype];
 
}
 

	
 
static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming name_class)
 
/** Fetch the available station names. Patchpack moves this code from GenerateStationName. Should be easy to see what was moved if you do a diff :) */
 
static void FetchAvailableStationNames(uint32& free_names, bool* indtypes, Station* st, const Town* t)
 
{
 
	static const uint32 _gen_station_name_bits[] = {
 
		0,                                       // STATIONNAMING_RAIL
 
		0,                                       // STATIONNAMING_ROAD
 
		1U << M(STR_SV_STNAME_AIRPORT),          // STATIONNAMING_AIRPORT
 
		1U << M(STR_SV_STNAME_OILFIELD),         // STATIONNAMING_OILRIG
 
		1U << M(STR_SV_STNAME_DOCKS),            // STATIONNAMING_DOCK
 
		1U << M(STR_SV_STNAME_HELIPORT),         // STATIONNAMING_HELIPORT
 
	};
 

	
 
	const Town *t = st->town;
 
	uint32 free_names = UINT32_MAX;
 

	
 
	bool indtypes[NUM_INDUSTRYTYPES];
 
	memset(indtypes, 0, sizeof(indtypes));
 

	
 
	for (const Station *s : Station::Iterate()) {
 
		if (s != st && s->town == t) {
 
			if (s->indtype != IT_INVALID) {
 
@@ -278,6 +266,56 @@ static StringID GenerateStationName(Stat
 
			}
 
		}
 
	}
 
}
 

	
 
/** Callback proc for CircularTileSearch */
 
static bool FindNearPatchpackIndustryName(TileIndex tile, void *user_data)
 
{
 
	/* Is this an industry tile? If not, skip it */
 
	if (!IsTileType(tile, MP_INDUSTRY)) return false;
 

	
 
	uint32 free_names = UINT32_MAX;
 
	bool indtypes[NUM_INDUSTRYTYPES];
 
	memset(indtypes, 0, sizeof(indtypes));
 
	FetchAvailableStationNames(free_names, indtypes, (Station*)user_data, Industry::GetByTile(tile)->town);
 

	
 
	IndustryType indtype = GetIndustryType(tile);
 

	
 
	return !indtypes[indtype];
 
}
 

	
 
/** Generates station names */
 
static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming name_class)
 
{
 
	if (_settings_game.construction.name_stations_based_on_industries == 2)
 
	{
 
		/** I love having this as an in-game patch setting. DEM SETTINGS */
 
		TileIndex indtile = tile;
 
		if (CircularTileSearch(&indtile, 7, FindNearPatchpackIndustryName, (void*)st)) {
 
			IndustryType indtype = GetIndustryType(indtile);
 
			const IndustrySpec *indsp = GetIndustrySpec(indtype);
 
			st->indtype = indtype;
 
			st->town = Industry::GetByTile(indtile)->town;
 
			return STR_SV_STNAME_FALLBACK;
 
		}
 
	}
 

	
 
	static const uint32 _gen_station_name_bits[] = {
 
		0,                                       // STATIONNAMING_RAIL
 
		0,                                       // STATIONNAMING_ROAD
 
		1U << M(STR_SV_STNAME_AIRPORT),          // STATIONNAMING_AIRPORT
 
		1U << M(STR_SV_STNAME_OILFIELD),         // STATIONNAMING_OILRIG
 
		1U << M(STR_SV_STNAME_DOCKS),            // STATIONNAMING_DOCK
 
		1U << M(STR_SV_STNAME_HELIPORT),         // STATIONNAMING_HELIPORT
 
	};
 

	
 
	const Town *t = st->town;
 

	
 
	/* Fetch a list of available station names so we know which ones have already been used and are unavailable (including industry newGRF names) */
 
	uint32 free_names = UINT32_MAX;
 
	bool indtypes[NUM_INDUSTRYTYPES];
 
	memset(indtypes, 0, sizeof(indtypes));
 
	FetchAvailableStationNames(free_names, indtypes, st, t);
 

	
 
	TileIndex indtile = tile;
 
	StationNameInformation sni = { free_names, indtypes };
 
@@ -286,7 +324,7 @@ static StringID GenerateStationName(Stat
 
		IndustryType indtype = GetIndustryType(indtile);
 
		const IndustrySpec *indsp = GetIndustrySpec(indtype);
 
		/* STR_NULL means it only disables oil rig/mines */
 
		if (indsp->station_name != STR_NULL) {
 
		if (indsp->station_name != STR_NULL && (_settings_game.construction.name_stations_based_on_industries == 1)) {
 
			st->indtype = indtype;
 
			return STR_SV_STNAME_FALLBACK;
 
		}
 
@@ -843,7 +881,7 @@ CommandCost CheckBuildableTile(TileIndex
 
 */
 
static CommandCost CheckFlatLandAirport(AirportTileTableIterator tile_iter, DoCommandFlag flags)
 
{
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_AIRCRAFT_CON);
 
	int allowed_z = -1;
 

	
 
	for (; tile_iter != INVALID_TILE; ++tile_iter) {
 
@@ -875,7 +913,7 @@ static CommandCost CheckFlatLandAirport(
 
 */
 
static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag flags, Axis axis, StationID *station, RailType rt, std::vector<Train *> &affected_vehicles, StationClassID spec_class, byte spec_index, byte plat_len, byte numtracks)
 
{
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_TRAIN_CON);
 
	int allowed_z = -1;
 
	uint invalid_dirs = 5 << axis;
 

	
 
@@ -961,7 +999,7 @@ static CommandCost CheckFlatLandRailStat
 
 */
 
static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, bool is_truck_stop, Axis axis, StationID *station, RoadType rt)
 
{
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_ROAD_CON);
 
	int allowed_z = -1;
 

	
 
	for (TileIndex cur_tile : tile_area) {
 
@@ -1552,7 +1590,7 @@ CommandCost RemoveFromRailBaseStation(Ti
 
{
 
	/* Count of the number of tiles removed */
 
	int quantity = 0;
 
	CommandCost total_cost(EXPENSES_CONSTRUCTION);
 
	CommandCost total_cost(EXPENSES_T_TRAIN_CON);
 
	/* Accumulator for the errors seen during clearing. If no errors happen,
 
	 * and the quantity is 0 there is no station. Otherwise it will be one
 
	 * of the other error that got accumulated. */
 
@@ -1721,7 +1759,7 @@ CommandCost RemoveRailStation(T *st, DoC
 

	
 
	assert(ta.w != 0 && ta.h != 0);
 

	
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_TRAIN_CON);
 
	/* clear all areas of the station */
 
	for (TileIndex tile : ta) {
 
		/* only remove tiles that are actually train station tiles */
 
@@ -1853,7 +1891,7 @@ CommandCost CmdBuildRoadStop(DoCommandFl
 
	bool is_truck_stop = stop_type != ROADSTOP_BUS;
 

	
 
	/* Total road stop cost. */
 
	CommandCost cost(EXPENSES_CONSTRUCTION, roadstop_area.w * roadstop_area.h * _price[is_truck_stop ? PR_BUILD_STATION_TRUCK : PR_BUILD_STATION_BUS]);
 
	CommandCost cost(EXPENSES_T_ROAD_CON, roadstop_area.w * roadstop_area.h * _price[is_truck_stop ? PR_BUILD_STATION_TRUCK : PR_BUILD_STATION_BUS]);
 
	StationID est = INVALID_STATION;
 
	ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 5 << axis : 1 << ddir, is_drive_through, is_truck_stop, axis, &est, rt);
 
	if (ret.Failed()) return ret;
 
@@ -2045,7 +2083,7 @@ static CommandCost RemoveRoadStop(TileIn
 
		}
 
	}
 

	
 
	return CommandCost(EXPENSES_CONSTRUCTION, _price[is_truck ? PR_CLEAR_STATION_TRUCK : PR_CLEAR_STATION_BUS]);
 
	return CommandCost(EXPENSES_T_ROAD_CON, _price[is_truck ? PR_CLEAR_STATION_TRUCK : PR_CLEAR_STATION_BUS]);
 
}
 

	
 
/**
 
@@ -2070,7 +2108,7 @@ CommandCost CmdRemoveRoadStop(DoCommandF
 

	
 
	TileArea roadstop_area(tile, width, height);
 

	
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_ROAD_CON);
 
	CommandCost last_error(STR_ERROR_THERE_IS_NO_STATION);
 
	bool had_success = false;
 

	
 
@@ -2350,7 +2388,7 @@ static CommandCost RemoveAirport(TileInd
 

	
 
	tile = st->airport.tile;
 

	
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost cost(EXPENSES_T_AIRCRAFT_CON);
 

	
 
	for (const Aircraft *a : Aircraft::Iterate()) {
 
		if (!a->IsNormalAircraft()) continue;
 
@@ -2496,7 +2534,7 @@ CommandCost CmdBuildDock(DoCommandFlag f
 

	
 
	if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
 

	
 
	CommandCost cost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_STATION_DOCK]);
 
	CommandCost cost(EXPENSES_T_SHIP_CON, _price[PR_BUILD_STATION_DOCK]);
 
	ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
 
	if (ret.Failed()) return ret;
 
	cost.AddCost(ret);
 
@@ -2696,7 +2734,7 @@ static CommandCost RemoveDock(TileIndex 
 
		}
 
	}
 

	
 
	return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_STATION_DOCK]);
 
	return CommandCost(EXPENSES_T_SHIP_CON, _price[PR_CLEAR_STATION_DOCK]);
 
}
 

	
 
#include "table/station_land.h"
 
@@ -2994,7 +3032,6 @@ draw_default_foundation:
 
	}
 

	
 
	if (HasStationRail(ti->tile) && HasRailCatenaryDrawn(GetRailType(ti->tile))) DrawRailCatenary(ti);
 

	
 
	if (IsRoadStop(ti->tile)) {
 
		RoadType road_rt = GetRoadTypeRoad(ti->tile);
 
		RoadType tram_rt = GetRoadTypeTram(ti->tile);
 
@@ -3565,6 +3602,64 @@ static void UpdateStationRating(Station 
 
		}
 
	}
 

	
 
	// station dilapidation
 
	{
 
		if (_settings_game.economy.dilapidation_max_amount > 0) {
 
			bool dilapidation_calc = false;
 
			uint16 dilapidation_pop = 0;
 
			uint pop_count = st->goods[CT_PASSENGERS].cargo.AvailableCount();
 
			if (Company::IsValidID(st->owner)) {
 
				if ((st->facilities & FACIL_TRAIN) != 0) {
 
					dilapidation_calc = true;
 
					if (_settings_game.economy.dilapidation_pop_rail > dilapidation_pop) {
 
						dilapidation_pop = _settings_game.economy.dilapidation_pop_rail;
 
					}
 
				}
 
				if (((st->facilities & FACIL_BUS_STOP) != 0) || ((st->facilities & FACIL_TRUCK_STOP) != 0)) {
 
					dilapidation_calc = true;
 
					if (_settings_game.economy.dilapidation_pop_road > dilapidation_pop) {
 
						dilapidation_pop = _settings_game.economy.dilapidation_pop_road;
 
					}
 
				}
 
				if ((st->facilities & FACIL_DOCK) != 0) {
 
					dilapidation_calc = true;
 
					if (_settings_game.economy.dilapidation_pop_water > dilapidation_pop) {
 
						dilapidation_pop = _settings_game.economy.dilapidation_pop_water;
 
					}
 
				}
 
				if ((st->facilities & FACIL_AIRPORT) != 0) {
 
					dilapidation_calc = true;
 
					if (_settings_game.economy.dilapidation_pop_air > dilapidation_pop) {
 
						dilapidation_pop = _settings_game.economy.dilapidation_pop_air;
 
					}
 
				}
 
			}
 
			if (dilapidation_calc && pop_count > (uint)dilapidation_pop) {
 
				// increase the dilapidation, preventing overflow
 
				uint16 top_boundary = 65535 - _settings_game.economy.dilapidation_increase;
 
				if (st->dilapidation >= top_boundary) {
 
					st->dilapidation = 65535;
 
				}
 
				else {
 
					st->dilapidation += _settings_game.economy.dilapidation_increase;
 
				}
 
			}
 
			else
 
			{
 
				// decrease the dilapidation, preventing underflow
 
				if (st->dilapidation <= _settings_game.economy.dilapidation_decrease) {
 
					st->dilapidation = 0;
 
				}
 
				else {
 
					st->dilapidation -= _settings_game.economy.dilapidation_decrease;
 
				}
 
			}
 
		}
 
		if (st->dilapidation > _settings_game.economy.dilapidation_max_amount) {
 
			st->dilapidation = _settings_game.economy.dilapidation_max_amount;
 
		}
 
	}
 

	
 
	StationID index = st->index;
 
	if (waiting_changed) {
 
		SetWindowDirty(WC_STATION_VIEW, index); // update whole window
 
@@ -3803,6 +3898,40 @@ void OnTick_Station()
 
	}
 
}
 

	
 
/** Charges player for dilapidation at station */
 
void ChargePlayerForDilapidation(Station *st)
 
{
 
	if (st->dilapidation > 0 && Company::IsValidID(st->owner)) {
 
		uint32 dilapidation_fine = 0;
 
		if ((st->facilities & FACIL_TRAIN) != 0) {
 
			if (_settings_game.economy.dilapidation_fine_rail > dilapidation_fine) {
 
				dilapidation_fine = _settings_game.economy.dilapidation_fine_rail;
 
			}
 
		}
 
		if (((st->facilities & FACIL_BUS_STOP) != 0) || ((st->facilities & FACIL_TRUCK_STOP) != 0)) {
 
			if (_settings_game.economy.dilapidation_fine_road > dilapidation_fine) {
 
				dilapidation_fine = _settings_game.economy.dilapidation_fine_road;
 
			}
 
		}
 
		if ((st->facilities & FACIL_DOCK) != 0) {
 
			if (_settings_game.economy.dilapidation_fine_water > dilapidation_fine) {
 
				dilapidation_fine = _settings_game.economy.dilapidation_fine_water;
 
			}
 
		}
 
		if ((st->facilities & FACIL_AIRPORT) != 0) {
 
			if (_settings_game.economy.dilapidation_fine_air > dilapidation_fine) {
 
				dilapidation_fine = _settings_game.economy.dilapidation_fine_air;
 
			}
 
		}
 
		Money actual_fine = dilapidation_fine;
 
		actual_fine *= st->dilapidation;
 
		actual_fine *= (_economy.inflation_prices >> 16);
 
		if (actual_fine > 0) {
 
			SubtractMoneyFromCompanyFract(st->owner, CommandCost(EXPENSES_T_DILAPIDATION, actual_fine << 8));
 
		}
 
	}
 
}
 

	
 
/** Monthly loop for stations. */
 
void StationMonthlyLoop()
 
{
 
@@ -3812,6 +3941,7 @@ void StationMonthlyLoop()
 
			SB(ge->status, GoodsEntry::GES_LAST_MONTH, 1, GB(ge->status, GoodsEntry::GES_CURRENT_MONTH, 1));
 
			ClrBit(ge->status, GoodsEntry::GES_CURRENT_MONTH);
 
		}
 
		ChargePlayerForDilapidation(st);
 
	}
 
}
 

	
 
@@ -4302,11 +4432,11 @@ static CommandCost TerraformTile_Station
 
					DiagDirection direction = AxisToDiagDir(GetRailStationAxis(tile));
 
					if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, direction)) break;
 
					if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, ReverseDiagDir(direction))) break;
 
					return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
					return CommandCost(EXPENSES_T_TRAIN_CON, _price[PR_BUILD_FOUNDATION]);
 
				}
 

	
 
				case STATION_AIRPORT:
 
					return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
					return CommandCost(EXPENSES_T_AIRCRAFT_CON, _price[PR_BUILD_FOUNDATION]);
 

	
 
				case STATION_TRUCK:
 
				case STATION_BUS: {
 
@@ -4315,7 +4445,7 @@ static CommandCost TerraformTile_Station
 
					if (IsDriveThroughStopTile(tile)) {
 
						if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, ReverseDiagDir(direction))) break;
 
					}
 
					return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
					return CommandCost(EXPENSES_T_ROAD_CON, _price[PR_BUILD_FOUNDATION]);
 
				}
 

	
 
				default: break;
src/station_gui.cpp
Show inline comments
 
@@ -322,6 +322,13 @@ protected:
 
		return minr1 > minr2;
 
	}
 

	
 
	/** Sort stations by their dilapidation */
 
	static bool StationDilapidationSorter(const Station* const& a, const Station* const& b)
 
	{
 
		if (a->dilapidation == b->dilapidation) return StationNameSorter(a, b); // fallback
 
		return a->dilapidation < b->dilapidation;
 
	}
 

	
 
	/** Sort the stations list */
 
	void SortStationsList()
 
	{
 
@@ -460,7 +467,17 @@ public:
 

	
 
					SetDParam(0, st->index);
 
					SetDParam(1, st->facilities);
 
					int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y + (line_height - FONT_HEIGHT_NORMAL) / 2, STR_STATION_LIST_STATION);
 
					int x;
 

	
 
					if (_settings_game.economy.dilapidation_max_amount > 0 && st->dilapidation > 0)
 
					{
 
						SetDParam(2, st->dilapidation);
 
						x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y + (line_height - FONT_HEIGHT_NORMAL) / 2, STR_STATION_LIST_STATION_WITH_DILAPIDATION);
 
					}
 
					else
 
					{
 
						x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y + (line_height - FONT_HEIGHT_NORMAL) / 2, STR_STATION_LIST_STATION);
 
					}
 
					x += rtl ? -text_spacing : text_spacing;
 

	
 
					/* show cargo waiting and station ratings */
 
@@ -699,7 +716,8 @@ GUIStationList::SortFunction * const Com
 
	&StationWaitingTotalSorter,
 
	&StationWaitingAvailableSorter,
 
	&StationRatingMaxSorter,
 
	&StationRatingMinSorter
 
	&StationRatingMinSorter,
 
	&StationDilapidationSorter
 
};
 

	
 
/* Names of the sorting functions */
 
@@ -710,6 +728,7 @@ const StringID CompanyStationsWindow::so
 
	STR_SORT_BY_WAITING_AVAILABLE,
 
	STR_SORT_BY_RATING_MAX,
 
	STR_SORT_BY_RATING_MIN,
 
	STR_SORT_BY_DILAPIDATION,
 
	INVALID_STRING_ID
 
};
 

	
 
@@ -1854,6 +1873,13 @@ struct StationViewWindow : public Window
 
			y += WD_PAR_VSEP_WIDE;
 
		}
 

	
 
		if (_settings_game.economy.dilapidation_max_amount > 0) {
 
			SetDParam(0, st->dilapidation);
 
			SetDParam(1, _settings_game.economy.dilapidation_max_amount);
 
			y = DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, r.bottom, STR_STATION_VIEW_DILAPIDATION);
 
			y += WD_PAR_VSEP_WIDE;
 
		}
 

	
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_VIEW_SUPPLY_RATINGS_TITLE);
 
		y += FONT_HEIGHT_NORMAL;
 

	
src/station_type.h
Show inline comments
 
@@ -85,7 +85,7 @@ enum CatchmentArea {
 
	MAX_CATCHMENT      = 10, ///< Maximum catchment for airports with "modified catchment" enabled
 
};
 

	
 
static const uint MAX_LENGTH_STATION_NAME_CHARS = 32; ///< The maximum length of a station name in characters including '\0'
 
static const uint MAX_LENGTH_STATION_NAME_CHARS = 128; ///< The maximum length of a station name in characters including '\0'
 

	
 
struct StationCompare {
 
	bool operator() (const Station *lhs, const Station *rhs) const;
src/stdafx.h
Show inline comments
 
@@ -428,6 +428,16 @@ static_assert(SIZE_MAX >= UINT32_MAX);
 
/* For the FMT library we only want to use the headers, not link to some library. */
 
#define FMT_HEADER_ONLY
 

	
 
#if defined(__GNUC__) || defined(__clang__)
 
__attribute__((aligned(1))) typedef uint16 unaligned_uint16;
 
__attribute__((aligned(1))) typedef uint32 unaligned_uint32;
 
__attribute__((aligned(1))) typedef uint64 unaligned_uint64;
 
#else
 
typedef uint16 unaligned_uint16;
 
typedef uint32 unaligned_uint32;
 
typedef uint64 unaligned_uint64;
 
#endif /* __GNUC__ || __clang__ */
 

	
 
void NORETURN CDECL usererror(const char *str, ...) WARN_FORMAT(1, 2);
 
void NORETURN CDECL error(const char *str, ...) WARN_FORMAT(1, 2);
 
#define NOT_REACHED() error("NOT_REACHED triggered at line %i of %s", __LINE__, __FILE__)
src/string.cpp
Show inline comments
 
@@ -120,9 +120,9 @@ char *strecpy(char *dst, const char *src
 

	
 
	if (dst == last && *src != '\0') {
 
#if defined(STRGEN) || defined(SETTINGSGEN)
 
		error("String too long for destination buffer");
 
		error("String too long for destination buffer: %s", src);
 
#else /* STRGEN || SETTINGSGEN */
 
		Debug(misc, 0, "String too long for destination buffer");
 
		Debug(misc, 0, "String too long for destination buffer: {}", src);
 
#endif /* STRGEN || SETTINGSGEN */
 
	}
 
	return dst;
 
@@ -143,6 +143,16 @@ char *stredup(const char *s, const char 
 
	return tmp;
 
}
 

	
 
char *str_vfmt(const char *str, va_list va)
 
{
 
	char buf[4096];
 

	
 
	int len = vseprintf(buf, lastof(buf), str, va);
 
	char *p = MallocT<char>(len + 1);
 
	memcpy(p, buf, len + 1);
 
	return p;
 
}
 

	
 
/**
 
 * Format, "printf", into a newly allocated string.
 
 * @param str The formatting string.
src/string_func.h
Show inline comments
 
@@ -39,6 +39,7 @@ int CDECL seprintf(char *str, const char
 
int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap) WARN_FORMAT(3, 0) NOACCESS(2);
 

	
 
char *CDECL str_fmt(const char *str, ...) WARN_FORMAT(1, 2);
 
char *str_vfmt(const char *str, va_list ap);
 

	
 
std::string FormatArrayAsHex(span<const byte> data);
 

	
src/string_func_extra.h
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/*
 
 * 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/>.
 
 */
 

	
 
#ifndef STRING_FUNC_EXTRA_H
 
#define STRING_FUNC_EXTRA_H
 

	
 
#include "string_func.h"
 
#include <string>
 

	
 
static inline void str_validate(std::string &str, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK)
 
{
 
	if (str.empty()) return;
 
	char *buf = const_cast<char *>(str.c_str());
 
	str.resize(str_validate_intl(buf, buf + str.size(), settings) - buf);
 
}
 

	
 
#endif /* STRING_FUNC_EXTRA_H */
src/strings.cpp
Show inline comments
 
@@ -1027,6 +1027,9 @@ static char *FormatString(char *buff, co
 

	
 
			case SCC_REVISION: // {REV}
 
				buff = strecpy(buff, _openttd_revision, last);
 
				buff = strecpy(buff, " (", last);
 
				buff = strecpy(buff, _openttd_build_date_short, last);
 
				buff = strecpy(buff, ")", last);
 
				break;
 

	
 
			case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
 
@@ -1430,23 +1433,39 @@ static char *FormatString(char *buff, co
 
					StringParameters tmp_params(args_array);
 
					buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
 
				} else {
 
					StringID str = st->string_id;
 
					if (st->indtype != IT_INVALID) {
 
						/* Special case where the industry provides the name for the station */
 
						const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
 
					bool station_name_from_industry_success = false;
 

	
 
						/* Industry GRFs can change which might remove the station name and
 
						 * thus cause very strange things. Here we check for that before we
 
						 * actually set the station name. */
 
						if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
 
							str = indsp->station_name;
 
					StringID str = st->string_id;
 
					if (st->indtype != IT_INVALID)
 
					{
 
						if (_settings_game.construction.name_stations_based_on_industries == 2)
 
						{
 
							int64 args_array[] = { st->town->index, GetIndustrySpec(st->indtype)->name };
 
							StringParameters tmp_params(args_array);
 
							buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), &tmp_params, last);
 
							station_name_from_industry_success = true;
 
						}
 
						else if (_settings_game.construction.name_stations_based_on_industries == 1)
 
						{
 
							/* Special case where the industry provides the name for the station */
 
							const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
 

	
 
							/* Industry GRFs can change which might remove the station name and
 
							 * thus cause very strange things. Here we check for that before we
 
							 * actually set the station name. */
 
							if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
 
								str = indsp->station_name;
 
							}
 
						}
 
					}
 

	
 
					uint64 args_array[] = {STR_TOWN_NAME, st->town->index, st->index};
 
					WChar types_array[] = {0, SCC_TOWN_NAME, SCC_NUM};
 
					StringParameters tmp_params(args_array, 3, types_array);
 
					buff = GetStringWithArgs(buff, str, &tmp_params, last);
 
					
 
					if (!station_name_from_industry_success)
 
					{
 
						uint64 args_array[] = {STR_TOWN_NAME, st->town->index, st->index};
 
						WChar types_array[] = {0, SCC_TOWN_NAME, SCC_NUM};
 
						StringParameters tmp_params(args_array, 3, types_array);
 
						buff = GetStringWithArgs(buff, str, &tmp_params, last);
 
					}
 
				}
 
				break;
 
			}
src/table/settings.h.preamble
Show inline comments
 
@@ -56,56 +56,56 @@ static size_t ConvertLandscape(const cha
 

	
 
/* Macros for various objects to go in the configuration file.
 
 * This section is for global variables */
 
#define SDTG_VAR(name, type, flags, var, def, min, max, interval, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup)\
 
	NSD(Int, SLEG_GENERAL(name, SL_VAR, var, type, 1, from, to, extra), flags, startup, def, min, max, interval, str, strhelp, strval, cat, pre_check, post_callback)
 
#define SDTG_VAR(name, type, flags, var, def, min, max, interval, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup, extver)\
 
	NSD(Int, SLEG_GENERAL_X(name, SL_VAR, var, type, 1, from, to, extra, extver), flags, startup, def, min, max, interval, str, strhelp, strval, cat, pre_check, post_callback)
 

	
 
#define SDTG_BOOL(name, flags, var, def, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup)\
 
	NSD(Bool, SLEG_GENERAL(name, SL_VAR, var, SLE_BOOL, 1, from, to, extra), flags, startup, def, str, strhelp, strval, cat, pre_check, post_callback)
 
#define SDTG_BOOL(name, flags, var, def, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup, extver)\
 
	NSD(Bool, SLEG_GENERAL_X(name, SL_VAR, var, SLE_BOOL, 1, from, to, extra, extver), flags, startup, def, str, strhelp, strval, cat, pre_check, post_callback)
 

	
 
#define SDTG_LIST(name, type, flags, var, def, length, from, to, cat, extra, startup)\
 
	NSD(List, SLEG_GENERAL(name, SL_ARR, var, type, length, from, to, extra),flags, startup, def)
 
#define SDTG_LIST(name, type, flags, var, def, length, from, to, cat, extra, startup, extver)\
 
	NSD(List, SLEG_GENERAL_X(name, SL_ARR, var, type, length, from, to, extra, extver),flags, startup, def)
 

	
 
#define SDTG_SSTR(name, type, flags, var, def, max_length, pre_check, post_callback, from, to, cat, extra, startup)\
 
	NSD(String, SLEG_GENERAL(name, SL_STDSTR, var, type, sizeof(var), from, to, extra), flags, startup, def, max_length, pre_check, post_callback)
 
#define SDTG_SSTR(name, type, flags, var, def, max_length, pre_check, post_callback, from, to, cat, extra, startup, extver)\
 
	NSD(String, SLEG_GENERAL_X(name, SL_STDSTR, var, type, sizeof(var), from, to, extra, extver), flags, startup, def, max_length, pre_check, post_callback)
 

	
 
#define SDTG_OMANY(name, type, flags, var, def, max, full, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup)\
 
	NSD(OneOfMany, SLEG_GENERAL(name, SL_VAR, var, type, 1, from, to, extra), flags, startup, def, max, str, strhelp, strval, cat, pre_check, post_callback, full, nullptr)
 
#define SDTG_OMANY(name, type, flags, var, def, max, full, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup, extver)\
 
	NSD(OneOfMany, SLEG_GENERAL_X(name, SL_VAR, var, type, 1, from, to, extra, extver), flags, startup, def, max, str, strhelp, strval, cat, pre_check, post_callback, full, nullptr)
 

	
 
#define SDTG_MMANY(name, type, flags, var, def, full, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup)\
 
	NSD(ManyOfMany, SLEG_GENERAL(name, SL_VAR, var, type, 1, from, to, extra), flags, startup, def, str, strhelp, strval, cat, pre_check, post_callback, full, nullptr)
 
#define SDTG_MMANY(name, type, flags, var, def, full, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup, extver)\
 
	NSD(ManyOfMany, SLEG_GENERAL_X(name, SL_VAR, var, type, 1, from, to, extra, extver), flags, startup, def, str, strhelp, strval, cat, pre_check, post_callback, full, nullptr)
 

	
 
/* Macros for various objects to go in the configuration file.
 
 * This section is for structures where their various members are saved */
 
#define SDT_VAR(base, var, type, flags, def, min, max, interval, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup)\
 
	NSD(Int, SLE_GENERAL(SL_VAR, base, var, type, 1, from, to, extra), flags, startup, def, min, max, interval, str, strhelp, strval, cat, pre_check, post_callback)
 
#define SDT_VAR(base, var, type, flags, def, min, max, interval, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup, extver)\
 
	NSD(Int, SLE_GENERAL_X(SL_VAR, base, var, type, 1, from, to, extra, extver), flags, startup, def, min, max, interval, str, strhelp, strval, cat, pre_check, post_callback)
 

	
 
#define SDT_BOOL(base, var, flags, def, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup)\
 
	NSD(Bool, SLE_GENERAL(SL_VAR, base, var, SLE_BOOL, 1, from, to, extra), flags, startup, def, str, strhelp, strval, cat, pre_check, post_callback)
 
#define SDT_BOOL(base, var, flags, def, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup, extver)\
 
	NSD(Bool, SLE_GENERAL_X(SL_VAR, base, var, SLE_BOOL, 1, from, to, extra, extver), flags, startup, def, str, strhelp, strval, cat, pre_check, post_callback)
 

	
 
#define SDT_LIST(base, var, type, flags, def, from, to, cat, extra, startup)\
 
	NSD(List, SLE_GENERAL(SL_ARR, base, var, type, lengthof(((base*)8)->var), from, to, extra), flags, startup, def)
 
#define SDT_LIST(base, var, type, flags, def, from, to, cat, extra, startup, extver)\
 
	NSD(List, SLE_GENERAL_X(SL_ARR, base, var, type, lengthof(((base*)8)->var), from, to, extra, extver), flags, startup, def)
 

	
 
#define SDT_SSTR(base, var, type, flags, def, pre_check, post_callback, from, to, cat, extra, startup)\
 
	NSD(String, SLE_GENERAL(SL_STDSTR, base, var, type, sizeof(((base*)8)->var), from, to, extra), flags, startup, def, 0, pre_check, post_callback)
 
#define SDT_SSTR(base, var, type, flags, def, pre_check, post_callback, from, to, cat, extra, startup, extver)\
 
	NSD(String, SLE_GENERAL_X(SL_STDSTR, base, var, type, sizeof(((base*)8)->var), from, to, extra, extver), flags, startup, def, 0, pre_check, post_callback)
 

	
 
#define SDT_OMANY(base, var, type, flags, def, max, full, str, strhelp, strval, pre_check, post_callback, from, to, load, cat, extra, startup)\
 
	NSD(OneOfMany, SLE_GENERAL(SL_VAR, base, var, type, 1, from, to, extra), flags, startup, def, max, str, strhelp, strval, cat, pre_check, post_callback, full, load)
 
#define SDT_OMANY(base, var, type, flags, def, max, full, str, strhelp, strval, pre_check, post_callback, from, to, load, cat, extra, startup, extver)\
 
	NSD(OneOfMany, SLE_GENERAL_X(SL_VAR, base, var, type, 1, from, to, extra, extver), flags, startup, def, max, str, strhelp, strval, cat, pre_check, post_callback, full, load)
 

	
 
#define SDT_MMANY(base, var, type, flags, def, full, str, pre_check, post_callback, strhelp, strval, from, to, cat, extra, startup)\
 
	NSD(ManyOfMany, SLE_GENERAL(SL_VAR, base, var, type, 1, from, to, extra), flags, startup, def, str, strhelp, strval, cat, pre_check, post_callback, full, nullptr)
 
#define SDT_MMANY(base, var, type, flags, def, full, str, pre_check, post_callback, strhelp, strval, from, to, cat, extra, startup, extver)\
 
	NSD(ManyOfMany, SLE_GENERAL_X(SL_VAR, base, var, type, 1, from, to, extra, extver), flags, startup, def, str, strhelp, strval, cat, pre_check, post_callback, full, nullptr)
 

	
 

	
 
#define SDTC_VAR(var, type, flags, def, min, max, interval, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup)\
 
	SDTG_VAR(#var, type, flags, _settings_client.var, def, min, max, interval, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup)
 
#define SDTC_VAR(var, type, flags, def, min, max, interval, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup, extver)\
 
	SDTG_VAR(#var, type, flags, _settings_client.var, def, min, max, interval, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup, extver)
 

	
 
#define SDTC_BOOL(var, flags, def, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup)\
 
	SDTG_BOOL(#var, flags, _settings_client.var, def, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup)
 
#define SDTC_BOOL(var, flags, def, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup, extver)\
 
	SDTG_BOOL(#var, flags, _settings_client.var, def, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup, extver)
 

	
 
#define SDTC_LIST(var, type, flags, def, from, to, cat, extra, startup)\
 
	SDTG_LIST(#var, type, flags, _settings_client.var, def, lengthof(_settings_client.var), from, to, cat, extra, startup)
 
#define SDTC_LIST(var, type, flags, def, from, to, cat, extra, startup, extver)\
 
	SDTG_LIST(#var, type, flags, _settings_client.var, def, lengthof(_settings_client.var), from, to, cat, extra, startup, extver)
 

	
 
#define SDTC_SSTR(var, type, flags, def, max_length, pre_check, post_callback, from, to, cat, extra, startup)\
 
	SDTG_SSTR(#var, type, flags, _settings_client.var, def, max_length, pre_check, post_callback, from, to, cat, extra, startup)\
 
#define SDTC_SSTR(var, type, flags, def, max_length, pre_check, post_callback, from, to, cat, extra, startup, extver)\
 
	SDTG_SSTR(#var, type, flags, _settings_client.var, def, max_length, pre_check, post_callback, from, to, cat, extra, startup, extver)\
 

	
 
#define SDTC_OMANY(var, type, flags, def, max, full, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup)\
 
	SDTG_OMANY(#var, type, flags, _settings_client.var, def, max, full, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup)
 
#define SDTC_OMANY(var, type, flags, def, max, full, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup, extver)\
 
	SDTG_OMANY(#var, type, flags, _settings_client.var, def, max, full, str, strhelp, strval, pre_check, post_callback, from, to, cat, extra, startup, extver)
src/table/settings/company_settings.ini
Show inline comments
 
@@ -16,8 +16,8 @@ static const SettingVariant _company_set
 
[post-amble]
 
};
 
[templates]
 
SDT_BOOL = SDT_BOOL(CompanySettings, $var,        $flags, $def,                        $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup),
 
SDT_VAR  =  SDT_VAR(CompanySettings, $var, $type, $flags, $def, $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup),
 
SDT_BOOL = SDT_BOOL(CompanySettings, $var,        $flags, $def,                        $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup, $extver),
 
SDT_VAR  =  SDT_VAR(CompanySettings, $var, $type, $flags, $def, $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup, $extver),
 

	
 
[validation]
 
SDT_VAR = static_assert($max <= MAX_$type, "Maximum value for CompanySettings.$var exceeds storage size");
 
@@ -36,6 +36,7 @@ to       = SL_MAX_VERSION
 
cat      = SC_ADVANCED
 
extra    = 0
 
startup  = false
 
extver   = SlXvFeatureTest()
 

	
 

	
 

	
src/table/settings/currency_settings.ini
Show inline comments
 
@@ -11,8 +11,8 @@ static const SettingVariant _currency_se
 
[post-amble]
 
};
 
[templates]
 
SDT_VAR  = SDT_VAR (CurrencySpec, $var, $type, $flags, $def, $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup),
 
SDT_SSTR = SDT_SSTR(CurrencySpec, $var, $type, $flags, $def,                                                 $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup),
 
SDT_VAR  = SDT_VAR (CurrencySpec, $var, $type, $flags, $def, $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup, $extver),
 
SDT_SSTR = SDT_SSTR(CurrencySpec, $var, $type, $flags, $def,                                                 $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup, $extver),
 

	
 
[validation]
 
SDT_VAR = static_assert($max <= MAX_$type, "Maximum value for CurrencySpec.$var exceeds storage size");
 
@@ -31,6 +31,7 @@ to       = SL_MAX_VERSION
 
cat      = SC_ADVANCED
 
extra    = 0
 
startup  = false
 
extver   = SlXvFeatureTest()
 

	
 

	
 
[SDT_VAR]
src/table/settings/difficulty_settings.ini
Show inline comments
 
@@ -20,9 +20,9 @@ static const SettingVariant _difficulty_
 
[post-amble]
 
};
 
[templates]
 
SDTG_VAR   =   SDTG_VAR($name,              $type, $flags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDT_BOOL   =   SDT_BOOL(GameSettings, $var,        $flags, $def,                              $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDT_VAR    =    SDT_VAR(GameSettings, $var, $type, $flags, $def,       $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDTG_VAR   =   SDTG_VAR($name,              $type, $flags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 
SDT_BOOL   =   SDT_BOOL(GameSettings, $var,        $flags, $def,                              $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 
SDT_VAR    =    SDT_VAR(GameSettings, $var, $type, $flags, $def,       $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 

	
 
[validation]
 
SDTG_VAR = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size");
 
@@ -42,6 +42,7 @@ to       = SL_MAX_VERSION
 
cat      = SC_ADVANCED
 
extra    = 0
 
startup  = false
 
extver   = SlXvFeatureTest()
 

	
 

	
 
; Saved settings variables.
 
@@ -171,6 +172,18 @@ strval   = STR_DISASTER_NONE
 
cat      = SC_BASIC
 

	
 
[SDT_VAR]
 
var      = difficulty.vehicle_breakdown_scaler
 
type     = SLE_UINT32
 
def      = 16777215
 
min      = 0
 
max      = 16777215
 
interval = 1
 
str      = STR_CONFIG_SETTING_VEHICLE_BREAKDOWN_SCALER
 
strhelp  = STR_CONFIG_SETTING_VEHICLE_BREAKDOWN_SCALER_HELPTEXT
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_BREAKDOWN_SCALER)
 

	
 
[SDT_VAR]
 
var      = difficulty.subsidy_multiplier
 
type     = SLE_UINT8
 
from     = SLV_97
src/table/settings/economy_settings.ini
Show inline comments
 
@@ -9,13 +9,14 @@
 

	
 
[pre-amble]
 
static void TownFoundingChanged(int32 new_value);
 
static void PatchpackInvalidateRunningCostsOrElse(int32 new_value);
 

	
 
static const SettingVariant _economy_settings_table[] = {
 
[post-amble]
 
};
 
[templates]
 
SDT_BOOL   =   SDT_BOOL(GameSettings, $var,        $flags, $def,                              $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDT_VAR    =    SDT_VAR(GameSettings, $var, $type, $flags, $def,       $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDT_BOOL   =   SDT_BOOL(GameSettings, $var,        $flags, $def,                              $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 
SDT_VAR    =    SDT_VAR(GameSettings, $var, $type, $flags, $def,       $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 

	
 
[validation]
 
SDT_VAR = static_assert($max <= MAX_$type, "Maximum value for GameSettings.$var exceeds storage size");
 
@@ -34,6 +35,7 @@ to       = SL_MAX_VERSION
 
cat      = SC_ADVANCED
 
extra    = 0
 
startup  = false
 
extver   = SlXvFeatureTest()
 

	
 

	
 
[SDT_VAR]
 
@@ -127,6 +129,15 @@ post_cb  = [](auto) { SetWindowClassesDi
 
cat      = SC_BASIC
 

	
 
[SDT_BOOL]
 
var      = economy.bribe_risky
 
def      = true
 
str      = STR_CONFIG_SETTING_BRIBE_RISKY
 
strhelp  = STR_CONFIG_SETTING_BRIBE_RISKY_HELPTEXT
 
post_cb  = [](auto) { SetWindowClassesDirty(WC_TOWN_AUTHORITY); }
 
cat      = SC_BASIC
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_IMPROVEMENTS)
 

	
 
[SDT_BOOL]
 
var      = economy.exclusive_rights
 
from     = SLV_79
 
def      = true
 
@@ -174,6 +185,30 @@ strval   = STR_CONFIG_SETTING_ECONOMY_TY
 
post_cb  = [](auto) { InvalidateWindowClassesData(WC_INDUSTRY_VIEW); }
 
cat      = SC_BASIC
 

	
 
[SDT_VAR]
 
var      = economy.daylength_multiplier
 
type     = SLE_UINT8
 
def      = 1
 
min      = 1
 
max      = 255
 
interval = 1
 
str      = STR_CONFIG_SETTING_DAYLENGTH_FACTOR
 
strhelp  = STR_CONFIG_SETTING_DAYLENGTH_FACTOR_HELPTEXT
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_DAYLENGTH)
 

	
 
[SDT_VAR]
 
var      = economy.town_growth_multiplier
 
type     = SLE_UINT8
 
def      = 1
 
min      = 1
 
max      = 255
 
interval = 1
 
str      = STR_CONFIG_SETTING_TOWN_GROWTH_FACTOR
 
strhelp  = STR_CONFIG_SETTING_TOWN_GROWTH_FACTOR_HELPTEXT
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_IMPROVEMENTS)
 

	
 
[SDT_BOOL]
 
var      = economy.allow_shares
 
def      = false
 
@@ -292,3 +327,272 @@ str      = STR_CONFIG_SETTING_INFRASTRUC
 
strhelp  = STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT
 
post_cb  = [](auto) { InvalidateWindowClassesData(WC_COMPANY_INFRASTRUCTURE); }
 
cat      = SC_BASIC
 

	
 
[SDT_VAR]
 
var      = economy.infrastructure_base_cost_rail
 
type     = SLE_UINT16
 
def      = 10
 
min      = 1
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_RAIL
 
strhelp  = STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_RAIL_HELPTEXT
 
post_cb  = [](auto) { InvalidateWindowClassesData(WC_COMPANY_INFRASTRUCTURE); }
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_INFRASTRUCTURE)
 

	
 
[SDT_VAR]
 
var      = economy.infrastructure_base_cost_road
 
type     = SLE_UINT16
 
def      = 10
 
min      = 1
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_ROAD
 
strhelp  = STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_ROAD_HELPTEXT
 
post_cb  = [](auto) { InvalidateWindowClassesData(WC_COMPANY_INFRASTRUCTURE); }
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_INFRASTRUCTURE)
 

	
 
[SDT_VAR]
 
var      = economy.infrastructure_base_cost_water
 
type     = SLE_UINT16
 
def      = 8
 
min      = 1
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_WATER
 
strhelp  = STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_WATER_HELPTEXT
 
post_cb  = [](auto) { InvalidateWindowClassesData(WC_COMPANY_INFRASTRUCTURE); }
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_INFRASTRUCTURE)
 

	
 
[SDT_VAR]
 
var      = economy.infrastructure_base_cost_air
 
type     = SLE_UINT16
 
def      = 5000
 
min      = 1
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_AIR
 
strhelp  = STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_AIR_HELPTEXT
 
post_cb  = [](auto) { InvalidateWindowClassesData(WC_COMPANY_INFRASTRUCTURE); }
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_INFRASTRUCTURE)
 

	
 
[SDT_VAR]
 
var      = economy.infrastructure_base_cost_station
 
type     = SLE_UINT16
 
def      = 100
 
min      = 1
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_STATION
 
strhelp  = STR_CONFIG_SETTING_INFRASTRUCTURE_BASE_COST_STATION_HELPTEXT
 
post_cb  = [](auto) { InvalidateWindowClassesData(WC_COMPANY_INFRASTRUCTURE); }
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_INFRASTRUCTURE)
 

	
 
[SDT_VAR]
 
var      = economy.running_cost_multiplier_rail
 
type     = SLE_UINT16
 
def      = 1
 
min      = 1
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_RAIL
 
strhelp  = STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_RAIL_HELPTEXT
 
post_cb  = PatchpackInvalidateRunningCostsOrElse
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_RUNNING_COST_MULT)
 

	
 
[SDT_VAR]
 
var      = economy.running_cost_multiplier_road
 
type     = SLE_UINT16
 
def      = 1
 
min      = 1
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_ROAD
 
strhelp  = STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_ROAD_HELPTEXT
 
post_cb  = PatchpackInvalidateRunningCostsOrElse
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_RUNNING_COST_MULT)
 

	
 
[SDT_VAR]
 
var      = economy.running_cost_multiplier_water
 
type     = SLE_UINT16
 
def      = 1
 
min      = 1
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_WATER
 
strhelp  = STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_WATER_HELPTEXT
 
post_cb  = PatchpackInvalidateRunningCostsOrElse
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_RUNNING_COST_MULT)
 

	
 
[SDT_VAR]
 
var      = economy.running_cost_multiplier_air
 
type     = SLE_UINT16
 
def      = 1
 
min      = 1
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_AIR
 
strhelp  = STR_CONFIG_SETTING_RUNNING_COST_MULTIPLIER_AIR_HELPTEXT
 
post_cb  = PatchpackInvalidateRunningCostsOrElse
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_RUNNING_COST_MULT)
 

	
 
[SDT_VAR]
 
var      = economy.dilapidation_max_amount
 
type     = SLE_UINT16
 
def      = 0
 
min      = 0
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_DILAPIDATION_MAX_AMOUNT
 
strhelp  = STR_CONFIG_SETTING_DILAPIDATION_MAX_AMOUNT_HELPTEXT
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_DILAPIDATION)
 

	
 
[SDT_VAR]
 
var      = economy.dilapidation_increase
 
type     = SLE_UINT16
 
def      = 0
 
min      = 0
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_DILAPIDATION_INCREASE
 
strhelp  = STR_CONFIG_SETTING_DILAPIDATION_INCREASE_HELPTEXT
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_DILAPIDATION)
 

	
 
[SDT_VAR]
 
var      = economy.dilapidation_decrease
 
type     = SLE_UINT16
 
def      = 0
 
min      = 0
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_DILAPIDATION_DECREASE
 
strhelp  = STR_CONFIG_SETTING_DILAPIDATION_DECREASE_HELPTEXT
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_DILAPIDATION)
 

	
 
[SDT_VAR]
 
var      = economy.dilapidation_pop_rail
 
type     = SLE_UINT16
 
def      = 0
 
min      = 0
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_DILAPIDATION_POP_RAIL
 
strhelp  = STR_CONFIG_SETTING_DILAPIDATION_POP_RAIL_HELPTEXT
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_DILAPIDATION)
 

	
 
[SDT_VAR]
 
var      = economy.dilapidation_pop_road
 
type     = SLE_UINT16
 
def      = 0
 
min      = 0
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_DILAPIDATION_POP_ROAD
 
strhelp  = STR_CONFIG_SETTING_DILAPIDATION_POP_ROAD_HELPTEXT
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_DILAPIDATION)
 

	
 
[SDT_VAR]
 
var      = economy.dilapidation_pop_water
 
type     = SLE_UINT16
 
def      = 0
 
min      = 0
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_DILAPIDATION_POP_WATER
 
strhelp  = STR_CONFIG_SETTING_DILAPIDATION_POP_WATER_HELPTEXT
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_DILAPIDATION)
 

	
 
[SDT_VAR]
 
var      = economy.dilapidation_pop_air
 
type     = SLE_UINT16
 
def      = 0
 
min      = 0
 
max      = 65535
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_DILAPIDATION_POP_AIR
 
strhelp  = STR_CONFIG_SETTING_DILAPIDATION_POP_AIR_HELPTEXT
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_DILAPIDATION)
 

	
 
[SDT_VAR]
 
var      = economy.dilapidation_fine_rail
 
type     = SLE_UINT32
 
def      = 0
 
min      = 0
 
max      = 1000000
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_DILAPIDATION_FINE_RAIL
 
strhelp  = STR_CONFIG_SETTING_DILAPIDATION_FINE_RAIL_HELPTEXT
 
strval   = STR_JUST_CURRENCY_LONG
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_DILAPIDATION)
 

	
 
[SDT_VAR]
 
var      = economy.dilapidation_fine_road
 
type     = SLE_UINT32
 
def      = 0
 
min      = 0
 
max      = 1000000
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_DILAPIDATION_FINE_ROAD
 
strhelp  = STR_CONFIG_SETTING_DILAPIDATION_FINE_ROAD_HELPTEXT
 
strval   = STR_JUST_CURRENCY_LONG
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_DILAPIDATION)
 

	
 
[SDT_VAR]
 
var      = economy.dilapidation_fine_water
 
type     = SLE_UINT32
 
def      = 0
 
min      = 0
 
max      = 1000000
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_DILAPIDATION_FINE_WATER
 
strhelp  = STR_CONFIG_SETTING_DILAPIDATION_FINE_WATER_HELPTEXT
 
strval   = STR_JUST_CURRENCY_LONG
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_DILAPIDATION)
 

	
 
[SDT_VAR]
 
var      = economy.dilapidation_fine_air
 
type     = SLE_UINT32
 
def      = 0
 
min      = 0
 
max      = 1000000
 
interval = 1
 
cat      = SC_EXPERT
 
str      = STR_CONFIG_SETTING_DILAPIDATION_FINE_AIR
 
strhelp  = STR_CONFIG_SETTING_DILAPIDATION_FINE_AIR_HELPTEXT
 
strval   = STR_JUST_CURRENCY_LONG
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_DILAPIDATION)
src/table/settings/game_settings.ini
Show inline comments
 
@@ -26,12 +26,12 @@ static const SettingVariant _game_settin
 
[post-amble]
 
};
 
[templates]
 
SDTG_BOOL  =  SDTG_BOOL($name,                     $flags, $var, $def,                        $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDTG_VAR   =   SDTG_VAR($name,              $type, $flags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDTC_BOOL  =  SDTC_BOOL(              $var,        $flags, $def,                              $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDT_BOOL   =   SDT_BOOL(GameSettings, $var,        $flags, $def,                              $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDT_OMANY  =  SDT_OMANY(GameSettings, $var, $type, $flags, $def,             $max, $full,     $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $load, $cat, $extra, $startup),
 
SDT_VAR    =    SDT_VAR(GameSettings, $var, $type, $flags, $def,       $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDTG_BOOL  =  SDTG_BOOL($name,                     $flags, $var, $def,                        $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 
SDTG_VAR   =   SDTG_VAR($name,              $type, $flags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 
SDTC_BOOL  =  SDTC_BOOL(              $var,        $flags, $def,                              $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 
SDT_BOOL   =   SDT_BOOL(GameSettings, $var,        $flags, $def,                              $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 
SDT_OMANY  =  SDT_OMANY(GameSettings, $var, $type, $flags, $def,             $max, $full,     $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $load, $cat, $extra, $startup, $extver),
 
SDT_VAR    =    SDT_VAR(GameSettings, $var, $type, $flags, $def,       $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 

	
 
[validation]
 
SDTG_VAR = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size");
 
@@ -52,6 +52,7 @@ to       = SL_MAX_VERSION
 
cat      = SC_ADVANCED
 
extra    = 0
 
startup  = false
 
extver   = SlXvFeatureTest()
 

	
 

	
 
[SDT_BOOL]
 
@@ -327,6 +328,18 @@ str      = STR_CONFIG_SETTING_PLANE_SPEE
 
strhelp  = STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT
 
strval   = STR_CONFIG_SETTING_PLANE_SPEED_VALUE
 

	
 
[SDT_VAR]
 
var      = vehicle.plane_range_multiplier
 
type     = SLE_UINT8
 
def      = 1
 
min      = 1
 
max      = 255
 
interval = 1
 
str      = STR_CONFIG_SETTING_PLANE_RANGE_MULTIPLIER
 
strhelp  = STR_CONFIG_SETTING_PLANE_RANGE_MULTIPLIER_HELPTEXT
 
strval   = STR_JUST_INT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_PLANE_RANGE_MULT)
 

	
 
[SDT_BOOL]
 
var      = vehicle.dynamic_engines
 
from     = SLV_95
 
@@ -349,6 +362,14 @@ strhelp  = STR_CONFIG_SETTING_PLANE_CRAS
 
strval   = STR_CONFIG_SETTING_PLANE_CRASHES_NONE
 
cat      = SC_BASIC
 

	
 
[SDT_BOOL]
 
var      = vehicle.improved_breakdowns
 
flags    = SF_NO_NETWORK
 
def      = false
 
str      = STR_CONFIG_SETTING_IMPROVED_BREAKDOWNS
 
strhelp  = STR_CONFIG_SETTING_IMPROVED_BREAKDOWNS_HELPTEXT
 
extver   = SlXvFeatureTest(XSLFTO_AND, XSLFI_IMPROVED_BREAKDOWNS)
 

	
 
[SDT_VAR]
 
var      = vehicle.extend_vehicle_life
 
type     = SLE_UINT8
src/table/settings/gui_settings.ini
Show inline comments
 
@@ -23,9 +23,9 @@ static const SettingVariant _gui_setting
 
[post-amble]
 
};
 
[templates]
 
SDTC_BOOL  =  SDTC_BOOL(              $var,        $flags, $def,                              $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDTC_OMANY = SDTC_OMANY(              $var, $type, $flags, $def,             $max, $full,     $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDTC_VAR   =   SDTC_VAR(              $var, $type, $flags, $def,       $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDTC_BOOL  =  SDTC_BOOL(              $var,        $flags, $def,                              $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 
SDTC_OMANY = SDTC_OMANY(              $var, $type, $flags, $def,             $max, $full,     $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 
SDTC_VAR   =   SDTC_VAR(              $var, $type, $flags, $def,       $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 

	
 
[validation]
 
SDTC_OMANY = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size");
 
@@ -45,6 +45,7 @@ to       = SL_MAX_VERSION
 
cat      = SC_ADVANCED
 
extra    = 0
 
startup  = false
 
extver   = SlXvFeatureTest()
 

	
 

	
 
[SDTC_OMANY]
 
@@ -294,6 +295,14 @@ strhelp  = STR_CONFIG_SETTING_POPULATION
 
post_cb  = [](auto) { UpdateAllTownVirtCoords(); }
 

	
 
[SDTC_BOOL]
 
var      = gui.colour_based_on_town_rating
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC
 
def      = true
 
str      = STR_CONFIG_SETTING_RATING_COLOUR_IN_LABEL
 
strhelp  = STR_CONFIG_SETTING_RATING_COLOUR_IN_LABEL_HELPTEXT
 
post_cb  = [](auto) { UpdateAllTownVirtCoords(); }
 

	
 
[SDTC_BOOL]
 
var      = gui.link_terraform_toolbar
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC
 
def      = false
 
@@ -856,3 +865,9 @@ min      = 1
 
max      = 65535
 
cat      = SC_EXPERT
 

	
 
[SDTC_BOOL]
 
var      = gui.load_legacy_patchpack_savedata
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC
 
def      = true
 
str      = STR_CONFIG_SETTING_LOAD_LEGACY_PATCHPACK_DATA
 
strhelp  = STR_CONFIG_SETTING_LOAD_LEGACY_PATCHPACK_DATA_HELPTEXT
src/table/settings/linkgraph_settings.ini
Show inline comments
 
@@ -12,7 +12,7 @@ static const SettingVariant _linkgraph_s
 
[post-amble]
 
};
 
[templates]
 
SDT_VAR    =    SDT_VAR(GameSettings, $var, $type, $flags, $def,       $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDT_VAR    =    SDT_VAR(GameSettings, $var, $type, $flags, $def,       $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 

	
 
[validation]
 
SDT_VAR = static_assert($max <= MAX_$type, "Maximum value for GameSettings.$var exceeds storage size");
 
@@ -31,6 +31,7 @@ to       = SL_MAX_VERSION
 
cat      = SC_ADVANCED
 
extra    = 0
 
startup  = false
 
extver   = SlXvFeatureTest()
 

	
 

	
 
[SDT_VAR]
src/table/settings/locale_settings.ini
Show inline comments
 
@@ -19,9 +19,9 @@ static const SettingVariant _locale_sett
 
[post-amble]
 
};
 
[templates]
 
SDTG_OMANY = SDTG_OMANY($name,              $type, $flags, $var, $def,       $max, $full,     $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDT_OMANY  =  SDT_OMANY(GameSettings, $var, $type, $flags, $def,             $max, $full,     $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $load, $cat, $extra, $startup),
 
SDT_SSTR   =   SDT_SSTR(GameSettings, $var, $type, $flags, $def,                                                       $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup),
 
SDTG_OMANY = SDTG_OMANY($name,              $type, $flags, $var, $def,       $max, $full,     $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 
SDT_OMANY  =  SDT_OMANY(GameSettings, $var, $type, $flags, $def,             $max, $full,     $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $load, $cat, $extra, $startup, $extver),
 
SDT_SSTR   =   SDT_SSTR(GameSettings, $var, $type, $flags, $def,                                                       $pre_cb, $post_cb, $from, $to,        $cat, $extra, $startup, $extver),
 

	
 
[validation]
 
SDTG_OMANY = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size");
 
@@ -41,6 +41,7 @@ to       = SL_MAX_VERSION
 
cat      = SC_ADVANCED
 
extra    = 0
 
startup  = false
 
extver   = SlXvFeatureTest()
 

	
 

	
 
[SDT_OMANY]
src/table/settings/misc_settings.ini
Show inline comments
 
@@ -24,12 +24,12 @@ static const SettingVariant _misc_settin
 
[post-amble]
 
};
 
[templates]
 
SDTG_LIST  =  SDTG_LIST($name, $type, $flags, $var, $def,       $length,                                                            $from, $to, $cat, $extra, $startup),
 
SDTG_MMANY = SDTG_MMANY($name, $type, $flags, $var, $def,                        $full, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup),
 
SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $var, $def,       $max,            $full, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup),
 
SDTG_SSTR  =  SDTG_SSTR($name, $type, $flags, $var, $def,       0,                                               $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup),
 
SDTG_BOOL  =  SDTG_BOOL($name,        $flags, $var, $def,                               $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup),
 
SDTG_VAR   =   SDTG_VAR($name, $type, $flags, $var, $def, $min, $max, $interval,        $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup),
 
SDTG_LIST  =  SDTG_LIST($name, $type, $flags, $var, $def,       $length,                                                            $from, $to, $cat, $extra, $startup, $extver),
 
SDTG_MMANY = SDTG_MMANY($name, $type, $flags, $var, $def,                        $full, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup, $extver),
 
SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $var, $def,       $max,            $full, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup, $extver),
 
SDTG_SSTR  =  SDTG_SSTR($name, $type, $flags, $var, $def,       0,                                               $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup, $extver),
 
SDTG_BOOL  =  SDTG_BOOL($name,        $flags, $var, $def,                               $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup, $extver),
 
SDTG_VAR   =   SDTG_VAR($name, $type, $flags, $var, $def, $min, $max, $interval,        $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup, $extver),
 

	
 
[validation]
 
SDTG_VAR = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size");
 
@@ -49,6 +49,7 @@ to       = SL_MAX_VERSION
 
cat      = SC_ADVANCED
 
extra    = 0
 
startup  = true
 
extver   = SlXvFeatureTest()
 

	
 

	
 

	

Changeset was too big and was cut off... Show full diff anyway

0 comments (0 inline, 0 general)