1642 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1642 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "stdafx.h"
 | |
| #include "ttd.h"
 | |
| #include "table/strings.h"
 | |
| #include "map.h"
 | |
| #include "town.h"
 | |
| #include "industry.h"
 | |
| #include "station.h"
 | |
| #include "economy.h"
 | |
| #include "player.h"
 | |
| #include "engine.h"
 | |
| #include "vehicle.h"
 | |
| #include "signs.h"
 | |
| #include "debug.h"
 | |
| #include "depot.h"
 | |
| 
 | |
| enum {
 | |
| 	HEADER_SIZE = 49,
 | |
| 	BUFFER_SIZE = 4096,
 | |
| 
 | |
| 	OLD_MAP_SIZE = 256 * 256
 | |
| };
 | |
| 
 | |
| typedef 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;
 | |
| } LoadgameState;
 | |
| 
 | |
| typedef bool OldChunkProc(LoadgameState *ls, int num);
 | |
| 
 | |
| typedef struct OldChunks {
 | |
| 	uint32 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
 | |
| } OldChunks;
 | |
| 
 | |
| /* OldChunk-Type */
 | |
| enum {
 | |
| 	OC_END       = 0,
 | |
| 	OC_NULL      = 1 << 0,
 | |
| 	OC_CHUNK     = 1 << 1,
 | |
| 	OC_ASSERT    = 1 << 2,
 | |
| 
 | |
| 	OC_VAR_I8    = 1 << 9,
 | |
| 	OC_VAR_U8    = 1 << 10,
 | |
| 	OC_VAR_I16   = 1 << 11,
 | |
| 	OC_VAR_U16   = 1 << 12,
 | |
| 	OC_VAR_I32   = 1 << 13,
 | |
| 	OC_VAR_U32   = 1 << 14,
 | |
| 	OC_VAR_I64   = 1 << 15,
 | |
| 
 | |
| 	OC_FILE_I8   = 1 << 17,
 | |
| 	OC_FILE_U8   = 1 << 18,
 | |
| 	OC_FILE_I16  = 1 << 19,
 | |
| 	OC_FILE_U16  = 1 << 20,
 | |
| 	OC_FILE_I32  = 1 << 21,
 | |
| 	OC_FILE_U32  = 1 << 22,
 | |
| 
 | |
| 	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
 | |
| };
 | |
| /* If it fails, check lines above.. */
 | |
| assert_compile(sizeof(TileIndex) == 4);
 | |
| 
 | |
| static LoadgameState _ls;
 | |
| static uint32 _bump_assert_value;
 | |
| static bool   _read_ttdpatch_flags;
 | |
| 
 | |
| /**
 | |
|  *
 | |
|  * 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 = 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, 1)("[OldLoader] 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 */
 | |
| 	int8 new_byte;
 | |
| 
 | |
| 	/* Check if we are reading a chunk */
 | |
| 	if (ls->chunk_size != 0) {
 | |
| 		ls->total_read++;
 | |
| 		ls->chunk_size--;
 | |
| 
 | |
| 		/* If we are decoding, return the decode_char */
 | |
| 		if (ls->decoding)
 | |
| 			return ls->decode_char;
 | |
| 
 | |
| 		/* Else return byte from file */
 | |
| 		return ReadByteFromFile(ls);
 | |
| 	}
 | |
| 
 | |
| 	/* Read new chunk */
 | |
| 	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;
 | |
| 	}
 | |
| 
 | |
| 	/* Call this function again to return a byte */
 | |
| 	return ReadByte(ls);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  *
 | |
|  * Loads a chunk from the old savegame
 | |
|  *
 | |
|  */
 | |
| static bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks)
 | |
