Changeset - r3765:c9eaea3d3f78
[Not reviewed]
master
0 6 0
peter1138 - 18 years ago 2006-05-06 21:46:26
peter1138@openttd.org
(svn r4757) - Newstations: add saveload support for custom station speclists
6 files changed with 53 insertions and 2 deletions:
0 comments (0 inline, 0 general)
newgrf_station.c
Show inline comments
 
@@ -119,96 +119,113 @@ uint GetNumStationClasses(void)
 

	
 
/**
 
 * Return the number of stations for the given station class.
 
 * @param sclass Index of the station class.
 
 * @return Number of stations in the class.
 
 */
 
uint GetNumCustomStations(StationClassID sclass)
 
{
 
	assert(sclass < STAT_CLASS_MAX);
 
	return station_classes[sclass].stations;
 
}
 

	
 
/**
 
 * Tie a station spec to its station class.
 
 * @param spec The station spec.
 
 */
 
void SetCustomStationSpec(StationSpec *statspec)
 
{
 
	StationClass *station_class;
 
	int i;
 

	
 
	assert(statspec->sclass < STAT_CLASS_MAX);
 
	station_class = &station_classes[statspec->sclass];
 

	
 
	i = station_class->stations++;
 
	station_class->spec = realloc(station_class->spec, station_class->stations * sizeof(*station_class->spec));
 

	
 
	station_class->spec[i] = statspec;
 
}
 

	
 
/**
 
 * Retrieve a station spec from a class.
 
 * @param sclass Index of the station class.
 
 * @param station The station index with the class.
 
 * @return The station spec.
 
 */
 
const StationSpec *GetCustomStationSpec(StationClassID sclass, uint station)
 
{
 
	assert(sclass < STAT_CLASS_MAX);
 
	if (station < station_classes[sclass].stations)
 
		return station_classes[sclass].spec[station];
 

	
 
	// If the custom station isn't defined any more, then the GRF file
 
	// probably was not loaded.
 
	return NULL;
 
}
 

	
 

	
 
const StationSpec *GetCustomStationSpecByGrf(uint32 grfid, byte localidx)
 
{
 
	StationClassID i;
 
	uint j;
 

	
 
	for (i = STAT_CLASS_DFLT; i < STAT_CLASS_MAX; i++) {
 
		for (j = 0; j < station_classes[i].stations; j++) {
 
			const StationSpec *statspec = station_classes[i].spec[j];
 
			if (statspec == NULL) continue;
 
			if (statspec->grfid == grfid && statspec->localidx == localidx) return statspec;
 
		}
 
	}
 

	
 
	return NULL;
 
}
 

	
 

	
 
/* Evaluate a tile's position within a station, and return the result a bitstuffed format.
 
 * if not centred: .TNLcCpP, if centred: .TNL..CP
 
 * T = Tile layout number (GetStationGfx), N = Number of platforms, L = Length of platforms
 
 * C = Current platform number from start, c = from end
 
 * P = Position along platform from start, p = from end
 
 * if centred, C/P start from the centre and c/p are not available.
 
 */
 
uint32 GetPlatformInfo(Axis axis, byte tile, int platforms, int length, int x, int y, bool centred)
 
{
 
	uint32 retval = 0;
 

	
 
	if (axis == AXIS_X) {
 
		intswap(platforms, length);
 
		intswap(x, y);
 
	}
 

	
 
	/* Limit our sizes to 4 bits */
 
	platforms = min(15, platforms);
 
	length    = min(15, length);
 
	x = min(15, x);
 
	y = min(15, y);
 
	if (centred) {
 
		x -= platforms / 2;
 
		y -= length / 2;
 
		SB(retval,  0, 4, clamp(y, -8, 7));
 
		SB(retval,  4, 4, clamp(x, -8, 7));
 
	} else {
 
		SB(retval,  0, 4, y);
 
		SB(retval,  4, 4, length - y - 1);
 
		SB(retval,  8, 4, x);
 
		SB(retval, 12, 4, platforms - x - 1);
 
	}
 
	SB(retval, 16, 4, length);
 
	SB(retval, 20, 4, platforms);
 
	SB(retval, 24, 4, tile);
 

	
 
	return retval;
 
}
 

	
 

	
 
