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
57 files changed:
Changeset was too big and was cut off... Show full diff anyway
0 comments (0 inline, 0 general)
.gitignore
Show inline comments
 
/.vs
 
/build*
 
CMakeSettings.json
 
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
 
@@ -94,24 +94,38 @@ if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_
 
            set(REV_ISSTABLETAG 1)
 
        else()
 
            set(REV_ISSTABLETAG 0)
 
        endif()
 
    else()
 
        set(REV_VERSION "${REV_ISODATE}-${BRANCH}${HASHPREFIX}${SHORTHASH}")
 
        set(REV_ISTAG 0)
 
        set(REV_ISSTABLETAG 0)
 
    endif()
 

	
 
    # 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}")
 
    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)
 
else()
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
 
@@ -398,24 +398,25 @@ add_files(
 
    statusbar_gui.cpp
 
    statusbar_gui.h
 
    stdafx.h
 
    story.cpp
 
    story_base.h
 
    story_cmd.h
 
    story_gui.cpp
 
    story_type.h
 
    strgen/strgen.h
 
    string.cpp
 
    string_base.h
 
    string_func.h
 
    string_func_extra.h
 
    string_type.h
 
    stringfilter.cpp
 
    stringfilter_type.h
 
    strings.cpp
 
    strings_func.h
 
    strings_type.h
 
    subsidy.cpp
 
    subsidy_base.h
 
    subsidy_cmd.h
 
    subsidy_func.h
 
    subsidy_gui.cpp
 
    subsidy_type.h
src/aircraft.h
Show inline comments
 
@@ -48,24 +48,25 @@ enum AirVehicleFlags {
 
};
 

	
 
static const int ROTOR_Z_OFFSET         = 5;    ///< Z Offset between helicopter- and rotorsprite.
 

	
 
void HandleAircraftEnterHangar(Aircraft *v);
 
void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type);
 
void UpdateAirplanesOnNewStation(const Station *st);
 
void UpdateAircraftCache(Aircraft *v, bool update_range = false);
 

	
 
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>
 
int GetAircraftFlightLevel(T *v, bool takeoff = false);
 

	
 
/** Variables that are cached to improve performance and such. */
 
struct AircraftCache {
 
	uint32 cached_max_range_sqr;   ///< Cached squared maximum range.
 
	uint16 cached_max_range;       ///< Cached maximum range.
 
};
 

	
 
/**
src/aircraft_cmd.cpp
Show inline comments
 
@@ -140,26 +140,26 @@ static StationID FindNearestHangar(const
 
			next_dest = Station::GetIfValid(v->GetNextStoppingStation().value);
 
		}
 
	}
 

	
 
	for (const Station *st : Station::Iterate()) {
 
		if (st->owner != v->owner || !(st->facilities & FACIL_AIRPORT) || !st->airport.HasHangar()) continue;
 

	
 
		const AirportFTAClass *afc = st->airport.GetFTA();
 

	
 
		/* 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) {
 
			uint last_dist = (last_dest != nullptr && last_dest->airport.tile != INVALID_TILE) ? DistanceSquare(st->airport.tile, last_dest->airport.tile) : 0;
 
			uint next_dist = (next_dest != nullptr && next_dest->airport.tile != INVALID_TILE) ? DistanceSquare(st->airport.tile, next_dest->airport.tile) : 0;
 
			if (last_dist > max_range || next_dist > max_range) continue;
 
		}
 

	
 
		/* v->tile can't be used here, when aircraft is flying v->tile is set to 0 */
 
		uint distance = DistanceSquare(vtile, st->airport.tile);
 
		if (distance < best || index == INVALID_STATION) {
 
			best = distance;
 
@@ -317,24 +317,27 @@ CommandCost CmdBuildAircraft(DoCommandFl
 
		v->acceleration = avi->acceleration;
 
		v->engine_type = e->index;
 
		u->engine_type = e->index;
 

	
 
		v->subtype = (avi->subtype & AIR_CTOL ? AIR_AIRCRAFT : AIR_HELICOPTER);
 
		v->UpdateDeltaXY();
 

	
 
		u->subtype = AIR_SHADOW;
 
		u->UpdateDeltaXY();
 

	
 
		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);
 

	
 
		v->state = HANGAR;
 
		v->previous_pos = v->pos;
 
		v->targetairport = GetStationIndex(tile);
 
		v->SetNext(u);
 

	
 
		v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_aircraft);
 

	
 
		v->date_of_last_service = _date;
 
@@ -428,24 +431,25 @@ static void CheckIfAircraftNeedsService(
 
		v->current_order.MakeGoToDepot(st->index, ODTFB_SERVICE);
 
		SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
 
	} else if (v->current_order.IsType(OT_GOTO_DEPOT)) {
 
		v->current_order.MakeDummy();
 
		SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
 
	}
 
}
 

	
 
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());
 
}
 

	
 
void Aircraft::OnNewDay()
 