| {
 | |
| 	const OldChunks *chunk = chunks;
 | |
| 	byte *ptr;
 | |
| 	byte *base_ptr = base;
 | |
| 	uint i;
 | |
| 
 | |
| 	while (chunk->type != OC_END) {
 | |
| 		ptr = chunk->ptr;
 | |
| 
 | |
| 		for (i = 0; i < chunk->amount; i++) {
 | |
| 			if (ls->failed)
 | |
| 				return false;
 | |
| 
 | |
| 			/* Handle simple types */
 | |
| 			if ((chunk->type & 0xFF) != 0) {
 | |
| 				switch (chunk->type & 0xFF) {
 | |
| 					case OC_NULL:
 | |
| 						/* Just read the byte and forget about it */
 | |
| 						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)("[OldLoader] Assert point: %x / %x", ls->total_read, chunk->offset + _bump_assert_value);
 | |
| 						if (ls->total_read != chunk->offset + _bump_assert_value)
 | |
| 							ls->failed = true;
 | |
| 
 | |
| 						break;
 | |
| 
 | |
| 				}
 | |
| 			} else {
 | |
| 				uint32 res = 0;
 | |
| 
 | |
| 				/* Reading from the file: bit 16 to 23 have the FILE */
 | |
| 				switch (((chunk->type >> 16) & 0xFF) << 16) {
 | |
| 					case OC_FILE_I8:
 | |
| 						res = ReadByte(ls);
 | |
| 						res = (int8)res;
 | |
| 						break;
 | |
| 
 | |
| 					case OC_FILE_U8:
 | |
| 						res = ReadByte(ls);
 | |
| 						break;
 | |
| 
 | |
| 					case OC_FILE_U16:
 | |
| 						res =  ReadByte(ls);
 | |
| 						res += ReadByte(ls) << 8;
 | |
| 						break;
 | |
| 
 | |
| 					case OC_FILE_I16:
 | |
| 						res =  ReadByte(ls);
 | |
| 						res += ReadByte(ls) << 8;
 | |
| 						res = (int16)res;
 | |
| 						break;
 | |
| 
 | |
| 					case OC_FILE_U32:
 | |
| 						res =  ReadByte(ls);
 | |
| 						res += ReadByte(ls) << 8;
 | |
| 						res += ReadByte(ls) << 16;
 | |
| 						res += ReadByte(ls) << 24;
 | |
| 						break;
 | |
| 
 | |
| 					case OC_FILE_I32:
 | |
| 						res =  ReadByte(ls);
 | |
| 						res += ReadByte(ls) << 8;
 | |
| 						res += ReadByte(ls) << 16;
 | |
| 						res += ReadByte(ls) << 24;
 | |
| 						res = (int32)res;
 | |
| 						break;
 | |
| 				}
 | |
| 
 | |
| 				/* Sanity check */
 | |
| 				assert(base_ptr != NULL || chunk->ptr != NULL);
 | |
| 
 | |
| 				/* Writing to the var: bit 8 till 15 have the VAR */
 | |
| 				switch (((chunk->type >> 8) & 0xFF) << 8) {
 | |
| 					case OC_VAR_I8:
 | |
| 						/* Write the data */
 | |
| 						if (chunk->ptr != NULL) {
 | |
| 							*(int8 *)ptr = res & 0xFF;
 | |
| 							ptr++;
 | |
| 						} else
 | |
| 							*(int8 *)(base_ptr + chunk->offset) = res & 0xFF;
 | |
| 							break;
 | |
| 
 | |
| 					case OC_VAR_U8:
 | |
| 						/* Write the data */
 | |
| 						if (chunk->ptr != NULL) {
 | |
| 							*(uint8 *)ptr = res & 0xFF;
 | |
| 							ptr++;
 | |
| 						} else
 | |
| 							*(uint8 *)(base_ptr + chunk->offset) = res & 0xFF;
 | |
| 							break;
 | |
| 
 | |
| 					case OC_VAR_U16:
 | |
| 						/* Write the data */
 | |
| 						if (chunk->ptr != NULL) {
 | |
| 							*(uint16 *)ptr = res & 0xFFFF;
 | |
| 							ptr += 2;
 | |
| 						} else
 | |
| 							*(uint16 *)(base_ptr + chunk->offset) = res & 0xFFFF;
 | |
| 							break;
 | |
| 
 | |
| 					case OC_VAR_I16:
 | |
| 						/* Write the data */
 | |
| 						if (chunk->ptr != NULL) {
 | |
| 							*(int16 *)ptr = res & 0xFFFF;
 | |
| 							ptr += 2;
 | |
| 						} else
 | |
| 							*(int16 *)(base_ptr + chunk->offset) = res & 0xFFFF;
 | |
| 							break;
 | |
| 
 | |
| 					case OC_VAR_U32:
 | |
| 						/* Write the data */
 | |
| 						if (chunk->ptr != NULL) {
 | |
| 							*(uint32 *)ptr = res;
 | |
| 							ptr += 4;
 | |
| 						} else
 | |
| 							*(uint32 *)(base_ptr + chunk->offset) = res;
 | |
| 							break;
 | |
| 
 | |
| 					case OC_VAR_I32:
 | |
| 						/* Write the data */
 | |
| 						if (chunk->ptr != NULL) {
 | |
| 							*(int32 *)ptr = res;
 | |
| 							ptr += 4;
 | |
| 						} else
 | |
| 							*(int32 *)(base_ptr + chunk->offset) = res;
 | |
| 							break;
 | |
| 
 | |
| 					case OC_VAR_I64:
 | |
| 						/* Write the data */
 | |
| 						if (chunk->ptr != NULL) {
 | |
| 							*(int64 *)ptr = res;
 | |
| 							ptr += 8;
 | |
| 						} else
 | |
| 							*(int64 *)(base_ptr + chunk->offset) = res;
 | |
| 							break;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		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;
 | |
| 
 | |
| 	_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(void)
 | |
| {
 | |
| 	Town *town;
 | |
| 
 | |
| 	/* Convert town-names if needed */
 | |
| 	FOR_ALL_TOWNS(town) {
 | |
| 		if (town->xy == 0)
 | |
| 			continue;
 | |
| 
 | |
| 		if (IS_INT_INSIDE(town->townnametype, 0x20C1, 0x20C3)) {
 | |
| 			town->townnametype = SPECSTR_TOWNNAME_ENGLISH + _opt.town_name;
 | |
| 			town->townnameparts = GetOldTownName(town->townnameparts, _opt.town_name);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void FixOldStations(void)
 | |
| {
 | |
| 	Station *st;
 | |
| 
 | |
| 	FOR_ALL_STATIONS(st) {
 | |
| 		/* Check if we need to swap width and height for the station */
 | |
| 		if (st->train_tile != 0 && _map5[st->train_tile] & 1) {
 | |
| 			swap_byte(&st->trainst_w, &st->trainst_h);
 | |
| 		}
 | |
| 
 | |
| 		/* Check if there is a bus or truck station, and convert to new format */
 | |
| 		if (st->bus_tile_obsolete != 0) {
 | |
| 			st->bus_stops = AllocateRoadStop();
 | |
| 			st->bus_stops->xy = st->bus_tile_obsolete;
 | |
| 			st->bus_stops->used = true;
 | |
| 			st->bus_stops->status = 3;
 | |
| 			st->bus_stops->station = st->index;
 | |
| 			st->bus_stops->next = NULL;
 | |
| 			st->bus_stops->prev = NULL;
 | |
| 			st->bus_stops->slot[0] = st->bus_stops->slot[1] = INVALID_SLOT;
 | |
| 		}
 | |
| 
 | |
| 		if (st->lorry_tile_obsolete != 0) {
 | |
| 			st->truck_stops = AllocateRoadStop();
 | |
| 			st->truck_stops->xy = st->lorry_tile_obsolete;
 | |
| 			st->truck_stops->used = true;
 | |
| 			st->truck_stops->status = 3;
 | |
| 			st->truck_stops->station = st->index;
 | |
| 			st->truck_stops->next = NULL;
 | |
| 			st->truck_stops->prev = NULL;
 | |
| 			st->truck_stops->slot[0] = st->truck_stops->slot[1] = INVALID_SLOT;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void FixOldVehicles(void)
 | |
| {
 | |
| 	/* Check for shared orders, and link them correctly */
 | |
| 	{
 | |
| 		Vehicle *v;
 | |
| 
 | |
| 		FOR_ALL_VEHICLES(v) {
 | |
| 			Vehicle *u;
 | |
| 
 | |
| 			if (v->type == 0)
 | |
| 				continue;
 | |
| 
 | |
| 			FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
 | |
| 				if (u->type == 0)
 | |
| 					continue;
 | |
| 
 | |
| 					/* If a vehicle has the same orders, add the link to eachother
 | |
| 				in both vehicles */
 | |
| 				if (v->orders == u->orders) {
 | |
| 					v->next_shared = u;
 | |
| 					u->prev_shared = v;
 | |
| 					break;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	_vehicle_id_ctr_day = 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * 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,    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[256];
 | |
| extern char _name_array[512][32];
 | |
| extern uint16 _custom_sprites_base;
 | |
| 
 | |
| static byte   _old_vehicle_multipler;
 | |
| static uint8  _old_map3[OLD_MAP_SIZE * 2];
 | |
| static bool   _new_ttdpatch_format;
 | |
| static uint32 _old_town_index;
 | |
| static uint16 _old_string_id;
 | |
| static uint16 _old_string_id_2;
 | |
| 
 | |
| void ReadTTDPatchFlags(void)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	if (_read_ttdpatch_flags)
 | |
| 		return;
 | |
| 
 | |
| 	_read_ttdpatch_flags = true;
 | |
| 
 | |
| 	/* TTDPatch misuses _old_map3 for flags.. read them! */
 | |
| 	_old_vehicle_multipler = _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_multipler < 2)
 | |
| 		_old_vehicle_multipler++;
 | |
| 
 | |
| 	/* TTDPatch incraeses 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_multipler - 1) * 850 * 128;
 | |
| 
 | |
| 	_new_ttdpatch_format   = false;
 | |
| 
 | |
| 	/* Check if we have a modern TTDPatch savegame (has extra data all around) */
 | |
| 	if (memcmp(&_old_map3[0x1FFFA], "TTDp", 4) == 0)
 | |
| 		_new_ttdpatch_format = true;
 | |
| 
 | |
| 	/* Clean the misused places */
 | |
| 	for (i = 0; i < 17; i++)
 | |
| 		_old_map3[i] = 0;
 | |
| 	for (i = 0x1FE00; i < 0x20000; i++)
 | |
| 		_old_map3[i] = 0;
 | |
| 
 | |
| 	if (_new_ttdpatch_format)
 | |
| 		DEBUG(oldloader, 1)("[OldLoader] Found TTDPatch game");
 | |
| 
 | |
| 	DEBUG(oldloader, 1)("[OldLoader] Vehicle-multipler is set to %d (%d vehicles)", _old_vehicle_multipler, _old_vehicle_multipler * 850);
 | |
| }
 | |
| 
 | |
| static const OldChunks town_chunk[] = {
 | |
| 	OCL_SVAR(   OC_TILE, Town, xy ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, population ),
 | |
| 	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 8bit.. sure there is
 | |
| 	nothing changed?? */
 | |
| 	OCL_SVAR( OC_FILE_U32 | OC_VAR_U8, Town, have_ratings ),
 | |
| 	OCL_SVAR( OC_FILE_U32 | OC_VAR_U8, Town, statues ),
 | |
| 	OCL_SVAR( OC_UINT16, Town, num_houses ),
 | |
| 	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)
 | |
| {
 | |
| 	if (!AddBlockIfNeeded(&_town_pool, num))
 | |
| 		error("Towns: failed loading savegame: too many towns");
 | |
| 
 | |
| 	return LoadChunk(ls, GetTown(num), town_chunk);
 | |
| }
 | |
| 
 | |
| 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 (!AddBlockIfNeeded(&_order_pool, num))
 | |
| 		error("Orders: failed loading savegame: too many orders");
 | |
| 
 | |
| 	if (!LoadChunk(ls, NULL, order_chunk))
 | |
| 		return false;
 | |
| 
 | |
| 	AssignOrder(GetOrder(num), UnpackOldOrder(_old_order));
 | |
| 
 | |
| 	/* Relink the orders to eachother (in TTD(Patch) the orders for one
 | |
| 	vehicle are behind eachother, with OT_NOTHING as indication that
 | |
| 	it is the last order */
 | |
| 	if (num > 0 && GetOrder(num)->type != OT_NOTHING)
 | |
| 		GetOrder(num - 1)->next = GetOrder(num);
 | |
| 
 | |
| 	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)
 | |
| {
 | |
| 	if (!AddBlockIfNeeded(&_depot_pool, num))
 | |
| 		error("Depots: failed loading savegame: too many depots");
 | |
| 
 | |
| 	if (!LoadChunk(ls, GetDepot(num), depot_chunk))
 | |
| 		return false;
 | |
| 
 | |
| 	if (GetDepot(num)->xy != 0) {
 | |
| 		GetDepot(num)->town_index = REMAP_TOWN_IDX(_old_town_index);
 | |
| 	}
 | |
| 
 | |
| 	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 */
 | |
| 	((int32*)&_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 uint8 _old_platforms;
 | |
| static uint _current_station_id;
 | |
| 
 | |
| static const OldChunks goods_chunk[] = {
 | |
| 	OCL_SVAR( OC_UINT16, GoodsEntry, waiting_acceptance ),
 | |
| 	OCL_SVAR(  OC_UINT8, GoodsEntry, days_since_pickup ),
 | |
| 	OCL_SVAR(  OC_UINT8, GoodsEntry, rating ),
 | |
| 	OCL_SVAR(  OC_FILE_U8 | OC_VAR_U16, GoodsEntry, enroute_from ),
 | |
| 	OCL_SVAR(  OC_UINT8, GoodsEntry, enroute_time ),
 | |
| 	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);
 | |
| 	return LoadChunk(ls, &st->goods[num], goods_chunk);
 | |
| }
 | |
| 
 | |
| static const OldChunks station_chunk[] = {
 | |
| 	OCL_SVAR(   OC_TILE, Station, xy ),
 | |
| 	OCL_VAR ( OC_UINT32,   1, &_old_town_index ),
 | |
| 
 | |
| 	OCL_SVAR(   OC_TILE, Station, bus_tile_obsolete ),
 | |
| 	OCL_SVAR(   OC_TILE, Station, lorry_tile_obsolete ),
 | |
| 	OCL_SVAR(   OC_TILE, Station, train_tile ),
 | |
| 	OCL_SVAR(   OC_TILE, Station, airport_tile ),
 | |
| 	OCL_SVAR(   OC_TILE, Station, dock_tile ),
 | |
| 
 | |
| 	OCL_VAR (  OC_UINT8,   1, &_old_platforms ),
 | |
| 
 | |
| 	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 ),
 | |
| 	OCL_NULL( 2 ),         // Bus/truck status, no longer in use
 | |
| 	OCL_SVAR(  OC_UINT8, Station, blocked_months_obsolete ),
 | |
| 	OCL_NULL( 1 ),         // Unknown
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Station, airport_flags ),
 | |
| 	OCL_SVAR( OC_UINT16, Station, last_vehicle ),
 | |
| 
 | |
| 	OCL_NULL( 4 ),         // Junk at end of chunk
 | |
| 
 | |
| 	OCL_END()
 | |
| };
 | |
| static bool LoadOldStation(LoadgameState *ls, int num)
 | |
| {
 | |
| 	Station *st;
 | |
| 
 | |
| 	if (!AddBlockIfNeeded(&_station_pool, num))
 | |
| 		error("Stations: failed loading savegame: too many stations");
 | |
| 
 | |
| 	st = GetStation(num);
 | |
| 	_current_station_id = num;
 | |
| 
 | |
| 	if (!LoadChunk(ls, st, station_chunk))
 | |
| 		return false;
 | |
| 
 | |
| 	if (st->xy != 0) {
 | |
| 		if (st->train_tile) {
 | |
| 			/* Calculate the trainst_w and trainst_h */
 | |
| 			int w = (_old_platforms >> 3) & 0x7;
 | |
| 			int h = (_old_platforms & 0x7);
 | |
| 			st->trainst_w = w;
 | |
| 			st->trainst_h = h;
 | |
| 		}
 | |
| 
 | |
| 		st->town    = GetTown(REMAP_TOWN_IDX(_old_town_index));
 | |
| 		st->string_id = RemapOldStringID(_old_string_id);
 | |
| 	}
 | |
| 
 | |
| 	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_SVAR(  OC_UINT8, Industry, produced_cargo[0] ),
 | |
| 	OCL_SVAR(  OC_UINT8, Industry, produced_cargo[1] ),
 | |
| 
 | |
| 	OCL_SVAR( OC_UINT16, Industry, cargo_waiting[0] ),
 | |
| 	OCL_SVAR( OC_UINT16, Industry, cargo_waiting[1] ),
 | |
| 
 | |
| 	OCL_SVAR(  OC_UINT8, Industry, production_rate[0] ),
 | |
| 	OCL_SVAR(  OC_UINT8, Industry, production_rate[1] ),
 | |
| 
 | |
| 	OCL_SVAR(  OC_UINT8, Industry, accepts_cargo[0] ),
 | |
| 	OCL_SVAR(  OC_UINT8, Industry, accepts_cargo[1] ),
 | |
| 	OCL_SVAR(  OC_UINT8, Industry, accepts_cargo[2] ),
 | |
| 
 | |
| 	OCL_SVAR(  OC_UINT8, Industry, prod_level ),
 | |
| 
 | |
| 	OCL_SVAR( OC_UINT16, Industry, last_mo_production[0] ),
 | |
| 	OCL_SVAR( OC_UINT16, Industry, last_mo_production[1] ),
 | |
| 	OCL_SVAR( OC_UINT16, Industry, last_mo_transported[0] ),
 | |
| 	OCL_SVAR( OC_UINT16, Industry, last_mo_transported[1] ),
 | |
| 
 | |
| 	OCL_SVAR(  OC_UINT8, Industry, pct_transported[0] ),
 | |
| 	OCL_SVAR(  OC_UINT8, Industry, pct_transported[1] ),
 | |
| 
 | |
| 	OCL_SVAR( OC_UINT16, Industry, total_production[0] ),
 | |
| 	OCL_SVAR( OC_UINT16, Industry, total_production[1] ),
 | |
| 	OCL_SVAR( OC_UINT16, Industry, total_transported[0] ),
 | |
| 	OCL_SVAR( OC_UINT16, Industry, total_transported[1] ),
 | |
| 
 | |
| 	OCL_SVAR(  OC_UINT8, Industry, type ),
 | |
| 	OCL_SVAR(  OC_UINT8, Industry, owner ),
 | |
| 	OCL_SVAR(  OC_UINT8, Industry, color_map ),
 | |
| 	OCL_SVAR(  OC_UINT8, 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;
 | |
| 
 | |
| 	if (!AddBlockIfNeeded(&_industry_pool, num))
 | |
| 		error("Industries: failed loading savegame: too many industries");
 | |
| 
 | |
| 	i = GetIndustry(num);
 | |
| 	if (!LoadChunk(ls, i, industry_chunk))
 | |
| 		return false;
 | |
| 
 | |
| 	if (i->xy != 0) {
 | |
| 		i->town = GetTown(REMAP_TOWN_IDX(_old_town_index));
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| static uint _current_player_id;
 | |
| static uint16 _old_inaugurated_year;
 | |
| static int32 _old_yearly;
 | |
| 
 | |
| static const OldChunks player_yearly_chunk[] = {
 | |
| 	OCL_VAR(  OC_INT32,   1, &_old_yearly ),
 | |
| 	OCL_END()
 | |
| };
 | |
| static bool OldPlayerYearly(LoadgameState *ls, int num)
 | |
| {
 | |
| 	int i;
 | |
| 	Player *p = DEREF_PLAYER(_current_player_id);
 | |
| 
 | |
| 	for (i = 0; i < 13; i++) {
 | |
| 		if (!LoadChunk(ls, NULL, player_yearly_chunk))
 | |
| 			return false;
 | |
| 
 | |
| 		p->yearly_expenses[num][i] = _old_yearly;
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| static const OldChunks player_economy_chunk[] = {
 | |
| 	OCL_SVAR( OC_INT32, PlayerEconomyEntry, income ),
 | |
| 	OCL_SVAR( OC_INT32, PlayerEconomyEntry, expenses ),
 | |
| 	OCL_SVAR( OC_INT32, PlayerEconomyEntry, delivered_cargo ),
 | |
| 	OCL_SVAR( OC_INT32, PlayerEconomyEntry, performance_history ),
 | |
| 	OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, PlayerEconomyEntry, company_value ),
 | |
| 
 | |
| 	OCL_END()
 | |
| };
 | |
| static bool OldPlayerEconomy(LoadgameState *ls, int num)
 | |
| {
 | |
| 	int i;
 | |
| 	Player *p = DEREF_PLAYER(_current_player_id);
 | |
| 
 | |
| 	if (!LoadChunk(ls, &p->cur_economy, player_economy_chunk))
 | |
| 		return false;
 | |
| 
 | |
| 	/* Don't ask, but the number in TTD(Patch) are inversed to OpenTTD */
 | |
| 	p->cur_economy.income   = -p->cur_economy.income;
 | |
| 	p->cur_economy.expenses = -p->cur_economy.expenses;
 | |
| 
 | |
| 	for (i = 0; i < 24; i++) {
 | |
| 		if (!LoadChunk(ls, &p->old_economy[i], player_economy_chunk))
 | |
| 			return false;
 | |
| 
 | |
| 		p->old_economy[i].income   = -p->old_economy[i].income;
 | |
| 		p->old_economy[i].expenses = -p->old_economy[i].expenses;
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| static const OldChunks player_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)
 | |
| {
 | |
| 	Player *p = DEREF_PLAYER(_current_player_id);
 | |
| 
 | |
| 	switch (num) {
 | |
| 		case 0: return LoadChunk(ls, &p->ai.src, player_ai_build_rec_chunk);
 | |
| 		case 1: return LoadChunk(ls, &p->ai.dst, player_ai_build_rec_chunk);
 | |
| 		case 2: return LoadChunk(ls, &p->ai.mid1, player_ai_build_rec_chunk);
 | |
| 		case 3: return LoadChunk(ls, &p->ai.mid2, player_ai_build_rec_chunk);
 | |
| 	}
 | |
| 
 | |
| 	return false;
 | |
| }
 | |
| static const OldChunks player_ai_chunk[] = {
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, state ),
 | |
| 	OCL_NULL( 1 ),         // Junk
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, state_mode ),
 | |
| 	OCL_SVAR( OC_UINT16, PlayerAI, state_counter ),
 | |
| 	OCL_SVAR( OC_UINT16, PlayerAI, timeout_counter ),
 | |
| 
 | |
| 	OCL_CHUNK( 4, OldLoadAIBuildRec ),
 | |
| 
 | |
| 	OCL_NULL( 20 ),        // More junk
 | |
| 
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, cargo_type ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, num_wagons ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, build_kind ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, num_build_rec ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, num_loco_to_build ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, num_want_fullload ),
 | |
| 
 | |
| 	OCL_NULL( 14 ),        // Oh no more junk :|
 | |
| 
 | |
| 	OCL_NULL( 2 ),         // Loco-id, not used
 | |
| 
 | |
| 	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[0] ),
 | |
| 	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[1] ),
 | |
| 	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[2] ),
 | |
| 	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[3] ),
 | |
| 	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[4] ),
 | |
| 	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[5] ),
 | |
| 	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[6] ),
 | |
| 	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[7] ),
 | |
| 	OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[8] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[0] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[1] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[2] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[3] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[4] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[5] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[6] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[7] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[8] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[9] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[10] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[11] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[12] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[13] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[14] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[15] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[16] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[17] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[18] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, order_list_blocks[19] ),
 | |
| 
 | |
| 	OCL_SVAR( OC_UINT16, PlayerAI, start_tile_a ),
 | |
| 	OCL_SVAR( OC_UINT16, PlayerAI, start_tile_b ),
 | |
| 	OCL_SVAR( OC_UINT16, PlayerAI, cur_tile_a ),
 | |
| 	OCL_SVAR( OC_UINT16, PlayerAI, cur_tile_b ),
 | |
| 
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, start_dir_a ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, start_dir_b ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, cur_dir_a ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, cur_dir_b ),
 | |
| 
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_tile_count ),
 | |
| 
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[0] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[0] ),
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[1] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[1] ),
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[2] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[2] ),
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[3] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[3] ),
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[4] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[4] ),
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[5] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[5] ),
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[6] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[6] ),
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[7] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[7] ),
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[8] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[8] ),
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[9] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[9] ),
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[10] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[10] ),
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[11] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[11] ),
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[12] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[12] ),
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[13] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[13] ),
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[14] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[14] ),
 | |