/* Find the end of a railway station, from the tile, in the direction of delta.
 
 * If check_type is set, we stop if the custom station type changes.
 
 * If check_axis is set, we stop if the station direction changes.
 
 */
 
static TileIndex FindRailStationEnd(TileIndex tile, TileIndexDiff delta, bool check_type, bool check_axis)
 
{
 
	bool waypoint;
 
	byte orig_type = 0;
newgrf_station.h
Show inline comments
 
@@ -49,65 +49,66 @@ typedef struct StationSpec {
 
	/** Cargo threshold for choosing between little and lots of cargo
 
	 * @note little/lots are equivalent to the moving/loading states for vehicles
 
	 */
 
	uint16 cargo_threshold;
 

	
 
	uint32 cargo_triggers; ///< Bitmask of cargo types which cause trigger re-randomizing
 

	
 
	byte callbackmask; ///< Bitmask of callbacks to use, @see newgrf_callbacks.h
 

	
 
	byte flags; ///< Bitmask of flags, bit 0: use different sprite set; bit 1: divide cargo about by station size
 

	
 
	byte pylons;  ///< Bitmask of base tiles (0 - 7) which should contain elrail pylons
 
	byte wires;   ///< Bitmask of base tiles (0 - 7) which should contain elrail wires
 
	byte blocked; ///< Bitmask of base tiles (0 - 7) which are blocked to trains
 

	
 
	byte lengths;
 
	byte *platforms;
 
	StationLayout **layouts;
 

	
 
	/**
 
	 * NUM_GLOBAL_CID sprite groups.
 
	 * Used for obtaining the sprite offset of custom sprites, and for
 
	 * evaluating callbacks.
 
	 */
 
	SpriteGroup *spritegroup[NUM_GLOBAL_CID];
 
} StationSpec;
 

	
 
/**
 
 * Struct containing information relating to station classes.
 
 */
 
typedef struct StationClass {
 
	uint32 id;          ///< ID of this class, e.g. 'DFLT', 'WAYP', etc.
 
	StringID name;      ///< Name of this class.
 
	uint stations;      ///< Number of stations in this class.
 
	StationSpec **spec; ///< Array of station specifications.
 
} StationClass;
 

	
 
void ResetStationClasses(void);
 
StationClassID AllocateStationClass(uint32 class);
 
void SetStationClassName(StationClassID sclass, StringID name);
 
StringID GetStationClassName(StationClassID sclass);
 
StringID *BuildStationClassDropdown(void);
 

	
 
uint GetNumStationClasses(void);
 
uint GetNumCustomStations(StationClassID sclass);
 

	
 
void SetCustomStationSpec(StationSpec *statspec);
 
const StationSpec *GetCustomStationSpec(StationClassID sclass, uint station);
 
const StationSpec *GetCustomStationSpecByGrf(uint32 grfid, byte localidx);
 

	
 
/* Get sprite offset for a given custom station and station structure (may be
 
 * NULL - that means we are in a build dialog). The station structure is used
 
 * for variational sprite groups. */
 
SpriteID GetCustomStationRelocation(const StationSpec *statspec, const Station *st, TileIndex tile);
 
uint16 GetStationCallback(uint16 callback, uint32 param1, uint32 param2, const StationSpec *statspec, const Station *st, TileIndex tile);
 

	
 
/* Allocate a StationSpec to a Station. This is called once per build operation. */
 
int AllocateSpecToStation(const StationSpec *statspec, Station *st, bool exec);
 

	
 
/* Deallocate a StationSpec from a Station. Called when removing a single station tile. */
 
bool DeallocateSpecFromStation(Station *st, byte specindex);
 

	
 
/* Draw representation of a station tile for GUI purposes. */
 
bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID sclass, uint station);
 

	
 
#endif /* NEWGRF_STATION_H */
openttd.c
Show inline comments
 