{
 
	if (!this->IsNormalAircraft()) return;
 

	
 
	if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
 

	
 
	CheckOrders(this);
 

	
 
	CheckVehicleBreakdown(this);
 
@@ -598,25 +602,25 @@ void UpdateAircraftCache(Aircraft *v, bo
 
	} else {
 
		/* Use the default max speed of the vehicle. */
 
		v->vcache.cached_max_speed = AircraftVehInfo(v->engine_type)->max_speed;
 
	}
 

	
 
	/* Update cargo aging period. */
 
	v->vcache.cached_cargo_age_period = GetVehicleProperty(v, PROP_AIRCRAFT_CARGO_AGE_PERIOD, EngInfo(v->engine_type)->cargo_age_period);
 
	Aircraft *u = v->Next(); // Shadow for mail
 
	u->vcache.cached_cargo_age_period = GetVehicleProperty(u, PROP_AIRCRAFT_CARGO_AGE_PERIOD, EngInfo(u->engine_type)->cargo_age_period);
 

	
 
	/* 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;
 
	}
 
}
 

	
 

	
 
/**
 
 * Special velocities for aircraft
 
 */
 
enum AircraftSpeedLimits {
 
	SPEED_LIMIT_TAXI     =     50,  ///< Maximum speed of an aircraft while taxiing
 
	SPEED_LIMIT_APPROACH =    230,  ///< Maximum speed of an aircraft on finals
 
@@ -640,27 +644,35 @@ static int UpdateAircraftSpeed(Aircraft 
 
	 *     acceleration * 3 / 16 mph = acceleration * 3 / 16 * 16 / 10 km-ish/h
 
	 *                               = acceleration * 3 / 10 * 256 * (km-ish/h / 256)
 
	 *                               ~ acceleration * 77 (km-ish/h / 256)
 
	 */
 
	uint spd = v->acceleration * 77;
 
	byte t;
 

	
 
	/* Adjust speed limits by plane speed factor to prevent taxiing
 
	 * and take-off speeds being too low. */
 
	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) {
 
		if (v->cur_speed < speed_limit) hard_limit = false;
 
		speed_limit = v->vcache.cached_max_speed;
 
	}
 

	
 
	v->subspeed = (t = v->subspeed) + (byte)spd;
 

	
 
	/* Aircraft's current speed is used twice so that very fast planes are
 
	 * forced to slow down rapidly in the short distance needed. The magic
 
	 * value 16384 was determined to give similar results to the old speed/48
 
@@ -1147,24 +1159,57 @@ static bool AircraftController(Aircraft 
 
			} else if (z < airport_z) {
 
				z++;
 
			}
 

	
 
		}
 

	
 
		SetAircraftPosition(v, gp.x, gp.y, z);
 
	} while (--count != 0);
 
	return false;
 
}
 

	
 
/**
 
 * 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.
 
 */
 
static bool HandleCrashedAircraft(Aircraft *v)
 
{
 
	v->crashed_counter += 3;
 

	
 
	Station *st = GetTargetAirportIfValid(v);
 

	
 
	/* make aircraft crash down to the ground */
 
	if (v->crashed_counter < 500 && st == nullptr && ((v->crashed_counter % 3) == 0) ) {
 
		int z = GetSlopePixelZ(Clamp(v->x_pos, 0, MapMaxX() * TILE_SIZE), Clamp(v->y_pos, 0, MapMaxY() * TILE_SIZE));
 
@@ -1226,26 +1271,27 @@ static void HandleAircraftSmoke(Aircraft
 
		{  5,  5 },
 
		{  6,  0 },
 
		{  5, -5 },
 
		{  0, -6 },
 
		{ -5, -5 },
 
		{ -6,  0 },
 
		{ -5,  5 },
 
		{  0,  6 }
 
	};
 

	
 
	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;
 
	}
 

	
 
	/* Spawn effect et most once per Tick, i.e. !mode */
 
	if (!mode && (v->tick_counter & 0x0F) == 0) {
 
		CreateEffectVehicleRel(v,
 
			smoke_pos[v->direction].x,
 
			smoke_pos[v->direction].y,
 
			2,
 
			EV_BREAKDOWN_SMOKE_AIRCRAFT
 
@@ -1356,26 +1402,30 @@ static void CrashAirplane(Aircraft *v)
 
 * @param v Aircraft to test.
 
 */
 
static void MaybeCrashAirplane(Aircraft *v)
 
{
 

	
 
	Station *st = Station::Get(v->targetairport);
 

	
 
	uint32 prob;
 
	if ((st->airport.GetFTA()->flags & AirportFTAClass::SHORT_STRIP) &&
 
			(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;
 
	}
 

	
 
	if (GB(Random(), 0, 22) > prob) return;
 

	
 
	/* Crash the airplane. Remove all goods stored at the station. */
 
	for (CargoID i = 0; i < NUM_CARGO; i++) {
 
		st->goods[i].rating = 1;
 
		st->goods[i].cargo.Truncate();
 
	}
 

	
 
	CrashAirplane(v);
src/clear_cmd.cpp
Show inline comments
 
@@ -25,25 +25,25 @@
 
#include "safeguards.h"
 

	
 
static CommandCost ClearTile_Clear(TileIndex tile, DoCommandFlag flags)
 
{
 
	static const Price clear_price_table[] = {
 
		PR_CLEAR_GRASS,
 
		PR_CLEAR_ROUGH,
 
		PR_CLEAR_ROCKS,
 
		PR_CLEAR_FIELDS,
 
		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)]]);
 
	}
 

	
 
	if (flags & DC_EXEC) DoClearSquare(tile);
 

	
 
	return price;
 
}
 

	
 
void DrawClearLandTile(const TileInfo *ti, byte set)
 
{
src/command_type.h
Show inline comments
 
@@ -13,25 +13,25 @@
 
#include "economy_type.h"
 
#include "strings_type.h"
 
#include "tile_type.h"
 
#include <vector>
 

	
 
struct GRFFile;
 

	
 
/**
 
 * Common return value for all commands. Wraps the cost and
 
 * 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
 
	const GRFFile *textref_stack_grffile; ///< NewGRF providing the #TextRefStack content.
 
	uint textref_stack_size;   ///< Number of uint32 values to put on the #TextRefStack for the error message.
 

	
 
	static uint32 textref_stack[16];
 

	
 
public:
 
	/**
 
	 * Creates a command cost return with no cost and no error
 
	 */
src/company_cmd.cpp
Show inline comments
 
@@ -571,24 +571,26 @@ Company *DoStartupNewCompany(bool is_ai,
 

	
 
	SetWindowDirty(WC_GRAPH_LEGEND, 0);
 
	InvalidateWindowData(WC_CLIENT_LIST, 0);
 
	InvalidateWindowData(WC_LINKGRAPH_LEGEND, 0);
 
	BuildOwnerLegend();
 
	InvalidateWindowData(WC_SMALLMAP, 0, 1);
 

	
 
	if (is_ai && (!_networking || _network_server)) AI::StartNew(c->index);
 

	
 
	AI::BroadcastNewEvent(new ScriptEventCompanyNew(c->index), c->index);
 
	Game::NewEvent(new ScriptEventCompanyNew(c->index));
 

	
 
	if (!is_ai) UpdateAllTownVirtCoords();
 

	
 
	return c;
 
}
 

	
 
/** Start the next competitor now. */
 
void StartupCompanies()
 
{
 
	_next_competitor_start = 0;
 
}
 

	
 
/** Start a new competitor company if possible. */
 
static bool MaybeStartNewCompany()
 
{
src/company_gui.cpp
Show inline comments
 
@@ -61,42 +61,62 @@ static ExpensesType _expenses_list_1[] =
 
	EXPENSES_NEW_VEHICLES,
 
	EXPENSES_TRAIN_RUN,
 
	EXPENSES_ROADVEH_RUN,
 
	EXPENSES_AIRCRAFT_RUN,
 
	EXPENSES_SHIP_RUN,
 
	EXPENSES_PROPERTY,
 
	EXPENSES_TRAIN_INC,
 
	EXPENSES_ROADVEH_INC,
 
	EXPENSES_AIRCRAFT_INC,
 
	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. */
 
static ExpensesType _expenses_list_2[] = {
 
	EXPENSES_TRAIN_INC,
 
	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,
 
};
 

	
 
/** Expense list container. */
 
struct ExpensesList {
 
	const ExpensesType *et;   ///< Expenses items.
 
	const uint length;        ///< Number of items in list.
 
	const uint num_subtotals; ///< Number of sub-totals in the list.
 

	
 
	ExpensesList(ExpensesType *et, int length, int num_subtotals) : et(et), length(length), num_subtotals(num_subtotals)
 
	{
src/company_type.h
Show inline comments
 
@@ -27,25 +27,25 @@ enum Owner : byte {
 
	OWNER_DEITY     = 0x12, ///< The object is owned by a superuser / goal script
 
	OWNER_END,              ///< Last + 1 owner
 
	INVALID_OWNER   = 0xFF, ///< An invalid owner
 
	INVALID_COMPANY = 0xFF, ///< An invalid company
 

	
 
	/* 'Fake' companies used for networks */
 
	COMPANY_INACTIVE_CLIENT = 253, ///< The client is joining
 
	COMPANY_NEW_COMPANY     = 254, ///< The client wants a new company
 
	COMPANY_SPECTATOR       = 255, ///< The client is spectating
 
};
 
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
 
static const uint MAX_COMPANY_SHARE_OWNERS        =  4; ///< The maximum number of shares of a company that can be owned by another company.
 

	
 
/** Define basic enum properties */
 
template <> struct EnumPropsT<Owner> : MakeEnumPropsT<Owner, byte, OWNER_BEGIN, OWNER_END, INVALID_OWNER> {};
 

	
 
typedef Owner CompanyID;
 

	
 
typedef uint16 CompanyMask;
 

	
src/core/bitmath_func.hpp
Show inline comments
 
@@ -366,32 +366,51 @@ struct SetBitIterator {
 
	Iterator end() { return Iterator(static_cast<Tbitset>(0)); }
 
	bool empty() { return this->begin() == this->end(); }
 

	
 
private:
 
	Tbitset bitset;
 
};
 

	
 
#if defined(__APPLE__)
 
	/* Make endian swapping use Apple's macros to increase speed
 
	 * (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.
 
	 */
 
	static inline uint32 BSWAP32(uint32 x)
 
	{
 
#if !defined(__ICC) && defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4)  && __GNUC_MINOR__ >= 3))
 
		/* GCC >= 4.3 provides a builtin, resulting in faster code */
 
		return static_cast<uint32>(__builtin_bswap32(static_cast<int32>(x)));
 
#else
 
		return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) | ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000);
 
#endif /* defined(__GNUC__) */
src/core/endian_func.hpp
Show inline comments
 
@@ -8,43 +8,51 @@
 
/** @file endian_func.hpp Function to handling different endian machines. */
 

	
 
#ifndef ENDIAN_FUNC_HPP
 
#define ENDIAN_FUNC_HPP
 

	
 
#include "endian_type.hpp"
 
#include "bitmath_func.hpp"
 

	
 
/* Setup alignment and conversion macros */
 
#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)
 
{
 
	return FROM_LE16(*(const uint16*)x);
 
}
 

	
 
static inline uint16 ReadLE16Unaligned(const void *x)
 
{
 
#if OTTD_ALIGNMENT == 1
 
	return ((const byte*)x)[0] | ((const byte*)x)[1] << 8;
 
#else
src/date.cpp
Show inline comments
 
@@ -27,25 +27,26 @@ Year      _cur_year;   ///< Current year
 
Month     _cur_month;  ///< Current month (0..11)
 
Date      _date;       ///< Current date in days (day counter)
 
DateFract _date_fract; ///< Fractional part of the day.
 
uint16 _tick_counter;  ///< Ever incrementing (and sometimes wrapping) tick counter for setting off various events
 

	
 
/**
 
 * Set the date.
 
 * @param date  New date
 
 * @param fract The number of ticks that have passed on this date.
 
 */
 
void SetDate(Date date, DateFract fract)
 
{
 
	assert(fract < DAY_TICKS);
 
	//Get rid of this insane assert
 
	//assert(fract < DAY_TICKS);
 

	
 
	YearMonthDay ymd;
 

	
 
	_date = date;
 
	_date_fract = fract;
 
	ConvertDateToYMD(date, &ymd);
 
	_cur_year = ymd.year;
 
	_cur_month = ymd.month;
 
}
 

	
 
#define M(a, b) ((a << 5) | b)
 
static const uint16 _month_date_from_year_day[] = {
src/date_type.h
Show inline comments
 
@@ -16,37 +16,44 @@ typedef uint16 DateFract; ///< The fract
 
typedef int32  Ticks;     ///< The type to store ticks in
 

	
 
typedef int32  Year;  ///< Type for the year, note: 0 based, i.e. starts at the year 0.
 
typedef uint8  Month; ///< Type for the month, note: 0 based, i.e. 0 = January, 11 = December.
 
typedef uint8  Day;   ///< Type for the day of the month, note: 1 based, first day of a month is 1.
 

	
 
/**
 
 * 1 day is 74 ticks; _date_fract used to be uint16 and incremented by 885. On
 
 *                    an overflow the new day begun and 65535 / 885 = 74.
 
 * 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
 
 * primarily used for loading newgrf and savegame data and returning some
 
 * newgrf (callback) functions that were in the original (TTD) inherited
 
 * format, where '_date == 0' meant that it was 1920-01-01.
 
 */
 

	
 
/** The minimum starting year/base year of the original TTD */
 
static const Year ORIGINAL_BASE_YEAR = 1920;
 
/** The original ending year */
 
static const Year ORIGINAL_END_YEAR  = 2051;
 
@@ -102,13 +109,16 @@ static const Year MAX_YEAR  = 5000000;
 
 * @see ConvertDateToYMD(), ConvertYMDToDate()
 
 */
 
struct YearMonthDay {
 
	Year  year;   ///< Year (0...)
 
	Month month;  ///< Month (0..11)
 
	Day   day;    ///< Day (1..31)
 
};
 

	
 
static const Year  INVALID_YEAR  = -1; ///< Representation of an invalid year
 
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
 
@@ -4,15 +4,15 @@
 
 * 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 depot_type.h Header files for depots (not hangars) */
 

	
 
#ifndef DEPOT_TYPE_H
 
#define DEPOT_TYPE_H
 

	
 
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
 
@@ -353,24 +353,25 @@ static bool DisasterTick_Ufo(DisasterVeh
 
			}
 
		}
 

	
 
		return true;
 
	} else {
 
		/* Target a vehicle */
 
		RoadVehicle *u = RoadVehicle::Get(v->dest_tile);
 
		assert(u != nullptr && u->type == VEH_ROAD && u->IsFrontEngine());
 

	
 
		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;
 
		}
 

	
 
		v->direction = GetDirectionTowards(v, u->x_pos, u->y_pos);
 
		GetNewVehiclePosResult gp = GetNewVehiclePos(v);
 

	
 
		int z = v->z_pos;
 
		if (dist <= TILE_SIZE && z > u->z_pos) z--;
 
		v->UpdatePosition(gp.x, gp.y, z);
 

	
 
		if (z <= u->z_pos && (u->vehstatus & VS_HIDDEN) == 0) {
 
@@ -538,24 +539,25 @@ static bool DisasterTick_Big_Ufo(Disaste
 
		if (z < v->z_pos) {
 
			v->UpdatePosition(v->x_pos, v->y_pos, v->z_pos - 1);
 
			return true;
 
		}
 

	
 
		v->current_order.SetDestination(2);
 

	
 
		for (Vehicle *target : Vehicle::Iterate()) {
 
			if (target->IsGroundVehicle()) {
 
				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;
 
				}
 
			}
 
		}
 

	
 
		Town *t = ClosestTownFromTile(v->dest_tile, UINT_MAX);
 
		SetDParam(0, t->index);
 
		AddTileNewsItem(STR_NEWS_DISASTER_BIG_UFO, NT_ACCIDENT, v->tile);
 

	
 
		if (!Vehicle::CanAllocateItem(2)) {
 
			delete v;
 
			return false;
 
		}
src/economy.cpp
Show inline comments
 
@@ -738,25 +738,50 @@ bool AddInflation(bool check_year)
 
}
 

	
 
/**
 
 * Computes all prices, payments and maximum loan.
 
 */
 
void RecomputePrices()
 
{
 
	/* Setup maximum loan */
 
	_economy.max_loan = ((uint64)_settings_game.difficulty.max_loan * _economy.inflation_prices >> 16) / 50000 * 50000;
 

	
 
	/* 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;
 
		switch (_price_base_specs[i].category) {
 
			case PCAT_RUNNING:
 
				mod = _settings_game.difficulty.vehicle_costs;
 
				break;
 

	
 
			case PCAT_CONSTRUCTION:
 
				mod = _settings_game.difficulty.construction_cost;
 
				break;
 

	
src/economy_type.h
Show inline comments
 
@@ -146,37 +146,47 @@ enum Price {
 
	PR_INFRASTRUCTURE_AIRPORT,
 

	
 
	PR_END,
 
	INVALID_PRICE = 0xFF
 
};
 
DECLARE_POSTFIX_INCREMENT(Price)
 

	
 
typedef Money Prices[PR_END]; ///< Prices of everything. @see Price
 
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.
 
	EXPENSES_AIRCRAFT_RUN,        ///< Running costs aircraft.
 
	EXPENSES_SHIP_RUN,            ///< Running costs ships.
 
	EXPENSES_PROPERTY,            ///< Property costs.
 
	EXPENSES_TRAIN_INC,           ///< Income from trains.
 
	EXPENSES_ROADVEH_INC,         ///< Income from road vehicles.
 
	EXPENSES_AIRCRAFT_INC,        ///< Income from aircraft.
 
	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.
 
};
 

	
 
/** Define basic enum properties for ExpensesType */
 
template <> struct EnumPropsT<ExpensesType> : MakeEnumPropsT<ExpensesType, byte, EXPENSES_CONSTRUCTION, EXPENSES_END, INVALID_EXPENSES, 8> {};
 

	
 
/**
 
 * Categories of a price bases.
 
 */
 
enum PriceCategory {
 
	PCAT_NONE,         ///< Not affected by difficulty settings
src/engine.cpp
Show inline comments
 
@@ -267,40 +267,44 @@ uint Engine::DetermineCapacity(const Veh
 
 * Return how much the running costs of this engine are.
 
 * @return Yearly running cost of the engine.
 
 */
 
Money Engine::GetRunningCost() const
 
{
 
	Price base_price;
 
	uint cost_factor;
 
	switch (this->type) {
 
		case VEH_ROAD:
 
			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();
 
	}
 

	
 
	return GetPrice(base_price, cost_factor, this->GetGRF(), -8);
 
}
 

	
 
/**
 
 * Return how much a new engine costs.
 
 * @return Cost of the engine.
 
 */
 
@@ -434,25 +438,25 @@ Date Engine::GetLifeLengthInDays() const
 
	/* Assume leap years; this gives the player a bit more than the given amount of years, but never less. */
 
	return (this->info.lifelength + _settings_game.vehicle.extend_vehicle_life) * DAYS_IN_LEAP_YEAR;
 
}
 

	
 
/**
 
 * Get the range of an aircraft type.
 
 * @return Range of the aircraft type in tiles or 0 if unlimited range.
 
 */
 
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();
 
	}
 
}
 

	
 
/**
 
 * Get the name of the aircraft type for display purposes.
 
 * @return Aircraft type string.
 
 */
 
StringID Engine::GetAircraftTypeText() const
 
{
 
	switch (this->type) {
src/engine_type.h
Show inline comments
 
@@ -161,17 +161,17 @@ enum EngineMiscFlags {
 
	EF_NO_BREAKDOWN_SMOKE          = 6, ///< Do not show black smoke during a breakdown.
 
	EF_SPRITE_STACK                = 7, ///< Draw vehicle by stacking multiple sprites.
 
};
 

	
 
/**
 
 * Engine.flags is a bitmask, with the following values.
 
 */
 
enum EngineFlags {
 
	ENGINE_AVAILABLE         = 1, ///< This vehicle is available to everyone.
 
	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.
 

	
 
#endif /* ENGINE_TYPE_H */
src/fios.h
Show inline comments
 
@@ -14,46 +14,55 @@
 
#include "company_base.h"
 
#include "newgrf_config.h"
 
#include "network/core/tcp_content_type.h"
 

	
 

	
 
/** Special values for save-load window for the data parameter of #InvalidateWindowData. */
 
enum SaveLoadInvalidateWindowData {
 
	SLIWD_RESCAN_FILES,          ///< Rescan all files (when changed directory, ...)
 
	SLIWD_SELECTION_CHANGES,     ///< File selection has changed (user click, ...)
 
	SLIWD_FILTER_CHANGES,        ///< The filename filter has changed (via the editbox)
 
};
 

	
 
enum PatchpackSaveExtensionType {
 
	PSXT_NONE,
 
	PSXT_MODIFIED,
 
	PSXT_EXTENDED
 
};
 

	
 
typedef SmallMap<uint, CompanyProperties *> CompanyPropertiesMap;
 

	
 
/**
 
 * Container for loading in mode SL_LOAD_CHECK.
 
 */
 
struct LoadCheckData {
 
	bool checkable;     ///< True if the savegame could be checked by SL_LOAD_CHECK. (Old savegames are not checkable.)
 
	StringID error;     ///< Error message from loading. INVALID_STRING_ID if no error.
 
	char *error_data;   ///< Data to pass to SetDParamStr when displaying #error.
 

	
 
	uint32 map_size_x, map_size_y;
 
	Date current_date;
 

	
 
	GameSettings settings;
 

	
 
	CompanyPropertiesMap companies;               ///< Company information.
 

	
 
	GRFConfig *grfconfig;                         ///< NewGrf configuration from save.
 
	GRFListCompatibility grf_compatibility;       ///< Summary state of NewGrfs, whether missing files or only compatible found.
 

	
 
	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)
 
	{
 
		this->Clear();
 
	}
 

	
 
	/**
 
	 * Don't leak memory at program exit
 
	 */
 
	~LoadCheckData()
 
	{
src/fios_gui.cpp
Show inline comments
 
@@ -45,24 +45,27 @@ static bool _savegame_sort_dirty;
 
/**
 
 * Reset read data.
 
 */
 
void LoadCheckData::Clear()
 
{
 
	this->checkable = false;
 
	this->error = INVALID_STRING_ID;
 
	free(this->error_data);
 
	this->error_data = nullptr;
 

	
 
	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) {
 
		delete pair.second;
 
	}
 
	companies.clear();
 

	
 
	GamelogFree(this->gamelog_action, this->gamelog_actions);
 
	this->gamelog_action = nullptr;
 
	this->gamelog_actions = 0;
 

	
 
	ClearGRFConfigList(&this->grfconfig);
 
@@ -462,24 +465,37 @@ public:
 

	
 
			case WID_SL_DETAILS: {
 
				GfxFillRect(r.left + WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP,
 
						r.right - WD_FRAMERECT_RIGHT, r.top + FONT_HEIGHT_NORMAL * 2 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM, PC_GREY);
 
				DrawString(r.left, r.right, r.top + FONT_HEIGHT_NORMAL / 2 + WD_FRAMERECT_TOP, STR_SAVELOAD_DETAIL_CAPTION, TC_FROMSTRING, SA_HOR_CENTER);
 

	
 
				if (this->selected == nullptr) break;
 

	
 
				uint y = r.top + FONT_HEIGHT_NORMAL * 2 + WD_PAR_VSEP_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
 
				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);
 
					y += FONT_HEIGHT_NORMAL;
 
				} else if (_load_check_data.error != INVALID_STRING_ID) {
 
					/* Incompatible / broken savegame */
 
					SetDParamStr(0, _load_check_data.error_data);
 
					y = DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT,
 
							y, r.bottom - WD_FRAMERECT_BOTTOM, _load_check_data.error, TC_RED);
 
				} else {
 
					/* Mapsize */
 
					SetDParam(0, _load_check_data.map_size_x);
src/gamelog.cpp
Show inline comments
 
@@ -42,26 +42,26 @@ static LoggedAction *_current_action = n
 
 * The string returned is at most GAMELOG_REVISION_LENGTH bytes long.
 
 */
 
static const char * GetGamelogRevisionString()
 
{
 
	/* Allocate a buffer larger than necessary (git revision hash is 40 bytes) to avoid truncation later */
 
	static char gamelog_revision[48] = { 0 };
 
	static_assert(lengthof(gamelog_revision) > GAMELOG_REVISION_LENGTH);
 

	
 
	if (IsReleasedVersion()) {
 
		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 */
 
		gamelog_revision[GAMELOG_REVISION_LENGTH - 1] = '\0';
 
	}
 
	return gamelog_revision;
 
}
 

	
 
/**
 
 * Stores information about new action, but doesn't allocate it
 
 * Action is allocated only when there is at least one change
 
 * @param at type of action
src/ground_vehicle.cpp
Show inline comments
 
@@ -19,67 +19,86 @@
 
 */
 
template <class T, VehicleType Type>
 
void GroundVehicle<T, Type>::PowerChanged()
 
{
 
	assert(this->First() == this);
 
	const T *v = T::From(this);
 

	
 
	uint32 total_power = 0;
 
	uint32 max_te = 0;
 
	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. */
 
		uint16 track_speed = u->GetMaxTrackSpeed();
 
		if (track_speed > 0) max_track_speed = std::min(max_track_speed, track_speed);
 
	}
 

	
 
	byte air_drag;
 
	byte air_drag_value = v->GetAirDrag();
 

	
 
	/* If air drag is set to zero (default), the resulting air drag coefficient is dependent on max speed. */
 
	if (air_drag_value == 0) {
 
		uint16 max_speed = v->GetDisplayMaxSpeed();
 
		/* Simplification of the method used in TTDPatch. It uses <= 10 to change more steadily from 128 to 196. */
 
		air_drag = (max_speed <= 10) ? 192 : std::max(2048 / max_speed, 1);
 
	} else {
 
		/* According to the specs, a value of 0x01 in the air drag property means "no air drag". */
 
		air_drag = (air_drag_value == 1) ? 0 : air_drag_value;
 
	}
 

	
 
	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;
 

	
 
		this->gcache.cached_power = total_power;
 
		this->gcache.cached_max_te = max_te;
 
		SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
 
		SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
 
	}
 

	
 
	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.
 
 */
 
template <class T, VehicleType Type>
 
void GroundVehicle<T, Type>::CargoChanged()
 
{
 
	assert(this->First() == this);
 
	uint32 weight = 0;
 

	
 
	for (T *u = T::From(this); u != nullptr; u = u->Next()) {
 
		uint32 current_weight = u->GetWeight();
 
@@ -93,39 +112,40 @@ void GroundVehicle<T, Type>::CargoChange
 
	/* Friction in bearings and other mechanical parts is 0.1% of the weight (result in N). */
 
	this->gcache.cached_axle_resistance = 10 * weight;
 

	
 
	/* Now update vehicle power (tractive effort is dependent on weight). */
 
	this->PowerChanged();
 
}
 

	
 
/**
 
 * Calculates the acceleration of the vehicle under its current conditions.
 
 * @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);
 
	/* Speed is used squared later on, so U16 * U16, and then multiplied by other values. */
 
	int64 speed = v->GetCurrentSpeed(); // [km/h-ish]
 

	
 
	/* Weight is stored in tonnes. */
 
	int32 mass = this->gcache.cached_weight;
 

	
 
	/* Power is stored in HP, we need it in watts.
 
	 * Each vehicle can have U16 power, 128 vehicles, HP -> watt
 
	 * 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.
 
	 *     * 8.3E7
 
	 *  - rolling friction: U16 power * 144 for 128 vehicles.
 
	 *     * 1.2E9
 
	 *  - slope resistance: U16 weight * 100 * 10 (steepness) for 128 vehicles.
 
	 *     * 8.4E9
 
	 *  - air drag: 28 * (U8 drag + 3 * U8 drag * 128 vehicles / 20) * U16 speed * U16 speed
 
	 *     * 6.2E14 before dividing by 1000
 
	 * Sum is 6.3E11, more than 4.3E9 of int32, so int64 is needed.
 
	 */
 
@@ -139,53 +159,110 @@ int GroundVehicle<T, Type>::GetAccelerat
 
		resistance = this->gcache.cached_axle_resistance;
 
		resistance += mass * v->GetRollingFriction();
 
	}
 
	/* Air drag; the air drag coefficient is in an arbitrary NewGRF-unit,
 
	 * so we need some magic conversion factor. */
 
	resistance += (area * this->gcache.cached_air_drag * speed * speed) / 1000;
 

	
 
	resistance += this->GetSlopeResistance();
 

	
 
	/* 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;
 
	if (speed > 0) {
 
		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;
 
		}
 
	} else {
 
		/* "Kickoff" acceleration. */
 
		force = (mode == AS_ACCEL && !maglev) ? std::min<int>(max_te, power) : power;
 
		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;
 

	
 
		/* When we accelerate, make sure we always keep doing that, even when
 
		 * the excess force is more than the mass. Otherwise a vehicle going
 
		 * down hill will never slow down enough, and a vehicle that came up
 
		 * 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);
 
	}
 
}
 

	
 
/**
 
 * Check whether the whole vehicle chain is in the depot.
 
 * @return true if and only if the whole chain is in the depot.
 
 */
 
template <class T, VehicleType Type>
 
bool GroundVehicle<T, Type>::IsChainInDepot() const
 
{
src/ground_vehicle.hpp
Show inline comments
 
@@ -80,27 +80,29 @@ struct GroundVehicle : public Specialize
 
	GroundVehicleCache gcache; ///< Cache of often calculated values.
 
	uint16 gv_flags;           ///< @see GroundVehicleFlags.
 

	
 
	typedef GroundVehicle<T, Type> GroundVehicleBase; ///< Our type
 

	
 
	/**
 
	 * The constructor at SpecializedVehicle must be called.
 
	 */
 
	GroundVehicle() : SpecializedVehicle<T, Type>() {}
 

	
 
	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?
 
	 * @return number of victims
 
	 */
 
	uint Crash(bool flooded) override
 
	{
 
		/* Crashed vehicles aren't going up or down */
 
		for (T *v = T::From(this); v != nullptr; v = v->Next()) {
 
			ClrBit(v->gv_flags, GVF_GOINGUP_BIT);
 
			ClrBit(v->gv_flags, GVF_GOINGDOWN_BIT);
 
		}
 
@@ -358,25 +360,40 @@ protected:
 
	 * @param accel     The acceleration we would like to give this vehicle.
 
	 * @param min_speed The minimum speed here, in vehicle specific units.
 
	 * @param max_speed The maximum speed here, in vehicle specific units.
 
	 * @return Distance to drive.
 
	 */
 
	inline uint DoUpdateSpeed(uint accel, int min_speed, int max_speed)
 
	{
 
		uint spd = this->subspeed + accel;
 
		this->subspeed = (byte)spd;
 

	
 
		/* 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);
 
		}
 

	
 
		/* Enforce a maximum and minimum speed. Normally we would use something like
 
		 * Clamp for this, but in this case min_speed might be below the maximum speed
 
		 * threshold for some reason. That makes acceleration fail and assertions
 
		 * happen in Clamp. So make it explicit that min_speed overrules the maximum
 
		 * speed by explicit ordering of min and max. */
 
		this->cur_speed = spd = std::max(std::min(this->cur_speed + ((int)spd >> 8), tempmax), min_speed);
 

	
 
		int scaled_spd = this->GetAdvanceSpeed(spd);
src/group_gui.cpp
Show inline comments
 
@@ -198,25 +198,25 @@ private:
 
	}
 

	
 
	/**
 
	 * Compute tiny_step_height and column_size
 
	 * @return Total width required for the group list.
 
	 */
 
	uint ComputeGroupInfoSize()
 
	{
 
		this->column_size[VGC_FOLD] = maxdim(GetSpriteSize(SPR_CIRCLE_FOLDED), GetSpriteSize(SPR_CIRCLE_UNFOLDED));
 
		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);
 
		this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_PROTECT].height);
 

	
 
		this->column_size[VGC_AUTOREPLACE] = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE);
 
		this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_AUTOREPLACE].height);
 

	
 
		this->column_size[VGC_PROFIT].width = 0;
 
		this->column_size[VGC_PROFIT].height = 0;
 
		static const SpriteID profit_sprites[] = {SPR_PROFIT_NA, SPR_PROFIT_NEGATIVE, SPR_PROFIT_SOME, SPR_PROFIT_LOT};
 
		for (uint i = 0; i < lengthof(profit_sprites); i++) {
 
@@ -1075,32 +1075,32 @@ public:
 
				id_g = find_index(this->groups, g);
 
			}
 
			this->group_sb->ScrollTowards(id_g);
 
		}
 
		this->vehgroups.ForceRebuild();
 
		this->SetDirty();
 
	}
 

	
 
};
 

	
 

	
 
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)
 
);
 

	
 