| 	OCL_SVAR(   OC_TILE, PlayerAI, banned_tiles[15] ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, banned_val[15] ),
 | |
| 
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, railtype_to_use ),
 | |
| 	OCL_SVAR(  OC_UINT8, PlayerAI, route_type_mask ),
 | |
| 
 | |
| 	OCL_END()
 | |
| };
 | |
| static bool OldPlayerAI(LoadgameState *ls, int num)
 | |
| {
 | |
| 	Player *p = DEREF_PLAYER(_current_player_id);
 | |
| 
 | |
| 	return LoadChunk(ls, &p->ai, player_ai_chunk);
 | |
| }
 | |
| 
 | |
| static const OldChunks player_chunk[] = {
 | |
| 	OCL_VAR ( OC_UINT16,   1, &_old_string_id ),
 | |
| 	OCL_SVAR( OC_UINT32, Player, name_2 ),
 | |
| 	OCL_SVAR( OC_UINT32, Player, face ),
 | |
| 	OCL_VAR ( OC_UINT16,   1, &_old_string_id_2 ),
 | |
| 	OCL_SVAR( OC_UINT32, Player, president_name_2 ),
 | |
| 
 | |
| 	OCL_SVAR(  OC_INT32, Player, player_money ),
 | |
| 	OCL_SVAR(  OC_INT32, Player, current_loan ),
 | |
| 
 | |
| 	OCL_SVAR(  OC_UINT8, Player, player_color ),
 | |
| 	OCL_SVAR(  OC_UINT8, Player, player_money_fraction ),
 | |
| 	OCL_SVAR(  OC_UINT8, Player, quarters_of_bankrupcy ),
 | |
| 	OCL_SVAR(  OC_UINT8, Player, bankrupt_asked ),
 | |
| 	OCL_SVAR( OC_UINT32, Player, bankrupt_value ),
 | |
| 	OCL_SVAR( OC_UINT16, Player, bankrupt_timeout ),
 | |
| 
 | |
| 	OCL_SVAR( OC_FILE_U32 | OC_VAR_U16, Player, cargo_types ),
 | |
| 
 | |
| 	OCL_CHUNK( 3, OldPlayerYearly ),
 | |
| 	OCL_CHUNK( 1, OldPlayerEconomy ),
 | |
| 
 | |
| 	OCL_VAR ( OC_UINT16,   1,    &_old_inaugurated_year ),
 | |
| 	OCL_SVAR(   OC_TILE, Player, last_build_coordinate ),
 | |
| 	OCL_SVAR(  OC_UINT8, Player, num_valid_stat_ent ),
 | |
| 
 | |
| 	OCL_CHUNK( 1, OldPlayerAI ),
 | |
| 
 | |
| 	OCL_SVAR(  OC_UINT8, Player, block_preview ),
 | |
| 	OCL_SVAR(  OC_UINT8, Player, ai.tick ),
 | |
| 	OCL_SVAR(  OC_UINT8, Player, max_railtype ),
 | |
| 	OCL_SVAR(   OC_TILE, Player, location_of_house ),
 | |
| 	OCL_SVAR(  OC_UINT8, Player, share_owners[0] ),
 | |
| 	OCL_SVAR(  OC_UINT8, Player, share_owners[1] ),
 | |
| 	OCL_SVAR(  OC_UINT8, Player, share_owners[2] ),
 | |
| 	OCL_SVAR(  OC_UINT8, Player, share_owners[3] ),
 | |
| 
 | |
| 	OCL_NULL( 8 ), // junk at end of chunk
 | |
| 
 | |
| 	OCL_END()
 | |
| };
 | |