@@ -1381,50 +1381,52 @@ bool AfterLoadGame(void)
 
				// Clear PBS signals, move back sempahore bit to 2
 
				if (HasSignals(tile)) {
 
					// convert PBS signals to combo-signals
 
					if (HASBIT(_m[tile].m4, 2)) SB(_m[tile].m4, 0, 2, 3);
 

	
 
					SB(_m[tile].m4, 2, 2, HASBIT(_m[tile].m4, 3));
 
					CLRBIT(_m[tile].m4, 3);
 
				}
 

	
 
				// Clear PBS reservation on track
 
				if (!IsTileDepotType(tile, TRANSPORT_RAIL))
 
					SB(_m[tile].m4, 4, 4, 0);
 
				else
 
					CLRBIT(_m[tile].m3, 6);
 
			}
 

	
 
			// Clear PBS reservation on crossing
 
			if (IsTileType(tile, MP_STREET) && IsLevelCrossing(tile))
 
				CLRBIT(_m[tile].m5, 0);
 

	
 
			// Clear PBS reservation on station
 
			if (IsTileType(tile, MP_STATION))
 
				CLRBIT(_m[tile].m3, 6);
 
		} END_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0);
 
	}
 

	
 
	if (CheckSavegameVersion(22))  UpdatePatches();
 

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

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

	
 
	FOR_ALL_PLAYERS(p) p->avail_railtypes = GetPlayerRailtypes(p->index);
 

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

	
 
	return true;
 
}
saveload.c
Show inline comments
 
/* $Id$ */
 

	
 
/** @file
 
 * 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>
 
 * @see ChunkHandler
 
 * @see SaveLoad
 
 */
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "debug.h"
 
#include "functions.h"
 
#include "hal.h"
 
#include "vehicle.h"
 
#include "station.h"
 
#include "thread.h"
 
#include "town.h"
 
#include "player.h"
 
#include "saveload.h"
 
#include "network.h"
 
#include "variables.h"
 
#include <setjmp.h>
 

	
 
const uint16 SAVEGAME_VERSION = 26;
 
const uint16 SAVEGAME_VERSION = 27;
 
uint16 _sl_version;       /// the major savegame version identifier
 
byte   _sl_minor_version; /// the minor savegame version, DO NOT USE!
 

	
 
typedef void WriterProc(uint len);
 
typedef uint ReaderProc(void);
 

	
 
typedef uint ReferenceToIntProc(const void *obj, SLRefType rt);
 
typedef void *IntToReferenceProc(uint index, SLRefType rt);
 

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

	
 
	int 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
 

	
 
	uint32 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
 

	
 
	ReferenceToIntProc *ref_to_int_proc; /// function to convert pointers to numbers when saving a game
 
	IntToReferenceProc *int_to_ref_proc; /// function to convert numbers to pointers when loading a game
 

	
 
	const ChunkHandler* const *chs;      /// the chunk of data that is being processed atm (vehicles, signs, etc.)
 
	const SaveLoad* const *includes;     /// the internal layouf of the given chunk
 

	
 
	/** 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)(void);          /// the function to execute on any encountered error
 
	const char *excpt_msg;               /// the error message
 
	jmp_buf excpt;                       /// @todo used to jump to "exception handler";  really ugly
 
} _sl;
 

	
 

	
 
enum NeedLengthValues {NL_NONE = 0, NL_WANTLENGTH = 1, NL_CALCLENGTH = 2};
 

	
station.h
Show inline comments
 
@@ -149,76 +149,77 @@ static inline Station *GetStation(Statio
 
}
 

	
 
/**
 
 * Get the current size of the StationPool
 
 */
 
static inline uint16 GetStationPoolSize(void)
 
{
 
	return _station_pool.total_items;
 
}
 

	
 
static inline bool IsStationIndex(StationID index)
 
{
 
	return index < GetStationPoolSize();
 
}
 

	
 
#define FOR_ALL_STATIONS_FROM(st, start) for (st = GetStation(start); st != NULL; st = (st->index + 1 < GetStationPoolSize()) ? GetStation(st->index + 1) : NULL)
 
#define FOR_ALL_STATIONS(st) FOR_ALL_STATIONS_FROM(st, 0)
 

	
 

	
 
/* Stuff for ROADSTOPS */
 

	
 
extern MemoryPool _roadstop_pool;
 

	
 