/**
 
 * Show the group window for the given company and vehicle type.
 
 * @param company The company to show the window for.
 
 * @param vehicle_type The type of vehicle to show it for.
 
 * @param group The group to be selected. Defaults to INVALID_GROUP.
 
 * @param need_existing_window Whether the existing window is needed. Defaults to false.
 
 */
src/group_type.h
Show inline comments
 
@@ -8,17 +8,17 @@
 
/** @file group_type.h Types of a group. */
 

	
 
#ifndef GROUP_TYPE_H
 
#define GROUP_TYPE_H
 

	
 
typedef uint16 GroupID; ///< Type for all group identifiers.
 

	
 
static const GroupID NEW_GROUP     = 0xFFFC; ///< Sentinel for a to-be-created group.
 
static const GroupID ALL_GROUP     = 0xFFFD; ///< All vehicles are in this group.
 
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;
 

	
 
#endif /* GROUP_TYPE_H */
src/industry_cmd.cpp
Show inline comments
 
@@ -511,25 +511,25 @@ static CommandCost ClearTile_Industry(Ti
 
			(_current_company == OWNER_WATER &&
 
				((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) ||
 
				HasBit(GetIndustryTileSpec(GetIndustryGfx(tile))->slopes_refused, 5)))) {
 
		SetDParam(1, indspec->name);
 
		return_cmd_error(flags & DC_AUTO ? STR_ERROR_GENERIC_OBJECT_IN_THE_WAY : INVALID_STRING_ID);
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
 
		Game::NewEvent(new ScriptEventIndustryClose(i->index));
 
		delete i;
 
	}
 
	return CommandCost(EXPENSES_CONSTRUCTION, indspec->GetRemovalCost());
 
	return CommandCost(EXPENSES_T_DEMOLITION, indspec->GetRemovalCost());
 
}
 

	
 
/**
 
 * Move produced cargo from industry to nearby stations.
 
 * @param tile Industry tile
 
 * @return true if any cargo was moved.
 
 */
 
static bool TransportIndustryGoods(TileIndex tile)
 
{
 
	Industry *i = Industry::GetByTile(tile);
 
	const IndustrySpec *indspec = GetIndustrySpec(i->type);
 
	bool moved_cargo = false;
 
@@ -2045,25 +2045,25 @@ CommandCost CmdBuildIndustry(DoCommandFl
 
			ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, _current_company, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, &ind);
 
			if (ret.Succeeded()) break;
 
		}
 

	
 
		/* If it still failed, there's no suitable layout to build here, return the error */
 
		if (ret.Failed()) return ret;
 
	}
 

	
 
	if ((flags & DC_EXEC) && ind != nullptr && _game_mode != GM_EDITOR) {
 
		AdvertiseIndustryOpening(ind);
 
	}
 

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

	
 
/**
 
 * Change industry properties
 
 * @param flags Type of operation.
 
 * @param ind_id IndustryID
 
 * @param action IndustryAction to perform
 
 * @param ctlflags IndustryControlFlags (only used with set control flags)
 
 * @param company_id CompanyID to set or INVALID_OWNER (available to everyone) or
 
 *                   OWNER_NONE (neutral stations only) or OWNER_DEITY (no one)
 
 *                   (only used with set exclusive supplier / consumer)
 
 * @param text - Additional industry text (only used with set text action)
src/landscape.cpp
Show inline comments
 
@@ -681,25 +681,25 @@ void ClearSnowLine()
 
	free(_snow_line);
 
	_snow_line = nullptr;
 
}
 

	
 
/**
 
 * Clear a piece of landscape
 
 * @param flags of operation to conduct
 
 * @param tile tile to clear
 
 * @return the cost of this operation or an error
 
 */
 
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)) {
 
		if ((flags & DC_AUTO) && GetWaterClass(tile) == WATER_CLASS_CANAL) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
 
		do_clear = true;
 
		cost.AddCost(GetWaterClass(tile) == WATER_CLASS_CANAL ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER]);
 
	}
 

	
 
	Company *c = (flags & (DC_AUTO | DC_BANKRUPT)) ? nullptr : Company::GetIfValid(_current_company);
 
	if (c != nullptr && (int)GB(c->clear_limit, 16, 16) < 1) {
 
		return_cmd_error(STR_ERROR_CLEARING_LIMIT_REACHED);
 
	}
 