| static bool LoadOldPlayer(LoadgameState *ls, int num)
 | |
| {
 | |
| 	Player *p = DEREF_PLAYER(num);
 | |
| 
 | |
| 	_current_player_id = num;
 | |
| 
 | |
| 	if (!LoadChunk(ls, p, player_chunk))
 | |
| 		return false;
 | |
| 
 | |
| 	p->name_1 = RemapOldStringID(_old_string_id);
 | |
| 	p->president_name_1 = RemapOldStringID(_old_string_id_2);
 | |
| 	p->money64 = p->player_money;
 | |
| 
 | |
| 	if (num == 0) {
 | |
| 		/* If the first player has no name, make sure we call it UNNAMED */
 | |
| 		if (p->name_1 == 0)
 | |
| 			p->name_1 = STR_SV_UNNAMED;
 | |
| 	} else {
 | |
| 		/* Beside some multiplayer maps (1 on 1), which we don't official support,
 | |
| 		all other players are an AI.. mark them as such */
 | |
| 		p->is_ai = 1;
 | |
| 	}
 | |
| 
 | |
| 	/* 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 10000.. this is a very VERY small chance ;) */
 | |
| 	if (p->player_money == 893288)
 | |
| 		p->money64 = p->player_money = p->current_loan = 100000;
 | |
| 
 | |
| 	_player_colors[num] = p->player_color;
 | |
| 	p->inaugurated_year = _old_inaugurated_year - MAX_YEAR_BEGIN_REAL;
 | |
| 	if (p->location_of_house == 0xFFFF)
 | |
| 		p->location_of_house = 0;
 | |
| 
 | |
| 	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, unk2 ),
 | |