/**
 
 * Get the pointer to the roadstop with index 'index'
 
 */
 
static inline RoadStop *GetRoadStop(uint index)
 
{
 
	return (RoadStop*)GetItemFromPool(&_roadstop_pool, index);
 
}
 

	
 
/**
 
 * Get the current size of the RoadStoptPool
 
 */
 
static inline uint16 GetRoadStopPoolSize(void)
 
{
 
	return _roadstop_pool.total_items;
 
}
 

	
 
#define FOR_ALL_ROADSTOPS_FROM(rs, start) for (rs = GetRoadStop(start); rs != NULL; rs = (rs->index + 1 < GetRoadStopPoolSize()) ? GetRoadStop(rs->index + 1) : NULL)
 
#define FOR_ALL_ROADSTOPS(rs) FOR_ALL_ROADSTOPS_FROM(rs, 0)
 

	
 
/* End of stuff for ROADSTOPS */
 

	
 

	
 
VARDEF bool _station_sort_dirty[MAX_PLAYERS];
 
VARDEF bool _global_station_sort_dirty;
 

	
 
void AfterLoadStations(void);
 
void GetProductionAroundTiles(AcceptedCargo produced, TileIndex tile, int w, int h, int rad);
 
void GetAcceptanceAroundTiles(AcceptedCargo accepts, TileIndex tile, int w, int h, int rad);
 
uint GetStationPlatforms(const Station *st, TileIndex tile);
 

	
 

	
 
const DrawTileSprites *GetStationTileLayout(byte gfx);
 
void StationPickerDrawSprite(int x, int y, RailType railtype, int image);
 

	
 
RoadStop * GetRoadStopByTile(TileIndex tile, RoadStopType type);
 
RoadStop * GetPrimaryRoadStop(const Station *st, RoadStopType type);
 
uint GetNumRoadStops(const Station* st, RoadStopType type);
 
RoadStop * AllocateRoadStop( void );
 
void ClearSlot(Vehicle *v);
 

	
 
/**
 
 * Check if a station really exists.
 
 */
 
static inline bool IsValidStation(const Station *st)
 
{
 
	return st->xy != 0; /* XXX: Replace by INVALID_TILE someday */
 
}
 

	
 
static inline bool IsBuoy(const Station* st)
 
{
 
	return st->had_vehicle_of_type & HVOT_BUOY; /* XXX: We should really ditch this ugly coding and switch to something sane... */
 
}
 

	
 
#endif /* STATION_H */
station_cmd.c
Show inline comments
 
@@ -2776,216 +2776,246 @@ static int32 ClearTile_Station(TileIndex
 
		switch (GetStationType(tile)) {
 
			case STATION_RAIL:    return_cmd_error(STR_300B_MUST_DEMOLISH_RAILROAD);
 
			case STATION_HANGAR:
 
			case STATION_AIRPORT: return_cmd_error(STR_300E_MUST_DEMOLISH_AIRPORT_FIRST);
 
			case STATION_TRUCK:   return_cmd_error(STR_3047_MUST_DEMOLISH_TRUCK_STATION);
 
			case STATION_BUS:     return_cmd_error(STR_3046_MUST_DEMOLISH_BUS_STATION);
 
			case STATION_BUOY:    return_cmd_error(STR_306A_BUOY_IN_THE_WAY);
 
			case STATION_DOCK:    return_cmd_error(STR_304D_MUST_DEMOLISH_DOCK_FIRST);
 
			case STATION_OILRIG:
 
				SetDParam(0, STR_4807_OIL_RIG);
 
				return_cmd_error(STR_4800_IN_THE_WAY);
 
		}
 
	}
 

	
 
	st = GetStationByTile(tile);
 

	
 
	switch (GetStationType(tile)) {
 
		case STATION_RAIL:    return RemoveRailroadStation(st, tile, flags);
 
		case STATION_HANGAR:
 
		case STATION_AIRPORT: return RemoveAirport(st, flags);
 
		case STATION_TRUCK:
 
		case STATION_BUS:     return RemoveRoadStop(st, flags, tile);
 
		case STATION_BUOY:    return RemoveBuoy(st, flags);
 
		case STATION_DOCK:    return RemoveDock(st, flags);
 
		default: break;
 
	}
 

	
 
	return CMD_ERROR;
 
}
 

	
 