@@ -732,25 +732,25 @@ CommandCost CmdLandscapeClear(DoCommandF
 
 * Clear a big piece of landscape
 
 * @param flags of operation to conduct
 
 * @param tile end tile of area dragging
 
 * @param start_tile start tile of area dragging
 
 * @param diagonal Whether to use the Orthogonal (false) or Diagonal (true) iterator.
 
 * @return the cost of this operation or an error
 
 */
 
std::tuple<CommandCost, Money> CmdClearArea(DoCommandFlag flags, TileIndex tile, TileIndex start_tile, bool diagonal)
 
{
 
	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;
 

	
 
	const Company *c = (flags & (DC_AUTO | DC_BANKRUPT)) ? nullptr : Company::GetIfValid(_current_company);
 
	int limit = (c == nullptr ? INT32_MAX : GB(c->clear_limit, 16, 16));
 

	
 
	TileIterator *iter = diagonal ? (TileIterator *)new DiagonalTileIterator(tile, start_tile) : new OrthogonalTileIterator(tile, start_tile);
 
	for (; *iter != INVALID_TILE; ++(*iter)) {
 
		TileIndex t = *iter;
 
		CommandCost ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags & ~DC_EXEC, t);
 
		if (ret.Failed()) {
 
			last_error = ret;
src/lang/english.txt
Show inline comments
 
@@ -295,24 +295,25 @@ STR_SORT_BY_RELIABILITY                 
 
STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE                        :Total capacity per cargo type
 
STR_SORT_BY_MAX_SPEED                                           :Maximum speed
 
STR_SORT_BY_MODEL                                               :Model
 
STR_SORT_BY_VALUE                                               :Value
 
STR_SORT_BY_LENGTH                                              :Length
 
STR_SORT_BY_LIFE_TIME                                           :Remaining lifetime
 
STR_SORT_BY_TIMETABLE_DELAY                                     :Timetable delay
 
STR_SORT_BY_FACILITY                                            :Station type
 
STR_SORT_BY_WAITING_TOTAL                                       :Total waiting cargo
 
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
 
STR_SORT_BY_TRACTIVE_EFFORT                                     :Tractive effort
 
STR_SORT_BY_INTRO_DATE                                          :Introduction date
 
STR_SORT_BY_RUNNING_COST                                        :Running cost
 
STR_SORT_BY_POWER_VS_RUNNING_COST                               :Power/Running cost
 
STR_SORT_BY_CARGO_CAPACITY                                      :Cargo capacity
 
STR_SORT_BY_RANGE                                               :Range
 
STR_SORT_BY_POPULATION                                          :Population
 
STR_SORT_BY_RATING                                              :Rating
 
STR_SORT_BY_NUM_VEHICLES                                        :Number of vehicles
 
@@ -1224,24 +1225,27 @@ STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_
 
STR_CONFIG_SETTING_INTEREST_RATE                                :Interest rate: {STRING2}
 
STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT                       :Loan interest rate; also controls inflation, if enabled
 

	
 
STR_CONFIG_SETTING_RUNNING_COSTS                                :Running costs: {STRING2}
 
STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT                       :Set level of maintenance and running costs of vehicles and infrastructure
 

	
 
STR_CONFIG_SETTING_CONSTRUCTION_SPEED                           :Construction speed: {STRING2}
 
STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT                  :Limit the amount of construction actions for AIs
 

	
 
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
 

	
 
STR_CONFIG_SETTING_SUBSIDY_DURATION                             :Subsidy duration: {STRING2}
 
STR_CONFIG_SETTING_SUBSIDY_DURATION_HELPTEXT                    :Set the number of years for which a subsidy is awarded
 

	
 
STR_CONFIG_SETTING_SUBSIDY_DURATION_VALUE                       :{NUM} year{P "" s}
 
###setting-zero-is-special
 
STR_CONFIG_SETTING_SUBSIDY_DURATION_DISABLED                    :No subsidies
 

	
 
STR_CONFIG_SETTING_CONSTRUCTION_COSTS                           :Construction costs: {STRING2}
 
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT                  :Set level of construction and purchase costs
 
@@ -1350,24 +1354,27 @@ STR_CONFIG_SETTING_STOP_LOCATION_FAR_END
 

	
 
STR_CONFIG_SETTING_AUTOSCROLL                                   :Pan window when mouse is at the edge: {STRING2}
 
STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT                          :When enabled, viewports will start to scroll when the mouse is near the edge of the window
 
###length 4
 
STR_CONFIG_SETTING_AUTOSCROLL_DISABLED                          :Disabled
 
STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT_FULLSCREEN          :Main viewport, full-screen only
 
STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT                     :Main viewport
 
STR_CONFIG_SETTING_AUTOSCROLL_EVERY_VIEWPORT                    :Every viewport
 

	
 
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
 

	
 
STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS                         :Allow funding buildings: {STRING2}
 
STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT                :Allow companies to give money to towns for funding new houses
 

	
 
STR_CONFIG_SETTING_ALLOW_FUND_ROAD                              :Allow funding local road reconstruction: {STRING2}
 
STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT                     :Allow companies to give money to towns for road re-construction to sabotage road-based services in the town
 

	
 
STR_CONFIG_SETTING_ALLOW_GIVE_MONEY                             :Allow sending money to other companies: {STRING2}
 
STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT                    :Allow transfer of money between companies in multiplayer mode
 

	
 
@@ -1432,24 +1439,27 @@ STR_CONFIG_SETTING_ERRMSG_DURATION      
 
STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT                     :Duration for displaying error messages in a red window. Note that some (critical) error messages are not closed automatically after this time, but must be closed manually
 
STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE                        :{COMMA} second{P 0 "" s}
 

	
 
STR_CONFIG_SETTING_HOVER_DELAY                                  :Show tooltips: {STRING2}
 
STR_CONFIG_SETTING_HOVER_DELAY_HELPTEXT                         :Delay before tooltips are displayed when hovering the mouse over some interface element. Alternatively tooltips are bound to the right mouse button when this value is set to 0.
 
STR_CONFIG_SETTING_HOVER_DELAY_VALUE                            :Hover for {COMMA} millisecond{P 0 "" s}
 
###setting-zero-is-special
 
STR_CONFIG_SETTING_HOVER_DELAY_DISABLED                         :Right click
 

	
 
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
 

	
 
STR_CONFIG_SETTING_SHOW_NEWGRF_NAME                             :Show the NewGRF's name in the build vehicle window: {STRING2}
 
STR_CONFIG_SETTING_SHOW_NEWGRF_NAME_HELPTEXT                    :Add a line to the build vehicle window, showing which NewGRF the selected vehicle comes from.
 

	
 
STR_CONFIG_SETTING_LANDSCAPE                                    :Landscape: {STRING2}
 
STR_CONFIG_SETTING_LANDSCAPE_HELPTEXT                           :Landscapes define basic gameplay scenarios with different cargoes and town growth requirements. NewGRF and Game Scripts allow finer control though
 

	
 
STR_CONFIG_SETTING_LAND_GENERATOR                               :Land generator: {STRING2}
 
STR_CONFIG_SETTING_LAND_GENERATOR_HELPTEXT                      :The original generator depends on the base graphics set, and composes fixed landscape shapes. TerraGenesis is a Perlin noise based generator with finer control settings
 
###length 2
 
@@ -1853,24 +1863,81 @@ STR_CONFIG_SETTING_NOISE_LEVEL_HELPTEXT 
 
STR_CONFIG_SETTING_TOWN_FOUNDING                                :Founding towns in game: {STRING2}
 
STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT                       :Enabling this setting allows players to found new towns in the game
 
###length 3
 
STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN                      :Forbidden
 
STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED                        :Allowed
 
STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT          :Allowed, custom town layout
 

	
 
STR_CONFIG_SETTING_TOWN_CARGOGENMODE                            :Town cargo generation: {STRING2}
 
STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT                   :How much cargo is produced by houses in towns, relative to the overall population of the town.{}Quadratic growth: A town twice the size generates four times as many passengers.{}Linear growth: A town twice the size generates twice the amount of passengers.
 
###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
 
###length 4
 
STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_SPREAD               :Grow but don't spread {RED}(breaks lumber mill)
 
STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_RAINFOREST       :Grow but only spread in rain forests
 
STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_ALL              :Grow and spread everywhere
 
STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_GROWTH_NO_SPREAD     :Don't grow, don't spread {RED}(breaks lumber mill)
 

	
 
STR_CONFIG_SETTING_TOOLBAR_POS                                  :Position of main toolbar: {STRING2}
 
STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT                         :Horizontal position of the main toolbar at the top of the screen
 
STR_CONFIG_SETTING_STATUSBAR_POS                                :Position of status bar: {STRING2}
 
@@ -2009,24 +2076,27 @@ STR_CONFIG_SETTING_VEHICLES_PHYSICS     
 
STR_CONFIG_SETTING_VEHICLES_ROUTING                             :{ORANGE}Routing
 
STR_CONFIG_SETTING_LIMITATIONS                                  :{ORANGE}Limitations
 
STR_CONFIG_SETTING_ACCIDENTS                                    :{ORANGE}Disasters / Accidents
 
STR_CONFIG_SETTING_GENWORLD                                     :{ORANGE}World generation
 
STR_CONFIG_SETTING_ENVIRONMENT                                  :{ORANGE}Environment
 
STR_CONFIG_SETTING_ENVIRONMENT_AUTHORITIES                      :{ORANGE}Authorities
 
STR_CONFIG_SETTING_ENVIRONMENT_TOWNS                            :{ORANGE}Towns
 
STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES                       :{ORANGE}Industries
 
STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST                        :{ORANGE}Cargo distribution
 
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
 
STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES                 :Pathfinder for road vehicles: {STRING2}
 
STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES_HELPTEXT        :Path finder to use for road vehicles
 
STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS                         :Pathfinder for ships: {STRING2}
 
STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS_HELPTEXT                :Path finder to use for ships
 
STR_CONFIG_SETTING_REVERSE_AT_SIGNALS                           :Automatic reversing at signals: {STRING2}
 
STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT                  :Allow trains to reverse on a signal, if they waited there a long time
 
###length 2
 
STR_CONFIG_SETTING_PATHFINDER_NPF                               :NPF
 
STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED                  :YAPF {BLUE}(Recommended)
 
@@ -2049,25 +2119,25 @@ STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRE
 
STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM         :{WHITE}... savegame format '{RAW_STRING}' is not available. Reverting to '{RAW_STRING}'
 
STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND                :{WHITE}... ignoring Base Graphics set '{RAW_STRING}': not found
 
STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND                  :{WHITE}... ignoring Base Sounds set '{RAW_STRING}': not found
 
STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND                   :{WHITE}... ignoring Base Music set '{RAW_STRING}': not found
 
STR_CONFIG_ERROR_OUT_OF_MEMORY                                  :{WHITE}Out of memory
 
STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG                            :{WHITE}Allocating {BYTES} of spritecache failed. The spritecache was reduced to {BYTES}. This will reduce the performance of OpenTTD. To reduce memory requirements you can try to disable 32bpp graphics and/or zoom-in levels
 

	
 
# Video initalization errors
 
STR_VIDEO_DRIVER_ERROR                                          :{WHITE}Error with video settings...
 
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
 
STR_INTRO_PLAY_SCENARIO                                         :{BLACK}Play Scenario
 
STR_INTRO_PLAY_HEIGHTMAP                                        :{BLACK}Play Heightmap
 
STR_INTRO_SCENARIO_EDITOR                                       :{BLACK}Scenario Editor
 
STR_INTRO_MULTIPLAYER                                           :{BLACK}Multiplayer
 

	
 
STR_INTRO_GAME_OPTIONS                                          :{BLACK}Game Options
 
STR_INTRO_HIGHSCORE                                             :{BLACK}Highscore Table
 
STR_INTRO_CONFIG_SETTINGS_TREE                                  :{BLACK}Settings
 
STR_INTRO_NEWGRF_SETTINGS                                       :{BLACK}NewGRF Settings
 
@@ -3024,25 +3094,25 @@ STR_LAI_BRIDGE_DESCRIPTION_ROAD_CONCRETE
 
STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL                   :Tubular road bridge
 

	
 
STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT                             :Aqueduct
 

	
 
STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER                          :Transmitter
 
STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE                           :Lighthouse
 
STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS                 :Company headquarters
 
STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND                   :Company-owned land
 

	
 
# 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
 
STR_FRAMERATE_CAPTION                                           :{WHITE}Frame rate
 
STR_FRAMERATE_CAPTION_SMALL                                     :{STRING2}{WHITE} ({DECIMAL}x)
 
STR_FRAMERATE_RATE_GAMELOOP                                     :{BLACK}Simulation rate: {STRING2}
 
STR_FRAMERATE_RATE_GAMELOOP_TOOLTIP                             :{BLACK}Number of game ticks simulated per second.
 
STR_FRAMERATE_RATE_BLITTER                                      :{BLACK}Graphics frame rate: {STRING2}
 
STR_FRAMERATE_RATE_BLITTER_TOOLTIP                              :{BLACK}Number of video frames rendered per second.
 
STR_FRAMERATE_SPEED_FACTOR                                      :{BLACK}Current game speed factor: {DECIMAL}x
 
STR_FRAMERATE_SPEED_FACTOR_TOOLTIP                              :{BLACK}How fast the game is currently running, compared to the expected speed at normal simulation rate.
 
STR_FRAMERATE_CURRENT                                           :{WHITE}Current
 
@@ -3115,24 +3185,27 @@ STR_SAVELOAD_LOAD_HEIGHTMAP_TOOLTIP     
 
STR_SAVELOAD_DETAIL_CAPTION                                     :{BLACK}Game Details
 
STR_SAVELOAD_DETAIL_NOT_AVAILABLE                               :{BLACK}No information available
 
STR_SAVELOAD_DETAIL_COMPANY_INDEX                               :{SILVER}{COMMA}: {WHITE}{STRING1}
 
STR_SAVELOAD_DETAIL_GRFSTATUS                                   :{SILVER}NewGRF: {WHITE}{STRING}
 
STR_SAVELOAD_FILTER_TITLE                                       :{BLACK}Filter string:
 
STR_SAVELOAD_OVERWRITE_TITLE                                    :{WHITE}Overwrite File
 
STR_SAVELOAD_OVERWRITE_WARNING                                  :{YELLOW}Are you sure you want to overwrite the existing file?
 
STR_SAVELOAD_DIRECTORY                                          :{RAW_STRING} (Directory)
 
STR_SAVELOAD_PARENT_DIRECTORY                                   :{RAW_STRING} (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:
 
STR_MAPGEN_MAPSIZE_TOOLTIP                                      :{BLACK}Select the size of the map in tiles. The number of available tiles will be slightly smaller
 
STR_MAPGEN_BY                                                   :{BLACK}*
 
STR_MAPGEN_NUMBER_OF_TOWNS                                      :{BLACK}No. of towns:
 
STR_MAPGEN_DATE                                                 :{BLACK}Date:
 
STR_MAPGEN_NUMBER_OF_INDUSTRIES                                 :{BLACK}No. of industries:
 
STR_MAPGEN_HEIGHTMAP_HEIGHT                                     :{BLACK}Highest peak:
 
STR_MAPGEN_HEIGHTMAP_HEIGHT_UP                                  :{BLACK}Increase the maximum height of highest peak on the map by one
 
STR_MAPGEN_HEIGHTMAP_HEIGHT_DOWN                                :{BLACK}Decrease the maximum height of highest peak on the map by one
 
STR_MAPGEN_SNOW_COVERAGE                                        :{BLACK}Snow coverage:
 
@@ -3520,47 +3593,50 @@ STR_STORY_BOOK_GENERIC_PAGE_ITEM        
 
STR_STORY_BOOK_SEL_PAGE_TOOLTIP                                 :{BLACK}Jump to a specific page by selecting it in this drop down list.
 
STR_STORY_BOOK_PREV_PAGE                                        :{BLACK}Previous
 
STR_STORY_BOOK_PREV_PAGE_TOOLTIP                                :{BLACK}Go to previous page
 
STR_STORY_BOOK_NEXT_PAGE                                        :{BLACK}Next
 
STR_STORY_BOOK_NEXT_PAGE_TOOLTIP                                :{BLACK}Go to next page
 
STR_STORY_BOOK_INVALID_GOAL_REF                                 :{RED}Invalid goal reference
 

	
 
# Station list window
 
STR_STATION_LIST_TOOLTIP                                        :{BLACK}Station names - click on name to centre main view on station. Ctrl+Click opens a new viewport on station location
 
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
 
STR_STATION_LIST_SELECT_ALL_TYPES                               :{BLACK}Select all cargo types (including no waiting cargo)
 
STR_STATION_LIST_NO_WAITING_CARGO                               :{BLACK}No cargo of any type is waiting
 

	
 
# Station view window
 
STR_STATION_VIEW_CAPTION                                        :{WHITE}{STATION} {STATION_FEATURES}
 
STR_STATION_VIEW_WAITING_CARGO                                  :{WHITE}{CARGO_LONG}
 
STR_STATION_VIEW_RESERVED                                       :{YELLOW}({CARGO_SHORT} reserved for loading)
 

	
 
STR_STATION_VIEW_ACCEPTS_BUTTON                                 :{BLACK}Accepts
 
STR_STATION_VIEW_ACCEPTS_TOOLTIP                                :{BLACK}Show list of accepted cargo
 
STR_STATION_VIEW_ACCEPTS_CARGO                                  :{BLACK}Accepts: {WHITE}{CARGO_LIST}
 

	
 
STR_STATION_VIEW_EXCLUSIVE_RIGHTS_SELF                          :{BLACK}This station has exclusive transport rights in this town.
 
STR_STATION_VIEW_EXCLUSIVE_RIGHTS_COMPANY                       :{YELLOW}{COMPANY}{BLACK} bought exclusive transport rights in this town.
 

	
 
STR_STATION_VIEW_RATINGS_BUTTON                                 :{BLACK}Ratings
 
STR_STATION_VIEW_RATINGS_TOOLTIP                                :{BLACK}Show station ratings
 
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
 
STR_STATION_VIEW_PLANNED_STATION                                :Station: Planned
 
STR_STATION_VIEW_PLANNED_AMOUNT                                 :Amount: Planned
 
STR_STATION_VIEW_FROM                                           :{YELLOW}{CARGO_SHORT} from {STATION}
 
STR_STATION_VIEW_VIA                                            :{YELLOW}{CARGO_SHORT} via {STATION}
 
STR_STATION_VIEW_TO                                             :{YELLOW}{CARGO_SHORT} to {STATION}
 
STR_STATION_VIEW_FROM_ANY                                       :{RED}{CARGO_SHORT} from unknown station
 
STR_STATION_VIEW_TO_ANY                                         :{RED}{CARGO_SHORT} to any station
 
STR_STATION_VIEW_VIA_ANY                                        :{RED}{CARGO_SHORT} via any station
 
STR_STATION_VIEW_FROM_HERE                                      :{GREEN}{CARGO_SHORT} from this station
 
@@ -3603,38 +3679,48 @@ STR_WAYPOINT_VIEW_CAPTION               
 
STR_WAYPOINT_VIEW_CENTER_TOOLTIP                                :{BLACK}Centre main view on waypoint location. Ctrl+Click opens a new viewport on waypoint location
 
STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME                          :{BLACK}Change waypoint name
 
STR_BUOY_VIEW_CENTER_TOOLTIP                                    :{BLACK}Centre main view on buoy location. Ctrl+Click opens a new viewport on buoy location
 
STR_BUOY_VIEW_CHANGE_BUOY_NAME                                  :{BLACK}Change buoy name
 

	
 
STR_EDIT_WAYPOINT_NAME                                          :{WHITE}Edit waypoint name
 

	
 
# Finances window
 
STR_FINANCES_CAPTION                                            :{WHITE}{COMPANY} Finances {BLACK}{COMPANY_NUM}
 
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
 
STR_FINANCES_SECTION_AIRCRAFT_RUNNING_COSTS                     :{GOLD}Aircraft Running Costs
 
STR_FINANCES_SECTION_SHIP_RUNNING_COSTS                         :{GOLD}Ship Running Costs
 
STR_FINANCES_SECTION_PROPERTY_MAINTENANCE                       :{GOLD}Property Maintenance
 
STR_FINANCES_SECTION_TRAIN_INCOME                               :{GOLD}Train Income
 
STR_FINANCES_SECTION_ROAD_VEHICLE_INCOME                        :{GOLD}Road Vehicle Income
 
STR_FINANCES_SECTION_AIRCRAFT_INCOME                            :{GOLD}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}
 
STR_FINANCES_TOTAL_CAPTION                                      :{WHITE}Total:
 
STR_FINANCES_BANK_BALANCE_TITLE                                 :{WHITE}Bank Balance
 
STR_FINANCES_LOAN_TITLE                                         :{WHITE}Loan
 
STR_FINANCES_MAX_LOAN                                           :{WHITE}Maximum Loan: {BLACK}{CURRENCY_LONG}
 
STR_FINANCES_TOTAL_CURRENCY                                     :{BLACK}{CURRENCY_LONG}
 
STR_FINANCES_BORROW_BUTTON                                      :{BLACK}Borrow {CURRENCY_LONG}
 
STR_FINANCES_BORROW_TOOLTIP                                     :{BLACK}Increase size of loan. Ctrl+Click borrows as much as possible
 
STR_FINANCES_REPAY_BUTTON                                       :{BLACK}Repay {CURRENCY_LONG}
 
STR_FINANCES_REPAY_TOOLTIP                                      :{BLACK}Repay part of loan. Ctrl+Click repays as much loan as possible
 
@@ -4128,29 +4214,38 @@ STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_T
 
###length VEHICLE_TYPES
 
STR_VEHICLE_VIEW_TRAIN_STATUS_START_STOP_TOOLTIP                :{BLACK}Current train action - click to stop/start train
 
STR_VEHICLE_VIEW_ROAD_VEHICLE_STATUS_START_STOP_TOOLTIP         :{BLACK}Current vehicle action - click to stop/start vehicle
 
STR_VEHICLE_VIEW_SHIP_STATE_STATUS_STOP_TOOLTIP                 :{BLACK}Current ship action - click to stop/start ship
 
STR_VEHICLE_VIEW_AIRCRAFT_STATUS_START_STOP_TOOLTIP             :{BLACK}Current aircraft action - click to stop/start aircraft
 

	
 
# Messages in the start stop button in the vehicle view
 
STR_VEHICLE_STATUS_LOADING_UNLOADING                            :{LTBLUE}Loading / Unloading
 
STR_VEHICLE_STATUS_LEAVING                                      :{LTBLUE}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}
 
STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL                        :{ORANGE}Heading for {DEPOT}, {VELOCITY}
 
STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL                :{LTBLUE}Service at {DEPOT}, {VELOCITY}
 

	
 
STR_VEHICLE_STATUS_CANNOT_REACH_STATION_VEL                     :{LTBLUE}Cannot reach {STATION}, {VELOCITY}
 
STR_VEHICLE_STATUS_CANNOT_REACH_WAYPOINT_VEL                    :{LTBLUE}Cannot reach {WAYPOINT}, {VELOCITY}
 
STR_VEHICLE_STATUS_CANNOT_REACH_DEPOT_VEL                       :{ORANGE}Cannot reach {DEPOT}, {VELOCITY}
 
STR_VEHICLE_STATUS_CANNOT_REACH_DEPOT_SERVICE_VEL               :{LTBLUE}Cannot reach {DEPOT}, {VELOCITY}
 

	
 
# Vehicle stopped/started animations
 
@@ -4163,24 +4258,29 @@ STR_VEHICLE_COMMAND_STARTED_SMALL       
 
STR_VEHICLE_COMMAND_STARTED                                     :{GREEN}Started
 

	
 
# Vehicle details
 
STR_VEHICLE_DETAILS_CAPTION                                     :{WHITE}{VEHICLE} (Details)
 

	
 
###length VEHICLE_TYPES
 
STR_VEHICLE_DETAILS_TRAIN_RENAME                                :{BLACK}Name train
 
STR_VEHICLE_DETAILS_ROAD_VEHICLE_RENAME                         :{BLACK}Name road vehicle
 
STR_VEHICLE_DETAILS_SHIP_RENAME                                 :{BLACK}Name ship
 
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})
 

	
 
STR_VEHICLE_INFO_MAX_SPEED                                      :{BLACK}Max. speed: {LTBLUE}{VELOCITY}
 
STR_VEHICLE_INFO_MAX_SPEED_TYPE                                 :{BLACK}Max. speed: {LTBLUE}{VELOCITY} {BLACK}Aircraft type: {LTBLUE}{STRING}
 
STR_VEHICLE_INFO_MAX_SPEED_TYPE_RANGE                           :{BLACK}Max. speed: {LTBLUE}{VELOCITY} {BLACK}Aircraft type: {LTBLUE}{STRING} {BLACK}Range: {LTBLUE}{COMMA} tiles
 
STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED                         :{BLACK}Weight: {LTBLUE}{WEIGHT_SHORT} {BLACK}Power: {LTBLUE}{POWER}{BLACK} Max. speed: {LTBLUE}{VELOCITY}
 
STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE                  :{BLACK}Weight: {LTBLUE}{WEIGHT_SHORT} {BLACK}Power: {LTBLUE}{POWER}{BLACK} Max. speed: {LTBLUE}{VELOCITY} {BLACK}Max. T.E.: {LTBLUE}{FORCE}
 

	
 
STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR                     :{BLACK}Profit this year: {LTBLUE}{CURRENCY_LONG} (last year: {CURRENCY_LONG})
 
STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS                         :{BLACK}Reliability: {LTBLUE}{COMMA}%  {BLACK}Breakdowns since last service: {LTBLUE}{COMMA}
 

	
 
@@ -4201,25 +4301,27 @@ STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP   
 
STR_VEHICLE_DETAILS_DEFAULT                                     :Default
 
STR_VEHICLE_DETAILS_DAYS                                        :Days
 
STR_VEHICLE_DETAILS_PERCENT                                     :Percentage
 

	
 
###length VEHICLE_TYPES
 
STR_QUERY_RENAME_TRAIN_CAPTION                                  :{WHITE}Name train
 
STR_QUERY_RENAME_ROAD_VEHICLE_CAPTION                           :{WHITE}Name road vehicle
 
STR_QUERY_RENAME_SHIP_CAPTION                                   :{WHITE}Name ship
 
STR_QUERY_RENAME_AIRCRAFT_CAPTION                               :{WHITE}Name aircraft
 

	
 
# 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})
 
STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_MULT                   :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) (x{NUM})
 

	
 
STR_VEHICLE_DETAILS_CARGO_EMPTY                                 :{LTBLUE}Empty
 
STR_VEHICLE_DETAILS_CARGO_FROM                                  :{LTBLUE}{CARGO_LONG} from {STATION}
 
STR_VEHICLE_DETAILS_CARGO_FROM_MULT                             :{LTBLUE}{CARGO_LONG} from {STATION} (x{NUM})
 

	
 
STR_VEHICLE_DETAIL_TAB_CARGO                                    :{BLACK}Cargo
 
STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP                         :{BLACK}Show details of cargo carried
 
STR_VEHICLE_DETAIL_TAB_INFORMATION                              :{BLACK}Information
 
@@ -4606,30 +4708,31 @@ STR_FEEDER_COST_TINY                    
 