| 	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_special_chunk[] = {
 | |
| 	OCL_SVAR( OC_UINT16, VehicleSpecial, unk0 ),
 | |
| 	OCL_SVAR(  OC_UINT8, VehicleSpecial, unk2 ),
 | |
| 
 | |
| 	OCL_NULL( 7 ), // Junk
 | |
| 
 | |
| 	OCL_END()
 | |
| };
 | |
| static const OldChunks vehicle_disaster_chunk[] = {
 | |
| 	OCL_SVAR( OC_UINT16, VehicleDisaster, image_override ),
 | |
| 	OCL_SVAR( OC_UINT16, VehicleDisaster, unk2 ),
 | |
| 
 | |
| 	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) {
 | |
| 		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_Special:  res = LoadChunk(ls, &v->u.special,  vehicle_special_chunk);  break;
 | |
| 		case VEH_Disaster: res = LoadChunk(ls, &v->u.disaster, vehicle_disaster_chunk); break;
 | |
| 		default:           res = LoadChunk(ls, NULL,           vehicle_empty_chunk);    break;
 | |
| 	}
 | |
| 
 | |
| 	/* This chunk size should always be 10 bytes */
 | |
| 	if (ls->total_read - temp != 10) {
 | |
| 		DEBUG(oldloader, 4)("[OldLoader] Assert failed in Vehicle");
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	return res;
 | |
| }
 | |