void InitializeStations(void)
 
{
 
	/* Clean the station pool and create 1 block in it */
 
	CleanPool(&_station_pool);
 
	AddBlockToPool(&_station_pool);
 

	
 
	/* Clean the roadstop pool and create 1 block in it */
 
	CleanPool(&_roadstop_pool);
 
	AddBlockToPool(&_roadstop_pool);
 

	
 
	_station_tick_ctr = 0;
 

	
 
	// set stations to be sorted on load of savegame
 
	memset(_station_sort_dirty, true, sizeof(_station_sort_dirty));
 
	_global_station_sort_dirty = true; // load of savegame
 
}
 

	
 

	
 
void AfterLoadStations(void)
 
{
 
	Station *st;
 
	uint i;
 

	
 
	/* Update the speclists of all stations to point to the currently loaded custom stations. */
 
	FOR_ALL_STATIONS(st) {
 
		for (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);
 
		}
 
	}
 
}
 

	
 

	
 
const TileTypeProcs _tile_type_station_procs = {
 
	DrawTile_Station,           /* draw_tile_proc */
 
	GetSlopeZ_Station,          /* get_slope_z_proc */
 
	ClearTile_Station,          /* clear_tile_proc */
 
	GetAcceptedCargo_Station,   /* get_accepted_cargo_proc */
 
	GetTileDesc_Station,        /* get_tile_desc_proc */
 
	GetTileTrackStatus_Station, /* get_tile_track_status_proc */
 
	ClickTile_Station,          /* click_tile_proc */
 
	AnimateTile_Station,        /* animate_tile_proc */
 
	TileLoop_Station,           /* tile_loop_clear */
 
	ChangeTileOwner_Station,    /* change_tile_owner_clear */
 
	NULL,                       /* get_produced_cargo_proc */
 
	VehicleEnter_Station,       /* vehicle_enter_tile_proc */
 
	GetSlopeTileh_Station,      /* get_slope_tileh_proc */
 
};
 

	
 