STR_FEEDER_COST                                                 :{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {RED}Cost: {CURRENCY_LONG}
 
STR_MESSAGE_ESTIMATED_COST                                      :{WHITE}Estimated Cost: {CURRENCY_LONG}
 
STR_MESSAGE_ESTIMATED_INCOME                                    :{WHITE}Estimated Income: {CURRENCY_LONG}
 

	
 
# Saveload messages
 
STR_ERROR_SAVE_STILL_IN_PROGRESS                                :{WHITE}Saving still in progress,{}please wait until it is finished!
 
STR_ERROR_AUTOSAVE_FAILED                                       :{WHITE}Autosave failed
 
STR_ERROR_UNABLE_TO_READ_DRIVE                                  :{BLACK}Unable to read drive
 
STR_ERROR_GAME_SAVE_FAILED                                      :{WHITE}Game Save Failed{}{STRING1}
 
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
 

	
 
# Map generation messages
 
STR_ERROR_COULD_NOT_CREATE_TOWN                                 :{WHITE}Map generation aborted...{}... no suitable town locations
 
STR_ERROR_NO_TOWN_IN_SCENARIO                                   :{WHITE}... there is no town in this scenario
 

	
 
STR_ERROR_PNGMAP                                                :{WHITE}Can't load landscape from PNG...
 
STR_ERROR_PNGMAP_FILE_NOT_FOUND                                 :{WHITE}... file not found
 
STR_ERROR_PNGMAP_IMAGE_TYPE                                     :{WHITE}... could not convert image type. 8 or 24-bit PNG image needed
 
STR_ERROR_PNGMAP_MISC                                           :{WHITE}... something just went wrong (probably corrupted file)
 

	
 
@@ -5458,27 +5561,42 @@ STR_FORMAT_DEPOT_NAME_SHIP_SERIAL       
 

	
 
STR_FORMAT_DEPOT_NAME_AIRCRAFT                                  :{STATION} Hangar
 
# _SERIAL version of AIRACRAFT doesn't exist
 

	
 
STR_UNKNOWN_STATION                                             :unknown station
 
STR_DEFAULT_SIGN_NAME                                           :Sign
 
STR_COMPANY_SOMEONE                                             :someone
 

	
 
STR_SAVEGAME_NAME_DEFAULT                                       :{COMPANY}, {STRING1}
 
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}
 
STR_VIEWPORT_SIGN_SMALL_WHITE                                   :{TINY_FONT}{WHITE}{SIGN}
 

	
 
STR_VIEWPORT_STATION                                            :{STATION} {STATION_FEATURES}
 
STR_VIEWPORT_STATION_TINY                                       :{TINY_FONT}{STATION}
 

	
 
STR_VIEWPORT_WAYPOINT                                           :{WAYPOINT}
 
STR_VIEWPORT_WAYPOINT_TINY                                      :{TINY_FONT}{WAYPOINT}
 

	
 
# Simple strings to get specific types of data
src/lang/english_AU.txt
Show inline comments
 
@@ -3238,25 +3238,25 @@ STR_WAYPOINT_VIEW_CENTER_TOOLTIP        
 
STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME                          :{BLACK}Change waypoint name
 
STR_BUOY_VIEW_CENTER_TOOLTIP                                    :{BLACK}Centre main view on buoy location. Ctrl+Click opens a new viewport on buoy location
 
STR_BUOY_VIEW_CHANGE_BUOY_NAME                                  :{BLACK}Change buoy name
 

	
 
STR_EDIT_WAYPOINT_NAME                                          :{WHITE}Edit waypoint name
 

	
 
# Finances window
 
STR_FINANCES_CAPTION                                            :{WHITE}{COMPANY} Finances {BLACK}{COMPANY_NUM}
 
STR_FINANCES_EXPENDITURE_INCOME_TITLE                           :{WHITE}Expenditure/Income
 
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
 
STR_FINANCES_SECTION_AIRCRAFT_RUNNING_COSTS                     :{GOLD}Aircraft Running Costs
 
STR_FINANCES_SECTION_SHIP_RUNNING_COSTS                         :{GOLD}Ship Running Costs
 
STR_FINANCES_SECTION_PROPERTY_MAINTENANCE                       :{GOLD}Property Maintenance
 
STR_FINANCES_SECTION_TRAIN_INCOME                               :{GOLD}Train Income
 
STR_FINANCES_SECTION_ROAD_VEHICLE_INCOME                        :{GOLD}Road Vehicle Income
 
STR_FINANCES_SECTION_AIRCRAFT_INCOME                            :{GOLD}Aircraft Income
 
STR_FINANCES_SECTION_SHIP_INCOME                                :{GOLD}Ship Income
 
STR_FINANCES_SECTION_LOAN_INTEREST                              :{GOLD}Loan Interest
 
STR_FINANCES_SECTION_OTHER                                      :{GOLD}Other
src/lang/english_US.txt
Show inline comments
 
@@ -3604,25 +3604,25 @@ STR_WAYPOINT_VIEW_CENTER_TOOLTIP        
 
STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME                          :{BLACK}Change waypoint name
 
STR_BUOY_VIEW_CENTER_TOOLTIP                                    :{BLACK}Center main view on buoy location. Ctrl+Click opens a new viewport on buoy location
 
STR_BUOY_VIEW_CHANGE_BUOY_NAME                                  :{BLACK}Change buoy name
 

	
 
STR_EDIT_WAYPOINT_NAME                                          :{WHITE}Edit waypoint name
 

	
 
# Finances window
 
STR_FINANCES_CAPTION                                            :{WHITE}{COMPANY} Finances {BLACK}{COMPANY_NUM}
 
STR_FINANCES_EXPENDITURE_INCOME_TITLE                           :{WHITE}Expenditure/Income
 
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
 
STR_FINANCES_SECTION_AIRCRAFT_RUNNING_COSTS                     :{GOLD}Aircraft Running Costs
 
STR_FINANCES_SECTION_SHIP_RUNNING_COSTS                         :{GOLD}Ship Running Costs
 
STR_FINANCES_SECTION_PROPERTY_MAINTENANCE                       :{GOLD}Property Maintenance
 
STR_FINANCES_SECTION_TRAIN_INCOME                               :{GOLD}Train Income
 
STR_FINANCES_SECTION_ROAD_VEHICLE_INCOME                        :{GOLD}Road Vehicle Income
 
STR_FINANCES_SECTION_AIRCRAFT_INCOME                            :{GOLD}Aircraft Income
 
STR_FINANCES_SECTION_SHIP_INCOME                                :{GOLD}Ship Income
 
STR_FINANCES_SECTION_LOAN_INTEREST                              :{GOLD}Loan Interest
 
STR_FINANCES_SECTION_OTHER                                      :{GOLD}Other
src/misc_gui.cpp
Show inline comments
 
@@ -399,24 +399,33 @@ static const NWidgetPart _nested_about_w
 

	
 
static WindowDesc _about_desc(
 
	WDP_CENTER, nullptr, 0, 0,
 
	WC_GAME_OPTIONS, WC_NONE,
 
	0,
 
	_nested_about_widgets, lengthof(_nested_about_widgets)
 
);
 

	
 
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)",
 
	u8"  Matthijs Kooijman (blathijs) - Pathfinder-guru, Debian port (since 0.3)",
 
	u8"  Ulf Hermann (fonsinchen) - Cargo Distribution (since 1.3)",
 
	u8"  Christoph Elsenhans (frosch) - General coding (since 0.6)",
 
	u8"  Lo\u00efc Guilloux (glx) - General / Windows Expert (since 0.4.5)",
 
	u8"  Charles Pigott (LordAro) - General / Correctness police (since 1.9)",
 
	u8"  Michael Lutz (michi_cc) - Path based signals (since 0.7)",
 
	u8"  Niels Martin Hansen (nielsm) - Music system, general coding (since 1.9)",
 
	u8"  Owen Rudge (orudge) - Forum host, OS/2 port (since 0.1)",
 
	u8"  Peter Nelson (peter1138) - Spiritual descendant from NewGRF gods (since 0.4.5)",
src/network/core/game_info.cpp
Show inline comments
 
@@ -37,25 +37,25 @@ static const uint GITHASH_SUFFIX_LEN = 1
 
NetworkServerGameInfo _network_game_info; ///< Information about our game.
 

	
 
/**
 
 * Get the network version string used by this build.
 
 * The returned string is guaranteed to be at most NETWORK_REVISON_LENGTH bytes including '\0' terminator.
 
 */
 
std::string_view GetNetworkRevisionString()
 
{
 
	static std::string network_revision;
 

	
 
	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 {
 
			/* Not tagged; add the githash suffix while ensuring the string does not become too long. */
 
			assert(_openttd_revision_modified < 3);
 
			std::string githash_suffix = fmt::format("-{}{}", "gum"[_openttd_revision_modified], _openttd_revision_hash);
 
			if (githash_suffix.size() > GITHASH_SUFFIX_LEN) githash_suffix.resize(GITHASH_SUFFIX_LEN);
 

	
 
			/* Where did the hash start in the original string? Overwrite from that position, unless that would create a too long string. */
 
			size_t hash_end = network_revision.find_last_of('-');
 
			if (hash_end == std::string::npos) hash_end = network_revision.size();
 
			if (hash_end + githash_suffix.size() >= NETWORK_REVISION_LENGTH) hash_end = NETWORK_REVISION_LENGTH - githash_suffix.size() - 1;
src/network/network_func.h
Show inline comments
 
@@ -65,24 +65,26 @@ void NetworkHandlePauseChange(PauseMode 
 

	
 
/*** Commands ran by the server ***/
 
void NetworkServerDailyLoop();
 
void NetworkServerMonthlyLoop();
 
void NetworkServerYearlyLoop();
 
void NetworkServerSendConfigUpdate();
 
void NetworkServerUpdateGameInfo();
 
void NetworkServerShowStatusToConsole();
 
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);
 
void NetworkServerSendChat(NetworkAction action, DestType type, int dest, const std::string &msg, ClientID from_id, int64 data = 0, bool from_admin = false);
 
void NetworkServerSendExternalChat(const std::string &source, TextColour colour, const std::string &user, const std::string &msg);
 

	
 
void NetworkServerKickClient(ClientID client_id, const std::string &reason);
 
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, const std::string &reason);
 
uint NetworkServerKickOrBanIP(const std::string &ip, bool ban, const std::string &reason);
 

	
 
void NetworkInitChatMessage();
 
void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const std::string &message);
src/network/network_server.cpp
Show inline comments
 
@@ -25,24 +25,25 @@
 
#include "../company_func.h"
 
#include "../company_gui.h"
 
#include "../company_cmd.h"
 
#include "../roadveh.h"
 
#include "../order_backup.h"
 
#include "../core/pool_func.hpp"
 
#include "../core/random_func.hpp"
 
#include "../company_cmd.h"
 
#include "../rev.h"
 
#include <mutex>
 
#include <condition_variable>
 

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

	
 

	
 
/* This file handles all the server-commands */
 

	
 
DECLARE_POSTFIX_INCREMENT(ClientID)
 
/** The identifier counter for new clients (is never decreased) */
 
static ClientID _network_client_id = CLIENT_ID_FIRST;
 

	
 
/** Make very sure the preconditions given in network_type.h are actually followed */
 
static_assert(MAX_CLIENT_SLOTS > MAX_CLIENTS);
 
/** Yes... */
 
@@ -1557,24 +1558,27 @@ static void NetworkAutoCleanCompanies()
 
			if (_settings_client.network.autoclean_unprotected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_unprotected && _network_company_states[c->index].password.empty()) {
 
				/* Shut the company down */
 
				Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, c->index, CRR_AUTOCLEAN, INVALID_CLIENT_ID);
 
				IConsolePrint(CC_INFO, "Auto-cleaned company #{} with no password.", c->index + 1);
 
			}
 
			/* Is the company empty for autoclean_protected-months, and there is a protection? */
 
			if (_settings_client.network.autoclean_protected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_protected && !_network_company_states[c->index].password.empty()) {
 
				/* Unprotect the company */
 
				_network_company_states[c->index].password.clear();
 
				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) {
 
				/* Shut the company down */
 
				Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, c->index, CRR_AUTOCLEAN, INVALID_CLIENT_ID);
 
				IConsolePrint(CC_INFO, "Auto-cleaned company #{} with no vehicles.", c->index + 1);
 
			}
 
		} else {
 
			/* It is not empty, reset the date */
 
			_network_company_states[c->index].months_empty = 0;
 
		}
 
	}
 