| 
 | |
| static const OldChunks vehicle_chunk[] = {
 | |
| 	OCL_SVAR(  OC_UINT8, Vehicle, type ),
 | |
| 	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_SVAR(  OC_UINT8, Vehicle, num_orders ),
 | |
| 	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_UINT16, 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_SVAR(   OC_INT8, Vehicle, x_offs ),
 | |
| 	OCL_SVAR(   OC_INT8, Vehicle, y_offs ),
 | |
| 	OCL_SVAR(  OC_UINT8, Vehicle, sprite_width ),
 | |
| 	OCL_SVAR(  OC_UINT8, Vehicle, sprite_height ),
 | |
| 	OCL_SVAR(  OC_UINT8, Vehicle, z_height ),
 | |
| 
 | |
| 	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_SVAR( OC_UINT16, Vehicle, cargo_count ),
 | |
| 	OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, cargo_source ),
 | |
| 	OCL_SVAR(  OC_UINT8, Vehicle, cargo_days ),
 | |
| 
 | |
| 	OCL_SVAR( OC_UINT16, Vehicle, age ),
 | |
| 	OCL_SVAR( OC_UINT16, Vehicle, max_age ),
 | |
| 	OCL_SVAR(  OC_UINT8, 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_INT32, Vehicle, profit_this_year ),
 | |
| 	OCL_SVAR(  OC_INT32, 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()
 | |
| };
 | |