static const SaveLoad _roadstop_desc[] = {
 
	SLE_VAR(RoadStop,xy,           SLE_UINT32),
 
	SLE_VAR(RoadStop,used,         SLE_UINT8),
 
	SLE_VAR(RoadStop,status,       SLE_UINT8),
 
	/* Index was saved in some versions, but this is not needed */
 
	SLE_CONDNULL(4, 0, 8),
 
	SLE_VAR(RoadStop,station,      SLE_UINT16),
 
	SLE_CONDNULL(1, 0, 25),
 

	
 
	SLE_REF(RoadStop,next,         REF_ROADSTOPS),
 
	SLE_REF(RoadStop,prev,         REF_ROADSTOPS),
 

	
 
	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_CONDVAR(Station, bus_tile_obsolete,   SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
 
	SLE_CONDVAR(Station, lorry_tile_obsolete, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
 
	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),
 

	
 
	// alpha_order was stored here in savegame format 0 - 3
 
	SLE_CONDNULL(1, 0, 3),
 

	
 
	SLE_VAR(Station,string_id,          SLE_STRINGID),
 
	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),
 

	
 
	// truck/bus_stop_status was stored here in savegame format 0 - 6
 
	SLE_CONDVAR(Station,truck_stop_status_obsolete, SLE_UINT8, 0, 5),
 
	SLE_CONDVAR(Station,bus_stop_status_obsolete,   SLE_UINT8, 0, 5),
 

	
 
	// blocked_months was stored here in savegame format 0 - 4.0
 
	SLE_CONDVAR(Station,blocked_months_obsolete,    SLE_UINT8, 0, 4),
 

	
 
	SLE_CONDVAR(Station,airport_flags,     SLE_VAR_U32 | SLE_FILE_U16, 0, 2),
 
	SLE_CONDVAR(Station,airport_flags,     SLE_UINT32, 3, SL_MAX_VERSION),
 

	
 
	SLE_CONDNULL(2, 0, 25), /* Ex last-vehicle */
 
	SLE_CONDVAR(Station,last_vehicle_type,          SLE_UINT8 , 26, SL_MAX_VERSION),
 

	
 
	// Was custom station class and id
 
	SLE_CONDNULL(2, 3, 25),
 
	SLE_CONDVAR(Station,build_date,        SLE_UINT16, 3, 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),
 

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

	
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _goods_desc[] = {
 
	SLE_VAR(GoodsEntry,waiting_acceptance, SLE_UINT16),
 
	SLE_VAR(GoodsEntry,days_since_pickup,  SLE_UINT8),
 
	SLE_VAR(GoodsEntry,rating,             SLE_UINT8),
 
	SLE_CONDVAR(GoodsEntry,enroute_from,   SLE_FILE_U8 | SLE_VAR_U16, 0, 6),
 
	SLE_CONDVAR(GoodsEntry,enroute_from,   SLE_UINT16, 7, SL_MAX_VERSION),
 
	SLE_VAR(GoodsEntry,enroute_time,       SLE_UINT8),
 
	SLE_VAR(GoodsEntry,last_speed,         SLE_UINT8),
 
	SLE_VAR(GoodsEntry,last_age,           SLE_UINT8),
 
	SLE_CONDVAR(GoodsEntry,feeder_profit,  SLE_INT32, 14, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

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

	
 

	
 
static void SaveLoad_STNS(Station *st)
 
{
 
	int i;
 
	uint i;
 

	
 
	SlObject(st, _station_desc);
 
	for (i = 0; i != NUM_CARGO; i++) {
 
		SlObject(&st->goods[i], _goods_desc);
 

	
 
		/* In older versions, enroute_from had 0xFF as INVALID_STATION, is now 0xFFFF */
 
		if (CheckSavegameVersion(7) && st->goods[i].enroute_from == 0xFF) {
 
			st->goods[i].enroute_from = INVALID_STATION;
 
		}
 
	}
 

	
 
	if (st->num_specs != 0) {
 
		/* Allocate speclist memory when loading a game */
 
		if (st->speclist == NULL) st->speclist = calloc(st->num_specs, sizeof(*st->speclist));
 
		for (i = 0; i < st->num_specs; i++) SlObject(&st->speclist[i], _station_speclist_desc);
 
	}
 
}
 

	
 
static void Save_STNS(void)
 
{
 
	Station *st;
 
	// Write the stations
 
	FOR_ALL_STATIONS(st) {
 
		if (st->xy != 0) {
 
			SlSetArrayIndex(st->index);
 
			SlAutolength((AutolengthProc*)SaveLoad_STNS, st);
 
		}
 
	}
 
}
 

	
 
static void Load_STNS(void)
 
{
 
	int index;
 
	while ((index = SlIterateArray()) != -1) {
 
		Station *st;
 

	
 
		if (!AddBlockIfNeeded(&_station_pool, index))
 
			error("Stations: failed loading savegame: too many stations");
 

	
 
		st = GetStation(index);
 
		SaveLoad_STNS(st);
 

	
 
		// this means it's an oldstyle savegame without support for nonuniform stations
 
		if (st->train_tile != 0 && st->trainst_h == 0) {
 
			uint w = GB(st->trainst_w, 4, 4);
 
			uint h = GB(st->trainst_w, 0, 4);
 

	
 
			if (GetRailStationAxis(st->train_tile) == AXIS_Y) uintswap(w, h);
 
			st->trainst_w = w;
 
			st->trainst_h = h;
 
		}
 

	
 
		/* In older versions, we had just 1 tile for a bus/lorry, now we have more..
 
		 *  convert, if needed */
 
		if (CheckSavegameVersion(6)) {
 
			if (st->bus_tile_obsolete != 0) {
 
				st->bus_stops = AllocateRoadStop();
 
				if (st->bus_stops == NULL)
 
					error("Station: too many busstations in savegame");
 

	
 
				InitializeRoadStop(st->bus_stops, NULL, st->bus_tile_obsolete, st->index);
 
			}
 
			if (st->lorry_tile_obsolete != 0) {
 
				st->truck_stops = AllocateRoadStop();
0 comments (0 inline, 0 general)