Changeset - r10571:99cb9a95b4cf
[Not reviewed]
master
3 62 29
smatz - 15 years ago 2009-01-04 15:32:25
smatz@openttd.org
(svn r14828) -Codechange: move most of save/load-specific code to separate files
94 files changed with 9226 insertions and 8648 deletions:
0 comments (0 inline, 0 general)
projects/openttd_vs80.vcproj
Show inline comments
 
@@ -648,10 +648,6 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\oldloader.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\oldpool.cpp"
 
				>
 
			</File>
 
@@ -692,10 +688,6 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\screenshot.cpp"
 
				>
 
			</File>
 
@@ -1044,6 +1036,10 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\gamelog_internal.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\genworld.h"
 
				>
 
			</File>
 
@@ -1360,10 +1356,6 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\screenshot.h"
 
				>
 
			</File>
 
@@ -2009,6 +2001,122 @@
 
			</File>
 
		</Filter>
 
		<Filter
 
			Name="Save/Load handlers"
 
			>
 
			<File
 
				RelativePath=".\..\src\saveload\afterload.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\ai_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\animated_tile_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\autoreplace_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\cargopacket_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\cheat_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\company_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\depot_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\economy_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\engine_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\gamelog_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\group_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\industry_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\map_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\misc_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\newgrf_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\oldloader.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\order_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\saveload.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\saveload.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\saveload_internal.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\signs_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\station_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\strings_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\subsidy_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\town_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\vehicle_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\waypoint_sl.cpp"
 
				>
 
			</File>
 
		</Filter>
 
		<Filter
 
			Name="Tables"
 
			>
 
			<File
projects/openttd_vs90.vcproj
Show inline comments
 
@@ -645,10 +645,6 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\oldloader.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\oldpool.cpp"
 
				>
 
			</File>
 
@@ -689,10 +685,6 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\screenshot.cpp"
 
				>
 
			</File>
 
@@ -1041,6 +1033,10 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\gamelog_internal.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\genworld.h"
 
				>
 
			</File>
 
@@ -1357,10 +1353,6 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\screenshot.h"
 
				>
 
			</File>
 
@@ -2006,6 +1998,122 @@
 
			</File>
 
		</Filter>
 
		<Filter
 
			Name="Save/Load handlers"
 
			>
 
			<File
 
				RelativePath=".\..\src\saveload\afterload.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\ai_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\animated_tile_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\autoreplace_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\cargopacket_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\cheat_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\company_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\depot_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\economy_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\engine_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\gamelog_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\group_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\industry_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\map_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\misc_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\newgrf_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\oldloader.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\order_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\saveload.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\saveload.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\saveload_internal.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\signs_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\station_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\strings_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\subsidy_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\town_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\vehicle_sl.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\saveload\waypoint_sl.cpp"
 
				>
 
			</File>
 
		</Filter>
 
		<Filter
 
			Name="Tables"
 
			>
 
			<File
source.list
Show inline comments
 
@@ -50,7 +50,6 @@ network/network_gamelist.cpp
 
network/network_server.cpp
 
network/network_udp.cpp
 
npf.cpp
 
oldloader.cpp
 
oldpool.cpp
 
openttd.cpp
 
os_timer.cpp
 
@@ -66,7 +65,6 @@ queue.cpp
 
rail.cpp
 
rev.cpp
 
road.cpp
 
saveload.cpp
 
screenshot.cpp
 
#if SDL
 
	sdl.cpp
 
@@ -193,6 +191,7 @@ fios.h
 
fontcache.h
 
functions.h
 
gamelog.h
 
gamelog_internal.h
 
genworld.h
 
gfx_func.h
 
gfx_type.h
 
@@ -272,7 +271,6 @@ road_gui.h
 
road_internal.h
 
road_type.h
 
roadveh.h
 
saveload.h
 
screenshot.h
 
sdl.h
 
sound/sdl_s.h
 
@@ -452,6 +450,36 @@ tunnelbridge_cmd.cpp
 
unmovable_cmd.cpp
 
water_cmd.cpp
 

	
 
# Save/Load handlers
 
saveload/afterload.cpp
 
saveload/ai_sl.cpp
 
saveload/animated_tile_sl.cpp
 
saveload/autoreplace_sl.cpp
 
saveload/cargopacket_sl.cpp
 
saveload/cheat_sl.cpp
 
saveload/company_sl.cpp
 
saveload/depot_sl.cpp
 
saveload/economy_sl.cpp
 
saveload/engine_sl.cpp
 
saveload/gamelog_sl.cpp
 
saveload/group_sl.cpp
 
saveload/industry_sl.cpp
 
saveload/map_sl.cpp
 
saveload/misc_sl.cpp
 
saveload/newgrf_sl.cpp
 
saveload/oldloader.cpp
 
saveload/order_sl.cpp
 
saveload/saveload.cpp
 
saveload/saveload.h
 
saveload/saveload_internal.h
 
saveload/signs_sl.cpp
 
saveload/station_sl.cpp
 
saveload/strings_sl.cpp
 
saveload/subsidy_sl.cpp
 
saveload/town_sl.cpp
 
saveload/vehicle_sl.cpp
 
saveload/waypoint_sl.cpp
 

	
 
# Tables
 
table/ai_rail.h
 
table/animcursors.h
src/ai/default/default.cpp
Show inline comments
 
@@ -25,7 +25,6 @@
 
#include "../../window_func.h"
 
#include "../../vehicle_func.h"
 
#include "../../functions.h"
 
#include "../../saveload.h"
 
#include "../../company_func.h"
 
#include "../../company_base.h"
 
#include "../../settings_type.h"
 
@@ -4027,74 +4026,3 @@ void AiDoGameLoop(Company *c)
 

	
 
	_ai_actions[_companies_ai[c->index].state](c);
 
}
 

	
 

	
 
static const SaveLoad _company_ai_desc[] = {
 
	    SLE_VAR(CompanyAI, state,             SLE_UINT8),
 
	    SLE_VAR(CompanyAI, tick,              SLE_UINT8),
 
	SLE_CONDVAR(CompanyAI, state_counter,     SLE_FILE_U16 | SLE_VAR_U32,  0, 12),
 
	SLE_CONDVAR(CompanyAI, state_counter,     SLE_UINT32,                 13, SL_MAX_VERSION),
 
	    SLE_VAR(CompanyAI, timeout_counter,   SLE_UINT16),
 

	
 
	    SLE_VAR(CompanyAI, state_mode,        SLE_UINT8),
 
	    SLE_VAR(CompanyAI, banned_tile_count, SLE_UINT8),
 
	    SLE_VAR(CompanyAI, railtype_to_use,   SLE_UINT8),
 

	
 
	    SLE_VAR(CompanyAI, cargo_type,        SLE_UINT8),
 
	    SLE_VAR(CompanyAI, num_wagons,        SLE_UINT8),
 
	    SLE_VAR(CompanyAI, build_kind,        SLE_UINT8),
 
	    SLE_VAR(CompanyAI, num_build_rec,     SLE_UINT8),
 
	    SLE_VAR(CompanyAI, num_loco_to_build, SLE_UINT8),
 
	    SLE_VAR(CompanyAI, num_want_fullload, SLE_UINT8),
 

	
 
	    SLE_VAR(CompanyAI, route_type_mask,   SLE_UINT8),
 

	
 
	SLE_CONDVAR(CompanyAI, start_tile_a,      SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
 
	SLE_CONDVAR(CompanyAI, start_tile_a,      SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(CompanyAI, cur_tile_a,        SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
 
	SLE_CONDVAR(CompanyAI, cur_tile_a,        SLE_UINT32,                  6, SL_MAX_VERSION),
 
	    SLE_VAR(CompanyAI, start_dir_a,       SLE_UINT8),
 
	    SLE_VAR(CompanyAI, cur_dir_a,         SLE_UINT8),
 

	
 
	SLE_CONDVAR(CompanyAI, start_tile_b,      SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
 
	SLE_CONDVAR(CompanyAI, start_tile_b,      SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(CompanyAI, cur_tile_b,        SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
 
	SLE_CONDVAR(CompanyAI, cur_tile_b,        SLE_UINT32,                  6, SL_MAX_VERSION),
 
	    SLE_VAR(CompanyAI, start_dir_b,       SLE_UINT8),
 
	    SLE_VAR(CompanyAI, cur_dir_b,         SLE_UINT8),
 

	
 
	    SLE_REF(CompanyAI, cur_veh,           REF_VEHICLE),
 

	
 
	    SLE_ARR(CompanyAI, wagon_list,        SLE_UINT16, 9),
 
	    SLE_ARR(CompanyAI, order_list_blocks, SLE_UINT8, 20),
 
	    SLE_ARR(CompanyAI, banned_tiles,      SLE_UINT16, 16),
 

	
 
	SLE_CONDNULL(64, 2, SL_MAX_VERSION),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _company_ai_build_rec_desc[] = {
 
	SLE_CONDVAR(AiBuildRec, spec_tile,         SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
 
	SLE_CONDVAR(AiBuildRec, spec_tile,         SLE_UINT32,                 6, SL_MAX_VERSION),
 
	SLE_CONDVAR(AiBuildRec, use_tile,          SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
 
	SLE_CONDVAR(AiBuildRec, use_tile,          SLE_UINT32,                 6, SL_MAX_VERSION),
 
	    SLE_VAR(AiBuildRec, rand_rng,          SLE_UINT8),
 
	    SLE_VAR(AiBuildRec, cur_building_rule, SLE_UINT8),
 
	    SLE_VAR(AiBuildRec, unk6,              SLE_UINT8),
 
	    SLE_VAR(AiBuildRec, unk7,              SLE_UINT8),
 
	    SLE_VAR(AiBuildRec, buildcmd_a,        SLE_UINT8),
 
	    SLE_VAR(AiBuildRec, buildcmd_b,        SLE_UINT8),
 
	    SLE_VAR(AiBuildRec, direction,         SLE_UINT8),
 
	    SLE_VAR(AiBuildRec, cargo,             SLE_UINT8),
 
	SLE_END()
 
};
 

	
 

	
 
void SaveLoad_AI(CompanyID company)
 
{
 
	CompanyAI *cai = &_companies_ai[company];
 
	SlObject(cai, _company_ai_desc);
 
	for (int i = 0; i != cai->num_build_rec; i++) {
 
		SlObject(&cai->src + i, _company_ai_build_rec_desc);
 
	}
 
}
src/ai/default/default.h
Show inline comments
 
@@ -10,7 +10,6 @@
 
#include "../../rail_type.h"
 

	
 
void AiDoGameLoop(Company *c);
 
void SaveLoad_AI(CompanyID company);
 

	
 
struct AiBuildRec {
 
	TileIndex spec_tile;
src/ai/trolly/trolly.h
Show inline comments
 
@@ -10,6 +10,7 @@
 
#include "../../vehicle_type.h"
 
#include "../../date_type.h"
 
#include "../../engine_type.h"
 
#include "../../direction_type.h"
 

	
 
/*
 
 * These defines can be altered to change the behavoir of the AI
src/aircraft.h
Show inline comments
 
@@ -99,6 +99,11 @@ void UpdateAirplanesOnNewStation(const S
 
 */
 
void UpdateAircraftCache(Vehicle *v);
 

	
 
void AircraftLeaveHangar(Vehicle *v);
 
void AircraftNextAirportPos_and_Order(Vehicle *v);
 
void SetAircraftPosition(Vehicle *v, int x, int y, int z);
 
byte GetAircraftFlyingAltitude(const Vehicle *v);
 

	
 
/**
 
 * This class 'wraps' Vehicle; you do not actually instantiate this class.
 
 * You create a Vehicle using AllocateVehicle, so it is added to the pool
src/aircraft_cmd.cpp
Show inline comments
 
@@ -82,9 +82,6 @@ static bool AirportFindFreeTerminal(Vehi
 
static bool AirportFindFreeHelipad(Vehicle *v, const AirportFTAClass *apc);
 
static void CrashAirplane(Vehicle *v);
 

	
 
void AircraftNextAirportPos_and_Order(Vehicle *v);
 
static byte GetAircraftFlyingAltitude(const Vehicle *v);
 

	
 
static const SpriteID _aircraft_sprite[] = {
 
	0x0EB5, 0x0EBD, 0x0EC5, 0x0ECD,
 
	0x0ED5, 0x0EDD, 0x0E9D, 0x0EA5,
 
@@ -727,7 +724,7 @@ static void HelicopterTickHandler(Vehicl
 
	EndVehicleMove(u);
 
}
 

	
 
static void SetAircraftPosition(Vehicle *v, int x, int y, int z)
 
void SetAircraftPosition(Vehicle *v, int x, int y, int z)
 
{
 
	v->x_pos = x;
 
	v->y_pos = y;
 
@@ -883,7 +880,7 @@ static int UpdateAircraftSpeed(Vehicle *
 
 * @param v The vehicle. Should be an aircraft
 
 * @returns Altitude in pixel units
 
 */
 
static byte GetAircraftFlyingAltitude(const Vehicle *v)
 
byte GetAircraftFlyingAltitude(const Vehicle *v)
 
{
 
	/* Make sure Aircraft fly no lower so that they don't conduct
 
	 * CFITs (controlled flight into terrain)
 
@@ -1433,7 +1430,7 @@ void AircraftNextAirportPos_and_Order(Ve
 
	v->u.air.pos = v->u.air.previous_pos = AircraftGetEntryPoint(v, apc);
 
}
 

	
 
static void AircraftLeaveHangar(Vehicle *v)
 
void AircraftLeaveHangar(Vehicle *v)
 
{
 
	v->cur_speed = 0;
 
	v->subspeed = 0;
 
@@ -2096,42 +2093,6 @@ Station *GetTargetAirportIfValid(const V
 
	return st->airport_tile == INVALID_TILE ? NULL : st;
 
}
 

	
 
/** need to be called to load aircraft from old version */
 
void UpdateOldAircraft()
 
{
 
	/* set airport_flags to 0 for all airports just to be sure */
 
	Station *st;
 
	FOR_ALL_STATIONS(st) {
 
		st->airport_flags = 0; // reset airport
 
	}
 

	
 
	Vehicle *v_oldstyle;
 
	FOR_ALL_VEHICLES(v_oldstyle) {
 
	/* airplane has another vehicle with subtype 4 (shadow), helicopter also has 3 (rotor)
 
	 * skip those */
 
		if (v_oldstyle->type == VEH_AIRCRAFT && IsNormalAircraft(v_oldstyle)) {
 
			/* airplane in terminal stopped doesn't hurt anyone, so goto next */
 
			if (v_oldstyle->vehstatus & VS_STOPPED && v_oldstyle->u.air.state == 0) {
 
				v_oldstyle->u.air.state = HANGAR;
 
				continue;
 
			}
 

	
 
			AircraftLeaveHangar(v_oldstyle); // make airplane visible if it was in a depot for example
 
			v_oldstyle->vehstatus &= ~VS_STOPPED; // make airplane moving
 
			v_oldstyle->u.air.state = FLYING;
 
			AircraftNextAirportPos_and_Order(v_oldstyle); // move it to the entry point of the airport
 
			GetNewVehiclePosResult gp = GetNewVehiclePos(v_oldstyle);
 
			v_oldstyle->tile = 0; // aircraft in air is tile=0
 

	
 
			/* correct speed of helicopter-rotors */
 
			if (v_oldstyle->subtype == AIR_HELICOPTER) v_oldstyle->Next()->Next()->cur_speed = 32;
 

	
 
			/* set new position x,y,z */
 
			SetAircraftPosition(v_oldstyle, gp.x, gp.y, GetAircraftFlyingAltitude(v_oldstyle));
 
		}
 
	}
 
}
 

	
 
/**
 
 * Updates the status of the Aircraft heading or in the station
 
 * @param st Station been updated
src/animated_tile.cpp
Show inline comments
 
@@ -4,7 +4,6 @@
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "saveload.h"
 
#include "landscape.h"
 
#include "core/alloc_func.hpp"
 
#include "functions.h"
 
@@ -14,7 +13,7 @@ TileIndex *_animated_tile_list = NULL;
 
/** The number of animated tiles in the current state. */
 
uint _animated_tile_count = 0;
 
/** The number of slots for animated tiles allocated currently. */
 
static uint _animated_tile_allocated = 0;
 
uint _animated_tile_allocated = 0;
 

	
 
/**
 
 * Removes the given tile from the animated tile table.
 
@@ -90,46 +89,3 @@ void InitializeAnimatedTiles()
 
	_animated_tile_count = 0;
 
	_animated_tile_allocated = 256;
 
}
 

	
 
/**
 
 * Save the ANIT chunk.
 
 */
 
static void Save_ANIT()
 
{
 
	SlSetLength(_animated_tile_count * sizeof(*_animated_tile_list));
 
	SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32);
 
}
 

	
 
/**
 
 * Load the ANIT chunk; the chunk containing the animated tiles.
 
 */
 
static void Load_ANIT()
 
{
 
	/* Before version 80 we did NOT have a variable length animated tile table */
 
	if (CheckSavegameVersion(80)) {
 
		/* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */
 
		SlArray(_animated_tile_list, 256, CheckSavegameVersion(6) ? (SLE_FILE_U16 | SLE_VAR_U32) : SLE_UINT32);
 

	
 
		for (_animated_tile_count = 0; _animated_tile_count < 256; _animated_tile_count++) {
 
			if (_animated_tile_list[_animated_tile_count] == 0) break;
 
		}
 
		return;
 
	}
 

	
 
	_animated_tile_count = (uint)SlGetFieldLength() / sizeof(*_animated_tile_list);
 

	
 
	/* Determine a nice rounded size for the amount of allocated tiles */
 
	_animated_tile_allocated = 256;
 
	while (_animated_tile_allocated < _animated_tile_count) _animated_tile_allocated *= 2;
 

	
 
	_animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, _animated_tile_allocated);
 
	SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32);
 
}
 

	
 
/**
 
 * "Definition" imported by the saveload code to be able to load and save
 
 * the animated tile table.
 
 */
 
extern const ChunkHandler _animated_tile_chunk_handlers[] = {
 
	{ 'ANIT', Save_ANIT, Load_ANIT, CH_RIFF | CH_LAST},
 
};
src/autoreplace.cpp
Show inline comments
 
@@ -6,7 +6,6 @@
 
#include "openttd.h"
 
#include "debug.h"
 
#include "command_func.h"
 
#include "saveload.h"
 
#include "group.h"
 
#include "autoreplace_base.h"
 
#include "oldpool_func.h"
 
@@ -102,46 +101,6 @@ CommandCost RemoveEngineReplacement(Engi
 
	return CMD_ERROR;
 
}
 

	
 
static const SaveLoad _engine_renew_desc[] = {
 
	    SLE_VAR(EngineRenew, from,     SLE_UINT16),
 
	    SLE_VAR(EngineRenew, to,       SLE_UINT16),
 

	
 
	    SLE_REF(EngineRenew, next,     REF_ENGINE_RENEWS),
 
	SLE_CONDVAR(EngineRenew, group_id, SLE_UINT16, 60, SL_MAX_VERSION),
 
	SLE_END()
 
};
 

	
 
static void Save_ERNW()
 
{
 
	EngineRenew *er;
 

	
 
	FOR_ALL_ENGINE_RENEWS(er) {
 
		SlSetArrayIndex(er->index);
 
		SlObject(er, _engine_renew_desc);
 
	}
 
}
 

	
 
static void Load_ERNW()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		EngineRenew *er = new (index) EngineRenew();
 
		SlObject(er, _engine_renew_desc);
 

	
 
		/* Advanced vehicle lists, ungrouped vehicles got added */
 
		if (CheckSavegameVersion(60)) {
 
			er->group_id = ALL_GROUP;
 
		} else if (CheckSavegameVersion(71)) {
 
			if (er->group_id == DEFAULT_GROUP) er->group_id = ALL_GROUP;
 
		}
 
	}
 
}
 

	
 
extern const ChunkHandler _autoreplace_chunk_handlers[] = {
 
	{ 'ERNW', Save_ERNW,     Load_ERNW,     CH_ARRAY | CH_LAST},
 
};
 

	
 
void InitializeEngineRenews()
 
{
 
	/* Clean the engine renew pool and create 1 block in it */
src/cargopacket.cpp
Show inline comments
 
@@ -3,10 +3,8 @@
 
/** @file cargopacket.cpp Implementation of the cargo packets */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "station_base.h"
 
#include "cargopacket.h"
 
#include "saveload.h"
 
#include "oldpool_func.h"
 

	
 
/* Initialize the cargopacket-pool */
 
@@ -43,42 +41,6 @@ bool CargoPacket::SameSource(const Cargo
 
	return this->source_xy == cp->source_xy && this->days_in_transit == cp->days_in_transit && this->paid_for == cp->paid_for;
 
}
 

	
 
static const SaveLoad _cargopacket_desc[] = {
 
	SLE_VAR(CargoPacket, source,          SLE_UINT16),
 
	SLE_VAR(CargoPacket, source_xy,       SLE_UINT32),
 
	SLE_VAR(CargoPacket, loaded_at_xy,    SLE_UINT32),
 
	SLE_VAR(CargoPacket, count,           SLE_UINT16),
 
	SLE_VAR(CargoPacket, days_in_transit, SLE_UINT8),
 
	SLE_VAR(CargoPacket, feeder_share,    SLE_INT64),
 
	SLE_VAR(CargoPacket, paid_for,        SLE_BOOL),
 

	
 
	SLE_END()
 
};
 

	
 
static void Save_CAPA()
 
{
 
	CargoPacket *cp;
 

	
 
	FOR_ALL_CARGOPACKETS(cp) {
 
		SlSetArrayIndex(cp->index);
 
		SlObject(cp, _cargopacket_desc);
 
	}
 
}
 

	
 
static void Load_CAPA()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		CargoPacket *cp = new (index) CargoPacket();
 
		SlObject(cp, _cargopacket_desc);
 
	}
 
}
 

	
 
extern const ChunkHandler _cargopacket_chunk_handlers[] = {
 
	{ 'CAPA', Save_CAPA, Load_CAPA, CH_ARRAY | CH_LAST},
 
};
 

	
 
/*
 
 *
 
 * Cargo list implementation
src/cheat.cpp
Show inline comments
 
@@ -3,7 +3,6 @@
 
/** @file cheat.cpp Handling (loading/saving/initializing) of cheats. */
 

	
 
#include "stdafx.h"
 
#include "saveload.h"
 
#include "cheat_type.h"
 

	
 
Cheats _cheats;
 
@@ -13,31 +12,6 @@ void InitializeCheats()
 
	memset(&_cheats, 0, sizeof(Cheats));
 
}
 

	
 
static void Save_CHTS()
 
{
 
	/* Cannot use lengthof because _cheats is of type Cheats, not Cheat */
 
	byte count = sizeof(_cheats) / sizeof(Cheat);
 
	Cheat *cht = (Cheat*) &_cheats;
 
	Cheat *cht_last = &cht[count];
 

	
 
	SlSetLength(count * 2);
 
	for (; cht != cht_last; cht++) {
 
		SlWriteByte(cht->been_used);
 
		SlWriteByte(cht->value);
 
	}
 
}
 

	
 
static void Load_CHTS()
 
{
 
	Cheat *cht = (Cheat*)&_cheats;
 
	size_t count = SlGetFieldLength() / 2;
 

	
 
	for (uint i = 0; i < count; i++) {
 
		cht[i].been_used = (SlReadByte() != 0);
 
		cht[i].value     = (SlReadByte() != 0);
 
	}
 
}
 

	
 
bool CheatHasBeenUsed()
 
{
 
	/* Cannot use lengthof because _cheats is of type Cheats, not Cheat */
 
@@ -50,8 +24,3 @@ bool CheatHasBeenUsed()
 

	
 
	return false;
 
}
 

	
 

	
 
extern const ChunkHandler _cheat_chunk_handlers[] = {
 
	{ 'CHTS', Save_CHTS,     Load_CHTS,     CH_RIFF | CH_LAST}
 
};
src/cheat_gui.cpp
Show inline comments
 
@@ -10,7 +10,7 @@
 
#include "company_func.h"
 
#include "gfx_func.h"
 
#include "date_func.h"
 
#include "saveload.h"
 
#include "saveload/saveload.h"
 
#include "window_gui.h"
 
#include "newgrf.h"
 
#include "settings_type.h"
src/company_cmd.cpp
Show inline comments
 
@@ -10,7 +10,6 @@
 
#include "company_gui.h"
 
#include "town.h"
 
#include "news_func.h"
 
#include "saveload.h"
 
#include "command_func.h"
 
#include "network/network.h"
 
#include "network/network_func.h"
 
@@ -111,74 +110,6 @@ void DrawCompanyIcon(CompanyID c, int x,
 
}
 

	
 
/**
 
 * 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
 
 * - 13 to 15: lips (also moustache for males)
 
 * - 16 to 19: hair
 
 * - 20 to 22: eye color
 
 * - 20 to 27: tie, ear rings etc.
 
 * - 28 to 30: glasses
 
 * - 19, 26 and 27: race (bit 27 set and bit 19 equal to bit 26 = black, otherwise white)
 
 * - 31: gender (0 = male, 1 = female)
 
 *
 
 * @param face the face in the old format
 
 * @return the face in the new format
 
 */
 
CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32 face)
 
{
 
	CompanyManagerFace cmf = 0;
 
	GenderEthnicity ge = GE_WM;
 

	
 
	if (HasBit(face, 31)) SetBit(ge, GENDER_FEMALE);
 
	if (HasBit(face, 27) && (HasBit(face, 26) == HasBit(face, 19))) SetBit(ge, ETHNICITY_BLACK);
 

	
 
	SetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN,    ge, ge);
 
	SetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge, GB(face, 28, 3) <= 1);
 
	SetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR,  ge, HasBit(ge, ETHNICITY_BLACK) ? 0 : ClampU(GB(face, 20, 3), 5, 7) - 5);
 
	SetCompanyManagerFaceBits(cmf, CMFV_CHIN,        ge, ScaleCompanyManagerFaceValue(CMFV_CHIN,     ge, GB(face,  4, 2)));
 
	SetCompanyManagerFaceBits(cmf, CMFV_EYEBROWS,    ge, ScaleCompanyManagerFaceValue(CMFV_EYEBROWS, ge, GB(face,  6, 4)));
 
	SetCompanyManagerFaceBits(cmf, CMFV_HAIR,        ge, ScaleCompanyManagerFaceValue(CMFV_HAIR,     ge, GB(face, 16, 4)));
 
	SetCompanyManagerFaceBits(cmf, CMFV_JACKET,      ge, ScaleCompanyManagerFaceValue(CMFV_JACKET,   ge, GB(face, 20, 2)));
 
	SetCompanyManagerFaceBits(cmf, CMFV_COLLAR,      ge, ScaleCompanyManagerFaceValue(CMFV_COLLAR,   ge, GB(face, 22, 2)));
 
	SetCompanyManagerFaceBits(cmf, CMFV_GLASSES,     ge, GB(face, 28, 1));
 

	
 
	uint lips = GB(face, 10, 4);
 
	if (!HasBit(ge, GENDER_FEMALE) && lips < 4) {
 
		SetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE, ge, true);
 
		SetCompanyManagerFaceBits(cmf, CMFV_MOUSTACHE,     ge, max(lips, 1U) - 1);
 
	} else {
 
		if (!HasBit(ge, GENDER_FEMALE)) {
 
			lips = lips * 15 / 16;
 
			lips -= 3;
 
			if (HasBit(ge, ETHNICITY_BLACK) && lips > 8) lips = 0;
 
		} else {
 
			lips = ScaleCompanyManagerFaceValue(CMFV_LIPS, ge, lips);
 
		}
 
		SetCompanyManagerFaceBits(cmf, CMFV_LIPS, ge, lips);
 

	
 
		uint nose = GB(face, 13, 3);
 
		if (ge == GE_WF) {
 
			nose = (nose * 3 >> 3) * 3 >> 2; // There is 'hole' in the nose sprites for females
 
		} else {
 
			nose = ScaleCompanyManagerFaceValue(CMFV_NOSE, ge, nose);
 
		}
 
		SetCompanyManagerFaceBits(cmf, CMFV_NOSE, ge, nose);
 
	}
 

	
 
	uint tie_earring = GB(face, 24, 4);
 
	if (!HasBit(ge, GENDER_FEMALE) || tie_earring < 3) { // Not all females have an earring
 
		if (HasBit(ge, GENDER_FEMALE)) SetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge, true);
 
		SetCompanyManagerFaceBits(cmf, CMFV_TIE_EARRING, ge, HasBit(ge, GENDER_FEMALE) ? tie_earring : ScaleCompanyManagerFaceValue(CMFV_TIE_EARRING, ge, tie_earring / 2));
 
	}
 

	
 
	return cmf;
 
}
 

	
 
/**
 
 * Checks whether a company manager's face is a valid encoding.
 
 * Unused bits are not enforced to be 0.
 
 * @param cmf the fact to check
 
@@ -936,159 +867,3 @@ CommandCost CmdCompanyCtrl(TileIndex til
 

	
 
	return CommandCost();
 
}
 

	
 
/* Save/load of companies */
 
static const SaveLoad _company_desc[] = {
 
	    SLE_VAR(Company, name_2,          SLE_UINT32),
 
	    SLE_VAR(Company, name_1,          SLE_STRINGID),
 
	SLE_CONDSTR(Company, name,            SLE_STR, 0,                       84, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(Company, president_name_1, SLE_UINT16),
 
	    SLE_VAR(Company, president_name_2, SLE_UINT32),
 
	SLE_CONDSTR(Company, president_name,  SLE_STR, 0,                       84, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(Company, face,            SLE_UINT32),
 

	
 
	/* money was changed to a 64 bit field in savegame version 1. */
 
	SLE_CONDVAR(Company, money,                 SLE_VAR_I64 | SLE_FILE_I32,  0, 0),
 
	SLE_CONDVAR(Company, money,                 SLE_INT64,                   1, SL_MAX_VERSION),
 

	
 
	SLE_CONDVAR(Company, current_loan,          SLE_VAR_I64 | SLE_FILE_I32,  0, 64),
 
	SLE_CONDVAR(Company, current_loan,          SLE_INT64,                  65, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(Company, colour,                SLE_UINT8),
 
	    SLE_VAR(Company, money_fraction,        SLE_UINT8),
 
	SLE_CONDVAR(Company, avail_railtypes,       SLE_UINT8,                   0, 57),
 
	    SLE_VAR(Company, block_preview,         SLE_UINT8),
 

	
 
	SLE_CONDVAR(Company, cargo_types,           SLE_FILE_U16 | SLE_VAR_U32,  0, 93),
 
	SLE_CONDVAR(Company, cargo_types,           SLE_UINT32,                 94, SL_MAX_VERSION),
 
	SLE_CONDVAR(Company, location_of_HQ,        SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
 
	SLE_CONDVAR(Company, location_of_HQ,        SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Company, last_build_coordinate, SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
 
	SLE_CONDVAR(Company, last_build_coordinate, SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Company, inaugurated_year,      SLE_FILE_U8  | SLE_VAR_I32,  0, 30),
 
	SLE_CONDVAR(Company, inaugurated_year,      SLE_INT32,                  31, SL_MAX_VERSION),
 

	
 
	    SLE_ARR(Company, share_owners,          SLE_UINT8, 4),
 

	
 
	    SLE_VAR(Company, num_valid_stat_ent,    SLE_UINT8),
 

	
 
	    SLE_VAR(Company, quarters_of_bankrupcy, SLE_UINT8),
 
	SLE_CONDVAR(Company, bankrupt_asked,        SLE_FILE_U8  | SLE_VAR_U16,  0, 103),
 
	SLE_CONDVAR(Company, bankrupt_asked,        SLE_UINT16,                104, SL_MAX_VERSION),
 
	    SLE_VAR(Company, bankrupt_timeout,      SLE_INT16),
 
	SLE_CONDVAR(Company, bankrupt_value,        SLE_VAR_I64 | SLE_FILE_I32,  0, 64),
 
	SLE_CONDVAR(Company, bankrupt_value,        SLE_INT64,                  65, SL_MAX_VERSION),
 

	
 
	/* yearly expenses was changed to 64-bit in savegame version 2. */
 
	SLE_CONDARR(Company, yearly_expenses,       SLE_FILE_I32 | SLE_VAR_I64, 3 * 13, 0, 1),
 
	SLE_CONDARR(Company, yearly_expenses,       SLE_INT64, 3 * 13,                  2, SL_MAX_VERSION),
 

	
 
	SLE_CONDVAR(Company, is_ai,                 SLE_BOOL, 2, SL_MAX_VERSION),
 
	SLE_CONDNULL(1, 4, 99),
 

	
 
	/* Engine renewal settings */
 
	SLE_CONDNULL(512, 16, 18),
 
	SLE_CONDREF(Company, engine_renew_list,     REF_ENGINE_RENEWS,          19, SL_MAX_VERSION),
 
	SLE_CONDVAR(Company, engine_renew,          SLE_BOOL,                   16, SL_MAX_VERSION),
 
	SLE_CONDVAR(Company, engine_renew_months,   SLE_INT16,                  16, SL_MAX_VERSION),
 
	SLE_CONDVAR(Company, engine_renew_money,    SLE_UINT32,                 16, SL_MAX_VERSION),
 
	SLE_CONDVAR(Company, renew_keep_length,     SLE_BOOL,                    2, SL_MAX_VERSION), // added with 16.1, but was blank since 2
 

	
 
	/* reserve extra space in savegame here. (currently 63 bytes) */
 
	SLE_CONDNULL(63, 2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _company_economy_desc[] = {
 
	/* these were changed to 64-bit in savegame format 2 */
 
	SLE_CONDVAR(CompanyEconomyEntry, income,              SLE_FILE_I32 | SLE_VAR_I64, 0, 1),
 
	SLE_CONDVAR(CompanyEconomyEntry, income,              SLE_INT64,                  2, SL_MAX_VERSION),
 
	SLE_CONDVAR(CompanyEconomyEntry, expenses,            SLE_FILE_I32 | SLE_VAR_I64, 0, 1),
 
	SLE_CONDVAR(CompanyEconomyEntry, expenses,            SLE_INT64,                  2, SL_MAX_VERSION),
 
	SLE_CONDVAR(CompanyEconomyEntry, company_value,       SLE_FILE_I32 | SLE_VAR_I64, 0, 1),
 
	SLE_CONDVAR(CompanyEconomyEntry, company_value,       SLE_INT64,                  2, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(CompanyEconomyEntry, delivered_cargo,     SLE_INT32),
 
	    SLE_VAR(CompanyEconomyEntry, performance_history, SLE_INT32),
 

	
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _company_livery_desc[] = {
 
	SLE_CONDVAR(Livery, in_use,  SLE_BOOL,  34, SL_MAX_VERSION),
 
	SLE_CONDVAR(Livery, colour1, SLE_UINT8, 34, SL_MAX_VERSION),
 
	SLE_CONDVAR(Livery, colour2, SLE_UINT8, 34, SL_MAX_VERSION),
 
	SLE_END()
 
};
 

	
 
static void SaveLoad_PLYR(Company *c)
 
{
 
	int i;
 

	
 
	SlObject(c, _company_desc);
 

	
 
	/* Write AI? */
 
	if (!IsHumanCompany(c->index)) {
 
		SaveLoad_AI(c->index);
 
	}
 

	
 
	/* Write economy */
 
	SlObject(&c->cur_economy, _company_economy_desc);
 

	
 
	/* Write old economy entries. */
 
	for (i = 0; i < c->num_valid_stat_ent; i++) {
 
		SlObject(&c->old_economy[i], _company_economy_desc);
 
	}
 

	
 
	/* Write each livery entry. */
 
	int num_liveries = CheckSavegameVersion(63) ? LS_END - 4 : (CheckSavegameVersion(85) ? LS_END - 2: LS_END);
 
	for (i = 0; i < num_liveries; i++) {
 
		SlObject(&c->livery[i], _company_livery_desc);
 
	}
 

	
 
	if (num_liveries < LS_END) {
 
		/* We want to insert some liveries somewhere in between. This means some have to be moved. */
 
		memmove(&c->livery[LS_FREIGHT_WAGON], &c->livery[LS_PASSENGER_WAGON_MONORAIL], (LS_END - LS_FREIGHT_WAGON) * sizeof(c->livery[0]));
 
		c->livery[LS_PASSENGER_WAGON_MONORAIL] = c->livery[LS_MONORAIL];
 
		c->livery[LS_PASSENGER_WAGON_MAGLEV]   = c->livery[LS_MAGLEV];
 
	}
 

	
 
	if (num_liveries == LS_END - 4) {
 
		/* Copy bus/truck liveries over to trams */
 
		c->livery[LS_PASSENGER_TRAM] = c->livery[LS_BUS];
 
		c->livery[LS_FREIGHT_TRAM]   = c->livery[LS_TRUCK];
 
	}
 
}
 

	
 
static void Save_PLYR()
 
{
 
	Company *c;
 
	FOR_ALL_COMPANIES(c) {
 
		SlSetArrayIndex(c->index);
 
		SlAutolength((AutolengthProc*)SaveLoad_PLYR, c);
 
	}
 
}
 

	
 
static void Load_PLYR()
 
{
 
	int index;
 
	while ((index = SlIterateArray()) != -1) {
 
		Company *c = new (index) Company();
 
		SaveLoad_PLYR(c);
 
		_company_colours[index] = c->colour;
 

	
 
		/* This is needed so an AI is attached to a loaded AI */
 
		if (c->is_ai && (!_networking || _network_server) && _ai.enabled) {
 
			/* Clear the memory of the new AI, otherwise we might be doing wrong things. */
 
			memset(&_companies_ainew[index], 0, sizeof(CompanyAiNew));
 
			AI_StartNewAI(c->index);
 
		}
 
	}
 
}
 

	
 
extern const ChunkHandler _company_chunk_handlers[] = {
 
	{ 'PLYR', Save_PLYR, Load_PLYR, CH_ARRAY | CH_LAST},
 
};
src/company_manager_face.h
Show inline comments
 
@@ -7,6 +7,8 @@
 

	
 
#include "core/random_func.hpp"
 
#include "core/bitmath_func.hpp"
 
#include "table/sprites.h"
 
#include "company_type.h"
 

	
 
/** The gender/race combinations that we have faces for */
 
enum GenderEthnicity {
 
@@ -228,7 +230,6 @@ static inline SpriteID GetCompanyManager
 
}
 

	
 
void DrawCompanyManagerFace(CompanyManagerFace face, int color, int x, int y);
 
CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32 face);
 
bool IsValidCompanyManagerFace(CompanyManagerFace cmf);
 

	
 
#endif /* COMPANY_MANAGER_FACE_H */
src/console_cmds.cpp
Show inline comments
 
@@ -8,7 +8,7 @@
 
#include "debug.h"
 
#include "engine_func.h"
 
#include "landscape.h"
 
#include "saveload.h"
 
#include "saveload/saveload.h"
 
#include "variables.h"
 
#include "network/network.h"
 
#include "network/network_func.h"
src/date.cpp
Show inline comments
 
@@ -15,7 +15,7 @@
 
#include "vehicle_base.h"
 
#include "debug.h"
 
#include "rail_gui.h"
 
#include "saveload.h"
 
#include "saveload/saveload.h"
 

	
 
Year      _cur_year;   ///< Current year, starting at 0
 
Month     _cur_month;  ///< Current month (0..11)
src/depot.cpp
Show inline comments
 
@@ -3,10 +3,8 @@
 
/** @file depot.cpp Handling of depots. */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "depot_base.h"
 
#include "landscape.h"
 
#include "saveload.h"
 
#include "order_func.h"
 
#include "window_func.h"
 
#include "oldpool_func.h"
 
@@ -51,35 +49,3 @@ void InitializeDepots()
 
	_Depot_pool.CleanPool();
 
	_Depot_pool.AddBlockToPool();
 
}
 

	
 

	
 
static const SaveLoad _depot_desc[] = {
 
	SLE_CONDVAR(Depot, xy,         SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
 
	SLE_CONDVAR(Depot, xy,         SLE_UINT32,                 6, SL_MAX_VERSION),
 
	    SLE_VAR(Depot, town_index, SLE_UINT16),
 
	SLE_END()
 
};
 

	
 
static void Save_DEPT()
 
{
 
	Depot *depot;
 

	
 
	FOR_ALL_DEPOTS(depot) {
 
		SlSetArrayIndex(depot->index);
 
		SlObject(depot, _depot_desc);
 
	}
 
}
 

	
 
static void Load_DEPT()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		Depot *depot = new (index) Depot();
 
		SlObject(depot, _depot_desc);
 
	}
 
}
 

	
 
extern const ChunkHandler _depot_chunk_handlers[] = {
 
	{ 'DEPT', Save_DEPT, Load_DEPT, CH_ARRAY | CH_LAST},
 
};
src/economy.cpp
Show inline comments
 
@@ -9,7 +9,6 @@
 
#include "company_base.h"
 
#include "company_func.h"
 
#include "command_func.h"
 
#include "saveload.h"
 
#include "industry.h"
 
#include "industry_map.h"
 
#include "town.h"
 
@@ -767,7 +766,7 @@ void SetPriceBaseMultiplier(uint price, 
 
 * Initialize the variables that will maintain the daily industry change system.
 
 * @param init_counter specifies if the counter is required to be initialized
 
 */
 
static void StartupIndustryDailyChanges(bool init_counter)
 
void StartupIndustryDailyChanges(bool init_counter)
 
{
 
	uint map_size = MapLogX() + MapLogY();
 
	/* After getting map size, it needs to be scaled appropriately and divided by 31,
 
@@ -1121,37 +1120,6 @@ no_add:;
 
		InvalidateWindow(WC_SUBSIDIES_LIST, 0);
 
}
 

	
 
static const SaveLoad _subsidies_desc[] = {
 
	    SLE_VAR(Subsidy, cargo_type, SLE_UINT8),
 
	    SLE_VAR(Subsidy, age,        SLE_UINT8),
 
	SLE_CONDVAR(Subsidy, from,       SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
 
	SLE_CONDVAR(Subsidy, from,       SLE_UINT16,                5, SL_MAX_VERSION),
 
	SLE_CONDVAR(Subsidy, to,         SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
 
	SLE_CONDVAR(Subsidy, to,         SLE_UINT16,                5, SL_MAX_VERSION),
 
	SLE_END()
 
};
 

	
 
static void Save_SUBS()
 
{
 
	int i;
 
	Subsidy *s;
 

	
 
	for (i = 0; i != lengthof(_subsidies); i++) {
 
		s = &_subsidies[i];
 
		if (s->cargo_type != CT_INVALID) {
 
			SlSetArrayIndex(i);
 
			SlObject(s, _subsidies_desc);
 
		}
 
	}
 
}
 

	
 
static void Load_SUBS()
 
{
 
	int index;
 
	while ((index = SlIterateArray()) != -1)
 
		SlObject(&_subsidies[index], _subsidies_desc);
 
}
 

	
 
Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type)
 
{
 
	const CargoSpec *cs = GetCargo(cargo_type);
 
@@ -1994,54 +1962,3 @@ CommandCost CmdBuyCompany(TileIndex tile
 
	}
 
	return CommandCost(EXPENSES_OTHER, c->bankrupt_value);
 
}
 

	
 
/** Prices */
 
static void SaveLoad_PRIC()
 
{
 
	int vt = CheckSavegameVersion(65) ? (SLE_FILE_I32 | SLE_VAR_I64) : SLE_INT64;
 
	SlArray(&_price,      NUM_PRICES, vt);
 
	SlArray(&_price_frac, NUM_PRICES, SLE_UINT16);
 
}
 

	
 
/** Cargo payment rates */
 
static void SaveLoad_CAPR()
 
{
 
	uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO;
 
	int vt = CheckSavegameVersion(65) ? (SLE_FILE_I32 | SLE_VAR_I64) : SLE_INT64;
 
	SlArray(&_cargo_payment_rates,      num_cargo, vt);
 
	SlArray(&_cargo_payment_rates_frac, num_cargo, SLE_UINT16);
 
}
 

	
 
static const SaveLoad _economy_desc[] = {
 
	SLE_CONDVAR(Economy, max_loan,                      SLE_FILE_I32 | SLE_VAR_I64,  0, 64),
 
	SLE_CONDVAR(Economy, max_loan,                      SLE_INT64,                  65, SL_MAX_VERSION),
 
	SLE_CONDVAR(Economy, max_loan_unround,              SLE_FILE_I32 | SLE_VAR_I64,  0, 64),
 
	SLE_CONDVAR(Economy, max_loan_unround,              SLE_INT64,                  65, SL_MAX_VERSION),
 
	SLE_CONDVAR(Economy, max_loan_unround_fract,        SLE_UINT16,                 70, SL_MAX_VERSION),
 
	    SLE_VAR(Economy, fluct,                         SLE_INT16),
 
	    SLE_VAR(Economy, interest_rate,                 SLE_UINT8),
 
	    SLE_VAR(Economy, infl_amount,                   SLE_UINT8),
 
	    SLE_VAR(Economy, infl_amount_pr,                SLE_UINT8),
 
	SLE_CONDVAR(Economy, industry_daily_change_counter, SLE_UINT32,                102, SL_MAX_VERSION),
 
	    SLE_END()
 
};
 

	
 
/** Economy variables */
 
static void Save_ECMY()
 
{
 
	SlObject(&_economy, _economy_desc);
 
}
 

	
 
/** Economy variables */
 
static void Load_ECMY()
 
{
 
	SlObject(&_economy, _economy_desc);
 
	StartupIndustryDailyChanges(CheckSavegameVersion(102));  // old savegames will need to be initialized
 
}
 

	
 
extern const ChunkHandler _economy_chunk_handlers[] = {
 
	{ 'PRIC', SaveLoad_PRIC, SaveLoad_PRIC, CH_RIFF | CH_AUTO_LENGTH},
 
	{ 'CAPR', SaveLoad_CAPR, SaveLoad_CAPR, CH_RIFF | CH_AUTO_LENGTH},
 
	{ 'SUBS', Save_SUBS,     Load_SUBS,     CH_ARRAY},
 
	{ 'ECMY', Save_ECMY,     Load_ECMY,     CH_RIFF | CH_LAST},
 
};
src/economy_func.h
Show inline comments
 
@@ -34,6 +34,7 @@ Pair SetupSubsidyDecodeParam(const Subsi
 
void DeleteSubsidyWithTown(TownID index);
 
void DeleteSubsidyWithIndustry(IndustryID index);
 
void DeleteSubsidyWithStation(StationID index);
 
void StartupIndustryDailyChanges(bool init_counter);
 

	
 
Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type);
 
uint MoveGoodsToStation(TileIndex tile, int w, int h, CargoID type, uint amount);
src/effectvehicle.cpp
Show inline comments
 
@@ -15,7 +15,6 @@
 
#include "gfx_func.h"
 
#include "news_func.h"
 
#include "command_func.h"
 
#include "saveload.h"
 
#include "company_func.h"
 
#include "debug.h"
 
#include "vehicle_gui.h"
src/engine.cpp
Show inline comments
 
@@ -9,7 +9,6 @@
 
#include "company_func.h"
 
#include "command_func.h"
 
#include "news_func.h"
 
#include "saveload.h"
 
#include "variables.h"
 
#include "train.h"
 
#include "aircraft.h"
 
@@ -27,7 +26,6 @@
 
#include "oldpool_func.h"
 
#include "core/alloc_func.hpp"
 
#include "vehicle_func.h"
 
#include <map>
 

	
 
#include "table/strings.h"
 
#include "table/engines.h"
 
@@ -613,112 +611,3 @@ CargoID GetEngineCargoType(EngineID engi
 
		default: NOT_REACHED(); return CT_INVALID;
 
	}
 
}
 

	
 
static const SaveLoad _engine_desc[] = {
 
	SLE_CONDVAR(Engine, intro_date,          SLE_FILE_U16 | SLE_VAR_I32,  0,  30),
 
	SLE_CONDVAR(Engine, intro_date,          SLE_INT32,                  31, SL_MAX_VERSION),
 
	SLE_CONDVAR(Engine, age,                 SLE_FILE_U16 | SLE_VAR_I32,  0,  30),
 
	SLE_CONDVAR(Engine, age,                 SLE_INT32,                  31, SL_MAX_VERSION),
 
	    SLE_VAR(Engine, reliability,         SLE_UINT16),
 
	    SLE_VAR(Engine, reliability_spd_dec, SLE_UINT16),
 
	    SLE_VAR(Engine, reliability_start,   SLE_UINT16),
 
	    SLE_VAR(Engine, reliability_max,     SLE_UINT16),
 
	    SLE_VAR(Engine, reliability_final,   SLE_UINT16),
 
	    SLE_VAR(Engine, duration_phase_1,    SLE_UINT16),
 
	    SLE_VAR(Engine, duration_phase_2,    SLE_UINT16),
 
	    SLE_VAR(Engine, duration_phase_3,    SLE_UINT16),
 

	
 
	    SLE_VAR(Engine, lifelength,          SLE_UINT8),
 
	    SLE_VAR(Engine, flags,               SLE_UINT8),
 
	    SLE_VAR(Engine, preview_company_rank,SLE_UINT8),
 
	    SLE_VAR(Engine, preview_wait,        SLE_UINT8),
 
	SLE_CONDNULL(1, 0, 44),
 
	SLE_CONDVAR(Engine, company_avail,       SLE_FILE_U8  | SLE_VAR_U16,  0, 103),
 
	SLE_CONDVAR(Engine, company_avail,       SLE_UINT16,                104, SL_MAX_VERSION),
 
	SLE_CONDSTR(Engine, name,                SLE_STR, 0,                 84, SL_MAX_VERSION),
 

	
 
	/* reserve extra space in savegame here. (currently 16 bytes) */
 
	SLE_CONDNULL(16, 2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
static std::map<EngineID, Engine> _temp_engine;
 

	
 
Engine *GetTempDataEngine(EngineID index)
 
{
 
	return &_temp_engine[index];
 
}
 

	
 
static void Save_ENGN()
 
{
 
	Engine *e;
 
	FOR_ALL_ENGINES(e) {
 
		SlSetArrayIndex(e->index);
 
		SlObject(e, _engine_desc);
 
	}
 
}
 

	
 
static void Load_ENGN()
 
{
 
	/* As engine data is loaded before engines are initialized we need to load
 
	 * this information into a temporary array. This is then copied into the
 
	 * engine pool after processing NewGRFs by CopyTempEngineData(). */
 
	int index;
 
	while ((index = SlIterateArray()) != -1) {
 
		Engine *e = GetTempDataEngine(index);
 
		SlObject(e, _engine_desc);
 
	}
 
}
 

	
 
/**
 
 * Copy data from temporary engine array into the real engine pool.
 
 */
 
void CopyTempEngineData()
 
{
 
	Engine *e;
 
	FOR_ALL_ENGINES(e) {
 
		if (e->index >= _temp_engine.size()) break;
 

	
 
		const Engine *se = GetTempDataEngine(e->index);
 
		e->intro_date          = se->intro_date;
 
		e->age                 = se->age;
 
		e->reliability         = se->reliability;
 
		e->reliability_spd_dec = se->reliability_spd_dec;
 
		e->reliability_start   = se->reliability_start;
 
		e->reliability_max     = se->reliability_max;
 
		e->reliability_final   = se->reliability_final;
 
		e->duration_phase_1    = se->duration_phase_1;
 
		e->duration_phase_2    = se->duration_phase_2;
 
		e->duration_phase_3    = se->duration_phase_3;
 
		e->lifelength          = se->lifelength;
 
		e->flags               = se->flags;
 
		e->preview_company_rank= se->preview_company_rank;
 
		e->preview_wait        = se->preview_wait;
 
		e->company_avail       = se->company_avail;
 
		if (se->name != NULL) e->name = strdup(se->name);
 
	}
 

	
 
	/* Get rid of temporary data */
 
	_temp_engine.clear();
 
}
 

	
 
static void Load_ENGS()
 
{
 
	/* Load old separate String ID list into a temporary array. This
 
	 * was always 256 entries. */
 
	StringID names[256];
 

	
 
	SlArray(names, lengthof(names), SLE_STRINGID);
 

	
 
	/* Copy each string into the temporary engine array. */
 
	for (EngineID engine = 0; engine < lengthof(names); engine++) {
 
		Engine *e = GetTempDataEngine(engine);
 
		e->name = CopyFromOldName(names[engine]);
 
	}
 
}
 

	
 
extern const ChunkHandler _engine_chunk_handlers[] = {
 
	{ 'ENGN', Save_ENGN,     Load_ENGN,     CH_ARRAY          },
 
	{ 'ENGS', NULL,          Load_ENGS,     CH_RIFF | CH_LAST },
 
};
src/gamelog.cpp
Show inline comments
 
@@ -4,7 +4,7 @@
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "saveload.h"
 
#include "saveload/saveload.h"
 
#include "core/alloc_func.hpp"
 
#include "core/bitmath_func.hpp"
 
#include "core/math_func.hpp"
 
@@ -13,13 +13,15 @@
 
#include "string_func.h"
 
#include "settings_type.h"
 
#include "newgrf_config.h"
 
#include <string.h>
 
#include <stdarg.h>
 
#include "gamelog.h"
 
#include "gamelog_internal.h"
 
#include "console_func.h"
 
#include "debug.h"
 
#include "rev.h"
 

	
 
#include <string.h>
 
#include <stdarg.h>
 

	
 
extern const uint16 SAVEGAME_VERSION;  ///< current savegame version
 

	
 
extern SavegameType _savegame_type; ///< type of savegame we are loading
 
@@ -28,79 +30,11 @@ extern uint32 _ttdp_version;     ///< ve
 
extern uint16 _sl_version;       ///< the major savegame version identifier
 
extern byte   _sl_minor_version; ///< the minor savegame version, DO NOT USE!
 

	
 
/** Type of logged change */
 
enum GamelogChangeType {
 
	GLCT_MODE,        ///< Scenario editor x Game, different landscape
 
	GLCT_REVISION,    ///< Changed game revision string
 
	GLCT_OLDVER,      ///< Loaded from savegame without logged data
 
	GLCT_PATCH,       ///< Non-networksafe patch value changed
 
	GLCT_GRFADD,      ///< Removed GRF
 
	GLCT_GRFREM,      ///< Added GRF
 
	GLCT_GRFCOMPAT,   ///< Loading compatible GRF
 
	GLCT_GRFPARAM,    ///< GRF parameter changed
 
	GLCT_GRFMOVE,     ///< GRF order changed
 
	GLCT_GRFBUG,      ///< GRF bug triggered
 
	GLCT_END,         ///< So we know how many GLCTs are there
 
	GLCT_NONE = 0xFF, ///< In savegames, end of list
 
};
 

	
 

	
 
/** Contains information about one logged change */
 
struct LoggedChange {
 
	GamelogChangeType ct; ///< Type of change logged in this struct
 
	union {
 
		struct {
 
			byte mode;       ///< new game mode - Editor x Game
 
			byte landscape;  ///< landscape (temperate, arctic, ...)
 
		} mode;
 
		struct {
 
			char text[NETWORK_REVISION_LENGTH]; ///< revision string, _openttd_revision
 
			uint32 newgrf;   ///< _openttd_newgrf_version
 
			uint16 slver;    ///< _sl_version
 
			byte modified;   ///< _openttd_revision_modified
 
		} revision;
 
		struct {
 
			uint32 type;     ///< type of savegame, @see SavegameType
 
			uint32 version;  ///< major and minor version OR ttdp version
 
		} oldver;
 
		GRFIdentifier grfadd;    ///< ID and md5sum of added GRF
 
		struct {
 
			uint32 grfid;    ///< ID of removed GRF
 
		} grfrem;
 
		GRFIdentifier grfcompat; ///< ID and new md5sum of changed GRF
 
		struct {
 
			uint32 grfid;    ///< ID of GRF with changed parameters
 
		} grfparam;
 
		struct {
 
			uint32 grfid;    ///< ID of moved GRF
 
			int32 offset;    ///< offset, positive = move down
 
		} grfmove;
 
		struct {
 
			char *name;      ///< name of the patch
 
			int32 oldval;    ///< old value
 
			int32 newval;    ///< new value
 
		} patch;
 
		struct {
 
			uint64 data;     ///< additional data
 
			uint32 grfid;    ///< ID of problematic GRF
 
			byte bug;        ///< type of bug, @see enum GRFBugs
 
		} grfbug;
 
	};
 
};
 

	
 

	
 
/** Contains information about one logged action that caused at least one logged change */
 
struct LoggedAction {
 
	LoggedChange *change; ///< First logged change in this action
 
	uint32 changes;       ///< Number of changes in this action
 
	GamelogActionType at; ///< Type of action
 
	uint16 tick;          ///< Tick when it happened
 
};
 

	
 
static GamelogActionType _gamelog_action_type = GLAT_NONE; ///< action to record if anything changes
 

	
 
static LoggedAction *_gamelog_action = NULL; ///< first logged action
 
static uint _gamelog_actions         = 0;    ///< number of actions
 
LoggedAction *_gamelog_action = NULL;        ///< first logged action
 
uint _gamelog_actions         = 0;           ///< number of actions
 
static LoggedAction *_current_action = NULL; ///< current action we are logging, NULL when there is no action active
 

	
 

	
 
@@ -728,155 +662,3 @@ void GamelogGRFUpdate(const GRFConfig *o
 
	free(ol);
 
	free(nl);
 
}
 

	
 

	
 
static const SaveLoad _glog_action_desc[] = {
 
	SLE_VAR(LoggedAction, tick,              SLE_UINT16),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_mode_desc[] = {
 
	SLE_VAR(LoggedChange, mode.mode,         SLE_UINT8),
 
	SLE_VAR(LoggedChange, mode.landscape,    SLE_UINT8),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_revision_desc[] = {
 
	SLE_ARR(LoggedChange, revision.text,     SLE_UINT8,  NETWORK_REVISION_LENGTH),
 
	SLE_VAR(LoggedChange, revision.newgrf,   SLE_UINT32),
 
	SLE_VAR(LoggedChange, revision.slver,    SLE_UINT16),
 
	SLE_VAR(LoggedChange, revision.modified, SLE_UINT8),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_oldver_desc[] = {
 
	SLE_VAR(LoggedChange, oldver.type,       SLE_UINT32),
 
	SLE_VAR(LoggedChange, oldver.version,    SLE_UINT32),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_patch_desc[] = {
 
	SLE_STR(LoggedChange, patch.name,        SLE_STR,    128),
 
	SLE_VAR(LoggedChange, patch.oldval,      SLE_INT32),
 
	SLE_VAR(LoggedChange, patch.newval,      SLE_INT32),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_grfadd_desc[] = {
 
	SLE_VAR(LoggedChange, grfadd.grfid,      SLE_UINT32    ),
 
	SLE_ARR(LoggedChange, grfadd.md5sum,     SLE_UINT8,  16),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_grfrem_desc[] = {
 
	SLE_VAR(LoggedChange, grfrem.grfid,      SLE_UINT32),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_grfcompat_desc[] = {
 
	SLE_VAR(LoggedChange, grfcompat.grfid,   SLE_UINT32    ),
 
	SLE_ARR(LoggedChange, grfcompat.md5sum,  SLE_UINT8,  16),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_grfparam_desc[] = {
 
	SLE_VAR(LoggedChange, grfparam.grfid,    SLE_UINT32),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_grfmove_desc[] = {
 
	SLE_VAR(LoggedChange, grfmove.grfid,     SLE_UINT32),
 
	SLE_VAR(LoggedChange, grfmove.offset,    SLE_INT32),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_grfbug_desc[] = {
 
	SLE_VAR(LoggedChange, grfbug.data,       SLE_UINT64),
 
	SLE_VAR(LoggedChange, grfbug.grfid,      SLE_UINT32),
 
	SLE_VAR(LoggedChange, grfbug.bug,        SLE_UINT8),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad *_glog_desc[] = {
 
	_glog_mode_desc,
 
	_glog_revision_desc,
 
	_glog_oldver_desc,
 
	_glog_patch_desc,
 
	_glog_grfadd_desc,
 
	_glog_grfrem_desc,
 
	_glog_grfcompat_desc,
 
	_glog_grfparam_desc,
 
	_glog_grfmove_desc,
 
	_glog_grfbug_desc,
 
};
 

	
 
assert_compile(lengthof(_glog_desc) == GLCT_END);
 

	
 
static void Load_GLOG()
 
{
 
	assert(_gamelog_action == NULL);
 
	assert(_gamelog_actions == 0);
 

	
 
	GamelogActionType at;
 
	while ((at = (GamelogActionType)SlReadByte()) != GLAT_NONE) {
 
		_gamelog_action = ReallocT(_gamelog_action, _gamelog_actions + 1);
 
		LoggedAction *la = &_gamelog_action[_gamelog_actions++];
 

	
 
		la->at = at;
 

	
 
		SlObject(la, _glog_action_desc); // has to be saved after 'DATE'!
 
		la->change = NULL;
 
		la->changes = 0;
 

	
 
		GamelogChangeType ct;
 
		while ((ct = (GamelogChangeType)SlReadByte()) != GLCT_NONE) {
 
			la->change = ReallocT(la->change, la->changes + 1);
 

	
 
			LoggedChange *lc = &la->change[la->changes++];
 
			/* for SLE_STR, pointer has to be valid! so make it NULL */
 
			memset(lc, 0, sizeof(*lc));
 
			lc->ct = ct;
 

	
 
			assert((uint)ct < GLCT_END);
 

	
 
			SlObject(lc, _glog_desc[ct]);
 
		}
 
	}
 
}
 

	
 
static void Save_GLOG()
 
{
 
	const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
 
	size_t length = 0;
 

	
 
	for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
 
		const LoggedChange *lcend = &la->change[la->changes];
 
		for (LoggedChange *lc = la->change; lc != lcend; lc++) {
 
			assert((uint)lc->ct < lengthof(_glog_desc));
 
			length += SlCalcObjLength(lc, _glog_desc[lc->ct]) + 1;
 
		}
 
		length += 4;
 
	}
 
	length++;
 

	
 
	SlSetLength(length);
 

	
 
	for (LoggedAction *la = _gamelog_action; la != laend; la++) {
 
		SlWriteByte(la->at);
 
		SlObject(la, _glog_action_desc);
 

	
 
		const LoggedChange *lcend = &la->change[la->changes];
 
		for (LoggedChange *lc = la->change; lc != lcend; lc++) {
 
			SlWriteByte(lc->ct);
 
			assert((uint)lc->ct < GLCT_END);
 
			SlObject(lc, _glog_desc[lc->ct]);
 
		}
 
		SlWriteByte(GLCT_NONE);
 
	}
 
	SlWriteByte(GLAT_NONE);
 
}
 

	
 

	
 
extern const ChunkHandler _gamelog_chunk_handlers[] = {
 
	{ 'GLOG', Save_GLOG, Load_GLOG, CH_RIFF | CH_LAST }
 
};
src/gamelog_internal.h
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file gamelog_internal.h Declaration shared among gamelog.cpp and saveload/gamelog_sl.cpp */
 

	
 
#ifndef GAMELOG_INTERNAL_H
 
#define GAMELOG_INTERNAL_H
 

	
 
#include "network/core/config.h"
 

	
 
/** Type of logged change */
 
enum GamelogChangeType {
 
	GLCT_MODE,        ///< Scenario editor x Game, different landscape
 
	GLCT_REVISION,    ///< Changed game revision string
 
	GLCT_OLDVER,      ///< Loaded from savegame without logged data
 
	GLCT_PATCH,       ///< Non-networksafe patch value changed
 
	GLCT_GRFADD,      ///< Removed GRF
 
	GLCT_GRFREM,      ///< Added GRF
 
	GLCT_GRFCOMPAT,   ///< Loading compatible GRF
 
	GLCT_GRFPARAM,    ///< GRF parameter changed
 
	GLCT_GRFMOVE,     ///< GRF order changed
 
	GLCT_GRFBUG,      ///< GRF bug triggered
 
	GLCT_END,         ///< So we know how many GLCTs are there
 
	GLCT_NONE = 0xFF, ///< In savegames, end of list
 
};
 

	
 

	
 
/** Contains information about one logged change */
 
struct LoggedChange {
 
	GamelogChangeType ct; ///< Type of change logged in this struct
 
	union {
 
		struct {
 
			byte mode;       ///< new game mode - Editor x Game
 
			byte landscape;  ///< landscape (temperate, arctic, ...)
 
		} mode;
 
		struct {
 
			char text[NETWORK_REVISION_LENGTH]; ///< revision string, _openttd_revision
 
			uint32 newgrf;   ///< _openttd_newgrf_version
 
			uint16 slver;    ///< _sl_version
 
			byte modified;   ///< _openttd_revision_modified
 
		} revision;
 
		struct {
 
			uint32 type;     ///< type of savegame, @see SavegameType
 
			uint32 version;  ///< major and minor version OR ttdp version
 
		} oldver;
 
		GRFIdentifier grfadd;    ///< ID and md5sum of added GRF
 
		struct {
 
			uint32 grfid;    ///< ID of removed GRF
 
		} grfrem;
 
		GRFIdentifier grfcompat; ///< ID and new md5sum of changed GRF
 
		struct {
 
			uint32 grfid;    ///< ID of GRF with changed parameters
 
		} grfparam;
 
		struct {
 
			uint32 grfid;    ///< ID of moved GRF
 
			int32 offset;    ///< offset, positive = move down
 
		} grfmove;
 
		struct {
 
			char *name;      ///< name of the patch
 
			int32 oldval;    ///< old value
 
			int32 newval;    ///< new value
 
		} patch;
 
		struct {
 
			uint64 data;     ///< additional data
 
			uint32 grfid;    ///< ID of problematic GRF
 
			byte bug;        ///< type of bug, @see enum GRFBugs
 
		} grfbug;
 
	};
 
};
 

	
 

	
 
/** Contains information about one logged action that caused at least one logged change */
 
struct LoggedAction {
 
	LoggedChange *change; ///< First logged change in this action
 
	uint32 changes;       ///< Number of changes in this action
 
	GamelogActionType at; ///< Type of action
 
	uint16 tick;          ///< Tick when it happened
 
};
 

	
 
extern LoggedAction *_gamelog_action;
 
extern uint _gamelog_actions;
 

	
 
#endif /* GAMELOG_INTERNAL_H */
src/genworld.cpp
Show inline comments
 
@@ -26,7 +26,7 @@
 
#include "newgrf_storage.h"
 
#include "water.h"
 
#include "tilehighlight_func.h"
 
#include "saveload.h"
 
#include "saveload/saveload.h"
 

	
 
#include "table/sprites.h"
 

	
src/group_cmd.cpp
Show inline comments
 
@@ -6,7 +6,6 @@
 
#include "openttd.h"
 
#include "variables.h"
 
#include "command_func.h"
 
#include "saveload.h"
 
#include "debug.h"
 
#include "group.h"
 
#include "train.h"
 
@@ -421,40 +420,3 @@ void RemoveAllGroupsForCompany(const Com
 
		if (company == g->owner) delete g;
 
	}
 
}
 

	
 

	
 
static const SaveLoad _group_desc[] = {
 
  SLE_CONDVAR(Group, name,           SLE_NAME,    0, 83),
 
  SLE_CONDSTR(Group, name,           SLE_STR, 0, 84, SL_MAX_VERSION),
 
  SLE_VAR(Group, num_vehicle,        SLE_UINT16),
 
  SLE_VAR(Group, owner,              SLE_UINT8),
 
  SLE_VAR(Group, vehicle_type,       SLE_UINT8),
 
  SLE_VAR(Group, replace_protection, SLE_BOOL),
 
  SLE_END()
 
};
 

	
 

	
 
static void Save_GROUP(void)
 
{
 
	Group *g;
 

	
 
	FOR_ALL_GROUPS(g) {
 
		SlSetArrayIndex(g->index);
 
		SlObject(g, _group_desc);
 
	}
 
}
 

	
 

	
 
static void Load_GROUP(void)
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		Group *g = new (index) Group();
 
		SlObject(g, _group_desc);
 
	}
 
}
 

	
 
extern const ChunkHandler _group_chunk_handlers[] = {
 
	{ 'GRPS', Save_GROUP, Load_GROUP, CH_ARRAY | CH_LAST},
 
};
src/heightmap.cpp
Show inline comments
 
@@ -10,7 +10,7 @@
 
#include "void_map.h"
 
#include "debug.h"
 
#include "gui.h"
 
#include "saveload.h"
 
#include "saveload/saveload.h"
 
#include "bmp.h"
 
#include "gfx_func.h"
 
#include "core/alloc_func.hpp"
src/industry_cmd.cpp
Show inline comments
 
@@ -14,7 +14,6 @@
 
#include "industry.h"
 
#include "town.h"
 
#include "news_func.h"
 
#include "saveload.h"
 
#include "variables.h"
 
#include "cheat_func.h"
 
#include "genworld.h"
 
@@ -2397,146 +2396,3 @@ extern const TileTypeProcs _tile_type_in
 
	GetFoundation_Industry,      /* get_foundation_proc */
 
	TerraformTile_Industry,      /* terraform_tile_proc */
 
};
 

	
 
static const SaveLoad _industry_desc[] = {
 
	SLE_CONDVAR(Industry, xy,                         SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Industry, xy,                         SLE_UINT32,                  6, SL_MAX_VERSION),
 
	    SLE_VAR(Industry, width,                      SLE_UINT8),
 
	    SLE_VAR(Industry, height,                     SLE_UINT8),
 
	    SLE_REF(Industry, town,                       REF_TOWN),
 
	SLE_CONDNULL( 2, 0, 60),       ///< used to be industry's produced_cargo
 
	SLE_CONDARR(Industry, produced_cargo,             SLE_UINT8,  2,              78, SL_MAX_VERSION),
 
	SLE_CONDARR(Industry, incoming_cargo_waiting,     SLE_UINT16, 3,              70, SL_MAX_VERSION),
 
	    SLE_ARR(Industry, produced_cargo_waiting,     SLE_UINT16, 2),
 
	    SLE_ARR(Industry, production_rate,            SLE_UINT8,  2),
 
	SLE_CONDNULL( 3, 0, 60),       ///< used to be industry's accepts_cargo
 
	SLE_CONDARR(Industry, accepts_cargo,              SLE_UINT8,  3,              78, SL_MAX_VERSION),
 
	    SLE_VAR(Industry, prod_level,                 SLE_UINT8),
 
	    SLE_ARR(Industry, this_month_production,      SLE_UINT16, 2),
 
	    SLE_ARR(Industry, this_month_transported,     SLE_UINT16, 2),
 
	    SLE_ARR(Industry, last_month_pct_transported, SLE_UINT8,  2),
 
	    SLE_ARR(Industry, last_month_production,      SLE_UINT16, 2),
 
	    SLE_ARR(Industry, last_month_transported,     SLE_UINT16, 2),
 

	
 
	    SLE_VAR(Industry, counter,                    SLE_UINT16),
 

	
 
	    SLE_VAR(Industry, type,                       SLE_UINT8),
 
	    SLE_VAR(Industry, owner,                      SLE_UINT8),
 
	    SLE_VAR(Industry, random_color,               SLE_UINT8),
 
	SLE_CONDVAR(Industry, last_prod_year,             SLE_FILE_U8 | SLE_VAR_I32,  0, 30),
 
	SLE_CONDVAR(Industry, last_prod_year,             SLE_INT32,                 31, SL_MAX_VERSION),
 
	    SLE_VAR(Industry, was_cargo_delivered,        SLE_UINT8),
 

	
 
	SLE_CONDVAR(Industry, founder,                    SLE_UINT8,                 70, SL_MAX_VERSION),
 
	SLE_CONDVAR(Industry, construction_date,          SLE_INT32,                 70, SL_MAX_VERSION),
 
	SLE_CONDVAR(Industry, construction_type,          SLE_UINT8,                 70, SL_MAX_VERSION),
 
	SLE_CONDVAR(Industry, last_cargo_accepted_at,     SLE_INT32,                 70, SL_MAX_VERSION),
 
	SLE_CONDVAR(Industry, selected_layout,            SLE_UINT8,                 73, SL_MAX_VERSION),
 

	
 
	SLE_CONDARRX(cpp_offsetof(Industry, psa) + cpp_offsetof(Industry::PersistentStorage, storage), SLE_UINT32, 16, 76, SL_MAX_VERSION),
 

	
 
	SLE_CONDVAR(Industry, random_triggers,            SLE_UINT8,                 82, SL_MAX_VERSION),
 
	SLE_CONDVAR(Industry, random,                     SLE_UINT16,                82, SL_MAX_VERSION),
 

	
 
	/* reserve extra space in savegame here. (currently 32 bytes) */
 
	SLE_CONDNULL(32, 2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
static void Save_INDY()
 
{
 
	Industry *ind;
 

	
 
	/* Write the industries */
 
	FOR_ALL_INDUSTRIES(ind) {
 
		SlSetArrayIndex(ind->index);
 
		SlObject(ind, _industry_desc);
 
	}
 
}
 

	
 
/* Save and load the mapping between the industry/tile id on the map, and the grf file
 
 * it came from. */
 
static const SaveLoad _industries_id_mapping_desc[] = {
 
	SLE_VAR(EntityIDMapping, grfid,         SLE_UINT32),
 
	SLE_VAR(EntityIDMapping, entity_id,     SLE_UINT8),
 
	SLE_VAR(EntityIDMapping, substitute_id, SLE_UINT8),
 
	SLE_END()
 
};
 

	
 
static void Save_IIDS()
 
{
 
	uint i;
 
	uint j = _industry_mngr.GetMaxMapping();
 

	
 
	for (i = 0; i < j; i++) {
 
		SlSetArrayIndex(i);
 
		SlObject(&_industry_mngr.mapping_ID[i], _industries_id_mapping_desc);
 
	}
 
}
 

	
 
static void Save_TIDS()
 
{
 
	uint i;
 
	uint j = _industile_mngr.GetMaxMapping();
 

	
 
	for (i = 0; i < j; i++) {
 
		SlSetArrayIndex(i);
 
		SlObject(&_industile_mngr.mapping_ID[i], _industries_id_mapping_desc);
 
	}
 
}
 

	
 
static void Load_INDY()
 
{
 
	int index;
 

	
 
	ResetIndustryCounts();
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		Industry *i = new (index) Industry();
 
		SlObject(i, _industry_desc);
 
		IncIndustryTypeCount(i->type);
 
	}
 
}
 

	
 
static void Load_IIDS()
 
{
 
	int index;
 
	uint max_id;
 

	
 
	/* clear the current mapping stored.
 
	 * This will create the manager if ever it is not yet done */
 
	_industry_mngr.ResetMapping();
 

	
 
	/* get boundary for the temporary map loader NUM_INDUSTRYTYPES? */
 
	max_id = _industry_mngr.GetMaxMapping();
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		if ((uint)index >= max_id) break;
 
		SlObject(&_industry_mngr.mapping_ID[index], _industries_id_mapping_desc);
 
	}
 
}
 

	
 
static void Load_TIDS()
 
{
 
	int index;
 
	uint max_id;
 

	
 
	/* clear the current mapping stored.
 
	 * This will create the manager if ever it is not yet done */
 
	_industile_mngr.ResetMapping();
 

	
 
	/* get boundary for the temporary map loader NUM_INDUSTILES? */
 
	max_id = _industile_mngr.GetMaxMapping();
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		if ((uint)index >= max_id) break;
 
		SlObject(&_industile_mngr.mapping_ID[index], _industries_id_mapping_desc);
 
	}
 
}
 

	
 
extern const ChunkHandler _industry_chunk_handlers[] = {
 
	{ 'INDY', Save_INDY, Load_INDY, CH_ARRAY},
 
	{ 'IIDS', Save_IIDS, Load_IIDS, CH_ARRAY},
 
	{ 'TIDS', Save_TIDS, Load_TIDS, CH_ARRAY | CH_LAST},
 
};
src/misc.cpp
Show inline comments
 
@@ -7,7 +7,6 @@
 
#include "currency.h"
 
#include "landscape.h"
 
#include "news_func.h"
 
#include "saveload.h"
 
#include "vehicle_gui.h"
 
#include "variables.h"
 
#include "cheat_func.h"
 
@@ -134,290 +133,3 @@ void InitializeLandscapeVariables(bool o
 
		_cargo_payment_rates_frac[i] = 0;
 
	}
 
}
 

	
 
static const SaveLoadGlobVarList _date_desc[] = {
 
	SLEG_CONDVAR(_date,                   SLE_FILE_U16 | SLE_VAR_I32,  0,  30),
 
	SLEG_CONDVAR(_date,                   SLE_INT32,                  31, SL_MAX_VERSION),
 
	    SLEG_VAR(_date_fract,             SLE_UINT16),
 
	    SLEG_VAR(_tick_counter,           SLE_UINT16),
 
	    SLEG_VAR(_vehicle_id_ctr_day,     SLE_UINT16),
 
	    SLEG_VAR(_age_cargo_skip_counter, SLE_UINT8),
 
	SLE_CONDNULL(1, 0, 45),
 
	SLEG_CONDVAR(_cur_tileloop_tile,      SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLEG_CONDVAR(_cur_tileloop_tile,      SLE_UINT32,                  6, SL_MAX_VERSION),
 
	    SLEG_VAR(_disaster_delay,         SLE_UINT16),
 
	    SLEG_VAR(_station_tick_ctr,       SLE_UINT16),
 
	    SLEG_VAR(_random.state[0],        SLE_UINT32),
 
	    SLEG_VAR(_random.state[1],        SLE_UINT32),
 
	SLEG_CONDVAR(_cur_town_ctr,           SLE_FILE_U8  | SLE_VAR_U32,  0, 9),
 
	SLEG_CONDVAR(_cur_town_ctr,           SLE_UINT32,                 10, SL_MAX_VERSION),
 
	    SLEG_VAR(_cur_company_tick_index, SLE_FILE_U8  | SLE_VAR_U32),
 
	    SLEG_VAR(_next_competitor_start,  SLE_FILE_U16 | SLE_VAR_U32),
 
	    SLEG_VAR(_trees_tick_ctr,         SLE_UINT8),
 
	SLEG_CONDVAR(_pause_game,             SLE_UINT8,                   4, SL_MAX_VERSION),
 
	SLEG_CONDVAR(_cur_town_iter,          SLE_UINT32,                 11, SL_MAX_VERSION),
 
	    SLEG_END()
 
};
 

	
 
/* Save load date related variables as well as persistent tick counters
 
 * XXX: currently some unrelated stuff is just put here */
 
static void SaveLoad_DATE()
 
{
 
	SlGlobList(_date_desc);
 
}
 

	
 

	
 
static const SaveLoadGlobVarList _view_desc[] = {
 
	SLEG_CONDVAR(_saved_scrollpos_x,    SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
 
	SLEG_CONDVAR(_saved_scrollpos_x,    SLE_INT32,                  6, SL_MAX_VERSION),
 
	SLEG_CONDVAR(_saved_scrollpos_y,    SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
 
	SLEG_CONDVAR(_saved_scrollpos_y,    SLE_INT32,                  6, SL_MAX_VERSION),
 
	    SLEG_VAR(_saved_scrollpos_zoom, SLE_UINT8),
 
	    SLEG_END()
 
};
 

	
 
static void SaveLoad_VIEW()
 
{
 
	SlGlobList(_view_desc);
 
}
 

	
 
static uint32 _map_dim_x;
 
static uint32 _map_dim_y;
 

	
 
static const SaveLoadGlobVarList _map_dimensions[] = {
 
	SLEG_CONDVAR(_map_dim_x, SLE_UINT32, 6, SL_MAX_VERSION),
 
	SLEG_CONDVAR(_map_dim_y, SLE_UINT32, 6, SL_MAX_VERSION),
 
	    SLEG_END()
 
};
 

	
 
static void Save_MAPS()
 
{
 
	_map_dim_x = MapSizeX();
 
	_map_dim_y = MapSizeY();
 
	SlGlobList(_map_dimensions);
 
}
 

	
 
static void Load_MAPS()
 
{
 
	SlGlobList(_map_dimensions);
 
	AllocateMap(_map_dim_x, _map_dim_y);
 
}
 

	
 
enum {
 
	MAP_SL_BUF_SIZE = 4096
 
};
 

	
 
static void Load_MAPT()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	for (TileIndex i = 0; i != size;) {
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].type_height = buf[j];
 
	}
 
}
 

	
 
static void Save_MAPT()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size);
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].type_height;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
	}
 
}
 

	
 
static void Load_MAP1()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	for (TileIndex i = 0; i != size;) {
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m1 = buf[j];
 
	}
 
}
 

	
 
static void Save_MAP1()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size);
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m1;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
	}
 
}
 

	
 
static void Load_MAP2()
 
{
 
	SmallStackSafeStackAlloc<uint16, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	for (TileIndex i = 0; i != size;) {
 
		SlArray(buf, MAP_SL_BUF_SIZE,
 
			/* In those versions the m2 was 8 bits */
 
			CheckSavegameVersion(5) ? SLE_FILE_U8 | SLE_VAR_U16 : SLE_UINT16
 
		);
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m2 = buf[j];
 
	}
 
}
 

	
 
static void Save_MAP2()
 
{
 
	SmallStackSafeStackAlloc<uint16, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size * sizeof(uint16));
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m2;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT16);
 
	}
 
}
 

	
 
static void Load_MAP3()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	for (TileIndex i = 0; i != size;) {
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m3 = buf[j];
 
	}
 
}
 

	
 
static void Save_MAP3()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size);
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m3;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
	}
 
}
 

	
 
static void Load_MAP4()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	for (TileIndex i = 0; i != size;) {
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m4 = buf[j];
 
	}
 
}
 

	
 
static void Save_MAP4()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size);
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m4;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
	}
 
}
 

	
 
static void Load_MAP5()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	for (TileIndex i = 0; i != size;) {
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m5 = buf[j];
 
	}
 
}
 

	
 
static void Save_MAP5()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size);
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m5;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
	}
 
}
 

	
 
static void Load_MAP6()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	if (CheckSavegameVersion(42)) {
 
		for (TileIndex i = 0; i != size;) {
 
			/* 1024, otherwise we overflow on 64x64 maps! */
 
			SlArray(buf, 1024, SLE_UINT8);
 
			for (uint j = 0; j != 1024; j++) {
 
				_m[i++].m6 = GB(buf[j], 0, 2);
 
				_m[i++].m6 = GB(buf[j], 2, 2);
 
				_m[i++].m6 = GB(buf[j], 4, 2);
 
				_m[i++].m6 = GB(buf[j], 6, 2);
 
			}
 
		}
 
	} else {
 
		for (TileIndex i = 0; i != size;) {
 
			SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
			for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m6 = buf[j];
 
		}
 
	}
 
}
 

	
 
static void Save_MAP6()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size);
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m6;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
	}
 
}
 

	
 
static void Load_MAP7()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	for (TileIndex i = 0; i != size;) {
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m7 = buf[j];
 
	}
 
}
 

	
 
static void Save_MAP7()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size);
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m7;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
	}
 
}
 

	
 
extern const ChunkHandler _misc_chunk_handlers[] = {
 
	{ 'MAPS', Save_MAPS,     Load_MAPS,     CH_RIFF },
 
	{ 'MAPT', Save_MAPT,     Load_MAPT,     CH_RIFF },
 
	{ 'MAPO', Save_MAP1,     Load_MAP1,     CH_RIFF },
 
	{ 'MAP2', Save_MAP2,     Load_MAP2,     CH_RIFF },
 
	{ 'M3LO', Save_MAP3,     Load_MAP3,     CH_RIFF },
 
	{ 'M3HI', Save_MAP4,     Load_MAP4,     CH_RIFF },
 
	{ 'MAP5', Save_MAP5,     Load_MAP5,     CH_RIFF },
 
	{ 'MAPE', Save_MAP6,     Load_MAP6,     CH_RIFF },
 
	{ 'MAP7', Save_MAP7,     Load_MAP7,     CH_RIFF },
 

	
 
	{ 'DATE', SaveLoad_DATE, SaveLoad_DATE, CH_RIFF},
 
	{ 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, CH_RIFF | CH_LAST},
 
};
src/misc_gui.cpp
Show inline comments
 
@@ -9,7 +9,7 @@
 
#include "landscape.h"
 
#include "newgrf.h"
 
#include "newgrf_text.h"
 
#include "saveload.h"
 
#include "saveload/saveload.h"
 
#include "tile_map.h"
 
#include "gui.h"
 
#include "window_gui.h"
src/network/network_client.cpp
Show inline comments
 
@@ -12,7 +12,7 @@
 
#include "network_client.h"
 
#include "network_gamelist.h"
 
#include "network_gui.h"
 
#include "../saveload.h"
 
#include "../saveload/saveload.h"
 
#include "../command_func.h"
 
#include "../console_func.h"
 
#include "../variables.h"
src/network/network_server.cpp
Show inline comments
 
@@ -17,7 +17,7 @@
 
#include "network_udp.h"
 
#include "../console_func.h"
 
#include "../command_func.h"
 
#include "../saveload.h"
 
#include "../saveload/saveload.h"
 
#include "../station_base.h"
 
#include "../variables.h"
 
#include "../genworld.h"
src/newgrf.h
Show inline comments
 
@@ -121,7 +121,7 @@ extern GRFLoadedFeatures _loaded_newgrf_
 

	
 
void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage);
 
void LoadNewGRF(uint load_index, uint file_index);
 
void ReloadNewGRFData(); // in openttd.cpp
 
void ReloadNewGRFData(); // in saveload/afterload.cpp
 

	
 
void CDECL grfmsg(int severity, const char *str, ...);
 

	
src/newgrf_config.cpp
Show inline comments
 
@@ -6,7 +6,6 @@
 
#include "openttd.h"
 
#include "debug.h"
 
#include "variables.h"
 
#include "saveload.h"
 
#include "md5.h"
 
#include "newgrf.h"
 
#include "newgrf_config.h"
 
@@ -495,48 +494,3 @@ bool GRFConfig::IsOpenTTDBaseGRF() const
 
{
 
	return (this->grfid & 0x00FFFFFF) == OPENTTD_GRAPHICS_BASE_GRF_ID;
 
}
 

	
 

	
 
static const SaveLoad _grfconfig_desc[] = {
 
	    SLE_STR(GRFConfig, filename,         SLE_STR,    0x40),
 
	    SLE_VAR(GRFConfig, grfid,            SLE_UINT32),
 
	    SLE_ARR(GRFConfig, md5sum,           SLE_UINT8,  16),
 
	    SLE_ARR(GRFConfig, param,            SLE_UINT32, 0x80),
 
	    SLE_VAR(GRFConfig, num_params,       SLE_UINT8),
 
	SLE_CONDVAR(GRFConfig, windows_paletted, SLE_BOOL,   101, SL_MAX_VERSION),
 
	SLE_END()
 
};
 

	
 

	
 
static void Save_NGRF()
 
{
 
	int index = 0;
 

	
 
	for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) {
 
		if (HasBit(c->flags, GCF_STATIC)) continue;
 
		SlSetArrayIndex(index++);
 
		SlObject(c, _grfconfig_desc);
 
	}
 
}
 

	
 

	
 
static void Load_NGRF()
 
{
 
	ClearGRFConfigList(&_grfconfig);
 
	while (SlIterateArray() != -1) {
 
		GRFConfig *c = CallocT<GRFConfig>(1);
 
		SlObject(c, _grfconfig_desc);
 
		if (CheckSavegameVersion(101)) c->windows_paletted = (_use_palette == PAL_WINDOWS);
 
		AppendToGRFConfigList(&_grfconfig, c);
 
	}
 

	
 
	/* Append static NewGRF configuration */
 
	AppendStaticGRFConfigs(&_grfconfig);
 
}
 

	
 
extern const ChunkHandler _newgrf_chunk_handlers[] = {
 
	{ 'NGRF', Save_NGRF, Load_NGRF, CH_ARRAY | CH_LAST }
 
};
 

	
 

	
 

	
src/newgrf_house.cpp
Show inline comments
 
@@ -34,53 +34,6 @@ static HouseClassMapping _class_mapping[
 

	
 
HouseOverrideManager _house_mngr(NEW_HOUSE_OFFSET, HOUSE_MAX, INVALID_HOUSE_ID);
 

	
 
/**
 
 * Check and update town and house values.
 
 *
 
 * Checked are the HouseIDs. Updated are the
 
 * town population the number of houses per
 
 * town, the town radius and the max passengers
 
 * of the town.
 
 */
 
void UpdateHousesAndTowns()
 
{
 
	Town *town;
 
	InitializeBuildingCounts();
 

	
 
	/* Reset town population and num_houses */
 
	FOR_ALL_TOWNS(town) {
 
		town->population = 0;
 
		town->num_houses = 0;
 
	}
 

	
 
	for (TileIndex t = 0; t < MapSize(); t++) {
 
		HouseID house_id;
 

	
 
		if (!IsTileType(t, MP_HOUSE)) continue;
 

	
 
		house_id = GetHouseType(t);
 
		if (!GetHouseSpecs(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) {
 
			/* The specs for this type of house are not available any more, so
 
			 * replace it with the substitute original house type. */
 
			house_id = _house_mngr.GetSubstituteID(house_id);
 
			SetHouseType(t, house_id);
 
		}
 

	
 
		town = GetTownByTile(t);
 
		IncreaseBuildingCount(town, house_id);
 
		if (IsHouseCompleted(t)) town->population += GetHouseSpecs(house_id)->population;
 

	
 
		/* Increase the number of houses for every house, but only once. */
 
		if (GetHouseNorthPart(house_id) == 0) town->num_houses++;
 
	}
 

	
 
	/* Update the population and num_house dependant values */
 
	FOR_ALL_TOWNS(town) {
 
		UpdateTownRadius(town);
 
		UpdateTownMaxPass(town);
 
	}
 
}
 

	
 
HouseClassID AllocateHouseClassID(byte grf_class_id, uint32 grfid)
 
{
 
	/* Start from 1 because 0 means that no class has been assigned. */
src/newgrf_house.h
Show inline comments
 
@@ -7,6 +7,7 @@
 

	
 
#include "town_type.h"
 
#include "newgrf_callbacks.h"
 
#include "tile_cmd.h"
 

	
 
/**
 
 * Makes class IDs unique to each GRF file.
 
@@ -26,8 +27,6 @@ struct HouseClassMapping {
 
	uint8  class_id;  ////< The class id within the grf file
 
};
 

	
 
void UpdateHousesAndTowns();
 

	
 
HouseClassID AllocateHouseClassID(byte grf_class_id, uint32 grfid);
 

	
 
void InitializeBuildingCounts();
src/newgrf_station.h
Show inline comments
 
@@ -13,6 +13,7 @@
 
#include "strings_type.h"
 
#include "sprite.h"
 
#include "direction_type.h"
 
#include "newgrf.h"
 

	
 
enum StationClassID {
 
	STAT_CLASS_BEGIN = 0,    ///< the lowest valid value
src/oldloader.cpp
Show inline comments
 
deleted file
src/openttd.cpp
Show inline comments
 
@@ -25,7 +25,7 @@
 
#include "window_func.h"
 

	
 
#include "debug.h"
 
#include "saveload.h"
 
#include "saveload/saveload.h"
 
#include "landscape.h"
 
#include "company_func.h"
 
#include "company_base.h"
 
@@ -96,7 +96,6 @@ void IncreaseDate();
 
void DoPaletteAnimations();
 
void MusicLoop();
 
void ResetMusic();
 
void ResetOldNames();
 
void ProcessAsyncSaveFinish();
 
void CallWindowTickEvent();
 

	
 
@@ -1182,1566 +1181,3 @@ void GameLoop()
 
	_sound_driver->MainLoop();
 
	MusicLoop();
 
}
 

	
 
static void ConvertTownOwner()
 
{
 
	for (TileIndex tile = 0; tile != MapSize(); tile++) {
 
		switch (GetTileType(tile)) {
 
			case MP_ROAD:
 
				if (GB(_m[tile].m5, 4, 2) == ROAD_TILE_CROSSING && HasBit(_m[tile].m3, 7)) {
 
					_m[tile].m3 = OWNER_TOWN;
 
				}
 
				/* FALLTHROUGH */
 

	
 
			case MP_TUNNELBRIDGE:
 
				if (GetTileOwner(tile) & 0x80) SetTileOwner(tile, OWNER_TOWN);
 
				break;
 

	
 
			default: break;
 
		}
 
	}
 
}
 

	
 
/* since savegame version 4.1, exclusive transport rights are stored at towns */
 
static void UpdateExclusiveRights()
 
{
 
	Town *t;
 

	
 
	FOR_ALL_TOWNS(t) {
 
		t->exclusivity = INVALID_COMPANY;
 
	}
 

	
 
	/* FIXME old exclusive rights status is not being imported (stored in s->blocked_months_obsolete)
 
	 *   could be implemented this way:
 
	 * 1.) Go through all stations
 
	 *     Build an array town_blocked[ town_id ][ company_id ]
 
	 *     that stores if at least one station in that town is blocked for a company
 
	 * 2.) Go through that array, if you find a town that is not blocked for
 
	 *     one company, but for all others, then give him exclusivity.
 
	 */
 
}
 

	
 
static const byte convert_currency[] = {
 
	 0,  1, 12,  8,  3,
 
	10, 14, 19,  4,  5,
 
	 9, 11, 13,  6, 17,
 
	16, 22, 21,  7, 15,
 
	18,  2, 20, };
 

	
 
/* since savegame version 4.2 the currencies are arranged differently */
 
static void UpdateCurrencies()
 
{
 
	_settings_game.locale.currency = convert_currency[_settings_game.locale.currency];
 
}
 

	
 
/* Up to revision 1413 the invisible tiles at the southern border have not been
 
 * MP_VOID, even though they should have. This is fixed by this function
 
 */
 
static void UpdateVoidTiles()
 
{
 
	uint i;
 

	
 
	for (i = 0; i < MapMaxY(); ++i) MakeVoid(i * MapSizeX() + MapMaxX());
 
	for (i = 0; i < MapSizeX(); ++i) MakeVoid(MapSizeX() * MapMaxY() + i);
 
}
 

	
 
/* since savegame version 6.0 each sign has an "owner", signs without owner (from old games are set to 255) */
 
static void UpdateSignOwner()
 
{
 
	Sign *si;
 

	
 
	FOR_ALL_SIGNS(si) si->owner = OWNER_NONE;
 
}
 

	
 
extern void UpdateOldAircraft();
 

	
 

	
 
static inline RailType UpdateRailType(RailType rt, RailType min)
 
{
 
	return rt >= min ? (RailType)(rt + 1): rt;
 
}
 

	
 
/**
 
 * Initialization of the windows and several kinds of caches.
 
 * This is not done directly in AfterLoadGame because these
 
 * functions require that all saveload conversions have been
 
 * done. As people tend to add savegame conversion stuff after
 
 * the intialization of the windows and caches quite some bugs
 
 * had been made.
 
 * Moving this out of there is both cleaner and less bug-prone.
 
 *
 
 * @return true if everything went according to plan, otherwise false.
 
 */
 
static bool InitializeWindowsAndCaches()
 
{
 
	/* Initialize windows */
 
	ResetWindowSystem();
 
	SetupColorsAndInitialWindow();
 

	
 
	extern void ResetViewportAfterLoadGame();
 
	ResetViewportAfterLoadGame();
 

	
 
	/* Update coordinates of the signs. */
 
	UpdateAllStationVirtCoord();
 
	UpdateAllSignVirtCoords();
 
	UpdateAllTownVirtCoords();
 
	UpdateAllWaypointSigns();
 

	
 
	Company *c;
 
	FOR_ALL_COMPANIES(c) {
 
		/* For each company, verify (while loading a scenario) that the inauguration date is the current year and set it
 
		 * accordingly if it is not the case.  No need to set it on companies that are not been used already,
 
		 * thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */
 
		if (_file_to_saveload.filetype == FT_SCENARIO && c->inaugurated_year != MIN_YEAR) {
 
			c->inaugurated_year = _cur_year;
 
		}
 
	}
 

	
 
	SetCachedEngineCounts();
 

	
 
	/* Towns have a noise controlled number of airports system
 
	 * So each airport's noise value must be added to the town->noise_reached value
 
	 * Reset each town's noise_reached value to '0' before. */
 
	UpdateAirportsNoise();
 

	
 
	CheckTrainsLengths();
 

	
 
	return true;
 
}
 

	
 
/**
 
 * Signal handler used to give a user a more useful report for crashes during
 
 * the savegame loading process; especially when there's problems with the
 
 * NewGRFs that are required by the savegame.
 
 * @param unused well... unused
 
 */
 
void CDECL HandleSavegameLoadCrash(int unused)
 
{
 
	char buffer[8192];
 
	char *p = buffer;
 
	p += seprintf(p, lastof(buffer),
 
			"Loading your savegame caused OpenTTD to crash.\n"
 
			"This is most likely caused by a missing NewGRF or a NewGRF that has been\n"
 
			"loaded as replacement for a missing NewGRF. OpenTTD cannot easily\n"
 
			"determine whether a replacement NewGRF is of a newer or older version.\n"
 
			"It will load a NewGRF with the same GRF ID as the missing NewGRF. This\n"
 
			"means that if the author makes incompatible NewGRFs with the same GRF ID\n"
 
			"OpenTTD cannot magically do the right thing. In most cases OpenTTD will\n"
 
			"load the savegame and not crash, but this is an exception.\n"
 
			"Please load the savegame with the appropriate NewGRFs. When loading a\n"
 
			"savegame still crashes when all NewGRFs are found you should file a\n"
 
			"bug report. The missing NewGRFs are:\n");
 

	
 
	for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) {
 
		if (HasBit(c->flags, GCF_COMPATIBLE)) {
 
			char buf[40];
 
			md5sumToString(buf, lastof(buf), c->md5sum);
 
			p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s. Tried another NewGRF with same GRF ID\n", BSWAP32(c->grfid), c->filename, buf);
 
		}
 
		if (c->status == GCS_NOT_FOUND) {
 
			char buf[40];
 
			md5sumToString(buf, lastof(buf), c->md5sum);
 
			p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s\n", BSWAP32(c->grfid), c->filename, buf);
 
		}
 
	}
 

	
 
	ShowInfo(buffer);
 
}
 

	
 
bool AfterLoadGame()
 
{
 
	typedef void (CDECL *SignalHandlerPointer)(int);
 
	SignalHandlerPointer prev_segfault = signal(SIGSEGV, HandleSavegameLoadCrash);
 
	SignalHandlerPointer prev_abort = signal(SIGABRT, HandleSavegameLoadCrash);
 

	
 
	TileIndex map_size = MapSize();
 
	Company *c;
 

	
 
	if (CheckSavegameVersion(98)) GamelogOldver();
 

	
 
	GamelogTestRevision();
 
	GamelogTestMode();
 

	
 
	if (CheckSavegameVersion(98)) GamelogGRFAddList(_grfconfig);
 

	
 
	/* in very old versions, size of train stations was stored differently */
 
	if (CheckSavegameVersion(2)) {
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			if (st->train_tile != 0 && st->trainst_h == 0) {
 
				extern SavegameType _savegame_type;
 
				uint n = _savegame_type == SGT_OTTD ? 4 : 3; // OTTD uses 4 bits per dimensions, TTD 3 bits
 
				uint w = GB(st->trainst_w, n, n);
 
				uint h = GB(st->trainst_w, 0, n);
 

	
 
				if (GetRailStationAxis(st->train_tile) != AXIS_X) Swap(w, h);
 

	
 
				st->trainst_w = w;
 
				st->trainst_h = h;
 

	
 
				assert(GetStationIndex(st->train_tile + TileDiffXY(w - 1, h - 1)) == st->index);
 
			}
 
		}
 
	}
 

	
 
	/* in version 2.1 of the savegame, town owner was unified. */
 
	if (CheckSavegameVersionOldStyle(2, 1)) ConvertTownOwner();
 

	
 
	/* from version 4.1 of the savegame, exclusive rights are stored at towns */
 
	if (CheckSavegameVersionOldStyle(4, 1)) UpdateExclusiveRights();
 

	
 
	/* from version 4.2 of the savegame, currencies are in a different order */
 
	if (CheckSavegameVersionOldStyle(4, 2)) UpdateCurrencies();
 

	
 
	/* from version 6.1 of the savegame, signs have an "owner" */
 
	if (CheckSavegameVersionOldStyle(6, 1)) UpdateSignOwner();
 

	
 
	/* In old version there seems to be a problem that water is owned by
 
	 * OWNER_NONE, not OWNER_WATER.. I can't replicate it for the current
 
	 * (4.3) version, so I just check when versions are older, and then
 
	 * walk through the whole map.. */
 
	if (CheckSavegameVersionOldStyle(4, 3)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_WATER) && GetTileOwner(t) >= MAX_COMPANIES) {
 
				SetTileOwner(t, OWNER_WATER);
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(84)) {
 
		FOR_ALL_COMPANIES(c) {
 
			c->name = CopyFromOldName(c->name_1);
 
			if (c->name != NULL) c->name_1 = STR_SV_UNNAMED;
 
			c->president_name = CopyFromOldName(c->president_name_1);
 
			if (c->president_name != NULL) c->president_name_1 = SPECSTR_PRESIDENT_NAME;
 
		}
 

	
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			st->name = CopyFromOldName(st->string_id);
 
			/* generating new name would be too much work for little effect, use the station name fallback */
 
			if (st->name != NULL) st->string_id = STR_SV_STNAME_FALLBACK;
 
		}
 

	
 
		Town *t;
 
		FOR_ALL_TOWNS(t) {
 
			t->name = CopyFromOldName(t->townnametype);
 
			if (t->name != NULL) t->townnametype = SPECSTR_TOWNNAME_START + _settings_game.game_creation.town_name;
 
		}
 

	
 
		Waypoint *wp;
 
		FOR_ALL_WAYPOINTS(wp) {
 
			wp->name = CopyFromOldName(wp->string);
 
			wp->string = STR_EMPTY;
 
		}
 

	
 
		for (uint i = 0; i < GetSignPoolSize(); i++) {
 
			/* invalid signs are determined by si->ower == INVALID_COMPANY now */
 
			Sign *si = GetSign(i);
 
			if (!si->IsValid() && si->name != NULL) {
 
				si->owner = OWNER_NONE;
 
			}
 
		}
 
	}
 

	
 
	/* From this point the old names array is cleared. */
 
	ResetOldNames();
 

	
 
	if (CheckSavegameVersion(106)) {
 
		/* no station is determined by 'tile == INVALID_TILE' now (instead of '0') */
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			if (st->airport_tile == 0) st->airport_tile = INVALID_TILE;
 
			if (st->dock_tile    == 0) st->dock_tile    = INVALID_TILE;
 
			if (st->train_tile   == 0) st->train_tile   = INVALID_TILE;
 
		}
 

	
 
		/* the same applies to Company::location_of_HQ */
 
		Company *c;
 
		FOR_ALL_COMPANIES(c) {
 
			if (c->location_of_HQ == 0 || (CheckSavegameVersion(4) && c->location_of_HQ == 0xFFFF)) {
 
				c->location_of_HQ = INVALID_TILE;
 
			}
 
		}
 
	}
 

	
 
	/* convert road side to my format. */
 
	if (_settings_game.vehicle.road_side) _settings_game.vehicle.road_side = 1;
 

	
 
	/* Check if all NewGRFs are present, we are very strict in MP mode */
 
	GRFListCompatibility gcf_res = IsGoodGRFConfigList();
 
	if (_networking && gcf_res != GLC_ALL_GOOD) {
 
		SetSaveLoadError(STR_NETWORK_ERR_CLIENT_NEWGRF_MISMATCH);
 
		/* Restore the signals */
 
		signal(SIGSEGV, prev_segfault);
 
		signal(SIGABRT, prev_abort);
 
		return false;
 
	}
 

	
 
	switch (gcf_res) {
 
		case GLC_COMPATIBLE: _switch_mode_errorstr = STR_NEWGRF_COMPATIBLE_LOAD_WARNING; break;
 
		case GLC_NOT_FOUND: _switch_mode_errorstr = STR_NEWGRF_DISABLED_WARNING; _pause_game = -1; break;
 
		default: break;
 
	}
 

	
 
	/* Update current year
 
	 * must be done before loading sprites as some newgrfs check it */
 
	SetDate(_date);
 

	
 
	/* Force dynamic engines off when loading older savegames */
 
	if (CheckSavegameVersion(95)) _settings_game.vehicle.dynamic_engines = 0;
 

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

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

	
 
	/* Connect front and rear engines of multiheaded trains and converts
 
	 * subtype to the new format */
 
	if (CheckSavegameVersionOldStyle(17, 1)) ConvertOldMultiheadToNew();
 

	
 
	/* Connect front and rear engines of multiheaded trains */
 
	ConnectMultiheadedTrains();
 

	
 
	/* reinit the landscape variables (landscape might have changed) */
 
	InitializeLandscapeVariables(true);
 

	
 
	/* Update all vehicles */
 
	AfterLoadVehicles(true);
 

	
 
	/* Update all waypoints */
 
	if (CheckSavegameVersion(12)) FixOldWaypoints();
 

	
 
	/* in version 2.2 of the savegame, we have new airports */
 
	if (CheckSavegameVersionOldStyle(2, 2)) UpdateOldAircraft();
 

	
 
	AfterLoadTown();
 

	
 
	/* make sure there is a town in the game */
 
	if (_game_mode == GM_NORMAL && !ClosestTownFromTile(0, UINT_MAX)) {
 
		SetSaveLoadError(STR_NO_TOWN_IN_SCENARIO);
 
		/* Restore the signals */
 
		signal(SIGSEGV, prev_segfault);
 
		signal(SIGABRT, prev_abort);
 
		return false;
 
	}
 

	
 
	/* The void tiles on the southern border used to belong to a wrong class (pre 4.3).
 
	 * This problem appears in savegame version 21 too, see r3455. But after loading the
 
	 * savegame and saving again, the buggy map array could be converted to new savegame
 
	 * version. It didn't show up before r12070. */
 
	if (CheckSavegameVersion(87)) UpdateVoidTiles();
 

	
 
	/* If Load Scenario / New (Scenario) Game is used,
 
	 *  a company does not exist yet. So create one here.
 
	 * 1 exeption: network-games. Those can have 0 companies
 
	 *   But this exeption is not true for non dedicated network_servers! */
 
	if (!IsValidCompanyID(COMPANY_FIRST) && (!_networking || (_networking && _network_server && !_network_dedicated)))
 
		DoStartupNewCompany(false);
 

	
 
	if (CheckSavegameVersion(72)) {
 
		/* Locks/shiplifts in very old savegames had OWNER_WATER as owner */
 
		for (TileIndex t = 0; t < MapSize(); t++) {
 
			switch (GetTileType(t)) {
 
				default: break;
 

	
 
				case MP_WATER:
 
					if (GetWaterTileType(t) == WATER_TILE_LOCK && GetTileOwner(t) == OWNER_WATER) SetTileOwner(t, OWNER_NONE);
 
					break;
 

	
 
				case MP_STATION: {
 
					if (HasBit(_m[t].m6, 3)) SetBit(_m[t].m6, 2);
 
					StationGfx gfx = GetStationGfx(t);
 
					StationType st;
 
					if (       IsInsideMM(gfx,   0,   8)) { // Railway station
 
						st = STATION_RAIL;
 
						SetStationGfx(t, gfx - 0);
 
					} else if (IsInsideMM(gfx,   8,  67)) { // Airport
 
						st = STATION_AIRPORT;
 
						SetStationGfx(t, gfx - 8);
 
					} else if (IsInsideMM(gfx,  67,  71)) { // Truck
 
						st = STATION_TRUCK;
 
						SetStationGfx(t, gfx - 67);
 
					} else if (IsInsideMM(gfx,  71,  75)) { // Bus
 
						st = STATION_BUS;
 
						SetStationGfx(t, gfx - 71);
 
					} else if (gfx == 75) {                    // Oil rig
 
						st = STATION_OILRIG;
 
						SetStationGfx(t, gfx - 75);
 
					} else if (IsInsideMM(gfx,  76,  82)) { // Dock
 
						st = STATION_DOCK;
 
						SetStationGfx(t, gfx - 76);
 
					} else if (gfx == 82) {                    // Buoy
 
						st = STATION_BUOY;
 
						SetStationGfx(t, gfx - 82);
 
					} else if (IsInsideMM(gfx,  83, 168)) { // Extended airport
 
						st = STATION_AIRPORT;
 
						SetStationGfx(t, gfx - 83 + 67 - 8);
 
					} else if (IsInsideMM(gfx, 168, 170)) { // Drive through truck
 
						st = STATION_TRUCK;
 
						SetStationGfx(t, gfx - 168 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET);
 
					} else if (IsInsideMM(gfx, 170, 172)) { // Drive through bus
 
						st = STATION_BUS;
 
						SetStationGfx(t, gfx - 170 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET);
 
					} else {
 
						/* Restore the signals */
 
						signal(SIGSEGV, prev_segfault);
 
						signal(SIGABRT, prev_abort);
 
						return false;
 
					}
 
					SB(_m[t].m6, 3, 3, st);
 
				} break;
 
			}
 
		}
 
	}
 

	
 
	for (TileIndex t = 0; t < map_size; t++) {
 
		switch (GetTileType(t)) {
 
			case MP_STATION: {
 
				Station *st = GetStationByTile(t);
 

	
 
				/* Set up station spread; buoys do not have one */
 
				if (!IsBuoy(t)) st->rect.BeforeAddTile(t, StationRect::ADD_FORCE);
 

	
 
				switch (GetStationType(t)) {
 
					case STATION_TRUCK:
 
					case STATION_BUS:
 
						if (CheckSavegameVersion(6)) {
 
							/* From this version on there can be multiple road stops of the
 
							 * same type per station. Convert the existing stops to the new
 
							 * internal data structure. */
 
							RoadStop *rs = new RoadStop(t);
 
							if (rs == NULL) error("Too many road stops in savegame");
 

	
 
							RoadStop **head =
 
								IsTruckStop(t) ? &st->truck_stops : &st->bus_stops;
 
							*head = rs;
 
						}
 
						break;
 

	
 
					case STATION_OILRIG: {
 
						/* Very old savegames sometimes have phantom oil rigs, i.e.
 
						 * an oil rig which got shut down, but not completly removed from
 
						 * the map
 
						 */
 
						TileIndex t1 = TILE_ADDXY(t, 0, 1);
 
						if (IsTileType(t1, MP_INDUSTRY) &&
 
								GetIndustryGfx(t1) == GFX_OILRIG_1) {
 
							/* The internal encoding of oil rigs was changed twice.
 
							 * It was 3 (till 2.2) and later 5 (till 5.1).
 
							 * Setting it unconditionally does not hurt.
 
							 */
 
							GetStationByTile(t)->airport_type = AT_OILRIG;
 
						} else {
 
							DeleteOilRig(t);
 
						}
 
						break;
 
					}
 

	
 
					default: break;
 
				}
 
				break;
 
			}
 

	
 
			default: break;
 
		}
 
	}
 

	
 
	/* In version 6.1 we put the town index in the map-array. To do this, we need
 
	 *  to use m2 (16bit big), so we need to clean m2, and that is where this is
 
	 *  all about ;) */
 
	if (CheckSavegameVersionOldStyle(6, 1)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			switch (GetTileType(t)) {
 
				case MP_HOUSE:
 
					_m[t].m4 = _m[t].m2;
 
					SetTownIndex(t, CalcClosestTownFromTile(t, UINT_MAX)->index);
 
					break;
 

	
 
				case MP_ROAD:
 
					_m[t].m4 |= (_m[t].m2 << 4);
 
					if ((GB(_m[t].m5, 4, 2) == ROAD_TILE_CROSSING ? (Owner)_m[t].m3 : GetTileOwner(t)) == OWNER_TOWN) {
 
						SetTownIndex(t, CalcClosestTownFromTile(t, UINT_MAX)->index);
 
					} else {
 
						SetTownIndex(t, 0);
 
					}
 
					break;
 

	
 
				default: break;
 
			}
 
		}
 
	}
 

	
 
	/* From version 9.0, we update the max passengers of a town (was sometimes negative
 
	 *  before that. */
 
	if (CheckSavegameVersion(9)) {
 
		Town *t;
 
		FOR_ALL_TOWNS(t) UpdateTownMaxPass(t);
 
	}
 

	
 
	/* From version 16.0, we included autorenew on engines, which are now saved, but
 
	 *  of course, we do need to initialize them for older savegames. */
 
	if (CheckSavegameVersion(16)) {
 
		FOR_ALL_COMPANIES(c) {
 
			c->engine_renew_list   = NULL;
 
			c->engine_renew        = false;
 
			c->engine_renew_months = -6;
 
			c->engine_renew_money  = 100000;
 
		}
 

	
 
		/* When loading a game, _local_company is not yet set to the correct value.
 
		 * However, in a dedicated server we are a spectator, so nothing needs to
 
		 * happen. In case we are not a dedicated server, the local company always
 
		 * becomes company 0, unless we are in the scenario editor where all the
 
		 * companies are 'invalid'.
 
		 */
 
		if (!_network_dedicated && IsValidCompanyID(COMPANY_FIRST)) {
 
			c = GetCompany(COMPANY_FIRST);
 
			c->engine_renew        = _settings_client.gui.autorenew;
 
			c->engine_renew_months = _settings_client.gui.autorenew_months;
 
			c->engine_renew_money  = _settings_client.gui.autorenew_money;
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(48)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			switch (GetTileType(t)) {
 
				case MP_RAILWAY:
 
					if (IsPlainRailTile(t)) {
 
						/* Swap ground type and signal type for plain rail tiles, so the
 
						 * ground type uses the same bits as for depots and waypoints. */
 
						uint tmp = GB(_m[t].m4, 0, 4);
 
						SB(_m[t].m4, 0, 4, GB(_m[t].m2, 0, 4));
 
						SB(_m[t].m2, 0, 4, tmp);
 
					} else if (HasBit(_m[t].m5, 2)) {
 
						/* Split waypoint and depot rail type and remove the subtype. */
 
						ClrBit(_m[t].m5, 2);
 
						ClrBit(_m[t].m5, 6);
 
					}
 
					break;
 

	
 
				case MP_ROAD:
 
					/* Swap m3 and m4, so the track type for rail crossings is the
 
					 * same as for normal rail. */
 
					Swap(_m[t].m3, _m[t].m4);
 
					break;
 

	
 
				default: break;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(61)) {
 
		/* Added the RoadType */
 
		bool old_bridge = CheckSavegameVersion(42);
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			switch(GetTileType(t)) {
 
				case MP_ROAD:
 
					SB(_m[t].m5, 6, 2, GB(_m[t].m5, 4, 2));
 
					switch (GetRoadTileType(t)) {
 
						default: NOT_REACHED();
 
						case ROAD_TILE_NORMAL:
 
							SB(_m[t].m4, 0, 4, GB(_m[t].m5, 0, 4));
 
							SB(_m[t].m4, 4, 4, 0);
 
							SB(_m[t].m6, 2, 4, 0);
 
							break;
 
						case ROAD_TILE_CROSSING:
 
							SB(_m[t].m4, 5, 2, GB(_m[t].m5, 2, 2));
 
							break;
 
						case ROAD_TILE_DEPOT:    break;
 
					}
 
					SetRoadTypes(t, ROADTYPES_ROAD);
 
					break;
 

	
 
				case MP_STATION:
 
					if (IsRoadStop(t)) SetRoadTypes(t, ROADTYPES_ROAD);
 
					break;
 

	
 
				case MP_TUNNELBRIDGE:
 
					/* Middle part of "old" bridges */
 
					if (old_bridge && IsBridge(t) && HasBit(_m[t].m5, 6)) break;
 
					if (((old_bridge && IsBridge(t)) ? (TransportType)GB(_m[t].m5, 1, 2) : GetTunnelBridgeTransportType(t)) == TRANSPORT_ROAD) {
 
						SetRoadTypes(t, ROADTYPES_ROAD);
 
					}
 
					break;
 

	
 
				default: break;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(42)) {
 
		Vehicle* v;
 

	
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (MayHaveBridgeAbove(t)) ClearBridgeMiddle(t);
 
			if (IsBridgeTile(t)) {
 
				if (HasBit(_m[t].m5, 6)) { // middle part
 
					Axis axis = (Axis)GB(_m[t].m5, 0, 1);
 

	
 
					if (HasBit(_m[t].m5, 5)) { // transport route under bridge?
 
						if (GB(_m[t].m5, 3, 2) == TRANSPORT_RAIL) {
 
							MakeRailNormal(
 
								t,
 
								GetTileOwner(t),
 
								axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X,
 
								GetRailType(t)
 
							);
 
						} else {
 
							TownID town = IsTileOwner(t, OWNER_TOWN) ? ClosestTownFromTile(t, UINT_MAX)->index : 0;
 

	
 
							MakeRoadNormal(
 
								t,
 
								axis == AXIS_X ? ROAD_Y : ROAD_X,
 
								ROADTYPES_ROAD,
 
								town,
 
								GetTileOwner(t), OWNER_NONE, OWNER_NONE
 
							);
 
						}
 
					} else {
 
						if (GB(_m[t].m5, 3, 2) == 0) {
 
							MakeClear(t, CLEAR_GRASS, 3);
 
						} else {
 
							if (GetTileSlope(t, NULL) != SLOPE_FLAT) {
 
								MakeShore(t);
 
							} else {
 
								if (GetTileOwner(t) == OWNER_WATER) {
 
									MakeWater(t);
 
								} else {
 
									MakeCanal(t, GetTileOwner(t), Random());
 
								}
 
							}
 
						}
 
					}
 
					SetBridgeMiddle(t, axis);
 
				} else { // ramp
 
					Axis axis = (Axis)GB(_m[t].m5, 0, 1);
 
					uint north_south = GB(_m[t].m5, 5, 1);
 
					DiagDirection dir = ReverseDiagDir(XYNSToDiagDir(axis, north_south));
 
					TransportType type = (TransportType)GB(_m[t].m5, 1, 2);
 

	
 
					_m[t].m5 = 1 << 7 | type << 2 | dir;
 
				}
 
			}
 
		}
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type != VEH_TRAIN && v->type != VEH_ROAD) continue;
 
			if (IsBridgeTile(v->tile)) {
 
				DiagDirection dir = GetTunnelBridgeDirection(v->tile);
 

	
 
				if (dir != DirToDiagDir(v->direction)) continue;
 
				switch (dir) {
 
					default: NOT_REACHED();
 
					case DIAGDIR_NE: if ((v->x_pos & 0xF) !=  0)            continue; break;
 
					case DIAGDIR_SE: if ((v->y_pos & 0xF) != TILE_SIZE - 1) continue; break;
 
					case DIAGDIR_SW: if ((v->x_pos & 0xF) != TILE_SIZE - 1) continue; break;
 
					case DIAGDIR_NW: if ((v->y_pos & 0xF) !=  0)            continue; break;
 
				}
 
			} else if (v->z_pos > GetSlopeZ(v->x_pos, v->y_pos)) {
 
				v->tile = GetNorthernBridgeEnd(v->tile);
 
			} else {
 
				continue;
 
			}
 
			if (v->type == VEH_TRAIN) {
 
				v->u.rail.track = TRACK_BIT_WORMHOLE;
 
			} else {
 
				v->u.road.state = RVSB_WORMHOLE;
 
			}
 
		}
 
	}
 

	
 
	/* Elrails got added in rev 24 */
 
	if (CheckSavegameVersion(24)) {
 
		Vehicle *v;
 
		RailType min_rail = RAILTYPE_ELECTRIC;
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_TRAIN) {
 
				RailType rt = RailVehInfo(v->engine_type)->railtype;
 

	
 
				v->u.rail.railtype = rt;
 
				if (rt == RAILTYPE_ELECTRIC) min_rail = RAILTYPE_RAIL;
 
			}
 
		}
 

	
 
		/* .. so we convert the entire map from normal to elrail (so maintain "fairness") */
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			switch (GetTileType(t)) {
 
				case MP_RAILWAY:
 
					SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
 
					break;
 

	
 
				case MP_ROAD:
 
					if (IsLevelCrossing(t)) {
 
						SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
 
					}
 
					break;
 

	
 
				case MP_STATION:
 
					if (IsRailwayStation(t)) {
 
						SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
 
					}
 
					break;
 

	
 
				case MP_TUNNELBRIDGE:
 
					if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) {
 
						SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
 
					}
 
					break;
 

	
 
				default:
 
					break;
 
			}
 
		}
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) TrainConsistChanged(v, true);
 
		}
 

	
 
	}
 

	
 
	/* In version 16.1 of the savegame a company can decide if trains, which get
 
	 * replaced, shall keep their old length. In all prior versions, just default
 
	 * to false */
 
	if (CheckSavegameVersionOldStyle(16, 1)) {
 
		FOR_ALL_COMPANIES(c) c->renew_keep_length = false;
 
	}
 

	
 
	/* In version 17, ground type is moved from m2 to m4 for depots and
 
	 * waypoints to make way for storing the index in m2. The custom graphics
 
	 * id which was stored in m4 is now saved as a grf/id reference in the
 
	 * waypoint struct. */
 
	if (CheckSavegameVersion(17)) {
 
		Waypoint *wp;
 

	
 
		FOR_ALL_WAYPOINTS(wp) {
 
			if (wp->deleted == 0) {
 
				const StationSpec *statspec = NULL;
 

	
 
				if (HasBit(_m[wp->xy].m3, 4))
 
					statspec = GetCustomStationSpec(STAT_CLASS_WAYP, _m[wp->xy].m4 + 1);
 

	
 
				if (statspec != NULL) {
 
					wp->stat_id = _m[wp->xy].m4 + 1;
 
					wp->grfid = statspec->grffile->grfid;
 
					wp->localidx = statspec->localidx;
 
				} else {
 
					/* No custom graphics set, so set to default. */
 
					wp->stat_id = 0;
 
					wp->grfid = 0;
 
					wp->localidx = 0;
 
				}
 

	
 
				/* Move ground type bits from m2 to m4. */
 
				_m[wp->xy].m4 = GB(_m[wp->xy].m2, 0, 4);
 
				/* Store waypoint index in the tile. */
 
				_m[wp->xy].m2 = wp->index;
 
			}
 
		}
 
	} else {
 
		/* As of version 17, we recalculate the custom graphic ID of waypoints
 
		 * from the GRF ID / station index. */
 
		AfterLoadWaypoints();
 
	}
 

	
 
	/* From version 15, we moved a semaphore bit from bit 2 to bit 3 in m4, making
 
	 *  room for PBS. Now in version 21 move it back :P. */
 
	if (CheckSavegameVersion(21) && !CheckSavegameVersion(15)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			switch (GetTileType(t)) {
 
				case MP_RAILWAY:
 
					if (HasSignals(t)) {
 
						/* convert PBS signals to combo-signals */
 
						if (HasBit(_m[t].m2, 2)) SetSignalType(t, TRACK_X, SIGTYPE_COMBO);
 

	
 
						/* move the signal variant back */
 
						SetSignalVariant(t, TRACK_X, HasBit(_m[t].m2, 3) ? SIG_SEMAPHORE : SIG_ELECTRIC);
 
						ClrBit(_m[t].m2, 3);
 
					}
 

	
 
					/* Clear PBS reservation on track */
 
					if (!IsRailDepotTile(t)) {
 
						SB(_m[t].m4, 4, 4, 0);
 
					} else {
 
						ClrBit(_m[t].m3, 6);
 
					}
 
					break;
 

	
 
				case MP_ROAD: /* Clear PBS reservation on crossing */
 
					if (IsLevelCrossing(t)) ClrBit(_m[t].m5, 0);
 
					break;
 

	
 
				case MP_STATION: /* Clear PBS reservation on station */
 
					ClrBit(_m[t].m3, 6);
 
					break;
 

	
 
				default: break;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(25)) {
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_ROAD) {
 
				v->vehstatus &= ~0x40;
 
				v->u.road.slot = NULL;
 
				v->u.road.slot_age = 0;
 
			}
 
		}
 
	} else {
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_ROAD && v->u.road.slot != NULL) v->u.road.slot->num_vehicles++;
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(26)) {
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			st->last_vehicle_type = VEH_INVALID;
 
		}
 
	}
 

	
 
	YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK);
 

	
 
	if (CheckSavegameVersion(34)) FOR_ALL_COMPANIES(c) ResetCompanyLivery(c);
 

	
 
	FOR_ALL_COMPANIES(c) {
 
		c->avail_railtypes = GetCompanyRailtypes(c->index);
 
		c->avail_roadtypes = GetCompanyRoadtypes(c->index);
 
	}
 

	
 
	if (!CheckSavegameVersion(27)) AfterLoadStations();
 

	
 
	/* Time starts at 0 instead of 1920.
 
	 * Account for this in older games by adding an offset */
 
	if (CheckSavegameVersion(31)) {
 
		Station *st;
 
		Waypoint *wp;
 
		Engine *e;
 
		Industry *i;
 
		Vehicle *v;
 

	
 
		_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		_cur_year += ORIGINAL_BASE_YEAR;
 

	
 
		FOR_ALL_STATIONS(st)  st->build_date      += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		FOR_ALL_WAYPOINTS(wp) wp->build_date      += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		FOR_ALL_ENGINES(e)    e->intro_date       += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		FOR_ALL_COMPANIES(c)  c->inaugurated_year += ORIGINAL_BASE_YEAR;
 
		FOR_ALL_INDUSTRIES(i) i->last_prod_year   += ORIGINAL_BASE_YEAR;
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			v->date_of_last_service += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			v->build_year += ORIGINAL_BASE_YEAR;
 
		}
 
	}
 

	
 
	/* From 32 on we save the industry who made the farmland.
 
	 *  To give this prettyness to old savegames, we remove all farmfields and
 
	 *  plant new ones. */
 
	if (CheckSavegameVersion(32)) {
 
		Industry *i;
 

	
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_FIELDS)) {
 
				/* remove fields */
 
				MakeClear(t, CLEAR_GRASS, 3);
 
			} else if (IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES)) {
 
				/* remove fences around fields */
 
				SetFenceSE(t, 0);
 
				SetFenceSW(t, 0);
 
			}
 
		}
 

	
 
		FOR_ALL_INDUSTRIES(i) {
 
			uint j;
 

	
 
			if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) {
 
				for (j = 0; j != 50; j++) PlantRandomFarmField(i);
 
			}
 
		}
 
	}
 

	
 
	/* Setting no refit flags to all orders in savegames from before refit in orders were added */
 
	if (CheckSavegameVersion(36)) {
 
		Order *order;
 
		Vehicle *v;
 

	
 
		FOR_ALL_ORDERS(order) {
 
			order->SetRefit(CT_NO_REFIT);
 
		}
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			v->current_order.SetRefit(CT_NO_REFIT);
 
		}
 
	}
 

	
 
	/* from version 38 we have optional elrails, since we cannot know the
 
	 * preference of a user, let elrails enabled; it can be disabled manually */
 
	if (CheckSavegameVersion(38)) _settings_game.vehicle.disable_elrails = false;
 
	/* do the same as when elrails were enabled/disabled manually just now */
 
	SettingsDisableElrail(_settings_game.vehicle.disable_elrails);
 
	InitializeRailGUI();
 

	
 
	/* From version 53, the map array was changed for house tiles to allow
 
	 * space for newhouses grf features. A new byte, m7, was also added. */
 
	if (CheckSavegameVersion(53)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_HOUSE)) {
 
				if (GB(_m[t].m3, 6, 2) != TOWN_HOUSE_COMPLETED) {
 
					/* Move the construction stage from m3[7..6] to m5[5..4].
 
					 * The construction counter does not have to move. */
 
					SB(_m[t].m5, 3, 2, GB(_m[t].m3, 6, 2));
 
					SB(_m[t].m3, 6, 2, 0);
 

	
 
					/* The "house is completed" bit is now in m6[2]. */
 
					SetHouseCompleted(t, false);
 
				} else {
 
					/* The "lift has destination" bit has been moved from
 
					 * m5[7] to m7[0]. */
 
					SB(_me[t].m7, 0, 1, HasBit(_m[t].m5, 7));
 
					ClrBit(_m[t].m5, 7);
 

	
 
					/* The "lift is moving" bit has been removed, as it does
 
					 * the same job as the "lift has destination" bit. */
 
					ClrBit(_m[t].m1, 7);
 

	
 
					/* The position of the lift goes from m1[7..0] to m6[7..2],
 
					 * making m1 totally free, now. The lift position does not
 
					 * have to be a full byte since the maximum value is 36. */
 
					SetLiftPosition(t, GB(_m[t].m1, 0, 6 ));
 

	
 
					_m[t].m1 = 0;
 
					_m[t].m3 = 0;
 
					SetHouseCompleted(t, true);
 
				}
 
			}
 
		}
 
	}
 

	
 
	/* Check and update house and town values */
 
	UpdateHousesAndTowns();
 

	
 
	if (CheckSavegameVersion(43)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_INDUSTRY)) {
 
				switch (GetIndustryGfx(t)) {
 
					case GFX_POWERPLANT_SPARKS:
 
						SetIndustryAnimationState(t, GB(_m[t].m1, 2, 5));
 
						break;
 

	
 
					case GFX_OILWELL_ANIMATED_1:
 
					case GFX_OILWELL_ANIMATED_2:
 
					case GFX_OILWELL_ANIMATED_3:
 
						SetIndustryAnimationState(t, GB(_m[t].m1, 0, 2));
 
						break;
 

	
 
					case GFX_COAL_MINE_TOWER_ANIMATED:
 
					case GFX_COPPER_MINE_TOWER_ANIMATED:
 
					case GFX_GOLD_MINE_TOWER_ANIMATED:
 
						 SetIndustryAnimationState(t, _m[t].m1);
 
						 break;
 

	
 
					default: /* No animation states to change */
 
						break;
 
				}
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(44)) {
 
		Vehicle *v;
 
		/* If we remove a station while cargo from it is still enroute, payment calculation will assume
 
		 * 0, 0 to be the source of the cargo, resulting in very high payments usually. v->source_xy
 
		 * stores the coordinates, preserving them even if the station is removed. However, if a game is loaded
 
		 * where this situation exists, the cargo-source information is lost. in this case, we set the source
 
		 * to the current tile of the vehicle to prevent excessive profits
 
		 */
 
		FOR_ALL_VEHICLES(v) {
 
			const CargoList::List *packets = v->cargo.Packets();
 
			for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) {
 
				CargoPacket *cp = *it;
 
				cp->source_xy = IsValidStationID(cp->source) ? GetStation(cp->source)->xy : v->tile;
 
				cp->loaded_at_xy = cp->source_xy;
 
			}
 
			v->cargo.InvalidateCache();
 
		}
 

	
 
		/* Store position of the station where the goods come from, so there
 
		 * are no very high payments when stations get removed. However, if the
 
		 * station where the goods came from is already removed, the source
 
		 * information is lost. In that case we set it to the position of this
 
		 * station */
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			for (CargoID c = 0; c < NUM_CARGO; c++) {
 
				GoodsEntry *ge = &st->goods[c];
 

	
 
				const CargoList::List *packets = ge->cargo.Packets();
 
				for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) {
 
					CargoPacket *cp = *it;
 
					cp->source_xy = IsValidStationID(cp->source) ? GetStation(cp->source)->xy : st->xy;
 
					cp->loaded_at_xy = cp->source_xy;
 
				}
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(45)) {
 
		Vehicle *v;
 
		/* Originally just the fact that some cargo had been paid for was
 
		 * stored to stop people cheating and cashing in several times. This
 
		 * wasn't enough though as it was cleared when the vehicle started
 
		 * loading again, even if it didn't actually load anything, so now the
 
		 * amount of cargo that has been paid for is stored. */
 
		FOR_ALL_VEHICLES(v) {
 
			const CargoList::List *packets = v->cargo.Packets();
 
			for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) {
 
				CargoPacket *cp = *it;
 
				cp->paid_for = HasBit(v->vehicle_flags, 2);
 
			}
 
			ClrBit(v->vehicle_flags, 2);
 
			v->cargo.InvalidateCache();
 
		}
 
	}
 

	
 
	/* Buoys do now store the owner of the previous water tile, which can never
 
	 * be OWNER_NONE. So replace OWNER_NONE with OWNER_WATER. */
 
	if (CheckSavegameVersion(46)) {
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			if (st->IsBuoy() && IsTileOwner(st->xy, OWNER_NONE) && TileHeight(st->xy) == 0) SetTileOwner(st->xy, OWNER_WATER);
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(50)) {
 
		Vehicle *v;
 
		/* Aircraft units changed from 8 mph to 1 km/h */
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_AIRCRAFT && v->subtype <= AIR_AIRCRAFT) {
 
				const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type);
 
				v->cur_speed *= 129;
 
				v->cur_speed /= 10;
 
				v->max_speed = avi->max_speed;
 
				v->acceleration = avi->acceleration;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(49)) FOR_ALL_COMPANIES(c) c->face = ConvertFromOldCompanyManagerFace(c->face);
 

	
 
	if (CheckSavegameVersion(52)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsStatueTile(t)) {
 
				_m[t].m2 = CalcClosestTownFromTile(t, UINT_MAX)->index;
 
			}
 
		}
 
	}
 

	
 
	/* A patch option containing the proportion of towns that grow twice as
 
	 * fast was added in version 54. From version 56 this is now saved in the
 
	 * town as cities can be built specifically in the scenario editor. */
 
	if (CheckSavegameVersion(56)) {
 
		Town *t;
 

	
 
		FOR_ALL_TOWNS(t) {
 
			if (_settings_game.economy.larger_towns != 0 && (t->index % _settings_game.economy.larger_towns) == 0) {
 
				t->larger_town = true;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(57)) {
 
		Vehicle *v;
 
		/* Added a FIFO queue of vehicles loading at stations */
 
		FOR_ALL_VEHICLES(v) {
 
			if ((v->type != VEH_TRAIN || IsFrontEngine(v)) &&  // for all locs
 
					!(v->vehstatus & (VS_STOPPED | VS_CRASHED)) && // not stopped or crashed
 
					v->current_order.IsType(OT_LOADING)) {         // loading
 
				GetStation(v->last_station_visited)->loading_vehicles.push_back(v);
 

	
 
				/* The loading finished flag is *only* set when actually completely
 
				 * finished. Because the vehicle is loading, it is not finished. */
 
				ClrBit(v->vehicle_flags, VF_LOADING_FINISHED);
 
			}
 
		}
 
	} else if (CheckSavegameVersion(59)) {
 
		/* For some reason non-loading vehicles could be in the station's loading vehicle list */
 

	
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			std::list<Vehicle *>::iterator iter;
 
			for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end();) {
 
				Vehicle *v = *iter;
 
				iter++;
 
				if (!v->current_order.IsType(OT_LOADING)) st->loading_vehicles.remove(v);
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(58)) {
 
		/* patch difficulty number_industries other than zero get bumped to +1
 
		 * since a new option (very low at position1) has been added */
 
		if (_settings_game.difficulty.number_industries > 0) {
 
			_settings_game.difficulty.number_industries++;
 
		}
 

	
 
		/* Same goes for number of towns, although no test is needed, just an increment */
 
		_settings_game.difficulty.number_towns++;
 
	}
 

	
 
	if (CheckSavegameVersion(64)) {
 
		/* copy the signal type/variant and move signal states bits */
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_RAILWAY) && HasSignals(t)) {
 
				SetSignalStates(t, GB(_m[t].m2, 4, 4));
 
				SetSignalVariant(t, INVALID_TRACK, GetSignalVariant(t, TRACK_X));
 
				SetSignalType(t, INVALID_TRACK, GetSignalType(t, TRACK_X));
 
				ClrBit(_m[t].m2, 7);
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(69)) {
 
		/* In some old savegames a bit was cleared when it should not be cleared */
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_ROAD && (v->u.road.state == 250 || v->u.road.state == 251)) {
 
				SetBit(v->u.road.state, RVS_IS_STOPPING);
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(70)) {
 
		/* Added variables to support newindustries */
 
		Industry *i;
 
		FOR_ALL_INDUSTRIES(i) i->founder = OWNER_NONE;
 
	}
 

	
 
	/* From version 82, old style canals (above sealevel (0), WATER owner) are no longer supported.
 
	    Replace the owner for those by OWNER_NONE. */
 
	if (CheckSavegameVersion(82)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_WATER) &&
 
					GetWaterTileType(t) == WATER_TILE_CLEAR &&
 
					GetTileOwner(t) == OWNER_WATER &&
 
					TileHeight(t) != 0) {
 
				SetTileOwner(t, OWNER_NONE);
 
			}
 
		}
 
	}
 

	
 
	/*
 
	 * Add the 'previous' owner to the ship depots so we can reset it with
 
	 * the correct values when it gets destroyed. This prevents that
 
	 * someone can remove canals owned by somebody else and it prevents
 
	 * making floods using the removal of ship depots.
 
	 */
 
	if (CheckSavegameVersion(83)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_WATER) && IsShipDepot(t)) {
 
				_m[t].m4 = (TileHeight(t) == 0) ? OWNER_WATER : OWNER_NONE;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(74)) {
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			for (CargoID c = 0; c < NUM_CARGO; c++) {
 
				st->goods[c].last_speed = 0;
 
				if (st->goods[c].cargo.Count() != 0) SetBit(st->goods[c].acceptance_pickup, GoodsEntry::PICKUP);
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(78)) {
 
		Industry *i;
 
		uint j;
 
		FOR_ALL_INDUSTRIES(i) {
 
			const IndustrySpec *indsp = GetIndustrySpec(i->type);
 
			for (j = 0; j < lengthof(i->produced_cargo); j++) {
 
				i->produced_cargo[j] = indsp->produced_cargo[j];
 
			}
 
			for (j = 0; j < lengthof(i->accepts_cargo); j++) {
 
				i->accepts_cargo[j] = indsp->accepts_cargo[j];
 
			}
 
		}
 
	}
 

	
 
	/* Before version 81, the density of grass was always stored as zero, and
 
	 * grassy trees were always drawn fully grassy. Furthermore, trees on rough
 
	 * land used to have zero density, now they have full density. Therefore,
 
	 * make all grassy/rough land trees have a density of 3. */
 
	if (CheckSavegameVersion(81)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (GetTileType(t) == MP_TREES) {
 
				TreeGround groundType = GetTreeGround(t);
 
				if (groundType != TREE_GROUND_SNOW_DESERT) SetTreeGroundDensity(t, groundType, 3);
 
			}
 
		}
 
	}
 

	
 

	
 
	if (CheckSavegameVersion(93)) {
 
		/* Rework of orders. */
 
		Order *order;
 
		FOR_ALL_ORDERS(order) order->ConvertFromOldSavegame();
 

	
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->orders.list != NULL && v->orders.list->GetFirstOrder() != NULL && !v->orders.list->GetFirstOrder()->IsValid()) {
 
				v->orders.list->FreeChain();
 
				v->orders.list = NULL;
 
			}
 

	
 
			v->current_order.ConvertFromOldSavegame();
 
			if (v->type == VEH_ROAD && v->IsPrimaryVehicle() && v->FirstShared() == v) {
 
				FOR_VEHICLE_ORDERS(v, order) order->SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS);
 
			}
 
		}
 
	} else if (CheckSavegameVersion(94)) {
 
		/* Unload and transfer are now mutual exclusive. */
 
		Order *order;
 
		FOR_ALL_ORDERS(order) {
 
			if ((order->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == (OUFB_UNLOAD | OUFB_TRANSFER)) {
 
				order->SetUnloadType(OUFB_TRANSFER);
 
				order->SetLoadType(OLFB_NO_LOAD);
 
			}
 
		}
 

	
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if ((v->current_order.GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == (OUFB_UNLOAD | OUFB_TRANSFER)) {
 
				v->current_order.SetUnloadType(OUFB_TRANSFER);
 
				v->current_order.SetLoadType(OLFB_NO_LOAD);
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(84)) {
 
		/* Update go to buoy orders because they are just waypoints */
 
		Order *order;
 
		FOR_ALL_ORDERS(order) {
 
			if (order->IsType(OT_GOTO_STATION) && GetStation(order->GetDestination())->IsBuoy()) {
 
				order->SetLoadType(OLF_LOAD_IF_POSSIBLE);
 
				order->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE);
 
			}
 
		}
 

	
 
		/* Set all share owners to INVALID_COMPANY for
 
		 * 1) all inactive companies
 
		 *     (when inactive companies were stored in the savegame - TTD, TTDP and some
 
		 *      *really* old revisions of OTTD; else it is already set in InitializeCompanies())
 
		 * 2) shares that are owned by inactive companies or self
 
		 *     (caused by cheating clients in earlier revisions) */
 
		FOR_ALL_COMPANIES(c) {
 
			for (uint i = 0; i < 4; i++) {
 
				CompanyID company = c->share_owners[i];
 
				if (company == INVALID_COMPANY) continue;
 
				if (!IsValidCompanyID(company) || company == c->index) c->share_owners[i] = INVALID_COMPANY;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(86)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			/* Move river flag and update canals to use water class */
 
			if (IsTileType(t, MP_WATER)) {
 
				if (GetWaterClass(t) != WATER_CLASS_RIVER) {
 
					if (IsWater(t)) {
 
						Owner o = GetTileOwner(t);
 
						if (o == OWNER_WATER) {
 
							MakeWater(t);
 
						} else {
 
							MakeCanal(t, o, Random());
 
						}
 
					} else if (IsShipDepot(t)) {
 
						Owner o = (Owner)_m[t].m4; // Original water owner
 
						SetWaterClass(t, o == OWNER_WATER ? WATER_CLASS_SEA : WATER_CLASS_CANAL);
 
					}
 
				}
 
			}
 
		}
 

	
 
		/* Update locks, depots, docks and buoys to have a water class based
 
		 * on its neighbouring tiles. Done after river and canal updates to
 
		 * ensure neighbours are correct. */
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (GetTileSlope(t, NULL) != SLOPE_FLAT) continue;
 

	
 
			if (IsTileType(t, MP_WATER) && IsLock(t)) SetWaterClassDependingOnSurroundings(t, false);
 
			if (IsTileType(t, MP_STATION) && (IsDock(t) || IsBuoy(t))) SetWaterClassDependingOnSurroundings(t, false);
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(87)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			/* skip oil rigs at borders! */
 
			if ((IsTileType(t, MP_WATER) || IsBuoyTile(t)) &&
 
					(TileX(t) == 0 || TileY(t) == 0 || TileX(t) == MapMaxX() - 1 || TileY(t) == MapMaxY() - 1)) {
 
				/* Some version 86 savegames have wrong water class at map borders (under buoy, or after removing buoy).
 
				 * This conversion has to be done before buoys with invalid owner are removed. */
 
				SetWaterClass(t, WATER_CLASS_SEA);
 
			}
 

	
 
			if (IsBuoyTile(t) || IsDriveThroughStopTile(t) || IsTileType(t, MP_WATER)) {
 
				Owner o = GetTileOwner(t);
 
				if (o < MAX_COMPANIES && !IsValidCompanyID(o)) {
 
					_current_company = o;
 
					ChangeTileOwner(t, o, INVALID_OWNER);
 
				}
 
				if (IsBuoyTile(t)) {
 
					/* reset buoy owner to OWNER_NONE in the station struct
 
					 * (even if it is owned by active company) */
 
					GetStationByTile(t)->owner = OWNER_NONE;
 
				}
 
			} else if (IsTileType(t, MP_ROAD)) {
 
				/* works for all RoadTileType */
 
				for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) {
 
					/* update even non-existing road types to update tile owner too */
 
					Owner o = GetRoadOwner(t, rt);
 
					if (o < MAX_COMPANIES && !IsValidCompanyID(o)) SetRoadOwner(t, rt, OWNER_NONE);
 
				}
 
				if (IsLevelCrossing(t)) {
 
					Owner o = GetTileOwner(t);
 
					if (!IsValidCompanyID(o)) {
 
						/* remove leftover rail piece from crossing (from very old savegames) */
 
						_current_company = o;
 
						DoCommand(t, 0, GetCrossingRailTrack(t), DC_EXEC | DC_BANKRUPT, CMD_REMOVE_SINGLE_RAIL);
 
					}
 
				}
 
			}
 
		}
 

	
 
		/* Convert old PF settings to new */
 
		if (_settings_game.pf.yapf.rail_use_yapf || CheckSavegameVersion(28)) {
 
			_settings_game.pf.pathfinder_for_trains = VPF_YAPF;
 
		} else {
 
			_settings_game.pf.pathfinder_for_trains = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_NTP);
 
		}
 

	
 
		if (_settings_game.pf.yapf.road_use_yapf || CheckSavegameVersion(28)) {
 
			_settings_game.pf.pathfinder_for_roadvehs = VPF_YAPF;
 
		} else {
 
			_settings_game.pf.pathfinder_for_roadvehs = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_OPF);
 
		}
 

	
 
		if (_settings_game.pf.yapf.ship_use_yapf) {
 
			_settings_game.pf.pathfinder_for_ships = VPF_YAPF;
 
		} else {
 
			_settings_game.pf.pathfinder_for_ships = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_OPF);
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(88)) {
 
		/* Profits are now with 8 bit fract */
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			v->profit_this_year <<= 8;
 
			v->profit_last_year <<= 8;
 
			v->running_ticks = 0;
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(91)) {
 
		/* Increase HouseAnimationFrame from 5 to 7 bits */
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_HOUSE) && GetHouseType(t) >= NEW_HOUSE_OFFSET) {
 
				SetHouseAnimationFrame(t, GB(_m[t].m6, 3, 5));
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(62)) {
 
		/* Remove all trams from savegames without tram support.
 
		 * There would be trams without tram track under causing crashes sooner or later. */
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_ROAD && v->First() == v &&
 
					HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM)) {
 
				if (_switch_mode_errorstr == INVALID_STRING_ID || _switch_mode_errorstr == STR_NEWGRF_COMPATIBLE_LOAD_WARNING) {
 
					_switch_mode_errorstr = STR_LOADGAME_REMOVED_TRAMS;
 
				}
 
				delete v;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(99)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			/* Set newly introduced WaterClass of industry tiles */
 
			if (IsTileType(t, MP_STATION) && IsOilRig(t)) {
 
				SetWaterClassDependingOnSurroundings(t, true);
 
			}
 
			if (IsTileType(t, MP_INDUSTRY)) {
 
				if ((GetIndustrySpec(GetIndustryType(t))->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) {
 
					SetWaterClassDependingOnSurroundings(t, true);
 
				} else {
 
					SetWaterClass(t, WATER_CLASS_INVALID);
 
				}
 
			}
 

	
 
			/* Replace "house construction year" with "house age" */
 
			if (IsTileType(t, MP_HOUSE) && IsHouseCompleted(t)) {
 
				_m[t].m5 = Clamp(_cur_year - (_m[t].m5 + ORIGINAL_BASE_YEAR), 0, 0xFF);
 
			}
 
		}
 
	}
 

	
 
	/* Move the signal variant back up one bit for PBS. We don't convert the old PBS
 
	 * format here, as an old layout wouldn't work properly anyway. To be safe, we
 
	 * clear any possible PBS reservations as well. */
 
	if (CheckSavegameVersion(100)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			switch (GetTileType(t)) {
 
				case MP_RAILWAY:
 
					if (HasSignals(t)) {
 
						/* move the signal variant */
 
						SetSignalVariant(t, TRACK_UPPER, HasBit(_m[t].m2, 2) ? SIG_SEMAPHORE : SIG_ELECTRIC);
 
						SetSignalVariant(t, TRACK_LOWER, HasBit(_m[t].m2, 6) ? SIG_SEMAPHORE : SIG_ELECTRIC);
 
						ClrBit(_m[t].m2, 2);
 
						ClrBit(_m[t].m2, 6);
 
					}
 

	
 
					/* Clear PBS reservation on track */
 
					if (IsRailDepot(t) ||IsRailWaypoint(t)) {
 
						SetDepotWaypointReservation(t, false);
 
					} else {
 
						SetTrackReservation(t, TRACK_BIT_NONE);
 
					}
 
					break;
 

	
 
				case MP_ROAD: /* Clear PBS reservation on crossing */
 
					if (IsLevelCrossing(t)) SetCrossingReservation(t, false);
 
					break;
 

	
 
				case MP_STATION: /* Clear PBS reservation on station */
 
					if (IsRailwayStation(t)) SetRailwayStationReservation(t, false);
 
					break;
 

	
 
				case MP_TUNNELBRIDGE: /* Clear PBS reservation on tunnels/birdges */
 
					if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) SetTunnelBridgeReservation(t, false);
 
					break;
 

	
 
				default: break;
 
			}
 
		}
 
	}
 

	
 
	/* Reserve all tracks trains are currently on. */
 
	if (CheckSavegameVersion(101)) {
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_TRAIN) {
 
				if ((v->u.rail.track & TRACK_BIT_WORMHOLE) == TRACK_BIT_WORMHOLE) {
 
					TryReserveRailTrack(v->tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(v->tile)));
 
				} else if ((v->u.rail.track & TRACK_BIT_MASK) != TRACK_BIT_NONE) {
 
					TryReserveRailTrack(v->tile, TrackBitsToTrack(v->u.rail.track));
 
				}
 
			}
 
		}
 

	
 
		/* Give owners to waypoints, based on rail tracks it is sitting on.
 
		 * If none is available, specify OWNER_NONE */
 
		Waypoint *wp;
 
		FOR_ALL_WAYPOINTS(wp) {
 
			Owner owner = (IsRailWaypointTile(wp->xy) ? GetTileOwner(wp->xy) : OWNER_NONE);
 
			wp->owner = IsValidCompanyID(owner) ? owner : OWNER_NONE;
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(102)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			/* Now all crossings should be in correct state */
 
			if (IsLevelCrossingTile(t)) UpdateLevelCrossing(t, false);
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(103)) {
 
		/* Non-town-owned roads now store the closest town */
 
		UpdateNearestTownForRoadTiles(false);
 

	
 
		/* signs with invalid owner left from older savegames */
 
		Sign *si;
 
		FOR_ALL_SIGNS(si) {
 
			if (si->owner != OWNER_NONE && !IsValidCompanyID(si->owner)) si->owner = OWNER_NONE;
 
		}
 

	
 
		/* Station can get named based on an industry type, but the current ones
 
		 * are not, so mark them as if they are not named by an industry. */
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			st->indtype = IT_INVALID;
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(104)) {
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			/* Set engine_type of shadow and rotor */
 
			if (v->type == VEH_AIRCRAFT && !IsNormalAircraft(v)) {
 
				v->engine_type = v->First()->engine_type;
 
			}
 
		}
 

	
 
		/* More companies ... */
 
		Company *c;
 
		FOR_ALL_COMPANIES(c) {
 
			if (c->bankrupt_asked == 0xFF) c->bankrupt_asked = 0xFFFF;
 
		}
 

	
 
		Engine *e;
 
		FOR_ALL_ENGINES(e) {
 
			if (e->company_avail == 0xFF) e->company_avail = 0xFFFF;
 
		}
 

	
 
		Town *t;
 
		FOR_ALL_TOWNS(t) {
 
			if (t->have_ratings == 0xFF) t->have_ratings = 0xFFFF;
 
			for (uint i = 8; i != MAX_COMPANIES; i++) t->ratings[i] = RATING_INITIAL;
 
		}
 
	}
 

	
 
	GamelogPrintDebug(1);
 

	
 
	bool ret = InitializeWindowsAndCaches();
 
	/* Restore the signals */
 
	signal(SIGSEGV, prev_segfault);
 
	signal(SIGABRT, prev_abort);
 
	return ret;
 
}
 

	
 
/** Reload all NewGRF files during a running game. This is a cut-down
 
 * version of AfterLoadGame().
 
 * XXX - We need to reset the vehicle position hash because with a non-empty
 
 * hash AfterLoadVehicles() will loop infinitely. We need AfterLoadVehicles()
 
 * to recalculate vehicle data as some NewGRF vehicle sets could have been
 
 * removed or added and changed statistics */
 
void ReloadNewGRFData()
 
{
 
	/* reload grf data */
 
	GfxLoadSprites();
 
	LoadStringWidthTable();
 
	ResetEconomy();
 
	/* reload vehicles */
 
	ResetVehiclePosHash();
 
	AfterLoadVehicles(false);
 
	StartupEngines();
 
	SetCachedEngineCounts();
 
	/* update station and waypoint graphics */
 
	AfterLoadWaypoints();
 
	AfterLoadStations();
 
	/* Check and update house and town values */
 
	UpdateHousesAndTowns();
 
	/* Update livery selection windows */
 
	for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) InvalidateWindowData(WC_COMPANY_COLOR, i, _loaded_newgrf_features.has_2CC);
 
	/* redraw the whole screen */
 
	MarkWholeScreenDirty();
 
	CheckTrainsLengths();
 
}
src/order_base.h
Show inline comments
 
@@ -431,7 +431,4 @@ static inline bool IsValidOrderListID(ui
 
#define FOR_ALL_ORDER_LISTS_FROM(ol, start) for (ol = GetOrderList(start); ol != NULL; ol = (ol->index + 1U < GetOrderListPoolSize()) ? GetOrderList(ol->index + 1U) : NULL) if (ol->IsValid())
 
#define FOR_ALL_ORDER_LISTS(ol) FOR_ALL_ORDER_LISTS_FROM(ol, 0)
 

	
 
/* (Un)pack routines */
 
Order UnpackOldOrder(uint16 packed);
 

	
 
#endif /* ORDER_H */
src/order_cmd.cpp
Show inline comments
 
@@ -13,7 +13,6 @@
 
#include "command_func.h"
 
#include "company_func.h"
 
#include "news_func.h"
 
#include "saveload.h"
 
#include "vehicle_gui.h"
 
#include "cargotype.h"
 
#include "aircraft.h"
 
@@ -147,82 +146,6 @@ Order::Order(uint32 packed)
 
	this->travel_time   = 0;
 
}
 

	
 
void Order::ConvertFromOldSavegame()
 
{
 
	uint8 old_flags = this->flags;
 
	this->flags = 0;
 

	
 
	/* First handle non-stop */
 
	if (_settings_client.gui.sg_new_nonstop) {
 
		/* OFB_NON_STOP */
 
		this->SetNonStopType((old_flags & 8) ? ONSF_NO_STOP_AT_ANY_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS);
 
	} else {
 
		this->SetNonStopType((old_flags & 8) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE);
 
	}
 

	
 
	switch (this->GetType()) {
 
		/* Only a few types need the other savegame conversions. */
 
		case OT_GOTO_DEPOT: case OT_GOTO_STATION: case OT_LOADING: break;
 
		default: return;
 
	}
 

	
 
	if (this->GetType() != OT_GOTO_DEPOT) {
 
		/* Then the load flags */
 
		if ((old_flags & 2) != 0) { // OFB_UNLOAD
 
			this->SetLoadType(OLFB_NO_LOAD);
 
		} else if ((old_flags & 4) == 0) { // !OFB_FULL_LOAD
 
			this->SetLoadType(OLF_LOAD_IF_POSSIBLE);
 
		} else {
 
			this->SetLoadType(_settings_client.gui.sg_full_load_any ? OLF_FULL_LOAD_ANY : OLFB_FULL_LOAD);
 
		}
 

	
 
		/* Finally fix the unload flags */
 
		if ((old_flags & 1) != 0) { // OFB_TRANSFER
 
			this->SetUnloadType(OUFB_TRANSFER);
 
		} else if ((old_flags & 2) != 0) { // OFB_UNLOAD
 
			this->SetUnloadType(OUFB_UNLOAD);
 
		} else {
 
			this->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE);
 
		}
 
	} else {
 
		/* Then the depot action flags */
 
		this->SetDepotActionType(((old_flags & 6) == 4) ? ODATFB_HALT : ODATF_SERVICE_ONLY);
 

	
 
		/* Finally fix the depot type flags */
 
		uint t = ((old_flags & 6) == 6) ? ODTFB_SERVICE : ODTF_MANUAL;
 
		if ((old_flags & 2) != 0) t |= ODTFB_PART_OF_ORDERS;
 
		this->SetDepotOrderType((OrderDepotTypeFlags)t);
 
	}
 
}
 

	
 
/**
 
 *
 
 * Unpacks a order from savegames with version 4 and lower
 
 *
 
 */
 
static Order UnpackVersion4Order(uint16 packed)
 
{
 
	return Order(GB(packed, 8, 8) << 16 | GB(packed, 4, 4) << 8 | GB(packed, 0, 4));
 
}
 

	
 
/**
 
 *
 
 * Unpacks a order from savegames made with TTD(Patch)
 
 *
 
 */
 
Order UnpackOldOrder(uint16 packed)
 
{
 
	Order order = UnpackVersion4Order(packed);
 

	
 
	/*
 
	 * Sanity check
 
	 * TTD stores invalid orders as OT_NOTHING with non-zero flags/station
 
	 */
 
	if (!order.IsValid() && packed != 0) order.MakeDummy();
 

	
 
	return order;
 
}
 

	
 
/**
 
 *
 
 * Updates the widgets of a vehicle which contains the order-data
 
@@ -1898,118 +1821,3 @@ void InitializeOrders()
 

	
 
	_backup_orders_tile = 0;
 
}
 

	
 
const SaveLoad *GetOrderDescription() {
 
static const SaveLoad _order_desc[] = {
 
	SLE_VAR(Order, type,  SLE_UINT8),
 
	SLE_VAR(Order, flags, SLE_UINT8),
 
	SLE_VAR(Order, dest,  SLE_UINT16),
 
	SLE_REF(Order, next,  REF_ORDER),
 
	SLE_CONDVAR(Order, refit_cargo,    SLE_UINT8,  36, SL_MAX_VERSION),
 
	SLE_CONDVAR(Order, refit_subtype,  SLE_UINT8,  36, SL_MAX_VERSION),
 
	SLE_CONDVAR(Order, wait_time,      SLE_UINT16, 67, SL_MAX_VERSION),
 
	SLE_CONDVAR(Order, travel_time,    SLE_UINT16, 67, SL_MAX_VERSION),
 

	
 
	/* Leftover from the minor savegame version stuff
 
	 * We will never use those free bytes, but we have to keep this line to allow loading of old savegames */
 
	SLE_CONDNULL(10, 5, 35),
 
	SLE_END()
 
};
 
	return _order_desc;
 
}
 

	
 
static void Save_ORDR()
 
{
 
	Order *order;
 

	
 
	FOR_ALL_ORDERS(order) {
 
		SlSetArrayIndex(order->index);
 
		SlObject(order, GetOrderDescription());
 
	}
 
}
 

	
 
static void Load_ORDR()
 
{
 
	if (CheckSavegameVersionOldStyle(5, 2)) {
 
		/* Version older than 5.2 did not have a ->next pointer. Convert them
 
		    (in the old days, the orderlist was 5000 items big) */
 
		size_t len = SlGetFieldLength();
 
		uint i;
 

	
 
		if (CheckSavegameVersion(5)) {
 
			/* Pre-version 5 had an other layout for orders
 
			    (uint16 instead of uint32) */
 
			len /= sizeof(uint16);
 
			uint16 *orders = MallocT<uint16>(len + 1);
 

	
 
			SlArray(orders, len, SLE_UINT16);
 

	
 
			for (i = 0; i < len; ++i) {
 
				Order *order = new (i) Order();
 
				order->AssignOrder(UnpackVersion4Order(orders[i]));
 
			}
 

	
 
			free(orders);
 
		} else if (CheckSavegameVersionOldStyle(5, 2)) {
 
			len /= sizeof(uint16);
 
			uint16 *orders = MallocT<uint16>(len + 1);
 

	
 
			SlArray(orders, len, SLE_UINT32);
 

	
 
			for (i = 0; i < len; ++i) {
 
				new (i) Order(orders[i]);
 
			}
 

	
 
			free(orders);
 
		}
 

	
 
		/* Update all the next pointer */
 
		for (i = 1; i < len; ++i) {
 
			/* The orders were built like this:
 
			 *   While the order is valid, set the previous will get it's next pointer set
 
			 *   We start with index 1 because no order will have the first in it's next pointer */
 
			if (GetOrder(i)->IsValid())
 
				GetOrder(i - 1)->next = GetOrder(i);
 
		}
 
	} else {
 
		int index;
 

	
 
		while ((index = SlIterateArray()) != -1) {
 
			Order *order = new (index) Order();
 
			SlObject(order, GetOrderDescription());
 
		}
 
	}
 
}
 

	
 
const SaveLoad *GetOrderListDescription() {
 
static const SaveLoad _orderlist_desc[] = {
 
	SLE_REF(OrderList, first,              REF_ORDER),
 
	SLE_END()
 
};
 
	return _orderlist_desc;
 
}
 

	
 
static void Save_ORDL()
 
{
 
	OrderList *list;
 

	
 
	FOR_ALL_ORDER_LISTS(list) {
 
		SlSetArrayIndex(list->index);
 
		SlObject(list, GetOrderListDescription());
 
	}
 
}
 

	
 
static void Load_ORDL()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		OrderList *list = new (index) OrderList();
 
		SlObject(list, GetOrderListDescription());
 
	}
 
}
 

	
 
extern const ChunkHandler _order_chunk_handlers[] = {
 
	{ 'ORDR', Save_ORDR, Load_ORDR, CH_ARRAY},
 
	{ 'ORDL', Save_ORDL, Load_ORDL, CH_ARRAY | CH_LAST},
 
};
src/saveload.cpp
Show inline comments
 
deleted file
src/saveload.h
Show inline comments
 
deleted file
src/saveload/afterload.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file afterload.cpp Code updating data after game load */
 

	
 
#include "../stdafx.h"
 
#include "../strings_type.h"
 
#include "../tile_type.h"
 
#include "../tile_map.h"
 
#include "../map_type.h"
 
#include "../road_map.h"
 
#include "../town.h"
 
#include "../void_map.h"
 
#include "../signs_base.h"
 
#include "../window_func.h"
 
#include "../station_func.h"
 
#include "../company_base.h"
 
#include "../fios.h"
 
#include "../date_func.h"
 
#include "../engine_func.h"
 
#include "../train.h"
 
#include "../string_func.h"
 
#include "../newgrf_config.h"
 
#include "../gamelog.h"
 
#include "../waypoint.h"
 
#include "../station_map.h"
 
#include "../station_base.h"
 
#include "../tunnelbridge_map.h"
 
#include "../debug.h"
 
#include "../network/network.h"
 
#include "../openttd.h"
 
#include "../gfxinit.h"
 
#include "../gfx_func.h"
 
#include "../functions.h"
 
#include "../industry_map.h"
 
#include "../town_map.h"
 
#include "../clear_map.h"
 
#include "../engine_base.h"
 
#include "../landscape.h"
 
#include "../vehicle_func.h"
 
#include "../newgrf_station.h"
 
#include "../yapf/yapf.hpp"
 
#include "../elrail_func.h"
 
#include "../signs_func.h"
 
#include "../newgrf_house.h"
 
#include "../aircraft.h"
 
#include "../unmovable_map.h"
 
#include "../tree_map.h"
 
#include "../company_func.h"
 
#include "../command_func.h"
 
#include "../road_cmd.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "saveload.h"
 
#include "saveload_internal.h"
 

	
 
#include <signal.h>
 

	
 
extern StringID _switch_mode_errorstr;
 
extern Company *DoStartupNewCompany(bool is_ai);
 
extern void InitializeRailGUI();
 

	
 
/**
 
 * Makes a tile canal or water depending on the surroundings.
 
 *
 
 * Must only be used for converting old savegames. Use WaterClass now.
 
 *
 
 * This as for example docks and shipdepots do not store
 
 * whether the tile used to be canal or 'normal' water.
 
 * @param t the tile to change.
 
 * @param o the owner of the new tile.
 
 * @param include_invalid_water_class Also consider WATER_CLASS_INVALID, i.e. industry tiles on land
 
 */
 
void SetWaterClassDependingOnSurroundings(TileIndex t, bool include_invalid_water_class)
 
{
 
	/* If the slope is not flat, we always assume 'land' (if allowed). Also for one-corner-raised-shores.
 
	 * Note: Wrt. autosloping under industry tiles this is the most fool-proof behaviour. */
 
	if (GetTileSlope(t, NULL) != SLOPE_FLAT) {
 
		if (include_invalid_water_class) {
 
			SetWaterClass(t, WATER_CLASS_INVALID);
 
			return;
 
		} else {
 
			NOT_REACHED();
 
		}
 
	}
 

	
 
	/* Mark tile dirty in all cases */
 
	MarkTileDirtyByTile(t);
 

	
 
	if (TileX(t) == 0 || TileY(t) == 0 || TileX(t) == MapMaxX() - 1 || TileY(t) == MapMaxY() - 1) {
 
		/* tiles at map borders are always WATER_CLASS_SEA */
 
		SetWaterClass(t, WATER_CLASS_SEA);
 
		return;
 
	}
 

	
 
	bool has_water = false;
 
	bool has_canal = false;
 
	bool has_river = false;
 

	
 
	for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
 
		TileIndex neighbour = TileAddByDiagDir(t, dir);
 
		switch (GetTileType(neighbour)) {
 
			case MP_WATER:
 
				/* clear water and shipdepots have already a WaterClass associated */
 
				if (IsCoast(neighbour)) {
 
					has_water = true;
 
				} else if (!IsLock(neighbour)) {
 
					switch (GetWaterClass(neighbour)) {
 
						case WATER_CLASS_SEA:   has_water = true; break;
 
						case WATER_CLASS_CANAL: has_canal = true; break;
 
						case WATER_CLASS_RIVER: has_river = true; break;
 
						default: NOT_REACHED();
 
					}
 
				}
 
				break;
 

	
 
			case MP_RAILWAY:
 
				/* Shore or flooded halftile */
 
				has_water |= (GetRailGroundType(neighbour) == RAIL_GROUND_WATER);
 
				break;
 

	
 
			case MP_TREES:
 
				/* trees on shore */
 
				has_water |= (GetTreeGround(neighbour) == TREE_GROUND_SHORE);
 
				break;
 

	
 
			default: break;
 
		}
 
	}
 

	
 
	if (!has_water && !has_canal && !has_river && include_invalid_water_class) {
 
		SetWaterClass(t, WATER_CLASS_INVALID);
 
		return;
 
	}
 

	
 
	if (has_river && !has_canal) {
 
		SetWaterClass(t, WATER_CLASS_RIVER);
 
	} else if (has_canal || !has_water) {
 
		SetWaterClass(t, WATER_CLASS_CANAL);
 
	} else {
 
		SetWaterClass(t, WATER_CLASS_SEA);
 
	}
 
}
 

	
 
static void ConvertTownOwner()
 
{
 
	for (TileIndex tile = 0; tile != MapSize(); tile++) {
 
		switch (GetTileType(tile)) {
 
			case MP_ROAD:
 
				if (GB(_m[tile].m5, 4, 2) == ROAD_TILE_CROSSING && HasBit(_m[tile].m3, 7)) {
 
					_m[tile].m3 = OWNER_TOWN;
 
				}
 
				/* FALLTHROUGH */
 

	
 
			case MP_TUNNELBRIDGE:
 
				if (GetTileOwner(tile) & 0x80) SetTileOwner(tile, OWNER_TOWN);
 
				break;
 

	
 
			default: break;
 
		}
 
	}
 
}
 

	
 
/* since savegame version 4.1, exclusive transport rights are stored at towns */
 
static void UpdateExclusiveRights()
 
{
 
	Town *t;
 

	
 
	FOR_ALL_TOWNS(t) {
 
		t->exclusivity = INVALID_COMPANY;
 
	}
 

	
 
	/* FIXME old exclusive rights status is not being imported (stored in s->blocked_months_obsolete)
 
	 *   could be implemented this way:
 
	 * 1.) Go through all stations
 
	 *     Build an array town_blocked[ town_id ][ company_id ]
 
	 *     that stores if at least one station in that town is blocked for a company
 
	 * 2.) Go through that array, if you find a town that is not blocked for
 
	 *     one company, but for all others, then give him exclusivity.
 
	 */
 
}
 

	
 
static const byte convert_currency[] = {
 
	 0,  1, 12,  8,  3,
 
	10, 14, 19,  4,  5,
 
	 9, 11, 13,  6, 17,
 
	16, 22, 21,  7, 15,
 
	18,  2, 20,
 
};
 

	
 
/* since savegame version 4.2 the currencies are arranged differently */
 
static void UpdateCurrencies()
 
{
 
	_settings_game.locale.currency = convert_currency[_settings_game.locale.currency];
 
}
 

	
 
/* Up to revision 1413 the invisible tiles at the southern border have not been
 
 * MP_VOID, even though they should have. This is fixed by this function
 
 */
 
static void UpdateVoidTiles()
 
{
 
	uint i;
 

	
 
	for (i = 0; i < MapMaxY(); ++i) MakeVoid(i * MapSizeX() + MapMaxX());
 
	for (i = 0; i < MapSizeX(); ++i) MakeVoid(MapSizeX() * MapMaxY() + i);
 
}
 

	
 
/* since savegame version 6.0 each sign has an "owner", signs without owner (from old games are set to 255) */
 
static void UpdateSignOwner()
 
{
 
	Sign *si;
 

	
 
	FOR_ALL_SIGNS(si) si->owner = OWNER_NONE;
 
}
 

	
 
static inline RailType UpdateRailType(RailType rt, RailType min)
 
{
 
	return rt >= min ? (RailType)(rt + 1): rt;
 
}
 

	
 
/**
 
 * Initialization of the windows and several kinds of caches.
 
 * This is not done directly in AfterLoadGame because these
 
 * functions require that all saveload conversions have been
 
 * done. As people tend to add savegame conversion stuff after
 
 * the intialization of the windows and caches quite some bugs
 
 * had been made.
 
 * Moving this out of there is both cleaner and less bug-prone.
 
 *
 
 * @return true if everything went according to plan, otherwise false.
 
 */
 
static bool InitializeWindowsAndCaches()
 
{
 
	/* Initialize windows */
 
	ResetWindowSystem();
 
	SetupColorsAndInitialWindow();
 

	
 
	ResetViewportAfterLoadGame();
 

	
 
	/* Update coordinates of the signs. */
 
	UpdateAllStationVirtCoord();
 
	UpdateAllSignVirtCoords();
 
	UpdateAllTownVirtCoords();
 
	UpdateAllWaypointSigns();
 

	
 
	Company *c;
 
	FOR_ALL_COMPANIES(c) {
 
		/* For each company, verify (while loading a scenario) that the inauguration date is the current year and set it
 
		 * accordingly if it is not the case.  No need to set it on companies that are not been used already,
 
		 * thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */
 
		if (_file_to_saveload.filetype == FT_SCENARIO && c->inaugurated_year != MIN_YEAR) {
 
			c->inaugurated_year = _cur_year;
 
		}
 
	}
 

	
 
	SetCachedEngineCounts();
 

	
 
	/* Towns have a noise controlled number of airports system
 
	 * So each airport's noise value must be added to the town->noise_reached value
 
	 * Reset each town's noise_reached value to '0' before. */
 
	UpdateAirportsNoise();
 

	
 
	CheckTrainsLengths();
 

	
 
	return true;
 
}
 

	
 
/**
 
 * Signal handler used to give a user a more useful report for crashes during
 
 * the savegame loading process; especially when there's problems with the
 
 * NewGRFs that are required by the savegame.
 
 * @param unused well... unused
 
 */
 
void CDECL HandleSavegameLoadCrash(int unused)
 
{
 
	char buffer[8192];
 
	char *p = buffer;
 
	p += seprintf(p, lastof(buffer),
 
			"Loading your savegame caused OpenTTD to crash.\n"
 
			"This is most likely caused by a missing NewGRF or a NewGRF that has been\n"
 
			"loaded as replacement for a missing NewGRF. OpenTTD cannot easily\n"
 
			"determine whether a replacement NewGRF is of a newer or older version.\n"
 
			"It will load a NewGRF with the same GRF ID as the missing NewGRF. This\n"
 
			"means that if the author makes incompatible NewGRFs with the same GRF ID\n"
 
			"OpenTTD cannot magically do the right thing. In most cases OpenTTD will\n"
 
			"load the savegame and not crash, but this is an exception.\n"
 
			"Please load the savegame with the appropriate NewGRFs. When loading a\n"
 
			"savegame still crashes when all NewGRFs are found you should file a\n"
 
			"bug report. The missing NewGRFs are:\n");
 

	
 
	for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) {
 
		if (HasBit(c->flags, GCF_COMPATIBLE)) {
 
			char buf[40];
 
			md5sumToString(buf, lastof(buf), c->md5sum);
 
			p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s. Tried another NewGRF with same GRF ID\n", BSWAP32(c->grfid), c->filename, buf);
 
		}
 
		if (c->status == GCS_NOT_FOUND) {
 
			char buf[40];
 
			md5sumToString(buf, lastof(buf), c->md5sum);
 
			p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s\n", BSWAP32(c->grfid), c->filename, buf);
 
		}
 
	}
 

	
 
	ShowInfo(buffer);
 
}
 

	
 

	
 
bool AfterLoadGame()
 
{
 
	typedef void (CDECL *SignalHandlerPointer)(int);
 
	SignalHandlerPointer prev_segfault = signal(SIGSEGV, HandleSavegameLoadCrash);
 
	SignalHandlerPointer prev_abort = signal(SIGABRT, HandleSavegameLoadCrash);
 

	
 
	TileIndex map_size = MapSize();
 
	Company *c;
 

	
 
	if (CheckSavegameVersion(98)) GamelogOldver();
 

	
 
	GamelogTestRevision();
 
	GamelogTestMode();
 

	
 
	if (CheckSavegameVersion(98)) GamelogGRFAddList(_grfconfig);
 

	
 
	/* in very old versions, size of train stations was stored differently */
 
	if (CheckSavegameVersion(2)) {
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			if (st->train_tile != 0 && st->trainst_h == 0) {
 
				extern SavegameType _savegame_type;
 
				uint n = _savegame_type == SGT_OTTD ? 4 : 3; // OTTD uses 4 bits per dimensions, TTD 3 bits
 
				uint w = GB(st->trainst_w, n, n);
 
				uint h = GB(st->trainst_w, 0, n);
 

	
 
				if (GetRailStationAxis(st->train_tile) != AXIS_X) Swap(w, h);
 

	
 
				st->trainst_w = w;
 
				st->trainst_h = h;
 

	
 
				assert(GetStationIndex(st->train_tile + TileDiffXY(w - 1, h - 1)) == st->index);
 
			}
 
		}
 
	}
 

	
 
	/* in version 2.1 of the savegame, town owner was unified. */
 
	if (CheckSavegameVersionOldStyle(2, 1)) ConvertTownOwner();
 

	
 
	/* from version 4.1 of the savegame, exclusive rights are stored at towns */
 
	if (CheckSavegameVersionOldStyle(4, 1)) UpdateExclusiveRights();
 

	
 
	/* from version 4.2 of the savegame, currencies are in a different order */
 
	if (CheckSavegameVersionOldStyle(4, 2)) UpdateCurrencies();
 

	
 
	/* from version 6.1 of the savegame, signs have an "owner" */
 
	if (CheckSavegameVersionOldStyle(6, 1)) UpdateSignOwner();
 

	
 
	/* In old version there seems to be a problem that water is owned by
 
	 * OWNER_NONE, not OWNER_WATER.. I can't replicate it for the current
 
	 * (4.3) version, so I just check when versions are older, and then
 
	 * walk through the whole map.. */
 
	if (CheckSavegameVersionOldStyle(4, 3)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_WATER) && GetTileOwner(t) >= MAX_COMPANIES) {
 
				SetTileOwner(t, OWNER_WATER);
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(84)) {
 
		FOR_ALL_COMPANIES(c) {
 
			c->name = CopyFromOldName(c->name_1);
 
			if (c->name != NULL) c->name_1 = STR_SV_UNNAMED;
 
			c->president_name = CopyFromOldName(c->president_name_1);
 
			if (c->president_name != NULL) c->president_name_1 = SPECSTR_PRESIDENT_NAME;
 
		}
 

	
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			st->name = CopyFromOldName(st->string_id);
 
			/* generating new name would be too much work for little effect, use the station name fallback */
 
			if (st->name != NULL) st->string_id = STR_SV_STNAME_FALLBACK;
 
		}
 

	
 
		Town *t;
 
		FOR_ALL_TOWNS(t) {
 
			t->name = CopyFromOldName(t->townnametype);
 
			if (t->name != NULL) t->townnametype = SPECSTR_TOWNNAME_START + _settings_game.game_creation.town_name;
 
		}
 

	
 
		Waypoint *wp;
 
		FOR_ALL_WAYPOINTS(wp) {
 
			wp->name = CopyFromOldName(wp->string);
 
			wp->string = STR_EMPTY;
 
		}
 

	
 
		for (uint i = 0; i < GetSignPoolSize(); i++) {
 
			/* invalid signs are determined by si->ower == INVALID_COMPANY now */
 
			Sign *si = GetSign(i);
 
			if (!si->IsValid() && si->name != NULL) {
 
				si->owner = OWNER_NONE;
 
			}
 
		}
 
	}
 

	
 
	/* From this point the old names array is cleared. */
 
	ResetOldNames();
 

	
 
	if (CheckSavegameVersion(106)) {
 
		/* no station is determined by 'tile == INVALID_TILE' now (instead of '0') */
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			if (st->airport_tile == 0) st->airport_tile = INVALID_TILE;
 
			if (st->dock_tile    == 0) st->dock_tile    = INVALID_TILE;
 
			if (st->train_tile   == 0) st->train_tile   = INVALID_TILE;
 
		}
 

	
 
		/* the same applies to Company::location_of_HQ */
 
		Company *c;
 
		FOR_ALL_COMPANIES(c) {
 
			if (c->location_of_HQ == 0 || (CheckSavegameVersion(4) && c->location_of_HQ == 0xFFFF)) {
 
				c->location_of_HQ = INVALID_TILE;
 
			}
 
		}
 
	}
 

	
 
	/* convert road side to my format. */
 
	if (_settings_game.vehicle.road_side) _settings_game.vehicle.road_side = 1;
 

	
 
	/* Check if all NewGRFs are present, we are very strict in MP mode */
 
	GRFListCompatibility gcf_res = IsGoodGRFConfigList();
 
	if (_networking && gcf_res != GLC_ALL_GOOD) {
 
		SetSaveLoadError(STR_NETWORK_ERR_CLIENT_NEWGRF_MISMATCH);
 
		/* Restore the signals */
 
		signal(SIGSEGV, prev_segfault);
 
		signal(SIGABRT, prev_abort);
 
		return false;
 
	}
 

	
 
	switch (gcf_res) {
 
		case GLC_COMPATIBLE: _switch_mode_errorstr = STR_NEWGRF_COMPATIBLE_LOAD_WARNING; break;
 
		case GLC_NOT_FOUND: _switch_mode_errorstr = STR_NEWGRF_DISABLED_WARNING; _pause_game = -1; break;
 
		default: break;
 
	}
 

	
 
	/* Update current year
 
	 * must be done before loading sprites as some newgrfs check it */
 
	SetDate(_date);
 

	
 
	/* Force dynamic engines off when loading older savegames */
 
	if (CheckSavegameVersion(95)) _settings_game.vehicle.dynamic_engines = 0;
 

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

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

	
 
	/* Connect front and rear engines of multiheaded trains and converts
 
	 * subtype to the new format */
 
	if (CheckSavegameVersionOldStyle(17, 1)) ConvertOldMultiheadToNew();
 

	
 
	/* Connect front and rear engines of multiheaded trains */
 
	ConnectMultiheadedTrains();
 

	
 
	/* reinit the landscape variables (landscape might have changed) */
 
	InitializeLandscapeVariables(true);
 

	
 
	/* Update all vehicles */
 
	AfterLoadVehicles(true);
 

	
 
	/* Update all waypoints */
 
	if (CheckSavegameVersion(12)) FixOldWaypoints();
 

	
 
	/* in version 2.2 of the savegame, we have new airports */
 
	if (CheckSavegameVersionOldStyle(2, 2)) UpdateOldAircraft();
 

	
 
	AfterLoadTown();
 

	
 
	/* make sure there is a town in the game */
 
	if (_game_mode == GM_NORMAL && !ClosestTownFromTile(0, UINT_MAX)) {
 
		SetSaveLoadError(STR_NO_TOWN_IN_SCENARIO);
 
		/* Restore the signals */
 
		signal(SIGSEGV, prev_segfault);
 
		signal(SIGABRT, prev_abort);
 
		return false;
 
	}
 

	
 
	/* The void tiles on the southern border used to belong to a wrong class (pre 4.3).
 
	 * This problem appears in savegame version 21 too, see r3455. But after loading the
 
	 * savegame and saving again, the buggy map array could be converted to new savegame
 
	 * version. It didn't show up before r12070. */
 
	if (CheckSavegameVersion(87)) UpdateVoidTiles();
 

	
 
	/* If Load Scenario / New (Scenario) Game is used,
 
	 *  a company does not exist yet. So create one here.
 
	 * 1 exeption: network-games. Those can have 0 companies
 
	 *   But this exeption is not true for non dedicated network_servers! */
 
	if (!IsValidCompanyID(COMPANY_FIRST) && (!_networking || (_networking && _network_server && !_network_dedicated)))
 
		DoStartupNewCompany(false);
 

	
 
	if (CheckSavegameVersion(72)) {
 
		/* Locks/shiplifts in very old savegames had OWNER_WATER as owner */
 
		for (TileIndex t = 0; t < MapSize(); t++) {
 
			switch (GetTileType(t)) {
 
				default: break;
 

	
 
				case MP_WATER:
 
					if (GetWaterTileType(t) == WATER_TILE_LOCK && GetTileOwner(t) == OWNER_WATER) SetTileOwner(t, OWNER_NONE);
 
					break;
 

	
 
				case MP_STATION: {
 
					if (HasBit(_m[t].m6, 3)) SetBit(_m[t].m6, 2);
 
					StationGfx gfx = GetStationGfx(t);
 
					StationType st;
 
					if (       IsInsideMM(gfx,   0,   8)) { // Railway station
 
						st = STATION_RAIL;
 
						SetStationGfx(t, gfx - 0);
 
					} else if (IsInsideMM(gfx,   8,  67)) { // Airport
 
						st = STATION_AIRPORT;
 
						SetStationGfx(t, gfx - 8);
 
					} else if (IsInsideMM(gfx,  67,  71)) { // Truck
 
						st = STATION_TRUCK;
 
						SetStationGfx(t, gfx - 67);
 
					} else if (IsInsideMM(gfx,  71,  75)) { // Bus
 
						st = STATION_BUS;
 
						SetStationGfx(t, gfx - 71);
 
					} else if (gfx == 75) {                    // Oil rig
 
						st = STATION_OILRIG;
 
						SetStationGfx(t, gfx - 75);
 
					} else if (IsInsideMM(gfx,  76,  82)) { // Dock
 
						st = STATION_DOCK;
 
						SetStationGfx(t, gfx - 76);
 
					} else if (gfx == 82) {                    // Buoy
 
						st = STATION_BUOY;
 
						SetStationGfx(t, gfx - 82);
 
					} else if (IsInsideMM(gfx,  83, 168)) { // Extended airport
 
						st = STATION_AIRPORT;
 
						SetStationGfx(t, gfx - 83 + 67 - 8);
 
					} else if (IsInsideMM(gfx, 168, 170)) { // Drive through truck
 
						st = STATION_TRUCK;
 
						SetStationGfx(t, gfx - 168 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET);
 
					} else if (IsInsideMM(gfx, 170, 172)) { // Drive through bus
 
						st = STATION_BUS;
 
						SetStationGfx(t, gfx - 170 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET);
 
					} else {
 
						/* Restore the signals */
 
						signal(SIGSEGV, prev_segfault);
 
						signal(SIGABRT, prev_abort);
 
						return false;
 
					}
 
					SB(_m[t].m6, 3, 3, st);
 
				} break;
 
			}
 
		}
 
	}
 

	
 
	for (TileIndex t = 0; t < map_size; t++) {
 
		switch (GetTileType(t)) {
 
			case MP_STATION: {
 
				Station *st = GetStationByTile(t);
 

	
 
				/* Set up station spread; buoys do not have one */
 
				if (!IsBuoy(t)) st->rect.BeforeAddTile(t, StationRect::ADD_FORCE);
 

	
 
				switch (GetStationType(t)) {
 
					case STATION_TRUCK:
 
					case STATION_BUS:
 
						if (CheckSavegameVersion(6)) {
 
							/* From this version on there can be multiple road stops of the
 
							 * same type per station. Convert the existing stops to the new
 
							 * internal data structure. */
 
							RoadStop *rs = new RoadStop(t);
 
							if (rs == NULL) error("Too many road stops in savegame");
 

	
 
							RoadStop **head =
 
								IsTruckStop(t) ? &st->truck_stops : &st->bus_stops;
 
							*head = rs;
 
						}
 
						break;
 

	
 
					case STATION_OILRIG: {
 
						/* Very old savegames sometimes have phantom oil rigs, i.e.
 
						 * an oil rig which got shut down, but not completly removed from
 
						 * the map
 
						 */
 
						TileIndex t1 = TILE_ADDXY(t, 0, 1);
 
						if (IsTileType(t1, MP_INDUSTRY) &&
 
								GetIndustryGfx(t1) == GFX_OILRIG_1) {
 
							/* The internal encoding of oil rigs was changed twice.
 
							 * It was 3 (till 2.2) and later 5 (till 5.1).
 
							 * Setting it unconditionally does not hurt.
 
							 */
 
							GetStationByTile(t)->airport_type = AT_OILRIG;
 
						} else {
 
							DeleteOilRig(t);
 
						}
 
						break;
 
					}
 

	
 
					default: break;
 
				}
 
				break;
 
			}
 

	
 
			default: break;
 
		}
 
	}
 

	
 
	/* In version 6.1 we put the town index in the map-array. To do this, we need
 
	 *  to use m2 (16bit big), so we need to clean m2, and that is where this is
 
	 *  all about ;) */
 
	if (CheckSavegameVersionOldStyle(6, 1)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			switch (GetTileType(t)) {
 
				case MP_HOUSE:
 
					_m[t].m4 = _m[t].m2;
 
					SetTownIndex(t, CalcClosestTownFromTile(t, UINT_MAX)->index);
 
					break;
 

	
 
				case MP_ROAD:
 
					_m[t].m4 |= (_m[t].m2 << 4);
 
					if ((GB(_m[t].m5, 4, 2) == ROAD_TILE_CROSSING ? (Owner)_m[t].m3 : GetTileOwner(t)) == OWNER_TOWN) {
 
						SetTownIndex(t, CalcClosestTownFromTile(t, UINT_MAX)->index);
 
					} else {
 
						SetTownIndex(t, 0);
 
					}
 
					break;
 

	
 
				default: break;
 
			}
 
		}
 
	}
 

	
 
	/* From version 9.0, we update the max passengers of a town (was sometimes negative
 
	 *  before that. */
 
	if (CheckSavegameVersion(9)) {
 
		Town *t;
 
		FOR_ALL_TOWNS(t) UpdateTownMaxPass(t);
 
	}
 

	
 
	/* From version 16.0, we included autorenew on engines, which are now saved, but
 
	 *  of course, we do need to initialize them for older savegames. */
 
	if (CheckSavegameVersion(16)) {
 
		FOR_ALL_COMPANIES(c) {
 
			c->engine_renew_list   = NULL;
 
			c->engine_renew        = false;
 
			c->engine_renew_months = -6;
 
			c->engine_renew_money  = 100000;
 
		}
 

	
 
		/* When loading a game, _local_company is not yet set to the correct value.
 
		 * However, in a dedicated server we are a spectator, so nothing needs to
 
		 * happen. In case we are not a dedicated server, the local company always
 
		 * becomes company 0, unless we are in the scenario editor where all the
 
		 * companies are 'invalid'.
 
		 */
 
		if (!_network_dedicated && IsValidCompanyID(COMPANY_FIRST)) {
 
			c = GetCompany(COMPANY_FIRST);
 
			c->engine_renew        = _settings_client.gui.autorenew;
 
			c->engine_renew_months = _settings_client.gui.autorenew_months;
 
			c->engine_renew_money  = _settings_client.gui.autorenew_money;
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(48)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			switch (GetTileType(t)) {
 
				case MP_RAILWAY:
 
					if (IsPlainRailTile(t)) {
 
						/* Swap ground type and signal type for plain rail tiles, so the
 
						 * ground type uses the same bits as for depots and waypoints. */
 
						uint tmp = GB(_m[t].m4, 0, 4);
 
						SB(_m[t].m4, 0, 4, GB(_m[t].m2, 0, 4));
 
						SB(_m[t].m2, 0, 4, tmp);
 
					} else if (HasBit(_m[t].m5, 2)) {
 
						/* Split waypoint and depot rail type and remove the subtype. */
 
						ClrBit(_m[t].m5, 2);
 
						ClrBit(_m[t].m5, 6);
 
					}
 
					break;
 

	
 
				case MP_ROAD:
 
					/* Swap m3 and m4, so the track type for rail crossings is the
 
					 * same as for normal rail. */
 
					Swap(_m[t].m3, _m[t].m4);
 
					break;
 

	
 
				default: break;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(61)) {
 
		/* Added the RoadType */
 
		bool old_bridge = CheckSavegameVersion(42);
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			switch(GetTileType(t)) {
 
				case MP_ROAD:
 
					SB(_m[t].m5, 6, 2, GB(_m[t].m5, 4, 2));
 
					switch (GetRoadTileType(t)) {
 
						default: NOT_REACHED();
 
						case ROAD_TILE_NORMAL:
 
							SB(_m[t].m4, 0, 4, GB(_m[t].m5, 0, 4));
 
							SB(_m[t].m4, 4, 4, 0);
 
							SB(_m[t].m6, 2, 4, 0);
 
							break;
 
						case ROAD_TILE_CROSSING:
 
							SB(_m[t].m4, 5, 2, GB(_m[t].m5, 2, 2));
 
							break;
 
						case ROAD_TILE_DEPOT:    break;
 
					}
 
					SetRoadTypes(t, ROADTYPES_ROAD);
 
					break;
 

	
 
				case MP_STATION:
 
					if (IsRoadStop(t)) SetRoadTypes(t, ROADTYPES_ROAD);
 
					break;
 

	
 
				case MP_TUNNELBRIDGE:
 
					/* Middle part of "old" bridges */
 
					if (old_bridge && IsBridge(t) && HasBit(_m[t].m5, 6)) break;
 
					if (((old_bridge && IsBridge(t)) ? (TransportType)GB(_m[t].m5, 1, 2) : GetTunnelBridgeTransportType(t)) == TRANSPORT_ROAD) {
 
						SetRoadTypes(t, ROADTYPES_ROAD);
 
					}
 
					break;
 

	
 
				default: break;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(42)) {
 
		Vehicle* v;
 

	
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (MayHaveBridgeAbove(t)) ClearBridgeMiddle(t);
 
			if (IsBridgeTile(t)) {
 
				if (HasBit(_m[t].m5, 6)) { // middle part
 
					Axis axis = (Axis)GB(_m[t].m5, 0, 1);
 

	
 
					if (HasBit(_m[t].m5, 5)) { // transport route under bridge?
 
						if (GB(_m[t].m5, 3, 2) == TRANSPORT_RAIL) {
 
							MakeRailNormal(
 
								t,
 
								GetTileOwner(t),
 
								axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X,
 
								GetRailType(t)
 
							);
 
						} else {
 
							TownID town = IsTileOwner(t, OWNER_TOWN) ? ClosestTownFromTile(t, UINT_MAX)->index : 0;
 

	
 
							MakeRoadNormal(
 
								t,
 
								axis == AXIS_X ? ROAD_Y : ROAD_X,
 
								ROADTYPES_ROAD,
 
								town,
 
								GetTileOwner(t), OWNER_NONE, OWNER_NONE
 
							);
 
						}
 
					} else {
 
						if (GB(_m[t].m5, 3, 2) == 0) {
 
							MakeClear(t, CLEAR_GRASS, 3);
 
						} else {
 
							if (GetTileSlope(t, NULL) != SLOPE_FLAT) {
 
								MakeShore(t);
 
							} else {
 
								if (GetTileOwner(t) == OWNER_WATER) {
 
									MakeWater(t);
 
								} else {
 
									MakeCanal(t, GetTileOwner(t), Random());
 
								}
 
							}
 
						}
 
					}
 
					SetBridgeMiddle(t, axis);
 
				} else { // ramp
 
					Axis axis = (Axis)GB(_m[t].m5, 0, 1);
 
					uint north_south = GB(_m[t].m5, 5, 1);
 
					DiagDirection dir = ReverseDiagDir(XYNSToDiagDir(axis, north_south));
 
					TransportType type = (TransportType)GB(_m[t].m5, 1, 2);
 

	
 
					_m[t].m5 = 1 << 7 | type << 2 | dir;
 
				}
 
			}
 
		}
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type != VEH_TRAIN && v->type != VEH_ROAD) continue;
 
			if (IsBridgeTile(v->tile)) {
 
				DiagDirection dir = GetTunnelBridgeDirection(v->tile);
 

	
 
				if (dir != DirToDiagDir(v->direction)) continue;
 
				switch (dir) {
 
					default: NOT_REACHED();
 
					case DIAGDIR_NE: if ((v->x_pos & 0xF) !=  0)            continue; break;
 
					case DIAGDIR_SE: if ((v->y_pos & 0xF) != TILE_SIZE - 1) continue; break;
 
					case DIAGDIR_SW: if ((v->x_pos & 0xF) != TILE_SIZE - 1) continue; break;
 
					case DIAGDIR_NW: if ((v->y_pos & 0xF) !=  0)            continue; break;
 
				}
 
			} else if (v->z_pos > GetSlopeZ(v->x_pos, v->y_pos)) {
 
				v->tile = GetNorthernBridgeEnd(v->tile);
 
			} else {
 
				continue;
 
			}
 
			if (v->type == VEH_TRAIN) {
 
				v->u.rail.track = TRACK_BIT_WORMHOLE;
 
			} else {
 
				v->u.road.state = RVSB_WORMHOLE;
 
			}
 
		}
 
	}
 

	
 
	/* Elrails got added in rev 24 */
 
	if (CheckSavegameVersion(24)) {
 
		Vehicle *v;
 
		RailType min_rail = RAILTYPE_ELECTRIC;
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_TRAIN) {
 
				RailType rt = RailVehInfo(v->engine_type)->railtype;
 

	
 
				v->u.rail.railtype = rt;
 
				if (rt == RAILTYPE_ELECTRIC) min_rail = RAILTYPE_RAIL;
 
			}
 
		}
 

	
 
		/* .. so we convert the entire map from normal to elrail (so maintain "fairness") */
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			switch (GetTileType(t)) {
 
				case MP_RAILWAY:
 
					SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
 
					break;
 

	
 
				case MP_ROAD:
 
					if (IsLevelCrossing(t)) {
 
						SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
 
					}
 
					break;
 

	
 
				case MP_STATION:
 
					if (IsRailwayStation(t)) {
 
						SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
 
					}
 
					break;
 

	
 
				case MP_TUNNELBRIDGE:
 
					if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) {
 
						SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
 
					}
 
					break;
 

	
 
				default:
 
					break;
 
			}
 
		}
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) TrainConsistChanged(v, true);
 
		}
 

	
 
	}
 

	
 
	/* In version 16.1 of the savegame a company can decide if trains, which get
 
	 * replaced, shall keep their old length. In all prior versions, just default
 
	 * to false */
 
	if (CheckSavegameVersionOldStyle(16, 1)) {
 
		FOR_ALL_COMPANIES(c) c->renew_keep_length = false;
 
	}
 

	
 
	/* In version 17, ground type is moved from m2 to m4 for depots and
 
	 * waypoints to make way for storing the index in m2. The custom graphics
 
	 * id which was stored in m4 is now saved as a grf/id reference in the
 
	 * waypoint struct. */
 
	if (CheckSavegameVersion(17)) {
 
		Waypoint *wp;
 

	
 
		FOR_ALL_WAYPOINTS(wp) {
 
			if (wp->deleted == 0) {
 
				const StationSpec *statspec = NULL;
 

	
 
				if (HasBit(_m[wp->xy].m3, 4))
 
					statspec = GetCustomStationSpec(STAT_CLASS_WAYP, _m[wp->xy].m4 + 1);
 

	
 
				if (statspec != NULL) {
 
					wp->stat_id = _m[wp->xy].m4 + 1;
 
					wp->grfid = statspec->grffile->grfid;
 
					wp->localidx = statspec->localidx;
 
				} else {
 
					/* No custom graphics set, so set to default. */
 
					wp->stat_id = 0;
 
					wp->grfid = 0;
 
					wp->localidx = 0;
 
				}
 

	
 
				/* Move ground type bits from m2 to m4. */
 
				_m[wp->xy].m4 = GB(_m[wp->xy].m2, 0, 4);
 
				/* Store waypoint index in the tile. */
 
				_m[wp->xy].m2 = wp->index;
 
			}
 
		}
 
	} else {
 
		/* As of version 17, we recalculate the custom graphic ID of waypoints
 
		 * from the GRF ID / station index. */
 
		AfterLoadWaypoints();
 
	}
 

	
 
	/* From version 15, we moved a semaphore bit from bit 2 to bit 3 in m4, making
 
	 *  room for PBS. Now in version 21 move it back :P. */
 
	if (CheckSavegameVersion(21) && !CheckSavegameVersion(15)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			switch (GetTileType(t)) {
 
				case MP_RAILWAY:
 
					if (HasSignals(t)) {
 
						/* convert PBS signals to combo-signals */
 
						if (HasBit(_m[t].m2, 2)) SetSignalType(t, TRACK_X, SIGTYPE_COMBO);
 

	
 
						/* move the signal variant back */
 
						SetSignalVariant(t, TRACK_X, HasBit(_m[t].m2, 3) ? SIG_SEMAPHORE : SIG_ELECTRIC);
 
						ClrBit(_m[t].m2, 3);
 
					}
 

	
 
					/* Clear PBS reservation on track */
 
					if (!IsRailDepotTile(t)) {
 
						SB(_m[t].m4, 4, 4, 0);
 
					} else {
 
						ClrBit(_m[t].m3, 6);
 
					}
 
					break;
 

	
 
				case MP_ROAD: /* Clear PBS reservation on crossing */
 
					if (IsLevelCrossing(t)) ClrBit(_m[t].m5, 0);
 
					break;
 

	
 
				case MP_STATION: /* Clear PBS reservation on station */
 
					ClrBit(_m[t].m3, 6);
 
					break;
 

	
 
				default: break;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(25)) {
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_ROAD) {
 
				v->vehstatus &= ~0x40;
 
				v->u.road.slot = NULL;
 
				v->u.road.slot_age = 0;
 
			}
 
		}
 
	} else {
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_ROAD && v->u.road.slot != NULL) v->u.road.slot->num_vehicles++;
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(26)) {
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			st->last_vehicle_type = VEH_INVALID;
 
		}
 
	}
 

	
 
	YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK);
 

	
 
	if (CheckSavegameVersion(34)) FOR_ALL_COMPANIES(c) ResetCompanyLivery(c);
 

	
 
	FOR_ALL_COMPANIES(c) {
 
		c->avail_railtypes = GetCompanyRailtypes(c->index);
 
		c->avail_roadtypes = GetCompanyRoadtypes(c->index);
 
	}
 

	
 
	if (!CheckSavegameVersion(27)) AfterLoadStations();
 

	
 
	/* Time starts at 0 instead of 1920.
 
	 * Account for this in older games by adding an offset */
 
	if (CheckSavegameVersion(31)) {
 
		Station *st;
 
		Waypoint *wp;
 
		Engine *e;
 
		Industry *i;
 
		Vehicle *v;
 

	
 
		_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		_cur_year += ORIGINAL_BASE_YEAR;
 

	
 
		FOR_ALL_STATIONS(st)  st->build_date      += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		FOR_ALL_WAYPOINTS(wp) wp->build_date      += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		FOR_ALL_ENGINES(e)    e->intro_date       += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		FOR_ALL_COMPANIES(c)  c->inaugurated_year += ORIGINAL_BASE_YEAR;
 
		FOR_ALL_INDUSTRIES(i) i->last_prod_year   += ORIGINAL_BASE_YEAR;
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			v->date_of_last_service += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			v->build_year += ORIGINAL_BASE_YEAR;
 
		}
 
	}
 

	
 
	/* From 32 on we save the industry who made the farmland.
 
	 *  To give this prettyness to old savegames, we remove all farmfields and
 
	 *  plant new ones. */
 
	if (CheckSavegameVersion(32)) {
 
		Industry *i;
 

	
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_FIELDS)) {
 
				/* remove fields */
 
				MakeClear(t, CLEAR_GRASS, 3);
 
			} else if (IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES)) {
 
				/* remove fences around fields */
 
				SetFenceSE(t, 0);
 
				SetFenceSW(t, 0);
 
			}
 
		}
 

	
 
		FOR_ALL_INDUSTRIES(i) {
 
			uint j;
 

	
 
			if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) {
 
				for (j = 0; j != 50; j++) PlantRandomFarmField(i);
 
			}
 
		}
 
	}
 

	
 
	/* Setting no refit flags to all orders in savegames from before refit in orders were added */
 
	if (CheckSavegameVersion(36)) {
 
		Order *order;
 
		Vehicle *v;
 

	
 
		FOR_ALL_ORDERS(order) {
 
			order->SetRefit(CT_NO_REFIT);
 
		}
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			v->current_order.SetRefit(CT_NO_REFIT);
 
		}
 
	}
 

	
 
	/* from version 38 we have optional elrails, since we cannot know the
 
	 * preference of a user, let elrails enabled; it can be disabled manually */
 
	if (CheckSavegameVersion(38)) _settings_game.vehicle.disable_elrails = false;
 
	/* do the same as when elrails were enabled/disabled manually just now */
 
	SettingsDisableElrail(_settings_game.vehicle.disable_elrails);
 
	InitializeRailGUI();
 

	
 
	/* From version 53, the map array was changed for house tiles to allow
 
	 * space for newhouses grf features. A new byte, m7, was also added. */
 
	if (CheckSavegameVersion(53)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_HOUSE)) {
 
				if (GB(_m[t].m3, 6, 2) != TOWN_HOUSE_COMPLETED) {
 
					/* Move the construction stage from m3[7..6] to m5[5..4].
 
					 * The construction counter does not have to move. */
 
					SB(_m[t].m5, 3, 2, GB(_m[t].m3, 6, 2));
 
					SB(_m[t].m3, 6, 2, 0);
 

	
 
					/* The "house is completed" bit is now in m6[2]. */
 
					SetHouseCompleted(t, false);
 
				} else {
 
					/* The "lift has destination" bit has been moved from
 
					 * m5[7] to m7[0]. */
 
					SB(_me[t].m7, 0, 1, HasBit(_m[t].m5, 7));
 
					ClrBit(_m[t].m5, 7);
 

	
 
					/* The "lift is moving" bit has been removed, as it does
 
					 * the same job as the "lift has destination" bit. */
 
					ClrBit(_m[t].m1, 7);
 

	
 
					/* The position of the lift goes from m1[7..0] to m6[7..2],
 
					 * making m1 totally free, now. The lift position does not
 
					 * have to be a full byte since the maximum value is 36. */
 
					SetLiftPosition(t, GB(_m[t].m1, 0, 6 ));
 

	
 
					_m[t].m1 = 0;
 
					_m[t].m3 = 0;
 
					SetHouseCompleted(t, true);
 
				}
 
			}
 
		}
 
	}
 

	
 
	/* Check and update house and town values */
 
	UpdateHousesAndTowns();
 

	
 
	if (CheckSavegameVersion(43)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_INDUSTRY)) {
 
				switch (GetIndustryGfx(t)) {
 
					case GFX_POWERPLANT_SPARKS:
 
						SetIndustryAnimationState(t, GB(_m[t].m1, 2, 5));
 
						break;
 

	
 
					case GFX_OILWELL_ANIMATED_1:
 
					case GFX_OILWELL_ANIMATED_2:
 
					case GFX_OILWELL_ANIMATED_3:
 
						SetIndustryAnimationState(t, GB(_m[t].m1, 0, 2));
 
						break;
 

	
 
					case GFX_COAL_MINE_TOWER_ANIMATED:
 
					case GFX_COPPER_MINE_TOWER_ANIMATED:
 
					case GFX_GOLD_MINE_TOWER_ANIMATED:
 
						 SetIndustryAnimationState(t, _m[t].m1);
 
						 break;
 

	
 
					default: /* No animation states to change */
 
						break;
 
				}
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(44)) {
 
		Vehicle *v;
 
		/* If we remove a station while cargo from it is still enroute, payment calculation will assume
 
		 * 0, 0 to be the source of the cargo, resulting in very high payments usually. v->source_xy
 
		 * stores the coordinates, preserving them even if the station is removed. However, if a game is loaded
 
		 * where this situation exists, the cargo-source information is lost. in this case, we set the source
 
		 * to the current tile of the vehicle to prevent excessive profits
 
		 */
 
		FOR_ALL_VEHICLES(v) {
 
			const CargoList::List *packets = v->cargo.Packets();
 
			for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) {
 
				CargoPacket *cp = *it;
 
				cp->source_xy = IsValidStationID(cp->source) ? GetStation(cp->source)->xy : v->tile;
 
				cp->loaded_at_xy = cp->source_xy;
 
			}
 
			v->cargo.InvalidateCache();
 
		}
 

	
 
		/* Store position of the station where the goods come from, so there
 
		 * are no very high payments when stations get removed. However, if the
 
		 * station where the goods came from is already removed, the source
 
		 * information is lost. In that case we set it to the position of this
 
		 * station */
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			for (CargoID c = 0; c < NUM_CARGO; c++) {
 
				GoodsEntry *ge = &st->goods[c];
 

	
 
				const CargoList::List *packets = ge->cargo.Packets();
 
				for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) {
 
					CargoPacket *cp = *it;
 
					cp->source_xy = IsValidStationID(cp->source) ? GetStation(cp->source)->xy : st->xy;
 
					cp->loaded_at_xy = cp->source_xy;
 
				}
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(45)) {
 
		Vehicle *v;
 
		/* Originally just the fact that some cargo had been paid for was
 
		 * stored to stop people cheating and cashing in several times. This
 
		 * wasn't enough though as it was cleared when the vehicle started
 
		 * loading again, even if it didn't actually load anything, so now the
 
		 * amount of cargo that has been paid for is stored. */
 
		FOR_ALL_VEHICLES(v) {
 
			const CargoList::List *packets = v->cargo.Packets();
 
			for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) {
 
				CargoPacket *cp = *it;
 
				cp->paid_for = HasBit(v->vehicle_flags, 2);
 
			}
 
			ClrBit(v->vehicle_flags, 2);
 
			v->cargo.InvalidateCache();
 
		}
 
	}
 

	
 
	/* Buoys do now store the owner of the previous water tile, which can never
 
	 * be OWNER_NONE. So replace OWNER_NONE with OWNER_WATER. */
 
	if (CheckSavegameVersion(46)) {
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			if (st->IsBuoy() && IsTileOwner(st->xy, OWNER_NONE) && TileHeight(st->xy) == 0) SetTileOwner(st->xy, OWNER_WATER);
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(50)) {
 
		Vehicle *v;
 
		/* Aircraft units changed from 8 mph to 1 km/h */
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_AIRCRAFT && v->subtype <= AIR_AIRCRAFT) {
 
				const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type);
 
				v->cur_speed *= 129;
 
				v->cur_speed /= 10;
 
				v->max_speed = avi->max_speed;
 
				v->acceleration = avi->acceleration;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(49)) FOR_ALL_COMPANIES(c) c->face = ConvertFromOldCompanyManagerFace(c->face);
 

	
 
	if (CheckSavegameVersion(52)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsStatueTile(t)) {
 
				_m[t].m2 = CalcClosestTownFromTile(t, UINT_MAX)->index;
 
			}
 
		}
 
	}
 

	
 
	/* A patch option containing the proportion of towns that grow twice as
 
	 * fast was added in version 54. From version 56 this is now saved in the
 
	 * town as cities can be built specifically in the scenario editor. */
 
	if (CheckSavegameVersion(56)) {
 
		Town *t;
 

	
 
		FOR_ALL_TOWNS(t) {
 
			if (_settings_game.economy.larger_towns != 0 && (t->index % _settings_game.economy.larger_towns) == 0) {
 
				t->larger_town = true;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(57)) {
 
		Vehicle *v;
 
		/* Added a FIFO queue of vehicles loading at stations */
 
		FOR_ALL_VEHICLES(v) {
 
			if ((v->type != VEH_TRAIN || IsFrontEngine(v)) &&  // for all locs
 
					!(v->vehstatus & (VS_STOPPED | VS_CRASHED)) && // not stopped or crashed
 
					v->current_order.IsType(OT_LOADING)) {         // loading
 
				GetStation(v->last_station_visited)->loading_vehicles.push_back(v);
 

	
 
				/* The loading finished flag is *only* set when actually completely
 
				 * finished. Because the vehicle is loading, it is not finished. */
 
				ClrBit(v->vehicle_flags, VF_LOADING_FINISHED);
 
			}
 
		}
 
	} else if (CheckSavegameVersion(59)) {
 
		/* For some reason non-loading vehicles could be in the station's loading vehicle list */
 

	
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			std::list<Vehicle *>::iterator iter;
 
			for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end();) {
 
				Vehicle *v = *iter;
 
				iter++;
 
				if (!v->current_order.IsType(OT_LOADING)) st->loading_vehicles.remove(v);
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(58)) {
 
		/* patch difficulty number_industries other than zero get bumped to +1
 
		 * since a new option (very low at position1) has been added */
 
		if (_settings_game.difficulty.number_industries > 0) {
 
			_settings_game.difficulty.number_industries++;
 
		}
 

	
 
		/* Same goes for number of towns, although no test is needed, just an increment */
 
		_settings_game.difficulty.number_towns++;
 
	}
 

	
 
	if (CheckSavegameVersion(64)) {
 
		/* copy the signal type/variant and move signal states bits */
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_RAILWAY) && HasSignals(t)) {
 
				SetSignalStates(t, GB(_m[t].m2, 4, 4));
 
				SetSignalVariant(t, INVALID_TRACK, GetSignalVariant(t, TRACK_X));
 
				SetSignalType(t, INVALID_TRACK, GetSignalType(t, TRACK_X));
 
				ClrBit(_m[t].m2, 7);
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(69)) {
 
		/* In some old savegames a bit was cleared when it should not be cleared */
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_ROAD && (v->u.road.state == 250 || v->u.road.state == 251)) {
 
				SetBit(v->u.road.state, RVS_IS_STOPPING);
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(70)) {
 
		/* Added variables to support newindustries */
 
		Industry *i;
 
		FOR_ALL_INDUSTRIES(i) i->founder = OWNER_NONE;
 
	}
 

	
 
	/* From version 82, old style canals (above sealevel (0), WATER owner) are no longer supported.
 
	    Replace the owner for those by OWNER_NONE. */
 
	if (CheckSavegameVersion(82)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_WATER) &&
 
					GetWaterTileType(t) == WATER_TILE_CLEAR &&
 
					GetTileOwner(t) == OWNER_WATER &&
 
					TileHeight(t) != 0) {
 
				SetTileOwner(t, OWNER_NONE);
 
			}
 
		}
 
	}
 

	
 
	/*
 
	 * Add the 'previous' owner to the ship depots so we can reset it with
 
	 * the correct values when it gets destroyed. This prevents that
 
	 * someone can remove canals owned by somebody else and it prevents
 
	 * making floods using the removal of ship depots.
 
	 */
 
	if (CheckSavegameVersion(83)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_WATER) && IsShipDepot(t)) {
 
				_m[t].m4 = (TileHeight(t) == 0) ? OWNER_WATER : OWNER_NONE;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(74)) {
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			for (CargoID c = 0; c < NUM_CARGO; c++) {
 
				st->goods[c].last_speed = 0;
 
				if (st->goods[c].cargo.Count() != 0) SetBit(st->goods[c].acceptance_pickup, GoodsEntry::PICKUP);
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(78)) {
 
		Industry *i;
 
		uint j;
 
		FOR_ALL_INDUSTRIES(i) {
 
			const IndustrySpec *indsp = GetIndustrySpec(i->type);
 
			for (j = 0; j < lengthof(i->produced_cargo); j++) {
 
				i->produced_cargo[j] = indsp->produced_cargo[j];
 
			}
 
			for (j = 0; j < lengthof(i->accepts_cargo); j++) {
 
				i->accepts_cargo[j] = indsp->accepts_cargo[j];
 
			}
 
		}
 
	}
 

	
 
	/* Before version 81, the density of grass was always stored as zero, and
 
	 * grassy trees were always drawn fully grassy. Furthermore, trees on rough
 
	 * land used to have zero density, now they have full density. Therefore,
 
	 * make all grassy/rough land trees have a density of 3. */
 
	if (CheckSavegameVersion(81)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (GetTileType(t) == MP_TREES) {
 
				TreeGround groundType = GetTreeGround(t);
 
				if (groundType != TREE_GROUND_SNOW_DESERT) SetTreeGroundDensity(t, groundType, 3);
 
			}
 
		}
 
	}
 

	
 

	
 
	if (CheckSavegameVersion(93)) {
 
		/* Rework of orders. */
 
		Order *order;
 
		FOR_ALL_ORDERS(order) order->ConvertFromOldSavegame();
 

	
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->orders.list != NULL && v->orders.list->GetFirstOrder() != NULL && !v->orders.list->GetFirstOrder()->IsValid()) {
 
				v->orders.list->FreeChain();
 
				v->orders.list = NULL;
 
			}
 

	
 
			v->current_order.ConvertFromOldSavegame();
 
			if (v->type == VEH_ROAD && v->IsPrimaryVehicle() && v->FirstShared() == v) {
 
				FOR_VEHICLE_ORDERS(v, order) order->SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS);
 
			}
 
		}
 
	} else if (CheckSavegameVersion(94)) {
 
		/* Unload and transfer are now mutual exclusive. */
 
		Order *order;
 
		FOR_ALL_ORDERS(order) {
 
			if ((order->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == (OUFB_UNLOAD | OUFB_TRANSFER)) {
 
				order->SetUnloadType(OUFB_TRANSFER);
 
				order->SetLoadType(OLFB_NO_LOAD);
 
			}
 
		}
 

	
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if ((v->current_order.GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == (OUFB_UNLOAD | OUFB_TRANSFER)) {
 
				v->current_order.SetUnloadType(OUFB_TRANSFER);
 
				v->current_order.SetLoadType(OLFB_NO_LOAD);
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(84)) {
 
		/* Update go to buoy orders because they are just waypoints */
 
		Order *order;
 
		FOR_ALL_ORDERS(order) {
 
			if (order->IsType(OT_GOTO_STATION) && GetStation(order->GetDestination())->IsBuoy()) {
 
				order->SetLoadType(OLF_LOAD_IF_POSSIBLE);
 
				order->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE);
 
			}
 
		}
 

	
 
		/* Set all share owners to INVALID_COMPANY for
 
		 * 1) all inactive companies
 
		 *     (when inactive companies were stored in the savegame - TTD, TTDP and some
 
		 *      *really* old revisions of OTTD; else it is already set in InitializeCompanies())
 
		 * 2) shares that are owned by inactive companies or self
 
		 *     (caused by cheating clients in earlier revisions) */
 
		FOR_ALL_COMPANIES(c) {
 
			for (uint i = 0; i < 4; i++) {
 
				CompanyID company = c->share_owners[i];
 
				if (company == INVALID_COMPANY) continue;
 
				if (!IsValidCompanyID(company) || company == c->index) c->share_owners[i] = INVALID_COMPANY;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(86)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			/* Move river flag and update canals to use water class */
 
			if (IsTileType(t, MP_WATER)) {
 
				if (GetWaterClass(t) != WATER_CLASS_RIVER) {
 
					if (IsWater(t)) {
 
						Owner o = GetTileOwner(t);
 
						if (o == OWNER_WATER) {
 
							MakeWater(t);
 
						} else {
 
							MakeCanal(t, o, Random());
 
						}
 
					} else if (IsShipDepot(t)) {
 
						Owner o = (Owner)_m[t].m4; // Original water owner
 
						SetWaterClass(t, o == OWNER_WATER ? WATER_CLASS_SEA : WATER_CLASS_CANAL);
 
					}
 
				}
 
			}
 
		}
 

	
 
		/* Update locks, depots, docks and buoys to have a water class based
 
		 * on its neighbouring tiles. Done after river and canal updates to
 
		 * ensure neighbours are correct. */
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (GetTileSlope(t, NULL) != SLOPE_FLAT) continue;
 

	
 
			if (IsTileType(t, MP_WATER) && IsLock(t)) SetWaterClassDependingOnSurroundings(t, false);
 
			if (IsTileType(t, MP_STATION) && (IsDock(t) || IsBuoy(t))) SetWaterClassDependingOnSurroundings(t, false);
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(87)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			/* skip oil rigs at borders! */
 
			if ((IsTileType(t, MP_WATER) || IsBuoyTile(t)) &&
 
					(TileX(t) == 0 || TileY(t) == 0 || TileX(t) == MapMaxX() - 1 || TileY(t) == MapMaxY() - 1)) {
 
				/* Some version 86 savegames have wrong water class at map borders (under buoy, or after removing buoy).
 
				 * This conversion has to be done before buoys with invalid owner are removed. */
 
				SetWaterClass(t, WATER_CLASS_SEA);
 
			}
 

	
 
			if (IsBuoyTile(t) || IsDriveThroughStopTile(t) || IsTileType(t, MP_WATER)) {
 
				Owner o = GetTileOwner(t);
 
				if (o < MAX_COMPANIES && !IsValidCompanyID(o)) {
 
					_current_company = o;
 
					ChangeTileOwner(t, o, INVALID_OWNER);
 
				}
 
				if (IsBuoyTile(t)) {
 
					/* reset buoy owner to OWNER_NONE in the station struct
 
					 * (even if it is owned by active company) */
 
					GetStationByTile(t)->owner = OWNER_NONE;
 
				}
 
			} else if (IsTileType(t, MP_ROAD)) {
 
				/* works for all RoadTileType */
 
				for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) {
 
					/* update even non-existing road types to update tile owner too */
 
					Owner o = GetRoadOwner(t, rt);
 
					if (o < MAX_COMPANIES && !IsValidCompanyID(o)) SetRoadOwner(t, rt, OWNER_NONE);
 
				}
 
				if (IsLevelCrossing(t)) {
 
					Owner o = GetTileOwner(t);
 
					if (!IsValidCompanyID(o)) {
 
						/* remove leftover rail piece from crossing (from very old savegames) */
 
						_current_company = o;
 
						DoCommand(t, 0, GetCrossingRailTrack(t), DC_EXEC | DC_BANKRUPT, CMD_REMOVE_SINGLE_RAIL);
 
					}
 
				}
 
			}
 
		}
 

	
 
		/* Convert old PF settings to new */
 
		if (_settings_game.pf.yapf.rail_use_yapf || CheckSavegameVersion(28)) {
 
			_settings_game.pf.pathfinder_for_trains = VPF_YAPF;
 
		} else {
 
			_settings_game.pf.pathfinder_for_trains = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_NTP);
 
		}
 

	
 
		if (_settings_game.pf.yapf.road_use_yapf || CheckSavegameVersion(28)) {
 
			_settings_game.pf.pathfinder_for_roadvehs = VPF_YAPF;
 
		} else {
 
			_settings_game.pf.pathfinder_for_roadvehs = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_OPF);
 
		}
 

	
 
		if (_settings_game.pf.yapf.ship_use_yapf) {
 
			_settings_game.pf.pathfinder_for_ships = VPF_YAPF;
 
		} else {
 
			_settings_game.pf.pathfinder_for_ships = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_OPF);
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(88)) {
 
		/* Profits are now with 8 bit fract */
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			v->profit_this_year <<= 8;
 
			v->profit_last_year <<= 8;
 
			v->running_ticks = 0;
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(91)) {
 
		/* Increase HouseAnimationFrame from 5 to 7 bits */
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsTileType(t, MP_HOUSE) && GetHouseType(t) >= NEW_HOUSE_OFFSET) {
 
				SetHouseAnimationFrame(t, GB(_m[t].m6, 3, 5));
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(62)) {
 
		/* Remove all trams from savegames without tram support.
 
		 * There would be trams without tram track under causing crashes sooner or later. */
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_ROAD && v->First() == v &&
 
					HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM)) {
 
				if (_switch_mode_errorstr == INVALID_STRING_ID || _switch_mode_errorstr == STR_NEWGRF_COMPATIBLE_LOAD_WARNING) {
 
					_switch_mode_errorstr = STR_LOADGAME_REMOVED_TRAMS;
 
				}
 
				delete v;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(99)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			/* Set newly introduced WaterClass of industry tiles */
 
			if (IsTileType(t, MP_STATION) && IsOilRig(t)) {
 
				SetWaterClassDependingOnSurroundings(t, true);
 
			}
 
			if (IsTileType(t, MP_INDUSTRY)) {
 
				if ((GetIndustrySpec(GetIndustryType(t))->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) {
 
					SetWaterClassDependingOnSurroundings(t, true);
 
				} else {
 
					SetWaterClass(t, WATER_CLASS_INVALID);
 
				}
 
			}
 

	
 
			/* Replace "house construction year" with "house age" */
 
			if (IsTileType(t, MP_HOUSE) && IsHouseCompleted(t)) {
 
				_m[t].m5 = Clamp(_cur_year - (_m[t].m5 + ORIGINAL_BASE_YEAR), 0, 0xFF);
 
			}
 
		}
 
	}
 

	
 
	/* Move the signal variant back up one bit for PBS. We don't convert the old PBS
 
	 * format here, as an old layout wouldn't work properly anyway. To be safe, we
 
	 * clear any possible PBS reservations as well. */
 
	if (CheckSavegameVersion(100)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			switch (GetTileType(t)) {
 
				case MP_RAILWAY:
 
					if (HasSignals(t)) {
 
						/* move the signal variant */
 
						SetSignalVariant(t, TRACK_UPPER, HasBit(_m[t].m2, 2) ? SIG_SEMAPHORE : SIG_ELECTRIC);
 
						SetSignalVariant(t, TRACK_LOWER, HasBit(_m[t].m2, 6) ? SIG_SEMAPHORE : SIG_ELECTRIC);
 
						ClrBit(_m[t].m2, 2);
 
						ClrBit(_m[t].m2, 6);
 
					}
 

	
 
					/* Clear PBS reservation on track */
 
					if (IsRailDepot(t) ||IsRailWaypoint(t)) {
 
						SetDepotWaypointReservation(t, false);
 
					} else {
 
						SetTrackReservation(t, TRACK_BIT_NONE);
 
					}
 
					break;
 

	
 
				case MP_ROAD: /* Clear PBS reservation on crossing */
 
					if (IsLevelCrossing(t)) SetCrossingReservation(t, false);
 
					break;
 

	
 
				case MP_STATION: /* Clear PBS reservation on station */
 
					if (IsRailwayStation(t)) SetRailwayStationReservation(t, false);
 
					break;
 

	
 
				case MP_TUNNELBRIDGE: /* Clear PBS reservation on tunnels/birdges */
 
					if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) SetTunnelBridgeReservation(t, false);
 
					break;
 

	
 
				default: break;
 
			}
 
		}
 
	}
 

	
 
	/* Reserve all tracks trains are currently on. */
 
	if (CheckSavegameVersion(101)) {
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_TRAIN) {
 
				if ((v->u.rail.track & TRACK_BIT_WORMHOLE) == TRACK_BIT_WORMHOLE) {
 
					TryReserveRailTrack(v->tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(v->tile)));
 
				} else if ((v->u.rail.track & TRACK_BIT_MASK) != TRACK_BIT_NONE) {
 
					TryReserveRailTrack(v->tile, TrackBitsToTrack(v->u.rail.track));
 
				}
 
			}
 
		}
 

	
 
		/* Give owners to waypoints, based on rail tracks it is sitting on.
 
		 * If none is available, specify OWNER_NONE */
 
		Waypoint *wp;
 
		FOR_ALL_WAYPOINTS(wp) {
 
			Owner owner = (IsRailWaypointTile(wp->xy) ? GetTileOwner(wp->xy) : OWNER_NONE);
 
			wp->owner = IsValidCompanyID(owner) ? owner : OWNER_NONE;
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(102)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			/* Now all crossings should be in correct state */
 
			if (IsLevelCrossingTile(t)) UpdateLevelCrossing(t, false);
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(103)) {
 
		/* Non-town-owned roads now store the closest town */
 
		UpdateNearestTownForRoadTiles(false);
 

	
 
		/* signs with invalid owner left from older savegames */
 
		Sign *si;
 
		FOR_ALL_SIGNS(si) {
 
			if (si->owner != OWNER_NONE && !IsValidCompanyID(si->owner)) si->owner = OWNER_NONE;
 
		}
 

	
 
		/* Station can get named based on an industry type, but the current ones
 
		 * are not, so mark them as if they are not named by an industry. */
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			st->indtype = IT_INVALID;
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(104)) {
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			/* Set engine_type of shadow and rotor */
 
			if (v->type == VEH_AIRCRAFT && !IsNormalAircraft(v)) {
 
				v->engine_type = v->First()->engine_type;
 
			}
 
		}
 

	
 
		/* More companies ... */
 
		Company *c;
 
		FOR_ALL_COMPANIES(c) {
 
			if (c->bankrupt_asked == 0xFF) c->bankrupt_asked = 0xFFFF;
 
		}
 

	
 
		Engine *e;
 
		FOR_ALL_ENGINES(e) {
 
			if (e->company_avail == 0xFF) e->company_avail = 0xFFFF;
 
		}
 

	
 
		Town *t;
 
		FOR_ALL_TOWNS(t) {
 
			if (t->have_ratings == 0xFF) t->have_ratings = 0xFFFF;
 
			for (uint i = 8; i != MAX_COMPANIES; i++) t->ratings[i] = RATING_INITIAL;
 
		}
 
	}
 

	
 
	GamelogPrintDebug(1);
 

	
 
	bool ret = InitializeWindowsAndCaches();
 
	/* Restore the signals */
 
	signal(SIGSEGV, prev_segfault);
 
	signal(SIGABRT, prev_abort);
 
	return ret;
 
}
 

	
 
/** Reload all NewGRF files during a running game. This is a cut-down
 
 * version of AfterLoadGame().
 
 * XXX - We need to reset the vehicle position hash because with a non-empty
 
 * hash AfterLoadVehicles() will loop infinitely. We need AfterLoadVehicles()
 
 * to recalculate vehicle data as some NewGRF vehicle sets could have been
 
 * removed or added and changed statistics */
 
void ReloadNewGRFData()
 
{
 
	/* reload grf data */
 
	GfxLoadSprites();
 
	LoadStringWidthTable();
 
	ResetEconomy();
 
	/* reload vehicles */
 
	ResetVehiclePosHash();
 
	AfterLoadVehicles(false);
 
	StartupEngines();
 
	SetCachedEngineCounts();
 
	/* update station and waypoint graphics */
 
	AfterLoadWaypoints();
 
	AfterLoadStations();
 
	/* Check and update house and town values */
 
	UpdateHousesAndTowns();
 
	/* Update livery selection windows */
 
	for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) InvalidateWindowData(WC_COMPANY_COLOR, i, _loaded_newgrf_features.has_2CC);
 
	/* redraw the whole screen */
 
	MarkWholeScreenDirty();
 
	CheckTrainsLengths();
 
}
src/saveload/ai_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file ai_sl.cpp Code handling saving and loading of old AI + new AI initialisation after game load */
 

	
 
#include "../stdafx.h"
 
#include "../ai/ai.h"
 
#include "../ai/default/default.h"
 

	
 
#include "saveload.h"
 

	
 
static const SaveLoad _company_ai_desc[] = {
 
	    SLE_VAR(CompanyAI, state,             SLE_UINT8),
 
	    SLE_VAR(CompanyAI, tick,              SLE_UINT8),
 
	SLE_CONDVAR(CompanyAI, state_counter,     SLE_FILE_U16 | SLE_VAR_U32,  0, 12),
 
	SLE_CONDVAR(CompanyAI, state_counter,     SLE_UINT32,                 13, SL_MAX_VERSION),
 
	    SLE_VAR(CompanyAI, timeout_counter,   SLE_UINT16),
 

	
 
	    SLE_VAR(CompanyAI, state_mode,        SLE_UINT8),
 
	    SLE_VAR(CompanyAI, banned_tile_count, SLE_UINT8),
 
	    SLE_VAR(CompanyAI, railtype_to_use,   SLE_UINT8),
 

	
 
	    SLE_VAR(CompanyAI, cargo_type,        SLE_UINT8),
 
	    SLE_VAR(CompanyAI, num_wagons,        SLE_UINT8),
 
	    SLE_VAR(CompanyAI, build_kind,        SLE_UINT8),
 
	    SLE_VAR(CompanyAI, num_build_rec,     SLE_UINT8),
 
	    SLE_VAR(CompanyAI, num_loco_to_build, SLE_UINT8),
 
	    SLE_VAR(CompanyAI, num_want_fullload, SLE_UINT8),
 

	
 
	    SLE_VAR(CompanyAI, route_type_mask,   SLE_UINT8),
 

	
 
	SLE_CONDVAR(CompanyAI, start_tile_a,      SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
 
	SLE_CONDVAR(CompanyAI, start_tile_a,      SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(CompanyAI, cur_tile_a,        SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
 
	SLE_CONDVAR(CompanyAI, cur_tile_a,        SLE_UINT32,                  6, SL_MAX_VERSION),
 
	    SLE_VAR(CompanyAI, start_dir_a,       SLE_UINT8),
 
	    SLE_VAR(CompanyAI, cur_dir_a,         SLE_UINT8),
 

	
 
	SLE_CONDVAR(CompanyAI, start_tile_b,      SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
 
	SLE_CONDVAR(CompanyAI, start_tile_b,      SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(CompanyAI, cur_tile_b,        SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
 
	SLE_CONDVAR(CompanyAI, cur_tile_b,        SLE_UINT32,                  6, SL_MAX_VERSION),
 
	    SLE_VAR(CompanyAI, start_dir_b,       SLE_UINT8),
 
	    SLE_VAR(CompanyAI, cur_dir_b,         SLE_UINT8),
 

	
 
	    SLE_REF(CompanyAI, cur_veh,           REF_VEHICLE),
 

	
 
	    SLE_ARR(CompanyAI, wagon_list,        SLE_UINT16, 9),
 
	    SLE_ARR(CompanyAI, order_list_blocks, SLE_UINT8, 20),
 
	    SLE_ARR(CompanyAI, banned_tiles,      SLE_UINT16, 16),
 

	
 
	SLE_CONDNULL(64, 2, SL_MAX_VERSION),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _company_ai_build_rec_desc[] = {
 
	SLE_CONDVAR(AiBuildRec, spec_tile,         SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
 
	SLE_CONDVAR(AiBuildRec, spec_tile,         SLE_UINT32,                 6, SL_MAX_VERSION),
 
	SLE_CONDVAR(AiBuildRec, use_tile,          SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
 
	SLE_CONDVAR(AiBuildRec, use_tile,          SLE_UINT32,                 6, SL_MAX_VERSION),
 
	    SLE_VAR(AiBuildRec, rand_rng,          SLE_UINT8),
 
	    SLE_VAR(AiBuildRec, cur_building_rule, SLE_UINT8),
 
	    SLE_VAR(AiBuildRec, unk6,              SLE_UINT8),
 
	    SLE_VAR(AiBuildRec, unk7,              SLE_UINT8),
 
	    SLE_VAR(AiBuildRec, buildcmd_a,        SLE_UINT8),
 
	    SLE_VAR(AiBuildRec, buildcmd_b,        SLE_UINT8),
 
	    SLE_VAR(AiBuildRec, direction,         SLE_UINT8),
 
	    SLE_VAR(AiBuildRec, cargo,             SLE_UINT8),
 
	SLE_END()
 
};
 

	
 

	
 
void SaveLoad_AI(CompanyID company)
 
{
 
	CompanyAI *cai = &_companies_ai[company];
 
	SlObject(cai, _company_ai_desc);
 
	for (int i = 0; i != cai->num_build_rec; i++) {
 
		SlObject(&cai->src + i, _company_ai_build_rec_desc);
 
	}
 
}
src/saveload/animated_tile_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file animated_tile_sl.cpp Code handling saving and loading of animated tiles */
 

	
 
#include "../stdafx.h"
 
#include "../tile_type.h"
 
#include "../core/alloc_func.hpp"
 

	
 
#include "saveload.h"
 

	
 
extern TileIndex *_animated_tile_list;
 
extern uint _animated_tile_count;
 
extern uint _animated_tile_allocated;
 

	
 
/**
 
 * Save the ANIT chunk.
 
 */
 
static void Save_ANIT()
 
{
 
	SlSetLength(_animated_tile_count * sizeof(*_animated_tile_list));
 
	SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32);
 
}
 

	
 
/**
 
 * Load the ANIT chunk; the chunk containing the animated tiles.
 
 */
 
static void Load_ANIT()
 
{
 
	/* Before version 80 we did NOT have a variable length animated tile table */
 
	if (CheckSavegameVersion(80)) {
 
		/* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */
 
		SlArray(_animated_tile_list, 256, CheckSavegameVersion(6) ? (SLE_FILE_U16 | SLE_VAR_U32) : SLE_UINT32);
 

	
 
		for (_animated_tile_count = 0; _animated_tile_count < 256; _animated_tile_count++) {
 
			if (_animated_tile_list[_animated_tile_count] == 0) break;
 
		}
 
		return;
 
	}
 

	
 
	_animated_tile_count = (uint)SlGetFieldLength() / sizeof(*_animated_tile_list);
 

	
 
	/* Determine a nice rounded size for the amount of allocated tiles */
 
	_animated_tile_allocated = 256;
 
	while (_animated_tile_allocated < _animated_tile_count) _animated_tile_allocated *= 2;
 

	
 
	_animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, _animated_tile_allocated);
 
	SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32);
 
}
 

	
 
/**
 
 * "Definition" imported by the saveload code to be able to load and save
 
 * the animated tile table.
 
 */
 
extern const ChunkHandler _animated_tile_chunk_handlers[] = {
 
	{ 'ANIT', Save_ANIT, Load_ANIT, CH_RIFF | CH_LAST},
 
};
src/saveload/autoreplace_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file autoreplace_sl.cpp Code handling saving and loading of autoreplace rules */
 

	
 
#include "../stdafx.h"
 
#include "../autoreplace_type.h"
 
#include "../engine_type.h"
 
#include "../group_type.h"
 
#include "../autoreplace_base.h"
 

	
 
#include "saveload.h"
 

	
 
static const SaveLoad _engine_renew_desc[] = {
 
	    SLE_VAR(EngineRenew, from,     SLE_UINT16),
 
	    SLE_VAR(EngineRenew, to,       SLE_UINT16),
 

	
 
	    SLE_REF(EngineRenew, next,     REF_ENGINE_RENEWS),
 
	SLE_CONDVAR(EngineRenew, group_id, SLE_UINT16, 60, SL_MAX_VERSION),
 
	SLE_END()
 
};
 

	
 
static void Save_ERNW()
 
{
 
	EngineRenew *er;
 

	
 
	FOR_ALL_ENGINE_RENEWS(er) {
 
		SlSetArrayIndex(er->index);
 
		SlObject(er, _engine_renew_desc);
 
	}
 
}
 

	
 
static void Load_ERNW()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		EngineRenew *er = new (index) EngineRenew();
 
		SlObject(er, _engine_renew_desc);
 

	
 
		/* Advanced vehicle lists, ungrouped vehicles got added */
 
		if (CheckSavegameVersion(60)) {
 
			er->group_id = ALL_GROUP;
 
		} else if (CheckSavegameVersion(71)) {
 
			if (er->group_id == DEFAULT_GROUP) er->group_id = ALL_GROUP;
 
		}
 
	}
 
}
 

	
 
extern const ChunkHandler _autoreplace_chunk_handlers[] = {
 
	{ 'ERNW', Save_ERNW,     Load_ERNW,     CH_ARRAY | CH_LAST},
 
};
src/saveload/cargopacket_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file cargopacket_sl.cpp Code handling saving and loading of cargo packets */
 

	
 
#include "../stdafx.h"
 
#include "../openttd.h"
 
#include "../cargopacket.h"
 

	
 
#include "saveload.h"
 

	
 
static const SaveLoad _cargopacket_desc[] = {
 
	SLE_VAR(CargoPacket, source,          SLE_UINT16),
 
	SLE_VAR(CargoPacket, source_xy,       SLE_UINT32),
 
	SLE_VAR(CargoPacket, loaded_at_xy,    SLE_UINT32),
 
	SLE_VAR(CargoPacket, count,           SLE_UINT16),
 
	SLE_VAR(CargoPacket, days_in_transit, SLE_UINT8),
 
	SLE_VAR(CargoPacket, feeder_share,    SLE_INT64),
 
	SLE_VAR(CargoPacket, paid_for,        SLE_BOOL),
 

	
 
	SLE_END()
 
};
 

	
 
static void Save_CAPA()
 
{
 
	CargoPacket *cp;
 

	
 
	FOR_ALL_CARGOPACKETS(cp) {
 
		SlSetArrayIndex(cp->index);
 
		SlObject(cp, _cargopacket_desc);
 
	}
 
}
 

	
 
static void Load_CAPA()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		CargoPacket *cp = new (index) CargoPacket();
 
		SlObject(cp, _cargopacket_desc);
 
	}
 
}
 

	
 
extern const ChunkHandler _cargopacket_chunk_handlers[] = {
 
	{ 'CAPA', Save_CAPA, Load_CAPA, CH_ARRAY | CH_LAST},
 
};
src/saveload/cheat_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file cheat_sl.cpp Code handling saving and loading of cheats */
 

	
 
#include "../stdafx.h"
 
#include "../cheat_type.h"
 

	
 
#include "saveload.h"
 

	
 
static void Save_CHTS()
 
{
 
	/* Cannot use lengthof because _cheats is of type Cheats, not Cheat */
 
	byte count = sizeof(_cheats) / sizeof(Cheat);
 
	Cheat *cht = (Cheat*) &_cheats;
 
	Cheat *cht_last = &cht[count];
 

	
 
	SlSetLength(count * 2);
 
	for (; cht != cht_last; cht++) {
 
		SlWriteByte(cht->been_used);
 
		SlWriteByte(cht->value);
 
	}
 
}
 

	
 
static void Load_CHTS()
 
{
 
	Cheat *cht = (Cheat*)&_cheats;
 
	size_t count = SlGetFieldLength() / 2;
 

	
 
	for (uint i = 0; i < count; i++) {
 
		cht[i].been_used = (SlReadByte() != 0);
 
		cht[i].value     = (SlReadByte() != 0);
 
	}
 
}
 

	
 
extern const ChunkHandler _cheat_chunk_handlers[] = {
 
	{ 'CHTS', Save_CHTS,     Load_CHTS,     CH_RIFF | CH_LAST}
 
};
src/saveload/company_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file company_sl.cpp Code handling saving and loading of company data */
 

	
 
#include "../stdafx.h"
 
#include "../company_base.h"
 
#include "../company_func.h"
 
#include "../network/network.h"
 
#include "../ai/ai.h"
 
#include "../ai/trolly/trolly.h"
 
#include "../company_manager_face.h"
 

	
 
#include "saveload.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
 
 * - 13 to 15: lips (also moustache for males)
 
 * - 16 to 19: hair
 
 * - 20 to 22: eye color
 
 * - 20 to 27: tie, ear rings etc.
 
 * - 28 to 30: glasses
 
 * - 19, 26 and 27: race (bit 27 set and bit 19 equal to bit 26 = black, otherwise white)
 
 * - 31: gender (0 = male, 1 = female)
 
 *
 
 * @param face the face in the old format
 
 * @return the face in the new format
 
 */
 
CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32 face)
 
{
 
	CompanyManagerFace cmf = 0;
 
	GenderEthnicity ge = GE_WM;
 

	
 
	if (HasBit(face, 31)) SetBit(ge, GENDER_FEMALE);
 
	if (HasBit(face, 27) && (HasBit(face, 26) == HasBit(face, 19))) SetBit(ge, ETHNICITY_BLACK);
 

	
 
	SetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN,    ge, ge);
 
	SetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge, GB(face, 28, 3) <= 1);
 
	SetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR,  ge, HasBit(ge, ETHNICITY_BLACK) ? 0 : ClampU(GB(face, 20, 3), 5, 7) - 5);
 
	SetCompanyManagerFaceBits(cmf, CMFV_CHIN,        ge, ScaleCompanyManagerFaceValue(CMFV_CHIN,     ge, GB(face,  4, 2)));
 
	SetCompanyManagerFaceBits(cmf, CMFV_EYEBROWS,    ge, ScaleCompanyManagerFaceValue(CMFV_EYEBROWS, ge, GB(face,  6, 4)));
 
	SetCompanyManagerFaceBits(cmf, CMFV_HAIR,        ge, ScaleCompanyManagerFaceValue(CMFV_HAIR,     ge, GB(face, 16, 4)));
 
	SetCompanyManagerFaceBits(cmf, CMFV_JACKET,      ge, ScaleCompanyManagerFaceValue(CMFV_JACKET,   ge, GB(face, 20, 2)));
 
	SetCompanyManagerFaceBits(cmf, CMFV_COLLAR,      ge, ScaleCompanyManagerFaceValue(CMFV_COLLAR,   ge, GB(face, 22, 2)));
 
	SetCompanyManagerFaceBits(cmf, CMFV_GLASSES,     ge, GB(face, 28, 1));
 

	
 
	uint lips = GB(face, 10, 4);
 
	if (!HasBit(ge, GENDER_FEMALE) && lips < 4) {
 
		SetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE, ge, true);
 
		SetCompanyManagerFaceBits(cmf, CMFV_MOUSTACHE,     ge, max(lips, 1U) - 1);
 
	} else {
 
		if (!HasBit(ge, GENDER_FEMALE)) {
 
			lips = lips * 15 / 16;
 
			lips -= 3;
 
			if (HasBit(ge, ETHNICITY_BLACK) && lips > 8) lips = 0;
 
		} else {
 
			lips = ScaleCompanyManagerFaceValue(CMFV_LIPS, ge, lips);
 
		}
 
		SetCompanyManagerFaceBits(cmf, CMFV_LIPS, ge, lips);
 

	
 
		uint nose = GB(face, 13, 3);
 
		if (ge == GE_WF) {
 
			nose = (nose * 3 >> 3) * 3 >> 2; // There is 'hole' in the nose sprites for females
 
		} else {
 
			nose = ScaleCompanyManagerFaceValue(CMFV_NOSE, ge, nose);
 
		}
 
		SetCompanyManagerFaceBits(cmf, CMFV_NOSE, ge, nose);
 
	}
 

	
 
	uint tie_earring = GB(face, 24, 4);
 
	if (!HasBit(ge, GENDER_FEMALE) || tie_earring < 3) { // Not all females have an earring
 
		if (HasBit(ge, GENDER_FEMALE)) SetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge, true);
 
		SetCompanyManagerFaceBits(cmf, CMFV_TIE_EARRING, ge, HasBit(ge, GENDER_FEMALE) ? tie_earring : ScaleCompanyManagerFaceValue(CMFV_TIE_EARRING, ge, tie_earring / 2));
 
	}
 

	
 
	return cmf;
 
}
 

	
 

	
 

	
 
/* Save/load of companies */
 
static const SaveLoad _company_desc[] = {
 
	    SLE_VAR(Company, name_2,          SLE_UINT32),
 
	    SLE_VAR(Company, name_1,          SLE_STRINGID),
 
	SLE_CONDSTR(Company, name,            SLE_STR, 0,                       84, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(Company, president_name_1, SLE_UINT16),
 
	    SLE_VAR(Company, president_name_2, SLE_UINT32),
 
	SLE_CONDSTR(Company, president_name,  SLE_STR, 0,                       84, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(Company, face,            SLE_UINT32),
 

	
 
	/* money was changed to a 64 bit field in savegame version 1. */
 
	SLE_CONDVAR(Company, money,                 SLE_VAR_I64 | SLE_FILE_I32,  0, 0),
 
	SLE_CONDVAR(Company, money,                 SLE_INT64,                   1, SL_MAX_VERSION),
 

	
 
	SLE_CONDVAR(Company, current_loan,          SLE_VAR_I64 | SLE_FILE_I32,  0, 64),
 
	SLE_CONDVAR(Company, current_loan,          SLE_INT64,                  65, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(Company, colour,                SLE_UINT8),
 
	    SLE_VAR(Company, money_fraction,        SLE_UINT8),
 
	SLE_CONDVAR(Company, avail_railtypes,       SLE_UINT8,                   0, 57),
 
	    SLE_VAR(Company, block_preview,         SLE_UINT8),
 

	
 
	SLE_CONDVAR(Company, cargo_types,           SLE_FILE_U16 | SLE_VAR_U32,  0, 93),
 
	SLE_CONDVAR(Company, cargo_types,           SLE_UINT32,                 94, SL_MAX_VERSION),
 
	SLE_CONDVAR(Company, location_of_HQ,        SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
 
	SLE_CONDVAR(Company, location_of_HQ,        SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Company, last_build_coordinate, SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
 
	SLE_CONDVAR(Company, last_build_coordinate, SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Company, inaugurated_year,      SLE_FILE_U8  | SLE_VAR_I32,  0, 30),
 
	SLE_CONDVAR(Company, inaugurated_year,      SLE_INT32,                  31, SL_MAX_VERSION),
 

	
 
	    SLE_ARR(Company, share_owners,          SLE_UINT8, 4),
 

	
 
	    SLE_VAR(Company, num_valid_stat_ent,    SLE_UINT8),
 

	
 
	    SLE_VAR(Company, quarters_of_bankrupcy, SLE_UINT8),
 
	SLE_CONDVAR(Company, bankrupt_asked,        SLE_FILE_U8  | SLE_VAR_U16,  0, 103),
 
	SLE_CONDVAR(Company, bankrupt_asked,        SLE_UINT16,                104, SL_MAX_VERSION),
 
	    SLE_VAR(Company, bankrupt_timeout,      SLE_INT16),
 
	SLE_CONDVAR(Company, bankrupt_value,        SLE_VAR_I64 | SLE_FILE_I32,  0, 64),
 
	SLE_CONDVAR(Company, bankrupt_value,        SLE_INT64,                  65, SL_MAX_VERSION),
 

	
 
	/* yearly expenses was changed to 64-bit in savegame version 2. */
 
	SLE_CONDARR(Company, yearly_expenses,       SLE_FILE_I32 | SLE_VAR_I64, 3 * 13, 0, 1),
 
	SLE_CONDARR(Company, yearly_expenses,       SLE_INT64, 3 * 13,                  2, SL_MAX_VERSION),
 

	
 
	SLE_CONDVAR(Company, is_ai,                 SLE_BOOL, 2, SL_MAX_VERSION),
 
	SLE_CONDNULL(1, 4, 99),
 

	
 
	/* Engine renewal settings */
 
	SLE_CONDNULL(512, 16, 18),
 
	SLE_CONDREF(Company, engine_renew_list,     REF_ENGINE_RENEWS,          19, SL_MAX_VERSION),
 
	SLE_CONDVAR(Company, engine_renew,          SLE_BOOL,                   16, SL_MAX_VERSION),
 
	SLE_CONDVAR(Company, engine_renew_months,   SLE_INT16,                  16, SL_MAX_VERSION),
 
	SLE_CONDVAR(Company, engine_renew_money,    SLE_UINT32,                 16, SL_MAX_VERSION),
 
	SLE_CONDVAR(Company, renew_keep_length,     SLE_BOOL,                    2, SL_MAX_VERSION), // added with 16.1, but was blank since 2
 

	
 
	/* reserve extra space in savegame here. (currently 63 bytes) */
 
	SLE_CONDNULL(63, 2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _company_economy_desc[] = {
 
	/* these were changed to 64-bit in savegame format 2 */
 
	SLE_CONDVAR(CompanyEconomyEntry, income,              SLE_FILE_I32 | SLE_VAR_I64, 0, 1),
 
	SLE_CONDVAR(CompanyEconomyEntry, income,              SLE_INT64,                  2, SL_MAX_VERSION),
 
	SLE_CONDVAR(CompanyEconomyEntry, expenses,            SLE_FILE_I32 | SLE_VAR_I64, 0, 1),
 
	SLE_CONDVAR(CompanyEconomyEntry, expenses,            SLE_INT64,                  2, SL_MAX_VERSION),
 
	SLE_CONDVAR(CompanyEconomyEntry, company_value,       SLE_FILE_I32 | SLE_VAR_I64, 0, 1),
 
	SLE_CONDVAR(CompanyEconomyEntry, company_value,       SLE_INT64,                  2, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(CompanyEconomyEntry, delivered_cargo,     SLE_INT32),
 
	    SLE_VAR(CompanyEconomyEntry, performance_history, SLE_INT32),
 

	
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _company_livery_desc[] = {
 
	SLE_CONDVAR(Livery, in_use,  SLE_BOOL,  34, SL_MAX_VERSION),
 
	SLE_CONDVAR(Livery, colour1, SLE_UINT8, 34, SL_MAX_VERSION),
 
	SLE_CONDVAR(Livery, colour2, SLE_UINT8, 34, SL_MAX_VERSION),
 
	SLE_END()
 
};
 

	
 
static void SaveLoad_PLYR(Company *c)
 
{
 
	int i;
 

	
 
	SlObject(c, _company_desc);
 

	
 
	/* Write AI? */
 
	if (!IsHumanCompany(c->index)) {
 
		extern void SaveLoad_AI(CompanyID company);
 
		SaveLoad_AI(c->index);
 
	}
 

	
 
	/* Write economy */
 
	SlObject(&c->cur_economy, _company_economy_desc);
 

	
 
	/* Write old economy entries. */
 
	for (i = 0; i < c->num_valid_stat_ent; i++) {
 
		SlObject(&c->old_economy[i], _company_economy_desc);
 
	}
 

	
 
	/* Write each livery entry. */
 
	int num_liveries = CheckSavegameVersion(63) ? LS_END - 4 : (CheckSavegameVersion(85) ? LS_END - 2: LS_END);
 
	for (i = 0; i < num_liveries; i++) {
 
		SlObject(&c->livery[i], _company_livery_desc);
 
	}
 

	
 
	if (num_liveries < LS_END) {
 
		/* We want to insert some liveries somewhere in between. This means some have to be moved. */
 
		memmove(&c->livery[LS_FREIGHT_WAGON], &c->livery[LS_PASSENGER_WAGON_MONORAIL], (LS_END - LS_FREIGHT_WAGON) * sizeof(c->livery[0]));
 
		c->livery[LS_PASSENGER_WAGON_MONORAIL] = c->livery[LS_MONORAIL];
 
		c->livery[LS_PASSENGER_WAGON_MAGLEV]   = c->livery[LS_MAGLEV];
 
	}
 

	
 
	if (num_liveries == LS_END - 4) {
 
		/* Copy bus/truck liveries over to trams */
 
		c->livery[LS_PASSENGER_TRAM] = c->livery[LS_BUS];
 
		c->livery[LS_FREIGHT_TRAM]   = c->livery[LS_TRUCK];
 
	}
 
}
 

	
 
static void Save_PLYR()
 
{
 
	Company *c;
 
	FOR_ALL_COMPANIES(c) {
 
		SlSetArrayIndex(c->index);
 
		SlAutolength((AutolengthProc*)SaveLoad_PLYR, c);
 
	}
 
}
 

	
 
static void Load_PLYR()
 
{
 
	int index;
 
	while ((index = SlIterateArray()) != -1) {
 
		Company *c = new (index) Company();
 
		SaveLoad_PLYR(c);
 
		_company_colours[index] = c->colour;
 

	
 
		/* This is needed so an AI is attached to a loaded AI */
 
		if (c->is_ai && (!_networking || _network_server) && _ai.enabled) {
 
			/* Clear the memory of the new AI, otherwise we might be doing wrong things. */
 
			memset(&_companies_ainew[index], 0, sizeof(CompanyAiNew));
 
			AI_StartNewAI(c->index);
 
		}
 
	}
 
}
 

	
 
extern const ChunkHandler _company_chunk_handlers[] = {
 
	{ 'PLYR', Save_PLYR, Load_PLYR, CH_ARRAY | CH_LAST},
 
};
src/saveload/depot_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file depot_sl.cpp Code handling saving and loading of depots */
 

	
 
#include "../stdafx.h"
 
#include "../depot_base.h"
 

	
 
#include "saveload.h"
 

	
 
static const SaveLoad _depot_desc[] = {
 
	SLE_CONDVAR(Depot, xy,         SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
 
	SLE_CONDVAR(Depot, xy,         SLE_UINT32,                 6, SL_MAX_VERSION),
 
	    SLE_VAR(Depot, town_index, SLE_UINT16),
 
	SLE_END()
 
};
 

	
 
static void Save_DEPT()
 
{
 
	Depot *depot;
 

	
 
	FOR_ALL_DEPOTS(depot) {
 
		SlSetArrayIndex(depot->index);
 
		SlObject(depot, _depot_desc);
 
	}
 
}
 

	
 
static void Load_DEPT()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		Depot *depot = new (index) Depot();
 
		SlObject(depot, _depot_desc);
 
	}
 
}
 

	
 
extern const ChunkHandler _depot_chunk_handlers[] = {
 
	{ 'DEPT', Save_DEPT, Load_DEPT, CH_ARRAY | CH_LAST},
 
};
src/saveload/economy_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file economy_sl.cpp Code handling saving and loading of economy data */
 

	
 
#include "../stdafx.h"
 
#include "../economy_func.h"
 

	
 
#include "saveload.h"
 

	
 
/** Prices */
 
static void SaveLoad_PRIC()
 
{
 
	int vt = CheckSavegameVersion(65) ? (SLE_FILE_I32 | SLE_VAR_I64) : SLE_INT64;
 
	SlArray(&_price,      NUM_PRICES, vt);
 
	SlArray(&_price_frac, NUM_PRICES, SLE_UINT16);
 
}
 

	
 
/** Cargo payment rates */
 
static void SaveLoad_CAPR()
 
{
 
	uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO;
 
	int vt = CheckSavegameVersion(65) ? (SLE_FILE_I32 | SLE_VAR_I64) : SLE_INT64;
 
	SlArray(&_cargo_payment_rates,      num_cargo, vt);
 
	SlArray(&_cargo_payment_rates_frac, num_cargo, SLE_UINT16);
 
}
 

	
 
static const SaveLoad _economy_desc[] = {
 
	SLE_CONDVAR(Economy, max_loan,                      SLE_FILE_I32 | SLE_VAR_I64,  0, 64),
 
	SLE_CONDVAR(Economy, max_loan,                      SLE_INT64,                  65, SL_MAX_VERSION),
 
	SLE_CONDVAR(Economy, max_loan_unround,              SLE_FILE_I32 | SLE_VAR_I64,  0, 64),
 
	SLE_CONDVAR(Economy, max_loan_unround,              SLE_INT64,                  65, SL_MAX_VERSION),
 
	SLE_CONDVAR(Economy, max_loan_unround_fract,        SLE_UINT16,                 70, SL_MAX_VERSION),
 
	    SLE_VAR(Economy, fluct,                         SLE_INT16),
 
	    SLE_VAR(Economy, interest_rate,                 SLE_UINT8),
 
	    SLE_VAR(Economy, infl_amount,                   SLE_UINT8),
 
	    SLE_VAR(Economy, infl_amount_pr,                SLE_UINT8),
 
	SLE_CONDVAR(Economy, industry_daily_change_counter, SLE_UINT32,                102, SL_MAX_VERSION),
 
	    SLE_END()
 
};
 

	
 
/** Economy variables */
 
static void Save_ECMY()
 
{
 
	SlObject(&_economy, _economy_desc);
 
}
 

	
 
/** Economy variables */
 
static void Load_ECMY()
 
{
 
	SlObject(&_economy, _economy_desc);
 
	StartupIndustryDailyChanges(CheckSavegameVersion(102));  // old savegames will need to be initialized
 
}
 

	
 
extern const ChunkHandler _economy_chunk_handlers[] = {
 
	{ 'PRIC', SaveLoad_PRIC, SaveLoad_PRIC, CH_RIFF | CH_AUTO_LENGTH},
 
	{ 'CAPR', SaveLoad_CAPR, SaveLoad_CAPR, CH_RIFF | CH_AUTO_LENGTH},
 
	{ 'ECMY', Save_ECMY,     Load_ECMY,     CH_RIFF | CH_LAST},
 
};
src/saveload/engine_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file engine_sl.cpp Code handling saving and loading of engines */
 

	
 
#include "../stdafx.h"
 
#include "saveload.h"
 
#include "saveload_internal.h"
 
#include "../engine_base.h"
 
#include <map>
 

	
 
static const SaveLoad _engine_desc[] = {
 
	SLE_CONDVAR(Engine, intro_date,          SLE_FILE_U16 | SLE_VAR_I32,  0,  30),
 
	SLE_CONDVAR(Engine, intro_date,          SLE_INT32,                  31, SL_MAX_VERSION),
 
	SLE_CONDVAR(Engine, age,                 SLE_FILE_U16 | SLE_VAR_I32,  0,  30),
 
	SLE_CONDVAR(Engine, age,                 SLE_INT32,                  31, SL_MAX_VERSION),
 
	    SLE_VAR(Engine, reliability,         SLE_UINT16),
 
	    SLE_VAR(Engine, reliability_spd_dec, SLE_UINT16),
 
	    SLE_VAR(Engine, reliability_start,   SLE_UINT16),
 
	    SLE_VAR(Engine, reliability_max,     SLE_UINT16),
 
	    SLE_VAR(Engine, reliability_final,   SLE_UINT16),
 
	    SLE_VAR(Engine, duration_phase_1,    SLE_UINT16),
 
	    SLE_VAR(Engine, duration_phase_2,    SLE_UINT16),
 
	    SLE_VAR(Engine, duration_phase_3,    SLE_UINT16),
 

	
 
	    SLE_VAR(Engine, lifelength,          SLE_UINT8),
 
	    SLE_VAR(Engine, flags,               SLE_UINT8),
 
	    SLE_VAR(Engine, preview_company_rank,SLE_UINT8),
 
	    SLE_VAR(Engine, preview_wait,        SLE_UINT8),
 
	SLE_CONDNULL(1, 0, 44),
 
	SLE_CONDVAR(Engine, company_avail,       SLE_FILE_U8  | SLE_VAR_U16,  0, 103),
 
	SLE_CONDVAR(Engine, company_avail,       SLE_UINT16,                104, SL_MAX_VERSION),
 
	SLE_CONDSTR(Engine, name,                SLE_STR, 0,                 84, SL_MAX_VERSION),
 

	
 
	/* reserve extra space in savegame here. (currently 16 bytes) */
 
	SLE_CONDNULL(16, 2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
static std::map<EngineID, Engine> _temp_engine;
 

	
 
Engine *GetTempDataEngine(EngineID index)
 
{
 
	return &_temp_engine[index];
 
}
 

	
 
static void Save_ENGN()
 
{
 
	Engine *e;
 
	FOR_ALL_ENGINES(e) {
 
		SlSetArrayIndex(e->index);
 
		SlObject(e, _engine_desc);
 
	}
 
}
 

	
 
static void Load_ENGN()
 
{
 
	/* As engine data is loaded before engines are initialized we need to load
 
	 * this information into a temporary array. This is then copied into the
 
	 * engine pool after processing NewGRFs by CopyTempEngineData(). */
 
	int index;
 
	while ((index = SlIterateArray()) != -1) {
 
		Engine *e = GetTempDataEngine(index);
 
		SlObject(e, _engine_desc);
 
	}
 
}
 

	
 
/**
 
 * Copy data from temporary engine array into the real engine pool.
 
 */
 
void CopyTempEngineData()
 
{
 
	Engine *e;
 
	FOR_ALL_ENGINES(e) {
 
		if (e->index >= _temp_engine.size()) break;
 

	
 
		const Engine *se = GetTempDataEngine(e->index);
 
		e->intro_date          = se->intro_date;
 
		e->age                 = se->age;
 
		e->reliability         = se->reliability;
 
		e->reliability_spd_dec = se->reliability_spd_dec;
 
		e->reliability_start   = se->reliability_start;
 
		e->reliability_max     = se->reliability_max;
 
		e->reliability_final   = se->reliability_final;
 
		e->duration_phase_1    = se->duration_phase_1;
 
		e->duration_phase_2    = se->duration_phase_2;
 
		e->duration_phase_3    = se->duration_phase_3;
 
		e->lifelength          = se->lifelength;
 
		e->flags               = se->flags;
 
		e->preview_company_rank= se->preview_company_rank;
 
		e->preview_wait        = se->preview_wait;
 
		e->company_avail       = se->company_avail;
 
		if (se->name != NULL) e->name = strdup(se->name);
 
	}
 

	
 
	/* Get rid of temporary data */
 
	_temp_engine.clear();
 
}
 

	
 
static void Load_ENGS()
 
{
 
	/* Load old separate String ID list into a temporary array. This
 
	 * was always 256 entries. */
 
	StringID names[256];
 

	
 
	SlArray(names, lengthof(names), SLE_STRINGID);
 

	
 
	/* Copy each string into the temporary engine array. */
 
	for (EngineID engine = 0; engine < lengthof(names); engine++) {
 
		Engine *e = GetTempDataEngine(engine);
 
		e->name = CopyFromOldName(names[engine]);
 
	}
 
}
 

	
 
extern const ChunkHandler _engine_chunk_handlers[] = {
 
	{ 'ENGN', Save_ENGN,     Load_ENGN,     CH_ARRAY          },
 
	{ 'ENGS', NULL,          Load_ENGS,     CH_RIFF | CH_LAST },
 
};
src/saveload/gamelog_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

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

	
 
#include "../stdafx.h"
 
#include "../gamelog.h"
 
#include "../gamelog_internal.h"
 
#include "../core/alloc_func.hpp"
 

	
 
#include "saveload.h"
 

	
 
static const SaveLoad _glog_action_desc[] = {
 
	SLE_VAR(LoggedAction, tick,              SLE_UINT16),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_mode_desc[] = {
 
	SLE_VAR(LoggedChange, mode.mode,         SLE_UINT8),
 
	SLE_VAR(LoggedChange, mode.landscape,    SLE_UINT8),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_revision_desc[] = {
 
	SLE_ARR(LoggedChange, revision.text,     SLE_UINT8,  NETWORK_REVISION_LENGTH),
 
	SLE_VAR(LoggedChange, revision.newgrf,   SLE_UINT32),
 
	SLE_VAR(LoggedChange, revision.slver,    SLE_UINT16),
 
	SLE_VAR(LoggedChange, revision.modified, SLE_UINT8),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_oldver_desc[] = {
 
	SLE_VAR(LoggedChange, oldver.type,       SLE_UINT32),
 
	SLE_VAR(LoggedChange, oldver.version,    SLE_UINT32),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_patch_desc[] = {
 
	SLE_STR(LoggedChange, patch.name,        SLE_STR,    128),
 
	SLE_VAR(LoggedChange, patch.oldval,      SLE_INT32),
 
	SLE_VAR(LoggedChange, patch.newval,      SLE_INT32),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_grfadd_desc[] = {
 
	SLE_VAR(LoggedChange, grfadd.grfid,      SLE_UINT32    ),
 
	SLE_ARR(LoggedChange, grfadd.md5sum,     SLE_UINT8,  16),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_grfrem_desc[] = {
 
	SLE_VAR(LoggedChange, grfrem.grfid,      SLE_UINT32),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_grfcompat_desc[] = {
 
	SLE_VAR(LoggedChange, grfcompat.grfid,   SLE_UINT32    ),
 
	SLE_ARR(LoggedChange, grfcompat.md5sum,  SLE_UINT8,  16),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_grfparam_desc[] = {
 
	SLE_VAR(LoggedChange, grfparam.grfid,    SLE_UINT32),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_grfmove_desc[] = {
 
	SLE_VAR(LoggedChange, grfmove.grfid,     SLE_UINT32),
 
	SLE_VAR(LoggedChange, grfmove.offset,    SLE_INT32),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _glog_grfbug_desc[] = {
 
	SLE_VAR(LoggedChange, grfbug.data,       SLE_UINT64),
 
	SLE_VAR(LoggedChange, grfbug.grfid,      SLE_UINT32),
 
	SLE_VAR(LoggedChange, grfbug.bug,        SLE_UINT8),
 
	SLE_END()
 
};
 

	
 
static const SaveLoad *_glog_desc[] = {
 
	_glog_mode_desc,
 
	_glog_revision_desc,
 
	_glog_oldver_desc,
 
	_glog_patch_desc,
 
	_glog_grfadd_desc,
 
	_glog_grfrem_desc,
 
	_glog_grfcompat_desc,
 
	_glog_grfparam_desc,
 
	_glog_grfmove_desc,
 
	_glog_grfbug_desc,
 
};
 

	
 
assert_compile(lengthof(_glog_desc) == GLCT_END);
 

	
 
static void Load_GLOG()
 
{
 
	assert(_gamelog_action == NULL);
 
	assert(_gamelog_actions == 0);
 

	
 
	GamelogActionType at;
 
	while ((at = (GamelogActionType)SlReadByte()) != GLAT_NONE) {
 
		_gamelog_action = ReallocT(_gamelog_action, _gamelog_actions + 1);
 
		LoggedAction *la = &_gamelog_action[_gamelog_actions++];
 

	
 
		la->at = at;
 

	
 
		SlObject(la, _glog_action_desc); // has to be saved after 'DATE'!
 
		la->change = NULL;
 
		la->changes = 0;
 

	
 
		GamelogChangeType ct;
 
		while ((ct = (GamelogChangeType)SlReadByte()) != GLCT_NONE) {
 
			la->change = ReallocT(la->change, la->changes + 1);
 

	
 
			LoggedChange *lc = &la->change[la->changes++];
 
			/* for SLE_STR, pointer has to be valid! so make it NULL */
 
			memset(lc, 0, sizeof(*lc));
 
			lc->ct = ct;
 

	
 
			assert((uint)ct < GLCT_END);
 

	
 
			SlObject(lc, _glog_desc[ct]);
 
		}
 
	}
 
}
 

	
 
static void Save_GLOG()
 
{
 
	const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
 
	size_t length = 0;
 

	
 
	for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
 
		const LoggedChange *lcend = &la->change[la->changes];
 
		for (LoggedChange *lc = la->change; lc != lcend; lc++) {
 
			assert((uint)lc->ct < lengthof(_glog_desc));
 
			length += SlCalcObjLength(lc, _glog_desc[lc->ct]) + 1;
 
		}
 
		length += 4;
 
	}
 
	length++;
 

	
 
	SlSetLength(length);
 

	
 
	for (LoggedAction *la = _gamelog_action; la != laend; la++) {
 
		SlWriteByte(la->at);
 
		SlObject(la, _glog_action_desc);
 

	
 
		const LoggedChange *lcend = &la->change[la->changes];
 
		for (LoggedChange *lc = la->change; lc != lcend; lc++) {
 
			SlWriteByte(lc->ct);
 
			assert((uint)lc->ct < GLCT_END);
 
			SlObject(lc, _glog_desc[lc->ct]);
 
		}
 
		SlWriteByte(GLCT_NONE);
 
	}
 
	SlWriteByte(GLAT_NONE);
 
}
 

	
 

	
 
extern const ChunkHandler _gamelog_chunk_handlers[] = {
 
	{ 'GLOG', Save_GLOG, Load_GLOG, CH_RIFF | CH_LAST }
 
};
src/saveload/group_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file group_sl.cpp Code handling saving and loading of economy data */
 

	
 
#include "../stdafx.h"
 
#include "../group.h"
 

	
 
#include "saveload.h"
 

	
 
static const SaveLoad _group_desc[] = {
 
  SLE_CONDVAR(Group, name,           SLE_NAME,    0, 83),
 
  SLE_CONDSTR(Group, name,           SLE_STR, 0, 84, SL_MAX_VERSION),
 
  SLE_VAR(Group, num_vehicle,        SLE_UINT16),
 
  SLE_VAR(Group, owner,              SLE_UINT8),
 
  SLE_VAR(Group, vehicle_type,       SLE_UINT8),
 
  SLE_VAR(Group, replace_protection, SLE_BOOL),
 
  SLE_END()
 
};
 

	
 
static void Save_GRPS(void)
 
{
 
	Group *g;
 

	
 
	FOR_ALL_GROUPS(g) {
 
		SlSetArrayIndex(g->index);
 
		SlObject(g, _group_desc);
 
	}
 
}
 

	
 

	
 
static void Load_GRPS(void)
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		Group *g = new (index) Group();
 
		SlObject(g, _group_desc);
 
	}
 
}
 

	
 
extern const ChunkHandler _group_chunk_handlers[] = {
 
	{ 'GRPS', Save_GRPS, Load_GRPS, CH_ARRAY | CH_LAST},
 
};
src/saveload/industry_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file industry_sl.cpp Code handling saving and loading of industries */
 

	
 
#include "../stdafx.h"
 
#include "../tile_type.h"
 
#include "../strings_type.h"
 
#include "../company_type.h"
 
#include "../industry.h"
 
#include "../newgrf_commons.h"
 

	
 
#include "saveload.h"
 

	
 
static const SaveLoad _industry_desc[] = {
 
	SLE_CONDVAR(Industry, xy,                         SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Industry, xy,                         SLE_UINT32,                  6, SL_MAX_VERSION),
 
	    SLE_VAR(Industry, width,                      SLE_UINT8),
 
	    SLE_VAR(Industry, height,                     SLE_UINT8),
 
	    SLE_REF(Industry, town,                       REF_TOWN),
 
	SLE_CONDNULL( 2, 0, 60),       ///< used to be industry's produced_cargo
 
	SLE_CONDARR(Industry, produced_cargo,             SLE_UINT8,  2,              78, SL_MAX_VERSION),
 
	SLE_CONDARR(Industry, incoming_cargo_waiting,     SLE_UINT16, 3,              70, SL_MAX_VERSION),
 
	    SLE_ARR(Industry, produced_cargo_waiting,     SLE_UINT16, 2),
 
	    SLE_ARR(Industry, production_rate,            SLE_UINT8,  2),
 
	SLE_CONDNULL( 3, 0, 60),       ///< used to be industry's accepts_cargo
 
	SLE_CONDARR(Industry, accepts_cargo,              SLE_UINT8,  3,              78, SL_MAX_VERSION),
 
	    SLE_VAR(Industry, prod_level,                 SLE_UINT8),
 
	    SLE_ARR(Industry, this_month_production,      SLE_UINT16, 2),
 
	    SLE_ARR(Industry, this_month_transported,     SLE_UINT16, 2),
 
	    SLE_ARR(Industry, last_month_pct_transported, SLE_UINT8,  2),
 
	    SLE_ARR(Industry, last_month_production,      SLE_UINT16, 2),
 
	    SLE_ARR(Industry, last_month_transported,     SLE_UINT16, 2),
 

	
 
	    SLE_VAR(Industry, counter,                    SLE_UINT16),
 

	
 
	    SLE_VAR(Industry, type,                       SLE_UINT8),
 
	    SLE_VAR(Industry, owner,                      SLE_UINT8),
 
	    SLE_VAR(Industry, random_color,               SLE_UINT8),
 
	SLE_CONDVAR(Industry, last_prod_year,             SLE_FILE_U8 | SLE_VAR_I32,  0, 30),
 
	SLE_CONDVAR(Industry, last_prod_year,             SLE_INT32,                 31, SL_MAX_VERSION),
 
	    SLE_VAR(Industry, was_cargo_delivered,        SLE_UINT8),
 

	
 
	SLE_CONDVAR(Industry, founder,                    SLE_UINT8,                 70, SL_MAX_VERSION),
 
	SLE_CONDVAR(Industry, construction_date,          SLE_INT32,                 70, SL_MAX_VERSION),
 
	SLE_CONDVAR(Industry, construction_type,          SLE_UINT8,                 70, SL_MAX_VERSION),
 
	SLE_CONDVAR(Industry, last_cargo_accepted_at,     SLE_INT32,                 70, SL_MAX_VERSION),
 
	SLE_CONDVAR(Industry, selected_layout,            SLE_UINT8,                 73, SL_MAX_VERSION),
 

	
 
	SLE_CONDARRX(cpp_offsetof(Industry, psa) + cpp_offsetof(Industry::PersistentStorage, storage), SLE_UINT32, 16, 76, SL_MAX_VERSION),
 

	
 
	SLE_CONDVAR(Industry, random_triggers,            SLE_UINT8,                 82, SL_MAX_VERSION),
 
	SLE_CONDVAR(Industry, random,                     SLE_UINT16,                82, SL_MAX_VERSION),
 

	
 
	/* reserve extra space in savegame here. (currently 32 bytes) */
 
	SLE_CONDNULL(32, 2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
static void Save_INDY()
 
{
 
	Industry *ind;
 

	
 
	/* Write the industries */
 
	FOR_ALL_INDUSTRIES(ind) {
 
		SlSetArrayIndex(ind->index);
 
		SlObject(ind, _industry_desc);
 
	}
 
}
 

	
 
/* Save and load the mapping between the industry/tile id on the map, and the grf file
 
 * it came from. */
 
static const SaveLoad _industries_id_mapping_desc[] = {
 
	SLE_VAR(EntityIDMapping, grfid,         SLE_UINT32),
 
	SLE_VAR(EntityIDMapping, entity_id,     SLE_UINT8),
 
	SLE_VAR(EntityIDMapping, substitute_id, SLE_UINT8),
 
	SLE_END()
 
};
 

	
 
static void Save_IIDS()
 
{
 
	uint i;
 
	uint j = _industry_mngr.GetMaxMapping();
 

	
 
	for (i = 0; i < j; i++) {
 
		SlSetArrayIndex(i);
 
		SlObject(&_industry_mngr.mapping_ID[i], _industries_id_mapping_desc);
 
	}
 
}
 

	
 
static void Save_TIDS()
 
{
 
	uint i;
 
	uint j = _industile_mngr.GetMaxMapping();
 

	
 
	for (i = 0; i < j; i++) {
 
		SlSetArrayIndex(i);
 
		SlObject(&_industile_mngr.mapping_ID[i], _industries_id_mapping_desc);
 
	}
 
}
 

	
 
static void Load_INDY()
 
{
 
	int index;
 

	
 
	ResetIndustryCounts();
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		Industry *i = new (index) Industry();
 
		SlObject(i, _industry_desc);
 
		IncIndustryTypeCount(i->type);
 
	}
 
}
 

	
 
static void Load_IIDS()
 
{
 
	int index;
 
	uint max_id;
 

	
 
	/* clear the current mapping stored.
 
	 * This will create the manager if ever it is not yet done */
 
	_industry_mngr.ResetMapping();
 

	
 
	/* get boundary for the temporary map loader NUM_INDUSTRYTYPES? */
 
	max_id = _industry_mngr.GetMaxMapping();
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		if ((uint)index >= max_id) break;
 
		SlObject(&_industry_mngr.mapping_ID[index], _industries_id_mapping_desc);
 
	}
 
}
 

	
 
static void Load_TIDS()
 
{
 
	int index;
 
	uint max_id;
 

	
 
	/* clear the current mapping stored.
 
	 * This will create the manager if ever it is not yet done */
 
	_industile_mngr.ResetMapping();
 

	
 
	/* get boundary for the temporary map loader NUM_INDUSTILES? */
 
	max_id = _industile_mngr.GetMaxMapping();
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		if ((uint)index >= max_id) break;
 
		SlObject(&_industile_mngr.mapping_ID[index], _industries_id_mapping_desc);
 
	}
 
}
 

	
 
extern const ChunkHandler _industry_chunk_handlers[] = {
 
	{ 'INDY', Save_INDY, Load_INDY, CH_ARRAY},
 
	{ 'IIDS', Save_IIDS, Load_IIDS, CH_ARRAY},
 
	{ 'TIDS', Save_TIDS, Load_TIDS, CH_ARRAY | CH_LAST},
 
};
src/saveload/map_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file map_sl.cpp Code handling saving and loading of map */
 

	
 
#include "../stdafx.h"
 
#include "../tile_type.h"
 
#include "../map_func.h"
 
#include "../core/alloc_type.hpp"
 
#include "../core/bitmath_func.hpp"
 

	
 
#include "saveload.h"
 

	
 
static uint32 _map_dim_x;
 
static uint32 _map_dim_y;
 

	
 
static const SaveLoadGlobVarList _map_dimensions[] = {
 
	SLEG_CONDVAR(_map_dim_x, SLE_UINT32, 6, SL_MAX_VERSION),
 
	SLEG_CONDVAR(_map_dim_y, SLE_UINT32, 6, SL_MAX_VERSION),
 
	    SLEG_END()
 
};
 

	
 
static void Save_MAPS()
 
{
 
	_map_dim_x = MapSizeX();
 
	_map_dim_y = MapSizeY();
 
	SlGlobList(_map_dimensions);
 
}
 

	
 
static void Load_MAPS()
 
{
 
	SlGlobList(_map_dimensions);
 
	AllocateMap(_map_dim_x, _map_dim_y);
 
}
 

	
 
enum {
 
	MAP_SL_BUF_SIZE = 4096
 
};
 

	
 
static void Load_MAPT()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	for (TileIndex i = 0; i != size;) {
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].type_height = buf[j];
 
	}
 
}
 

	
 
static void Save_MAPT()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size);
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].type_height;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
	}
 
}
 

	
 
static void Load_MAP1()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	for (TileIndex i = 0; i != size;) {
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m1 = buf[j];
 
	}
 
}
 

	
 
static void Save_MAP1()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size);
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m1;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
	}
 
}
 

	
 
static void Load_MAP2()
 
{
 
	SmallStackSafeStackAlloc<uint16, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	for (TileIndex i = 0; i != size;) {
 
		SlArray(buf, MAP_SL_BUF_SIZE,
 
			/* In those versions the m2 was 8 bits */
 
			CheckSavegameVersion(5) ? SLE_FILE_U8 | SLE_VAR_U16 : SLE_UINT16
 
		);
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m2 = buf[j];
 
	}
 
}
 

	
 
static void Save_MAP2()
 
{
 
	SmallStackSafeStackAlloc<uint16, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size * sizeof(uint16));
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m2;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT16);
 
	}
 
}
 

	
 
static void Load_MAP3()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	for (TileIndex i = 0; i != size;) {
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m3 = buf[j];
 
	}
 
}
 

	
 
static void Save_MAP3()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size);
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m3;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
	}
 
}
 

	
 
static void Load_MAP4()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	for (TileIndex i = 0; i != size;) {
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m4 = buf[j];
 
	}
 
}
 

	
 
static void Save_MAP4()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size);
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m4;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
	}
 
}
 

	
 
static void Load_MAP5()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	for (TileIndex i = 0; i != size;) {
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m5 = buf[j];
 
	}
 
}
 

	
 
static void Save_MAP5()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size);
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m5;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
	}
 
}
 

	
 
static void Load_MAP6()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	if (CheckSavegameVersion(42)) {
 
		for (TileIndex i = 0; i != size;) {
 
			/* 1024, otherwise we overflow on 64x64 maps! */
 
			SlArray(buf, 1024, SLE_UINT8);
 
			for (uint j = 0; j != 1024; j++) {
 
				_m[i++].m6 = GB(buf[j], 0, 2);
 
				_m[i++].m6 = GB(buf[j], 2, 2);
 
				_m[i++].m6 = GB(buf[j], 4, 2);
 
				_m[i++].m6 = GB(buf[j], 6, 2);
 
			}
 
		}
 
	} else {
 
		for (TileIndex i = 0; i != size;) {
 
			SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
			for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m6 = buf[j];
 
		}
 
	}
 
}
 

	
 
static void Save_MAP6()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size);
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m6;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
	}
 
}
 

	
 
static void Load_MAP7()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	for (TileIndex i = 0; i != size;) {
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m7 = buf[j];
 
	}
 
}
 

	
 
static void Save_MAP7()
 
{
 
	SmallStackSafeStackAlloc<byte, MAP_SL_BUF_SIZE> buf;
 
	TileIndex size = MapSize();
 

	
 
	SlSetLength(size);
 
	for (TileIndex i = 0; i != size;) {
 
		for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m7;
 
		SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8);
 
	}
 
}
 

	
 
extern const ChunkHandler _map_chunk_handlers[] = {
 
	{ 'MAPS', Save_MAPS,     Load_MAPS,     CH_RIFF },
 
	{ 'MAPT', Save_MAPT,     Load_MAPT,     CH_RIFF },
 
	{ 'MAPO', Save_MAP1,     Load_MAP1,     CH_RIFF },
 
	{ 'MAP2', Save_MAP2,     Load_MAP2,     CH_RIFF },
 
	{ 'M3LO', Save_MAP3,     Load_MAP3,     CH_RIFF },
 
	{ 'M3HI', Save_MAP4,     Load_MAP4,     CH_RIFF },
 
	{ 'MAP5', Save_MAP5,     Load_MAP5,     CH_RIFF },
 
	{ 'MAPE', Save_MAP6,     Load_MAP6,     CH_RIFF },
 
	{ 'MAP7', Save_MAP7,     Load_MAP7,     CH_RIFF },
 
};
src/saveload/misc_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file misc_sl.cpp Saving and loading of things that didn't fit anywhere else */
 

	
 
#include "../stdafx.h"
 
#include "../date_func.h"
 
#include "../variables.h"
 
#include "../core/random_func.hpp"
 
#include "../openttd.h"
 
#include "../tile_type.h"
 
#include "../zoom_func.h"
 
#include "../vehicle_func.h"
 
#include "../window_gui.h"
 
#include "../window_func.h"
 
#include "../viewport_func.h"
 
#include "../gfx_func.h"
 

	
 
#include "saveload.h"
 

	
 
extern TileIndex _cur_tileloop_tile;
 

	
 
/* Keep track of current game position */
 
int _saved_scrollpos_x;
 
int _saved_scrollpos_y;
 

	
 
void SaveViewportBeforeSaveGame()
 
{
 
	const Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
 

	
 
	if (w != NULL) {
 
		_saved_scrollpos_x = w->viewport->scrollpos_x;
 
		_saved_scrollpos_y = w->viewport->scrollpos_y;
 
		_saved_scrollpos_zoom = w->viewport->zoom;
 
	}
 
}
 

	
 
void ResetViewportAfterLoadGame()
 
{
 
	Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
 

	
 
	w->viewport->scrollpos_x = _saved_scrollpos_x;
 
	w->viewport->scrollpos_y = _saved_scrollpos_y;
 
	w->viewport->dest_scrollpos_x = _saved_scrollpos_x;
 
	w->viewport->dest_scrollpos_y = _saved_scrollpos_y;
 

	
 
	ViewPort *vp = w->viewport;
 
	vp->zoom = min(_saved_scrollpos_zoom, ZOOM_LVL_MAX);
 
	vp->virtual_width = ScaleByZoom(vp->width, vp->zoom);
 
	vp->virtual_height = ScaleByZoom(vp->height, vp->zoom);
 

	
 
	DoZoomInOutWindow(ZOOM_NONE, w); // update button status
 
	MarkWholeScreenDirty();
 
}
 

	
 

	
 
static const SaveLoadGlobVarList _date_desc[] = {
 
	SLEG_CONDVAR(_date,                   SLE_FILE_U16 | SLE_VAR_I32,  0,  30),
 
	SLEG_CONDVAR(_date,                   SLE_INT32,                  31, SL_MAX_VERSION),
 
	    SLEG_VAR(_date_fract,             SLE_UINT16),
 
	    SLEG_VAR(_tick_counter,           SLE_UINT16),
 
	    SLEG_VAR(_vehicle_id_ctr_day,     SLE_UINT16),
 
	    SLEG_VAR(_age_cargo_skip_counter, SLE_UINT8),
 
	SLE_CONDNULL(1, 0, 45),
 
	SLEG_CONDVAR(_cur_tileloop_tile,      SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLEG_CONDVAR(_cur_tileloop_tile,      SLE_UINT32,                  6, SL_MAX_VERSION),
 
	    SLEG_VAR(_disaster_delay,         SLE_UINT16),
 
	    SLEG_VAR(_station_tick_ctr,       SLE_UINT16),
 
	    SLEG_VAR(_random.state[0],        SLE_UINT32),
 
	    SLEG_VAR(_random.state[1],        SLE_UINT32),
 
	SLEG_CONDVAR(_cur_town_ctr,           SLE_FILE_U8  | SLE_VAR_U32,  0, 9),
 
	SLEG_CONDVAR(_cur_town_ctr,           SLE_UINT32,                 10, SL_MAX_VERSION),
 
	    SLEG_VAR(_cur_company_tick_index, SLE_FILE_U8  | SLE_VAR_U32),
 
	    SLEG_VAR(_next_competitor_start,  SLE_FILE_U16 | SLE_VAR_U32),
 
	    SLEG_VAR(_trees_tick_ctr,         SLE_UINT8),
 
	SLEG_CONDVAR(_pause_game,             SLE_UINT8,                   4, SL_MAX_VERSION),
 
	SLEG_CONDVAR(_cur_town_iter,          SLE_UINT32,                 11, SL_MAX_VERSION),
 
	    SLEG_END()
 
};
 

	
 
/* Save load date related variables as well as persistent tick counters
 
 * XXX: currently some unrelated stuff is just put here */
 
static void SaveLoad_DATE()
 
{
 
	SlGlobList(_date_desc);
 
}
 

	
 

	
 
static const SaveLoadGlobVarList _view_desc[] = {
 
	SLEG_CONDVAR(_saved_scrollpos_x,    SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
 
	SLEG_CONDVAR(_saved_scrollpos_x,    SLE_INT32,                  6, SL_MAX_VERSION),
 
	SLEG_CONDVAR(_saved_scrollpos_y,    SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
 
	SLEG_CONDVAR(_saved_scrollpos_y,    SLE_INT32,                  6, SL_MAX_VERSION),
 
	    SLEG_VAR(_saved_scrollpos_zoom, SLE_UINT8),
 
	    SLEG_END()
 
};
 

	
 
static void SaveLoad_VIEW()
 
{
 
	SlGlobList(_view_desc);
 
}
 

	
 
extern const ChunkHandler _misc_chunk_handlers[] = {
 
	{ 'DATE', SaveLoad_DATE, SaveLoad_DATE, CH_RIFF},
 
	{ 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, CH_RIFF | CH_LAST},
 
};
src/saveload/newgrf_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file newgrf_sl.cpp Code handling saving and loading of newgrf config */
 

	
 
#include "../stdafx.h"
 
#include "../newgrf_config.h"
 
#include "../core/bitmath_func.hpp"
 
#include "../core/alloc_func.hpp"
 
#include "../gfx_func.h"
 

	
 
#include "saveload.h"
 

	
 
static const SaveLoad _grfconfig_desc[] = {
 
	    SLE_STR(GRFConfig, filename,         SLE_STR,    0x40),
 
	    SLE_VAR(GRFConfig, grfid,            SLE_UINT32),
 
	    SLE_ARR(GRFConfig, md5sum,           SLE_UINT8,  16),
 
	    SLE_ARR(GRFConfig, param,            SLE_UINT32, 0x80),
 
	    SLE_VAR(GRFConfig, num_params,       SLE_UINT8),
 
	SLE_CONDVAR(GRFConfig, windows_paletted, SLE_BOOL,   101, SL_MAX_VERSION),
 
	SLE_END()
 
};
 

	
 

	
 
static void Save_NGRF()
 
{
 
	int index = 0;
 

	
 
	for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) {
 
		if (HasBit(c->flags, GCF_STATIC)) continue;
 
		SlSetArrayIndex(index++);
 
		SlObject(c, _grfconfig_desc);
 
	}
 
}
 

	
 

	
 
static void Load_NGRF()
 
{
 
	ClearGRFConfigList(&_grfconfig);
 
	while (SlIterateArray() != -1) {
 
		GRFConfig *c = CallocT<GRFConfig>(1);
 
		SlObject(c, _grfconfig_desc);
 
		if (CheckSavegameVersion(101)) c->windows_paletted = (_use_palette == PAL_WINDOWS);
 
		AppendToGRFConfigList(&_grfconfig, c);
 
	}
 

	
 
	/* Append static NewGRF configuration */
 
	AppendStaticGRFConfigs(&_grfconfig);
 
}
 

	
 
extern const ChunkHandler _newgrf_chunk_handlers[] = {
 
	{ 'NGRF', Save_NGRF, Load_NGRF, CH_ARRAY | CH_LAST }
 
};
src/saveload/oldloader.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file oldloader.cpp Loading of old TTD(patch) savegames. */
 

	
 
#include "../stdafx.h"
 
#include "../openttd.h"
 
#include "../station_map.h"
 
#include "../town.h"
 
#include "../industry.h"
 
#include "../company_func.h"
 
#include "../company_base.h"
 
#include "../aircraft.h"
 
#include "../roadveh.h"
 
#include "../ship.h"
 
#include "../train.h"
 
#include "../signs_base.h"
 
#include "../debug.h"
 
#include "../depot_base.h"
 
#include "../newgrf_config.h"
 
#include "../ai/ai.h"
 
#include "../ai/default/default.h"
 
#include "../zoom_func.h"
 
#include "../functions.h"
 
#include "../date_func.h"
 
#include "../vehicle_func.h"
 
#include "../variables.h"
 
#include "../strings_func.h"
 
#include "../effectvehicle_base.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "saveload.h"
 
#include "saveload_internal.h"
 

	
 
enum {
 
	HEADER_SIZE = 49,
 
	BUFFER_SIZE = 4096,
 

	
 
	OLD_MAP_SIZE = 256 * 256
 
};
 

	
 
struct LoadgameState {
 
	FILE *file;
 

	
 
	uint chunk_size;
 

	
 
	bool decoding;
 
	byte decode_char;
 

	
 
	uint buffer_count;
 
	uint buffer_cur;
 
	byte buffer[BUFFER_SIZE];
 

	
 
	uint total_read;
 
	bool failed;
 
};
 

	
 
/* OldChunk-Type */
 
enum OldChunkType {
 
	OC_SIMPLE    = 0,
 
	OC_NULL      = 1,
 
	OC_CHUNK     = 2,
 
	OC_ASSERT    = 3,
 
	/* 8 bits allocated (256 max) */
 

	
 
	OC_VAR_I8    = 1 << 8,
 
	OC_VAR_U8    = 2 << 8,
 
	OC_VAR_I16   = 3 << 8,
 
	OC_VAR_U16   = 4 << 8,
 
	OC_VAR_I32   = 5 << 8,
 
	OC_VAR_U32   = 6 << 8,
 
	OC_VAR_I64   = 7 << 8,
 
	/* 8 bits allocated (256 max) */
 

	
 
	OC_FILE_I8   = 1 << 16,
 
	OC_FILE_U8   = 2 << 16,
 
	OC_FILE_I16  = 3 << 16,
 
	OC_FILE_U16  = 4 << 16,
 
	OC_FILE_I32  = 5 << 16,
 
	OC_FILE_U32  = 6 << 16,
 
	/* 8 bits allocated (256 max) */
 

	
 
	OC_INT8      = OC_VAR_I8   | OC_FILE_I8,
 
	OC_UINT8     = OC_VAR_U8   | OC_FILE_U8,
 
	OC_INT16     = OC_VAR_I16  | OC_FILE_I16,
 
	OC_UINT16    = OC_VAR_U16  | OC_FILE_U16,
 
	OC_INT32     = OC_VAR_I32  | OC_FILE_I32,
 
	OC_UINT32    = OC_VAR_U32  | OC_FILE_U32,
 

	
 
	OC_TILE      = OC_VAR_U32  | OC_FILE_U16,
 

	
 
	/**
 
	 * Dereference the pointer once before writing to it,
 
	 * so we do not have to use big static arrays.
 
	 */
 
	OC_DEREFERENCE_POINTER = 1 << 31,
 

	
 
	OC_END       = 0 ///< End of the whole chunk, all 32 bits set to zero
 
};
 

	
 
DECLARE_ENUM_AS_BIT_SET(OldChunkType);
 

	
 
typedef bool OldChunkProc(LoadgameState *ls, int num);
 

	
 
struct OldChunks {
 
	OldChunkType type;   ///< Type of field
 
	uint32 amount;       ///< Amount of fields
 

	
 
	void *ptr;           ///< Pointer where to save the data (may only be set if offset is 0)
 
	uint offset;         ///< Offset from basepointer (may only be set if ptr is NULL)
 
	OldChunkProc *proc;  ///< Pointer to function that is called with OC_CHUNK
 
};
 

	
 
/* If it fails, check lines above.. */
 
assert_compile(sizeof(TileIndex) == 4);
 

	
 
extern SavegameType _savegame_type;
 
extern uint32 _ttdp_version;
 

	
 
static uint32 _bump_assert_value;
 
static bool   _read_ttdpatch_flags;
 

	
 
static OldChunkType GetOldChunkType(OldChunkType type)     {return (OldChunkType)GB(type, 0, 8);}
 
static OldChunkType GetOldChunkVarType(OldChunkType type)  {return (OldChunkType)(GB(type, 8, 8) << 8);}
 
static OldChunkType GetOldChunkFileType(OldChunkType type) {return (OldChunkType)(GB(type, 16, 8) << 16);}
 

	
 
static inline byte CalcOldVarLen(OldChunkType type)
 
{
 
	static const byte type_mem_size[] = {0, 1, 1, 2, 2, 4, 4, 8};
 
	byte length = GB(type, 8, 8);
 
	assert(length != 0 && length < lengthof(type_mem_size));
 
	return type_mem_size[length];
 
}
 

	
 
/**
 
 *
 
 * Reads a byte from a file (do not call yourself, use ReadByte())
 
 *
 
 */
 
static byte ReadByteFromFile(LoadgameState *ls)
 
{
 
	/* To avoid slow reads, we read BUFFER_SIZE of bytes per time
 
	and just return a byte per time */
 
	if (ls->buffer_cur >= ls->buffer_count) {
 
		/* Read some new bytes from the file */
 
		int count = (int)fread(ls->buffer, 1, BUFFER_SIZE, ls->file);
 

	
 
		/* We tried to read, but there is nothing in the file anymore.. */
 
		if (count == 0) {
 
			DEBUG(oldloader, 0, "Read past end of file, loading failed");
 
			ls->failed = true;
 
		}
 

	
 
		ls->buffer_count = count;
 
		ls->buffer_cur   = 0;
 
	}
 

	
 
	return ls->buffer[ls->buffer_cur++];
 
}
 

	
 
/**
 
 *
 
 * Reads a byte from the buffer and decompress if needed
 
 *
 
 */
 
static byte ReadByte(LoadgameState *ls)
 
{
 
	/* Old savegames have a nice compression algorithm (RLE)
 
	which means that we have a chunk, which starts with a length
 
	byte. If that byte is negative, we have to repeat the next byte
 
	that many times ( + 1). Else, we need to read that amount of bytes.
 
	Works pretty good if you have many zero's behind eachother */
 

	
 
	if (ls->chunk_size == 0) {
 
		/* Read new chunk */
 
		int8 new_byte = ReadByteFromFile(ls);
 

	
 
		if (new_byte < 0) {
 
			/* Repeat next char for new_byte times */
 
			ls->decoding    = true;
 
			ls->decode_char = ReadByteFromFile(ls);
 
			ls->chunk_size  = -new_byte + 1;
 
		} else {
 
			ls->decoding    = false;
 
			ls->chunk_size  = new_byte + 1;
 
		}
 
	}
 

	
 
	ls->total_read++;
 
	ls->chunk_size--;
 

	
 
	return ls->decoding ? ls->decode_char : ReadByteFromFile(ls);
 
}
 

	
 
static inline uint16 ReadUint16(LoadgameState *ls)
 
{
 
	byte x = ReadByte(ls);
 
	return x | ReadByte(ls) << 8;
 
}
 

	
 
static inline uint32 ReadUint32(LoadgameState *ls)
 
{
 
	uint16 x = ReadUint16(ls);
 
	return x | ReadUint16(ls) << 16;
 
}
 

	
 
/**
 
 *
 
 * Loads a chunk from the old savegame
 
 *
 
 */
 
static bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks)
 
{
 
	const OldChunks *chunk = chunks;
 
	byte *base_ptr = (byte*)base;
 

	
 
	while (chunk->type != OC_END) {
 
		byte *ptr = (byte*)chunk->ptr;
 
		if ((chunk->type & OC_DEREFERENCE_POINTER) != 0) ptr = *(byte**)ptr;
 

	
 
		for (uint i = 0; i < chunk->amount; i++) {
 
			if (ls->failed) return false;
 

	
 
			/* Handle simple types */
 
			if (GetOldChunkType(chunk->type) != 0) {
 
				switch (GetOldChunkType(chunk->type)) {
 
					/* Just read the byte and forget about it */
 
					case OC_NULL: ReadByte(ls); break;
 

	
 
					case OC_CHUNK:
 
						/* Call function, with 'i' as parameter to tell which item we
 
						 * are going to read */
 
						if (!chunk->proc(ls, i)) return false;
 
						break;
 

	
 
					case OC_ASSERT:
 
						DEBUG(oldloader, 4, "Assert point: 0x%X / 0x%X", ls->total_read, chunk->offset + _bump_assert_value);
 
						if (ls->total_read != chunk->offset + _bump_assert_value) ls->failed = true;
 
					default: break;
 
				}
 
			} else {
 
				uint64 res = 0;
 

	
 
				/* Reading from the file: bits 16 to 23 have the FILE type */
 
				switch (GetOldChunkFileType(chunk->type)) {
 
					case OC_FILE_I8:  res = (int8)ReadByte(ls); break;
 
					case OC_FILE_U8:  res = ReadByte(ls); break;
 
					case OC_FILE_I16: res = (int16)ReadUint16(ls); break;
 
					case OC_FILE_U16: res = ReadUint16(ls); break;
 
					case OC_FILE_I32: res = (int32)ReadUint32(ls); break;
 
					case OC_FILE_U32: res = ReadUint32(ls); break;
 
					default: NOT_REACHED();
 
				}
 

	
 
				/* Sanity check */
 
				assert(base_ptr != NULL || chunk->ptr != NULL);
 

	
 
				/* Writing to the var: bits 8 to 15 have the VAR type */
 
				if (chunk->ptr == NULL) ptr = base_ptr + chunk->offset;
 

	
 
				/* Write the data */
 
				switch (GetOldChunkVarType(chunk->type)) {
 
					case OC_VAR_I8: *(int8  *)ptr = GB(res, 0, 8); break;
 
					case OC_VAR_U8: *(uint8 *)ptr = GB(res, 0, 8); break;
 
					case OC_VAR_I16:*(int16 *)ptr = GB(res, 0, 16); break;
 
					case OC_VAR_U16:*(uint16*)ptr = GB(res, 0, 16); break;
 
					case OC_VAR_I32:*(int32 *)ptr = res; break;
 
					case OC_VAR_U32:*(uint32*)ptr = res; break;
 
					case OC_VAR_I64:*(int64 *)ptr = res; break;
 
					default: NOT_REACHED();
 
				}
 

	
 
				/* Increase pointer base for arrays when looping */
 
				if (chunk->amount > 1 && chunk->ptr != NULL) ptr += CalcOldVarLen(chunk->type);
 
			}
 
		}
 

	
 
		chunk++;
 
	}
 

	
 
	return true;
 
}
 

	
 
/**
 
 *
 
 * Initialize some data before reading
 
 *
 
 */
 
static void InitLoading(LoadgameState *ls)
 
{
 
	ls->chunk_size   = 0;
 
	ls->total_read   = 0;
 
	ls->failed       = false;
 

	
 
	ls->decoding     = false;
 
	ls->decode_char  = 0;
 

	
 
	ls->buffer_cur   = 0;
 
	ls->buffer_count = 0;
 
	memset(ls->buffer, 0, BUFFER_SIZE);
 

	
 
	_bump_assert_value = 0;
 

	
 
	_savegame_type   = SGT_TTD;
 
	_ttdp_version    = 0;
 

	
 
	_read_ttdpatch_flags = false;
 
}
 

	
 

	
 
/*
 
 * Begin -- Stuff to fix the savegames to be OpenTTD compatible
 
 */
 

	
 
extern uint32 GetOldTownName(uint32 townnameparts, byte old_town_name_type);
 

	
 
static void FixOldTowns()
 
{
 
	Town *town;
 

	
 
	/* Convert town-names if needed */
 
	FOR_ALL_TOWNS(town) {
 
		if (IsInsideMM(town->townnametype, 0x20C1, 0x20C3)) {
 
			town->townnametype = SPECSTR_TOWNNAME_ENGLISH + _settings_game.game_creation.town_name;
 
			town->townnameparts = GetOldTownName(town->townnameparts, _settings_game.game_creation.town_name);
 
		}
 
	}
 
}
 

	
 
static StringID *_old_vehicle_names = NULL;
 

	
 
static void FixOldVehicles()
 
{
 
	Vehicle* v;
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		v->name = CopyFromOldName(_old_vehicle_names[v->index]);
 

	
 
		/* We haven't used this bit for stations for ages */
 
		if (v->type == VEH_ROAD &&
 
				v->u.road.state != RVSB_IN_DEPOT &&
 
				v->u.road.state != RVSB_WORMHOLE) {
 
			ClrBit(v->u.road.state, RVS_IS_STOPPING);
 
		}
 

	
 
		/* The subtype should be 0, but it sometimes isn't :( */
 
		if (v->type == VEH_ROAD) v->subtype = 0;
 

	
 
		/* Sometimes primary vehicles would have a nothing (invalid) order
 
		 * or vehicles that could not have an order would still have a
 
		 * (loading) order which causes assertions and the like later on.
 
		 */
 
		if (!IsCompanyBuildableVehicleType(v) ||
 
				(v->IsPrimaryVehicle() && v->current_order.IsType(OT_NOTHING))) {
 
			v->current_order.MakeDummy();
 
		}
 

	
 
		/* Shared orders are fixed in AfterLoadVehicles now */
 
	}
 
}
 

	
 
/*
 
 * End -- Stuff to fix the savegames to be OpenTTD compatible
 
 */
 

	
 

	
 
/* Help:
 
 *  - OCL_SVAR: load 'type' to offset 'offset' in a struct of type 'base', which must also
 
 *       be given via base in LoadChunk() as real pointer
 
 *  - OCL_VAR: load 'type' to a global var
 
 *  - OCL_END: every struct must end with this
 
 *  - OCL_NULL: read 'amount' of bytes and send them to /dev/null or something
 
 *  - OCL_CHUNK: load an other proc to load a part of the savegame, 'amount' times
 
 *  - OCL_ASSERT: to check if we are really at the place we expect to be.. because old savegames are too binary to be sure ;)
 
 */
 
#define OCL_SVAR(type, base, offset)         { type,          1, NULL,    (uint)cpp_offsetof(base, offset), NULL }
 
#define OCL_VAR(type, amount, pointer)       { type,     amount, pointer, 0,                      NULL }
 
#define OCL_END()                                   { OC_END,        0, NULL,    0,                      NULL }
 
#define OCL_NULL(amount)                            { OC_NULL,  amount, NULL,    0,                      NULL }
 
#define OCL_CHUNK(amount, proc)                     { OC_CHUNK, amount, NULL,    0,                      proc }
 
#define OCL_ASSERT(size)                            { OC_ASSERT,     1, NULL, size,                      NULL }
 

	
 
/* The savegames has some hard-coded pointers, because it always enters the same
 
    piece of memory.. we don't.. so we need to remap ;)
 
   Old Towns are 94 bytes big
 
   Old Orders are 2 bytes big */
 
#define REMAP_TOWN_IDX(x) ((x) - (0x0459154 - 0x0458EF0)) / 94
 
#define REMAP_ORDER_IDX(x) ((x) - (0x045AB08 - 0x0458EF0)) / 2
 

	
 
extern TileIndex *_animated_tile_list;
 
extern uint _animated_tile_count;
 
extern char *_old_name_array;
 

	
 
static byte   _old_vehicle_multiplier;
 
static uint8  *_old_map3;
 
static uint32 _old_town_index;
 
static uint16 _old_string_id;
 
static uint16 _old_string_id_2;
 
static uint16 _old_extra_chunk_nums;
 

	
 
static void ReadTTDPatchFlags()
 
{
 
	if (_read_ttdpatch_flags) return;
 

	
 
	_read_ttdpatch_flags = true;
 

	
 
	/* TTDPatch misuses _old_map3 for flags.. read them! */
 
	_old_vehicle_multiplier = _old_map3[0];
 
	/* Somehow.... there was an error in some savegames, so 0 becomes 1
 
	and 1 becomes 2. The rest of the values are okay */
 
	if (_old_vehicle_multiplier < 2) _old_vehicle_multiplier++;
 

	
 
	_old_vehicle_names = MallocT<StringID>(_old_vehicle_multiplier * 850);
 

	
 
	/* TTDPatch increases the Vehicle-part in the middle of the game,
 
	so if the multipler is anything else but 1, the assert fails..
 
	bump the assert value so it doesn't!
 
	(1 multipler == 850 vehicles
 
	1 vehicle   == 128 bytes */
 
	_bump_assert_value = (_old_vehicle_multiplier - 1) * 850 * 128;
 

	
 
	for (uint i = 0; i < 17; i++) { // check tile 0, too
 
		if (_old_map3[i] != 0) _savegame_type = SGT_TTDP1;
 
	}
 

	
 
	/* Check if we have a modern TTDPatch savegame (has extra data all around) */
 
	if (memcmp(&_old_map3[0x1FFFA], "TTDp", 4) == 0) _savegame_type = SGT_TTDP2;
 

	
 
	_old_extra_chunk_nums = _old_map3[_savegame_type == SGT_TTDP2 ? 0x1FFFE : 0x2];
 

	
 
	/* Clean the misused places */
 
	for (uint i = 0;       i < 17;      i++) _old_map3[i] = 0;
 
	for (uint i = 0x1FE00; i < 0x20000; i++) _old_map3[i] = 0;
 

	
 
	if (_savegame_type == SGT_TTDP2) DEBUG(oldloader, 2, "Found TTDPatch game");
 

	
 
	DEBUG(oldloader, 3, "Vehicle-multiplier is set to %d (%d vehicles)", _old_vehicle_multiplier, _old_vehicle_multiplier * 850);
 
}
 

	
 
static const OldChunks town_chunk[] = {
 
	OCL_SVAR(   OC_TILE, Town, xy ),
 
	OCL_NULL( 2 ),         ///< population,        no longer in use
 
	OCL_SVAR( OC_UINT16, Town, townnametype ),
 
	OCL_SVAR( OC_UINT32, Town, townnameparts ),
 
	OCL_SVAR(  OC_UINT8, Town, grow_counter ),
 
	OCL_NULL( 1 ),         ///< sort_index,        no longer in use
 
	OCL_NULL( 4 ),         ///< sign-coordinates,  no longer in use
 
	OCL_NULL( 2 ),         ///< namewidth,         no longer in use
 
	OCL_SVAR( OC_UINT16, Town, flags12 ),
 
	OCL_NULL( 10 ),        ///< radius,            no longer in use
 

	
 
	OCL_SVAR( OC_UINT16, Town, ratings[0] ),
 
	OCL_SVAR( OC_UINT16, Town, ratings[1] ),
 
	OCL_SVAR( OC_UINT16, Town, ratings[2] ),
 
	OCL_SVAR( OC_UINT16, Town, ratings[3] ),
 
	OCL_SVAR( OC_UINT16, Town, ratings[4] ),
 
	OCL_SVAR( OC_UINT16, Town, ratings[5] ),
 
	OCL_SVAR( OC_UINT16, Town, ratings[6] ),
 
	OCL_SVAR( OC_UINT16, Town, ratings[7] ),
 

	
 
	/* XXX - This is pretty odd.. we read 32bit, but only write 16bit.. sure there is
 
	nothing changed ? ? */
 
	OCL_SVAR( OC_FILE_U32 | OC_VAR_U16, Town, have_ratings ),
 
	OCL_SVAR( OC_FILE_U32 | OC_VAR_U16, Town, statues ),
 
	OCL_NULL( 2 ),         ///< num_houses,        no longer in use
 
	OCL_SVAR(  OC_UINT8, Town, time_until_rebuild ),
 
	OCL_SVAR(  OC_UINT8, Town, growth_rate ),
 

	
 
	OCL_SVAR( OC_UINT16, Town, new_max_pass ),
 
	OCL_SVAR( OC_UINT16, Town, new_max_mail ),
 
	OCL_SVAR( OC_UINT16, Town, new_act_pass ),
 
	OCL_SVAR( OC_UINT16, Town, new_act_mail ),
 
	OCL_SVAR( OC_UINT16, Town, max_pass ),
 
	OCL_SVAR( OC_UINT16, Town, max_mail ),
 
	OCL_SVAR( OC_UINT16, Town, act_pass ),
 
	OCL_SVAR( OC_UINT16, Town, act_mail ),
 

	
 
	OCL_SVAR(  OC_UINT8, Town, pct_pass_transported ),
 
	OCL_SVAR(  OC_UINT8, Town, pct_mail_transported ),
 

	
 
	OCL_SVAR( OC_UINT16, Town, new_act_food ),
 
	OCL_SVAR( OC_UINT16, Town, new_act_water ),
 
	OCL_SVAR( OC_UINT16, Town, act_food ),
 
	OCL_SVAR( OC_UINT16, Town, act_water ),
 

	
 
	OCL_SVAR(  OC_UINT8, Town, road_build_months ),
 
	OCL_SVAR(  OC_UINT8, Town, fund_buildings_months ),
 

	
 
	OCL_NULL( 8 ),         ///< some junk at the end of the record
 

	
 
	OCL_END()
 
};
 
static bool LoadOldTown(LoadgameState *ls, int num)
 
{
 
	Town *t = new (num) Town();
 
	if (!LoadChunk(ls, t, town_chunk)) return false;
 

	
 
	if (t->xy == 0) t->xy = INVALID_TILE;
 

	
 
	return true;
 
}
 

	
 
static uint16 _old_order;
 
static const OldChunks order_chunk[] = {
 
	OCL_VAR ( OC_UINT16,   1, &_old_order ),
 
	OCL_END()
 
};
 

	
 
static bool LoadOldOrder(LoadgameState *ls, int num)
 
{
 
	if (!LoadChunk(ls, NULL, order_chunk)) return false;
 

	
 
	new (num) Order(UnpackOldOrder(_old_order));
 

	
 
	/* Relink the orders to eachother (in TTD(Patch) the orders for one
 
	vehicle are behind eachother, with an invalid order (OT_NOTHING) as indication that
 
	it is the last order */
 
	if (num > 0 && GetOrder(num)->IsValid())
 
		GetOrder(num - 1)->next = GetOrder(num);
 

	
 
	return true;
 
}
 

	
 
static bool LoadOldAnimTileList(LoadgameState *ls, int num)
 
{
 
	/* This is sligthly hackish - we must load a chunk into an array whose
 
	 * address isn't static, but instead pointed to by _animated_tile_list.
 
	 * To achieve that, create an OldChunks list on the stack on the fly.
 
	 * The list cannot be static because the value of _animated_tile_list
 
	 * can change between calls. */
 

	
 
	const OldChunks anim_chunk[] = {
 
		OCL_VAR (   OC_TILE, 256, _animated_tile_list ),
 
		OCL_END ()
 
	};
 

	
 
	if (!LoadChunk(ls, NULL, anim_chunk)) return false;
 

	
 
	/* Update the animated tile counter by counting till the first zero in the array */
 
	for (_animated_tile_count = 0; _animated_tile_count < 256; _animated_tile_count++) {
 
		if (_animated_tile_list[_animated_tile_count] == 0) break;
 
	}
 

	
 
	return true;
 
}
 

	
 
static const OldChunks depot_chunk[] = {
 
	OCL_SVAR(   OC_TILE, Depot, xy ),
 
	OCL_VAR ( OC_UINT32,   1, &_old_town_index ),
 
	OCL_END()
 
};
 

	
 
static bool LoadOldDepot(LoadgameState *ls, int num)
 
{
 
	Depot *d = new (num) Depot();
 
	if (!LoadChunk(ls, d, depot_chunk)) return false;
 

	
 
	if (d->xy != 0) {
 
		GetDepot(num)->town_index = REMAP_TOWN_IDX(_old_town_index);
 
	} else {
 
		d->xy = INVALID_TILE;
 
	}
 

	
 
	return true;
 
}
 

	
 
static int32 _old_price;
 
static uint16 _old_price_frac;
 
static const OldChunks price_chunk[] = {
 
	OCL_VAR (  OC_INT32,   1, &_old_price ),
 
	OCL_VAR ( OC_UINT16,   1, &_old_price_frac ),
 
	OCL_END()
 
};
 

	
 
static bool LoadOldPrice(LoadgameState *ls, int num)
 
{
 
	if (!LoadChunk(ls, NULL, price_chunk)) return false;
 

	
 
	/* We use a struct to store the prices, but they are ints in a row..
 
	so just access the struct as an array of int32's */
 
	((Money*)&_price)[num] = _old_price;
 
	_price_frac[num] = _old_price_frac;
 

	
 
	return true;
 
}
 

	
 
static const OldChunks cargo_payment_rate_chunk[] = {
 
	OCL_VAR (  OC_INT32,   1, &_old_price ),
 
	OCL_VAR ( OC_UINT16,   1, &_old_price_frac ),
 

	
 
	OCL_NULL( 2 ),         ///< Junk
 
	OCL_END()
 
};
 

	
 
static bool LoadOldCargoPaymentRate(LoadgameState *ls, int num)
 
{
 
	if (!LoadChunk(ls, NULL, cargo_payment_rate_chunk)) return false;
 

	
 
	_cargo_payment_rates[num] = -_old_price;
 
	_cargo_payment_rates_frac[num] = _old_price_frac;
 

	
 
	return true;
 
}
 

	
 
static uint   _current_station_id;
 
static uint16 _waiting_acceptance;
 
static uint8  _cargo_source;
 
static uint8  _cargo_days;
 

	
 
static const OldChunks goods_chunk[] = {
 
	OCL_VAR ( OC_UINT16, 1,          &_waiting_acceptance ),
 
	OCL_SVAR(  OC_UINT8, GoodsEntry, days_since_pickup ),
 
	OCL_SVAR(  OC_UINT8, GoodsEntry, rating ),
 
	OCL_VAR (  OC_UINT8, 1,          &_cargo_source ),
 
	OCL_VAR (  OC_UINT8, 1,          &_cargo_days ),
 
	OCL_SVAR(  OC_UINT8, GoodsEntry, last_speed ),
 
	OCL_SVAR(  OC_UINT8, GoodsEntry, last_age ),
 

	
 
	OCL_END()
 
};
 

	
 
static bool LoadOldGood(LoadgameState *ls, int num)
 
{
 
	Station *st = GetStation(_current_station_id);
 
	GoodsEntry *ge = &st->goods[num];
 
	bool ret = LoadChunk(ls, ge, goods_chunk);
 
	if (!ret) return false;
 

	
 
	SB(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15));
 
	SB(ge->acceptance_pickup, GoodsEntry::PICKUP, 1, _cargo_source != 0xFF);
 
	if (GB(_waiting_acceptance, 0, 12) != 0) {
 
		CargoPacket *cp = new CargoPacket();
 
		cp->source          = (_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source;
 
		cp->count           = GB(_waiting_acceptance, 0, 12);
 
		cp->days_in_transit = _cargo_days;
 
		ge->cargo.Append(cp);
 
	}
 
	return ret;
 
}
 

	
 
static const OldChunks station_chunk[] = {
 
	OCL_SVAR(   OC_TILE, Station, xy ),
 
	OCL_VAR ( OC_UINT32,   1, &_old_town_index ),
 

	
 
	OCL_NULL( 4 ), ///< bus/lorry tile
 
	OCL_SVAR(   OC_TILE, Station, train_tile ),
 
	OCL_SVAR(   OC_TILE, Station, airport_tile ),
 
	OCL_SVAR(   OC_TILE, Station, dock_tile ),
 
	OCL_SVAR(  OC_UINT8, Station, trainst_w ),
 

	
 
	OCL_NULL( 1 ),         ///< sort-index, no longer in use
 
	OCL_NULL( 2 ),         ///< sign-width, no longer in use
 

	
 
	OCL_VAR ( OC_UINT16,   1, &_old_string_id ),
 

	
 
	OCL_NULL( 4 ),         ///< sign left/top, no longer in use
 

	
 
	OCL_SVAR( OC_UINT16, Station, had_vehicle_of_type ),
 

	
 
	OCL_CHUNK( 12, LoadOldGood ),
 

	
 
	OCL_SVAR(  OC_UINT8, Station, time_since_load ),
 
	OCL_SVAR(  OC_UINT8, Station, time_since_unload ),
 
	OCL_SVAR(  OC_UINT8, Station, delete_ctr ),
 
	OCL_SVAR(  OC_UINT8, Station, owner ),
 
	OCL_SVAR(  OC_UINT8, Station, facilities ),
 
	OCL_SVAR(  OC_UINT8, Station, airport_type ),
 
	/* Bus/truck status, no longer in use
 
	 * Blocked months
 
	 * Unknown
 
	 */
 
	OCL_NULL( 4 ),
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Station, airport_flags ),
 
	OCL_NULL( 2 ),         ///< last_vehicle. now last_vehicle_type
 

	
 
	OCL_NULL( 4 ),         ///< Junk at end of chunk
 

	
 
	OCL_END()
 
};
 
static bool LoadOldStation(LoadgameState *ls, int num)
 
{
 
	Station *st = new (num) Station();
 
	_current_station_id = num;
 

	
 
	if (!LoadChunk(ls, st, station_chunk))
 
		return false;
 

	
 
	if (st->xy != 0) {
 
		st->town    = GetTown(REMAP_TOWN_IDX(_old_town_index));
 
		st->string_id = RemapOldStringID(_old_string_id);
 
	} else {
 
		st->xy = INVALID_TILE;
 
	}
 

	
 
	return true;
 
}
 

	
 
static const OldChunks industry_chunk[] = {
 
	OCL_SVAR(   OC_TILE, Industry, xy ),
 
	OCL_VAR ( OC_UINT32,   1, &_old_town_index ),
 
	OCL_SVAR(  OC_UINT8, Industry, width ),
 
	OCL_SVAR(  OC_UINT8, Industry, height ),
 
	OCL_NULL( 2 ),  ///< used to be industry's produced_cargo
 

	
 
	OCL_SVAR( OC_UINT16, Industry, produced_cargo_waiting[0] ),
 
	OCL_SVAR( OC_UINT16, Industry, produced_cargo_waiting[1] ),
 

	
 
	OCL_SVAR(  OC_UINT8, Industry, production_rate[0] ),
 
	OCL_SVAR(  OC_UINT8, Industry, production_rate[1] ),
 

	
 
	OCL_NULL( 3 ),  ///< used to be industry's accepts_cargo
 

	
 
	OCL_SVAR(  OC_UINT8, Industry, prod_level ),
 

	
 
	OCL_SVAR( OC_UINT16, Industry, this_month_production[0] ),
 
	OCL_SVAR( OC_UINT16, Industry, this_month_production[1] ),
 
	OCL_SVAR( OC_UINT16, Industry, this_month_transported[0] ),
 
	OCL_SVAR( OC_UINT16, Industry, this_month_transported[1] ),
 

	
 
	OCL_SVAR(  OC_UINT8, Industry, last_month_pct_transported[0] ),
 
	OCL_SVAR(  OC_UINT8, Industry, last_month_pct_transported[1] ),
 

	
 
	OCL_SVAR( OC_UINT16, Industry, last_month_production[0] ),
 
	OCL_SVAR( OC_UINT16, Industry, last_month_production[1] ),
 
	OCL_SVAR( OC_UINT16, Industry, last_month_transported[0] ),
 
	OCL_SVAR( OC_UINT16, Industry, last_month_transported[1] ),
 

	
 
	OCL_SVAR(  OC_UINT8, Industry, type ),
 
	OCL_SVAR(  OC_UINT8, Industry, owner ),
 
	OCL_SVAR(  OC_UINT8, Industry, random_color ),
 
	OCL_SVAR( OC_FILE_U8 | OC_VAR_I32, Industry, last_prod_year ),
 
	OCL_SVAR( OC_UINT16, Industry, counter ),
 
	OCL_SVAR(  OC_UINT8, Industry, was_cargo_delivered ),
 

	
 
	OCL_NULL( 9 ), ///< Random junk at the end of this chunk
 

	
 
	OCL_END()
 
};
 

	
 
static bool LoadOldIndustry(LoadgameState *ls, int num)
 
{
 
	Industry *i = new (num) Industry();
 
	if (!LoadChunk(ls, i, industry_chunk)) return false;
 

	
 
	if (i->xy != 0) {
 
		i->town = GetTown(REMAP_TOWN_IDX(_old_town_index));
 
		IncIndustryTypeCount(i->type);
 
	} else {
 
		i->xy = INVALID_TILE;
 
	}
 

	
 
	return true;
 
}
 

	
 
static CompanyID _current_company_id;
 
static int32 _old_yearly;
 

	
 
static const OldChunks _company_yearly_chunk[] = {
 
	OCL_VAR(  OC_INT32,   1, &_old_yearly ),
 
	OCL_END()
 
};
 

	
 
static bool OldCompanyYearly(LoadgameState *ls, int num)
 
{
 
	int i;
 
	Company *c = GetCompany(_current_company_id);
 

	
 
	for (i = 0; i < 13; i++) {
 
		if (!LoadChunk(ls, NULL, _company_yearly_chunk)) return false;
 

	
 
		c->yearly_expenses[num][i] = _old_yearly;
 
	}
 

	
 
	return true;
 
}
 

	
 
static const OldChunks _company_economy_chunk[] = {
 
	OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, CompanyEconomyEntry, income ),
 
	OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, CompanyEconomyEntry, expenses ),
 
	OCL_SVAR( OC_INT32,                 CompanyEconomyEntry, delivered_cargo ),
 
	OCL_SVAR( OC_INT32,                 CompanyEconomyEntry, performance_history ),
 
	OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, CompanyEconomyEntry, company_value ),
 

	
 
	OCL_END()
 
};
 

	
 
static bool OldCompanyEconomy(LoadgameState *ls, int num)
 
{
 
	int i;
 
	Company *c = GetCompany(_current_company_id);
 

	
 
	if (!LoadChunk(ls, &c->cur_economy, _company_economy_chunk)) return false;
 

	
 
	/* Don't ask, but the number in TTD(Patch) are inversed to OpenTTD */
 
	c->cur_economy.income   = -c->cur_economy.income;
 
	c->cur_economy.expenses = -c->cur_economy.expenses;
 

	
 
	for (i = 0; i < 24; i++) {
 
		if (!LoadChunk(ls, &c->old_economy[i], _company_economy_chunk)) return false;
 

	
 
		c->old_economy[i].income   = -c->old_economy[i].income;
 
		c->old_economy[i].expenses = -c->old_economy[i].expenses;
 
	}
 

	
 
	return true;
 
}
 

	
 
static const OldChunks _company_ai_build_rec_chunk[] = {
 
	OCL_SVAR(   OC_TILE, AiBuildRec, spec_tile ),
 
	OCL_SVAR(   OC_TILE, AiBuildRec, use_tile ),
 
	OCL_SVAR(  OC_UINT8, AiBuildRec, rand_rng ),
 
	OCL_SVAR(  OC_UINT8, AiBuildRec, cur_building_rule ),
 
	OCL_SVAR(  OC_UINT8, AiBuildRec, unk6 ),
 
	OCL_SVAR(  OC_UINT8, AiBuildRec, unk7 ),
 
	OCL_SVAR(  OC_UINT8, AiBuildRec, buildcmd_a ),
 
	OCL_SVAR(  OC_UINT8, AiBuildRec, buildcmd_b ),
 
	OCL_SVAR(  OC_UINT8, AiBuildRec, direction ),
 
	OCL_SVAR(  OC_UINT8, AiBuildRec, cargo ),
 

	
 
	OCL_NULL( 8 ),  ///< Junk...
 

	
 
	OCL_END()
 
};
 

	
 
static bool OldLoadAIBuildRec(LoadgameState *ls, int num)
 
{
 
	Company *c = GetCompany(_current_company_id);
 

	
 
	switch (num) {
 
		case 0: return LoadChunk(ls, &_companies_ai[c->index].src,  _company_ai_build_rec_chunk);
 
		case 1: return LoadChunk(ls, &_companies_ai[c->index].dst,  _company_ai_build_rec_chunk);
 
		case 2: return LoadChunk(ls, &_companies_ai[c->index].mid1, _company_ai_build_rec_chunk);
 
		case 3: return LoadChunk(ls, &_companies_ai[c->index].mid2, _company_ai_build_rec_chunk);
 
	}
 

	
 
	return false;
 
}
 
static const OldChunks _company_ai_chunk[] = {
 
	OCL_SVAR(  OC_UINT8, CompanyAI, state ),
 
	OCL_NULL( 1 ),         ///< Junk
 
	OCL_SVAR(  OC_UINT8, CompanyAI, state_mode ),
 
	OCL_SVAR( OC_UINT16, CompanyAI, state_counter ),
 
	OCL_SVAR( OC_UINT16, CompanyAI, timeout_counter ),
 

	
 
	OCL_CHUNK( 4, OldLoadAIBuildRec ),
 

	
 
	OCL_NULL( 20 ),        ///< More junk
 

	
 
	OCL_SVAR(  OC_UINT8, CompanyAI, cargo_type ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, num_wagons ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, build_kind ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, num_build_rec ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, num_loco_to_build ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, num_want_fullload ),
 

	
 
	OCL_NULL( 14 ),        ///< Oh no more junk :|
 

	
 
	OCL_NULL( 2 ),         ///< Loco-id, not used
 

	
 
	OCL_SVAR( OC_UINT16, CompanyAI, wagon_list[0] ),
 
	OCL_SVAR( OC_UINT16, CompanyAI, wagon_list[1] ),
 
	OCL_SVAR( OC_UINT16, CompanyAI, wagon_list[2] ),
 
	OCL_SVAR( OC_UINT16, CompanyAI, wagon_list[3] ),
 
	OCL_SVAR( OC_UINT16, CompanyAI, wagon_list[4] ),
 
	OCL_SVAR( OC_UINT16, CompanyAI, wagon_list[5] ),
 
	OCL_SVAR( OC_UINT16, CompanyAI, wagon_list[6] ),
 
	OCL_SVAR( OC_UINT16, CompanyAI, wagon_list[7] ),
 
	OCL_SVAR( OC_UINT16, CompanyAI, wagon_list[8] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[0] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[1] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[2] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[3] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[4] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[5] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[6] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[7] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[8] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[9] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[10] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[11] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[12] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[13] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[14] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[15] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[16] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[17] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[18] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, order_list_blocks[19] ),
 

	
 
	OCL_SVAR( OC_UINT16, CompanyAI, start_tile_a ),
 
	OCL_SVAR( OC_UINT16, CompanyAI, start_tile_b ),
 
	OCL_SVAR( OC_UINT16, CompanyAI, cur_tile_a ),
 
	OCL_SVAR( OC_UINT16, CompanyAI, cur_tile_b ),
 

	
 
	OCL_SVAR(  OC_UINT8, CompanyAI, start_dir_a ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, start_dir_b ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, cur_dir_a ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, cur_dir_b ),
 

	
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_tile_count ),
 

	
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[0] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[0] ),
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[1] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[1] ),
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[2] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[2] ),
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[3] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[3] ),
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[4] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[4] ),
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[5] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[5] ),
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[6] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[6] ),
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[7] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[7] ),
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[8] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[8] ),
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[9] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[9] ),
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[10] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[10] ),
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[11] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[11] ),
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[12] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[12] ),
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[13] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[13] ),
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[14] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[14] ),
 
	OCL_SVAR(   OC_TILE, CompanyAI, banned_tiles[15] ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, banned_val[15] ),
 

	
 
	OCL_SVAR(  OC_UINT8, CompanyAI, railtype_to_use ),
 
	OCL_SVAR(  OC_UINT8, CompanyAI, route_type_mask ),
 

	
 
	OCL_END()
 
};
 

	
 
static bool OldCompanyAI(LoadgameState *ls, int num)
 
{
 
	return LoadChunk(ls, &_companies_ai[_current_company_id], _company_ai_chunk);
 
}
 

	
 
uint8 ai_tick;
 
static const OldChunks _company_chunk[] = {
 
	OCL_VAR ( OC_UINT16,   1, &_old_string_id ),
 
	OCL_SVAR( OC_UINT32, Company, name_2 ),
 
	OCL_SVAR( OC_UINT32, Company, face ),
 
	OCL_VAR ( OC_UINT16,   1, &_old_string_id_2 ),
 
	OCL_SVAR( OC_UINT32, Company, president_name_2 ),
 

	
 
	OCL_SVAR(  OC_INT32, Company, money ),
 
	OCL_SVAR(  OC_INT32, Company, current_loan ),
 

	
 
	OCL_SVAR(  OC_UINT8, Company, colour ),
 
	OCL_SVAR(  OC_UINT8, Company, money_fraction ),
 
	OCL_SVAR(  OC_UINT8, Company, quarters_of_bankrupcy ),
 
	OCL_SVAR(  OC_UINT8, Company, bankrupt_asked ),
 
	OCL_SVAR( OC_FILE_U32 | OC_VAR_I64, Company, bankrupt_value ),
 
	OCL_SVAR( OC_UINT16, Company, bankrupt_timeout ),
 

	
 
	OCL_SVAR( OC_UINT32, Company, cargo_types ),
 

	
 
	OCL_CHUNK( 3, OldCompanyYearly ),
 
	OCL_CHUNK( 1, OldCompanyEconomy ),
 

	
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Company, inaugurated_year),
 
	OCL_SVAR(                  OC_TILE, Company, last_build_coordinate ),
 
	OCL_SVAR(                 OC_UINT8, Company, num_valid_stat_ent ),
 

	
 
	OCL_CHUNK( 1, OldCompanyAI ),
 

	
 
	OCL_SVAR(  OC_UINT8, Company, block_preview ),
 
	 OCL_VAR(  OC_UINT8,   1, &ai_tick ),
 
	OCL_SVAR(  OC_UINT8, Company, avail_railtypes ),
 
	OCL_SVAR(   OC_TILE, Company, location_of_HQ ),
 
	OCL_SVAR(  OC_UINT8, Company, share_owners[0] ),
 
	OCL_SVAR(  OC_UINT8, Company, share_owners[1] ),
 
	OCL_SVAR(  OC_UINT8, Company, share_owners[2] ),
 
	OCL_SVAR(  OC_UINT8, Company, share_owners[3] ),
 

	
 
	OCL_NULL( 8 ), ///< junk at end of chunk
 

	
 
	OCL_END()
 
};
 

	
 
static bool LoadOldCompany(LoadgameState *ls, int num)
 
{
 
	Company *c = new (num) Company();
 

	
 
	_current_company_id = (CompanyID)num;
 

	
 
	if (!LoadChunk(ls, c, _company_chunk)) return false;
 

	
 
	if (_old_string_id == 0) {
 
		delete c;
 
		return true;
 
	}
 

	
 
	c->name_1 = RemapOldStringID(_old_string_id);
 
	c->president_name_1 = RemapOldStringID(_old_string_id_2);
 
	_companies_ai[_current_company_id].tick = ai_tick;
 

	
 
	if (num == 0) {
 
		/* If the first company has no name, make sure we call it UNNAMED */
 
		if (c->name_1 == 0)
 
			c->name_1 = STR_SV_UNNAMED;
 
	} else {
 
		/* Beside some multiplayer maps (1 on 1), which we don't official support,
 
		 * all other companys are an AI.. mark them as such */
 
		c->is_ai = true;
 
	}
 

	
 
	/* Sometimes it is better to not ask.. in old scenarios, the money
 
	 * was always 893288 pounds. In the newer versions this is correct,
 
	 * but correct for those oldies
 
	 * Ps: this also means that if you had exact 893288 pounds, you will go back
 
	 * to 100000.. this is a very VERY small chance ;) */
 
	if (c->money == 893288) c->money = c->current_loan = 100000;
 

	
 
	_company_colours[num] = c->colour;
 
	c->inaugurated_year -= ORIGINAL_BASE_YEAR;
 

	
 
	/* State 20 for AI companies is sell vehicle. Since the AI struct is not
 
	 * really figured out as of now, _companies_ai[c->index].cur_veh; needed for 'sell vehicle'
 
	 * is NULL and the function will crash. To fix this, just change the state
 
	 * to some harmless state, like 'loop vehicle'; 1 */
 
	if (!IsHumanCompany((CompanyID)num) && _companies_ai[c->index].state == 20) _companies_ai[c->index].state = 1;
 

	
 
	if (c->is_ai && (!_networking || _network_server) && _ai.enabled)
 
		AI_StartNewAI(c->index);
 

	
 
	return true;
 
}
 

	
 
static uint32 _old_order_ptr;
 
static uint16 _old_next_ptr;
 
static uint32 _current_vehicle_id;
 

	
 
static const OldChunks vehicle_train_chunk[] = {
 
	OCL_SVAR(  OC_UINT8, VehicleRail, track ),
 
	OCL_SVAR(  OC_UINT8, VehicleRail, force_proceed ),
 
	OCL_SVAR( OC_UINT16, VehicleRail, crash_anim_pos ),
 
	OCL_SVAR(  OC_UINT8, VehicleRail, railtype ),
 

	
 
	OCL_NULL( 5 ), ///< Junk
 

	
 
	OCL_END()
 
};
 

	
 
static const OldChunks vehicle_road_chunk[] = {
 
	OCL_SVAR(  OC_UINT8, VehicleRoad, state ),
 
	OCL_SVAR(  OC_UINT8, VehicleRoad, frame ),
 
	OCL_SVAR( OC_UINT16, VehicleRoad, blocked_ctr ),
 
	OCL_SVAR(  OC_UINT8, VehicleRoad, overtaking ),
 
	OCL_SVAR(  OC_UINT8, VehicleRoad, overtaking_ctr ),
 
	OCL_SVAR( OC_UINT16, VehicleRoad, crashed_ctr ),
 
	OCL_SVAR(  OC_UINT8, VehicleRoad, reverse_ctr ),
 

	
 
	OCL_NULL( 1 ), ///< Junk
 

	
 
	OCL_END()
 
};
 

	
 
static const OldChunks vehicle_ship_chunk[] = {
 
	OCL_SVAR(  OC_UINT8, VehicleShip, state ),
 

	
 
	OCL_NULL( 9 ), ///< Junk
 

	
 
	OCL_END()
 
};
 

	
 
static const OldChunks vehicle_air_chunk[] = {
 
	OCL_SVAR(  OC_UINT8, VehicleAir, pos ),
 
	OCL_SVAR(  OC_FILE_U8 | OC_VAR_U16, VehicleAir, targetairport ),
 
	OCL_SVAR( OC_UINT16, VehicleAir, crashed_counter ),
 
	OCL_SVAR(  OC_UINT8, VehicleAir, state ),
 

	
 
	OCL_NULL( 5 ), ///< Junk
 

	
 
	OCL_END()
 
};
 

	
 
static const OldChunks vehicle_effect_chunk[] = {
 
	OCL_SVAR( OC_UINT16, VehicleEffect, animation_state ),
 
	OCL_SVAR(  OC_UINT8, VehicleEffect, animation_substate ),
 

	
 
	OCL_NULL( 7 ), // Junk
 

	
 
	OCL_END()
 
};
 

	
 
static const OldChunks vehicle_disaster_chunk[] = {
 
	OCL_SVAR( OC_UINT16, VehicleDisaster, image_override ),
 
	OCL_SVAR( OC_UINT16, VehicleDisaster, big_ufo_destroyer_target ),
 

	
 
	OCL_NULL( 6 ), ///< Junk
 

	
 
	OCL_END()
 
};
 

	
 
static const OldChunks vehicle_empty_chunk[] = {
 
	OCL_NULL( 10 ), ///< Junk
 

	
 
	OCL_END()
 
};
 

	
 
static bool LoadOldVehicleUnion(LoadgameState *ls, int num)
 
{
 
	Vehicle *v = GetVehicle(_current_vehicle_id);
 
	uint temp = ls->total_read;
 
	bool res;
 

	
 
	switch (v->type) {
 
		default: NOT_REACHED();
 
		case VEH_INVALID : res = LoadChunk(ls, NULL,           vehicle_empty_chunk);    break;
 
		case VEH_TRAIN   : res = LoadChunk(ls, &v->u.rail,     vehicle_train_chunk);    break;
 
		case VEH_ROAD    : res = LoadChunk(ls, &v->u.road,     vehicle_road_chunk);     break;
 
		case VEH_SHIP    : res = LoadChunk(ls, &v->u.ship,     vehicle_ship_chunk);     break;
 
		case VEH_AIRCRAFT: res = LoadChunk(ls, &v->u.air,      vehicle_air_chunk);      break;
 
		case VEH_EFFECT  : res = LoadChunk(ls, &v->u.effect,   vehicle_effect_chunk);   break;
 
		case VEH_DISASTER: res = LoadChunk(ls, &v->u.disaster, vehicle_disaster_chunk); break;
 
	}
 

	
 
	/* This chunk size should always be 10 bytes */
 
	if (ls->total_read - temp != 10) {
 
		DEBUG(oldloader, 0, "Assert failed in VehicleUnion: invalid chunk size");
 
		return false;
 
	}
 

	
 
	return res;
 
}
 

	
 
static uint16 _cargo_count;
 

	
 
static const OldChunks vehicle_chunk[] = {
 
	OCL_SVAR(  OC_UINT8, Vehicle, subtype ),
 

	
 
	OCL_NULL( 2 ),         ///< Hash, calculated automatically
 
	OCL_NULL( 2 ),         ///< Index, calculated automatically
 

	
 
	OCL_VAR ( OC_UINT32,   1, &_old_order_ptr ),
 
	OCL_VAR ( OC_UINT16,   1, &_old_order ),
 

	
 
	OCL_NULL ( 1 ), ///< num_orders, now calculated
 
	OCL_SVAR(  OC_UINT8, Vehicle, cur_order_index ),
 
	OCL_SVAR(   OC_TILE, Vehicle, dest_tile ),
 
	OCL_SVAR( OC_UINT16, Vehicle, load_unload_time_rem ),
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, date_of_last_service ),
 
	OCL_SVAR( OC_UINT16, Vehicle, service_interval ),
 
	OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, last_station_visited ),
 
	OCL_SVAR(  OC_UINT8, Vehicle, tick_counter ),
 
	OCL_SVAR( OC_UINT16, Vehicle, max_speed ),
 

	
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, x_pos ),
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, y_pos ),
 
	OCL_SVAR(  OC_UINT8, Vehicle, z_pos ),
 
	OCL_SVAR(  OC_UINT8, Vehicle, direction ),
 
	OCL_NULL( 2 ),         ///< x_offs and y_offs, calculated automatically
 
	OCL_NULL( 2 ),         ///< x_extent and y_extent, calculated automatically
 
	OCL_NULL( 1 ),         ///< z_extent, calculated automatically
 

	
 
	OCL_SVAR(  OC_UINT8, Vehicle, owner ),
 
	OCL_SVAR(   OC_TILE, Vehicle, tile ),
 
	OCL_SVAR( OC_UINT16, Vehicle, cur_image ),
 

	
 
	OCL_NULL( 8 ),        ///< Vehicle sprite box, calculated automatically
 

	
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, Vehicle, vehstatus ),
 
	OCL_SVAR( OC_UINT16, Vehicle, cur_speed ),
 
	OCL_SVAR(  OC_UINT8, Vehicle, subspeed ),
 
	OCL_SVAR(  OC_UINT8, Vehicle, acceleration ),
 
	OCL_SVAR(  OC_UINT8, Vehicle, progress ),
 

	
 
	OCL_SVAR(  OC_UINT8, Vehicle, cargo_type ),
 
	OCL_SVAR( OC_UINT16, Vehicle, cargo_cap ),
 
	OCL_VAR ( OC_UINT16, 1,       &_cargo_count ),
 
	OCL_VAR (  OC_UINT8, 1,       &_cargo_source ),
 
	OCL_VAR (  OC_UINT8, 1,       &_cargo_days ),
 

	
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, age ),
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, max_age ),
 
	OCL_SVAR( OC_FILE_U8 | OC_VAR_I32, Vehicle, build_year ),
 
	OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, unitnumber ),
 

	
 
	OCL_SVAR( OC_UINT16, Vehicle, engine_type ),
 

	
 
	OCL_SVAR(  OC_UINT8, Vehicle, spritenum ),
 
	OCL_SVAR(  OC_UINT8, Vehicle, day_counter ),
 

	
 
	OCL_SVAR(  OC_UINT8, Vehicle, breakdowns_since_last_service ),
 
	OCL_SVAR(  OC_UINT8, Vehicle, breakdown_ctr ),
 
	OCL_SVAR(  OC_UINT8, Vehicle, breakdown_delay ),
 
	OCL_SVAR(  OC_UINT8, Vehicle, breakdown_chance ),
 

	
 
	OCL_SVAR( OC_UINT16, Vehicle, reliability ),
 
	OCL_SVAR( OC_UINT16, Vehicle, reliability_spd_dec ),
 

	
 
	OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, Vehicle, profit_this_year ),
 
	OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, Vehicle, profit_last_year ),
 

	
 
	OCL_VAR ( OC_UINT16,   1, &_old_next_ptr ),
 

	
 
	OCL_SVAR( OC_UINT32, Vehicle, value ),
 

	
 
	OCL_VAR ( OC_UINT16,   1, &_old_string_id ),
 

	
 
	OCL_CHUNK( 1, LoadOldVehicleUnion ),
 

	
 
	OCL_NULL( 20 ), ///< Junk at end of struct (TTDPatch has some data in it)
 

	
 
	OCL_END()
 
};
 

	
 
bool LoadOldVehicle(LoadgameState *ls, int num)
 
{
 
	uint i;
 

	
 
	/* Read the TTDPatch flags, because we need some info from it */
 
	ReadTTDPatchFlags();
 

	
 
	for (i = 0; i < _old_vehicle_multiplier; i++) {
 
		_current_vehicle_id = num * _old_vehicle_multiplier + i;
 

	
 
		/* Read the vehicle type and allocate the right vehicle */
 
		Vehicle *v;
 
		switch (ReadByte(ls)) {
 
			default: NOT_REACHED();
 
			case 0x00 /*VEH_INVALID */: v = new (_current_vehicle_id) InvalidVehicle();  break;
 
			case 0x10 /*VEH_TRAIN   */: v = new (_current_vehicle_id) Train();           break;
 
			case 0x11 /*VEH_ROAD    */: v = new (_current_vehicle_id) RoadVehicle();     break;
 
			case 0x12 /*VEH_SHIP    */: v = new (_current_vehicle_id) Ship();            break;
 
			case 0x13 /*VEH_AIRCRAFT*/: v = new (_current_vehicle_id) Aircraft();        break;
 
			case 0x14 /*VEH_EFFECT  */: v = new (_current_vehicle_id) EffectVehicle();   break;
 
			case 0x15 /*VEH_DISASTER*/: v = new (_current_vehicle_id) DisasterVehicle(); break;
 
		}
 
		if (!LoadChunk(ls, v, vehicle_chunk)) return false;
 

	
 
		/* This should be consistent, else we have a big problem... */
 
		if (v->index != _current_vehicle_id) {
 
			DEBUG(oldloader, 0, "Loading failed - vehicle-array is invalid");
 
			return false;
 
		}
 

	
 
		if (_old_order_ptr != 0 && _old_order_ptr != 0xFFFFFFFF) {
 
			uint old_id = REMAP_ORDER_IDX(_old_order_ptr);
 
			/* There is a maximum of 5000 orders in old savegames, so *if*
 
			 * we go over that limit something is very wrong. In that case
 
			 * we just assume there are no orders for the vehicle.
 
			 */
 
			if (old_id < 5000) v->orders.old = GetOrder(old_id);
 
		}
 
		v->current_order.AssignOrder(UnpackOldOrder(_old_order));
 

	
 
		/* For some reason we need to correct for this */
 
		switch (v->spritenum) {
 
			case 0xfd: break;
 
			case 0xff: v->spritenum = 0xfe; break;
 
			default:   v->spritenum >>= 1; break;
 
		}
 

	
 
		if (_old_next_ptr != 0xFFFF) v->next = GetVehiclePoolSize() <= _old_next_ptr ? new (_old_next_ptr) InvalidVehicle() : GetVehicle(_old_next_ptr);
 

	
 
		_old_vehicle_names[_current_vehicle_id] = RemapOldStringID(_old_string_id);
 
		v->name = NULL;
 

	
 
		/* Vehicle-subtype is different in TTD(Patch) */
 
		if (v->type == VEH_EFFECT) v->subtype = v->subtype >> 1;
 

	
 
		if (_cargo_count != 0) {
 
			CargoPacket *cp = new CargoPacket((_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source, _cargo_count);
 
			cp->days_in_transit = _cargo_days;
 
			v->cargo.Append(cp);
 
		}
 
	}
 

	
 
	return true;
 
}
 

	
 
static const OldChunks sign_chunk[] = {
 
	OCL_VAR ( OC_UINT16, 1, &_old_string_id ),
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Sign, x ),
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Sign, y ),
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_I8, Sign, z ),
 

	
 
	OCL_NULL( 6 ),         ///< Width of sign, no longer in use
 

	
 
	OCL_END()
 
};
 

	
 
static bool LoadOldSign(LoadgameState *ls, int num)
 
{
 
	Sign *si = new (num) Sign();
 
	if (!LoadChunk(ls, si, sign_chunk)) return false;
 

	
 
	_old_string_id = RemapOldStringID(_old_string_id);
 
	si->name = CopyFromOldName(_old_string_id);
 

	
 
	return true;
 
}
 

	
 
static const OldChunks engine_chunk[] = {
 
	OCL_SVAR( OC_UINT16, Engine, company_avail ),
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Engine, intro_date ),
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Engine, age ),
 
	OCL_SVAR( OC_UINT16, Engine, reliability ),
 
	OCL_SVAR( OC_UINT16, Engine, reliability_spd_dec ),
 
	OCL_SVAR( OC_UINT16, Engine, reliability_start ),
 
	OCL_SVAR( OC_UINT16, Engine, reliability_max ),
 
	OCL_SVAR( OC_UINT16, Engine, reliability_final ),
 
	OCL_SVAR( OC_UINT16, Engine, duration_phase_1 ),
 
	OCL_SVAR( OC_UINT16, Engine, duration_phase_2 ),
 
	OCL_SVAR( OC_UINT16, Engine, duration_phase_3 ),
 

	
 
	OCL_SVAR(  OC_UINT8, Engine, lifelength ),
 
	OCL_SVAR(  OC_UINT8, Engine, flags ),
 
	OCL_SVAR(  OC_UINT8, Engine, preview_company_rank ),
 
	OCL_SVAR(  OC_UINT8, Engine, preview_wait ),
 

	
 
	OCL_NULL( 2 ), ///< Junk
 

	
 
	OCL_END()
 
};
 

	
 
static bool LoadOldEngine(LoadgameState *ls, int num)
 
{
 
	Engine *e = GetTempDataEngine(num);
 
	return LoadChunk(ls, e, engine_chunk);
 
}
 

	
 
static bool LoadOldEngineName(LoadgameState *ls, int num)
 
{
 
	Engine *e = GetTempDataEngine(num);
 
	e->name = CopyFromOldName(RemapOldStringID(ReadUint16(ls)));
 
	return true;
 
}
 

	
 
static const OldChunks subsidy_chunk[] = {
 
	OCL_SVAR(  OC_UINT8, Subsidy, cargo_type ),
 
	OCL_SVAR(  OC_UINT8, Subsidy, age ),
 
	OCL_SVAR(  OC_FILE_U8 | OC_VAR_U16, Subsidy, from ),
 
	OCL_SVAR(  OC_FILE_U8 | OC_VAR_U16, Subsidy, to ),
 

	
 
	OCL_END()
 
};
 

	
 
static inline bool LoadOldSubsidy(LoadgameState *ls, int num)
 
{
 
	return LoadChunk(ls, &_subsidies[num], subsidy_chunk);
 
}
 

	
 
static const OldChunks game_difficulty_chunk[] = {
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, max_no_competitors ),
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, competitor_start_time ),
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, number_towns ),
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, number_industries ),
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, DifficultySettings, max_loan ),
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, initial_interest ),
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, vehicle_costs ),
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, competitor_speed ),
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, competitor_intelligence ),
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, vehicle_breakdowns ),
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, subsidy_multiplier ),
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, construction_cost ),
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, terrain_type ),
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, quantity_sea_lakes ),
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, economy ),
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, line_reverse_mode ),
 
	OCL_SVAR( OC_FILE_U16 |  OC_VAR_U8, DifficultySettings, disasters ),
 
	OCL_END()
 
};
 

	
 
static inline bool LoadOldGameDifficulty(LoadgameState *ls, int num)
 
{
 
	bool ret = LoadChunk(ls, &_settings_game.difficulty, game_difficulty_chunk);
 
	_settings_game.difficulty.max_loan *= 1000;
 
	return ret;
 
}
 

	
 

	
 
static bool LoadOldMapPart1(LoadgameState *ls, int num)
 
{
 
	uint i;
 

	
 
	for (i = 0; i < OLD_MAP_SIZE; i++) {
 
		_m[i].m1 = ReadByte(ls);
 
	}
 
	for (i = 0; i < OLD_MAP_SIZE; i++) {
 
		_m[i].m2 = ReadByte(ls);
 
	}
 
	for (i = 0; i < OLD_MAP_SIZE; i++) {
 
		_old_map3[i * 2] = ReadByte(ls);
 
		_old_map3[i * 2 + 1] = ReadByte(ls);
 
	}
 
	for (i = 0; i < OLD_MAP_SIZE / 4; i++) {
 
		byte b = ReadByte(ls);
 
		_m[i * 4 + 0].m6 = GB(b, 0, 2);
 
		_m[i * 4 + 1].m6 = GB(b, 2, 2);
 
		_m[i * 4 + 2].m6 = GB(b, 4, 2);
 
		_m[i * 4 + 3].m6 = GB(b, 6, 2);
 
	}
 

	
 
	return !ls->failed;
 
}
 

	
 
static bool LoadOldMapPart2(LoadgameState *ls, int num)
 
{
 
	uint i;
 

	
 
	for (i = 0; i < OLD_MAP_SIZE; i++) {
 
		_m[i].type_height = ReadByte(ls);
 
	}
 
	for (i = 0; i < OLD_MAP_SIZE; i++) {
 
		_m[i].m5 = ReadByte(ls);
 
	}
 

	
 
	return !ls->failed;
 
}
 

	
 
static bool LoadTTDPatchExtraChunks(LoadgameState *ls, int num)
 
{
 
	ReadTTDPatchFlags();
 

	
 
	DEBUG(oldloader, 2, "Found %d extra chunk(s)", _old_extra_chunk_nums);
 

	
 
	for (int i = 0; i != _old_extra_chunk_nums; i++) {
 
		uint16 id = ReadUint16(ls);
 
		uint32 len = ReadUint32(ls);
 

	
 
		switch (id) {
 
			/* List of GRFIDs, used in the savegame. 0x8004 is the new ID
 
			 * They are saved in a 'GRFID:4 active:1' format, 5 bytes for each entry */
 
			case 0x2:
 
			case 0x8004: {
 
				/* Skip the first element: TTDP hack for the Action D special variables (FFFF0000 01) */
 
				ReadUint32(ls); ReadByte(ls); len -= 5;
 

	
 
				ClearGRFConfigList(&_grfconfig);
 
				while (len != 0) {
 
					uint32 grfid = ReadUint32(ls);
 

	
 
					if (ReadByte(ls) == 1) {
 
						GRFConfig *c = CallocT<GRFConfig>(1);
 
						c->grfid = grfid;
 
						c->filename = strdup("TTDP game, no information");
 

	
 
						AppendToGRFConfigList(&_grfconfig, c);
 
						DEBUG(oldloader, 3, "TTDPatch game using GRF file with GRFID %0X", BSWAP32(c->grfid));
 
					}
 
					len -= 5;
 
				};
 

	
 
				/* Append static NewGRF configuration */
 
				AppendStaticGRFConfigs(&_grfconfig);
 
			} break;
 

	
 
			/* TTDPatch version and configuration */
 
			case 0x3:
 
				_ttdp_version = ReadUint32(ls);
 
				DEBUG(oldloader, 3, "Game saved with TTDPatch version %d.%d.%d r%d",
 
					GB(_ttdp_version, 24, 8), GB(_ttdp_version, 20, 4), GB(_ttdp_version, 16, 4), GB(_ttdp_version, 0, 16));
 
				len -= 4;
 
				while (len-- != 0) ReadByte(ls); // skip the configuration
 
				break;
 

	
 
			default:
 
				DEBUG(oldloader, 4, "Skipping unknown extra chunk %X", id);
 
				while (len-- != 0) ReadByte(ls);
 
				break;
 
		}
 
	}
 

	
 
	return !ls->failed;
 
}
 

	
 
extern TileIndex _cur_tileloop_tile;
 
static uint32 _old_cur_town_ctr;
 
static const OldChunks main_chunk[] = {
 
	OCL_ASSERT( 0 ),
 
	OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_date ),
 
	OCL_VAR ( OC_UINT16,   1, &_date_fract ),
 
	OCL_NULL( 600 ),            ///< TextEffects
 
	OCL_VAR ( OC_UINT32,   2, &_random.state ),
 

	
 
	OCL_ASSERT( 0x264 ),
 
	OCL_CHUNK(  70, LoadOldTown ),
 
	OCL_ASSERT( 0x1C18 ),
 
	OCL_CHUNK(5000, LoadOldOrder ),
 
	OCL_ASSERT( 0x4328 ),
 

	
 
	OCL_CHUNK( 1, LoadOldAnimTileList ),
 
	OCL_NULL( 4 ),              ///< old end-of-order-list-pointer, no longer in use
 

	
 
	OCL_CHUNK( 255, LoadOldDepot ),
 
	OCL_ASSERT( 0x4B26 ),
 

	
 
	OCL_VAR ( OC_UINT32,   1, &_old_cur_town_ctr ),
 
	OCL_NULL( 2 ),              ///< timer_counter, no longer in use
 
	OCL_NULL( 2 ),              ///< land_code,     no longer in use
 

	
 
	OCL_VAR ( OC_FILE_U16 | OC_VAR_U8, 1, &_age_cargo_skip_counter ),
 
	OCL_VAR ( OC_UINT16,   1, &_tick_counter ),
 
	OCL_VAR (   OC_TILE,   1, &_cur_tileloop_tile ),
 

	
 
	OCL_CHUNK( 49, LoadOldPrice ),
 
	OCL_CHUNK( 12, LoadOldCargoPaymentRate ),
 

	
 
	OCL_ASSERT( 0x4CBA ),
 

	
 
	OCL_CHUNK( 1, LoadOldMapPart1 ),
 

	
 
	OCL_ASSERT( 0x48CBA ),
 

	
 
	OCL_CHUNK(250, LoadOldStation ),
 
	OCL_CHUNK( 90, LoadOldIndustry ),
 
	OCL_CHUNK(  8, LoadOldCompany ),
 

	
 
	OCL_ASSERT( 0x547F2 ),
 

	
 
	OCL_CHUNK( 850, LoadOldVehicle ),
 

	
 
	OCL_ASSERT( 0x6F0F2 ),
 

	
 
	OCL_VAR (  OC_UINT8 | OC_DEREFERENCE_POINTER, 32 * 500, &_old_name_array ),
 

	
 
	OCL_NULL( 0x2000 ),            ///< Old hash-table, no longer in use
 

	
 
	OCL_CHUNK( 40, LoadOldSign ),
 
	OCL_CHUNK(256, LoadOldEngine ),
 

	
 
	OCL_VAR ( OC_UINT16,    1, &_vehicle_id_ctr_day ),
 

	
 
	OCL_CHUNK(  8, LoadOldSubsidy ),
 

	
 
	OCL_VAR ( OC_FILE_U16 | OC_VAR_U32,   1, &_next_competitor_start ),
 
	OCL_VAR ( OC_FILE_I16 | OC_VAR_I32,   1, &_saved_scrollpos_x ),
 
	OCL_VAR ( OC_FILE_I16 | OC_VAR_I32,   1, &_saved_scrollpos_y ),
 
	OCL_VAR ( OC_FILE_U16 | OC_VAR_U8,    1, &_saved_scrollpos_zoom ),
 

	
 
	OCL_VAR ( OC_FILE_U32 | OC_VAR_I64,   1, &_economy.max_loan ),
 
	OCL_VAR ( OC_FILE_U32 | OC_VAR_I64,   1, &_economy.max_loan_unround ),
 
	OCL_VAR (  OC_INT16,    1, &_economy.fluct ),
 

	
 
	OCL_VAR ( OC_UINT16,    1, &_disaster_delay ),
 

	
 
	OCL_NULL( 144 ),             ///< cargo-stuff, calculated in InitializeLandscapeVariables
 

	
 
	OCL_CHUNK(256, LoadOldEngineName ),
 

	
 
	OCL_NULL( 144 ),             ///< AI cargo-stuff, calculated in InitializeLandscapeVariables
 
	OCL_NULL( 2 ),               ///< Company indexes of companies, no longer in use
 

	
 
	OCL_VAR ( OC_FILE_U8 | OC_VAR_U16,    1, &_station_tick_ctr ),
 

	
 
	OCL_VAR (  OC_UINT8,    1, &_settings_game.locale.currency ),
 
	OCL_VAR (  OC_UINT8,    1, &_settings_game.locale.units ),
 
	OCL_VAR ( OC_FILE_U8 | OC_VAR_U32,    1, &_cur_company_tick_index ),
 

	
 
	OCL_NULL( 2 ),               ///< Date stuff, calculated automatically
 
	OCL_NULL( 8 ),               ///< Company colors, calculated automatically
 

	
 
	OCL_VAR (  OC_UINT8,    1, &_economy.infl_amount ),
 
	OCL_VAR (  OC_UINT8,    1, &_economy.infl_amount_pr ),
 
	OCL_VAR (  OC_UINT8,    1, &_economy.interest_rate ),
 
	OCL_NULL( 1 ), // available airports
 
	OCL_VAR (  OC_UINT8,    1, &_settings_game.vehicle.road_side ),
 
	OCL_VAR (  OC_UINT8,    1, &_settings_game.game_creation.town_name ),
 

	
 
	OCL_CHUNK( 1, LoadOldGameDifficulty ),
 

	
 
	OCL_ASSERT( 0x77130 ),
 

	
 
	OCL_VAR (  OC_UINT8,    1, &_settings_game.difficulty.diff_level ),
 
	OCL_VAR (  OC_UINT8,    1, &_settings_game.game_creation.landscape ),
 
	OCL_VAR (  OC_UINT8,    1, &_trees_tick_ctr ),
 

	
 
	OCL_NULL( 1 ),               ///< Custom vehicle types yes/no, no longer used
 
	OCL_VAR (  OC_UINT8,    1, &_settings_game.game_creation.snow_line ),
 

	
 
	OCL_NULL( 32 ),              ///< new_industry_randtable, no longer used (because of new design)
 
	OCL_NULL( 36 ),              ///< cargo-stuff, calculated in InitializeLandscapeVariables
 

	
 
	OCL_ASSERT( 0x77179 ),
 

	
 
	OCL_CHUNK( 1, LoadOldMapPart2 ),
 

	
 
	OCL_ASSERT( 0x97179 ),
 

	
 
	/* Below any (if available) extra chunks from TTDPatch can follow */
 
	OCL_CHUNK(1, LoadTTDPatchExtraChunks),
 

	
 
	OCL_END()
 
};
 

	
 
static bool LoadOldMain(LoadgameState *ls)
 
{
 
	int i;
 

	
 
	/* The first 49 is the name of the game + checksum, skip it */
 
	fseek(ls->file, HEADER_SIZE, SEEK_SET);
 

	
 
	DEBUG(oldloader, 3, "Reading main chunk...");
 
	/* Load the biggest chunk */
 
	_old_map3 = MallocT<byte>(OLD_MAP_SIZE * 2);
 
	_old_vehicle_names = NULL;
 
	if (!LoadChunk(ls, NULL, main_chunk)) {
 
		DEBUG(oldloader, 0, "Loading failed");
 
		free(_old_map3);
 
		free(_old_vehicle_names);
 
		return false;
 
	}
 
	DEBUG(oldloader, 3, "Done, converting game data...");
 

	
 
	/* Fix some general stuff */
 
	_settings_game.game_creation.landscape = _settings_game.game_creation.landscape & 0xF;
 

	
 
	/* Remap some pointers */
 
	_cur_town_ctr      = REMAP_TOWN_IDX(_old_cur_town_ctr);
 

	
 
	/* _old_map3 is changed in _map3_lo and _map3_hi */
 
	for (i = 0; i < OLD_MAP_SIZE; i++) {
 
		_m[i].m3 = _old_map3[i * 2];
 
		_m[i].m4 = _old_map3[i * 2 + 1];
 
	}
 

	
 
	for (i = 0; i < OLD_MAP_SIZE; i ++) {
 
		switch (GetTileType(i)) {
 
			case MP_STATION:
 
				_m[i].m4 = 0; // We do not understand this TTDP station mapping (yet)
 
				switch (_m[i].m5) {
 
					/* We have drive through stops at a totally different place */
 
					case 0x53: case 0x54: _m[i].m5 += 170 - 0x53; break; // Bus drive through
 
					case 0x57: case 0x58: _m[i].m5 += 168 - 0x57; break; // Truck drive through
 
					case 0x55: case 0x56: _m[i].m5 += 170 - 0x55; break; // Bus tram stop
 
					case 0x59: case 0x5A: _m[i].m5 += 168 - 0x59; break; // Truck tram stop
 
					default: break;
 
				}
 
				break;
 

	
 
			case MP_RAILWAY:
 
				/* We save presignals different from TTDPatch, convert them */
 
				if (GetRailTileType(i) == RAIL_TILE_SIGNALS) {
 
					/* This byte is always zero in TTD for this type of tile */
 
					if (_m[i].m4) /* Convert the presignals to our own format */
 
						_m[i].m4 = (_m[i].m4 >> 1) & 7;
 
				}
 
				/* TTDPatch stores PBS things in L6 and all elsewhere; so we'll just
 
				 * clear it for ourselves and let OTTD's rebuild PBS itself */
 
				_m[i].m4 &= 0xF; /* Only keep the lower four bits; upper four is PBS */
 
				break;
 

	
 
			case MP_WATER:
 
				if (GetWaterClass(i) == 3) MakeRiver(i, Random());
 
				break;
 

	
 
			default:
 
				break;
 
		}
 
	}
 

	
 
	/* Make sure the available engines are really available, otherwise
 
	 * we will get a "new vehicle"-spree. */
 
	Engine *e;
 
	FOR_ALL_ENGINES(e) {
 
		if (_date >= (e->intro_date + 365)) {
 
			e->flags = (e->flags & ~ENGINE_EXCLUSIVE_PREVIEW) | ENGINE_AVAILABLE;
 
			e->company_avail = (CompanyMask)-1;
 
		}
 
	}
 

	
 
	/* Fix the game to be compatible with OpenTTD */
 
	FixOldTowns();
 
	FixOldVehicles();
 

	
 
	/* We have a new difficulty setting */
 
	_settings_game.difficulty.town_council_tolerance = Clamp(_settings_game.difficulty.diff_level, 0, 2);
 

	
 
	DEBUG(oldloader, 3, "Finished converting game data");
 
	DEBUG(oldloader, 1, "TTD(Patch) savegame successfully converted");
 

	
 
	free(_old_map3);
 
	free(_old_vehicle_names);
 

	
 
	return true;
 
}
 

	
 
bool LoadOldSaveGame(const char *file)
 
{
 
	LoadgameState ls;
 

	
 
	DEBUG(oldloader, 3, "Trying to load a TTD(Patch) savegame");
 

	
 
	InitLoading(&ls);
 

	
 
	/* Open file */
 
	ls.file = fopen(file, "rb");
 

	
 
	if (ls.file == NULL) {
 
		DEBUG(oldloader, 0, "Cannot open file '%s'", file);
 
		return false;
 
	}
 

	
 
	/* Load the main chunk */
 
	if (!LoadOldMain(&ls)) return false;
 

	
 
	fclose(ls.file);
 

	
 
	/* Some old TTD(Patch) savegames could have buoys at tile 0
 
	 * (without assigned station struct)
 
	 * MakeWater() can be used as long as sea has the same
 
	 * format as old savegames (eg. everything is zeroed) */
 
	MakeWater(0);
 

	
 
	_pause_game = 2;
 

	
 
	return true;
 
}
 

	
 
void GetOldSaveGameName(char *title, const char *path, const char *file)
 
{
 
	char filename[MAX_PATH];
 
	FILE *f;
 

	
 
	snprintf(filename, lengthof(filename), "%s" PATHSEP "%s", path, file);
 
	f = fopen(filename, "rb");
 
	title[0] = '\0';
 
	title[48] = '\0';
 

	
 
	if (f == NULL) return;
 

	
 
	if (fread(title, 1, 48, f) != 48) snprintf(title, 48, "Corrupt file");
 

	
 
	fclose(f);
 
}
src/saveload/order_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file order_sl.cpp Code handling saving and loading of orders */
 

	
 
#include "../stdafx.h"
 
#include "../order_base.h"
 
#include "../core/alloc_func.hpp"
 
#include "../settings_type.h"
 

	
 
#include "saveload.h"
 

	
 
void Order::ConvertFromOldSavegame()
 
{
 
	uint8 old_flags = this->flags;
 
	this->flags = 0;
 

	
 
	/* First handle non-stop */
 
	if (_settings_client.gui.sg_new_nonstop) {
 
		/* OFB_NON_STOP */
 
		this->SetNonStopType((old_flags & 8) ? ONSF_NO_STOP_AT_ANY_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS);
 
	} else {
 
		this->SetNonStopType((old_flags & 8) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE);
 
	}
 

	
 
	switch (this->GetType()) {
 
		/* Only a few types need the other savegame conversions. */
 
		case OT_GOTO_DEPOT: case OT_GOTO_STATION: case OT_LOADING: break;
 
		default: return;
 
	}
 

	
 
	if (this->GetType() != OT_GOTO_DEPOT) {
 
		/* Then the load flags */
 
		if ((old_flags & 2) != 0) { // OFB_UNLOAD
 
			this->SetLoadType(OLFB_NO_LOAD);
 
		} else if ((old_flags & 4) == 0) { // !OFB_FULL_LOAD
 
			this->SetLoadType(OLF_LOAD_IF_POSSIBLE);
 
		} else {
 
			this->SetLoadType(_settings_client.gui.sg_full_load_any ? OLF_FULL_LOAD_ANY : OLFB_FULL_LOAD);
 
		}
 

	
 
		/* Finally fix the unload flags */
 
		if ((old_flags & 1) != 0) { // OFB_TRANSFER
 
			this->SetUnloadType(OUFB_TRANSFER);
 
		} else if ((old_flags & 2) != 0) { // OFB_UNLOAD
 
			this->SetUnloadType(OUFB_UNLOAD);
 
		} else {
 
			this->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE);
 
		}
 
	} else {
 
		/* Then the depot action flags */
 
		this->SetDepotActionType(((old_flags & 6) == 4) ? ODATFB_HALT : ODATF_SERVICE_ONLY);
 

	
 
		/* Finally fix the depot type flags */
 
		uint t = ((old_flags & 6) == 6) ? ODTFB_SERVICE : ODTF_MANUAL;
 
		if ((old_flags & 2) != 0) t |= ODTFB_PART_OF_ORDERS;
 
		this->SetDepotOrderType((OrderDepotTypeFlags)t);
 
	}
 
}
 

	
 
/** Unpacks a order from savegames with version 4 and lower
 
 * @param packed packed order
 
 * @return unpacked order
 
 */
 
static Order UnpackVersion4Order(uint16 packed)
 
{
 
	return Order(GB(packed, 8, 8) << 16 | GB(packed, 4, 4) << 8 | GB(packed, 0, 4));
 
}
 

	
 
/** Unpacks a order from savegames made with TTD(Patch)
 
 * @param packed packed order
 
 * @return unpacked order
 
 */
 
Order UnpackOldOrder(uint16 packed)
 
{
 
	Order order = UnpackVersion4Order(packed);
 

	
 
	/*
 
	 * Sanity check
 
	 * TTD stores invalid orders as OT_NOTHING with non-zero flags/station
 
	 */
 
	if (!order.IsValid() && packed != 0) order.MakeDummy();
 

	
 
	return order;
 
}
 

	
 
const SaveLoad *GetOrderDescription()
 
{
 
	static const SaveLoad _order_desc[] = {
 
		     SLE_VAR(Order, type,           SLE_UINT8),
 
		     SLE_VAR(Order, flags,          SLE_UINT8),
 
		     SLE_VAR(Order, dest,           SLE_UINT16),
 
		     SLE_REF(Order, next,           REF_ORDER),
 
		 SLE_CONDVAR(Order, refit_cargo,    SLE_UINT8,   36, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Order, refit_subtype,  SLE_UINT8,   36, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Order, wait_time,      SLE_UINT16,  67, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Order, travel_time,    SLE_UINT16,  67, SL_MAX_VERSION),
 

	
 
		/* Leftover from the minor savegame version stuff
 
		 * We will never use those free bytes, but we have to keep this line to allow loading of old savegames */
 
		SLE_CONDNULL(10,                                  5,  35),
 
		     SLE_END()
 
	};
 

	
 
	return _order_desc;
 
}
 

	
 
static void Save_ORDR()
 
{
 
	Order *order;
 

	
 
	FOR_ALL_ORDERS(order) {
 
		SlSetArrayIndex(order->index);
 
		SlObject(order, GetOrderDescription());
 
	}
 
}
 

	
 
static void Load_ORDR()
 
{
 
	if (CheckSavegameVersionOldStyle(5, 2)) {
 
		/* Version older than 5.2 did not have a ->next pointer. Convert them
 
		    (in the old days, the orderlist was 5000 items big) */
 
		size_t len = SlGetFieldLength();
 
		uint i;
 

	
 
		if (CheckSavegameVersion(5)) {
 
			/* Pre-version 5 had an other layout for orders
 
			    (uint16 instead of uint32) */
 
			len /= sizeof(uint16);
 
			uint16 *orders = MallocT<uint16>(len + 1);
 

	
 
			SlArray(orders, len, SLE_UINT16);
 

	
 
			for (i = 0; i < len; ++i) {
 
				Order *order = new (i) Order();
 
				order->AssignOrder(UnpackVersion4Order(orders[i]));
 
			}
 

	
 
			free(orders);
 
		} else if (CheckSavegameVersionOldStyle(5, 2)) {
 
			len /= sizeof(uint16);
 
			uint16 *orders = MallocT<uint16>(len + 1);
 

	
 
			SlArray(orders, len, SLE_UINT32);
 

	
 
			for (i = 0; i < len; ++i) {
 
				new (i) Order(orders[i]);
 
			}
 

	
 
			free(orders);
 
		}
 

	
 
		/* Update all the next pointer */
 
		for (i = 1; i < len; ++i) {
 
			/* The orders were built like this:
 
			 *   While the order is valid, set the previous will get it's next pointer set
 
			 *   We start with index 1 because no order will have the first in it's next pointer */
 
			if (GetOrder(i)->IsValid())
 
				GetOrder(i - 1)->next = GetOrder(i);
 
		}
 
	} else {
 
		int index;
 

	
 
		while ((index = SlIterateArray()) != -1) {
 
			Order *order = new (index) Order();
 
			SlObject(order, GetOrderDescription());
 
		}
 
	}
 
}
 

	
 
const SaveLoad *GetOrderListDescription()
 
{
 
	static const SaveLoad _orderlist_desc[] = {
 
		SLE_REF(OrderList, first,              REF_ORDER),
 
		SLE_END()
 
	};
 

	
 
	return _orderlist_desc;
 
}
 

	
 
static void Save_ORDL()
 
{
 
	OrderList *list;
 

	
 
	FOR_ALL_ORDER_LISTS(list) {
 
		SlSetArrayIndex(list->index);
 
		SlObject(list, GetOrderListDescription());
 
	}
 
}
 

	
 
static void Load_ORDL()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		OrderList *list = new (index) OrderList();
 
		SlObject(list, GetOrderListDescription());
 
	}
 
}
 

	
 
extern const ChunkHandler _order_chunk_handlers[] = {
 
	{ 'ORDR', Save_ORDR, Load_ORDR, CH_ARRAY},
 
	{ 'ORDL', Save_ORDL, Load_ORDL, CH_ARRAY | CH_LAST},
 
};
src/saveload/saveload.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file saveload.cpp
 
 * All actions handling saving and loading goes on in this file. The general actions
 
 * are as follows for saving a game (loading is analogous):
 
 * <ol>
 
 * <li>initialize the writer by creating a temporary memory-buffer for it
 
 * <li>go through all to-be saved elements, each 'chunk' (ChunkHandler) prefixed by a label
 
 * <li>use their description array (SaveLoad) to know what elements to save and in what version
 
 *    of the game it was active (used when loading)
 
 * <li>write all data byte-by-byte to the temporary buffer so it is endian-safe
 
 * <li>when the buffer is full; flush it to the output (eg save to file) (_sl.buf, _sl.bufp, _sl.bufe)
 
 * <li>repeat this until everything is done, and flush any remaining output to file
 
 * </ol>
 
 */
 
#include "../stdafx.h"
 
#include "../openttd.h"
 
#include "../debug.h"
 
#include "../station_base.h"
 
#include "../thread.h"
 
#include "../town.h"
 
#include "../network/network.h"
 
#include "../variables.h"
 
#include "../window_func.h"
 
#include "../strings_func.h"
 
#include "../gfx_func.h"
 
#include "../core/alloc_func.hpp"
 
#include "../functions.h"
 
#include "../core/endian_func.hpp"
 
#include "../vehicle_base.h"
 
#include "../company_func.h"
 
#include "../date_func.h"
 
#include "../autoreplace_base.h"
 
#include "../statusbar_gui.h"
 
#include "../fileio_func.h"
 
#include "../gamelog.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "saveload.h"
 
#include "saveload_internal.h"
 

	
 
#include <list>
 

	
 
extern const uint16 SAVEGAME_VERSION = 105;
 

	
 
SavegameType _savegame_type; ///< type of savegame we are loading
 

	
 
uint32 _ttdp_version;     ///< version of TTDP savegame (if applicable)
 
uint16 _sl_version;       ///< the major savegame version identifier
 
byte   _sl_minor_version; ///< the minor savegame version, DO NOT USE!
 

	
 
typedef void WriterProc(size_t len);
 
typedef size_t ReaderProc();
 

	
 
/** The saveload struct, containing reader-writer functions, bufffer, version, etc. */
 
static struct {
 
	bool save;                           ///< are we doing a save or a load atm. True when saving
 
	byte need_length;                    ///< ???
 
	byte block_mode;                     ///< ???
 
	bool error;                          ///< did an error occur or not
 

	
 
	size_t obj_len;                      ///< the length of the current object we are busy with
 
	int array_index, last_array_index;   ///< in the case of an array, the current and last positions
 

	
 
	size_t offs_base;                    ///< the offset in number of bytes since we started writing data (eg uncompressed savegame size)
 

	
 
	WriterProc *write_bytes;             ///< savegame writer function
 
	ReaderProc *read_bytes;              ///< savegame loader function
 

	
 
	const ChunkHandler* const *chs;      ///< the chunk of data that is being processed atm (vehicles, signs, etc.)
 

	
 
	/* When saving/loading savegames, they are always saved to a temporary memory-place
 
	 * to be flushed to file (save) or to final place (load) when full. */
 
	byte *bufp, *bufe;                   ///< bufp(ointer) gives the current position in the buffer bufe(nd) gives the end of the buffer
 

	
 
	/* these 3 may be used by compressor/decompressors. */
 
	byte *buf;                           ///< pointer to temporary memory to read/write, initialized by SaveLoadFormat->initread/write
 
	byte *buf_ori;                       ///< pointer to the original memory location of buf, used to free it afterwards
 
	uint bufsize;                        ///< the size of the temporary memory *buf
 
	FILE *fh;                            ///< the file from which is read or written to
 

	
 
	void (*excpt_uninit)();              ///< the function to execute on any encountered error
 
	StringID error_str;                  ///< the translateable error message to show
 
	char *extra_msg;                     ///< the error message
 
} _sl;
 

	
 

	
 
enum NeedLengthValues {NL_NONE = 0, NL_WANTLENGTH = 1, NL_CALCLENGTH = 2};
 

	
 
/** Error handler, calls longjmp to simulate an exception.
 
 * @todo this was used to have a central place to handle errors, but it is
 
 * pretty ugly, and seriously interferes with any multithreaded approaches */
 
static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
 
{
 
	_sl.error_str = string;
 
	free(_sl.extra_msg);
 
	_sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
 
	throw std::exception();
 
}
 

	
 
typedef void (*AsyncSaveFinishProc)();
 
static AsyncSaveFinishProc _async_save_finish = NULL;
 
static ThreadObject *_save_thread;
 

	
 
/**
 
 * Called by save thread to tell we finished saving.
 
 */
 
static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
 
{
 
	if (_exit_game) return;
 
	while (_async_save_finish != NULL) CSleep(10);
 

	
 
	_async_save_finish = proc;
 
}
 

	
 
/**
 
 * Handle async save finishes.
 
 */
 
void ProcessAsyncSaveFinish()
 
{
 
	if (_async_save_finish == NULL) return;
 

	
 
	_async_save_finish();
 

	
 
	_async_save_finish = NULL;
 

	
 
	if (_save_thread != NULL) {
 
		_save_thread->Join();
 
		delete _save_thread;
 
		_save_thread = NULL;
 
	}
 
}
 

	
 
/**
 
 * Fill the input buffer by reading from the file with the given reader
 
 */
 
static void SlReadFill()
 
{
 
	size_t len = _sl.read_bytes();
 
	if (len == 0) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected end of chunk");
 

	
 
	_sl.bufp = _sl.buf;
 
	_sl.bufe = _sl.buf + len;
 
	_sl.offs_base += len;
 
}
 

	
 
static inline size_t SlGetOffs() {return _sl.offs_base - (_sl.bufe - _sl.bufp);}
 

	
 
/** Return the size in bytes of a certain type of normal/atomic variable
 
 * as it appears in memory. See VarTypes
 
 * @param conv VarType type of variable that is used for calculating the size
 
 * @return Return the size of this type in bytes */
 
static inline byte SlCalcConvMemLen(VarType conv)
 
{
 
	static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
 
	byte length = GB(conv, 4, 4);
 
	assert(length < lengthof(conv_mem_size));
 
	return conv_mem_size[length];
 
}
 

	
 
/** Return the size in bytes of a certain type of normal/atomic variable
 
 * as it appears in a saved game. See VarTypes
 
 * @param conv VarType type of variable that is used for calculating the size
 
 * @return Return the size of this type in bytes */
 
static inline byte SlCalcConvFileLen(VarType conv)
 
{
 
	static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
 
	byte length = GB(conv, 0, 4);
 
	assert(length < lengthof(conv_file_size));
 
	return conv_file_size[length];
 
}
 

	
 
/** Return the size in bytes of a reference (pointer) */
 
static inline size_t SlCalcRefLen() {return CheckSavegameVersion(69) ? 2 : 4;}
 

	
 
/** Flush the output buffer by writing to disk with the given reader.
 
 * If the buffer pointer has not yet been set up, set it up now. Usually
 
 * only called when the buffer is full, or there is no more data to be processed
 
 */
 
static void SlWriteFill()
 
{
 
	/* flush the buffer to disk (the writer) */
 
	if (_sl.bufp != NULL) {
 
		uint len = _sl.bufp - _sl.buf;
 
		_sl.offs_base += len;
 
		if (len) _sl.write_bytes(len);
 
	}
 

	
 
	/* All the data from the buffer has been written away, rewind to the beginning
 
	 * to start reading in more data */
 
	_sl.bufp = _sl.buf;
 
	_sl.bufe = _sl.buf + _sl.bufsize;
 
}
 

	
 
/** Read in a single byte from file. If the temporary buffer is full,
 
 * flush it to its final destination
 
 * @return return the read byte from file
 
 */
 
static inline byte SlReadByteInternal()
 
{
 
	if (_sl.bufp == _sl.bufe) SlReadFill();
 
	return *_sl.bufp++;
 
}
 

	
 
/** Wrapper for SlReadByteInternal */
 
byte SlReadByte() {return SlReadByteInternal();}
 

	
 
/** Write away a single byte from memory. If the temporary buffer is full,
 
 * flush it to its destination (file)
 
 * @param b the byte that is currently written
 
 */
 
static inline void SlWriteByteInternal(byte b)
 
{
 
	if (_sl.bufp == _sl.bufe) SlWriteFill();
 
	*_sl.bufp++ = b;
 
}
 

	
 
/** Wrapper for SlWriteByteInternal */
 
void SlWriteByte(byte b) {SlWriteByteInternal(b);}
 

	
 
static inline int SlReadUint16()
 
{
 
	int x = SlReadByte() << 8;
 
	return x | SlReadByte();
 
}
 

	
 
static inline uint32 SlReadUint32()
 
{
 
	uint32 x = SlReadUint16() << 16;
 
	return x | SlReadUint16();
 
}
 

	
 
static inline uint64 SlReadUint64()
 
{
 
	uint32 x = SlReadUint32();
 
	uint32 y = SlReadUint32();
 
	return (uint64)x << 32 | y;
 
}
 

	
 
static inline void SlWriteUint16(uint16 v)
 
{
 
	SlWriteByte(GB(v, 8, 8));
 
	SlWriteByte(GB(v, 0, 8));
 
}
 

	
 
static inline void SlWriteUint32(uint32 v)
 
{
 
	SlWriteUint16(GB(v, 16, 16));
 
	SlWriteUint16(GB(v,  0, 16));
 
}
 

	
 
static inline void SlWriteUint64(uint64 x)
 
{
 
	SlWriteUint32((uint32)(x >> 32));
 
	SlWriteUint32((uint32)x);
 
}
 

	
 
/**
 
 * Read in the header descriptor of an object or an array.
 
 * If the highest bit is set (7), then the index is bigger than 127
 
 * elements, so use the next byte to read in the real value.
 
 * The actual value is then both bytes added with the first shifted
 
 * 8 bits to the left, and dropping the highest bit (which only indicated a big index).
 
 * x = ((x & 0x7F) << 8) + SlReadByte();
 
 * @return Return the value of the index
 
 */
 
static uint SlReadSimpleGamma()
 
{
 
	uint i = SlReadByte();
 
	if (HasBit(i, 7)) {
 
		i &= ~0x80;
 
		if (HasBit(i, 6)) {
 
			i &= ~0x40;
 
			if (HasBit(i, 5)) {
 
				i &= ~0x20;
 
				if (HasBit(i, 4))
 
					SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unsupported gamma");
 
				i = (i << 8) | SlReadByte();
 
			}
 
			i = (i << 8) | SlReadByte();
 
		}
 
		i = (i << 8) | SlReadByte();
 
	}
 
	return i;
 
}
 

	
 
/**
 
 * Write the header descriptor of an object or an array.
 
 * If the element is bigger than 127, use 2 bytes for saving
 
 * and use the highest byte of the first written one as a notice
 
 * that the length consists of 2 bytes, etc.. like this:
 
 * 0xxxxxxx
 
 * 10xxxxxx xxxxxxxx
 
 * 110xxxxx xxxxxxxx xxxxxxxx
 
 * 1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx
 
 * @param i Index being written
 
 */
 

	
 
static void SlWriteSimpleGamma(size_t i)
 
{
 
	if (i >= (1 << 7)) {
 
		if (i >= (1 << 14)) {
 
			if (i >= (1 << 21)) {
 
				assert(i < (1 << 28));
 
				SlWriteByte((byte)(0xE0 | (i >> 24)));
 
				SlWriteByte((byte)(i >> 16));
 
			} else {
 
				SlWriteByte((byte)(0xC0 | (i >> 16)));
 
			}
 
			SlWriteByte((byte)(i >> 8));
 
		} else {
 
			SlWriteByte((byte)(0x80 | (i >> 8)));
 
		}
 
	}
 
	SlWriteByte((byte)i);
 
}
 

	
 
/** Return how many bytes used to encode a gamma value */
 
static inline uint SlGetGammaLength(size_t i)
 
{
 
	return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
 
}
 

	
 
static inline uint SlReadSparseIndex() {return SlReadSimpleGamma();}
 
static inline void SlWriteSparseIndex(uint index) {SlWriteSimpleGamma(index);}
 

	
 
static inline uint SlReadArrayLength() {return SlReadSimpleGamma();}
 
static inline void SlWriteArrayLength(size_t length) {SlWriteSimpleGamma(length);}
 
static inline uint SlGetArrayLength(size_t length) {return SlGetGammaLength(length);}
 

	
 
void SlSetArrayIndex(uint index)
 
{
 
	_sl.need_length = NL_WANTLENGTH;
 
	_sl.array_index = index;
 
}
 

	
 
static size_t _next_offs;
 

	
 
/**
 
 * Iterate through the elements of an array and read the whole thing
 
 * @return The index of the object, or -1 if we have reached the end of current block
 
 */
 
int SlIterateArray()
 
{
 
	int index;
 

	
 
	/* After reading in the whole array inside the loop
 
	 * we must have read in all the data, so we must be at end of current block. */
 
	if (_next_offs != 0 && SlGetOffs() != _next_offs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
 

	
 
	while (true) {
 
		uint length = SlReadArrayLength();
 
		if (length == 0) {
 
			_next_offs = 0;
 
			return -1;
 
		}
 

	
 
		_sl.obj_len = --length;
 
		_next_offs = SlGetOffs() + length;
 

	
 
		switch (_sl.block_mode) {
 
		case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
 
		case CH_ARRAY:        index = _sl.array_index++; break;
 
		default:
 
			DEBUG(sl, 0, "SlIterateArray error");
 
			return -1; // error
 
		}
 

	
 
		if (length != 0) return index;
 
	}
 
}
 

	
 
/**
 
 * Sets the length of either a RIFF object or the number of items in an array.
 
 * This lets us load an object or an array of arbitrary size
 
 * @param length The length of the sought object/array
 
 */
 
void SlSetLength(size_t length)
 
{
 
	assert(_sl.save);
 

	
 
	switch (_sl.need_length) {
 
	case NL_WANTLENGTH:
 
		_sl.need_length = NL_NONE;
 
		switch (_sl.block_mode) {
 
		case CH_RIFF:
 
			/* Ugly encoding of >16M RIFF chunks
 
			 * The lower 24 bits are normal
 
			 * The uppermost 4 bits are bits 24:27 */
 
			assert(length < (1 << 28));
 
			SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
 
			break;
 
		case CH_ARRAY:
 
			assert(_sl.last_array_index <= _sl.array_index);
 
			while (++_sl.last_array_index <= _sl.array_index)
 
				SlWriteArrayLength(1);
 
			SlWriteArrayLength(length + 1);
 
			break;
 
		case CH_SPARSE_ARRAY:
 
			SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index)); // Also include length of sparse index.
 
			SlWriteSparseIndex(_sl.array_index);
 
			break;
 
		default: NOT_REACHED();
 
		} break;
 
	case NL_CALCLENGTH:
 
		_sl.obj_len += (int)length;
 
		break;
 
	}
 
}
 

	
 
/**
 
 * Save/Load bytes. These do not need to be converted to Little/Big Endian
 
 * so directly write them or read them to/from file
 
 * @param ptr The source or destination of the object being manipulated
 
 * @param length number of bytes this fast CopyBytes lasts
 
 */
 
static void SlCopyBytes(void *ptr, size_t length)
 
{
 
	byte *p = (byte*)ptr;
 

	
 
	if (_sl.save) {
 
		for (; length != 0; length--) {SlWriteByteInternal(*p++);}
 
	} else {
 
		for (; length != 0; length--) {*p++ = SlReadByteInternal();}
 
	}
 
}
 

	
 
/** Read in bytes from the file/data structure but don't do
 
 * anything with them, discarding them in effect
 
 * @param length The amount of bytes that is being treated this way
 
 */
 
static inline void SlSkipBytes(size_t length)
 
{
 
	for (; length != 0; length--) SlReadByte();
 
}
 

	
 
/* Get the length of the current object */
 
size_t SlGetFieldLength() {return _sl.obj_len;}
 

	
 
/** Return a signed-long version of the value of a setting
 
 * @param ptr pointer to the variable
 
 * @param conv type of variable, can be a non-clean
 
 * type, eg one with other flags because it is parsed
 
 * @return returns the value of the pointer-setting */
 
int64 ReadValue(const void *ptr, VarType conv)
 
{
 
	switch (GetVarMemType(conv)) {
 
	case SLE_VAR_BL:  return (*(bool*)ptr != 0);
 
	case SLE_VAR_I8:  return *(int8*  )ptr;
 
	case SLE_VAR_U8:  return *(byte*  )ptr;
 
	case SLE_VAR_I16: return *(int16* )ptr;
 
	case SLE_VAR_U16: return *(uint16*)ptr;
 
	case SLE_VAR_I32: return *(int32* )ptr;
 
	case SLE_VAR_U32: return *(uint32*)ptr;
 
	case SLE_VAR_I64: return *(int64* )ptr;
 
	case SLE_VAR_U64: return *(uint64*)ptr;
 
	case SLE_VAR_NULL:return 0;
 
	default: NOT_REACHED();
 
	}
 

	
 
	/* useless, but avoids compiler warning this way */
 
	return 0;
 
}
 

	
 
/** Write the value of a setting
 
 * @param ptr pointer to the variable
 
 * @param conv type of variable, can be a non-clean type, eg
 
 *             with other flags. It is parsed upon read
 
 * @param val the new value being given to the variable */
 
void WriteValue(void *ptr, VarType conv, int64 val)
 
{
 
	switch (GetVarMemType(conv)) {
 
	case SLE_VAR_BL:  *(bool  *)ptr = (val != 0);  break;
 
	case SLE_VAR_I8:  *(int8  *)ptr = val; break;
 
	case SLE_VAR_U8:  *(byte  *)ptr = val; break;
 
	case SLE_VAR_I16: *(int16 *)ptr = val; break;
 
	case SLE_VAR_U16: *(uint16*)ptr = val; break;
 
	case SLE_VAR_I32: *(int32 *)ptr = val; break;
 
	case SLE_VAR_U32: *(uint32*)ptr = val; break;
 
	case SLE_VAR_I64: *(int64 *)ptr = val; break;
 
	case SLE_VAR_U64: *(uint64*)ptr = val; break;
 
	case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
 
	case SLE_VAR_NULL: break;
 
	default: NOT_REACHED();
 
	}
 
}
 

	
 
/**
 
 * Handle all conversion and typechecking of variables here.
 
 * In the case of saving, read in the actual value from the struct
 
 * and then write them to file, endian safely. Loading a value
 
 * goes exactly the opposite way
 
 * @param ptr The object being filled/read
 
 * @param conv VarType type of the current element of the struct
 
 */
 
static void SlSaveLoadConv(void *ptr, VarType conv)
 
{
 
	int64 x = 0;
 

	
 
	if (_sl.save) { // SAVE values
 
		/* Read a value from the struct. These ARE endian safe. */
 
		x = ReadValue(ptr, conv);
 

	
 
		/* Write the value to the file and check if its value is in the desired range */
 
		switch (GetVarFileType(conv)) {
 
		case SLE_FILE_I8: assert(x >= -128 && x <= 127);     SlWriteByte(x);break;
 
		case SLE_FILE_U8: assert(x >= 0 && x <= 255);        SlWriteByte(x);break;
 
		case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
 
		case SLE_FILE_STRINGID:
 
		case SLE_FILE_U16:assert(x >= 0 && x <= 65535);      SlWriteUint16(x);break;
 
		case SLE_FILE_I32:
 
		case SLE_FILE_U32:                                   SlWriteUint32((uint32)x);break;
 
		case SLE_FILE_I64:
 
		case SLE_FILE_U64:                                   SlWriteUint64(x);break;
 
		default: NOT_REACHED();
 
		}
 
	} else { // LOAD values
 

	
 
		/* Read a value from the file */
 
		switch (GetVarFileType(conv)) {
 
		case SLE_FILE_I8:  x = (int8  )SlReadByte();   break;
 
		case SLE_FILE_U8:  x = (byte  )SlReadByte();   break;
 
		case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
 
		case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
 
		case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
 
		case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
 
		case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
 
		case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
 
		case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
 
		default: NOT_REACHED();
 
		}
 

	
 
		/* Write The value to the struct. These ARE endian safe. */
 
		WriteValue(ptr, conv, x);
 
	}
 
}
 

	
 
/** Calculate the net length of a string. This is in almost all cases
 
 * just strlen(), but if the string is not properly terminated, we'll
 
 * resort to the maximum length of the buffer.
 
 * @param ptr pointer to the stringbuffer
 
 * @param length maximum length of the string (buffer). If -1 we don't care
 
 * about a maximum length, but take string length as it is.
 
 * @return return the net length of the string */
 
static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
 
{
 
	if (ptr == NULL) return 0;
 
	return min(strlen(ptr), length - 1);
 
}
 

	
 
/** Calculate the gross length of the string that it
 
 * will occupy in the savegame. This includes the real length, returned
 
 * by SlCalcNetStringLen and the length that the index will occupy.
 
 * @param ptr pointer to the stringbuffer
 
 * @param length maximum length of the string (buffer size, etc.)
 
 * @param conv type of data been used
 
 * @return return the gross length of the string */
 
static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
 
{
 
	size_t len;
 
	const char *str;
 

	
 
	switch (GetVarMemType(conv)) {
 
		default: NOT_REACHED();
 
		case SLE_VAR_STR:
 
		case SLE_VAR_STRQ:
 
			str = *(const char**)ptr;
 
			len = SIZE_MAX;
 
			break;
 
		case SLE_VAR_STRB:
 
		case SLE_VAR_STRBQ:
 
			str = (const char*)ptr;
 
			len = length;
 
			break;
 
	}
 

	
 
	len = SlCalcNetStringLen(str, len);
 
	return len + SlGetArrayLength(len); // also include the length of the index
 
}
 

	
 
/**
 
 * Save/Load a string.
 
 * @param ptr the string being manipulated
 
 * @param length of the string (full length)
 
 * @param conv must be SLE_FILE_STRING */
 
static void SlString(void *ptr, size_t length, VarType conv)
 
{
 
	size_t len;
 

	
 
	if (_sl.save) { // SAVE string
 
		switch (GetVarMemType(conv)) {
 
			default: NOT_REACHED();
 
			case SLE_VAR_STRB:
 
			case SLE_VAR_STRBQ:
 
				len = SlCalcNetStringLen((char*)ptr, length);
 
				break;
 
			case SLE_VAR_STR:
 
			case SLE_VAR_STRQ:
 
				ptr = *(char**)ptr;
 
				len = SlCalcNetStringLen((char*)ptr, SIZE_MAX);
 
				break;
 
		}
 

	
 
		SlWriteArrayLength(len);
 
		SlCopyBytes(ptr, len);
 
	} else { // LOAD string
 
		len = SlReadArrayLength();
 

	
 
		switch (GetVarMemType(conv)) {
 
			default: NOT_REACHED();
 
			case SLE_VAR_STRB:
 
			case SLE_VAR_STRBQ:
 
				if (len >= length) {
 
					DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
 
					SlCopyBytes(ptr, length);
 
					SlSkipBytes(len - length);
 
					len = length - 1;
 
				} else {
 
					SlCopyBytes(ptr, len);
 
				}
 
				break;
 
			case SLE_VAR_STR:
 
			case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate
 
				free(*(char**)ptr);
 
				if (len == 0) {
 
					*(char**)ptr = NULL;
 
				} else {
 
					*(char**)ptr = MallocT<char>(len + 1); // terminating '\0'
 
					ptr = *(char**)ptr;
 
					SlCopyBytes(ptr, len);
 
				}
 
				break;
 
		}
 

	
 
		((char*)ptr)[len] = '\0'; // properly terminate the string
 
	}
 
}
 

	
 
/**
 
 * Return the size in bytes of a certain type of atomic array
 
 * @param length The length of the array counted in elements
 
 * @param conv VarType type of the variable that is used in calculating the size
 
 */
 
static inline size_t SlCalcArrayLen(size_t length, VarType conv)
 
{
 
	return SlCalcConvFileLen(conv) * length;
 
}
 

	
 
/**
 
 * Save/Load an array.
 
 * @param array The array being manipulated
 
 * @param length The length of the array in elements
 
 * @param conv VarType type of the atomic array (int, byte, uint64, etc.)
 
 */
 
void SlArray(void *array, size_t length, VarType conv)
 
{
 
	/* Automatically calculate the length? */
 
	if (_sl.need_length != NL_NONE) {
 
		SlSetLength(SlCalcArrayLen(length, conv));
 
		/* Determine length only? */
 
		if (_sl.need_length == NL_CALCLENGTH) return;
 
	}
 

	
 
	/* NOTICE - handle some buggy stuff, in really old versions everything was saved
 
	 * as a byte-type. So detect this, and adjust array size accordingly */
 
	if (!_sl.save && _sl_version == 0) {
 
		/* all arrays except difficulty settings */
 
		if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
 
				conv == SLE_INT32 || conv == SLE_UINT32) {
 
			SlCopyBytes(array, length * SlCalcConvFileLen(conv));
 
			return;
 
		}
 
		/* used for conversion of Money 32bit->64bit */
 
		if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
 
			for (uint i = 0; i < length; i++) {
 
				((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
 
			}
 
			return;
 
		}
 
	}
 

	
 
	/* If the size of elements is 1 byte both in file and memory, no special
 
	 * conversion is needed, use specialized copy-copy function to speed up things */
 
	if (conv == SLE_INT8 || conv == SLE_UINT8) {
 
		SlCopyBytes(array, length);
 
	} else {
 
		byte *a = (byte*)array;
 
		byte mem_size = SlCalcConvMemLen(conv);
 

	
 
		for (; length != 0; length --) {
 
			SlSaveLoadConv(a, conv);
 
			a += mem_size; // get size
 
		}
 
	}
 
}
 

	
 

	
 
static uint ReferenceToInt(const void* obj, SLRefType rt);
 
static void* IntToReference(uint index, SLRefType rt);
 

	
 

	
 
/**
 
 * Return the size in bytes of a list
 
 * @param list The std::list to find the size of
 
 */
 
static inline size_t SlCalcListLen(const void *list)
 
{
 
	std::list<void *> *l = (std::list<void *> *) list;
 

	
 
	int type_size = CheckSavegameVersion(69) ? 2 : 4;
 
	/* Each entry is saved as type_size bytes, plus type_size bytes are used for the length
 
	 * of the list */
 
	return l->size() * type_size + type_size;
 
}
 

	
 

	
 
/**
 
 * Save/Load a list.
 
 * @param list The list being manipulated
 
 * @param conv SLRefType type of the list (Vehicle *, Station *, etc)
 
 */
 
void SlList(void *list, SLRefType conv)
 
{
 
	/* Automatically calculate the length? */
 
	if (_sl.need_length != NL_NONE) {
 
		SlSetLength(SlCalcListLen(list));
 
		/* Determine length only? */
 
		if (_sl.need_length == NL_CALCLENGTH) return;
 
	}
 

	
 
	std::list<void *> *l = (std::list<void *> *) list;
 

	
 
	if (_sl.save) {
 
		SlWriteUint32((uint32)l->size());
 

	
 
		std::list<void *>::iterator iter;
 
		for (iter = l->begin(); iter != l->end(); ++iter) {
 
			void *ptr = *iter;
 
			SlWriteUint32(ReferenceToInt(ptr, conv));
 
		}
 
	} else {
 
		uint length = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
 

	
 
		/* Load each reference and push to the end of the list */
 
		for (uint i = 0; i < length; i++) {
 
			void *ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), conv);
 
			l->push_back(ptr);
 
		}
 
	}
 
}
 

	
 

	
 
/** Are we going to save this object or not? */
 
static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
 
{
 
	if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
 
	if (sld->conv & SLF_SAVE_NO) return false;
 

	
 
	return true;
 
}
 

	
 
/** Are we going to load this variable when loading a savegame or not?
 
 * @note If the variable is skipped it is skipped in the savegame
 
 * bytestream itself as well, so there is no need to skip it somewhere else */
 
static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
 
{
 
	if ((sld->conv & SLF_NETWORK_NO) && !_sl.save && _networking && !_network_server) {
 
		SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
 
		return true;
 
	}
 

	
 
	return false;
 
}
 

	
 
/**
 
 * Calculate the size of an object.
 
 * @param object to be measured
 
 * @param sld The SaveLoad description of the object so we know how to manipulate it
 
 * @return size of given objetc
 
 */
 
size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
 
{
 
	size_t length = 0;
 

	
 
	/* Need to determine the length and write a length tag. */
 
	for (; sld->cmd != SL_END; sld++) {
 
		length += SlCalcObjMemberLength(object, sld);
 
	}
 
	return length;
 
}
 

	
 
size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
 
{
 
	assert(_sl.save);
 

	
 
	switch (sld->cmd) {
 
		case SL_VAR:
 
		case SL_REF:
 
		case SL_ARR:
 
		case SL_STR:
 
		case SL_LST:
 
			/* CONDITIONAL saveload types depend on the savegame version */
 
			if (!SlIsObjectValidInSavegame(sld)) break;
 

	
 
			switch (sld->cmd) {
 
			case SL_VAR: return SlCalcConvFileLen(sld->conv);
 
			case SL_REF: return SlCalcRefLen();
 
			case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
 
			case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
 
			case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
 
			default: NOT_REACHED();
 
			}
 
			break;
 
		case SL_WRITEBYTE: return 1; // a byte is logically of size 1
 
		case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
 
		default: NOT_REACHED();
 
	}
 
	return 0;
 
}
 

	
 

	
 
bool SlObjectMember(void *ptr, const SaveLoad *sld)
 
{
 
	VarType conv = GB(sld->conv, 0, 8);
 
	switch (sld->cmd) {
 
	case SL_VAR:
 
	case SL_REF:
 
	case SL_ARR:
 
	case SL_STR:
 
	case SL_LST:
 
		/* CONDITIONAL saveload types depend on the savegame version */
 
		if (!SlIsObjectValidInSavegame(sld)) return false;
 
		if (SlSkipVariableOnLoad(sld)) return false;
 

	
 
		switch (sld->cmd) {
 
		case SL_VAR: SlSaveLoadConv(ptr, conv); break;
 
		case SL_REF: // Reference variable, translate
 
			if (_sl.save) {
 
				SlWriteUint32(ReferenceToInt(*(void**)ptr, (SLRefType)conv));
 
			} else {
 
				*(void**)ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), (SLRefType)conv);
 
			}
 
			break;
 
		case SL_ARR: SlArray(ptr, sld->length, conv); break;
 
		case SL_STR: SlString(ptr, sld->length, conv); break;
 
		case SL_LST: SlList(ptr, (SLRefType)conv); break;
 
		default: NOT_REACHED();
 
		}
 
		break;
 

	
 
	/* SL_WRITEBYTE translates a value of a variable to another one upon
 
	 * saving or loading.
 
	 * XXX - variable renaming abuse
 
	 * game_value: the value of the variable ingame is abused by sld->version_from
 
	 * file_value: the value of the variable in the savegame is abused by sld->version_to */
 
	case SL_WRITEBYTE:
 
		if (_sl.save) {
 
			SlWriteByte(sld->version_to);
 
		} else {
 
			*(byte*)ptr = sld->version_from;
 
		}
 
		break;
 

	
 
	/* SL_VEH_INCLUDE loads common code for vehicles */
 
	case SL_VEH_INCLUDE:
 
		SlObject(ptr, GetVehicleDescription(VEH_END));
 
		break;
 
	default: NOT_REACHED();
 
	}
 
	return true;
 
}
 

	
 
/**
 
 * Main SaveLoad function.
 
 * @param object The object that is being saved or loaded
 
 * @param sld The SaveLoad description of the object so we know how to manipulate it
 
 */
 
void SlObject(void *object, const SaveLoad *sld)
 
{
 
	/* Automatically calculate the length? */
 
	if (_sl.need_length != NL_NONE) {
 
		SlSetLength(SlCalcObjLength(object, sld));
 
		if (_sl.need_length == NL_CALCLENGTH) return;
 
	}
 

	
 
	for (; sld->cmd != SL_END; sld++) {
 
		void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
 
		SlObjectMember(ptr, sld);
 
	}
 
}
 

	
 
/**
 
 * Save or Load (a list of) global variables
 
 * @param sldg The global variable that is being loaded or saved
 
 */
 
void SlGlobList(const SaveLoadGlobVarList *sldg)
 
{
 
	SlObject(NULL, (const SaveLoad*)sldg);
 
}
 

	
 
/**
 
 * Do something of which I have no idea what it is :P
 
 * @param proc The callback procedure that is called
 
 * @param arg The variable that will be used for the callback procedure
 
 */
 
void SlAutolength(AutolengthProc *proc, void *arg)
 
{
 
	size_t offs;
 

	
 
	assert(_sl.save);
 

	
 
	/* Tell it to calculate the length */
 
	_sl.need_length = NL_CALCLENGTH;
 
	_sl.obj_len = 0;
 
	proc(arg);
 

	
 
	/* Setup length */
 
	_sl.need_length = NL_WANTLENGTH;
 
	SlSetLength(_sl.obj_len);
 

	
 
	offs = SlGetOffs() + _sl.obj_len;
 

	
 
	/* And write the stuff */
 
	proc(arg);
 

	
 
	if (offs != SlGetOffs()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
 
}
 

	
 
/**
 
 * Load a chunk of data (eg vehicles, stations, etc.)
 
 * @param ch The chunkhandler that will be used for the operation
 
 */
 
static void SlLoadChunk(const ChunkHandler *ch)
 
{
 
	byte m = SlReadByte();
 
	size_t len;
 
	size_t endoffs;
 

	
 
	_sl.block_mode = m;
 
	_sl.obj_len = 0;
 

	
 
	switch (m) {
 
	case CH_ARRAY:
 
		_sl.array_index = 0;
 
		ch->load_proc();
 
		break;
 
	case CH_SPARSE_ARRAY:
 
		ch->load_proc();
 
		break;
 
	default:
 
		if ((m & 0xF) == CH_RIFF) {
 
			/* Read length */
 
			len = (SlReadByte() << 16) | ((m >> 4) << 24);
 
			len += SlReadUint16();
 
			_sl.obj_len = len;
 
			endoffs = SlGetOffs() + len;
 
			ch->load_proc();
 
			if (SlGetOffs() != endoffs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
 
		} else {
 
			SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk type");
 
		}
 
		break;
 
	}
 
}
 

	
 
/* Stub Chunk handlers to only calculate length and do nothing else */
 
static ChunkSaveLoadProc *_tmp_proc_1;
 
static inline void SlStubSaveProc2(void *arg) {_tmp_proc_1();}
 
static void SlStubSaveProc() {SlAutolength(SlStubSaveProc2, NULL);}
 

	
 
/** Save a chunk of data (eg. vehicles, stations, etc.). Each chunk is
 
 * prefixed by an ID identifying it, followed by data, and terminator where appropiate
 
 * @param ch The chunkhandler that will be used for the operation
 
 */
 
static void SlSaveChunk(const ChunkHandler *ch)
 
{
 
	ChunkSaveLoadProc *proc = ch->save_proc;
 

	
 
	/* Don't save any chunk information if there is no save handler. */
 
	if (proc == NULL) return;
 

	
 
	SlWriteUint32(ch->id);
 
	DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
 

	
 
	if (ch->flags & CH_AUTO_LENGTH) {
 
		/* Need to calculate the length. Solve that by calling SlAutoLength in the save_proc. */
 
		_tmp_proc_1 = proc;
 
		proc = SlStubSaveProc;
 
	}
 

	
 
	_sl.block_mode = ch->flags & CH_TYPE_MASK;
 
	switch (ch->flags & CH_TYPE_MASK) {
 
	case CH_RIFF:
 
		_sl.need_length = NL_WANTLENGTH;
 
		proc();
 
		break;
 
	case CH_ARRAY:
 
		_sl.last_array_index = 0;
 
		SlWriteByte(CH_ARRAY);
 
		proc();
 
		SlWriteArrayLength(0); // Terminate arrays
 
		break;
 
	case CH_SPARSE_ARRAY:
 
		SlWriteByte(CH_SPARSE_ARRAY);
 
		proc();
 
		SlWriteArrayLength(0); // Terminate arrays
 
		break;
 
	default: NOT_REACHED();
 
	}
 
}
 

	
 
/** Save all chunks */
 
static void SlSaveChunks()
 
{
 
	const ChunkHandler *ch;
 
	const ChunkHandler* const *chsc;
 
	uint p;
 

	
 
	for (p = 0; p != CH_NUM_PRI_LEVELS; p++) {
 
		for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
 
			while (true) {
 
				if (((ch->flags >> CH_PRI_SHL) & (CH_NUM_PRI_LEVELS - 1)) == p)
 
					SlSaveChunk(ch);
 
				if (ch->flags & CH_LAST)
 
					break;
 
				ch++;
 
			}
 
		}
 
	}
 

	
 
	/* Terminator */
 
	SlWriteUint32(0);
 
}
 

	
 
/** Find the ChunkHandler that will be used for processing the found
 
 * chunk in the savegame or in memory
 
 * @param id the chunk in question
 
 * @return returns the appropiate chunkhandler
 
 */
 
static const ChunkHandler *SlFindChunkHandler(uint32 id)
 
{
 
	const ChunkHandler *ch;
 
	const ChunkHandler *const *chsc;
 
	for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
 
		for (;;) {
 
			if (ch->id == id) return ch;
 
			if (ch->flags & CH_LAST) break;
 
			ch++;
 
		}
 
	}
 
	return NULL;
 
}
 

	
 
/** Load all chunks */
 
static void SlLoadChunks()
 
{
 
	uint32 id;
 
	const ChunkHandler *ch;
 

	
 
	for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
 
		DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
 

	
 
		ch = SlFindChunkHandler(id);
 
		if (ch == NULL) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unknown chunk type");
 
		SlLoadChunk(ch);
 
	}
 
}
 

	
 
/*******************************************
 
 ********** START OF LZO CODE **************
 
 *******************************************/
 
#define LZO_SIZE 8192
 

	
 
#include "../minilzo.h"
 

	
 
static size_t ReadLZO()
 
{
 
	byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
 
	uint32 tmp[2];
 
	uint32 size;
 
	uint len;
 

	
 
	/* Read header*/
 
	if (fread(tmp, sizeof(tmp), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
 

	
 
	/* Check if size is bad */
 
	((uint32*)out)[0] = size = tmp[1];
 

	
 
	if (_sl_version != 0) {
 
		tmp[0] = TO_BE32(tmp[0]);
 
		size = TO_BE32(size);
 
	}
 

	
 
	if (size >= sizeof(out)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Inconsistent size");
 

	
 
	/* Read block */
 
	if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
 

	
 
	/* Verify checksum */
 
	if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Bad checksum");
 

	
 
	/* Decompress */
 
	lzo1x_decompress(out + sizeof(uint32)*1, size, _sl.buf, &len, NULL);
 
	return len;
 
}
 

	
 
/* p contains the pointer to the buffer, len contains the pointer to the length.
 
 * len bytes will be written, p and l will be updated to reflect the next buffer. */
 
static void WriteLZO(size_t size)
 
{
 
	byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
 
	byte wrkmem[sizeof(byte*)*4096];
 
	uint outlen;
 

	
 
	lzo1x_1_compress(_sl.buf, (lzo_uint)size, out + sizeof(uint32)*2, &outlen, wrkmem);
 
	((uint32*)out)[1] = TO_BE32(outlen);
 
	((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
 
	if (fwrite(out, outlen + sizeof(uint32)*2, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
 
}
 

	
 
static bool InitLZO()
 
{
 
	_sl.bufsize = LZO_SIZE;
 
	_sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
 
	return true;
 
}
 

	
 
static void UninitLZO()
 
{
 
	free(_sl.buf_ori);
 
}
 

	
 
/*********************************************
 
 ******** START OF NOCOMP CODE (uncompressed)*
 
 *********************************************/
 
static size_t ReadNoComp()
 
{
 
	return fread(_sl.buf, 1, LZO_SIZE, _sl.fh);
 
}
 

	
 
static void WriteNoComp(size_t size)
 
{
 
	if (fwrite(_sl.buf, 1, size, _sl.fh) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
 
}
 

	
 
static bool InitNoComp()
 
{
 
	_sl.bufsize = LZO_SIZE;
 
	_sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
 
	return true;
 
}
 

	
 
static void UninitNoComp()
 
{
 
	free(_sl.buf_ori);
 
}
 

	
 
/********************************************
 
 ********** START OF MEMORY CODE (in ram)****
 
 ********************************************/
 

	
 
#include "../table/sprites.h"
 
#include "../gui.h"
 

	
 
struct ThreadedSave {
 
	uint count;
 
	byte ff_state;
 
	bool saveinprogress;
 
	CursorID cursor;
 
};
 

	
 
/* A maximum size of of 128K * 500 = 64.000KB savegames */
 
STATIC_OLD_POOL(Savegame, byte, 17, 500, NULL, NULL)
 
static ThreadedSave _ts;
 

	
 
static bool InitMem()
 
{
 
	_ts.count = 0;
 

	
 
	_Savegame_pool.CleanPool();
 
	_Savegame_pool.AddBlockToPool();
 

	
 
	/* A block from the pool is a contigious area of memory, so it is safe to write to it sequentially */
 
	_sl.bufsize = GetSavegamePoolSize();
 
	_sl.buf = GetSavegame(_ts.count);
 
	return true;
 
}
 

	
 
static void UnInitMem()
 
{
 
	_Savegame_pool.CleanPool();
 
}
 

	
 
static void WriteMem(size_t size)
 
{
 
	_ts.count += (uint)size;
 
	/* Allocate new block and new buffer-pointer */
 
	_Savegame_pool.AddBlockIfNeeded(_ts.count);
 
	_sl.buf = GetSavegame(_ts.count);
 
}
 

	
 
/********************************************
 
 ********** START OF ZLIB CODE **************
 
 ********************************************/
 

	
 
#if defined(WITH_ZLIB)
 
#include <zlib.h>
 

	
 
static z_stream _z;
 

	
 
static bool InitReadZlib()
 
{
 
	memset(&_z, 0, sizeof(_z));
 
	if (inflateInit(&_z) != Z_OK) return false;
 

	
 
	_sl.bufsize = 4096;
 
	_sl.buf = _sl.buf_ori = MallocT<byte>(4096 + 4096); // also contains fread buffer
 
	return true;
 
}
 

	
 
static size_t ReadZlib()
 
{
 
	int r;
 

	
 
	_z.next_out = _sl.buf;
 
	_z.avail_out = 4096;
 

	
 
	do {
 
		/* read more bytes from the file? */
 
		if (_z.avail_in == 0) {
 
			_z.avail_in = (uint)fread(_z.next_in = _sl.buf + 4096, 1, 4096, _sl.fh);
 
		}
 

	
 
		/* inflate the data */
 
		r = inflate(&_z, 0);
 
		if (r == Z_STREAM_END)
 
			break;
 

	
 
		if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
 
	} while (_z.avail_out);
 

	
 
	return 4096 - _z.avail_out;
 
}
 

	
 
static void UninitReadZlib()
 
{
 
	inflateEnd(&_z);
 
	free(_sl.buf_ori);
 
}
 

	
 
static bool InitWriteZlib()
 
{
 
	memset(&_z, 0, sizeof(_z));
 
	if (deflateInit(&_z, 6) != Z_OK) return false;
 

	
 
	_sl.bufsize = 4096;
 
	_sl.buf = _sl.buf_ori = MallocT<byte>(4096); // also contains fread buffer
 
	return true;
 
}
 

	
 
static void WriteZlibLoop(z_streamp z, byte *p, size_t len, int mode)
 
{
 
	byte buf[1024]; // output buffer
 
	int r;
 
	uint n;
 
	z->next_in = p;
 
	z->avail_in = (uInt)len;
 
	do {
 
		z->next_out = buf;
 
		z->avail_out = sizeof(buf);
 
		r = deflate(z, mode);
 
			/* bytes were emitted? */
 
		if ((n = sizeof(buf) - z->avail_out) != 0) {
 
			if (fwrite(buf, n, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
 
		}
 
		if (r == Z_STREAM_END)
 
			break;
 
		if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
 
	} while (z->avail_in || !z->avail_out);
 
}
 

	
 
static void WriteZlib(size_t len)
 
{
 
	WriteZlibLoop(&_z, _sl.buf, len, 0);
 
}
 

	
 
static void UninitWriteZlib()
 
{
 
	/* flush any pending output. */
 
	if (_sl.fh) WriteZlibLoop(&_z, NULL, 0, Z_FINISH);
 
	deflateEnd(&_z);
 
	free(_sl.buf_ori);
 
}
 

	
 
#endif /* WITH_ZLIB */
 

	
 
/*******************************************
 
 ************* END OF CODE *****************
 
 *******************************************/
 

	
 
/* these define the chunks */
 
extern const ChunkHandler _gamelog_chunk_handlers[];
 
extern const ChunkHandler _map_chunk_handlers[];
 
extern const ChunkHandler _misc_chunk_handlers[];
 
extern const ChunkHandler _name_chunk_handlers[];
 
extern const ChunkHandler _cheat_chunk_handlers[] ;
 
extern const ChunkHandler _setting_chunk_handlers[];
 
extern const ChunkHandler _company_chunk_handlers[];
 
extern const ChunkHandler _engine_chunk_handlers[];
 
extern const ChunkHandler _veh_chunk_handlers[];
 
extern const ChunkHandler _waypoint_chunk_handlers[];
 
extern const ChunkHandler _depot_chunk_handlers[];
 
extern const ChunkHandler _order_chunk_handlers[];
 
extern const ChunkHandler _town_chunk_handlers[];
 
extern const ChunkHandler _sign_chunk_handlers[];
 
extern const ChunkHandler _station_chunk_handlers[];
 
extern const ChunkHandler _industry_chunk_handlers[];
 
extern const ChunkHandler _economy_chunk_handlers[];
 
extern const ChunkHandler _subsidy_chunk_handlers[];
 
extern const ChunkHandler _animated_tile_chunk_handlers[];
 
extern const ChunkHandler _newgrf_chunk_handlers[];
 
extern const ChunkHandler _group_chunk_handlers[];
 
extern const ChunkHandler _cargopacket_chunk_handlers[];
 
extern const ChunkHandler _autoreplace_chunk_handlers[];
 

	
 
static const ChunkHandler * const _chunk_handlers[] = {
 
	_gamelog_chunk_handlers,
 
	_map_chunk_handlers,
 
	_misc_chunk_handlers,
 
	_name_chunk_handlers,
 
	_cheat_chunk_handlers,
 
	_setting_chunk_handlers,
 
	_veh_chunk_handlers,
 
	_waypoint_chunk_handlers,
 
	_depot_chunk_handlers,
 
	_order_chunk_handlers,
 
	_industry_chunk_handlers,
 
	_economy_chunk_handlers,
 
	_subsidy_chunk_handlers,
 
	_engine_chunk_handlers,
 
	_town_chunk_handlers,
 
	_sign_chunk_handlers,
 
	_station_chunk_handlers,
 
	_company_chunk_handlers,
 
	_animated_tile_chunk_handlers,
 
	_newgrf_chunk_handlers,
 
	_group_chunk_handlers,
 
	_cargopacket_chunk_handlers,
 
	_autoreplace_chunk_handlers,
 
	NULL,
 
};
 

	
 
/**
 
 * Pointers cannot be saved to a savegame, so this functions gets
 
 * the index of the item, and if not available, it hussles with
 
 * pointers (looks really bad :()
 
 * Remember that a NULL item has value 0, and all
 
 * indeces have +1, so vehicle 0 is saved as index 1.
 
 * @param obj The object that we want to get the index of
 
 * @param rt SLRefType type of the object the index is being sought of
 
 * @return Return the pointer converted to an index of the type pointed to
 
 */
 
static uint ReferenceToInt(const void *obj, SLRefType rt)
 
{
 
	if (obj == NULL) return 0;
 

	
 
	switch (rt) {
 
		case REF_VEHICLE_OLD: // Old vehicles we save as new onces
 
		case REF_VEHICLE:   return ((const  Vehicle*)obj)->index + 1;
 
		case REF_STATION:   return ((const  Station*)obj)->index + 1;
 
		case REF_TOWN:      return ((const     Town*)obj)->index + 1;
 
		case REF_ORDER:     return ((const    Order*)obj)->index + 1;
 
		case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
 
		case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
 
		case REF_CARGO_PACKET:  return ((const CargoPacket*)obj)->index + 1;
 
		case REF_ORDERLIST:     return ((const   OrderList*)obj)->index + 1;
 
		default: NOT_REACHED();
 
	}
 

	
 
	return 0; // avoid compiler warning
 
}
 

	
 
/**
 
 * Pointers cannot be loaded from a savegame, so this function
 
 * gets the index from the savegame and returns the appropiate
 
 * pointer from the already loaded base.
 
 * Remember that an index of 0 is a NULL pointer so all indeces
 
 * are +1 so vehicle 0 is saved as 1.
 
 * @param index The index that is being converted to a pointer
 
 * @param rt SLRefType type of the object the pointer is sought of
 
 * @return Return the index converted to a pointer of any type
 
 */
 
static void *IntToReference(uint index, SLRefType rt)
 
{
 
	/* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE,
 
	 * and should be loaded like that */
 
	if (rt == REF_VEHICLE_OLD && !CheckSavegameVersionOldStyle(4, 4)) {
 
		rt = REF_VEHICLE;
 
	}
 

	
 
	/* No need to look up NULL pointers, just return immediately */
 
	if (rt != REF_VEHICLE_OLD && index == 0) {
 
		return NULL;
 
	}
 

	
 
	index--; // correct for the NULL index
 

	
 
	switch (rt) {
 
		case REF_ORDERLIST:
 
			if (_OrderList_pool.AddBlockIfNeeded(index)) return GetOrderList(index);
 
			error("Orders: failed loading savegame: too many order lists");
 

	
 
		case REF_ORDER:
 
			if (_Order_pool.AddBlockIfNeeded(index)) return GetOrder(index);
 
			error("Orders: failed loading savegame: too many orders");
 

	
 
		case REF_VEHICLE:
 
			if (_Vehicle_pool.AddBlockIfNeeded(index)) return GetVehicle(index);
 
			error("Vehicles: failed loading savegame: too many vehicles");
 

	
 
		case REF_STATION:
 
			if (_Station_pool.AddBlockIfNeeded(index)) return GetStation(index);
 
			error("Stations: failed loading savegame: too many stations");
 

	
 
		case REF_TOWN:
 
			if (_Town_pool.AddBlockIfNeeded(index)) return GetTown(index);
 
			error("Towns: failed loading savegame: too many towns");
 

	
 
		case REF_ROADSTOPS:
 
			if (_RoadStop_pool.AddBlockIfNeeded(index)) return GetRoadStop(index);
 
			error("RoadStops: failed loading savegame: too many RoadStops");
 

	
 
		case REF_ENGINE_RENEWS:
 
			if (_EngineRenew_pool.AddBlockIfNeeded(index)) return GetEngineRenew(index);
 
			error("EngineRenews: failed loading savegame: too many EngineRenews");
 

	
 
		case REF_CARGO_PACKET:
 
			if (_CargoPacket_pool.AddBlockIfNeeded(index)) return GetCargoPacket(index);
 
			error("CargoPackets: failed loading savegame: too many Cargo packets");
 

	
 
		case REF_VEHICLE_OLD:
 
			/* Old vehicles were saved differently:
 
			 * invalid vehicle was 0xFFFF,
 
			 * and the index was not - 1.. correct for this */
 
			index++;
 
			if (index == INVALID_VEHICLE) return NULL;
 

	
 
			if (_Vehicle_pool.AddBlockIfNeeded(index)) return GetVehicle(index);
 
			error("Vehicles: failed loading savegame: too many vehicles");
 

	
 
		default: NOT_REACHED();
 
	}
 

	
 
	return NULL;
 
}
 

	
 
/** The format for a reader/writer type of a savegame */
 
struct SaveLoadFormat {
 
	const char *name;           ///< name of the compressor/decompressor (debug-only)
 
	uint32 tag;                 ///< the 4-letter tag by which it is identified in the savegame
 

	
 
	bool (*init_read)();        ///< function executed upon initalization of the loader
 
	ReaderProc *reader;         ///< function that loads the data from the file
 
	void (*uninit_read)();      ///< function executed when reading is finished
 

	
 
	bool (*init_write)();       ///< function executed upon intialization of the saver
 
	WriterProc *writer;         ///< function that saves the data to the file
 
	void (*uninit_write)();     ///< function executed when writing is done
 
};
 

	
 
static const SaveLoadFormat _saveload_formats[] = {
 
	{"memory", 0,                NULL,         NULL,       NULL,           InitMem,       WriteMem,    UnInitMem},
 
	{"lzo",    TO_BE32X('OTTD'), InitLZO,      ReadLZO,    UninitLZO,      InitLZO,       WriteLZO,    UninitLZO},
 
	{"none",   TO_BE32X('OTTN'), InitNoComp,   ReadNoComp, UninitNoComp,   InitNoComp,    WriteNoComp, UninitNoComp},
 
#if defined(WITH_ZLIB)
 
	{"zlib",   TO_BE32X('OTTZ'), InitReadZlib, ReadZlib,   UninitReadZlib, InitWriteZlib, WriteZlib,   UninitWriteZlib},
 
#else
 
	{"zlib",   TO_BE32X('OTTZ'), NULL,         NULL,       NULL,           NULL,          NULL,        NULL},
 
#endif
 
};
 

	
 
/**
 
 * Return the savegameformat of the game. Whether it was create with ZLIB compression
 
 * uncompressed, or another type
 
 * @param s Name of the savegame format. If NULL it picks the first available one
 
 * @return Pointer to SaveLoadFormat struct giving all characteristics of this type of savegame
 
 */
 
static const SaveLoadFormat *GetSavegameFormat(const char *s)
 
{
 
	const SaveLoadFormat *def = endof(_saveload_formats) - 1;
 

	
 
	/* find default savegame format, the highest one with which files can be written */
 
	while (!def->init_write) def--;
 

	
 
	if (s != NULL && s[0] != '\0') {
 
		const SaveLoadFormat *slf;
 
		for (slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
 
			if (slf->init_write != NULL && strcmp(s, slf->name) == 0)
 
				return slf;
 
		}
 

	
 
		ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
 
	}
 
	return def;
 
}
 

	
 
/* actual loader/saver function */
 
void InitializeGame(uint size_x, uint size_y, bool reset_date);
 
extern bool AfterLoadGame();
 
extern bool LoadOldSaveGame(const char *file);
 

	
 
/** Small helper function to close the to be loaded savegame an signal error */
 
static inline SaveOrLoadResult AbortSaveLoad()
 
{
 
	if (_sl.fh != NULL) fclose(_sl.fh);
 

	
 
	_sl.fh = NULL;
 
	return SL_ERROR;
 
}
 

	
 
/** Update the gui accordingly when starting saving
 
 * and set locks on saveload. Also turn off fast-forward cause with that
 
 * saving takes Aaaaages */
 
static void SaveFileStart()
 
{
 
	_ts.ff_state = _fast_forward;
 
	_fast_forward = 0;
 
	if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
 

	
 
	InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
 
	_ts.saveinprogress = true;
 
}
 

	
 
/** Update the gui accordingly when saving is done and release locks
 
 * on saveload */
 
static void SaveFileDone()
 
{
 
	if (_game_mode != GM_MENU) _fast_forward = _ts.ff_state;
 
	if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
 

	
 
	InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
 
	_ts.saveinprogress = false;
 
}
 

	
 
/** Set the error message from outside of the actual loading/saving of the game (AfterLoadGame and friends) */
 
void SetSaveLoadError(StringID str)
 
{
 
	_sl.error_str = str;
 
}
 

	
 
/** Get the string representation of the error message */
 
const char *GetSaveLoadErrorString()
 
{
 
	SetDParam(0, _sl.error_str);
 
	SetDParamStr(1, _sl.extra_msg);
 

	
 
	static char err_str[512];
 
	GetString(err_str, _sl.save ? STR_4007_GAME_SAVE_FAILED : STR_4009_GAME_LOAD_FAILED, lastof(err_str));
 
	return err_str;
 
}
 

	
 
/** Show a gui message when saving has failed */
 
static void SaveFileError()
 
{
 
	SetDParamStr(0, GetSaveLoadErrorString());
 
	ShowErrorMessage(STR_JUST_RAW_STRING, STR_NULL, 0, 0);
 
	SaveFileDone();
 
}
 

	
 
/** We have written the whole game into memory, _Savegame_pool, now find
 
 * and appropiate compressor and start writing to file.
 
 */
 
static SaveOrLoadResult SaveFileToDisk(bool threaded)
 
{
 
	const SaveLoadFormat *fmt;
 
	uint32 hdr[2];
 

	
 
	_sl.excpt_uninit = NULL;
 
	try {
 
		fmt = GetSavegameFormat(_savegame_format);
 

	
 
		/* We have written our stuff to memory, now write it to file! */
 
		hdr[0] = fmt->tag;
 
		hdr[1] = TO_BE32(SAVEGAME_VERSION << 16);
 
		if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
 

	
 
		if (!fmt->init_write()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
 

	
 
		{
 
			uint i;
 
			uint count = 1 << Savegame_POOL_BLOCK_SIZE_BITS;
 

	
 
			if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
 
			for (i = 0; i != _Savegame_pool.GetBlockCount() - 1; i++) {
 
				_sl.buf = _Savegame_pool.blocks[i];
 
				fmt->writer(count);
 
			}
 

	
 
			/* The last block is (almost) always not fully filled, so only write away
 
			 * as much data as it is in there */
 
			_sl.buf = _Savegame_pool.blocks[i];
 
			fmt->writer(_ts.count - (i * count));
 
		}
 

	
 
		fmt->uninit_write();
 
		if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
 
		GetSavegameFormat("memory")->uninit_write(); // clean the memorypool
 
		fclose(_sl.fh);
 

	
 
		if (threaded) SetAsyncSaveFinish(SaveFileDone);
 

	
 
		return SL_OK;
 
	}
 
	catch (...) {
 
		AbortSaveLoad();
 
		if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
 

	
 
		/* Skip the "color" character */
 
		DEBUG(sl, 0, GetSaveLoadErrorString() + 3);
 

	
 
		if (threaded) {
 
			SetAsyncSaveFinish(SaveFileError);
 
		} else {
 
			SaveFileError();
 
		}
 
		return SL_ERROR;
 
	}
 
}
 

	
 
static void SaveFileToDiskThread(void *arg)
 
{
 
	SaveFileToDisk(true);
 
}
 

	
 
void WaitTillSaved()
 
{
 
	if (_save_thread == NULL) return;
 

	
 
	_save_thread->Join();
 
	delete _save_thread;
 
	_save_thread = NULL;
 
}
 

	
 
/**
 
 * Main Save or Load function where the high-level saveload functions are
 
 * handled. It opens the savegame, selects format and checks versions
 
 * @param filename The name of the savegame being created/loaded
 
 * @param mode Save or load. Load can also be a TTD(Patch) game. Use SL_LOAD, SL_OLD_LOAD or SL_SAVE
 
 * @return Return the results of the action. SL_OK, SL_ERROR or SL_REINIT ("unload" the game)
 
 */
 
SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb)
 
{
 
	uint32 hdr[2];
 
	const SaveLoadFormat *fmt;
 

	
 
	/* An instance of saving is already active, so don't go saving again */
 
	if (_ts.saveinprogress && mode == SL_SAVE) {
 
		/* if not an autosave, but a user action, show error message */
 
		if (!_do_autosave) ShowErrorMessage(INVALID_STRING_ID, STR_SAVE_STILL_IN_PROGRESS, 0, 0);
 
		return SL_OK;
 
	}
 
	WaitTillSaved();
 

	
 
	_next_offs = 0;
 

	
 
	/* Load a TTDLX or TTDPatch game */
 
	if (mode == SL_OLD_LOAD) {
 
		InitializeGame(256, 256, true); // set a mapsize of 256x256 for TTDPatch games or it might get confused
 
		GamelogReset();
 
		if (!LoadOldSaveGame(filename)) return SL_REINIT;
 
		_sl_version = 0;
 
		_sl_minor_version = 0;
 
		GamelogStartAction(GLAT_LOAD);
 
		if (!AfterLoadGame()) {
 
			GamelogStopAction();
 
			return SL_REINIT;
 
		}
 
		GamelogStopAction();
 
		return SL_OK;
 
	}
 

	
 
	_sl.excpt_uninit = NULL;
 
	try {
 
		_sl.fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
 

	
 
		/* Make it a little easier to load savegames from the console */
 
		if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", SAVE_DIR);
 
		if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", BASE_DIR);
 

	
 
		if (_sl.fh == NULL) {
 
			SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
 
		}
 

	
 
		_sl.bufe = _sl.bufp = NULL;
 
		_sl.offs_base = 0;
 
		_sl.save = (mode != 0);
 
		_sl.chs = _chunk_handlers;
 

	
 
		/* General tactic is to first save the game to memory, then use an available writer
 
		 * to write it to file, either in threaded mode if possible, or single-threaded */
 
		if (mode == SL_SAVE) { /* SAVE game */
 
			DEBUG(desync, 1, "save: %s\n", filename);
 
			fmt = GetSavegameFormat("memory"); // write to memory
 

	
 
			_sl.write_bytes = fmt->writer;
 
			_sl.excpt_uninit = fmt->uninit_write;
 
			if (!fmt->init_write()) {
 
				DEBUG(sl, 0, "Initializing writer '%s' failed.", fmt->name);
 
				return AbortSaveLoad();
 
			}
 

	
 
			_sl_version = SAVEGAME_VERSION;
 

	
 
			SaveViewportBeforeSaveGame();
 
			SlSaveChunks();
 
			SlWriteFill(); // flush the save buffer
 

	
 
			SaveFileStart();
 
			if (_network_server ||
 
						(_save_thread = ThreadObject::New(&SaveFileToDiskThread, NULL)) == NULL) {
 
				if (!_network_server) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
 

	
 
				SaveOrLoadResult result = SaveFileToDisk(false);
 
				SaveFileDone();
 

	
 
				return result;
 
			}
 
		} else { /* LOAD game */
 
			assert(mode == SL_LOAD);
 
			DEBUG(desync, 1, "load: %s\n", filename);
 

	
 
			if (fread(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
 

	
 
			/* see if we have any loader for this type. */
 
			for (fmt = _saveload_formats; ; fmt++) {
 
				/* No loader found, treat as version 0 and use LZO format */
 
				if (fmt == endof(_saveload_formats)) {
 
					DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
 
	#if defined(WINCE)
 
					/* Of course some system had not to support rewind ;) */
 
					fseek(_sl.fh, 0L, SEEK_SET);
 
					clearerr(_sl.fh);
 
	#else
 
					rewind(_sl.fh);
 
	#endif
 
					_sl_version = 0;
 
					_sl_minor_version = 0;
 
					fmt = _saveload_formats + 1; // LZO
 
					break;
 
				}
 

	
 
				if (fmt->tag == hdr[0]) {
 
					/* check version number */
 
					_sl_version = TO_BE32(hdr[1]) >> 16;
 
					/* Minor is not used anymore from version 18.0, but it is still needed
 
					 * in versions before that (4 cases) which can't be removed easy.
 
					 * Therefor it is loaded, but never saved (or, it saves a 0 in any scenario).
 
					 * So never EVER use this minor version again. -- TrueLight -- 22-11-2005 */
 
					_sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
 

	
 
					DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
 

	
 
					/* Is the version higher than the current? */
 
					if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
 
					break;
 
				}
 
			}
 

	
 
			_sl.read_bytes = fmt->reader;
 
			_sl.excpt_uninit = fmt->uninit_read;
 

	
 
			/* loader for this savegame type is not implemented? */
 
			if (fmt->init_read == NULL) {
 
				char err_str[64];
 
				snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
 
				SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
 
			}
 

	
 
			if (!fmt->init_read()) {
 
				char err_str[64];
 
				snprintf(err_str, lengthof(err_str), "Initializing loader '%s' failed", fmt->name);
 
				SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
 
			}
 

	
 
			/* Old maps were hardcoded to 256x256 and thus did not contain
 
			 * any mapsize information. Pre-initialize to 256x256 to not to
 
			 * confuse old games */
 
			InitializeGame(256, 256, true);
 

	
 
			GamelogReset();
 

	
 
			SlLoadChunks();
 
			fmt->uninit_read();
 
			fclose(_sl.fh);
 

	
 
			GamelogStartAction(GLAT_LOAD);
 

	
 
			_savegame_type = SGT_OTTD;
 

	
 
			/* After loading fix up savegame for any internal changes that
 
			 * might've occured since then. If it fails, load back the old game */
 
			if (!AfterLoadGame()) {
 
				GamelogStopAction();
 
				return SL_REINIT;
 
			}
 

	
 
			GamelogStopAction();
 
		}
 

	
 
		return SL_OK;
 
	}
 
	catch (...) {
 
		AbortSaveLoad();
 

	
 
		/* deinitialize compressor. */
 
		if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
 

	
 
		/* Skip the "color" character */
 
		DEBUG(sl, 0, GetSaveLoadErrorString() + 3);
 

	
 
		/* A saver/loader exception!! reinitialize all variables to prevent crash! */
 
		return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
 
	}
 
}
 

	
 
/** Do a save when exiting the game (patch option) _settings_client.gui.autosave_on_exit */
 
void DoExitSave()
 
{
 
	SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
 
}
 

	
 
/**
 
 * Fill the buffer with the default name for a savegame *or* screenshot.
 
 * @param buf the buffer to write to.
 
 * @param last the last element in the buffer.
 
 */
 
void GenerateDefaultSaveName(char *buf, const char *last)
 
{
 
	/* Check if we have a name for this map, which is the name of the first
 
	 * available company. When there's no company available we'll use
 
	 * 'Spectator' as "company" name. */
 
	CompanyID cid = _local_company;
 
	if (!IsValidCompanyID(cid)) {
 
		const Company *c;
 
		FOR_ALL_COMPANIES(c) {
 
			cid = c->index;
 
			break;
 
		}
 
	}
 

	
 
	SetDParam(0, cid);
 

	
 
	/* Insert current date */
 
	switch (_settings_client.gui.date_format_in_default_names) {
 
		case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
 
		case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
 
		case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
 
		default: NOT_REACHED();
 
	}
 
	SetDParam(2, _date);
 

	
 
	/* Get the correct string (special string for when there's not company) */
 
	GetString(buf, !IsValidCompanyID(cid) ? STR_GAME_SAVELOAD_SPECTATOR_SAVEGAME : STR_4004, last);
 
	SanitizeFilename(buf);
 
}
 

	
 
#if 0
 
/**
 
 * Function to get the type of the savegame by looking at the file header.
 
 * NOTICE: Not used right now, but could be used if extensions of savegames are garbled
 
 * @param file Savegame to be checked
 
 * @return SL_OLD_LOAD or SL_LOAD of the file
 
 */
 
int GetSavegameType(char *file)
 
{
 
	const SaveLoadFormat *fmt;
 
	uint32 hdr;
 
	FILE *f;
 
	int mode = SL_OLD_LOAD;
 

	
 
	f = fopen(file, "rb");
 
	if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
 
		DEBUG(sl, 0, "Savegame is obsolete or invalid format");
 
		mode = SL_LOAD; // don't try to get filename, just show name as it is written
 
	} else {
 
		/* see if we have any loader for this type. */
 
		for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
 
			if (fmt->tag == hdr) {
 
				mode = SL_LOAD; // new type of savegame
 
				break;
 
			}
 
		}
 
	}
 

	
 
	fclose(f);
 
	return mode;
 
}
 
#endif
src/saveload/saveload.h
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file saveload.h Functions/types related to saving and loading games. */
 

	
 
#ifndef SAVELOAD_H
 
#define SAVELOAD_H
 

	
 
#include "../fileio_type.h"
 

	
 
#ifdef SIZE_MAX
 
#undef SIZE_MAX
 
#endif
 

	
 
#define SIZE_MAX ((size_t)-1)
 

	
 
enum SaveOrLoadResult {
 
	SL_OK     = 0, ///< completed successfully
 
	SL_ERROR  = 1, ///< error that was caught before internal structures were modified
 
	SL_REINIT = 2, ///< error that was caught in the middle of updating game state, need to clear it. (can only happen during load)
 
};
 

	
 
enum SaveOrLoadMode {
 
	SL_INVALID  = -1,
 
	SL_LOAD     =  0,
 
	SL_SAVE     =  1,
 
	SL_OLD_LOAD =  2,
 
	SL_PNG      =  3,
 
	SL_BMP      =  4,
 
};
 

	
 
enum SavegameType {
 
	SGT_TTD,    ///< TTD  savegame (can be detected incorrectly)
 
	SGT_TTDP1,  ///< TTDP savegame ( -//- ) (data at NW border)
 
	SGT_TTDP2,  ///< TTDP savegame in new format (data at SE border)
 
	SGT_OTTD    ///< OTTD savegame
 
};
 

	
 
void GenerateDefaultSaveName(char *buf, const char *last);
 
void SetSaveLoadError(uint16 str);
 
const char *GetSaveLoadErrorString();
 
SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb);
 
void WaitTillSaved();
 
void DoExitSave();
 

	
 

	
 
typedef void ChunkSaveLoadProc();
 
typedef void AutolengthProc(void *arg);
 

	
 
struct ChunkHandler {
 
	uint32 id;
 
	ChunkSaveLoadProc *save_proc;
 
	ChunkSaveLoadProc *load_proc;
 
	uint32 flags;
 
};
 

	
 
struct NullStruct {
 
	byte null;
 
};
 

	
 
enum SLRefType {
 
	REF_ORDER         = 0,
 
	REF_VEHICLE       = 1,
 
	REF_STATION       = 2,
 
	REF_TOWN          = 3,
 
	REF_VEHICLE_OLD   = 4,
 
	REF_ROADSTOPS     = 5,
 
	REF_ENGINE_RENEWS = 6,
 
	REF_CARGO_PACKET  = 7,
 
	REF_ORDERLIST     = 8,
 
};
 

	
 
#define SL_MAX_VERSION 255
 

	
 
enum {
 
	INC_VEHICLE_COMMON = 0,
 
};
 

	
 
enum {
 
	CH_RIFF         =  0,
 
	CH_ARRAY        =  1,
 
	CH_SPARSE_ARRAY =  2,
 
	CH_TYPE_MASK    =  3,
 
	CH_LAST         =  8,
 
	CH_AUTO_LENGTH  = 16,
 

	
 
	CH_PRI_0          = 0 << 4,
 
	CH_PRI_1          = 1 << 4,
 
	CH_PRI_2          = 2 << 4,
 
	CH_PRI_3          = 3 << 4,
 
	CH_PRI_SHL        = 4,
 
	CH_NUM_PRI_LEVELS = 4,
 
};
 

	
 
/** VarTypes is the general bitmasked magic type that tells us
 
 * certain characteristics about the variable it refers to. For example
 
 * SLE_FILE_* gives the size(type) as it would be in the savegame and
 
 * SLE_VAR_* the size(type) as it is in memory during runtime. These are
 
 * the first 8 bits (0-3 SLE_FILE, 4-7 SLE_VAR).
 
 * Bits 8-15 are reserved for various flags as explained below */
 
enum VarTypes {
 
	/* 4 bits allocated a maximum of 16 types for NumberType */
 
	SLE_FILE_I8       = 0,
 
	SLE_FILE_U8       = 1,
 
	SLE_FILE_I16      = 2,
 
	SLE_FILE_U16      = 3,
 
	SLE_FILE_I32      = 4,
 
	SLE_FILE_U32      = 5,
 
	SLE_FILE_I64      = 6,
 
	SLE_FILE_U64      = 7,
 
	SLE_FILE_STRINGID = 8, ///< StringID offset into strings-array
 
	SLE_FILE_STRING   = 9,
 
	/* 6 more possible file-primitives */
 

	
 
	/* 4 bits allocated a maximum of 16 types for NumberType */
 
	SLE_VAR_BL    =  0 << 4,
 
	SLE_VAR_I8    =  1 << 4,
 
	SLE_VAR_U8    =  2 << 4,
 
	SLE_VAR_I16   =  3 << 4,
 
	SLE_VAR_U16   =  4 << 4,
 
	SLE_VAR_I32   =  5 << 4,
 
	SLE_VAR_U32   =  6 << 4,
 
	SLE_VAR_I64   =  7 << 4,
 
	SLE_VAR_U64   =  8 << 4,
 
	SLE_VAR_NULL  =  9 << 4, ///< useful to write zeros in savegame.
 
	SLE_VAR_STRB  = 10 << 4, ///< string (with pre-allocated buffer)
 
	SLE_VAR_STRBQ = 11 << 4, ///< string enclosed in quotes (with pre-allocated buffer)
 
	SLE_VAR_STR   = 12 << 4, ///< string pointer
 
	SLE_VAR_STRQ  = 13 << 4, ///< string pointer enclosed in quotes
 
	SLE_VAR_NAME  = 14 << 4, ///< old custom name to be converted to a char pointer
 
	/* 1 more possible memory-primitives */
 

	
 
	/* Shortcut values */
 
	SLE_VAR_CHAR = SLE_VAR_I8,
 

	
 
	/* Default combinations of variables. As savegames change, so can variables
 
	 * and thus it is possible that the saved value and internal size do not
 
	 * match and you need to specify custom combo. The defaults are listed here */
 
	SLE_BOOL         = SLE_FILE_I8  | SLE_VAR_BL,
 
	SLE_INT8         = SLE_FILE_I8  | SLE_VAR_I8,
 
	SLE_UINT8        = SLE_FILE_U8  | SLE_VAR_U8,
 
	SLE_INT16        = SLE_FILE_I16 | SLE_VAR_I16,
 
	SLE_UINT16       = SLE_FILE_U16 | SLE_VAR_U16,
 
	SLE_INT32        = SLE_FILE_I32 | SLE_VAR_I32,
 
	SLE_UINT32       = SLE_FILE_U32 | SLE_VAR_U32,
 
	SLE_INT64        = SLE_FILE_I64 | SLE_VAR_I64,
 
	SLE_UINT64       = SLE_FILE_U64 | SLE_VAR_U64,
 
	SLE_CHAR         = SLE_FILE_I8  | SLE_VAR_CHAR,
 
	SLE_STRINGID     = SLE_FILE_STRINGID | SLE_VAR_U16,
 
	SLE_STRINGBUF    = SLE_FILE_STRING   | SLE_VAR_STRB,
 
	SLE_STRINGBQUOTE = SLE_FILE_STRING   | SLE_VAR_STRBQ,
 
	SLE_STRING       = SLE_FILE_STRING   | SLE_VAR_STR,
 
	SLE_STRINGQUOTE  = SLE_FILE_STRING   | SLE_VAR_STRQ,
 
	SLE_NAME         = SLE_FILE_STRINGID | SLE_VAR_NAME,
 

	
 
	/* Shortcut values */
 
	SLE_UINT  = SLE_UINT32,
 
	SLE_INT   = SLE_INT32,
 
	SLE_STRB  = SLE_STRINGBUF,
 
	SLE_STRBQ = SLE_STRINGBQUOTE,
 
	SLE_STR   = SLE_STRING,
 
	SLE_STRQ  = SLE_STRINGQUOTE,
 

	
 
	/* 8 bits allocated for a maximum of 8 flags
 
	 * Flags directing saving/loading of a variable */
 
	SLF_SAVE_NO      = 1 <<  8, ///< do not save with savegame, basically client-based
 
	SLF_CONFIG_NO    = 1 <<  9, ///< do not save to config file
 
	SLF_NETWORK_NO   = 1 << 10, ///< do not synchronize over network (but it is saved if SSF_SAVE_NO is not set)
 
	/* 5 more possible flags */
 
};
 

	
 
typedef uint32 VarType;
 

	
 
enum SaveLoadTypes {
 
	SL_VAR         =  0,
 
	SL_REF         =  1,
 
	SL_ARR         =  2,
 
	SL_STR         =  3,
 
	SL_LST         =  4,
 
	// non-normal save-load types
 
	SL_WRITEBYTE   =  8,
 
	SL_VEH_INCLUDE =  9,
 
	SL_END         = 15
 
};
 

	
 
typedef byte SaveLoadType;
 

	
 
/** SaveLoad type struct. Do NOT use this directly but use the SLE_ macros defined just below! */
 
struct SaveLoad {
 
	bool global;         ///< should we load a global variable or a non-global one
 
	SaveLoadType cmd;    ///< the action to take with the saved/loaded type, All types need different action
 
	VarType conv;        ///< type of the variable to be saved, int
 
	uint16 length;       ///< (conditional) length of the variable (eg. arrays) (max array size is 65536 elements)
 
	uint16 version_from; ///< save/load the variable starting from this savegame version
 
	uint16 version_to;   ///< save/load the variable until this savegame version
 
	/* NOTE: This element either denotes the address of the variable for a global
 
	 * variable, or the offset within a struct which is then bound to a variable
 
	 * during runtime. Decision on which one to use is controlled by the function
 
	 * that is called to save it. address: global=true, offset: global=false */
 
	void *address;       ///< address of variable OR offset of variable in the struct (max offset is 65536)
 
};
 

	
 
/* Same as SaveLoad but global variables are used (for better readability); */
 
typedef SaveLoad SaveLoadGlobVarList;
 

	
 
/* Simple variables, references (pointers) and arrays */
 
#define SLE_GENERAL(cmd, base, variable, type, length, from, to) {false, cmd, type, length, from, to, (void*)cpp_offsetof(base, variable)}
 
#define SLE_CONDVAR(base, variable, type, from, to) SLE_GENERAL(SL_VAR, base, variable, type, 0, from, to)
 
#define SLE_CONDREF(base, variable, type, from, to) SLE_GENERAL(SL_REF, base, variable, type, 0, from, to)
 
#define SLE_CONDARR(base, variable, type, length, from, to) SLE_GENERAL(SL_ARR, base, variable, type, length, from, to)
 
#define SLE_CONDSTR(base, variable, type, length, from, to) SLE_GENERAL(SL_STR, base, variable, type, length, from, to)
 
#define SLE_CONDLST(base, variable, type, from, to) SLE_GENERAL(SL_LST, base, variable, type, 0, from, to)
 

	
 
#define SLE_VAR(base, variable, type) SLE_CONDVAR(base, variable, type, 0, SL_MAX_VERSION)
 
#define SLE_REF(base, variable, type) SLE_CONDREF(base, variable, type, 0, SL_MAX_VERSION)
 
#define SLE_ARR(base, variable, type, length) SLE_CONDARR(base, variable, type, length, 0, SL_MAX_VERSION)
 
#define SLE_STR(base, variable, type, length) SLE_CONDSTR(base, variable, type, length, 0, SL_MAX_VERSION)
 
#define SLE_LST(base, variable, type) SLE_CONDLST(base, variable, type, 0, SL_MAX_VERSION)
 

	
 
#define SLE_CONDNULL(length, from, to) SLE_CONDARR(NullStruct, null, SLE_FILE_U8 | SLE_VAR_NULL | SLF_CONFIG_NO, length, from, to)
 

	
 
/* Translate values ingame to different values in the savegame and vv */
 
#define SLE_WRITEBYTE(base, variable, value) SLE_GENERAL(SL_WRITEBYTE, base, variable, 0, 0, value, value)
 

	
 
/* The same as the ones at the top, only the offset is given directly; used for unions */
 
#define SLE_GENERALX(cmd, offset, type, length, param1, param2) {false, cmd, type, length, param1, param2, (void*)(offset)}
 
#define SLE_CONDVARX(offset, type, from, to) SLE_GENERALX(SL_VAR, offset, type, 0, from, to)
 
#define SLE_CONDARRX(offset, type, length, from, to) SLE_GENERALX(SL_ARR, offset, type, length, from, to)
 
#define SLE_CONDREFX(offset, type, from, to) SLE_GENERALX(SL_REF, offset, type, 0, from, to)
 

	
 
#define SLE_VARX(offset, type) SLE_CONDVARX(offset, type, 0, SL_MAX_VERSION)
 
#define SLE_REFX(offset, type) SLE_CONDREFX(offset, type, 0, SL_MAX_VERSION)
 

	
 
#define SLE_WRITEBYTEX(offset, something) SLE_GENERALX(SL_WRITEBYTE, offset, 0, 0, something, 0)
 
#define SLE_VEH_INCLUDEX() SLE_GENERALX(SL_VEH_INCLUDE, 0, 0, 0, 0, SL_MAX_VERSION)
 

	
 
/* End marker */
 
#define SLE_END() {false, SL_END, 0, 0, 0, 0, NULL}
 

	
 
/* Simple variables, references (pointers) and arrays, but for global variables */
 
#define SLEG_GENERAL(cmd, variable, type, length, from, to) {true, cmd, type, length, from, to, (void*)&variable}
 

	
 
#define SLEG_CONDVAR(variable, type, from, to) SLEG_GENERAL(SL_VAR, variable, type, 0, from, to)
 
#define SLEG_CONDREF(variable, type, from, to) SLEG_GENERAL(SL_REF, variable, type, 0, from, to)
 
#define SLEG_CONDARR(variable, type, length, from, to) SLEG_GENERAL(SL_ARR, variable, type, length, from, to)
 
#define SLEG_CONDSTR(variable, type, length, from, to) SLEG_GENERAL(SL_STR, variable, type, length, from, to)
 
#define SLEG_CONDLST(variable, type, from, to) SLEG_GENERAL(SL_LST, variable, type, 0, from, to)
 

	
 
#define SLEG_VAR(variable, type) SLEG_CONDVAR(variable, type, 0, SL_MAX_VERSION)
 
#define SLEG_REF(variable, type) SLEG_CONDREF(variable, type, 0, SL_MAX_VERSION)
 
#define SLEG_ARR(variable, type) SLEG_CONDARR(variable, type, lengthof(variable), 0, SL_MAX_VERSION)
 
#define SLEG_STR(variable, type) SLEG_CONDSTR(variable, type, lengthof(variable), 0, SL_MAX_VERSION)
 
#define SLEG_LST(variable, type) SLEG_CONDLST(variable, type, 0, SL_MAX_VERSION)
 

	
 
#define SLEG_CONDNULL(length, from, to) {true, SL_ARR, SLE_FILE_U8 | SLE_VAR_NULL | SLF_CONFIG_NO, length, from, to, (void*)NULL}
 

	
 
#define SLEG_END() {true, SL_END, 0, 0, 0, 0, NULL}
 

	
 
/** Checks if the savegame is below major.minor.
 
 */
 
static inline bool CheckSavegameVersionOldStyle(uint16 major, byte minor)
 
{
 
	extern uint16 _sl_version;
 
	extern byte   _sl_minor_version;
 
	return (_sl_version < major) || (_sl_version == major && _sl_minor_version < minor);
 
}
 

	
 
/** Checks if the savegame is below version.
 
 */
 
static inline bool CheckSavegameVersion(uint16 version)
 
{
 
	extern uint16 _sl_version;
 
	return _sl_version < version;
 
}
 

	
 
/** Checks if some version from/to combination falls within the range of the
 
 * active savegame version */
 
static inline bool SlIsObjectCurrentlyValid(uint16 version_from, uint16 version_to)
 
{
 
	extern const uint16 SAVEGAME_VERSION;
 
	if (SAVEGAME_VERSION < version_from || SAVEGAME_VERSION > version_to) return false;
 

	
 
	return true;
 
}
 

	
 
/* Get the NumberType of a setting. This describes the integer type
 
 * as it is represented in memory
 
 * @param type VarType holding information about the variable-type
 
 * @return return the SLE_VAR_* part of a variable-type description */
 
static inline VarType GetVarMemType(VarType type)
 
{
 
	return type & 0xF0; // GB(type, 4, 4) << 4;
 
}
 

	
 
/* Get the FileType of a setting. This describes the integer type
 
 * as it is represented in a savegame/file
 
 * @param type VarType holding information about the variable-type
 
 * @param return the SLE_FILE_* part of a variable-type description */
 
static inline VarType GetVarFileType(VarType type)
 
{
 
	return type & 0xF; // GB(type, 0, 4);
 
}
 

	
 
/** Get the address of the variable. Which one to pick depends on the object
 
 * pointer. If it is NULL we are dealing with global variables so the address
 
 * is taken. If non-null only the offset is stored in the union and we need
 
 * to add this to the address of the object */
 
static inline void *GetVariableAddress(const void *object, const SaveLoad *sld)
 
{
 
	return (byte*)(sld->global ? NULL : object) + (ptrdiff_t)sld->address;
 
}
 

	
 
int64 ReadValue(const void *ptr, VarType conv);
 
void WriteValue(void *ptr, VarType conv, int64 val);
 

	
 
void SlSetArrayIndex(uint index);
 
int SlIterateArray();
 

	
 
void SlAutolength(AutolengthProc *proc, void *arg);
 
size_t SlGetFieldLength();
 
void SlSetLength(size_t length);
 
size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld);
 
size_t SlCalcObjLength(const void *object, const SaveLoad *sld);
 

	
 
byte SlReadByte();
 
void SlWriteByte(byte b);
 

	
 
void SlGlobList(const SaveLoadGlobVarList *sldg);
 
void SlArray(void *array, size_t length, VarType conv);
 
void SlObject(void *object, const SaveLoad *sld);
 
bool SlObjectMember(void *object, const SaveLoad *sld);
 

	
 
#endif /* SAVELOAD_H */
src/saveload/saveload_internal.h
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file saveload_internal.h Declaration of functions used in more save/load files */
 

	
 
#ifndef SAVELOAD_INTERNAL_H
 
#define SAVELOAD_INTERNAL_H
 

	
 
#include "../strings_type.h"
 
#include "../company_manager_face.h"
 
#include "../order_base.h"
 

	
 
void InitializeOldNames();
 
StringID RemapOldStringID(StringID s);
 
char *CopyFromOldName(StringID id);
 
void ResetOldNames();
 

	
 
void FixOldWaypoints();
 

	
 
void AfterLoadWaypoints();
 
void AfterLoadVehicles(bool part_of_load);
 
void AfterLoadStations();
 
void AfterLoadTown();
 
void UpdateHousesAndTowns();
 

	
 
void UpdateOldAircraft();
 

	
 
void SaveViewportBeforeSaveGame();
 
void ResetViewportAfterLoadGame();
 

	
 
void ConvertOldMultiheadToNew();
 
void ConnectMultiheadedTrains();
 

	
 
extern int32 _saved_scrollpos_x;
 
extern int32 _saved_scrollpos_y;
 

	
 
CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32 face);
 

	
 
Order UnpackOldOrder(uint16 packed);
 

	
 
#endif /* SAVELOAD_INTERNAL_H */
src/saveload/signs_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file signs_sl.cpp Code handling saving and loading of economy data */
 

	
 
#include "../stdafx.h"
 
#include "../strings_func.h"
 
#include "../company_func.h"
 
#include "../signs_base.h"
 
#include "../signs_func.h"
 

	
 
#include "saveload_internal.h"
 
#include "saveload.h"
 

	
 
static const SaveLoad _sign_desc[] = {
 
  SLE_CONDVAR(Sign, name,  SLE_NAME,                   0, 83),
 
  SLE_CONDSTR(Sign, name,  SLE_STR, 0,                84, SL_MAX_VERSION),
 
  SLE_CONDVAR(Sign, x,     SLE_FILE_I16 | SLE_VAR_I32, 0, 4),
 
  SLE_CONDVAR(Sign, y,     SLE_FILE_I16 | SLE_VAR_I32, 0, 4),
 
  SLE_CONDVAR(Sign, x,     SLE_INT32,                  5, SL_MAX_VERSION),
 
  SLE_CONDVAR(Sign, y,     SLE_INT32,                  5, SL_MAX_VERSION),
 
  SLE_CONDVAR(Sign, owner, SLE_UINT8,                  6, SL_MAX_VERSION),
 
      SLE_VAR(Sign, z,     SLE_UINT8),
 
	SLE_END()
 
};
 

	
 
/** Save all signs */
 
static void Save_SIGN()
 
{
 
	Sign *si;
 

	
 
	FOR_ALL_SIGNS(si) {
 
		SlSetArrayIndex(si->index);
 
		SlObject(si, _sign_desc);
 
	}
 
}
 

	
 
/** Load all signs */
 
static void Load_SIGN()
 
{
 
	int index;
 
	while ((index = SlIterateArray()) != -1) {
 
		Sign *si = new (index) Sign();
 
		SlObject(si, _sign_desc);
 
	}
 
}
 

	
 
extern const ChunkHandler _sign_chunk_handlers[] = {
 
	{ 'SIGN', Save_SIGN, Load_SIGN, CH_ARRAY | CH_LAST},
 
};
src/saveload/station_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file station_sl.cpp Code handling saving and loading of economy data */
 

	
 
#include "../stdafx.h"
 
#include "../station_base.h"
 
#include "../core/bitmath_func.hpp"
 
#include "../core/alloc_func.hpp"
 
#include "../variables.h"
 
#include "../newgrf_station.h"
 

	
 
#include "saveload.h"
 

	
 

	
 
void AfterLoadStations()
 
{
 
	/* Update the speclists of all stations to point to the currently loaded custom stations. */
 
	Station *st;
 
	FOR_ALL_STATIONS(st) {
 
		for (uint i = 0; i < st->num_specs; i++) {
 
			if (st->speclist[i].grfid == 0) continue;
 

	
 
			st->speclist[i].spec = GetCustomStationSpecByGrf(st->speclist[i].grfid, st->speclist[i].localidx);
 
		}
 

	
 
		for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache();
 

	
 
		StationUpdateAnimTriggers(st);
 
	}
 
}
 

	
 
static const SaveLoad _roadstop_desc[] = {
 
	SLE_VAR(RoadStop, xy,           SLE_UINT32),
 
	SLE_CONDNULL(1, 0, 44),
 
	SLE_VAR(RoadStop, status,       SLE_UINT8),
 
	/* Index was saved in some versions, but this is not needed */
 
	SLE_CONDNULL(4, 0, 8),
 
	SLE_CONDNULL(2, 0, 44),
 
	SLE_CONDNULL(1, 0, 25),
 

	
 
	SLE_REF(RoadStop, next,         REF_ROADSTOPS),
 
	SLE_CONDNULL(2, 0, 44),
 

	
 
	SLE_CONDNULL(4, 0, 24),
 
	SLE_CONDNULL(1, 25, 25),
 

	
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _station_desc[] = {
 
	SLE_CONDVAR(Station, xy,                         SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Station, xy,                         SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDNULL(4, 0, 5),  ///< bus/lorry tile
 
	SLE_CONDVAR(Station, train_tile,                 SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Station, train_tile,                 SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Station, airport_tile,               SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Station, airport_tile,               SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Station, dock_tile,                  SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Station, dock_tile,                  SLE_UINT32,                  6, SL_MAX_VERSION),
 
	    SLE_REF(Station, town,                       REF_TOWN),
 
	    SLE_VAR(Station, trainst_w,                  SLE_UINT8),
 
	SLE_CONDVAR(Station, trainst_h,                  SLE_UINT8,                   2, SL_MAX_VERSION),
 

	
 
	SLE_CONDNULL(1, 0, 3),  ///< alpha_order
 

	
 
	    SLE_VAR(Station, string_id,                  SLE_STRINGID),
 
	SLE_CONDSTR(Station, name,                       SLE_STR, 0,                 84, SL_MAX_VERSION),
 
	SLE_CONDVAR(Station, indtype,                    SLE_UINT8,                 103, SL_MAX_VERSION),
 
	    SLE_VAR(Station, had_vehicle_of_type,        SLE_UINT16),
 

	
 
	    SLE_VAR(Station, time_since_load,            SLE_UINT8),
 
	    SLE_VAR(Station, time_since_unload,          SLE_UINT8),
 
	    SLE_VAR(Station, delete_ctr,                 SLE_UINT8),
 
	    SLE_VAR(Station, owner,                      SLE_UINT8),
 
	    SLE_VAR(Station, facilities,                 SLE_UINT8),
 
	    SLE_VAR(Station, airport_type,               SLE_UINT8),
 

	
 
	SLE_CONDNULL(2, 0, 5),  ///< Truck/bus stop status
 
	SLE_CONDNULL(1, 0, 4),  ///< Blocked months
 

	
 
	SLE_CONDVAR(Station, airport_flags,              SLE_VAR_U64 | SLE_FILE_U16,  0,  2),
 
	SLE_CONDVAR(Station, airport_flags,              SLE_VAR_U64 | SLE_FILE_U32,  3, 45),
 
	SLE_CONDVAR(Station, airport_flags,              SLE_UINT64,                 46, SL_MAX_VERSION),
 

	
 
	SLE_CONDNULL(2, 0, 25), ///< last-vehicle
 
	SLE_CONDVAR(Station, last_vehicle_type,          SLE_UINT8,                  26, SL_MAX_VERSION),
 

	
 
	SLE_CONDNULL(2, 3, 25), ///< custom station class and id
 
	SLE_CONDVAR(Station, build_date,                 SLE_FILE_U16 | SLE_VAR_I32,  3, 30),
 
	SLE_CONDVAR(Station, build_date,                 SLE_INT32,                  31, SL_MAX_VERSION),
 

	
 
	SLE_CONDREF(Station, bus_stops,                  REF_ROADSTOPS,               6, SL_MAX_VERSION),
 
	SLE_CONDREF(Station, truck_stops,                REF_ROADSTOPS,               6, SL_MAX_VERSION),
 

	
 
	/* Used by newstations for graphic variations */
 
	SLE_CONDVAR(Station, random_bits,                SLE_UINT16,                 27, SL_MAX_VERSION),
 
	SLE_CONDVAR(Station, waiting_triggers,           SLE_UINT8,                  27, SL_MAX_VERSION),
 
	SLE_CONDVAR(Station, num_specs,                  SLE_UINT8,                  27, SL_MAX_VERSION),
 

	
 
	SLE_CONDLST(Station, loading_vehicles,           REF_VEHICLE,                57, SL_MAX_VERSION),
 

	
 
	/* reserve extra space in savegame here. (currently 32 bytes) */
 
	SLE_CONDNULL(32, 2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
static uint16 _waiting_acceptance;
 
static uint16 _cargo_source;
 
static uint32 _cargo_source_xy;
 
static uint16 _cargo_days;
 
static Money  _cargo_feeder_share;
 

	
 
static const SaveLoad _station_speclist_desc[] = {
 
	SLE_CONDVAR(StationSpecList, grfid,    SLE_UINT32, 27, SL_MAX_VERSION),
 
	SLE_CONDVAR(StationSpecList, localidx, SLE_UINT8,  27, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 

	
 
void SaveLoad_STNS(Station *st)
 
{
 
	static const SaveLoad _goods_desc[] = {
 
		SLEG_CONDVAR(            _waiting_acceptance, SLE_UINT16,                  0, 67),
 
		 SLE_CONDVAR(GoodsEntry, acceptance_pickup,   SLE_UINT8,                  68, SL_MAX_VERSION),
 
		SLE_CONDNULL(2,                                                           51, 67),
 
		     SLE_VAR(GoodsEntry, days_since_pickup,   SLE_UINT8),
 
		     SLE_VAR(GoodsEntry, rating,              SLE_UINT8),
 
		SLEG_CONDVAR(            _cargo_source,       SLE_FILE_U8 | SLE_VAR_U16,   0, 6),
 
		SLEG_CONDVAR(            _cargo_source,       SLE_UINT16,                  7, 67),
 
		SLEG_CONDVAR(            _cargo_source_xy,    SLE_UINT32,                 44, 67),
 
		SLEG_CONDVAR(            _cargo_days,         SLE_UINT8,                   0, 67),
 
		     SLE_VAR(GoodsEntry, last_speed,          SLE_UINT8),
 
		     SLE_VAR(GoodsEntry, last_age,            SLE_UINT8),
 
		SLEG_CONDVAR(            _cargo_feeder_share, SLE_FILE_U32 | SLE_VAR_I64, 14, 64),
 
		SLEG_CONDVAR(            _cargo_feeder_share, SLE_INT64,                  65, 67),
 
		 SLE_CONDLST(GoodsEntry, cargo.packets,       REF_CARGO_PACKET,           68, SL_MAX_VERSION),
 

	
 
		SLE_END()
 
	};
 

	
 

	
 
	SlObject(st, _station_desc);
 

	
 
	_waiting_acceptance = 0;
 

	
 
	uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO;
 
	for (CargoID i = 0; i < num_cargo; i++) {
 
		GoodsEntry *ge = &st->goods[i];
 
		SlObject(ge, _goods_desc);
 
		if (CheckSavegameVersion(68)) {
 
			SB(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15));
 
			if (GB(_waiting_acceptance, 0, 12) != 0) {
 
				/* Don't construct the packet with station here, because that'll fail with old savegames */
 
				CargoPacket *cp = new CargoPacket();
 
				/* In old versions, enroute_from used 0xFF as INVALID_STATION */
 
				cp->source          = (CheckSavegameVersion(7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source;
 
				cp->count           = GB(_waiting_acceptance, 0, 12);
 
				cp->days_in_transit = _cargo_days;
 
				cp->feeder_share    = _cargo_feeder_share;
 
				cp->source_xy       = _cargo_source_xy;
 
				cp->days_in_transit = _cargo_days;
 
				cp->feeder_share    = _cargo_feeder_share;
 
				SB(ge->acceptance_pickup, GoodsEntry::PICKUP, 1, 1);
 
				ge->cargo.Append(cp);
 
			}
 
		}
 
	}
 

	
 
	if (st->num_specs != 0) {
 
		/* Allocate speclist memory when loading a game */
 
		if (st->speclist == NULL) st->speclist = CallocT<StationSpecList>(st->num_specs);
 
		for (uint i = 0; i < st->num_specs; i++) {
 
			SlObject(&st->speclist[i], _station_speclist_desc);
 
		}
 
	}
 
}
 

	
 
static void Save_STNS()
 
{
 
	Station *st;
 
	/* Write the stations */
 
	FOR_ALL_STATIONS(st) {
 
		SlSetArrayIndex(st->index);
 
		SlAutolength((AutolengthProc*)SaveLoad_STNS, st);
 
	}
 
}
 

	
 
static void Load_STNS()
 
{
 
	int index;
 
	while ((index = SlIterateArray()) != -1) {
 
		Station *st = new (index) Station();
 

	
 
		SaveLoad_STNS(st);
 
	}
 

	
 
	/* This is to ensure all pointers are within the limits of _stations_size */
 
	if (_station_tick_ctr > GetMaxStationIndex()) _station_tick_ctr = 0;
 
}
 

	
 
static void Save_ROADSTOP()
 
{
 
	RoadStop *rs;
 

	
 
	FOR_ALL_ROADSTOPS(rs) {
 
		SlSetArrayIndex(rs->index);
 
		SlObject(rs, _roadstop_desc);
 
	}
 
}
 

	
 
static void Load_ROADSTOP()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		RoadStop *rs = new (index) RoadStop(INVALID_TILE);
 

	
 
		SlObject(rs, _roadstop_desc);
 
	}
 
}
 

	
 
extern const ChunkHandler _station_chunk_handlers[] = {
 
	{ 'STNS', Save_STNS,      Load_STNS,      CH_ARRAY },
 
	{ 'ROAD', Save_ROADSTOP,  Load_ROADSTOP,  CH_ARRAY | CH_LAST},
 
};
src/saveload/strings_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file strings_sl.cpp Code handling saving and loading of strings */
 

	
 
#include "../stdafx.h"
 
#include "../strings_type.h"
 
#include "../core/math_func.hpp"
 
#include "../core/bitmath_func.hpp"
 
#include "../core/alloc_func.hpp"
 
#include "../string_func.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "saveload.h"
 

	
 
/**
 
 * Remap a string ID from the old format to the new format
 
 * @param s StringID that requires remapping
 
 * @return translated ID
 
 */
 
StringID RemapOldStringID(StringID s)
 
{
 
	switch (s) {
 
		case 0x0006: return STR_SV_EMPTY;
 
		case 0x7000: return STR_SV_UNNAMED;
 
		case 0x70E4: return SPECSTR_PLAYERNAME_ENGLISH;
 
		case 0x70E9: return SPECSTR_PLAYERNAME_ENGLISH;
 
		case 0x8864: return STR_SV_TRAIN_NAME;
 
		case 0x902B: return STR_SV_ROADVEH_NAME;
 
		case 0x9830: return STR_SV_SHIP_NAME;
 
		case 0xA02F: return STR_SV_AIRCRAFT_NAME;
 

	
 
		default:
 
			if (IsInsideMM(s, 0x300F, 0x3030)) {
 
				return s - 0x300F + STR_SV_STNAME;
 
			} else {
 
				return s;
 
			}
 
	}
 
}
 

	
 
/** Location to load the old names to. */
 
char *_old_name_array = NULL;
 

	
 
/**
 
 * Copy and convert old custom names to UTF-8.
 
 * They were all stored in a 512 by 32 long string array and are
 
 * now stored with stations, waypoints and other places with names.
 
 * @param id the StringID of the custom name to clone.
 
 * @return the clones custom name.
 
 */
 
char *CopyFromOldName(StringID id)
 
{
 
	/* Is this name an (old) custom name? */
 
	if (GB(id, 11, 5) != 15) return NULL;
 

	
 
	if (CheckSavegameVersion(37)) {
 
		/* Old names were 32 characters long, so 128 characters should be
 
		 * plenty to allow for expansion when converted to UTF-8. */
 
		char tmp[128];
 
		const char *strfrom = &_old_name_array[32 * GB(id, 0, 9)];
 
		char *strto = tmp;
 

	
 
		for (; *strfrom != '\0'; strfrom++) {
 
			WChar c = (byte)*strfrom;
 

	
 
			/* Map from non-ISO8859-15 characters to UTF-8. */
 
			switch (c) {
 
				case 0xA4: c = 0x20AC; break; // Euro
 
				case 0xA6: c = 0x0160; break; // S with caron
 
				case 0xA8: c = 0x0161; break; // s with caron
 
				case 0xB4: c = 0x017D; break; // Z with caron
 
				case 0xB8: c = 0x017E; break; // z with caron
 
				case 0xBC: c = 0x0152; break; // OE ligature
 
				case 0xBD: c = 0x0153; break; // oe ligature
 
				case 0xBE: c = 0x0178; break; // Y with diaresis
 
				default: break;
 
			}
 

	
 
			/* Check character will fit into our buffer. */
 
			if (strto + Utf8CharLen(c) > lastof(tmp)) break;
 

	
 
			strto += Utf8Encode(strto, c);
 
		}
 

	
 
		/* Terminate the new string and copy it back to the name array */
 
		*strto = '\0';
 

	
 
		return strdup(tmp);
 
	} else {
 
		/* Name will already be in UTF-8. */
 
		return strdup(&_old_name_array[32 * GB(id, 0, 9)]);
 
	}
 
}
 

	
 
/**
 
 * Free the memory of the old names array.
 
 * Should be called once the old names have all been converted.
 
 */
 
void ResetOldNames()
 
{
 
	free(_old_name_array);
 
	_old_name_array = NULL;
 
}
 

	
 
/**
 
 * Initialize the old names table memory.
 
 */
 
void InitializeOldNames()
 
{
 
	free(_old_name_array);
 
	_old_name_array = CallocT<char>(512 * 32);
 
}
 

	
 
static void Load_NAME()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		SlArray(&_old_name_array[32 * index], SlGetFieldLength(), SLE_UINT8);
 
	}
 
}
 

	
 
extern const ChunkHandler _name_chunk_handlers[] = {
 
	{ 'NAME', NULL, Load_NAME, CH_ARRAY | CH_LAST},
 
};
src/saveload/subsidy_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file subsidy_sl.cpp Code handling saving and loading of subsidies */
 

	
 
#include "../stdafx.h"
 
#include "../economy_func.h"
 

	
 
#include "saveload.h"
 

	
 
static const SaveLoad _subsidies_desc[] = {
 
	    SLE_VAR(Subsidy, cargo_type, SLE_UINT8),
 
	    SLE_VAR(Subsidy, age,        SLE_UINT8),
 
	SLE_CONDVAR(Subsidy, from,       SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
 
	SLE_CONDVAR(Subsidy, from,       SLE_UINT16,                5, SL_MAX_VERSION),
 
	SLE_CONDVAR(Subsidy, to,         SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
 
	SLE_CONDVAR(Subsidy, to,         SLE_UINT16,                5, SL_MAX_VERSION),
 
	SLE_END()
 
};
 

	
 
void Save_SUBS()
 
{
 
	int i;
 
	Subsidy *s;
 

	
 
	for (i = 0; i != lengthof(_subsidies); i++) {
 
		s = &_subsidies[i];
 
		if (s->cargo_type != CT_INVALID) {
 
			SlSetArrayIndex(i);
 
			SlObject(s, _subsidies_desc);
 
		}
 
	}
 
}
 

	
 
void Load_SUBS()
 
{
 
	int index;
 
	while ((index = SlIterateArray()) != -1)
 
		SlObject(&_subsidies[index], _subsidies_desc);
 
}
 

	
 
extern const ChunkHandler _subsidy_chunk_handlers[] = {
 
	{ 'SUBS', Save_SUBS,     Load_SUBS,     CH_ARRAY},
 
};
src/saveload/town_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file town_sl.cpp Code handling saving and loading of towns and houses */
 

	
 
#include "../stdafx.h"
 
#include "../town.h"
 
#include "../newgrf_house.h"
 
#include "../newgrf_commons.h"
 
#include "../variables.h"
 
#include "../tile_map.h"
 
#include "../town_map.h"
 

	
 
#include "saveload.h"
 

	
 
extern uint _total_towns;
 

	
 
/**
 
 * Check and update town and house values.
 
 *
 
 * Checked are the HouseIDs. Updated are the
 
 * town population the number of houses per
 
 * town, the town radius and the max passengers
 
 * of the town.
 
 */
 
void UpdateHousesAndTowns()
 
{
 
	Town *town;
 
	InitializeBuildingCounts();
 

	
 
	/* Reset town population and num_houses */
 
	FOR_ALL_TOWNS(town) {
 
		town->population = 0;
 
		town->num_houses = 0;
 
	}
 

	
 
	for (TileIndex t = 0; t < MapSize(); t++) {
 
		HouseID house_id;
 

	
 
		if (!IsTileType(t, MP_HOUSE)) continue;
 

	
 
		house_id = GetHouseType(t);
 
		if (!GetHouseSpecs(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) {
 
			/* The specs for this type of house are not available any more, so
 
			 * replace it with the substitute original house type. */
 
			house_id = _house_mngr.GetSubstituteID(house_id);
 
			SetHouseType(t, house_id);
 
		}
 

	
 
		town = GetTownByTile(t);
 
		IncreaseBuildingCount(town, house_id);
 
		if (IsHouseCompleted(t)) town->population += GetHouseSpecs(house_id)->population;
 

	
 
		/* Increase the number of houses for every house, but only once. */
 
		if (GetHouseNorthPart(house_id) == 0) town->num_houses++;
 
	}
 

	
 
	/* Update the population and num_house dependant values */
 
	FOR_ALL_TOWNS(town) {
 
		UpdateTownRadius(town);
 
		UpdateTownMaxPass(town);
 
	}
 
}
 

	
 
/** Save and load of towns. */
 
static const SaveLoad _town_desc[] = {
 
	SLE_CONDVAR(Town, xy,                    SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
 
	SLE_CONDVAR(Town, xy,                    SLE_UINT32,                 6, SL_MAX_VERSION),
 

	
 
	SLE_CONDNULL(2, 0, 2),                   ///< population, no longer in use
 
	SLE_CONDNULL(4, 3, 84),                  ///< population, no longer in use
 
	SLE_CONDNULL(2, 0, 91),                  ///< num_houses, no longer in use
 

	
 
	SLE_CONDVAR(Town, townnamegrfid,         SLE_UINT32, 66, SL_MAX_VERSION),
 
	    SLE_VAR(Town, townnametype,          SLE_UINT16),
 
	    SLE_VAR(Town, townnameparts,         SLE_UINT32),
 
	SLE_CONDSTR(Town, name,                  SLE_STR, 0, 84, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(Town, flags12,               SLE_UINT8),
 
	SLE_CONDVAR(Town, statues,               SLE_FILE_U8  | SLE_VAR_U16, 0, 103),
 
	SLE_CONDVAR(Town, statues,               SLE_UINT16,               104, SL_MAX_VERSION),
 

	
 
	SLE_CONDNULL(1, 0, 1),                   ///< sort_index, no longer in use
 

	
 
	SLE_CONDVAR(Town, have_ratings,          SLE_FILE_U8  | SLE_VAR_U16, 0, 103),
 
	SLE_CONDVAR(Town, have_ratings,          SLE_UINT16,               104, SL_MAX_VERSION),
 
	SLE_CONDARR(Town, ratings,               SLE_INT16, 8,               0, 103),
 
	SLE_CONDARR(Town, ratings,               SLE_INT16, MAX_COMPANIES, 104, SL_MAX_VERSION),
 
	/* failed bribe attempts are stored since savegame format 4 */
 
	SLE_CONDARR(Town, unwanted,              SLE_INT8,  8,               4, 103),
 
	SLE_CONDARR(Town, unwanted,              SLE_INT8,  MAX_COMPANIES, 104, SL_MAX_VERSION),
 

	
 
	SLE_CONDVAR(Town, max_pass,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 
	SLE_CONDVAR(Town, max_mail,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 
	SLE_CONDVAR(Town, new_max_pass,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 
	SLE_CONDVAR(Town, new_max_mail,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 
	SLE_CONDVAR(Town, act_pass,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 
	SLE_CONDVAR(Town, act_mail,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 
	SLE_CONDVAR(Town, new_act_pass,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 
	SLE_CONDVAR(Town, new_act_mail,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 

	
 
	SLE_CONDVAR(Town, max_pass,              SLE_UINT32,                 9, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, max_mail,              SLE_UINT32,                 9, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, new_max_pass,          SLE_UINT32,                 9, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, new_max_mail,          SLE_UINT32,                 9, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, act_pass,              SLE_UINT32,                 9, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, act_mail,              SLE_UINT32,                 9, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, new_act_pass,          SLE_UINT32,                 9, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, new_act_mail,          SLE_UINT32,                 9, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(Town, pct_pass_transported,  SLE_UINT8),
 
	    SLE_VAR(Town, pct_mail_transported,  SLE_UINT8),
 

	
 
	    SLE_VAR(Town, act_food,              SLE_UINT16),
 
	    SLE_VAR(Town, act_water,             SLE_UINT16),
 
	    SLE_VAR(Town, new_act_food,          SLE_UINT16),
 
	    SLE_VAR(Town, new_act_water,         SLE_UINT16),
 

	
 
	SLE_CONDVAR(Town, time_until_rebuild,    SLE_UINT8,                  0, 53),
 
	SLE_CONDVAR(Town, grow_counter,          SLE_UINT8,                  0, 53),
 
	SLE_CONDVAR(Town, growth_rate,           SLE_UINT8,                  0, 53),
 

	
 
	SLE_CONDVAR(Town, time_until_rebuild,    SLE_UINT16,                54, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, grow_counter,          SLE_UINT16,                54, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, growth_rate,           SLE_INT16,                 54, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(Town, fund_buildings_months, SLE_UINT8),
 
	    SLE_VAR(Town, road_build_months,     SLE_UINT8),
 

	
 
	SLE_CONDVAR(Town, exclusivity,           SLE_UINT8,                  2, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, exclusive_counter,     SLE_UINT8,                  2, SL_MAX_VERSION),
 

	
 
	SLE_CONDVAR(Town, larger_town,           SLE_BOOL,                  56, SL_MAX_VERSION),
 

	
 
	/* reserve extra space in savegame here. (currently 30 bytes) */
 
	SLE_CONDNULL(30, 2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
/* Save and load the mapping between the house id on the map, and the grf file
 
 * it came from. */
 
static const SaveLoad _house_id_mapping_desc[] = {
 
	SLE_VAR(EntityIDMapping, grfid,         SLE_UINT32),
 
	SLE_VAR(EntityIDMapping, entity_id,     SLE_UINT8),
 
	SLE_VAR(EntityIDMapping, substitute_id, SLE_UINT8),
 
	SLE_END()
 
};
 

	
 
static void Save_HOUSEIDS()
 
{
 
	uint j = _house_mngr.GetMaxMapping();
 

	
 
	for (uint i = 0; i < j; i++) {
 
		SlSetArrayIndex(i);
 
		SlObject(&_house_mngr.mapping_ID[i], _house_id_mapping_desc);
 
	}
 
}
 

	
 
static void Load_HOUSEIDS()
 
{
 
	int index;
 

	
 
	_house_mngr.ResetMapping();
 
	uint max_id = _house_mngr.GetMaxMapping();
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		if ((uint)index >= max_id) break;
 
		SlObject(&_house_mngr.mapping_ID[index], _house_id_mapping_desc);
 
	}
 
}
 

	
 
static void Save_TOWN()
 
{
 
	Town *t;
 

	
 
	FOR_ALL_TOWNS(t) {
 
		SlSetArrayIndex(t->index);
 
		SlObject(t, _town_desc);
 
	}
 
}
 

	
 
static void Load_TOWN()
 
{
 
	int index;
 

	
 
	_total_towns = 0;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		Town *t = new (index) Town();
 
		SlObject(t, _town_desc);
 

	
 
		_total_towns++;
 
	}
 

	
 
	/* This is to ensure all pointers are within the limits of
 
	 *  the size of the TownPool */
 
	if (_cur_town_ctr > GetMaxTownIndex())
 
		_cur_town_ctr = 0;
 
}
 

	
 
void AfterLoadTown()
 
{
 
	Town *t;
 
	FOR_ALL_TOWNS(t) t->InitializeLayout();
 
}
 

	
 
extern const ChunkHandler _town_chunk_handlers[] = {
 
	{ 'HIDS', Save_HOUSEIDS, Load_HOUSEIDS, CH_ARRAY },
 
	{ 'CITY', Save_TOWN,     Load_TOWN,     CH_ARRAY | CH_LAST},
 
};
src/saveload/vehicle_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file vehicle_sl.cpp Code handling saving and loading of vehicles */
 

	
 
#include "../stdafx.h"
 
#include "../vehicle_base.h"
 
#include "../vehicle_func.h"
 
#include "../train.h"
 
#include "../roadveh.h"
 
#include "../ship.h"
 
#include "../aircraft.h"
 
#include "../effectvehicle_base.h"
 

	
 
#include "saveload.h"
 

	
 
#include <map>
 

	
 
/*
 
 * Link front and rear multiheaded engines to each other
 
 * This is done when loading a savegame
 
 */
 
void ConnectMultiheadedTrains()
 
{
 
	Vehicle *v;
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN) {
 
			v->u.rail.other_multiheaded_part = NULL;
 
		}
 
	}
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) {
 
			/* Two ways to associate multiheaded parts to each other:
 
			 * sequential-matching: Trains shall be arranged to look like <..>..<..>..<..>..
 
			 * bracket-matching:    Free vehicle chains shall be arranged to look like ..<..<..>..<..>..>..
 
			 *
 
			 * Note: Old savegames might contain chains which do not comply with these rules, e.g.
 
			 *   - the front and read parts have invalid orders
 
			 *   - different engine types might be combined
 
			 *   - there might be different amounts of front and rear parts.
 
			 *
 
			 * Note: The multiheaded parts need to be matched exactly like they are matched on the server, else desyncs will occur.
 
			 *   This is why two matching strategies are needed.
 
			 */
 

	
 
			bool sequential_matching = IsFrontEngine(v);
 

	
 
			for (Vehicle *u = v; u != NULL; u = GetNextVehicle(u)) {
 
				if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one
 

	
 
				if (IsMultiheaded(u)) {
 
					if (!IsTrainEngine(u)) {
 
						/* we got a rear car without a front car. We will convert it to a front one */
 
						SetTrainEngine(u);
 
						u->spritenum--;
 
					}
 

	
 
					/* Find a matching back part */
 
					EngineID eid = u->engine_type;
 
					Vehicle *w;
 
					if (sequential_matching) {
 
						for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) {
 
							if (w->engine_type != eid || w->u.rail.other_multiheaded_part != NULL || !IsMultiheaded(w)) continue;
 

	
 
							/* we found a car to partner with this engine. Now we will make sure it face the right way */
 
							if (IsTrainEngine(w)) {
 
								ClearTrainEngine(w);
 
								w->spritenum++;
 
							}
 
							break;
 
						}
 
					} else {
 
						uint stack_pos = 0;
 
						for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) {
 
							if (w->engine_type != eid || w->u.rail.other_multiheaded_part != NULL || !IsMultiheaded(w)) continue;
 

	
 
							if (IsTrainEngine(w)) {
 
								stack_pos++;
 
							} else {
 
								if (stack_pos == 0) break;
 
								stack_pos--;
 
							}
 
						}
 
					}
 

	
 
					if (w != NULL) {
 
						w->u.rail.other_multiheaded_part = u;
 
						u->u.rail.other_multiheaded_part = w;
 
					} else {
 
						/* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */
 
						ClearMultiheaded(u);
 
					}
 
				}
 
			}
 
		}
 
	}
 
}
 

	
 
/**
 
 *  Converts all trains to the new subtype format introduced in savegame 16.2
 
 *  It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found
 
 */
 
void ConvertOldMultiheadToNew()
 
{
 
	Vehicle *v;
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN) {
 
			SetBit(v->subtype, 7); // indicates that it's the old format and needs to be converted in the next loop
 
		}
 
	}
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN) {
 
			if (HasBit(v->subtype, 7) && ((v->subtype & ~0x80) == 0 || (v->subtype & ~0x80) == 4)) {
 
				for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
					const RailVehicleInfo *rvi = RailVehInfo(u->engine_type);
 

	
 
					ClrBit(u->subtype, 7);
 
					switch (u->subtype) {
 
						case 0: /* TS_Front_Engine */
 
							if (rvi->railveh_type == RAILVEH_MULTIHEAD) SetMultiheaded(u);
 
							SetFrontEngine(u);
 
							SetTrainEngine(u);
 
							break;
 

	
 
						case 1: /* TS_Artic_Part */
 
							u->subtype = 0;
 
							SetArticulatedPart(u);
 
							break;
 

	
 
						case 2: /* TS_Not_First */
 
							u->subtype = 0;
 
							if (rvi->railveh_type == RAILVEH_WAGON) {
 
								// normal wagon
 
								SetTrainWagon(u);
 
								break;
 
							}
 
							if (rvi->railveh_type == RAILVEH_MULTIHEAD && rvi->image_index == u->spritenum - 1) {
 
								// rear end of a multiheaded engine
 
								SetMultiheaded(u);
 
								break;
 
							}
 
							if (rvi->railveh_type == RAILVEH_MULTIHEAD) SetMultiheaded(u);
 
							SetTrainEngine(u);
 
							break;
 

	
 
						case 4: /* TS_Free_Car */
 
							u->subtype = 0;
 
							SetTrainWagon(u);
 
							SetFreeWagon(u);
 
							break;
 
						default: NOT_REACHED(); break;
 
					}
 
				}
 
			}
 
		}
 
	}
 
}
 

	
 

	
 
/** need to be called to load aircraft from old version */
 
void UpdateOldAircraft()
 
{
 
	/* set airport_flags to 0 for all airports just to be sure */
 
	Station *st;
 
	FOR_ALL_STATIONS(st) {
 
		st->airport_flags = 0; // reset airport
 
	}
 

	
 
	Vehicle *v_oldstyle;
 
	FOR_ALL_VEHICLES(v_oldstyle) {
 
	/* airplane has another vehicle with subtype 4 (shadow), helicopter also has 3 (rotor)
 
	 * skip those */
 
		if (v_oldstyle->type == VEH_AIRCRAFT && IsNormalAircraft(v_oldstyle)) {
 
			/* airplane in terminal stopped doesn't hurt anyone, so goto next */
 
			if (v_oldstyle->vehstatus & VS_STOPPED && v_oldstyle->u.air.state == 0) {
 
				v_oldstyle->u.air.state = HANGAR;
 
				continue;
 
			}
 

	
 
			AircraftLeaveHangar(v_oldstyle); // make airplane visible if it was in a depot for example
 
			v_oldstyle->vehstatus &= ~VS_STOPPED; // make airplane moving
 
			v_oldstyle->u.air.state = FLYING;
 
			AircraftNextAirportPos_and_Order(v_oldstyle); // move it to the entry point of the airport
 
			GetNewVehiclePosResult gp = GetNewVehiclePos(v_oldstyle);
 
			v_oldstyle->tile = 0; // aircraft in air is tile=0
 

	
 
			/* correct speed of helicopter-rotors */
 
			if (v_oldstyle->subtype == AIR_HELICOPTER) v_oldstyle->Next()->Next()->cur_speed = 32;
 

	
 
			/* set new position x,y,z */
 
			SetAircraftPosition(v_oldstyle, gp.x, gp.y, GetAircraftFlyingAltitude(v_oldstyle));
 
		}
 
	}
 
}
 

	
 
/** Called after load to update coordinates */
 
void AfterLoadVehicles(bool part_of_load)
 
{
 
	Vehicle *v;
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		/* Reinstate the previous pointer */
 
		if (v->Next() != NULL) v->Next()->previous = v;
 
		if (v->NextShared() != NULL) v->NextShared()->previous_shared = v;
 

	
 
		v->UpdateDeltaXY(v->direction);
 

	
 
		if (part_of_load) v->fill_percent_te_id = INVALID_TE_ID;
 
		v->first = NULL;
 
		if (v->type == VEH_TRAIN) v->u.rail.first_engine = INVALID_ENGINE;
 
		if (v->type == VEH_ROAD)  v->u.road.first_engine = INVALID_ENGINE;
 

	
 
		v->cargo.InvalidateCache();
 
	}
 

	
 
	/* AfterLoadVehicles may also be called in case of NewGRF reload, in this
 
	 * case we may not convert orders again. */
 
	if (part_of_load) {
 
		/* Create shared vehicle chain for very old games (pre 5,2) and create
 
		 * OrderList from shared vehicle chains. For this to work correctly, the
 
		 * following conditions must be fulfilled:
 
		 * a) both next_shared and previous_shared are not set for pre 5,2 games
 
		 * b) both next_shared and previous_shared are set for later games
 
		 */
 
		std::map<Order*, OrderList*> mapping;
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->orders.old != NULL) {
 
				if (CheckSavegameVersion(105)) { // Pre-105 didn't save an OrderList
 
					if (mapping[v->orders.old] == NULL) {
 
						/* This adds the whole shared vehicle chain for case b */
 
						v->orders.list = mapping[v->orders.old] = new OrderList(v->orders.old, v);
 
					} else {
 
						v->orders.list = mapping[v->orders.old];
 
						/* For old games (case a) we must create the shared vehicle chain */
 
						if (CheckSavegameVersionOldStyle(5, 2)) {
 
							v->AddToShared(v->orders.list->GetFirstSharedVehicle());
 
						}
 
					}
 
				} else { // OrderList was saved as such, only recalculate not saved values
 
					if (v->PreviousShared() == NULL) {
 
						new (v->orders.list) OrderList(v->orders.list->GetFirstOrder(), v);
 
					}
 
				}
 
			}
 
		}
 
	}
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		/* Fill the first pointers */
 
		if (v->Previous() == NULL) {
 
			for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
				u->first = v;
 
			}
 
		}
 
	}
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		assert(v->first != NULL);
 

	
 
		if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) {
 
			if (IsFrontEngine(v)) v->u.rail.last_speed = v->cur_speed; // update displayed train speed
 
			TrainConsistChanged(v, false);
 
		} else if (v->type == VEH_ROAD && IsRoadVehFront(v)) {
 
			RoadVehUpdateCache(v);
 
		}
 
	}
 

	
 
	/* Stop non-front engines */
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN && IsTrainEngine(v) && !IsFrontEngine(v)) v->vehstatus |= VS_STOPPED;
 
	}
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		switch (v->type) {
 
			case VEH_ROAD:
 
				v->u.road.roadtype = HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
 
				v->u.road.compatible_roadtypes = RoadTypeToRoadTypes(v->u.road.roadtype);
 
				/* FALL THROUGH */
 
			case VEH_TRAIN:
 
			case VEH_SHIP:
 
				v->cur_image = v->GetImage(v->direction);
 
				break;
 

	
 
			case VEH_AIRCRAFT:
 
				if (IsNormalAircraft(v)) {
 
					v->cur_image = v->GetImage(v->direction);
 

	
 
					/* The plane's shadow will have the same image as the plane */
 
					Vehicle *shadow = v->Next();
 
					shadow->cur_image = v->cur_image;
 

	
 
					/* In the case of a helicopter we will update the rotor sprites */
 
					if (v->subtype == AIR_HELICOPTER) {
 
						Vehicle *rotor = shadow->Next();
 
						rotor->cur_image = GetRotorImage(v);
 
					}
 

	
 
					UpdateAircraftCache(v);
 
				}
 
				break;
 
			default: break;
 
		}
 

	
 
		v->left_coord = INVALID_COORD;
 
		VehiclePositionChanged(v);
 
	}
 
}
 

	
 
static uint8  _cargo_days;
 
static uint16 _cargo_source;
 
static uint32 _cargo_source_xy;
 
static uint16 _cargo_count;
 
static uint16 _cargo_paid_for;
 
static Money  _cargo_feeder_share;
 
static uint32 _cargo_loaded_at_xy;
 

	
 
/**
 
 * Make it possible to make the saveload tables "friends" of other classes.
 
 * @param vt the vehicle type. Can be VEH_END for the common vehicle description data
 
 * @return the saveload description
 
 */
 
const SaveLoad *GetVehicleDescription(VehicleType vt)
 
{
 
	/** Save and load of vehicles */
 
	static const SaveLoad _common_veh_desc[] = {
 
		     SLE_VAR(Vehicle, subtype,               SLE_UINT8),
 

	
 
		     SLE_REF(Vehicle, next,                  REF_VEHICLE_OLD),
 
		 SLE_CONDVAR(Vehicle, name,                  SLE_NAME,                     0,  83),
 
		 SLE_CONDSTR(Vehicle, name,                  SLE_STR, 0,                  84, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, unitnumber,            SLE_FILE_U8  | SLE_VAR_U16,   0,   7),
 
		 SLE_CONDVAR(Vehicle, unitnumber,            SLE_UINT16,                   8, SL_MAX_VERSION),
 
		     SLE_VAR(Vehicle, owner,                 SLE_UINT8),
 
		 SLE_CONDVAR(Vehicle, tile,                  SLE_FILE_U16 | SLE_VAR_U32,   0,   5),
 
		 SLE_CONDVAR(Vehicle, tile,                  SLE_UINT32,                   6, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, dest_tile,             SLE_FILE_U16 | SLE_VAR_U32,   0,   5),
 
		 SLE_CONDVAR(Vehicle, dest_tile,             SLE_UINT32,                   6, SL_MAX_VERSION),
 

	
 
		 SLE_CONDVAR(Vehicle, x_pos,                 SLE_FILE_U16 | SLE_VAR_U32,   0,   5),
 
		 SLE_CONDVAR(Vehicle, x_pos,                 SLE_UINT32,                   6, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, y_pos,                 SLE_FILE_U16 | SLE_VAR_U32,   0,   5),
 
		 SLE_CONDVAR(Vehicle, y_pos,                 SLE_UINT32,                   6, SL_MAX_VERSION),
 
		     SLE_VAR(Vehicle, z_pos,                 SLE_UINT8),
 
		     SLE_VAR(Vehicle, direction,             SLE_UINT8),
 

	
 
		SLE_CONDNULL(2,                                                            0,  57),
 
		     SLE_VAR(Vehicle, spritenum,             SLE_UINT8),
 
		SLE_CONDNULL(5,                                                            0,  57),
 
		     SLE_VAR(Vehicle, engine_type,           SLE_UINT16),
 

	
 
		     SLE_VAR(Vehicle, max_speed,             SLE_UINT16),
 
		     SLE_VAR(Vehicle, cur_speed,             SLE_UINT16),
 
		     SLE_VAR(Vehicle, subspeed,              SLE_UINT8),
 
		     SLE_VAR(Vehicle, acceleration,          SLE_UINT8),
 
		     SLE_VAR(Vehicle, progress,              SLE_UINT8),
 

	
 
		     SLE_VAR(Vehicle, vehstatus,             SLE_UINT8),
 
		 SLE_CONDVAR(Vehicle, last_station_visited,  SLE_FILE_U8  | SLE_VAR_U16,   0,   4),
 
		 SLE_CONDVAR(Vehicle, last_station_visited,  SLE_UINT16,                   5, SL_MAX_VERSION),
 

	
 
		     SLE_VAR(Vehicle, cargo_type,            SLE_UINT8),
 
		 SLE_CONDVAR(Vehicle, cargo_subtype,         SLE_UINT8,                   35, SL_MAX_VERSION),
 
		SLEG_CONDVAR(         _cargo_days,           SLE_UINT8,                    0,  67),
 
		SLEG_CONDVAR(         _cargo_source,         SLE_FILE_U8  | SLE_VAR_U16,   0,   6),
 
		SLEG_CONDVAR(         _cargo_source,         SLE_UINT16,                   7,  67),
 
		SLEG_CONDVAR(         _cargo_source_xy,      SLE_UINT32,                  44,  67),
 
		     SLE_VAR(Vehicle, cargo_cap,             SLE_UINT16),
 
		SLEG_CONDVAR(         _cargo_count,          SLE_UINT16,                   0,  67),
 
		 SLE_CONDLST(Vehicle, cargo,                 REF_CARGO_PACKET,            68, SL_MAX_VERSION),
 

	
 
		     SLE_VAR(Vehicle, day_counter,           SLE_UINT8),
 
		     SLE_VAR(Vehicle, tick_counter,          SLE_UINT8),
 
		 SLE_CONDVAR(Vehicle, running_ticks,         SLE_UINT8,                   88, SL_MAX_VERSION),
 

	
 
		     SLE_VAR(Vehicle, cur_order_index,       SLE_UINT8),
 
		/* num_orders is now part of OrderList and is not saved but counted */
 
		SLE_CONDNULL(1,                                                            0, 104),
 

	
 
		/* This next line is for version 4 and prior compatibility.. it temporarily reads
 
		 type and flags (which were both 4 bits) into type. Later on this is
 
		 converted correctly */
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, type),           SLE_UINT8,                    0,   4),
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest),           SLE_FILE_U8  | SLE_VAR_U16,   0,   4),
 

	
 
		/* Orders for version 5 and on */
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, type),           SLE_UINT8,                    5, SL_MAX_VERSION),
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, flags),          SLE_UINT8,                    5, SL_MAX_VERSION),
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest),           SLE_UINT16,                   5, SL_MAX_VERSION),
 

	
 
		/* Refit in current order */
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, refit_cargo),    SLE_UINT8,                   36, SL_MAX_VERSION),
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, refit_subtype),  SLE_UINT8,                   36, SL_MAX_VERSION),
 

	
 
		/* Timetable in current order */
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, wait_time),      SLE_UINT16,                  67, SL_MAX_VERSION),
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, travel_time),    SLE_UINT16,                  67, SL_MAX_VERSION),
 

	
 
		 SLE_CONDREF(Vehicle, orders,                REF_ORDER,                    0, 104),
 
		 SLE_CONDREF(Vehicle, orders,                REF_ORDERLIST,              105, SL_MAX_VERSION),
 

	
 
		 SLE_CONDVAR(Vehicle, age,                   SLE_FILE_U16 | SLE_VAR_I32,   0,  30),
 
		 SLE_CONDVAR(Vehicle, age,                   SLE_INT32,                   31, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, max_age,               SLE_FILE_U16 | SLE_VAR_I32,   0,  30),
 
		 SLE_CONDVAR(Vehicle, max_age,               SLE_INT32,                   31, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, date_of_last_service,  SLE_FILE_U16 | SLE_VAR_I32,   0,  30),
 
		 SLE_CONDVAR(Vehicle, date_of_last_service,  SLE_INT32,                   31, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, service_interval,      SLE_FILE_U16 | SLE_VAR_I32,   0,  30),
 
		 SLE_CONDVAR(Vehicle, service_interval,      SLE_INT32,                   31, SL_MAX_VERSION),
 
		     SLE_VAR(Vehicle, reliability,           SLE_UINT16),
 
		     SLE_VAR(Vehicle, reliability_spd_dec,   SLE_UINT16),
 
		     SLE_VAR(Vehicle, breakdown_ctr,         SLE_UINT8),
 
		     SLE_VAR(Vehicle, breakdown_delay,       SLE_UINT8),
 
		     SLE_VAR(Vehicle, breakdowns_since_last_service, SLE_UINT8),
 
		     SLE_VAR(Vehicle, breakdown_chance,      SLE_UINT8),
 
		 SLE_CONDVAR(Vehicle, build_year,            SLE_FILE_U8 | SLE_VAR_I32,    0,  30),
 
		 SLE_CONDVAR(Vehicle, build_year,            SLE_INT32,                   31, SL_MAX_VERSION),
 

	
 
		     SLE_VAR(Vehicle, load_unload_time_rem,  SLE_UINT16),
 
		SLEG_CONDVAR(         _cargo_paid_for,       SLE_UINT16,                  45, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, vehicle_flags,         SLE_UINT8,                   40, SL_MAX_VERSION),
 

	
 
		 SLE_CONDVAR(Vehicle, profit_this_year,      SLE_FILE_I32 | SLE_VAR_I64,   0,  64),
 
		 SLE_CONDVAR(Vehicle, profit_this_year,      SLE_INT64,                   65, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, profit_last_year,      SLE_FILE_I32 | SLE_VAR_I64,   0,  64),
 
		 SLE_CONDVAR(Vehicle, profit_last_year,      SLE_INT64,                   65, SL_MAX_VERSION),
 
		SLEG_CONDVAR(         _cargo_feeder_share,   SLE_FILE_I32 | SLE_VAR_I64,  51,  64),
 
		SLEG_CONDVAR(         _cargo_feeder_share,   SLE_INT64,                   65,  67),
 
		SLEG_CONDVAR(         _cargo_loaded_at_xy,   SLE_UINT32,                  51,  67),
 
		 SLE_CONDVAR(Vehicle, value,                 SLE_FILE_I32 | SLE_VAR_I64,   0,  64),
 
		 SLE_CONDVAR(Vehicle, value,                 SLE_INT64,                   65, SL_MAX_VERSION),
 

	
 
		 SLE_CONDVAR(Vehicle, random_bits,           SLE_UINT8,                    2, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, waiting_triggers,      SLE_UINT8,                    2, SL_MAX_VERSION),
 

	
 
		 SLE_CONDREF(Vehicle, next_shared,           REF_VEHICLE,                  2, SL_MAX_VERSION),
 
		SLE_CONDNULL(2,                                                            2,  68),
 
		SLE_CONDNULL(4,                                                           69, 100),
 

	
 
		 SLE_CONDVAR(Vehicle, group_id,              SLE_UINT16,                  60, SL_MAX_VERSION),
 

	
 
		 SLE_CONDVAR(Vehicle, current_order_time,    SLE_UINT32,                  67, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, lateness_counter,      SLE_INT32,                   67, SL_MAX_VERSION),
 

	
 
		/* reserve extra space in savegame here. (currently 10 bytes) */
 
		SLE_CONDNULL(10,                                                           2, SL_MAX_VERSION),
 

	
 
		     SLE_END()
 
	};
 

	
 

	
 
	static const SaveLoad _train_desc[] = {
 
		SLE_WRITEBYTE(Vehicle, type, VEH_TRAIN),
 
		SLE_VEH_INCLUDEX(),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, crash_anim_pos),      SLE_UINT16),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, force_proceed),       SLE_UINT8),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, railtype),            SLE_UINT8),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, track),               SLE_UINT8),
 

	
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, flags),               SLE_FILE_U8  | SLE_VAR_U16,   2,  99),
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, flags),               SLE_UINT16,                 100, SL_MAX_VERSION),
 
		SLE_CONDNULL(2, 2, 59),
 

	
 
		SLE_CONDNULL(2, 2, 19),
 
		/* reserve extra space in savegame here. (currently 11 bytes) */
 
		SLE_CONDNULL(11, 2, SL_MAX_VERSION),
 

	
 
		     SLE_END()
 
	};
 

	
 
	static const SaveLoad _roadveh_desc[] = {
 
		SLE_WRITEBYTE(Vehicle, type, VEH_ROAD),
 
		SLE_VEH_INCLUDEX(),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, state),                SLE_UINT8),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, frame),                SLE_UINT8),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, blocked_ctr),          SLE_UINT16),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, overtaking),           SLE_UINT8),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, overtaking_ctr),       SLE_UINT8),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, crashed_ctr),          SLE_UINT16),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, reverse_ctr),          SLE_UINT8),
 

	
 
		SLE_CONDREFX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, slot),                 REF_ROADSTOPS,                6, SL_MAX_VERSION),
 
		SLE_CONDNULL(1,                                                            6, SL_MAX_VERSION),
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, slot_age),             SLE_UINT8,                    6, SL_MAX_VERSION),
 
		/* reserve extra space in savegame here. (currently 16 bytes) */
 
		SLE_CONDNULL(16,                                                           2, SL_MAX_VERSION),
 

	
 
		     SLE_END()
 
	};
 

	
 
	static const SaveLoad _ship_desc[] = {
 
		SLE_WRITEBYTE(Vehicle, type, VEH_SHIP),
 
		SLE_VEH_INCLUDEX(),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleShip, state),  SLE_UINT8),
 

	
 
		/* reserve extra space in savegame here. (currently 16 bytes) */
 
		SLE_CONDNULL(16, 2, SL_MAX_VERSION),
 

	
 
		     SLE_END()
 
	};
 

	
 
	static const SaveLoad _aircraft_desc[] = {
 
		SLE_WRITEBYTE(Vehicle, type, VEH_AIRCRAFT),
 
		SLE_VEH_INCLUDEX(),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, crashed_counter),       SLE_UINT16),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, pos),                   SLE_UINT8),
 

	
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, targetairport),         SLE_FILE_U8  | SLE_VAR_U16,   0, 4),
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, targetairport),         SLE_UINT16,                   5, SL_MAX_VERSION),
 

	
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, state),                 SLE_UINT8),
 

	
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, previous_pos),          SLE_UINT8,                    2, SL_MAX_VERSION),
 

	
 
		/* reserve extra space in savegame here. (currently 15 bytes) */
 
		SLE_CONDNULL(15,                                                           2, SL_MAX_VERSION),
 

	
 
		     SLE_END()
 
	};
 

	
 
	static const SaveLoad _special_desc[] = {
 
		SLE_WRITEBYTE(Vehicle, type, VEH_EFFECT),
 

	
 
		     SLE_VAR(Vehicle, subtype,               SLE_UINT8),
 

	
 
		 SLE_CONDVAR(Vehicle, tile,                  SLE_FILE_U16 | SLE_VAR_U32,   0,   5),
 
		 SLE_CONDVAR(Vehicle, tile,                  SLE_UINT32,                   6, SL_MAX_VERSION),
 

	
 
		 SLE_CONDVAR(Vehicle, x_pos,                 SLE_FILE_I16 | SLE_VAR_I32,   0,   5),
 
		 SLE_CONDVAR(Vehicle, x_pos,                 SLE_INT32,                    6, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, y_pos,                 SLE_FILE_I16 | SLE_VAR_I32,   0,   5),
 
		 SLE_CONDVAR(Vehicle, y_pos,                 SLE_INT32,                    6, SL_MAX_VERSION),
 
		     SLE_VAR(Vehicle, z_pos,                 SLE_UINT8),
 

	
 
		     SLE_VAR(Vehicle, cur_image,             SLE_UINT16),
 
		SLE_CONDNULL(5,                                                            0,  57),
 
		     SLE_VAR(Vehicle, progress,              SLE_UINT8),
 
		     SLE_VAR(Vehicle, vehstatus,             SLE_UINT8),
 

	
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleEffect, animation_state),    SLE_UINT16),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleEffect, animation_substate), SLE_UINT8),
 

	
 
		 SLE_CONDVAR(Vehicle, spritenum,             SLE_UINT8,                    2, SL_MAX_VERSION),
 

	
 
		/* reserve extra space in savegame here. (currently 15 bytes) */
 
		SLE_CONDNULL(15,                                                           2, SL_MAX_VERSION),
 

	
 
		     SLE_END()
 
	};
 

	
 
	static const SaveLoad _disaster_desc[] = {
 
		SLE_WRITEBYTE(Vehicle, type, VEH_DISASTER),
 

	
 
		     SLE_REF(Vehicle, next,                  REF_VEHICLE_OLD),
 

	
 
		     SLE_VAR(Vehicle, subtype,               SLE_UINT8),
 
		 SLE_CONDVAR(Vehicle, tile,                  SLE_FILE_U16 | SLE_VAR_U32,   0,   5),
 
		 SLE_CONDVAR(Vehicle, tile,                  SLE_UINT32,                   6, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, dest_tile,             SLE_FILE_U16 | SLE_VAR_U32,   0,   5),
 
		 SLE_CONDVAR(Vehicle, dest_tile,             SLE_UINT32,                   6, SL_MAX_VERSION),
 

	
 
		 SLE_CONDVAR(Vehicle, x_pos,                 SLE_FILE_I16 | SLE_VAR_I32,   0,   5),
 
		 SLE_CONDVAR(Vehicle, x_pos,                 SLE_INT32,                    6, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, y_pos,                 SLE_FILE_I16 | SLE_VAR_I32,   0,   5),
 
		 SLE_CONDVAR(Vehicle, y_pos,                 SLE_INT32,                    6, SL_MAX_VERSION),
 
		     SLE_VAR(Vehicle, z_pos,                 SLE_UINT8),
 
		     SLE_VAR(Vehicle, direction,             SLE_UINT8),
 

	
 
		SLE_CONDNULL(5,                                                            0,  57),
 
		     SLE_VAR(Vehicle, owner,                 SLE_UINT8),
 
		     SLE_VAR(Vehicle, vehstatus,             SLE_UINT8),
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest),           SLE_FILE_U8 | SLE_VAR_U16,   0,   4),
 
		SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest),           SLE_UINT16,                  5, SL_MAX_VERSION),
 

	
 
		     SLE_VAR(Vehicle, cur_image,             SLE_UINT16),
 
		 SLE_CONDVAR(Vehicle, age,                   SLE_FILE_U16 | SLE_VAR_I32,   0,  30),
 
		 SLE_CONDVAR(Vehicle, age,                   SLE_INT32,                   31, SL_MAX_VERSION),
 
		     SLE_VAR(Vehicle, tick_counter,          SLE_UINT8),
 

	
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, image_override),            SLE_UINT16),
 
		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, big_ufo_destroyer_target),  SLE_UINT16),
 

	
 
		/* reserve extra space in savegame here. (currently 16 bytes) */
 
		SLE_CONDNULL(16,                                                           2, SL_MAX_VERSION),
 

	
 
		     SLE_END()
 
	};
 

	
 

	
 
	static const SaveLoad *_veh_descs[] = {
 
		_train_desc,
 
		_roadveh_desc,
 
		_ship_desc,
 
		_aircraft_desc,
 
		_special_desc,
 
		_disaster_desc,
 
		_common_veh_desc,
 
	};
 

	
 
	return _veh_descs[vt];
 
}
 

	
 
/** Will be called when the vehicles need to be saved. */
 
static void Save_VEHS()
 
{
 
	Vehicle *v;
 
	/* Write the vehicles */
 
	FOR_ALL_VEHICLES(v) {
 
		SlSetArrayIndex(v->index);
 
		SlObject(v, GetVehicleDescription(v->type));
 
	}
 
}
 

	
 
/** Will be called when vehicles need to be loaded. */
 
void Load_VEHS()
 
{
 
	int index;
 

	
 
	_cargo_count = 0;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		Vehicle *v;
 
		VehicleType vtype = (VehicleType)SlReadByte();
 

	
 
		switch (vtype) {
 
			case VEH_TRAIN:    v = new (index) Train();           break;
 
			case VEH_ROAD:     v = new (index) RoadVehicle();     break;
 
			case VEH_SHIP:     v = new (index) Ship();            break;
 
			case VEH_AIRCRAFT: v = new (index) Aircraft();        break;
 
			case VEH_EFFECT:   v = new (index) EffectVehicle();   break;
 
			case VEH_DISASTER: v = new (index) DisasterVehicle(); break;
 
			case VEH_INVALID:  v = new (index) InvalidVehicle();  break;
 
			default: NOT_REACHED();
 
		}
 

	
 
		SlObject(v, GetVehicleDescription(vtype));
 

	
 
		if (_cargo_count != 0 && IsCompanyBuildableVehicleType(v)) {
 
			/* Don't construct the packet with station here, because that'll fail with old savegames */
 
			CargoPacket *cp = new CargoPacket();
 
			cp->source          = _cargo_source;
 
			cp->source_xy       = _cargo_source_xy;
 
			cp->count           = _cargo_count;
 
			cp->days_in_transit = _cargo_days;
 
			cp->feeder_share    = _cargo_feeder_share;
 
			cp->loaded_at_xy    = _cargo_loaded_at_xy;
 
			v->cargo.Append(cp);
 
		}
 

	
 
		/* Old savegames used 'last_station_visited = 0xFF' */
 
		if (CheckSavegameVersion(5) && v->last_station_visited == 0xFF)
 
			v->last_station_visited = INVALID_STATION;
 

	
 
		if (CheckSavegameVersion(5)) {
 
			/* Convert the current_order.type (which is a mix of type and flags, because
 
			 *  in those versions, they both were 4 bits big) to type and flags */
 
			v->current_order.flags = GB(v->current_order.type, 4, 4);
 
			v->current_order.type &= 0x0F;
 
		}
 

	
 
		/* Advanced vehicle lists got added */
 
		if (CheckSavegameVersion(60)) v->group_id = DEFAULT_GROUP;
 
	}
 
}
 

	
 
extern const ChunkHandler _veh_chunk_handlers[] = {
 
	{ 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY | CH_LAST},
 
};
src/saveload/waypoint_sl.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file waypoint_sl.cpp Code handling saving and loading of waypoints */
 

	
 
#include "../stdafx.h"
 
#include "../waypoint.h"
 
#include "../newgrf_station.h"
 
#include "../town.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "saveload.h"
 

	
 
/**
 
 * Update waypoint graphics id against saved GRFID/localidx.
 
 * This is to ensure the chosen graphics are correct if GRF files are changed.
 
 */
 
void AfterLoadWaypoints()
 
{
 
	Waypoint *wp;
 

	
 
	FOR_ALL_WAYPOINTS(wp) {
 
		uint i;
 

	
 
		if (wp->grfid == 0) continue;
 

	
 
		for (i = 0; i < GetNumCustomStations(STAT_CLASS_WAYP); i++) {
 
			const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, i);
 
			if (statspec != NULL && statspec->grffile->grfid == wp->grfid && statspec->localidx == wp->localidx) {
 
				wp->stat_id = i;
 
				break;
 
			}
 
		}
 
	}
 
}
 

	
 
/**
 
 * Fix savegames which stored waypoints in their old format
 
 */
 
void FixOldWaypoints()
 
{
 
	Waypoint *wp;
 

	
 
	/* Convert the old 'town_or_string', to 'string' / 'town' / 'town_cn' */
 
	FOR_ALL_WAYPOINTS(wp) {
 
		wp->town_index = ClosestTownFromTile(wp->xy, UINT_MAX)->index;
 
		wp->town_cn = 0;
 
		if (wp->string & 0xC000) {
 
			wp->town_cn = wp->string & 0x3F;
 
			wp->string = STR_NULL;
 
		}
 
	}
 
}
 

	
 
static const SaveLoad _waypoint_desc[] = {
 
	SLE_CONDVAR(Waypoint, xy,         SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Waypoint, xy,         SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, town_index, SLE_UINT16,                 12, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, town_cn,    SLE_FILE_U8 | SLE_VAR_U16,  12, 88),
 
	SLE_CONDVAR(Waypoint, town_cn,    SLE_UINT16,                 89, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, string,     SLE_STRINGID,                0, 83),
 
	SLE_CONDSTR(Waypoint, name,       SLE_STR, 0,                 84, SL_MAX_VERSION),
 
	    SLE_VAR(Waypoint, deleted,    SLE_UINT8),
 

	
 
	SLE_CONDVAR(Waypoint, build_date, SLE_FILE_U16 | SLE_VAR_I32,  3, 30),
 
	SLE_CONDVAR(Waypoint, build_date, SLE_INT32,                  31, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, localidx,   SLE_UINT8,                   3, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, grfid,      SLE_UINT32,                 17, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, owner,      SLE_UINT8,                 101, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
static void Save_WAYP()
 
{
 
	Waypoint *wp;
 

	
 
	FOR_ALL_WAYPOINTS(wp) {
 
		SlSetArrayIndex(wp->index);
 
		SlObject(wp, _waypoint_desc);
 
	}
 
}
 

	
 
static void Load_WAYP()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		Waypoint *wp = new (index) Waypoint();
 
		SlObject(wp, _waypoint_desc);
 
	}
 
}
 

	
 
extern const ChunkHandler _waypoint_chunk_handlers[] = {
 
	{ 'CHKP', Save_WAYP, Load_WAYP, CH_ARRAY | CH_LAST},
 
};
src/screenshot.cpp
Show inline comments
 
@@ -17,7 +17,7 @@
 
#include "core/alloc_func.hpp"
 
#include "core/endian_func.hpp"
 
#include "map_func.h"
 
#include "saveload.h"
 
#include "saveload/saveload.h"
 
#include "company_func.h"
 

	
 
#include "table/strings.h"
src/settings.cpp
Show inline comments
 
@@ -29,7 +29,6 @@
 
#include "settings_internal.h"
 
#include "command_func.h"
 
#include "console_func.h"
 
#include "saveload.h"
 
#include "npf.h"
 
#include "yapf/yapf.h"
 
#include "newgrf.h"
src/settings_internal.h
Show inline comments
 
@@ -5,7 +5,7 @@
 
#ifndef SETTINGS_INTERNAL_H
 
#define SETTINGS_INTERNAL_H
 

	
 
#include "saveload.h"
 
#include "saveload/saveload.h"
 
#include "settings_type.h"
 

	
 
/** Convention/Type of settings. This is then further specified if necessary
src/signs.cpp
Show inline comments
 
@@ -8,7 +8,6 @@
 
#include "company_func.h"
 
#include "signs_base.h"
 
#include "signs_func.h"
 
#include "saveload.h"
 
#include "command_func.h"
 
#include "variables.h"
 
#include "strings_func.h"
 
@@ -56,17 +55,12 @@ static void UpdateSignVirtCoords(Sign *s
 
	UpdateViewportSignPos(&si->sign, pt.x, pt.y - 6, STR_2806);
 
}
 

	
 
/**
 
 *
 
 * Update the coordinates of all signs
 
 *
 
 */
 
/** Update the coordinates of all signs */
 
void UpdateAllSignVirtCoords()
 
{
 
	Sign *si;
 

	
 
	FOR_ALL_SIGNS(si) UpdateSignVirtCoords(si);
 

	
 
}
 

	
 
/**
 
@@ -203,48 +197,3 @@ void InitializeSigns()
 
	_Sign_pool.CleanPool();
 
	_Sign_pool.AddBlockToPool();
 
}
 

	
 
static const SaveLoad _sign_desc[] = {
 
  SLE_CONDVAR(Sign, name,  SLE_NAME,                   0, 83),
 
  SLE_CONDSTR(Sign, name,  SLE_STR, 0,                84, SL_MAX_VERSION),
 
  SLE_CONDVAR(Sign, x,     SLE_FILE_I16 | SLE_VAR_I32, 0, 4),
 
  SLE_CONDVAR(Sign, y,     SLE_FILE_I16 | SLE_VAR_I32, 0, 4),
 
  SLE_CONDVAR(Sign, x,     SLE_INT32,                  5, SL_MAX_VERSION),
 
  SLE_CONDVAR(Sign, y,     SLE_INT32,                  5, SL_MAX_VERSION),
 
  SLE_CONDVAR(Sign, owner, SLE_UINT8,                  6, SL_MAX_VERSION),
 
      SLE_VAR(Sign, z,     SLE_UINT8),
 
	SLE_END()
 
};
 

	
 
/**
 
 *
 
 * Save all signs
 
 *
 
 */
 
static void Save_SIGN()
 
{
 
	Sign *si;
 

	
 
	FOR_ALL_SIGNS(si) {
 
		SlSetArrayIndex(si->index);
 
		SlObject(si, _sign_desc);
 
	}
 
}
 

	
 
/**
 
 *
 
 * Load all signs
 
 *
 
 */
 
static void Load_SIGN()
 
{
 
	int index;
 
	while ((index = SlIterateArray()) != -1) {
 
		Sign *si = new (index) Sign();
 
		SlObject(si, _sign_desc);
 
	}
 
}
 

	
 
extern const ChunkHandler _sign_chunk_handlers[] = {
 
	{ 'SIGN', Save_SIGN, Load_SIGN, CH_ARRAY | CH_LAST},
 
};
src/signs_base.h
Show inline comments
 
@@ -7,6 +7,7 @@
 

	
 
#include "signs_type.h"
 
#include "viewport_type.h"
 
#include "tile_type.h"
 
#include "oldpool.h"
 

	
 
DECLARE_OLD_POOL(Sign, Sign, 2, 16000)
src/station.cpp
Show inline comments
 
@@ -9,7 +9,6 @@
 
#include "station_map.h"
 
#include "station_base.h"
 
#include "town.h"
 
#include "saveload.h"
 
#include "company_func.h"
 
#include "airport.h"
 
#include "sprite.h"
src/station_cmd.cpp
Show inline comments
 
@@ -15,7 +15,6 @@
 
#include "command_func.h"
 
#include "town.h"
 
#include "news_func.h"
 
#include "saveload.h"
 
#include "airport.h"
 
#include "sprite.h"
 
#include "train.h"
 
@@ -3185,24 +3184,6 @@ void InitializeStations()
 
	_station_tick_ctr = 0;
 
}
 

	
 

	
 
void AfterLoadStations()
 
{
 
	/* Update the speclists of all stations to point to the currently loaded custom stations. */
 
	Station *st;
 
	FOR_ALL_STATIONS(st) {
 
		for (uint i = 0; i < st->num_specs; i++) {
 
			if (st->speclist[i].grfid == 0) continue;
 

	
 
			st->speclist[i].spec = GetCustomStationSpecByGrf(st->speclist[i].grfid, st->speclist[i].localidx);
 
		}
 

	
 
		for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache();
 

	
 
		StationUpdateAnimTriggers(st);
 
	}
 
}
 

	
 
static CommandCost TerraformTile_Station(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
 
{
 
	if (_settings_game.construction.build_on_slopes && AutoslopeEnabled()) {
 
@@ -3255,200 +3236,3 @@ extern const TileTypeProcs _tile_type_st
 
	GetFoundation_Station,      /* get_foundation_proc */
 
	TerraformTile_Station,      /* terraform_tile_proc */
 
};
 

	
 
static const SaveLoad _roadstop_desc[] = {
 
	SLE_VAR(RoadStop, xy,           SLE_UINT32),
 
	SLE_CONDNULL(1, 0, 44),
 
	SLE_VAR(RoadStop, status,       SLE_UINT8),
 
	/* Index was saved in some versions, but this is not needed */
 
	SLE_CONDNULL(4, 0, 8),
 
	SLE_CONDNULL(2, 0, 44),
 
	SLE_CONDNULL(1, 0, 25),
 

	
 
	SLE_REF(RoadStop, next,         REF_ROADSTOPS),
 
	SLE_CONDNULL(2, 0, 44),
 

	
 
	SLE_CONDNULL(4, 0, 24),
 
	SLE_CONDNULL(1, 25, 25),
 

	
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _station_desc[] = {
 
	SLE_CONDVAR(Station, xy,                         SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Station, xy,                         SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDNULL(4, 0, 5),  ///< bus/lorry tile
 
	SLE_CONDVAR(Station, train_tile,                 SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Station, train_tile,                 SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Station, airport_tile,               SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Station, airport_tile,               SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Station, dock_tile,                  SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Station, dock_tile,                  SLE_UINT32,                  6, SL_MAX_VERSION),
 
	    SLE_REF(Station, town,                       REF_TOWN),
 
	    SLE_VAR(Station, trainst_w,                  SLE_UINT8),
 
	SLE_CONDVAR(Station, trainst_h,                  SLE_UINT8,                   2, SL_MAX_VERSION),
 

	
 
	SLE_CONDNULL(1, 0, 3),  ///< alpha_order
 

	
 
	    SLE_VAR(Station, string_id,                  SLE_STRINGID),
 
	SLE_CONDSTR(Station, name,                       SLE_STR, 0,                 84, SL_MAX_VERSION),
 
	SLE_CONDVAR(Station, indtype,                    SLE_UINT8,                 103, SL_MAX_VERSION),
 
	    SLE_VAR(Station, had_vehicle_of_type,        SLE_UINT16),
 

	
 
	    SLE_VAR(Station, time_since_load,            SLE_UINT8),
 
	    SLE_VAR(Station, time_since_unload,          SLE_UINT8),
 
	    SLE_VAR(Station, delete_ctr,                 SLE_UINT8),
 
	    SLE_VAR(Station, owner,                      SLE_UINT8),
 
	    SLE_VAR(Station, facilities,                 SLE_UINT8),
 
	    SLE_VAR(Station, airport_type,               SLE_UINT8),
 

	
 
	SLE_CONDNULL(2, 0, 5),  ///< Truck/bus stop status
 
	SLE_CONDNULL(1, 0, 4),  ///< Blocked months
 

	
 
	SLE_CONDVAR(Station, airport_flags,              SLE_VAR_U64 | SLE_FILE_U16,  0,  2),
 
	SLE_CONDVAR(Station, airport_flags,              SLE_VAR_U64 | SLE_FILE_U32,  3, 45),
 
	SLE_CONDVAR(Station, airport_flags,              SLE_UINT64,                 46, SL_MAX_VERSION),
 

	
 
	SLE_CONDNULL(2, 0, 25), ///< last-vehicle
 
	SLE_CONDVAR(Station, last_vehicle_type,          SLE_UINT8,                  26, SL_MAX_VERSION),
 

	
 
	SLE_CONDNULL(2, 3, 25), ///< custom station class and id
 
	SLE_CONDVAR(Station, build_date,                 SLE_FILE_U16 | SLE_VAR_I32,  3, 30),
 
	SLE_CONDVAR(Station, build_date,                 SLE_INT32,                  31, SL_MAX_VERSION),
 

	
 
	SLE_CONDREF(Station, bus_stops,                  REF_ROADSTOPS,               6, SL_MAX_VERSION),
 
	SLE_CONDREF(Station, truck_stops,                REF_ROADSTOPS,               6, SL_MAX_VERSION),
 

	
 
	/* Used by newstations for graphic variations */
 
	SLE_CONDVAR(Station, random_bits,                SLE_UINT16,                 27, SL_MAX_VERSION),
 
	SLE_CONDVAR(Station, waiting_triggers,           SLE_UINT8,                  27, SL_MAX_VERSION),
 
	SLE_CONDVAR(Station, num_specs,                  SLE_UINT8,                  27, SL_MAX_VERSION),
 

	
 
	SLE_CONDLST(Station, loading_vehicles,           REF_VEHICLE,                57, SL_MAX_VERSION),
 

	
 
	/* reserve extra space in savegame here. (currently 32 bytes) */
 
	SLE_CONDNULL(32, 2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
static uint16 _waiting_acceptance;
 
static uint16 _cargo_source;
 
static uint32 _cargo_source_xy;
 
static uint16 _cargo_days;
 
static Money  _cargo_feeder_share;
 

	
 
static const SaveLoad _station_speclist_desc[] = {
 
	SLE_CONDVAR(StationSpecList, grfid,    SLE_UINT32, 27, SL_MAX_VERSION),
 
	SLE_CONDVAR(StationSpecList, localidx, SLE_UINT8,  27, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 

	
 
void SaveLoad_STNS(Station *st)
 
{
 
	static const SaveLoad _goods_desc[] = {
 
		SLEG_CONDVAR(            _waiting_acceptance, SLE_UINT16,                  0, 67),
 
		 SLE_CONDVAR(GoodsEntry, acceptance_pickup,   SLE_UINT8,                  68, SL_MAX_VERSION),
 
		SLE_CONDNULL(2,                                                           51, 67),
 
		     SLE_VAR(GoodsEntry, days_since_pickup,   SLE_UINT8),
 
		     SLE_VAR(GoodsEntry, rating,              SLE_UINT8),
 
		SLEG_CONDVAR(            _cargo_source,       SLE_FILE_U8 | SLE_VAR_U16,   0, 6),
 
		SLEG_CONDVAR(            _cargo_source,       SLE_UINT16,                  7, 67),
 
		SLEG_CONDVAR(            _cargo_source_xy,    SLE_UINT32,                 44, 67),
 
		SLEG_CONDVAR(            _cargo_days,         SLE_UINT8,                   0, 67),
 
		     SLE_VAR(GoodsEntry, last_speed,          SLE_UINT8),
 
		     SLE_VAR(GoodsEntry, last_age,            SLE_UINT8),
 
		SLEG_CONDVAR(            _cargo_feeder_share, SLE_FILE_U32 | SLE_VAR_I64, 14, 64),
 
		SLEG_CONDVAR(            _cargo_feeder_share, SLE_INT64,                  65, 67),
 
		 SLE_CONDLST(GoodsEntry, cargo.packets,       REF_CARGO_PACKET,           68, SL_MAX_VERSION),
 

	
 
		SLE_END()
 
};
 

	
 

	
 
	SlObject(st, _station_desc);
 

	
 
	_waiting_acceptance = 0;
 

	
 
	uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO;
 
	for (CargoID i = 0; i < num_cargo; i++) {
 
		GoodsEntry *ge = &st->goods[i];
 
		SlObject(ge, _goods_desc);
 
		if (CheckSavegameVersion(68)) {
 
			SB(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15));
 
			if (GB(_waiting_acceptance, 0, 12) != 0) {
 
				/* Don't construct the packet with station here, because that'll fail with old savegames */
 
				CargoPacket *cp = new CargoPacket();
 
				/* In old versions, enroute_from used 0xFF as INVALID_STATION */
 
				cp->source          = (CheckSavegameVersion(7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source;
 
				cp->count           = GB(_waiting_acceptance, 0, 12);
 
				cp->days_in_transit = _cargo_days;
 
				cp->feeder_share    = _cargo_feeder_share;
 
				cp->source_xy       = _cargo_source_xy;
 
				cp->days_in_transit = _cargo_days;
 
				cp->feeder_share    = _cargo_feeder_share;
 
				SB(ge->acceptance_pickup, GoodsEntry::PICKUP, 1, 1);
 
				ge->cargo.Append(cp);
 
			}
 
		}
 
	}
 

	
 
	if (st->num_specs != 0) {
 
		/* Allocate speclist memory when loading a game */
 
		if (st->speclist == NULL) st->speclist = CallocT<StationSpecList>(st->num_specs);
 
		for (uint i = 0; i < st->num_specs; i++) {
 
			SlObject(&st->speclist[i], _station_speclist_desc);
 
		}
 
	}
 
}
 

	
 
static void Save_STNS()
 
{
 
	Station *st;
 
	/* Write the stations */
 
	FOR_ALL_STATIONS(st) {
 
		SlSetArrayIndex(st->index);
 
		SlAutolength((AutolengthProc*)SaveLoad_STNS, st);
 
	}
 
}
 

	
 
static void Load_STNS()
 
{
 
	int index;
 
	while ((index = SlIterateArray()) != -1) {
 
		Station *st = new (index) Station();
 

	
 
		SaveLoad_STNS(st);
 
	}
 

	
 
	/* This is to ensure all pointers are within the limits of _stations_size */
 
	if (_station_tick_ctr > GetMaxStationIndex()) _station_tick_ctr = 0;
 
}
 

	
 
static void Save_ROADSTOP()
 
{
 
	RoadStop *rs;
 

	
 
	FOR_ALL_ROADSTOPS(rs) {
 
		SlSetArrayIndex(rs->index);
 
		SlObject(rs, _roadstop_desc);
 
	}
 
}
 

	
 
static void Load_ROADSTOP()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		RoadStop *rs = new (index) RoadStop(INVALID_TILE);
 

	
 
		SlObject(rs, _roadstop_desc);
 
	}
 
}
 

	
 
extern const ChunkHandler _station_chunk_handlers[] = {
 
	{ 'STNS', Save_STNS,      Load_STNS,      CH_ARRAY },
 
	{ 'ROAD', Save_ROADSTOP,  Load_ROADSTOP,  CH_ARRAY | CH_LAST},
 
};
src/station_func.h
Show inline comments
 
@@ -25,7 +25,6 @@ StationSet FindStationsAroundTiles(TileI
 
void ShowStationViewWindow(StationID station);
 
void UpdateAllStationVirtCoord();
 

	
 
void AfterLoadStations();
 
void GetProductionAroundTiles(AcceptedCargo produced, TileIndex tile, int w, int h, int rad);
 
void GetAcceptanceAroundTiles(AcceptedCargo accepts, TileIndex tile, int w, int h, int rad);
 

	
src/strings.cpp
Show inline comments
 
@@ -39,7 +39,6 @@
 
#include "video/video_driver.hpp"
 
#include "engine_func.h"
 
#include "engine_base.h"
 
#include "saveload.h"
 
#include "strgen/strgen.h"
 

	
 
#include "table/strings.h"
 
@@ -1593,114 +1592,3 @@ void CheckForMissingGlyphsInLoadedLangua
 

	
 
/* --- Handling of saving/loading string IDs from old savegames --- */
 

	
 
/**
 
 * Remap a string ID from the old format to the new format
 
 * @param s StringID that requires remapping
 
 * @return translated ID
 
 */
 
StringID RemapOldStringID(StringID s)
 
{
 
	switch (s) {
 
		case 0x0006: return STR_SV_EMPTY;
 
		case 0x7000: return STR_SV_UNNAMED;
 
		case 0x70E4: return SPECSTR_PLAYERNAME_ENGLISH;
 
		case 0x70E9: return SPECSTR_PLAYERNAME_ENGLISH;
 
		case 0x8864: return STR_SV_TRAIN_NAME;
 
		case 0x902B: return STR_SV_ROADVEH_NAME;
 
		case 0x9830: return STR_SV_SHIP_NAME;
 
		case 0xA02F: return STR_SV_AIRCRAFT_NAME;
 

	
 
		default:
 
			if (IsInsideMM(s, 0x300F, 0x3030)) {
 
				return s - 0x300F + STR_SV_STNAME;
 
			} else {
 
				return s;
 
			}
 
	}
 
}
 

	
 
/** Location to load the old names to. */
 
char *_old_name_array = NULL;
 

	
 
/**
 
 * Copy and convert old custom names to UTF-8.
 
 * They were all stored in a 512 by 32 long string array and are
 
 * now stored with stations, waypoints and other places with names.
 
 * @param id the StringID of the custom name to clone.
 
 * @return the clones custom name.
 
 */
 
char *CopyFromOldName(StringID id)
 
{
 
	/* Is this name an (old) custom name? */
 
	if (GB(id, 11, 5) != 15) return NULL;
 

	
 
	if (CheckSavegameVersion(37)) {
 
		/* Old names were 32 characters long, so 128 characters should be
 
		 * plenty to allow for expansion when converted to UTF-8. */
 
		char tmp[128];
 
		const char *strfrom = &_old_name_array[32 * GB(id, 0, 9)];
 
		char *strto = tmp;
 

	
 
		for (; *strfrom != '\0'; strfrom++) {
 
			WChar c = (byte)*strfrom;
 

	
 
			/* Map from non-ISO8859-15 characters to UTF-8. */
 
			switch (c) {
 
				case 0xA4: c = 0x20AC; break; // Euro
 
				case 0xA6: c = 0x0160; break; // S with caron
 
				case 0xA8: c = 0x0161; break; // s with caron
 
				case 0xB4: c = 0x017D; break; // Z with caron
 
				case 0xB8: c = 0x017E; break; // z with caron
 
				case 0xBC: c = 0x0152; break; // OE ligature
 
				case 0xBD: c = 0x0153; break; // oe ligature
 
				case 0xBE: c = 0x0178; break; // Y with diaresis
 
				default: break;
 
			}
 

	
 
			/* Check character will fit into our buffer. */
 
			if (strto + Utf8CharLen(c) > lastof(tmp)) break;
 

	
 
			strto += Utf8Encode(strto, c);
 
		}
 

	
 
		/* Terminate the new string and copy it back to the name array */
 
		*strto = '\0';
 

	
 
		return strdup(tmp);
 
	} else {
 
		/* Name will already be in UTF-8. */
 
		return strdup(&_old_name_array[32 * GB(id, 0, 9)]);
 
	}
 
}
 

	
 
/**
 
 * Free the memory of the old names array.
 
 * Should be called once the old names have all been converted.
 
 */
 
void ResetOldNames()
 
{
 
	free(_old_name_array);
 
	_old_name_array = NULL;
 
}
 

	
 
/**
 
 * Initialize the old names table memory.
 
 */
 
void InitializeOldNames()
 
{
 
	free(_old_name_array);
 
	_old_name_array = CallocT<char>(512 * 32);
 
}
 

	
 
static void Load_NAME()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		SlArray(&_old_name_array[32 * index], SlGetFieldLength(), SLE_UINT8);
 
	}
 
}
 

	
 
extern const ChunkHandler _name_chunk_handlers[] = {
 
	{ 'NAME', NULL, Load_NAME, CH_ARRAY | CH_LAST},
 
};
src/strings_func.h
Show inline comments
 
@@ -68,7 +68,4 @@ struct StringIDCompare
 

	
 
void CheckForMissingGlyphsInLoadedLanguagePack();
 

	
 
StringID RemapOldStringID(StringID s);
 
char *CopyFromOldName(StringID id);
 

	
 
#endif /* STRINGS_TYPE_H */
src/town.h
Show inline comments
 
@@ -362,7 +362,6 @@ extern int _cleared_town_rating;
 
void ResetHouses();
 

	
 
void ClearTownHouse(Town *t, TileIndex tile);
 
void AfterLoadTown();
 
void UpdateTownMaxPass(Town *t);
 
void UpdateTownRadius(Town *t);
 
bool CheckIfAuthorityAllows(TileIndex tile);
src/town_cmd.cpp
Show inline comments
 
@@ -19,7 +19,6 @@
 
#include "station_base.h"
 
#include "company_base.h"
 
#include "news_func.h"
 
#include "saveload.h"
 
#include "gui.h"
 
#include "unmovable_map.h"
 
#include "water_map.h"
 
@@ -2676,155 +2675,6 @@ extern const TileTypeProcs _tile_type_to
 
	TerraformTile_Town,      // terraform_tile_proc
 
};
 

	
 

	
 
/** Save and load of towns. */
 
static const SaveLoad _town_desc[] = {
 
	SLE_CONDVAR(Town, xy,                    SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
 
	SLE_CONDVAR(Town, xy,                    SLE_UINT32,                 6, SL_MAX_VERSION),
 

	
 
	SLE_CONDNULL(2, 0, 2),                   ///< population, no longer in use
 
	SLE_CONDNULL(4, 3, 84),                  ///< population, no longer in use
 
	SLE_CONDNULL(2, 0, 91),                  ///< num_houses, no longer in use
 

	
 
	SLE_CONDVAR(Town, townnamegrfid,         SLE_UINT32, 66, SL_MAX_VERSION),
 
	    SLE_VAR(Town, townnametype,          SLE_UINT16),
 
	    SLE_VAR(Town, townnameparts,         SLE_UINT32),
 
	SLE_CONDSTR(Town, name,                  SLE_STR, 0, 84, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(Town, flags12,               SLE_UINT8),
 
	SLE_CONDVAR(Town, statues,               SLE_FILE_U8  | SLE_VAR_U16, 0, 103),
 
	SLE_CONDVAR(Town, statues,               SLE_UINT16,               104, SL_MAX_VERSION),
 

	
 
	SLE_CONDNULL(1, 0, 1),                   ///< sort_index, no longer in use
 

	
 
	SLE_CONDVAR(Town, have_ratings,          SLE_FILE_U8  | SLE_VAR_U16, 0, 103),
 
	SLE_CONDVAR(Town, have_ratings,          SLE_UINT16,               104, SL_MAX_VERSION),
 
	SLE_CONDARR(Town, ratings,               SLE_INT16, 8,               0, 103),
 
	SLE_CONDARR(Town, ratings,               SLE_INT16, MAX_COMPANIES, 104, SL_MAX_VERSION),
 
	/* failed bribe attempts are stored since savegame format 4 */
 
	SLE_CONDARR(Town, unwanted,              SLE_INT8,  8,               4, 103),
 
	SLE_CONDARR(Town, unwanted,              SLE_INT8,  MAX_COMPANIES, 104, SL_MAX_VERSION),
 

	
 
	SLE_CONDVAR(Town, max_pass,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 
	SLE_CONDVAR(Town, max_mail,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 
	SLE_CONDVAR(Town, new_max_pass,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 
	SLE_CONDVAR(Town, new_max_mail,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 
	SLE_CONDVAR(Town, act_pass,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 
	SLE_CONDVAR(Town, act_mail,              SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 
	SLE_CONDVAR(Town, new_act_pass,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 
	SLE_CONDVAR(Town, new_act_mail,          SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
 

	
 
	SLE_CONDVAR(Town, max_pass,              SLE_UINT32,                 9, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, max_mail,              SLE_UINT32,                 9, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, new_max_pass,          SLE_UINT32,                 9, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, new_max_mail,          SLE_UINT32,                 9, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, act_pass,              SLE_UINT32,                 9, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, act_mail,              SLE_UINT32,                 9, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, new_act_pass,          SLE_UINT32,                 9, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, new_act_mail,          SLE_UINT32,                 9, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(Town, pct_pass_transported,  SLE_UINT8),
 
	    SLE_VAR(Town, pct_mail_transported,  SLE_UINT8),
 

	
 
	    SLE_VAR(Town, act_food,              SLE_UINT16),
 
	    SLE_VAR(Town, act_water,             SLE_UINT16),
 
	    SLE_VAR(Town, new_act_food,          SLE_UINT16),
 
	    SLE_VAR(Town, new_act_water,         SLE_UINT16),
 

	
 
	SLE_CONDVAR(Town, time_until_rebuild,    SLE_UINT8,                  0, 53),
 
	SLE_CONDVAR(Town, grow_counter,          SLE_UINT8,                  0, 53),
 
	SLE_CONDVAR(Town, growth_rate,           SLE_UINT8,                  0, 53),
 

	
 
	SLE_CONDVAR(Town, time_until_rebuild,    SLE_UINT16,                54, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, grow_counter,          SLE_UINT16,                54, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, growth_rate,           SLE_INT16,                 54, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(Town, fund_buildings_months, SLE_UINT8),
 
	    SLE_VAR(Town, road_build_months,     SLE_UINT8),
 

	
 
	SLE_CONDVAR(Town, exclusivity,           SLE_UINT8,                  2, SL_MAX_VERSION),
 
	SLE_CONDVAR(Town, exclusive_counter,     SLE_UINT8,                  2, SL_MAX_VERSION),
 

	
 
	SLE_CONDVAR(Town, larger_town,           SLE_BOOL,                  56, SL_MAX_VERSION),
 

	
 
	/* reserve extra space in savegame here. (currently 30 bytes) */
 
	SLE_CONDNULL(30, 2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
/* Save and load the mapping between the house id on the map, and the grf file
 
 * it came from. */
 
static const SaveLoad _house_id_mapping_desc[] = {
 
	SLE_VAR(EntityIDMapping, grfid,         SLE_UINT32),
 
	SLE_VAR(EntityIDMapping, entity_id,     SLE_UINT8),
 
	SLE_VAR(EntityIDMapping, substitute_id, SLE_UINT8),
 
	SLE_END()
 
};
 

	
 
static void Save_HOUSEIDS()
 
{
 
	uint j = _house_mngr.GetMaxMapping();
 

	
 
	for (uint i = 0; i < j; i++) {
 
		SlSetArrayIndex(i);
 
		SlObject(&_house_mngr.mapping_ID[i], _house_id_mapping_desc);
 
	}
 
}
 

	
 
static void Load_HOUSEIDS()
 
{
 
	int index;
 

	
 
	_house_mngr.ResetMapping();
 
	uint max_id = _house_mngr.GetMaxMapping();
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		if ((uint)index >= max_id) break;
 
		SlObject(&_house_mngr.mapping_ID[index], _house_id_mapping_desc);
 
	}
 
}
 

	
 
static void Save_TOWN()
 
{
 
	Town *t;
 

	
 
	FOR_ALL_TOWNS(t) {
 
		SlSetArrayIndex(t->index);
 
		SlObject(t, _town_desc);
 
	}
 
}
 

	
 
static void Load_TOWN()
 
{
 
	int index;
 

	
 
	_total_towns = 0;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		Town *t = new (index) Town();
 
		SlObject(t, _town_desc);
 

	
 
		_total_towns++;
 
	}
 

	
 
	/* This is to ensure all pointers are within the limits of
 
	 *  the size of the TownPool */
 
	if (_cur_town_ctr > GetMaxTownIndex())
 
		_cur_town_ctr = 0;
 
}
 

	
 
void AfterLoadTown()
 
{
 
	Town *t;
 
	FOR_ALL_TOWNS(t) t->InitializeLayout();
 
}
 

	
 
extern const ChunkHandler _town_chunk_handlers[] = {
 
	{ 'HIDS', Save_HOUSEIDS, Load_HOUSEIDS, CH_ARRAY },
 
	{ 'CITY', Save_TOWN,     Load_TOWN,     CH_ARRAY | CH_LAST},
 
};
 

	
 
void ResetHouses()
 
{
 
	memset(&_house_specs, 0, sizeof(_house_specs));
src/train.h
Show inline comments
 
@@ -287,9 +287,6 @@ static inline Vehicle *GetPrevUnit(const
 
	return w;
 
}
 

	
 
void ConvertOldMultiheadToNew();
 
void ConnectMultiheadedTrains();
 

	
 
void CcBuildLoco(bool success, TileIndex tile, uint32 p1, uint32 p2);
 
void CcBuildWagon(bool success, TileIndex tile, uint32 p1, uint32 p2);
 

	
src/train_cmd.cpp
Show inline comments
 
@@ -4500,146 +4500,3 @@ void InitializeTrains()
 
{
 
	_age_cargo_skip_counter = 1;
 
}
 

	
 
/*
 
 * Link front and rear multiheaded engines to each other
 
 * This is done when loading a savegame
 
 */
 
void ConnectMultiheadedTrains()
 
{
 
	Vehicle *v;
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN) {
 
			v->u.rail.other_multiheaded_part = NULL;
 
		}
 
	}
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) {
 
			/* Two ways to associate multiheaded parts to each other:
 
			 * sequential-matching: Trains shall be arranged to look like <..>..<..>..<..>..
 
			 * bracket-matching:    Free vehicle chains shall be arranged to look like ..<..<..>..<..>..>..
 
			 *
 
			 * Note: Old savegames might contain chains which do not comply with these rules, e.g.
 
			 *   - the front and read parts have invalid orders
 
			 *   - different engine types might be combined
 
			 *   - there might be different amounts of front and rear parts.
 
			 *
 
			 * Note: The multiheaded parts need to be matched exactly like they are matched on the server, else desyncs will occur.
 
			 *   This is why two matching strategies are needed.
 
			 */
 

	
 
			bool sequential_matching = IsFrontEngine(v);
 

	
 
			for (Vehicle *u = v; u != NULL; u = GetNextVehicle(u)) {
 
				if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one
 

	
 
				if (IsMultiheaded(u)) {
 
					if (!IsTrainEngine(u)) {
 
						/* we got a rear car without a front car. We will convert it to a front one */
 
						SetTrainEngine(u);
 
						u->spritenum--;
 
					}
 

	
 
					/* Find a matching back part */
 
					EngineID eid = u->engine_type;
 
					Vehicle *w;
 
					if (sequential_matching) {
 
						for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) {
 
							if (w->engine_type != eid || w->u.rail.other_multiheaded_part != NULL || !IsMultiheaded(w)) continue;
 

	
 
							/* we found a car to partner with this engine. Now we will make sure it face the right way */
 
							if (IsTrainEngine(w)) {
 
								ClearTrainEngine(w);
 
								w->spritenum++;
 
							}
 
							break;
 
						}
 
					} else {
 
						uint stack_pos = 0;
 
						for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) {
 
							if (w->engine_type != eid || w->u.rail.other_multiheaded_part != NULL || !IsMultiheaded(w)) continue;
 

	
 
							if (IsTrainEngine(w)) {
 
								stack_pos++;
 
							} else {
 
								if (stack_pos == 0) break;
 
								stack_pos--;
 
							}
 
						}
 
					}
 

	
 
					if (w != NULL) {
 
						w->u.rail.other_multiheaded_part = u;
 
						u->u.rail.other_multiheaded_part = w;
 
					} else {
 
						/* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */
 
						ClearMultiheaded(u);
 
					}
 
				}
 
			}
 
		}
 
	}
 
}
 

	
 
/**
 
 *  Converts all trains to the new subtype format introduced in savegame 16.2
 
 *  It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found
 
 */
 
void ConvertOldMultiheadToNew()
 
{
 
	Vehicle *v;
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN) {
 
			SetBit(v->subtype, 7); // indicates that it's the old format and needs to be converted in the next loop
 
		}
 
	}
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN) {
 
			if (HasBit(v->subtype, 7) && ((v->subtype & ~0x80) == 0 || (v->subtype & ~0x80) == 4)) {
 
				for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
					const RailVehicleInfo *rvi = RailVehInfo(u->engine_type);
 

	
 
					ClrBit(u->subtype, 7);
 
					switch (u->subtype) {
 
						case 0: /* TS_Front_Engine */
 
							if (rvi->railveh_type == RAILVEH_MULTIHEAD) SetMultiheaded(u);
 
							SetFrontEngine(u);
 
							SetTrainEngine(u);
 
							break;
 

	
 
						case 1: /* TS_Artic_Part */
 
							u->subtype = 0;
 
							SetArticulatedPart(u);
 
							break;
 

	
 
						case 2: /* TS_Not_First */
 
							u->subtype = 0;
 
							if (rvi->railveh_type == RAILVEH_WAGON) {
 
								// normal wagon
 
								SetTrainWagon(u);
 
								break;
 
							}
 
							if (rvi->railveh_type == RAILVEH_MULTIHEAD && rvi->image_index == u->spritenum - 1) {
 
								// rear end of a multiheaded engine
 
								SetMultiheaded(u);
 
								break;
 
							}
 
							if (rvi->railveh_type == RAILVEH_MULTIHEAD) SetMultiheaded(u);
 
							SetTrainEngine(u);
 
							break;
 

	
 
						case 4: /* TS_Free_Car */
 
							u->subtype = 0;
 
							SetTrainWagon(u);
 
							SetFreeWagon(u);
 
							break;
 
						default: NOT_REACHED(); break;
 
					}
 
				}
 
			}
 
		}
 
	}
 
}
src/variables.h
Show inline comments
 
@@ -33,10 +33,6 @@ VARDEF uint _next_competitor_start;
 
/* Determines how often to run the tree loop */
 
VARDEF byte _trees_tick_ctr;
 

	
 
/* Keep track of current game position */
 
VARDEF int _saved_scrollpos_x;
 
VARDEF int _saved_scrollpos_y;
 

	
 
/* NOSAVE: Used in palette animations only, not really important. */
 
VARDEF int _palette_animation_counter;
 

	
src/vehicle.cpp
Show inline comments
 
@@ -15,7 +15,7 @@
 
#include "gfx_func.h"
 
#include "news_func.h"
 
#include "command_func.h"
 
#include "saveload.h"
 
#include "saveload/saveload.h"
 
#include "company_func.h"
 
#include "debug.h"
 
#include "vehicle_gui.h"
 
@@ -59,9 +59,6 @@
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
#include <map>
 

	
 
#define INVALID_COORD (0x7fffffff)
 
#define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6))
 

	
 
VehicleID _vehicle_id_ctr_day;
 
@@ -222,120 +219,6 @@ void VehiclePositionChanged(Vehicle *v)
 
	v->bottom_coord = pt.y + spr->height + 2;
 
}
 

	
 
/** Called after load to update coordinates */
 
void AfterLoadVehicles(bool part_of_load)
 
{
 
	Vehicle *v;
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		/* Reinstate the previous pointer */
 
		if (v->Next() != NULL) v->Next()->previous = v;
 
		if (v->NextShared() != NULL) v->NextShared()->previous_shared = v;
 

	
 
		v->UpdateDeltaXY(v->direction);
 

	
 
		if (part_of_load) v->fill_percent_te_id = INVALID_TE_ID;
 
		v->first = NULL;
 
		if (v->type == VEH_TRAIN) v->u.rail.first_engine = INVALID_ENGINE;
 
		if (v->type == VEH_ROAD)  v->u.road.first_engine = INVALID_ENGINE;
 

	
 
		v->cargo.InvalidateCache();
 
	}
 

	
 
	/* AfterLoadVehicles may also be called in case of NewGRF reload, in this
 
	 * case we may not convert orders again. */
 
	if (part_of_load) {
 
		/* Create shared vehicle chain for very old games (pre 5,2) and create
 
		 * OrderList from shared vehicle chains. For this to work correctly, the
 
		 * following conditions must be fulfilled:
 
		 * a) both next_shared and previous_shared are not set for pre 5,2 games
 
		 * b) both next_shared and previous_shared are set for later games
 
		 */
 
		std::map<Order*, OrderList*> mapping;
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->orders.old != NULL) {
 
				if (CheckSavegameVersion(105)) { // Pre-105 didn't save an OrderList
 
					if (mapping[v->orders.old] == NULL) {
 
						/* This adds the whole shared vehicle chain for case b */
 
						v->orders.list = mapping[v->orders.old] = new OrderList(v->orders.old, v);
 
					} else {
 
						v->orders.list = mapping[v->orders.old];
 
						/* For old games (case a) we must create the shared vehicle chain */
 
						if (CheckSavegameVersionOldStyle(5, 2)) {
 
							v->AddToShared(v->orders.list->GetFirstSharedVehicle());
 
						}
 
					}
 
				} else { // OrderList was saved as such, only recalculate not saved values
 
					if (v->PreviousShared() == NULL) {
 
						new (v->orders.list) OrderList(v->orders.list->GetFirstOrder(), v);
 
					}
 
				}
 
			}
 
		}
 
	}
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		/* Fill the first pointers */
 
		if (v->Previous() == NULL) {
 
			for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
				u->first = v;
 
			}
 
		}
 
	}
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		assert(v->first != NULL);
 

	
 
		if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) {
 
			if (IsFrontEngine(v)) v->u.rail.last_speed = v->cur_speed; // update displayed train speed
 
			TrainConsistChanged(v, false);
 
		} else if (v->type == VEH_ROAD && IsRoadVehFront(v)) {
 
			RoadVehUpdateCache(v);
 
		}
 
	}
 

	
 
	/* Stop non-front engines */
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN && IsTrainEngine(v) && !IsFrontEngine(v)) v->vehstatus |= VS_STOPPED;
 
	}
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		switch (v->type) {
 
			case VEH_ROAD:
 
				v->u.road.roadtype = HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
 
				v->u.road.compatible_roadtypes = RoadTypeToRoadTypes(v->u.road.roadtype);
 
				/* FALL THROUGH */
 
			case VEH_TRAIN:
 
			case VEH_SHIP:
 
				v->cur_image = v->GetImage(v->direction);
 
				break;
 

	
 
			case VEH_AIRCRAFT:
 
				if (IsNormalAircraft(v)) {
 
					v->cur_image = v->GetImage(v->direction);
 

	
 
					/* The plane's shadow will have the same image as the plane */
 
					Vehicle *shadow = v->Next();
 
					shadow->cur_image = v->cur_image;
 

	
 
					/* In the case of a helicopter we will update the rotor sprites */
 
					if (v->subtype == AIR_HELICOPTER) {
 
						Vehicle *rotor = shadow->Next();
 
						rotor->cur_image = GetRotorImage(v);
 
					}
 

	
 
					UpdateAircraftCache(v);
 
				}
 
				break;
 
			default: break;
 
		}
 

	
 
		v->left_coord = INVALID_COORD;
 
		VehiclePositionChanged(v);
 
	}
 
}
 

	
 
Vehicle::Vehicle()
 
{
 
	this->type               = VEH_INVALID;
 
@@ -622,11 +505,19 @@ void ResetVehicleColorMap()
 
	FOR_ALL_VEHICLES(v) { v->colormap = PAL_NONE; }
 
}
 

	
 
/**
 
 * List of vehicles that should check for autoreplace this tick.
 
 * Mapping of vehicle -> leave depot immediatelly after autoreplace.
 
 */
 
typedef SmallMap<Vehicle *, bool, 4> AutoreplaceMap;
 
static AutoreplaceMap _vehicles_to_autoreplace;
 

	
 
void InitializeVehicles()
 
{
 
	_Vehicle_pool.CleanPool();
 
	_Vehicle_pool.AddBlockToPool();
 

	
 
	_vehicles_to_autoreplace.Reset();
 
	ResetVehiclePosHash();
 
}
 

	
 
@@ -739,13 +630,6 @@ Vehicle::~Vehicle()
 
	new (this) InvalidVehicle();
 
}
 

	
 
/**
 
 * List of vehicles that should check for autoreplace this tick.
 
 * Mapping of vehicle -> leave depot immediatelly after autoreplace.
 
 */
 
typedef SmallMap<Vehicle *, bool, 4> AutoreplaceMap;
 
static AutoreplaceMap _vehicles_to_autoreplace;
 

	
 
/** Adds a vehicle to the list of vehicles, that visited a depot this tick
 
 * @param *v vehicle to add
 
 */
 
@@ -2128,367 +2012,6 @@ SpriteID GetVehiclePalette(const Vehicle
 
	return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
 
}
 

	
 
static uint8  _cargo_days;
 
static uint16 _cargo_source;
 
static uint32 _cargo_source_xy;
 
static uint16 _cargo_count;
 
static uint16 _cargo_paid_for;
 
static Money  _cargo_feeder_share;
 
static uint32 _cargo_loaded_at_xy;
 

	
 
/**
 
 * Make it possible to make the saveload tables "friends" of other classes.
 
 * @param vt the vehicle type. Can be VEH_END for the common vehicle description data
 
 * @return the saveload description
 
 */
 
const SaveLoad *GetVehicleDescription(VehicleType vt)
 
{
 
/** Save and load of vehicles */
 
static const SaveLoad _common_veh_desc[] = {
 
	    SLE_VAR(Vehicle, subtype,              SLE_UINT8),
 

	
 
	    SLE_REF(Vehicle, next,                 REF_VEHICLE_OLD),
 
	SLE_CONDVAR(Vehicle, name,                 SLE_NAME,                    0, 83),
 
	SLE_CONDSTR(Vehicle, name,                 SLE_STR, 0,                 84, SL_MAX_VERSION),
 
	SLE_CONDVAR(Vehicle, unitnumber,           SLE_FILE_U8  | SLE_VAR_U16,  0, 7),
 
	SLE_CONDVAR(Vehicle, unitnumber,           SLE_UINT16,                  8, SL_MAX_VERSION),
 
	    SLE_VAR(Vehicle, owner,                SLE_UINT8),
 
	SLE_CONDVAR(Vehicle, tile,                 SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Vehicle, tile,                 SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Vehicle, dest_tile,            SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Vehicle, dest_tile,            SLE_UINT32,                  6, SL_MAX_VERSION),
 

	
 
	SLE_CONDVAR(Vehicle, x_pos,                SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Vehicle, x_pos,                SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Vehicle, y_pos,                SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Vehicle, y_pos,                SLE_UINT32,                  6, SL_MAX_VERSION),
 
	    SLE_VAR(Vehicle, z_pos,                SLE_UINT8),
 
	    SLE_VAR(Vehicle, direction,            SLE_UINT8),
 

	
 
	SLE_CONDNULL(2,                                                         0, 57),
 
	    SLE_VAR(Vehicle, spritenum,            SLE_UINT8),
 
	SLE_CONDNULL(5,                                                         0, 57),
 
	    SLE_VAR(Vehicle, engine_type,          SLE_UINT16),
 

	
 
	    SLE_VAR(Vehicle, max_speed,            SLE_UINT16),
 
	    SLE_VAR(Vehicle, cur_speed,            SLE_UINT16),
 
	    SLE_VAR(Vehicle, subspeed,             SLE_UINT8),
 
	    SLE_VAR(Vehicle, acceleration,         SLE_UINT8),
 
	    SLE_VAR(Vehicle, progress,             SLE_UINT8),
 

	
 
	    SLE_VAR(Vehicle, vehstatus,            SLE_UINT8),
 
	SLE_CONDVAR(Vehicle, last_station_visited, SLE_FILE_U8  | SLE_VAR_U16,  0, 4),
 
	SLE_CONDVAR(Vehicle, last_station_visited, SLE_UINT16,                  5, SL_MAX_VERSION),
 

	
 
	     SLE_VAR(Vehicle, cargo_type,           SLE_UINT8),
 
	 SLE_CONDVAR(Vehicle, cargo_subtype,        SLE_UINT8,                  35, SL_MAX_VERSION),
 
	SLEG_CONDVAR(         _cargo_days,          SLE_UINT8,                   0, 67),
 
	SLEG_CONDVAR(         _cargo_source,        SLE_FILE_U8  | SLE_VAR_U16,  0, 6),
 
	SLEG_CONDVAR(         _cargo_source,        SLE_UINT16,                  7, 67),
 
	SLEG_CONDVAR(         _cargo_source_xy,     SLE_UINT32,                 44, 67),
 
	     SLE_VAR(Vehicle, cargo_cap,            SLE_UINT16),
 
	SLEG_CONDVAR(         _cargo_count,         SLE_UINT16,                  0, 67),
 
	 SLE_CONDLST(Vehicle, cargo,                REF_CARGO_PACKET,           68, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(Vehicle, day_counter,          SLE_UINT8),
 
	    SLE_VAR(Vehicle, tick_counter,         SLE_UINT8),
 
	SLE_CONDVAR(Vehicle, running_ticks,        SLE_UINT8,                   88, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(Vehicle, cur_order_index,      SLE_UINT8),
 
	/* num_orders is now part of OrderList and is not saved but counted */
 
	SLE_CONDNULL(1,                                                          0, 104),
 

	
 
	/* This next line is for version 4 and prior compatibility.. it temporarily reads
 
	    type and flags (which were both 4 bits) into type. Later on this is
 
	    converted correctly */
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, type), SLE_UINT8,                 0, 4),
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
 

	
 
	/* Orders for version 5 and on */
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, type),  SLE_UINT8,  5, SL_MAX_VERSION),
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, flags), SLE_UINT8,  5, SL_MAX_VERSION),
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest),  SLE_UINT16, 5, SL_MAX_VERSION),
 

	
 
	/* Refit in current order */
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, refit_cargo),    SLE_UINT8, 36, SL_MAX_VERSION),
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, refit_subtype),  SLE_UINT8, 36, SL_MAX_VERSION),
 

	
 
	/* Timetable in current order */
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, wait_time),      SLE_UINT16, 67, SL_MAX_VERSION),
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, travel_time),    SLE_UINT16, 67, SL_MAX_VERSION),
 

	
 
	SLE_CONDREF(Vehicle, orders,               REF_ORDER,                   0, 104),
 
	SLE_CONDREF(Vehicle, orders,               REF_ORDERLIST,             105, SL_MAX_VERSION),
 

	
 
	SLE_CONDVAR(Vehicle, age,                  SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
 
	SLE_CONDVAR(Vehicle, age,                  SLE_INT32,                  31, SL_MAX_VERSION),
 
	SLE_CONDVAR(Vehicle, max_age,              SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
 
	SLE_CONDVAR(Vehicle, max_age,              SLE_INT32,                  31, SL_MAX_VERSION),
 
	SLE_CONDVAR(Vehicle, date_of_last_service, SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
 
	SLE_CONDVAR(Vehicle, date_of_last_service, SLE_INT32,                  31, SL_MAX_VERSION),
 
	SLE_CONDVAR(Vehicle, service_interval,     SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
 
	SLE_CONDVAR(Vehicle, service_interval,     SLE_INT32,                  31, SL_MAX_VERSION),
 
	    SLE_VAR(Vehicle, reliability,          SLE_UINT16),
 
	    SLE_VAR(Vehicle, reliability_spd_dec,  SLE_UINT16),
 
	    SLE_VAR(Vehicle, breakdown_ctr,        SLE_UINT8),
 
	    SLE_VAR(Vehicle, breakdown_delay,      SLE_UINT8),
 
	    SLE_VAR(Vehicle, breakdowns_since_last_service, SLE_UINT8),
 
	    SLE_VAR(Vehicle, breakdown_chance,     SLE_UINT8),
 
	SLE_CONDVAR(Vehicle, build_year,           SLE_FILE_U8 | SLE_VAR_I32,  0, 30),
 
	SLE_CONDVAR(Vehicle, build_year,           SLE_INT32,                 31, SL_MAX_VERSION),
 

	
 
	     SLE_VAR(Vehicle, load_unload_time_rem, SLE_UINT16),
 
	SLEG_CONDVAR(         _cargo_paid_for,      SLE_UINT16,                45, SL_MAX_VERSION),
 
	 SLE_CONDVAR(Vehicle, vehicle_flags,        SLE_UINT8,                 40, SL_MAX_VERSION),
 

	
 
	 SLE_CONDVAR(Vehicle, profit_this_year,     SLE_FILE_I32 | SLE_VAR_I64, 0, 64),
 
	 SLE_CONDVAR(Vehicle, profit_this_year,     SLE_INT64,                 65, SL_MAX_VERSION),
 
	 SLE_CONDVAR(Vehicle, profit_last_year,     SLE_FILE_I32 | SLE_VAR_I64, 0, 64),
 
	 SLE_CONDVAR(Vehicle, profit_last_year,     SLE_INT64,                 65, SL_MAX_VERSION),
 
	SLEG_CONDVAR(         _cargo_feeder_share,  SLE_FILE_I32 | SLE_VAR_I64,51, 64),
 
	SLEG_CONDVAR(         _cargo_feeder_share,  SLE_INT64,                 65, 67),
 
	SLEG_CONDVAR(         _cargo_loaded_at_xy,  SLE_UINT32,                51, 67),
 
	 SLE_CONDVAR(Vehicle, value,                SLE_FILE_I32 | SLE_VAR_I64, 0, 64),
 
	 SLE_CONDVAR(Vehicle, value,                SLE_INT64,                 65, SL_MAX_VERSION),
 

	
 
	 SLE_CONDVAR(Vehicle, random_bits,          SLE_UINT8,                 2, SL_MAX_VERSION),
 
	 SLE_CONDVAR(Vehicle, waiting_triggers,     SLE_UINT8,                 2, SL_MAX_VERSION),
 

	
 
	 SLE_CONDREF(Vehicle, next_shared,        REF_VEHICLE,                 2, SL_MAX_VERSION),
 
	SLE_CONDNULL(2,                                                        2, 68),
 
	SLE_CONDNULL(4,                                                       69, 100),
 

	
 
	SLE_CONDVAR(Vehicle, group_id,             SLE_UINT16,                60, SL_MAX_VERSION),
 

	
 
	SLE_CONDVAR(Vehicle, current_order_time,   SLE_UINT32,                67, SL_MAX_VERSION),
 
	SLE_CONDVAR(Vehicle, lateness_counter,     SLE_INT32,                 67, SL_MAX_VERSION),
 

	
 
	/* reserve extra space in savegame here. (currently 10 bytes) */
 
	SLE_CONDNULL(10,                                                       2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 

	
 
static const SaveLoad _train_desc[] = {
 
	SLE_WRITEBYTE(Vehicle, type, VEH_TRAIN),
 
	SLE_VEH_INCLUDEX(),
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, crash_anim_pos),         SLE_UINT16),
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, force_proceed),          SLE_UINT8),
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, railtype),               SLE_UINT8),
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, track),                  SLE_UINT8),
 

	
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, flags), SLE_FILE_U8  | SLE_VAR_U16,  2, 99),
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, flags),                 SLE_UINT16,100, SL_MAX_VERSION),
 
	SLE_CONDNULL(2, 2, 59),
 

	
 
	SLE_CONDNULL(2, 2, 19),
 
	/* reserve extra space in savegame here. (currently 11 bytes) */
 
	SLE_CONDNULL(11, 2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _roadveh_desc[] = {
 
	SLE_WRITEBYTE(Vehicle, type, VEH_ROAD),
 
	SLE_VEH_INCLUDEX(),
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, state),          SLE_UINT8),
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, frame),          SLE_UINT8),
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, blocked_ctr),    SLE_UINT16),
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, overtaking),     SLE_UINT8),
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, overtaking_ctr), SLE_UINT8),
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, crashed_ctr),    SLE_UINT16),
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, reverse_ctr),    SLE_UINT8),
 

	
 
	SLE_CONDREFX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, slot),     REF_ROADSTOPS, 6, SL_MAX_VERSION),
 
	SLE_CONDNULL(1,                                                                     6, SL_MAX_VERSION),
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, slot_age), SLE_UINT8,     6, SL_MAX_VERSION),
 
	/* reserve extra space in savegame here. (currently 16 bytes) */
 
	SLE_CONDNULL(16,                                                                    2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _ship_desc[] = {
 
	SLE_WRITEBYTE(Vehicle, type, VEH_SHIP),
 
	SLE_VEH_INCLUDEX(),
 
	SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleShip, state), SLE_UINT8),
 

	
 
	/* reserve extra space in savegame here. (currently 16 bytes) */
 
	SLE_CONDNULL(16, 2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _aircraft_desc[] = {
 
	SLE_WRITEBYTE(Vehicle, type, VEH_AIRCRAFT),
 
	SLE_VEH_INCLUDEX(),
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, crashed_counter), SLE_UINT16),
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, pos),             SLE_UINT8),
 

	
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, targetairport),   SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, targetairport),   SLE_UINT16,                5, SL_MAX_VERSION),
 

	
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, state),           SLE_UINT8),
 

	
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, previous_pos),    SLE_UINT8,                 2, SL_MAX_VERSION),
 

	
 
	/* reserve extra space in savegame here. (currently 15 bytes) */
 
	SLE_CONDNULL(15,                                                                                      2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _special_desc[] = {
 
	SLE_WRITEBYTE(Vehicle, type, VEH_EFFECT),
 

	
 
	    SLE_VAR(Vehicle, subtype,       SLE_UINT8),
 

	
 
	SLE_CONDVAR(Vehicle, tile,          SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
 
	SLE_CONDVAR(Vehicle, tile,          SLE_UINT32,                 6, SL_MAX_VERSION),
 

	
 
	SLE_CONDVAR(Vehicle, x_pos,         SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
 
	SLE_CONDVAR(Vehicle, x_pos,         SLE_INT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Vehicle, y_pos,         SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
 
	SLE_CONDVAR(Vehicle, y_pos,         SLE_INT32,                  6, SL_MAX_VERSION),
 
	    SLE_VAR(Vehicle, z_pos,         SLE_UINT8),
 

	
 
	    SLE_VAR(Vehicle, cur_image,     SLE_UINT16),
 
	SLE_CONDNULL(5,                                                 0, 57),
 
	    SLE_VAR(Vehicle, progress,      SLE_UINT8),
 
	    SLE_VAR(Vehicle, vehstatus,     SLE_UINT8),
 

	
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleEffect, animation_state),    SLE_UINT16),
 
	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleEffect, animation_substate), SLE_UINT8),
 

	
 
	SLE_CONDVAR(Vehicle, spritenum,     SLE_UINT8, 2, SL_MAX_VERSION),
 

	
 
	/* reserve extra space in savegame here. (currently 15 bytes) */
 
	SLE_CONDNULL(15, 2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _disaster_desc[] = {
 
	SLE_WRITEBYTE(Vehicle, type, VEH_DISASTER),
 

	
 
	    SLE_REF(Vehicle, next,          REF_VEHICLE_OLD),
 

	
 
	    SLE_VAR(Vehicle, subtype,       SLE_UINT8),
 
	SLE_CONDVAR(Vehicle, tile,          SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Vehicle, tile,          SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Vehicle, dest_tile,     SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Vehicle, dest_tile,     SLE_UINT32,                  6, SL_MAX_VERSION),
 

	
 
	SLE_CONDVAR(Vehicle, x_pos,         SLE_FILE_I16 | SLE_VAR_I32,  0, 5),
 
	SLE_CONDVAR(Vehicle, x_pos,         SLE_INT32,                   6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Vehicle, y_pos,         SLE_FILE_I16 | SLE_VAR_I32,  0, 5),
 
	SLE_CONDVAR(Vehicle, y_pos,         SLE_INT32,                   6, SL_MAX_VERSION),
 
	    SLE_VAR(Vehicle, z_pos,         SLE_UINT8),
 
	    SLE_VAR(Vehicle, direction,     SLE_UINT8),
 

	
 
	SLE_CONDNULL(5,                                                  0, 57),
 
	    SLE_VAR(Vehicle, owner,         SLE_UINT8),
 
	    SLE_VAR(Vehicle, vehstatus,     SLE_UINT8),
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
 
	SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_UINT16,                5, SL_MAX_VERSION),
 

	
 
	    SLE_VAR(Vehicle, cur_image,     SLE_UINT16),
 
	SLE_CONDVAR(Vehicle, age,           SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
 
	SLE_CONDVAR(Vehicle, age,           SLE_INT32,                  31, SL_MAX_VERSION),
 
	    SLE_VAR(Vehicle, tick_counter,  SLE_UINT8),
 

	
 
	   SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, image_override),           SLE_UINT16),
 
	   SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, big_ufo_destroyer_target), SLE_UINT16),
 

	
 
	/* reserve extra space in savegame here. (currently 16 bytes) */
 
	SLE_CONDNULL(16,                                                 2, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 

	
 
static const SaveLoad *_veh_descs[] = {
 
	_train_desc,
 
	_roadveh_desc,
 
	_ship_desc,
 
	_aircraft_desc,
 
	_special_desc,
 
	_disaster_desc,
 
	_common_veh_desc,
 
};
 

	
 
	return _veh_descs[vt];
 
}
 

	
 
/** Will be called when the vehicles need to be saved. */
 
static void Save_VEHS()
 
{
 
	Vehicle *v;
 
	/* Write the vehicles */
 
	FOR_ALL_VEHICLES(v) {
 
		SlSetArrayIndex(v->index);
 
		SlObject(v, GetVehicleDescription(v->type));
 
	}
 
}
 

	
 
/** Will be called when vehicles need to be loaded. */
 
void Load_VEHS()
 
{
 
	_vehicles_to_autoreplace.Reset();
 

	
 
	int index;
 

	
 
	_cargo_count = 0;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		Vehicle *v;
 
		VehicleType vtype = (VehicleType)SlReadByte();
 

	
 
		switch (vtype) {
 
			case VEH_TRAIN:    v = new (index) Train();           break;
 
			case VEH_ROAD:     v = new (index) RoadVehicle();     break;
 
			case VEH_SHIP:     v = new (index) Ship();            break;
 
			case VEH_AIRCRAFT: v = new (index) Aircraft();        break;
 
			case VEH_EFFECT:   v = new (index) EffectVehicle();   break;
 
			case VEH_DISASTER: v = new (index) DisasterVehicle(); break;
 
			case VEH_INVALID:  v = new (index) InvalidVehicle();  break;
 
			default: NOT_REACHED();
 
		}
 

	
 
		SlObject(v, GetVehicleDescription(vtype));
 

	
 
		if (_cargo_count != 0 && IsCompanyBuildableVehicleType(v)) {
 
			/* Don't construct the packet with station here, because that'll fail with old savegames */
 
			CargoPacket *cp = new CargoPacket();
 
			cp->source          = _cargo_source;
 
			cp->source_xy       = _cargo_source_xy;
 
			cp->count           = _cargo_count;
 
			cp->days_in_transit = _cargo_days;
 
			cp->feeder_share    = _cargo_feeder_share;
 
			cp->loaded_at_xy    = _cargo_loaded_at_xy;
 
			v->cargo.Append(cp);
 
		}
 

	
 
		/* Old savegames used 'last_station_visited = 0xFF' */
 
		if (CheckSavegameVersion(5) && v->last_station_visited == 0xFF)
 
			v->last_station_visited = INVALID_STATION;
 

	
 
		if (CheckSavegameVersion(5)) {
 
			/* Convert the current_order.type (which is a mix of type and flags, because
 
			 *  in those versions, they both were 4 bits big) to type and flags */
 
			v->current_order.flags = GB(v->current_order.type, 4, 4);
 
			v->current_order.type &= 0x0F;
 
		}
 

	
 
		/* Advanced vehicle lists got added */
 
		if (CheckSavegameVersion(60)) v->group_id = DEFAULT_GROUP;
 
	}
 
}
 

	
 
extern const ChunkHandler _veh_chunk_handlers[] = {
 
	{ 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY | CH_LAST},
 
};
 

	
 
void Vehicle::BeginLoading()
 
{
src/vehicle_base.h
Show inline comments
 
@@ -194,7 +194,6 @@ DECLARE_OLD_POOL(Vehicle, Vehicle, 9, 12
 
/* Some declarations of functions, so we can make them friendly */
 
struct SaveLoad;
 
extern const SaveLoad *GetVehicleDescription(VehicleType vt);
 
extern void AfterLoadVehicles(bool part_of_load);
 
struct LoadgameState;
 
extern bool LoadOldVehicle(LoadgameState *ls, int num);
 

	
 
@@ -712,4 +711,6 @@ Trackdir GetVehicleTrackdir(const Vehicl
 

	
 
void CheckVehicle32Day(Vehicle *v);
 

	
 
static const int32 INVALID_COORD = 0x7fffffff;
 

	
 
#endif /* VEHICLE_BASE_H */
src/viewport.cpp
Show inline comments
 
@@ -2785,33 +2785,3 @@ void ResetObjectToPlace()
 
{
 
	SetObjectToPlace(SPR_CURSOR_MOUSE, PAL_NONE, VHM_NONE, WC_MAIN_WINDOW, 0);
 
}
 

	
 

	
 
void SaveViewportBeforeSaveGame()
 
{
 
	const Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
 

	
 
	if (w != NULL) {
 
		_saved_scrollpos_x = w->viewport->scrollpos_x;
 
		_saved_scrollpos_y = w->viewport->scrollpos_y;
 
		_saved_scrollpos_zoom = w->viewport->zoom;
 
	}
 
}
 

	
 
void ResetViewportAfterLoadGame()
 
{
 
	Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
 

	
 
	w->viewport->scrollpos_x = _saved_scrollpos_x;
 
	w->viewport->scrollpos_y = _saved_scrollpos_y;
 
	w->viewport->dest_scrollpos_x = _saved_scrollpos_x;
 
	w->viewport->dest_scrollpos_y = _saved_scrollpos_y;
 

	
 
	ViewPort *vp = w->viewport;
 
	vp->zoom = min(_saved_scrollpos_zoom, ZOOM_LVL_MAX);
 
	vp->virtual_width = ScaleByZoom(vp->width, vp->zoom);
 
	vp->virtual_height = ScaleByZoom(vp->height, vp->zoom);
 

	
 
	DoZoomInOutWindow(ZOOM_NONE, w); // update button status
 
	MarkWholeScreenDirty();
 
}
src/water.h
Show inline comments
 
@@ -15,6 +15,5 @@ void DrawWaterClassGround(const struct T
 
void DrawShoreTile(Slope tileh);
 

	
 
void MakeWaterKeepingClass(TileIndex tile, Owner o);
 
void SetWaterClassDependingOnSurroundings(TileIndex t, bool include_invalid_water_class);
 

	
 
#endif /* WATER_H */
src/water_cmd.cpp
Show inline comments
 
@@ -101,88 +101,6 @@ static void MarkCanalsAndRiversAroundDir
 
	}
 
}
 

	
 
/**
 
 * Makes a tile canal or water depending on the surroundings.
 
 *
 
 * Must only be used for converting old savegames. Use WaterClass now.
 
 *
 
 * This as for example docks and shipdepots do not store
 
 * whether the tile used to be canal or 'normal' water.
 
 * @param t the tile to change.
 
 * @param o the owner of the new tile.
 
 * @param include_invalid_water_class Also consider WATER_CLASS_INVALID, i.e. industry tiles on land
 
 */
 
void SetWaterClassDependingOnSurroundings(TileIndex t, bool include_invalid_water_class)
 
{
 
	/* If the slope is not flat, we always assume 'land' (if allowed). Also for one-corner-raised-shores.
 
	 * Note: Wrt. autosloping under industry tiles this is the most fool-proof behaviour. */
 
	if (GetTileSlope(t, NULL) != SLOPE_FLAT) {
 
		if (include_invalid_water_class) {
 
			SetWaterClass(t, WATER_CLASS_INVALID);
 
			return;
 
		} else {
 
			NOT_REACHED();
 
		}
 
	}
 

	
 
	/* Mark tile dirty in all cases */
 
	MarkTileDirtyByTile(t);
 

	
 
	if (TileX(t) == 0 || TileY(t) == 0 || TileX(t) == MapMaxX() - 1 || TileY(t) == MapMaxY() - 1) {
 
		/* tiles at map borders are always WATER_CLASS_SEA */
 
		SetWaterClass(t, WATER_CLASS_SEA);
 
		return;
 
	}
 

	
 
	bool has_water = false;
 
	bool has_canal = false;
 
	bool has_river = false;
 

	
 
	for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
 
		TileIndex neighbour = TileAddByDiagDir(t, dir);
 
		switch (GetTileType(neighbour)) {
 
			case MP_WATER:
 
				/* clear water and shipdepots have already a WaterClass associated */
 
				if (IsCoast(neighbour)) {
 
					has_water = true;
 
				} else if (!IsLock(neighbour)) {
 
					switch (GetWaterClass(neighbour)) {
 
						case WATER_CLASS_SEA:   has_water = true; break;
 
						case WATER_CLASS_CANAL: has_canal = true; break;
 
						case WATER_CLASS_RIVER: has_river = true; break;
 
						default: NOT_REACHED();
 
					}
 
				}
 
				break;
 

	
 
			case MP_RAILWAY:
 
				/* Shore or flooded halftile */
 
				has_water |= (GetRailGroundType(neighbour) == RAIL_GROUND_WATER);
 
				break;
 

	
 
			case MP_TREES:
 
				/* trees on shore */
 
				has_water |= (GetTreeGround(neighbour) == TREE_GROUND_SHORE);
 
				break;
 

	
 
			default: break;
 
		}
 
	}
 

	
 
	if (!has_water && !has_canal && !has_river && include_invalid_water_class) {
 
		SetWaterClass(t, WATER_CLASS_INVALID);
 
		return;
 
	}
 

	
 
	if (has_river && !has_canal) {
 
		SetWaterClass(t, WATER_CLASS_RIVER);
 
	} else if (has_canal || !has_water) {
 
		SetWaterClass(t, WATER_CLASS_CANAL);
 
	} else {
 
		SetWaterClass(t, WATER_CLASS_SEA);
 
	}
 
}
 

	
 

	
 
/** Build a ship depot.
 
 * @param tile tile where ship depot is built
src/waypoint.cpp
Show inline comments
 
@@ -11,7 +11,6 @@
 
#include "rail_map.h"
 
#include "rail.h"
 
#include "bridge_map.h"
 
#include "saveload.h"
 
#include "station_base.h"
 
#include "town.h"
 
#include "waypoint.h"
 
@@ -157,29 +156,6 @@ static Waypoint *FindDeletedWaypointClos
 
	return best;
 
}
 

	
 
/**
 
 * Update waypoint graphics id against saved GRFID/localidx.
 
 * This is to ensure the chosen graphics are correct if GRF files are changed.
 
 */
 
void AfterLoadWaypoints()
 
{
 
	Waypoint *wp;
 

	
 
	FOR_ALL_WAYPOINTS(wp) {
 
		uint i;
 

	
 
		if (wp->grfid == 0) continue;
 

	
 
		for (i = 0; i < GetNumCustomStations(STAT_CLASS_WAYP); i++) {
 
			const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, i);
 
			if (statspec != NULL && statspec->grffile->grfid == wp->grfid && statspec->localidx == wp->localidx) {
 
				wp->stat_id = i;
 
				break;
 
			}
 
		}
 
	}
 
}
 

	
 
/** Convert existing rail to waypoint. Eg build a waypoint station over
 
 * piece of rail
 
 * @param tile tile where waypoint will be built
 
@@ -463,69 +439,8 @@ Waypoint::~Waypoint()
 
	this->xy = INVALID_TILE;
 
}
 

	
 
/**
 
 * Fix savegames which stored waypoints in their old format
 
 */
 
void FixOldWaypoints()
 
{
 
	Waypoint *wp;
 

	
 
	/* Convert the old 'town_or_string', to 'string' / 'town' / 'town_cn' */
 
	FOR_ALL_WAYPOINTS(wp) {
 
		wp->town_index = ClosestTownFromTile(wp->xy, UINT_MAX)->index;
 
		wp->town_cn = 0;
 
		if (wp->string & 0xC000) {
 
			wp->town_cn = wp->string & 0x3F;
 
			wp->string = STR_NULL;
 
		}
 
	}
 
}
 

	
 
void InitializeWaypoints()
 
{
 
	_Waypoint_pool.CleanPool();
 
	_Waypoint_pool.AddBlockToPool();
 
}
 

	
 
static const SaveLoad _waypoint_desc[] = {
 
	SLE_CONDVAR(Waypoint, xy,         SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Waypoint, xy,         SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, town_index, SLE_UINT16,                 12, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, town_cn,    SLE_FILE_U8 | SLE_VAR_U16,  12, 88),
 
	SLE_CONDVAR(Waypoint, town_cn,    SLE_UINT16,                 89, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, string,     SLE_STRINGID,                0, 83),
 
	SLE_CONDSTR(Waypoint, name,       SLE_STR, 0,                 84, SL_MAX_VERSION),
 
	    SLE_VAR(Waypoint, deleted,    SLE_UINT8),
 

	
 
	SLE_CONDVAR(Waypoint, build_date, SLE_FILE_U16 | SLE_VAR_I32,  3, 30),
 
	SLE_CONDVAR(Waypoint, build_date, SLE_INT32,                  31, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, localidx,   SLE_UINT8,                   3, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, grfid,      SLE_UINT32,                 17, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, owner,      SLE_UINT8,                 101, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
 
static void Save_WAYP()
 
{
 
	Waypoint *wp;
 

	
 
	FOR_ALL_WAYPOINTS(wp) {
 
		SlSetArrayIndex(wp->index);
 
		SlObject(wp, _waypoint_desc);
 
	}
 
}
 

	
 
static void Load_WAYP()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		Waypoint *wp = new (index) Waypoint();
 
		SlObject(wp, _waypoint_desc);
 
	}
 
}
 

	
 
extern const ChunkHandler _waypoint_chunk_handlers[] = {
 
	{ 'CHKP', Save_WAYP, Load_WAYP, CH_ARRAY | CH_LAST},
 
};
src/waypoint.h
Show inline comments
 
@@ -12,6 +12,7 @@
 
#include "station_type.h"
 
#include "town_type.h"
 
#include "viewport_type.h"
 
#include "date_type.h"
 

	
 
DECLARE_OLD_POOL(Waypoint, Waypoint, 3, 8000)
 

	
 
@@ -63,8 +64,6 @@ CommandCost RemoveTrainWaypoint(TileInde
 
Station *ComposeWaypointStation(TileIndex tile);
 
void ShowWaypointWindow(const Waypoint *wp);
 
void DrawWaypointSprite(int x, int y, int stat_id, RailType railtype);
 
void FixOldWaypoints();
 
void UpdateAllWaypointSigns();
 
void AfterLoadWaypoints();
 

	
 
#endif /* WAYPOINT_H */
src/win32.cpp
Show inline comments
 
@@ -5,7 +5,7 @@
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "debug.h"
 
#include "saveload.h"
 
#include "saveload/saveload.h"
 
#include "gfx_func.h"
 
#include "textbuf_gui.h"
 
#include "fileio_func.h"
0 comments (0 inline, 0 general)