| static 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_multipler; i++) {
 | |
| 		Vehicle *v;
 | |
| 
 | |
| 		_current_vehicle_id = num * _old_vehicle_multipler + i;
 | |
| 
 | |
| 		if (!AddBlockIfNeeded(&_vehicle_pool, _current_vehicle_id))
 | |
| 			error("Vehicles: failed loading savegame: too many vehicles");
 | |
| 
 | |
| 		v = GetVehicle(_current_vehicle_id);
 | |
| 		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)("[OldLoader] -- Loading failed - vehicle-array is invalid");
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		if (_old_order_ptr != 0 && _old_order_ptr != 0xFFFFFFFF) {
 | |
| 			v->orders = GetOrder(REMAP_ORDER_IDX(_old_order_ptr));
 | |
| 		}
 | |
| 		AssignOrder(&v->current_order, UnpackOldOrder(_old_order));
 | |
| 		/* TTDPatch maps sprites from 0x2000 up. */
 | |
| 		if (v->cur_image >= 0x2000)
 | |
| 			v->cur_image -= 0x2000 - _custom_sprites_base;
 | |
| 
 | |
| 		/* 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 = GetVehicle(_old_next_ptr);
 | |
| 
 | |
| 		v->string_id = RemapOldStringID(_old_string_id);
 | |
| 
 | |
| 		/* Vehicle-subtype is different in TTD(Patch) */
 | |
| 		if (v->type == VEH_Special)
 | |
| 			v->subtype = v->subtype >> 1;
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| static const OldChunks sign_chunk[] = {
 | |
| 	OCL_SVAR( OC_UINT16, SignStruct, str ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32,SignStruct, x ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32,SignStruct, y ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I8, SignStruct, z ),
 | |
| 
 | |
| 	OCL_NULL( 6 ),         // Width of sign, no longer in use
 | |
| 
 | |
| 	OCL_END()
 | |
| };
 | |
| static bool LoadOldSign(LoadgameState *ls, int num)
 | |
| {
 | |
| 	if (!AddBlockIfNeeded(&_sign_pool, num))
 | |
| 		error("Signs: failed loading savegame: too many signs");
 | |
| 
 | |
| 	return LoadChunk(ls, GetSign(num), sign_chunk);
 | |
| }
 | |
| 
 | |
| static const OldChunks engine_chunk[] = {
 | |
| 	OCL_SVAR( OC_UINT16, Engine, player_avail ),
 | |
| 	OCL_SVAR( OC_UINT16, Engine, intro_date ),
 | |
| 	OCL_SVAR( OC_UINT16, 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_player ),
 | |
| 	OCL_SVAR(  OC_UINT8, Engine, preview_wait ),
 | |
| 	OCL_SVAR(  OC_UINT8, Engine, railtype ),
 | |
| 
 | |
| 	OCL_NULL( 1 ),         // Junk
 | |
| 
 | |
| 	OCL_END()
 | |
| };
 | |
| static bool LoadOldEngine(LoadgameState *ls, int num)
 | |
| {
 | |
| 	if (!LoadChunk(ls, &_engines[num], engine_chunk))
 | |
| 		return false;
 | |
| 
 | |
| 	/* Make sure wagons are marked as do-not-age */
 | |
| 	if ((num >= 27 && num < 54) || (num >= 57 && num < 84) || (num >= 89 && num < 116))
 | |
| 		_engines[num].age = 0xFFFF;
 | |
| 
 | |
| 	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 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_I32, GameDifficulty, max_no_competitors ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, competitor_start_time ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, number_towns ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, number_industries ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, max_loan ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, initial_interest ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, vehicle_costs ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, competitor_speed ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, competitor_intelligence ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, vehicle_breakdowns ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, subsidy_multiplier ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, construction_cost ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, terrain_type ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, quantity_sea_lakes ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, economy ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, line_reverse_mode ),
 | |
| 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, GameDifficulty, disasters ),
 | |
| 	OCL_END()
 | |
| };
 | |
| static bool LoadOldGameDifficulty(LoadgameState *ls, int num)
 | |
| {
 | |
| 	return LoadChunk(ls, &_opt.diff, game_difficulty_chunk);
 | |
| }
 | |
| 
 | |
| 
 | |
| static bool LoadOldMapPart1(LoadgameState *ls, int num)
 | |
| {
 | |
| 	uint i;
 | |
| 
 | |
| 	for (i = 0; i < OLD_MAP_SIZE; i++) {
 | |
| 		_map_owner[i] = ReadByte(ls);
 | |
| 	}
 | |
| 	for (i = 0; i < OLD_MAP_SIZE; i++) {
 | |
| 		_map2[i] = 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++) {
 | |
| 		_map_extra_bits[i] = ReadByte(ls);
 | |
| 	}
 | |
| 
 | |
| 	return !ls->failed;
 | |
| }
 | |
| static bool LoadOldMapPart2(LoadgameState *ls, int num)
 | |
| {
 | |
| 	uint i;
 | |
| 
 | |
| 	for (i = 0; i < OLD_MAP_SIZE; i++) {
 | |
| 		_map_type_and_height[i] = ReadByte(ls);
 | |
| 	}
 | |
| 	for (i = 0; i < OLD_MAP_SIZE; i++) {
 | |
| 		_map5[i] = ReadByte(ls);
 | |
| 	}
 | |
| 
 | |
| 	return !ls->failed;
 | |
| }
 | |
| 
 | |
| 
 | |
| static uint32 _old_cur_town_ctr;
 | |
| static const OldChunks main_chunk[] = {
 | |
| 	OCL_ASSERT( 0 ),
 | |
| 	OCL_VAR ( OC_UINT16,   1, &_date ),
 | |
| 	OCL_VAR ( OC_UINT16,   1, &_date_fract ),
 | |
| 	OCL_NULL( 600 ),            // TextEffects
 | |
| 	OCL_VAR ( OC_UINT32,   2, &_random_seeds[0] ),
 | |
| 
 | |
| 	OCL_ASSERT( 0x264 ),
 | |
| 	OCL_CHUNK(  70, LoadOldTown ),
 | |
| 	OCL_ASSERT( 0x1C18 ),
 | |
| 	OCL_CHUNK(5000, LoadOldOrder ),
 | |
| 	OCL_ASSERT( 0x4328 ),
 | |
| 
 | |
| 	OCL_VAR (   OC_TILE, 256, &_animated_tile_list[0] ),
 | |
| 	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, LoadOldPlayer ),
 | |