@@ -1650,24 +1654,28 @@ bool NetworkServerChangeClientName(Clien
 
 */
 
void NetworkServerSetCompanyPassword(CompanyID company_id, const std::string &password, bool already_hashed)
 
{
 
	if (!Company::IsValidHumanID(company_id)) return;
 

	
 
	if (already_hashed) {
 
		_network_company_states[company_id].password = password;
 
	} else {
 
		_network_company_states[company_id].password = GenerateCompanyPasswordHash(password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed);
 
	}
 

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

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

	
 
/**
 
 * Handle the command-queue of a socket.
 
 * @param cs The socket to handle the queue for.
 
 */
 
static void NetworkHandleCommandQueue(NetworkClientSocket *cs)
 
{
 
	CommandPacket *cp;
 
	while ((cp = cs->outgoing_queue.Pop()) != nullptr) {
 
		cs->SendCommand(cp);
 
		delete cp;
 
@@ -2067,30 +2075,71 @@ void NetworkPrintClients()
 
 * @param c  The newly created company; can't be nullptr.
 
 * @param ci The client information of the client that made the company; can be nullptr.
 
 */
 
void NetworkServerNewCompany(const Company *c, NetworkClientInfo *ci)
 
{
 
	assert(c != nullptr);
 

	
 
	if (!_network_server) return;
 

	
 
	_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. */
 
		ci->client_playas = c->index;
 
		NetworkUpdateClientInfo(ci->client_id);
 
		Command<CMD_RENAME_PRESIDENT>::SendNet(STR_NULL, c->index, ci->client_name);
 
	}
 

	
 
	/* Announce new company on network. */
 
	NetworkAdminCompanyInfo(c, true);
 

	
 
	if (ci != nullptr) {
 
		/* ci is nullptr when replaying, or for AIs. In neither case there is a client.
 
		   We need to send Admin port update here so that they first know about the new company
 
		   and then learn about a possibly joining client (see FS#6025) */
 
		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
 
@@ -196,25 +196,25 @@ extern CommandCost CheckBuildableTile(Ti
 
static CommandCost ClearTile_Object(TileIndex tile, DoCommandFlag flags);
 

	
 
/**
 
 * Build an object object
 
 * @param flags type of operation
 
 * @param tile tile where the object will be located
 
 * @param type the object type to build
 
 * @param view the view for the object
 
 * @return the cost of this operation or an error
 
 */
 
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);
 
	if (_game_mode == GM_NORMAL && !spec->IsAvailable() && !_generating_world) return CMD_ERROR;
 
	if ((_game_mode == GM_EDITOR || _generating_world) && !spec->WasEverAvailable()) return CMD_ERROR;
 

	
 
	if ((spec->flags & OBJECT_FLAG_ONLY_IN_SCENEDIT) != 0 && ((!_generating_world && _game_mode != GM_EDITOR) || _current_company != OWNER_NONE)) return CMD_ERROR;
 
	if ((spec->flags & OBJECT_FLAG_ONLY_IN_GAME) != 0 && (_generating_world || _game_mode != GM_NORMAL || _current_company > MAX_COMPANIES)) return CMD_ERROR;
 
	if (view >= spec->views) return CMD_ERROR;
 

	
 
	if (!Object::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_OBJECTS);
 
	if (Town::GetNumItems() == 0) return_cmd_error(STR_ERROR_MUST_FOUND_TOWN_FIRST);
 
@@ -469,25 +469,25 @@ ClearedObjectArea *FindClearedObject(Til
 
	return nullptr;
 
}
 

	
 
static CommandCost ClearTile_Object(TileIndex tile, DoCommandFlag flags)
 
{
 
	/* Get to the northern most tile. */
 
	Object *o = Object::GetByTile(tile);
 
	TileArea ta = o->location;
 

	
 
	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. */
 
	if (_current_company == OWNER_TOWN) return CMD_ERROR;
 

	
 
	/* Water can remove everything! */
 
	if (_current_company != OWNER_WATER) {
 
		if ((flags & DC_NO_WATER) && IsTileOnWater(tile)) {
 
			/* There is water under the object, treat it as water tile. */
 
			return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
 
		} else if (!(spec->flags & OBJECT_FLAG_AUTOREMOVE) && (flags & DC_AUTO)) {
 
			/* No automatic removal by overbuilding stuff. */
 
@@ -516,25 +516,25 @@ static CommandCost ClearTile_Object(Tile
 
	}
 

	
 
	switch (type) {
 
		case OBJECT_HQ: {
 
			Company *c = Company::Get(GetTileOwner(tile));
 
			if (flags & DC_EXEC) {
 
				c->location_of_HQ = INVALID_TILE; // reset HQ position
 
				SetWindowDirty(WC_COMPANY, c->index);
 
				CargoPacket::InvalidateAllFrom(ST_HEADQUARTERS, c->index);
 
			}
 

	
 
			/* 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;
 
		}
 

	
 
		case OBJECT_STATUE:
 
			if (flags & DC_EXEC) {
 
				Town *town = o->town;
 
				ClrBit(town->statues, GetTileOwner(tile));
 
				SetWindowDirty(WC_TOWN_AUTHORITY, town->index);
 
			}
 
			break;
 

	
 
		default:
src/openttd.cpp
Show inline comments
 
@@ -245,25 +245,38 @@ static void ShowHelp()
 
static void WriteSavegameInfo(const char *name)
 
{
 
	extern SaveLoadVersion _sl_version;
 
	uint32 last_ottd_rev = 0;
 
	byte ever_modified = 0;
 
	bool removed_newgrfs = false;
 

	
 
	GamelogInfo(_load_check_data.gamelog_action, _load_check_data.gamelog_actions, &last_ottd_rev, &ever_modified, &removed_newgrfs);
 

	
 
	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);
 

	
 
	if (removed_newgrfs) {
 
		p += seprintf(p, lastof(buf), "NewGRFs have been removed\n");
 
	}
 

	
 
	p = strecpy(p, "NewGRFs:\n", lastof(buf));
 
	if (_load_check_data.HasNewGrfs()) {
 
		for (GRFConfig *c = _load_check_data.grfconfig; c != nullptr; c = c->next) {
 
			char md5sum[33];
 
			md5sumToString(md5sum, lastof(md5sum), HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum);
 
@@ -1038,24 +1051,27 @@ void SwitchToMode(SwitchMode new_mode)
 

	
 
			if (!SafeLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.detail_ftype, GM_NORMAL, NO_DIRECTORY)) {
 
				SetDParamStr(0, GetSaveLoadErrorString());
 
				ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
 
			} else {
 
				if (_file_to_saveload.abstract_ftype == FT_SCENARIO) {
 
					/* Reset engine pool to simplify changing engine NewGRFs in scenario editor. */
 
					EngineOverrideManager::ResetToCurrentNewGRFConfig();
 
				}
 
				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;
 
		}
 

	
 
		case SM_RESTART_HEIGHTMAP: // Load a heightmap and start a new game from it with current settings
 
		case SM_START_HEIGHTMAP: // Load a heightmap and start a new game from it
 
			MakeNewGame(true, new_mode == SM_START_HEIGHTMAP);
 
			break;
 

	
 
		case SM_LOAD_HEIGHTMAP: // Load heightmap from scenario editor
 
			SetLocalCompany(OWNER_NONE);
 

	
src/order_type.h
Show inline comments
 
@@ -85,24 +85,25 @@ enum OrderStopLocation {
 
	OSL_PLATFORM_MIDDLE   = 1, ///< Stop at the middle of the platform
 
	OSL_PLATFORM_FAR_END  = 2, ///< Stop at the far end of the platform
 
	OSL_END
 
};
 

	
 
/**
 
 * Reasons that could cause us to go to the depot.
 
 */
 
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.
 
};
 

	
 
/**
 
 * Actions that can be performed when the vehicle enters the depot.
 
 */
 
enum OrderDepotActionFlags {
 
	ODATF_SERVICE_ONLY   = 0,      ///< Only service the vehicle.
 
	ODATFB_HALT          = 1 << 0, ///< Service the vehicle and then halt it.
 
	ODATFB_NEAREST_DEPOT = 1 << 1, ///< Send the vehicle to the nearest depot.
 
};
 
DECLARE_ENUM_AS_BIT_SET(OrderDepotActionFlags)
 

	
src/rail_cmd.cpp
Show inline comments
 
@@ -406,45 +406,45 @@ static CommandCost CheckRailSlope(Slope 
 
		if (!IsSteepSlope(tileh) && ((~_valid_tracks_on_leveled_foundation[tileh] & (rail_bits | existing)) != 0)) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
 
	}
 

	
 
	Foundation f_new = GetRailFoundation(tileh, rail_bits | existing);
 

	
 
	/* check track/slope combination */
 
	if ((f_new == FOUNDATION_INVALID) ||
 
			((f_new != FOUNDATION_NONE) && (!_settings_game.construction.build_on_slopes))) {
 
		return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
 
	}
 

	
 
	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 */
 
static inline bool ValParamTrackOrientation(Track track)
 
{
 
	return IsValidTrack(track);
 
}
 

	
 
/**
 
 * Build a single piece of rail
 
 * @param flags operation to perform
 
 * @param tile tile  to build on
 
 * @param railtype railtype of being built piece (normal, mono, maglev)
 
 * @param track track-orientation
 
 * @param auto_remove_signals false = error on signal in the way, true = auto remove signals when in the way
 
 * @return the cost of this operation or an error
 
 */
 
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;
 

	
 
	Slope tileh = GetTileSlope(tile);
 
	TrackBits trackbit = TrackToTrackBits(track);
 

	
 
	switch (GetTileType(tile)) {
 
		case MP_RAILWAY: {
 
			CommandCost ret = CheckTileOwnership(tile);
 
			if (ret.Failed()) return ret;
 

	
 
			if (!IsPlainRail(tile)) return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile); // just get appropriate error message
 
@@ -609,25 +609,25 @@ CommandCost CmdBuildSingleRail(DoCommand
 
	return cost;
 
}
 

	
 
/**
 
 * Remove a single piece of track
 
 * @param flags operation to perform
 
 * @param tile tile to remove track from
 
 * @param track rail orientation
 
 * @return the cost of this operation or an error
 
 */
 
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;
 
	TrackBits trackbit = TrackToTrackBits(track);
 

	
 
	/* Need to read tile owner now because it may change when the rail is removed
 
	 * Also, in case of floods, _current_company != owner
 
	 * There may be invalid tiletype even in exec run (when removing long track),
 
	 * so do not call GetTileOwner(tile) in any case here */
 
	Owner owner = INVALID_OWNER;
 

	
 
	Train *v = nullptr;
 
@@ -868,25 +868,25 @@ static CommandCost ValidateAutoDrag(Trac
 
 * @param flags operation to perform
 
 * @param tile start tile of drag
 
 * @param end_tile end tile of drag
 
 * @param railtype railroad type normal/maglev (0 = normal, 1 = mono, 2 = maglev), only used for building
 
 * @param track track-orientation
 
 * @param remove remove tracks?
 
 * @param auto_remove_signals false = build up to an obstacle, true = fail if an obstacle is found (used for AIs), only used for building
 
 * @param fail_on_obstacle false = error on signal in the way, true = auto remove signals when in the way, only used for building
 
 * @return the cost of this operation or an error
 
 */
 
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;
 

	
 
	Trackdir trackdir = TrackToTrackdir(track);
 

	
 
	CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
 
	if (ret.Failed()) return ret;
 

	
 
	bool had_success = false;
 
	CommandCost last_error = CMD_ERROR;
 
	for (;;) {
 
@@ -1052,35 +1052,35 @@ CommandCost CmdBuildSingleSignal(DoComma
 
	/* See if this is a valid track combination for signals (no overlap) */
 
	if (TracksOverlap(GetTrackBits(tile))) return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
 

	
 
	/* In case we don't want to change an existing signal, return without error. */
 
	if (skip_existing_signals && HasSignalOnTrack(tile, track)) return CommandCost();
 

	
 
	/* you can not convert a signal if no signal is on track */
 
	if (convert_signal && !HasSignalOnTrack(tile, track)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
 

	
 
	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();
 
			}
 

	
 
		} else {
 
			/* it is free to change orientation/pre-exit-combo signals */
 
			cost = CommandCost();
 
		}
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
@@ -1230,25 +1230,25 @@ static bool AdvanceSignalAutoFill(TileIn
 
 * @param track track-orientation
 
 * @param sigtype default signal type
 
 * @param sigvar signal variant to build
 
 * @param mode true = override signal/semaphore, or pre/exit/combo signal (CTRL-toggle)
 
 * @param remove remove signals?
 
 * @param autofill fill beyond selected stretch?
 
 * @param minimise_gaps false = keep fixed distance, true = minimise gaps between signals
 
 * @param signal_density user defined signals_density
 
 * @return the cost of this operation or an error
 
 */
 
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;
 
	if (!remove && (sigtype > SIGTYPE_LAST || sigvar > SIG_SEMAPHORE)) return CMD_ERROR;
 

	
 
	if (!IsPlainRailTile(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
 
	TileIndex start_tile = tile;
 

	
 
	/* Interpret signal_density as the logical length of said amount of tiles in X/Y direction. */
 
	signal_density *= TILE_AXIAL_DISTANCE;
 

	
 
	Trackdir trackdir = TrackToTrackdir(track);
 
@@ -1483,25 +1483,25 @@ CommandCost CmdRemoveSingleSignal(DoComm
 
			SetSignalStates(tile, 0);
 
			SetHasSignals(tile, false);
 
			SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC); // remove any possible semaphores
 
		}
 

	
 
		AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
 
		YapfNotifyTrackLayoutChange(tile, track);
 
		if (v != nullptr) TryPathReserve(v, false);
 

	
 
		MarkTileDirtyByTile(tile);
 
	}
 

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

	
 
/**
 
 * Remove signals on a stretch of track.
 
 * Stub for the unified signal builder/remover
 
 * @param flags operation to perform
 
 * @param tile start tile of drag
 
 * @param end_tile end tile of drag
 
 * @param track track-orientation
 
 * @param autofill fill beyond selected stretch?
 
 * @return the cost of this operation or an error
 
 * @see CmdSignalTrackHelper
 
@@ -1532,25 +1532,25 @@ static Vehicle *UpdateTrainPowerProc(Veh
 
 * @param diagonal build diagonally or not.
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdConvertRail(DoCommandFlag flags, TileIndex tile, TileIndex area_start, RailType totype, bool diagonal)
 
{
 
	TileIndex area_end = tile;
 

	
 
	if (!ValParamRailtype(totype)) return CMD_ERROR;
 
	if (area_start >= MapSize()) return CMD_ERROR;
 

	
 
	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)
 

	
 
	TileIterator *iter = diagonal ? (TileIterator *)new DiagonalTileIterator(area_start, area_end) : new OrthogonalTileIterator(area_start, area_end);
 
	for (; (tile = *iter) != INVALID_TILE; ++(*iter)) {
 
		TileType tt = GetTileType(tile);
 

	
 
		/* Check if there is any track on tile */
 
		switch (tt) {
 
			case MP_RAILWAY:
 
				break;
 
			case MP_STATION:
 
@@ -1768,30 +1768,30 @@ static CommandCost RemoveTrainDepot(Tile
 
		}
 

	
 
		Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--;
 
		DirtyCompanyInfrastructureWindows(owner);
 

	
 
		delete Depot::GetByTile(tile);
 
		DoClearSquare(tile);
 
		AddSideToSignalBuffer(tile, dir, owner);
 
		YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
 
		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)) {
 
			return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
 
		}
 

	
 
		if (IsPlainRail(tile)) {
 
			return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
 
		} else {
 
			return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
 
		}
 
	}
 
@@ -2988,33 +2988,33 @@ static CommandCost TestAutoslopeOnRailTi
 
	z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
 

	
 
	Corner track_corner;
 
	switch (rail_bits) {
 
		case TRACK_BIT_LEFT:  track_corner = CORNER_W; break;
 
		case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
 
		case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
 
		case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
 

	
 
		/* 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. */
 
	z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
 
	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 */
 
		if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
 
		if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
 
	}
 
	return  cost;
 
}
 

	
 
/**
 
 * Test-procedure for HasVehicleOnPos to check for a ship.
 
 */
 
@@ -3054,28 +3054,28 @@ static CommandCost TerraformTile_Track(T
 
		if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
 

	
 
		/* Everything is valid, which only changes allowed_corner */
 
		for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
 
			if (allowed_corner == corner) continue;
 
			if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
 
		}
 

	
 
		/* Make the ground dirty */
 
		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);
 
}
 

	
 

	
 
extern const TileTypeProcs _tile_type_rail_procs = {
 
	DrawTile_Track,           // draw_tile_proc
 
	GetSlopePixelZ_Track,     // get_slope_z_proc
 
	ClearTile_Track,          // clear_tile_proc
 
	nullptr,                     // add_accepted_cargo_proc
 
	GetTileDesc_Track,        // get_tile_desc_proc
 
	GetTileTrackStatus_Track, // get_tile_track_status_proc
src/rev.cpp.in
Show inline comments
 
@@ -29,48 +29,58 @@ bool IsReleasedVersion()
 
 * - "<commitdate>-g<shorthash><modified>" in "master",
 
 * - "<commitdate>-<branch>-g<shorthash><modified>" in other branches, or
 
 * - "norev000", if the version is unknown.
 
 *
 
 * The major, minor and build are the numbers that describe releases of
 
 * OpenTTD (like 0.5.3). "-RC" is used to flag release candidates.
 
 *
 
 * <modified> shows a "M", if the binary is made from modified source code.
 
 */
 
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.
 
 */
 
const char _openttd_build_date[] = __DATE__ " " __TIME__;
 

	
 
/**
 
 * The git revision hash of this version.
 
 */
 
const char _openttd_revision_hash[] = "${REV_HASH}";
 

	
 
/**
 
 * The year of this version.
 
 */
 
const char _openttd_revision_year[] = "${REV_YEAR}";
 

	
 
/**
 
 * Let us know if current build was modified. This detection
 
 * works even in the case when revision string is overridden by
 
 * --revision argument.
 
 * 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};
 

	
 
/**
 
 * Indicate whether this is a tagged version.
 
 * If this is non-0, then _openttd_revision is the name of the tag,
 
 * and the version is likely a beta, release candidate, or real release.
 
 */
 
const byte _openttd_revision_tagged = ${REV_ISTAG};
 

	
 
/**
 
 * To check compatibility of BaNaNaS content, this version string is used.
src/rev.h
Show inline comments
 
@@ -3,22 +3,23 @@
 
 * 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 rev.h declaration of OTTD revision dependent variables */
 

	
 
#ifndef REV_H
 
#define REV_H
 

	
 
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;
 
extern const byte _openttd_revision_tagged;
 
extern const char _openttd_content_version[];
 
extern const uint32 _openttd_newgrf_version;
 

	
 
bool IsReleasedVersion();
 

	
 
#endif /* REV_H */
src/road_cmd.cpp
Show inline comments
 
@@ -361,25 +361,25 @@ static CommandCost RemoveRoad(TileIndex 
 

	
 
		default:
 
			return CMD_ERROR;
 
	}
 

	
 
	CommandCost ret = CheckAllowRemoveRoad(tile, pieces, GetRoadOwner(tile, rtt), rtt, flags, town_check);
 
	if (ret.Failed()) return ret;
 

	
 
	if (!IsTileType(tile, MP_ROAD)) {
 
		/* 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);
 

	
 
			TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
 
			/* Pay for *every* tile of the bridge or tunnel */
 
			uint len = GetTunnelBridgeLength(other_end, tile) + 2;
 
			cost.AddCost(len * 2 * RoadClearCost(existing_rt));
 
			if (flags & DC_EXEC) {
 
				/* A full diagonal road tile has two road bits. */
 
				UpdateCompanyRoadInfrastructure(existing_rt, GetRoadOwner(tile, rtt), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR));
 

	
 
@@ -480,25 +480,25 @@ static CommandCost RemoveRoad(TileIndex 
 
						MarkTileDirtyByTile(tile);
 
					}
 
				} else {
 
					/* When bits are removed, you *always* end up with something that
 
					 * is not a complete straight road tile. However, trams do not have
 
					 * onewayness, so they cannot remove it either. */
 
					if (rtt == RTT_ROAD) SetDisallowedRoadDirections(tile, DRD_NONE);
 
					SetRoadBits(tile, present, rtt);
 
					MarkTileDirtyByTile(tile);
 
				}
 
			}
 

	
 
			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]);
 

	
 
			return cost;
 
		}
 

	
 
		case ROAD_TILE_CROSSING: {
 
			if (pieces & ComplementRoadBits(GetCrossingRoadBits(tile))) {
 
				return CMD_ERROR;
 
			}
 

	
 
			if (flags & DC_EXEC) {
 
@@ -516,25 +516,25 @@ static CommandCost RemoveRoad(TileIndex 
 
					 * for, so only subtract the difference to the level crossing cost. */
 
					Company *c = Company::GetIfValid(GetTileOwner(tile));
 
					if (c != nullptr) {
 
						c->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR - 1;
 
						DirtyCompanyInfrastructureWindows(c->index);
 
					}
 
				} else {
 
					SetRoadType(tile, rtt, INVALID_ROADTYPE);
 
				}
 
				MarkTileDirtyByTile(tile);
 
				YapfNotifyTrackLayoutChange(tile, railtrack);
 
			}
 
			return CommandCost(EXPENSES_CONSTRUCTION, RoadClearCost(existing_rt) * 2);
 
			return CommandCost(EXPENSES_T_ROAD_CON, RoadClearCost(existing_rt) * 2);
 
		}
 

	
 
		default:
 
		case ROAD_TILE_DEPOT:
 
			return CMD_ERROR;
 
	}
 
}
 

	
 

	
 
/**
 
 * Calculate the costs for roads on slopes
 
 *  Aside modify the RoadBits to fit on the slopes
 
@@ -560,70 +560,70 @@ static CommandCost CheckRoadSlope(Slope 
 
	/* Steep slopes behave the same as slopes with one corner raised. */
 
	if (IsSteepSlope(tileh)) {
 
		tileh = SlopeWithOneCornerRaised(GetHighestSlopeCorner(tileh));
 
	}
 

	
 
	/* Save the merge of all bits of the current type */
 
	RoadBits type_bits = existing | *pieces;
 

	
 
	/* Roads on slopes */
 
	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();
 
	}
 

	
 
	/* Autocomplete uphill roads */
 
	*pieces |= MirrorRoadBits(*pieces);
 
	type_bits = existing | *pieces;
 

	
 
	/* Uphill roads */
 
	if (IsStraightRoad(type_bits) && (other == type_bits || other == ROAD_NONE) &&
 
			(_invalid_tileh_slopes_road[1][tileh] & (other | type_bits)) == ROAD_NONE) {
 

	
 
		/* Slopes with foundation ? */
 
		if (IsSlopeWithOneCornerRaised(tileh)) {
 

	
 
			/* Prevent build on slopes if it isn't allowed */
 
			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();
 
		}
 
	}
 
	return CMD_ERROR;
 
}
 

	
 