| 
 | |
| 	OCL_ASSERT( 0x547F2 ),
 | |
| 
 | |
| 	OCL_CHUNK( 850, LoadOldVehicle ),
 | |
| 
 | |
| 	OCL_ASSERT( 0x6F0F2 ),
 | |
| 
 | |
| 	OCL_VAR (  OC_UINT8, 32 * 500, &_name_array[0] ),
 | |
| 
 | |
| 	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_UINT32,    1, &_economy.max_loan ),
 | |
| 	OCL_VAR ( OC_UINT32,    1, &_economy.max_loan_unround ),
 | |
| 	OCL_VAR ( OC_FILE_U16 | OC_VAR_U32,    1, &_economy.fluct ),
 | |
| 
 | |
| 	OCL_VAR ( OC_UINT16,    1, &_disaster_delay ),
 | |
| 
 | |
| 	OCL_NULL( 144 ),             // cargo-stuff, calculated in InitializeLandscapeVariables
 | |
| 
 | |
| 	OCL_VAR ( OC_UINT16,  256, &_engine_name_strings[0] ),
 | |
| 
 | |
| 	OCL_NULL( 144 ),             // AI cargo-stuff, calculated in InitializeLandscapeVariables
 | |
| 	OCL_NULL( 2 ),               // Company indexes of players, no longer in use
 | |
| 
 | |
| 	OCL_VAR ( OC_FILE_U8 | OC_VAR_U16,    1, &_station_tick_ctr ),
 | |
| 
 | |
| 	OCL_VAR (  OC_UINT8,    1, &_opt.currency ),
 | |
| 	OCL_VAR (  OC_UINT8,    1, &_opt.kilometers ),
 | |
| 	OCL_VAR ( OC_FILE_U8 | OC_VAR_U32,    1, &_cur_player_tick_index ),
 | |
| 
 | |
| 	OCL_NULL( 2 ),               // Date stuff, calculated automatically
 | |
| 	OCL_NULL( 8 ),               // Player 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_VAR (  OC_UINT8,    1, &_avail_aircraft ),
 | |
| 	OCL_VAR (  OC_UINT8,    1, &_opt.road_side ),
 | |
| 	OCL_VAR (  OC_UINT8,    1, &_opt.town_name ),
 | |
| 
 | |
| 	OCL_CHUNK( 1, LoadOldGameDifficulty ),
 | |
| 
 | |
| 	OCL_ASSERT( 0x77130 ),
 | |
| 
 | |
| 	OCL_VAR (  OC_UINT8,    1, &_opt.diff_level ),
 | |
| 	OCL_VAR (  OC_UINT8,    1, &_opt.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, &_opt.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_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, 4)("[OldLoader] Going to read main chunk..");
 | |
| 	/* Load the biggest chunk */
 | |
| 	if (!LoadChunk(&_ls, NULL, main_chunk)) {
 | |
| 		DEBUG(oldloader, 0)("[OldLoader] Loading failed!");
 | |
| 		return false;
 | |
| 	}
 | |
| 	DEBUG(oldloader, 4)("[OldLoader] Done. Converting stuff..");
 | |
| 
 | |
| 	/* Fix some general stuff */
 | |
| 	_opt.landscape = _opt.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++) {
 | |
| 		_map3_lo[i] = _old_map3[i * 2];
 | |
| 		_map3_hi[i] = _old_map3[i * 2 + 1];
 | |
| 	}
 | |
| 
 | |
| 	for (i = 0; i < OLD_MAP_SIZE; i ++) {
 | |
| 		/* We save presignals different from TTDPatch, convert them */
 | |
| 		if (IsTileType(i, MP_RAILWAY) && (_map5[i] & 0xC0) == 0x40) {
 | |
| 			/* This byte is always zero in TTD for this type of tile */
 | |
| 			if (_map3_hi[i]) {
 | |
| 				/* Convert the presignals to our own format */
 | |
| 				_map3_hi[i] = (_map3_hi[i] >> 1) & 7;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Fix the game to be compatible with OpenTTD */
 | |
| 	FixOldTowns();
 | |
| 	FixOldStations();
 | |
| 	FixOldVehicles();
 | |
| 
 | |
| 	AddTypeToEngines();
 | |
| 
 | |
| 	/* We have a new difficulty setting */
 | |
| 	_opt.diff.town_council_tolerance = clamp(_opt.diff_level, 0, 2);
 | |
| 
 | |
| 	DEBUG(oldloader, 4)("[OldLoader] Done!");
 | |
| 	DEBUG(oldloader, 1)("[OldLoader] TTD(Patch) savegame successfully converted");
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| bool LoadOldSaveGame(const char *file)
 | |
| {
 | |
| 	DEBUG(oldloader, 4)("[OldLoader] Trying to load an TTD(Patch) savegame");
 | |
| 
 | |
| 	InitLoading(&_ls);
 | |
| 
 | |
| 	/* Open file */
 | |
| 	_ls.file = fopen(file, "rb");
 | |
| 
 | |
| 	if (_ls.file == NULL) {
 | |
| 		DEBUG(oldloader, 0)("[OldLoader] Could not open file %s", file);
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	/* Load the main chunk */
 | |
| 	if (!LoadOldMain(&_ls))
 | |
| 		return false;
 | |
| 
 | |
| 	fclose(_ls.file);
 | |
| 
 | |
| 	_pause = 2;
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| void GetOldSaveGameName(char *title, const char *file)
 | |
| {
 | |
| 	FILE *f;
 | |
| 
 | |
| 	f = fopen(file, "rb");
 | |
| 	title[0] = 0;
 | |
| 	title[48] = 0;
 | |
| 
 | |
| 	if (f == NULL)
 | |
| 		return;
 | |
| 
 | |
| 	if (fread(title, 1, 48, f) != 48)
 | |
| 		title[0] = '\0';
 | |
| 
 | |
| 	fclose(f);
 | |
| }
 | |
| 
 | |
| void GetOldScenarioGameName(char *title, const char *file)
 | |
| {
 | |
| 	GetOldSaveGameName(title, file);
 | |
| }
 | 