/**
 
 * Build a piece of road.
 
 * @param flags operation to perform
 
 * @param tile tile where to build road
 
 * @param pieces road pieces to build (RoadBits)
 
 * @param rt road type
 
 * @param toggle_drd disallowed directions to toggle
 
 * @param town_id the town that is building the road (0 if not applicable)
 
 * @return the cost of this operation or an error
 
 */
 
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;
 

	
 
	/* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero
 
	 * if a non-company is building the road */
 
	if ((Company::IsValidID(company) && town_id != 0) || (company == OWNER_TOWN && !Town::IsValidID(town_id)) || (company == OWNER_DEITY && town_id != 0)) return CMD_ERROR;
 
	if (company != OWNER_TOWN) {
 
		const Town *town = CalcClosestTownFromTile(tile);
 
		town_id = (town != nullptr) ? town->index : INVALID_TOWN;
 

	
 
		if (company == OWNER_DEITY) {
 
@@ -773,25 +773,25 @@ CommandCost CmdBuildRoad(DoCommandFlag f
 
				if (c != nullptr) {
 
					c->infrastructure.rail[GetRailType(tile)] += LEVELCROSSING_TRACKBIT_FACTOR - 1;
 
					DirtyCompanyInfrastructureWindows(c->index);
 
				}
 

	
 
				/* Always add road to the roadtypes (can't draw without it) */
 
				bool reserved = HasBit(GetRailReservationTrackBits(tile), railtrack);
 
				MakeRoadCrossing(tile, company, company, GetTileOwner(tile), roaddir, GetRailType(tile), rtt == RTT_ROAD ? rt : INVALID_ROADTYPE, (rtt == RTT_TRAM) ? rt : INVALID_ROADTYPE, town_id);
 
				SetCrossingReservation(tile, reserved);
 
				UpdateLevelCrossing(tile, false);
 
				MarkTileDirtyByTile(tile);
 
			}
 
			return CommandCost(EXPENSES_CONSTRUCTION, 2 * RoadBuildCost(rt));
 
			return CommandCost(EXPENSES_T_ROAD_CON, 2 * RoadBuildCost(rt));
 
		}
 

	
 
		case MP_STATION: {
 
			if ((GetAnyRoadBits(tile, rtt) & pieces) == pieces) return_cmd_error(STR_ERROR_ALREADY_BUILT);
 
			if (!IsDriveThroughStopTile(tile)) goto do_clear;
 

	
 
			RoadBits curbits = AxisToRoadBits(DiagDirToAxis(GetRoadStopDir(tile)));
 
			if (pieces & ~curbits) goto do_clear;
 
			pieces = curbits; // we need to pay for both roadbits
 

	
 
			if (HasTileRoadType(tile, rtt)) return_cmd_error(STR_ERROR_ALREADY_BUILT);
 
			break;
 
@@ -990,25 +990,25 @@ CommandCost CmdBuildLongRoad(DoCommandFl
 
	if (start_tile > end_tile || (start_tile == end_tile && start_half)) {
 
		dir = ReverseDiagDir(dir);
 
		start_half = !start_half;
 
		end_half = !end_half;
 
		if (drd == DRD_NORTHBOUND || drd == DRD_SOUTHBOUND) drd ^= DRD_BOTH;
 
	}
 

	
 
	/* On the X-axis, we have to swap the initial bits, so they
 
	 * will be interpreted correctly in the GTTS. Furthermore
 
	 * 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;
 
	bool had_tunnel = false;
 
	bool had_success = false;
 

	
 
	/* Start tile is the first tile clicked by the user. */
 
	for (;;) {
 
		RoadBits bits = AxisToRoadBits(axis);
 

	
 
		/* Determine which road parts should be built. */
 
		if (!is_ai && start_tile != end_tile) {
 
@@ -1063,25 +1063,25 @@ CommandCost CmdBuildLongRoad(DoCommandFl
 
 * Remove a long piece of road.
 
 * @param flags operation to perform
 
 * @param start_tile start tile of drag
 
 * @param end_tile end tile of drag
 
 * @param rt road type
 
 * @param axis direction
 
 * @param start_half start tile starts in the 2nd half of tile
 
 * @param end_half end tile starts in the 2nd half of tile (p2 & 2)
 
 * @return the cost of this operation or an error
 
 */
 
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 };
 

	
 
	/* Only drag in X or Y direction dictated by the direction variable */
 
	if (axis == AXIS_X && TileY(start_tile) != TileY(end_tile)) return { CMD_ERROR, 0 }; // x-axis
 
	if (axis == AXIS_Y && TileX(start_tile) != TileX(end_tile)) return { CMD_ERROR, 0 }; // y-axis
 

	
 
	/* Swap start and ending tile, also the half-tile drag vars. */
 
	if (start_tile > end_tile || (start_tile == end_tile && start_half)) {
 
		std::swap(start_tile, end_tile);
 
		std::swap(start_half, end_half);
 
@@ -1195,50 +1195,50 @@ static CommandCost RemoveRoadDepot(TileI
 
		if (c != nullptr) {
 
			/* A road depot has two road bits. */
 
			RoadType rt = GetRoadTypeRoad(tile);
 
			if (rt == INVALID_ROADTYPE) rt = GetRoadTypeTram(tile);
 
			c->infrastructure.road[rt] -= ROAD_DEPOT_TRACKBIT_FACTOR;
 
			DirtyCompanyInfrastructureWindows(c->index);
 
		}
 

	
 
		delete Depot::GetByTile(tile);
 
		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)
 
{
 
	switch (GetRoadTileType(tile)) {
 
		case ROAD_TILE_NORMAL: {
 
			RoadBits b = GetAllRoadBits(tile);
 

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

	
 
					CommandCost tmp_ret = RemoveRoad(tile, flags, GetRoadBits(tile, rtt), rtt, true);
 
					if (tmp_ret.Failed()) return tmp_ret;
 
					ret.AddCost(tmp_ret);
 
				}
 
				return ret;
 
			}
 
			return_cmd_error(STR_ERROR_MUST_REMOVE_ROAD_FIRST);
 
		}
 

	
 
		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);
 

	
 
			/* Must iterate over the roadtypes in a reverse manner because
 
			 * tram tracks must be removed before the road bits. */
 
			for (RoadTramType rtt : { RTT_TRAM, RTT_ROAD }) {
 
				if (!MayHaveRoad(tile) || GetRoadType(tile, rtt) == INVALID_ROADTYPE) continue;
 

	
 
				CommandCost tmp_ret = RemoveRoad(tile, flags, GetCrossingRoadBits(tile), rtt, false);
 
				if (tmp_ret.Failed()) return tmp_ret;
 
				ret.AddCost(tmp_ret);
 
			}
 
@@ -1641,25 +1641,24 @@ static void DrawRoadBits(TileInfo *ti)
 
/** Tile callback function for rendering a road tile to the screen */
 
static void DrawTile_Road(TileInfo *ti)
 
{
 
	switch (GetRoadTileType(ti->tile)) {
 
		case ROAD_TILE_NORMAL:
 
			DrawRoadBits(ti);
 
			break;
 

	
 
		case ROAD_TILE_CROSSING: {
 
			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);
 
			RoadType tram_rt = GetRoadTypeTram(ti->tile);
 
			const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt);
 
			const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt);
 

	
 
			PaletteID pal = PAL_NONE;
 

	
 
			/* Draw base ground */
 
			if (rti->UsesOverlay()) {
 
				SpriteID image = SPR_ROAD_Y + axis;
 
@@ -2217,47 +2216,47 @@ static void ChangeTileOwner_Road(TileInd
 

	
 
				SetTileOwner(tile, new_owner);
 
			}
 
		}
 
	}
 
}
 

	
 
static CommandCost TerraformTile_Road(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
 
{
 
	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: {
 
				RoadBits bits = GetAllRoadBits(tile);
 
				RoadBits bits_copy = bits;
 
				/* Check if the slope-road_bits combination is valid at all, i.e. it is safe to call GetRoadFoundation(). */
 
				if (CheckRoadSlope(tileh_new, &bits_copy, ROAD_NONE, ROAD_NONE).Succeeded()) {
 
					/* CheckRoadSlope() sometimes changes the road_bits, if it does not agree with them. */
 
					if (bits == bits_copy) {
 
						int z_old;
 
						Slope tileh_old = GetTileSlope(tile, &z_old);
 

	
 
						/* Get the slope on top of the foundation */
 
						z_old += ApplyFoundationToSlope(GetRoadFoundation(tileh_old, bits), &tileh_old);
 
						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;
 
			}
 

	
 
			default: NOT_REACHED();
 
		}
 
	}
 

	
 
	return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
 
}
 

	
src/roadveh.h
Show inline comments
 
@@ -175,24 +175,26 @@ protected: // These functions should not
 
	/**
 
	 * Allows to know the weight value that this vehicle will use.
 
	 * @return Weight value from the engine in tonnes.
 
	 */
 
	inline uint16 GetWeight() const
 
	{
 
		uint16 weight = (CargoSpec::Get(this->cargo_type)->weight * this->cargo.StoredCount()) / 16;
 

	
 
		/* Vehicle weight is not added for articulated parts. */
 
		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;
 
	}
 

	
 
	/**
 
	 * Allows to know the tractive effort value that this vehicle will use.
 
	 * @return Tractive effort value from the engine.
 
	 */
 
	inline byte GetTractiveEffort() const
 
	{
 
		/* The tractive effort coefficient is in units of 1/256.  */
src/roadveh_cmd.cpp
Show inline comments
 
@@ -285,24 +285,25 @@ CommandCost CmdBuildRoadVehicle(DoComman
 
		v->spritenum = rvi->image_index;
 
		v->cargo_type = e->GetDefaultCargoType();
 
		v->cargo_cap = rvi->capacity;
 
		v->refit_cap = 0;
 

	
 
		v->last_station_visited = INVALID_STATION;
 
		v->last_loading_station = INVALID_STATION;
 
		v->engine_type = e->index;
 
		v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback
 

	
 
		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);
 

	
 
		v->date_of_last_service = _date;
 
		v->build_year = _cur_year;
 

	
 
		v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 
		v->random_bits = VehicleRandomBits();
 
		v->SetFrontEngine();
 

	
 
		v->roadtype = rt;
 
@@ -366,25 +367,24 @@ bool RoadVehicle::FindClosestDepot(TileI
 
CommandCost CmdTurnRoadVeh(DoCommandFlag flags, VehicleID veh_id)
 
{
 
	RoadVehicle *v = RoadVehicle::GetIfValid(veh_id);
 
	if (v == nullptr) return CMD_ERROR;
 

	
 
	if (!v->IsPrimaryVehicle()) return CMD_ERROR;
 

	
 
	CommandCost ret = CheckOwnership(v->owner);
 
	if (ret.Failed()) return ret;
 

	
 
	if ((v->vehstatus & VS_STOPPED) ||
 
			(v->vehstatus & VS_CRASHED) ||
 
			v->breakdown_ctr != 0 ||
 
			v->overtaking != 0 ||
 
			v->state == RVSB_WORMHOLE ||
 
			v->IsInDepot() ||
 
			v->current_order.IsType(OT_LOADING)) {
 
		return CMD_ERROR;
 
	}
 

	
 
	if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) return CMD_ERROR;
 

	
 
	if (IsTileType(v->tile, MP_TUNNELBRIDGE) && DirToDiagDir(v->direction) == GetTunnelBridgeDirection(v->tile)) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) v->reverse_ctr = 180;
 
@@ -803,24 +803,27 @@ static void RoadVehCheckOvertake(RoadVeh
 
	od.v = v;
 
	od.u = u;
 

	
 
	/* Trams can't overtake other trams */
 
	if (RoadTypeIsTram(v->roadtype)) return;
 

	
 
	/* Don't overtake in stations */
 
	if (IsTileType(v->tile, MP_STATION) || IsTileType(u->tile, MP_STATION)) return;
 

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

	
 
	/* Check if vehicle is in a road stop, depot, tunnel or bridge or not on a straight road */
 
	if (v->state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)(v->state & RVSB_TRACKDIR_MASK))) return;
 

	
 
	/* Can't overtake a vehicle that is moving faster than us. If the vehicle in front is
 
	 * accelerating, take the maximum speed for the comparison, else the current speed.
 
	 * Original acceleration always accelerates, so always use the maximum speed. */
 
	int u_speed = (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL || u->GetAcceleration() > 0) ? u->GetCurrentMaxSpeed() : u->cur_speed;
 
	if (u_speed >= v->GetCurrentMaxSpeed() &&
 
			!(u->vehstatus & VS_STOPPED) &&
 
@@ -1564,26 +1567,25 @@ again:
 
static bool RoadVehController(RoadVehicle *v)
 
{
 
	/* decrease counters */
 
	v->current_order_time++;
 
	if (v->reverse_ctr != 0) v->reverse_ctr--;
 

	
 
	/* handle crashed */
 
	if (v->vehstatus & VS_CRASHED || RoadVehCheckTrainCrash(v)) {
 
		return RoadVehIsCrashed(v);
 
	}
 

	
 
	/* 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;
 
	}
 

	
 
	ProcessOrders(v);
 
	v->HandleLoading();
 

	
 
	if (v->current_order.IsType(OT_LOADING)) return true;
 

	
 
	if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return true;
 

	
 
	v->ShowVisualEffect();
 
@@ -1625,24 +1627,25 @@ static bool RoadVehController(RoadVehicl
 
	 * on next tick to discover whether it is still blocked. */
 
	if (v->progress == 0) v->progress = blocked ? adv_spd - 1 : j;
 

	
 
	return true;
 
}
 

	
 
Money RoadVehicle::GetRunningCost() const
 
{
 
	const Engine *e = this->GetEngine();
 
	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());
 
}
 

	
 
bool RoadVehicle::Tick()
 
{
 
	PerformanceAccumulator framerate(PFE_GL_ROADVEHS);
 

	
 
	this->tick_counter++;
 

	
 
	if (this->IsFrontEngine()) {
src/saveload/CMakeLists.txt
Show inline comments
 
@@ -4,42 +4,45 @@ add_files(
 
    afterload.cpp
 
    ai_sl.cpp
 
    airport_sl.cpp
 
    animated_tile_sl.cpp
 
    autoreplace_sl.cpp
 
    cargomonitor_sl.cpp
 
    cargopacket_sl.cpp
 
    cheat_sl.cpp
 
    company_sl.cpp
 
    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
 
    group_sl.cpp
 
    industry_sl.cpp
 
    labelmaps_sl.cpp
 
    linkgraph_sl.cpp
 
    map_sl.cpp
 
    misc_sl.cpp
 
    newgrf_sl.cpp
 
    newgrf_sl.h
 
    object_sl.cpp
 
    oldloader.cpp
 
    oldloader.h
 
    oldloader_sl.cpp
 
    order_sl.cpp
 
    saveload.cpp
 
    saveload.h
 
    saveload_buffer.h
 
    saveload_filter.h
 
    saveload_internal.h
 
    settings_sl.cpp
 
    signs_sl.cpp
 
    station_sl.cpp
 
    storage_sl.cpp
 
    strings_sl.cpp
 
    story_sl.cpp
 
    subsidy_sl.cpp
 
    town_sl.cpp
 
    vehicle_sl.cpp
 
    waypoint_sl.cpp
src/saveload/afterload.cpp
Show inline comments
 
@@ -50,24 +50,25 @@
 
#include "../rail_gui.h"
 
#include "../core/backup_type.hpp"
 
#include "../smallmap_gui.h"
 
#include "../news_func.h"
 
#include "../order_backup.h"
 
#include "../error.h"
 
#include "../disaster_vehicle.h"
 
#include "../ship.h"
 
#include "../water.h"
 

	
 

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

	
 
#include <signal.h>
 

	
 
#include "../safeguards.h"
 

	
 
extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY);
 

	
 
/**
 
 * Makes a tile canal or water depending on the surroundings.
 
 *
 
 * Must only be used for converting old savegames. Use WaterClass now.
 
 *
 
@@ -741,31 +742,37 @@ bool AfterLoadGame()
 
	if (IsSavegameVersionBefore(SLV_134))  _settings_game.economy.feeder_payment_share = 75;
 
	if (IsSavegameVersionBefore(SLV_138))  _settings_game.vehicle.plane_crashes = 2;
 
	if (IsSavegameVersionBefore(SLV_139)) {
 
		_settings_game.vehicle.roadveh_acceleration_model = 0;
 
		_settings_game.vehicle.roadveh_slope_steepness = 7;
 
	}
 
	if (IsSavegameVersionBefore(SLV_143))  _settings_game.economy.allow_town_level_crossings = true;
 
	if (IsSavegameVersionBefore(SLV_159)) {
 
		_settings_game.vehicle.max_train_length = 50;
 
		_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;
 
		_settings_game.linkgraph.distribution_mail = DT_MANUAL;
 
		_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;
 
	}
 

	
 
	/* Load the sprites */
 
	GfxLoadSprites();
 
	LoadStringWidthTable();
 

	
 
	/* Copy temporary data to Engine pool */
 
	CopyTempEngineData();
 

	
 
@@ -2410,24 +2417,41 @@ bool AfterLoadGame()
 
		/* We need to properly number/name the depots.
 
		 * The first step is making sure none of the depots uses the
 
		 * 'default' names, after that we can assign the names. */
 
		for (Depot *d : Depot::Iterate()) d->town_cn = UINT16_MAX;
 

	
 
		for (Depot* d : Depot::Iterate()) MakeDefaultName(d);
 
	}
 

	
 
	if (IsSavegameVersionBefore(SLV_142)) {
 
		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.
 
	 * For old savegames with such aircraft we just throw them in the air and
 
	 * treat the aircraft like they were flying already. */
 
	if (IsSavegameVersionBefore(SLV_146)) {
 
		for (Aircraft *v : Aircraft::Iterate()) {
 
			if (!v->IsNormalAircraft()) continue;
 
			Station *st = GetTargetAirportIfValid(v);
 
			if (st == nullptr && v->state != FLYING) {
 
				v->state = FLYING;
 
				UpdateAircraftCache(v);
 
@@ -2813,24 +2837,55 @@ bool AfterLoadGame()
 
	if (IsSavegameVersionBefore(SLV_165)) {
 
		/* Adjust zoom level to account for new levels */
 
		_saved_scrollpos_zoom = static_cast<ZoomLevel>(_saved_scrollpos_zoom + ZOOM_LVL_SHIFT);
 
		_saved_scrollpos_x *= ZOOM_LVL_BASE;
 
		_saved_scrollpos_y *= ZOOM_LVL_BASE;
 
	}
 

	
 
	/* When any NewGRF has been changed the availability of some vehicles might
 
	 * have been changed too. e->company_avail must be set to 0 in that case
 
	 * 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++) {
 
			if (!IsStandardRoadStopTile(t)) continue;
 
			Owner o = GetTileOwner(t);
 
			SetRoadOwner(t, RTT_ROAD, o);
 
			SetRoadOwner(t, RTT_TRAM, o);
 
		}
 
	}
 

	
 
	if (IsSavegameVersionBefore(SLV_175)) {
 
		/* Introduced tree planting limit. */
src/saveload/company_sl.cpp
Show inline comments
 
@@ -10,24 +10,25 @@
 
#include "../stdafx.h"
 

	
 
#include "saveload.h"
 
#include "compat/company_sl_compat.h"
 

	
 
#include "../company_func.h"
 
#include "../company_manager_face.h"
 
#include "../fios.h"
 
#include "../tunnelbridge_map.h"
 
#include "../tunnelbridge.h"
 
#include "../station_base.h"
 
#include "../strings_func.h"
 
#include "../settings_func.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "../safeguards.h"
 

	
 
/**
 
 * Converts an old company manager's face format to the new company manager's face format
 
 *
 
 * Meaning of the bits in the old face (some bits are used in several times):
 
 * - 4 and 5: chin
 
 * - 6 to 9: eyebrows
 
 * - 10 to 13: nose
 
@@ -472,27 +473,29 @@ static const SaveLoad _company_desc[] = 
 

	
 
	    SLE_ARR(CompanyProperties, share_owners,          SLE_UINT8, 4),
 

	
 
	SLE_CONDVAR(CompanyProperties, num_valid_stat_ent,    SLE_UINT8,                   SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
 

	
 
	    SLE_VAR(CompanyProperties, months_of_bankruptcy,  SLE_UINT8),
 
	SLE_CONDVAR(CompanyProperties, bankrupt_asked,        SLE_FILE_U8  | SLE_VAR_U16,  SL_MIN_VERSION, SLV_104),
 
	SLE_CONDVAR(CompanyProperties, bankrupt_asked,        SLE_UINT16,                SLV_104, SL_MAX_VERSION),
 
	    SLE_VAR(CompanyProperties, bankrupt_timeout,      SLE_INT16),
 
	SLE_CONDVAR(CompanyProperties, bankrupt_value,        SLE_VAR_I64 | SLE_FILE_I32,  SL_MIN_VERSION, SLV_65),
 
	SLE_CONDVAR(CompanyProperties, bankrupt_value,        SLE_INT64,                  SLV_65, SL_MAX_VERSION),
 

	
 
	/* 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),
 

	
 
	SLE_CONDVAR(CompanyProperties, terraform_limit,       SLE_UINT32,                SLV_156, SL_MAX_VERSION),
 
	SLE_CONDVAR(CompanyProperties, clear_limit,           SLE_UINT32,                SLV_156, SL_MAX_VERSION),
 
	SLE_CONDVAR(CompanyProperties, tree_limit,            SLE_UINT32,                SLV_175, SL_MAX_VERSION),
 
	SLEG_STRUCT("settings", SlCompanySettings),
 
	SLEG_CONDSTRUCT("old_ai", SlCompanyOldAI,                                        SL_MIN_VERSION, SLV_107),
 
	SLEG_STRUCT("cur_economy", SlCompanyEconomy),
 
	SLEG_STRUCTLIST("old_economy", SlCompanyOldEconomy),
 
	SLEG_CONDSTRUCTLIST("liveries", SlCompanyLiveries,                               SLV_34, SL_MAX_VERSION),
 
};
src/saveload/compat/industry_sl_compat.h
Show inline comments
 
@@ -40,25 +40,25 @@ const SaveLoadCompat _industry_sl_compat
 
	SLC_VAR("was_cargo_delivered"),
 
	SLC_VAR("ctlflags"),
 
	SLC_VAR("founder"),
 
	SLC_VAR("construction_date"),
 
	SLC_VAR("construction_type"),
 
	SLC_VAR("last_cargo_accepted_at[0]"),
 
	SLC_VAR("last_cargo_accepted_at"),
 
	SLC_VAR("selected_layout"),
 
	SLC_VAR("exclusive_supplier"),
 
	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),
 
};
 

	
 
/** Original field order for _industry_builder_desc. */
 
const SaveLoadCompat _industry_builder_sl_compat[] = {
 
	SLC_VAR("wanted_inds"),
 
};
 

	
 
/** Original field order for _industrytype_builder_desc. */
 
const SaveLoadCompat _industrytype_builder_sl_compat[] = {
src/saveload/compat/settings_sl_compat.h
Show inline comments
 
@@ -29,24 +29,25 @@ const SaveLoadCompat _gameopt_sl_compat[
 
/** Original field order for _settings. */
 
const SaveLoadCompat _settings_sl_compat[] = {
 
	SLC_VAR("difficulty.max_no_competitors"),
 
	SLC_NULL(1, SLV_97, SLV_110),
 
	SLC_VAR("difficulty.number_towns"),
 
	SLC_VAR("difficulty.industry_density"),
 
	SLC_VAR("difficulty.max_loan"),
 
	SLC_VAR("difficulty.initial_interest"),
 
	SLC_VAR("difficulty.vehicle_costs"),
 
	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"),
 
	SLC_VAR("difficulty.terrain_type"),
 
	SLC_VAR("difficulty.quantity_sea_lakes"),
 
	SLC_VAR("difficulty.economy"),
 
	SLC_VAR("difficulty.line_reverse_mode"),
 
	SLC_VAR("difficulty.disasters"),
 
	SLC_VAR("difficulty.town_council_tolerance"),
 
	SLC_VAR("diff_level"),
 
	SLC_VAR("game_creation.town_name"),
 
	SLC_VAR("game_creation.landscape"),
 
@@ -60,24 +61,25 @@ const SaveLoadCompat _settings_sl_compat
 
	SLC_VAR("construction.terraform_frame_burst"),
 
	SLC_VAR("construction.clear_per_64k_frames"),
 
	SLC_VAR("construction.clear_frame_burst"),
 
	SLC_VAR("construction.tree_per_64k_frames"),
 
	SLC_VAR("construction.tree_frame_burst"),
 
	SLC_VAR("construction.autoslope"),
 
	SLC_VAR("construction.extra_dynamite"),
 
	SLC_VAR("construction.max_bridge_length"),
 
	SLC_VAR("construction.max_bridge_height"),
 
	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"),
 
	SLC_VAR("economy.found_town"),
 
	SLC_VAR("economy.allow_town_level_crossings"),
 
	SLC_VAR("economy.town_cargogen_mode"),
 
	SLC_VAR("linkgraph.recalc_interval"),
 
	SLC_VAR("linkgraph.recalc_time"),
 
	SLC_VAR("linkgraph.distribution_pax"),
 
	SLC_VAR("linkgraph.distribution_mail"),
 
	SLC_VAR("linkgraph.distribution_armoured"),
 
	SLC_VAR("linkgraph.distribution_default"),
 
@@ -109,60 +111,65 @@ const SaveLoadCompat _settings_sl_compat
 
	SLC_VAR("vehicle.max_ships"),
 
	SLC_VAR("vehicle.servint_ispercent"),
 
	SLC_VAR("vehicle.servint_trains"),
 
	SLC_VAR("vehicle.servint_roadveh"),
 
	SLC_VAR("vehicle.servint_ships"),
 
	SLC_VAR("vehicle.servint_aircraft"),
 
	SLC_VAR("order.no_servicing_if_no_breakdowns"),
 
	SLC_VAR("vehicle.wagon_speed_limits"),
 
	SLC_VAR("vehicle.disable_elrails"),
 
	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"),
 
	SLC_VAR("order.selectgoods"),
 
	SLC_VAR("gui.sg_new_nonstop"),
 
	SLC_NULL(1, SL_MIN_VERSION, SLV_159),
 
	SLC_VAR("station.station_spread"),
 
	SLC_VAR("order.serviceathelipad"),
 
	SLC_VAR("station.modified_catchment"),
 
	SLC_VAR("station.serve_neutral_industries"),
 
	SLC_VAR("order.gradual_loading"),
 
	SLC_VAR("construction.road_stop_on_town_road"),
 
	SLC_VAR("construction.road_stop_on_competitor_road"),
 
	SLC_VAR("station.adjacent_stations"),
 
	SLC_VAR("economy.station_noise_level"),
 
	SLC_VAR("station.distant_join_stations"),
 
	SLC_VAR("economy.inflation"),
 
	SLC_VAR("construction.raw_industry_construction"),
 
	SLC_VAR("construction.industry_platform"),
 
	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"),
 
	SLC_VAR("economy.give_money"),
 
	SLC_VAR("game_creation.snow_line_height"),
 
	SLC_VAR("game_creation.snow_coverage"),
 
	SLC_VAR("game_creation.desert_coverage"),
 
	SLC_NULL(4, SL_MIN_VERSION, SLV_144),
 
	SLC_VAR("game_creation.starting_year"),
 
	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"),
 
	SLC_VAR("economy.town_growth_rate"),
 
	SLC_VAR("economy.larger_towns"),
 
	SLC_VAR("economy.initial_city_size"),
 
	SLC_VAR("economy.mod_road_rebuild"),
 
	SLC_NULL(1, SL_MIN_VERSION, SLV_107),
 
	SLC_VAR("script.settings_profile"),
 
	SLC_VAR("ai.ai_in_multiplayer"),
 
	SLC_VAR("ai.ai_disable_veh_train"),
 
	SLC_VAR("ai.ai_disable_veh_roadveh"),
 
@@ -170,24 +177,44 @@ const SaveLoadCompat _settings_sl_compat
 
	SLC_VAR("ai.ai_disable_veh_ship"),
 
	SLC_VAR("script.script_max_opcode_till_suspend"),
 
	SLC_VAR("script.script_max_memory_megabytes"),
 
	SLC_VAR("vehicle.extend_vehicle_life"),
 
	SLC_VAR("economy.dist_local_authority"),
 
	SLC_VAR("pf.reverse_at_signals"),
 
	SLC_VAR("pf.wait_oneway_signal"),
 
	SLC_VAR("pf.wait_twoway_signal"),
 
	SLC_VAR("economy.town_noise_population[0]"),
 
	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"),
 
	SLC_NULL(3, SL_MIN_VERSION, SLV_REMOVE_OPF),
 
	SLC_VAR("pf.npf.npf_max_search_nodes"),
 
	SLC_VAR("pf.npf.npf_rail_firstred_penalty"),
 
	SLC_VAR("pf.npf.npf_rail_firstred_exit_penalty"),
 
	SLC_VAR("pf.npf.npf_rail_lastred_penalty"),
 
	SLC_VAR("pf.npf.npf_rail_station_penalty"),
 
	SLC_VAR("pf.npf.npf_rail_slope_penalty"),
 
	SLC_VAR("pf.npf.npf_rail_curve_penalty"),
 
	SLC_VAR("pf.npf.npf_rail_depot_reverse_penalty"),
src/saveload/compat/station_sl_compat.h
Show inline comments
 
@@ -108,24 +108,25 @@ const SaveLoadCompat _station_normal_sl_
 
	SLC_VAR("airport.layout"),
 
	SLC_VAR("airport.flags"),
 
	SLC_VAR("airport.rotation"),
 
	SLC_VAR("storage"),
 
	SLC_VAR("airport.psa"),
 
	SLC_VAR("indtype"),
 
	SLC_VAR("time_since_load"),
 
	SLC_VAR("time_since_unload"),
 
	SLC_VAR("last_vehicle_type"),
 
	SLC_VAR("had_vehicle_of_type"),
 
	SLC_VAR("loading_vehicles"),
 
	SLC_VAR("always_accepted"),
 
	SLC_VAR("dilapidation"),
 
	SLC_VAR("goods"),
 
};
 

	
 
/** Original field order for SlStationWaypoint. */
 
const SaveLoadCompat _station_waypoint_sl_compat[] = {
 
	SLC_VAR("base"),
 
	SLC_VAR("town_cn"),
 
	SLC_VAR("train_station.tile"),
 
	SLC_VAR("train_station.w"),
 
	SLC_VAR("train_station.h"),
 
};
 

	
src/saveload/compat/vehicle_sl_compat.h
Show inline comments
 
@@ -66,24 +66,26 @@ const SaveLoadCompat _vehicle_common_sl_
 
	SLC_VAR("timetable_start"),
 
	SLC_VAR("orders"),
 
	SLC_VAR("age"),
 
	SLC_VAR("max_age"),
 
	SLC_VAR("date_of_last_service"),
 
	SLC_VAR("service_interval"),
 
	SLC_VAR("reliability"),
 
	SLC_VAR("reliability_spd_dec"),
 
	SLC_VAR("breakdown_ctr"),
 
	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"),
 
	SLC_VAR("vehicle_flags"),
 
	SLC_VAR("profit_this_year"),
 
	SLC_VAR("profit_last_year"),
 
	SLC_VAR("cargo_feeder_share"),
 
	SLC_VAR("cargo_loaded_at_xy"),
 
	SLC_VAR("value"),
 
	SLC_VAR("random_bits"),
 
	SLC_VAR("waiting_triggers"),
 
	SLC_VAR("next_shared"),
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
 
@@ -2,30 +2,33 @@
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file gamelog_sl.cpp Code handling saving and loading of gamelog data */
 

	
 
#include "../stdafx.h"
 

	
 
#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:
 
	inline static const SaveLoad description[] = {
 
		SLE_VAR(LoggedChange, mode.mode,         SLE_UINT8),
 
		SLE_VAR(LoggedChange, mode.landscape,    SLE_UINT8),
 
	};
 
	inline const static SaveLoadCompatTable compat_description = _gamelog_mode_sl_compat;
 

	
 
	void Save(LoggedChange *lc) const override
 
	{
 
		if (lc->ct != GLCT_MODE) return;
 
@@ -52,24 +55,29 @@ public:
 
	inline const static SaveLoadCompatTable compat_description = _gamelog_revision_sl_compat;
 

	
 
	void Save(LoggedChange *lc) const override
 
	{
 
		if (lc->ct != GLCT_REVISION) return;
 
		SlObject(lc, this->GetDescription());
 
	}
 

	
 
	void Load(LoggedChange *lc) const override
 
	{
 
		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); }
 
};
 

	
 
class SlGamelogOldver : public DefaultSaveLoadHandler<SlGamelogOldver, LoggedChange> {
 
public:
 
	inline static const SaveLoad description[] = {
 
		SLE_VAR(LoggedChange, oldver.type,       SLE_UINT32),
 
		SLE_VAR(LoggedChange, oldver.version,    SLE_UINT32),
 
	};
 
	inline const static SaveLoadCompatTable compat_description = _gamelog_oldver_sl_compat;
 
@@ -389,26 +397,28 @@ struct GLOGChunkHandler : ChunkHandler {
 
		const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
 

	
 
		uint i = 0;
 
		for (LoggedAction *la = _gamelog_action; la != laend; la++, i++) {
 
			SlSetArrayIndex(i);
 
			SlObject(la, _gamelog_desc);
 
		}
 
	}
 

	
 
	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();
 
	}
 
};
 

	
 
static const GLOGChunkHandler GLOG;
 
static const ChunkHandlerRef gamelog_chunk_handlers[] = {
 
	GLOG,
 
};
 

	
 
extern const ChunkHandlerTable _gamelog_chunk_handlers(gamelog_chunk_handlers);

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

0 comments (0 inline, 0 general)