Changeset - r2848:ae67043fa1f1
[Not reviewed]
master
0 12 0
peter1138 - 18 years ago 2006-01-12 15:52:18
peter1138@openttd.org
(svn r3396) - Autoreplace changes:
- Change fixed array per player to a single pool. This avoids future problems
with vehicle numbers and decreases savegame size. Engine replacements from
previous savegames will be lost.
- Move engine replacement code from players.c to engine.c.
(thanks to blathijs for rewriting this)
12 files changed with 360 insertions and 116 deletions:
0 comments (0 inline, 0 general)
aircraft_cmd.c
Show inline comments
 
@@ -1447,13 +1447,13 @@ static void AircraftEventHandler_HeliTak
 
	v->u.air.state = FLYING;
 
	// get the next position to go to, differs per airport
 
	AircraftNextAirportPos_and_Order(v);
 

	
 
	// check if the aircraft needs to be replaced or renewed and send it to a hangar if needed
 
	if (v->owner == _local_player && (
 
				EngineHasReplacement(p, v->engine_type) ||
 
				EngineHasReplacementForPlayer(p, v->engine_type) ||
 
				(p->engine_renew && v->age - v->max_age > p->engine_renew_months * 30)
 
			)) {
 
		_current_player = _local_player;
 
		DoCommandP(v->tile, v->index, 1, NULL, CMD_SEND_AIRCRAFT_TO_HANGAR | CMD_SHOW_NO_ERROR);
 
		_current_player = OWNER_NONE;
 
	}
 
@@ -1511,13 +1511,13 @@ static void AircraftEventHandler_Landing
 
	const Player* p = GetPlayer(v->owner);
 
	AircraftLandAirplane(v);  // maybe crash airplane
 
	v->u.air.state = ENDLANDING;
 
	// check if the aircraft needs to be replaced or renewed and send it to a hangar if needed
 
	if (v->current_order.type != OT_GOTO_DEPOT && v->owner == _local_player) {
 
		// only the vehicle owner needs to calculate the rest (locally)
 
		if (EngineHasReplacement(p, v->engine_type) ||
 
		if (EngineHasReplacementForPlayer(p, v->engine_type) ||
 
			(p->engine_renew && v->age - v->max_age > (p->engine_renew_months * 30))) {
 
			// send the aircraft to the hangar at next airport (bit 17 set)
 
			_current_player = _local_player;
 
			DoCommandP(v->tile, v->index, 1 << 16, NULL, CMD_SEND_AIRCRAFT_TO_HANGAR | CMD_SHOW_NO_ERROR);
 
			_current_player = OWNER_NONE;
 
		}
engine.c
Show inline comments
 
@@ -1048,12 +1048,201 @@ int32 CmdRenameEngine(int x, int y, uint
 
	}
 

	
 
	return 0;
 
}
 

	
 

	
 
/*
 
 * returns true if an engine is valid, of the specified type, and buildable by
 
 * the current player, false otherwise
 
 *
 
 * engine = index of the engine to check
 
 * type   = the type the engine should be of (VEH_xxx)
 
 */
 
bool IsEngineBuildable(uint engine, byte type)
 
{
 
	const Engine *e;
 

	
 
	// check if it's an engine that is in the engine array
 
	if (!IsEngineIndex(engine)) return false;
 

	
 
	e = GetEngine(engine);
 

	
 
	// check if it's an engine of specified type
 
	if (e->type != type) return false;
 

	
 
	// check if it's available
 
	if (!HASBIT(e->player_avail, _current_player)) return false;
 

	
 
	return true;
 
}
 

	
 
/************************************************************************
 
 * Engine Replacement stuff
 
 ************************************************************************/
 

	
 
static void EngineRenewPoolNewBlock(uint start_item); /* Forward declare for initializer of _engine_renew_pool */
 
enum {
 
	ENGINE_RENEW_POOL_BLOCK_SIZE_BITS = 3,
 
	ENGINE_RENEW_POOL_MAX_BLOCKS      = 8000,
 
};
 

	
 
MemoryPool _engine_renew_pool = { "EngineRe", ENGINE_RENEW_POOL_MAX_BLOCKS, ENGINE_RENEW_POOL_BLOCK_SIZE_BITS, sizeof(EngineRenew), &EngineRenewPoolNewBlock, 0, 0, NULL };
 

	
 
static inline uint16 GetEngineRenewPoolSize(void)
 
{
 
	return _engine_renew_pool.total_items;
 
}
 

	
 
#define FOR_ALL_ENGINE_RENEWS_FROM(er, start) for (er = GetEngineRenew(start); er != NULL; er = (er->index + 1 < GetEngineRenewPoolSize()) ? GetEngineRenew(er->index + 1) : NULL)
 
#define FOR_ALL_ENGINE_RENEWS(er) FOR_ALL_ENGINE_RENEWS_FROM(er, 0)
 

	
 
static void EngineRenewPoolNewBlock(uint start_item)
 
{
 
	EngineRenew *er;
 

	
 
	FOR_ALL_ENGINE_RENEWS_FROM(er, start_item) {
 
		er->index = start_item++;
 
		er->from = INVALID_ENGINE;
 
	}
 
}
 

	
 

	
 
static EngineRenew *AllocateEngineRenew(void)
 
{
 
	EngineRenew *er;
 

	
 
	FOR_ALL_ENGINE_RENEWS(er) {
 
		if (er->from == INVALID_ENGINE) {
 
			er->to = INVALID_ENGINE;
 
			er->next = NULL;
 
			return er;
 
		}
 
	}
 

	
 
	/* Check if we can add a block to the pool */
 
	if (AddBlockToPool(&_engine_renew_pool)) return AllocateEngineRenew();
 

	
 
	return NULL;
 
}
 

	
 
/**
 
 * Retrieves the EngineRenew that specifies the replacement of the given
 
 * engine type from the given renewlist */
 
static EngineRenew *GetEngineReplacement(EngineRenewList erl, EngineID engine)
 
{
 
	EngineRenew* er = (EngineRenew*)erl; /* Fetch first element */
 
	while (er) {
 
		if (er->from == engine) return er;
 
		er = er->next;
 
	}
 
	return NULL;
 
}
 

	
 
void RemoveAllEngineReplacement(EngineRenewList* erl)
 
{
 
	EngineRenew* er = (EngineRenew*)(*erl); /* Fetch first element */
 
	while (er) {
 
		er->from = INVALID_ENGINE; /* "Deallocate" all elements */
 
		er = er->next;
 
	}
 
	*erl = NULL; /* Empty list */
 
}
 

	
 
EngineID EngineReplacement(EngineRenewList erl, EngineID engine)
 
{
 
	const EngineRenew *er = GetEngineReplacement(erl, engine);
 
	return er == NULL ? INVALID_ENGINE : er->to;
 
}
 

	
 
int32 AddEngineReplacement(EngineRenewList* erl, EngineID old_engine, EngineID new_engine, uint32 flags)
 
{
 
	EngineRenew *er;
 

	
 
	// Check if the old vehicle is already in the list
 
	er = GetEngineReplacement(*erl, old_engine);
 
	if (er != NULL) {
 
		if (flags & DC_EXEC) er->to = new_engine;
 
		return 0;
 
	}
 

	
 
	er = AllocateEngineRenew();
 
	if (er == NULL) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		er->from = old_engine;
 
		er->to = new_engine;
 
		er->next = (EngineRenew*)(*erl); /* Resolve the first element in the list */
 

	
 
		*erl = (EngineRenewList)er; /* Insert before the first element */
 
	}
 

	
 
	return 0;
 
}
 

	
 
int32 RemoveEngineReplacement(EngineRenewList* erl, EngineID engine, uint32 flags)
 
{
 
	EngineRenew* er = (EngineRenew*)(*erl); /* Start at the first element */
 
	EngineRenew* prev = NULL;
 

	
 
	while (er)
 
	{
 
		if (er->from == engine) {
 
			if (flags & DC_EXEC) {
 
				if (prev == NULL) { /* First element */
 
					(*erl) = (EngineRenewList)er->next; /* The second becomes the new first element */
 
				} else {
 
					prev->next = er->next; /* Cut this element out */
 
				}
 
				er->from = INVALID_ENGINE; /* Deallocate */
 
			}
 
			return 0;
 
		}
 
		prev = er;
 
		er = er->next; /* Look at next element */
 
	}
 

	
 
	return CMD_ERROR; /* Not found? */
 
}
 

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

	
 
static void Save_ERNW(void)
 
{
 
	EngineRenew *er;
 

	
 
	FOR_ALL_ENGINE_RENEWS(er) {
 
		if (er->from != INVALID_ENGINE) {
 
			SlSetArrayIndex(er->index);
 
			SlObject(er, _engine_renew_desc);
 
		}
 
	}
 
}
 

	
 
static void Load_ERNW(void)
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		EngineRenew *er;
 

	
 
		if (!AddBlockIfNeeded(&_engine_renew_pool, index))
 
			error("EngineRenews: failed loading savegame: too many EngineRenews");
 

	
 
		er = GetEngineRenew(index);
 
		SlObject(er, _engine_renew_desc);
 
	}
 
}
 

	
 
static const SaveLoad _engine_desc[] = {
 
	SLE_VAR(Engine,intro_date,						SLE_UINT16),
 
	SLE_VAR(Engine,age,										SLE_UINT16),
 
	SLE_VAR(Engine,reliability,						SLE_UINT16),
 
	SLE_VAR(Engine,reliability_spd_dec,		SLE_UINT16),
 
	SLE_VAR(Engine,reliability_start,			SLE_UINT16),
 
@@ -1097,35 +1286,17 @@ static void Load_ENGN(void)
 
static void LoadSave_ENGS(void)
 
{
 
	SlArray(_engine_name_strings, lengthof(_engine_name_strings), SLE_STRINGID);
 
}
 

	
 
const ChunkHandler _engine_chunk_handlers[] = {
 
	{ 'ENGN', Save_ENGN, Load_ENGN, CH_ARRAY},
 
	{ 'ENGS', LoadSave_ENGS, LoadSave_ENGS, CH_RIFF | CH_LAST},
 
	{ 'ENGN', Save_ENGN,     Load_ENGN,     CH_ARRAY          },
 
	{ 'ENGS', LoadSave_ENGS, LoadSave_ENGS, CH_RIFF           },
 
	{ 'ERNW', Save_ERNW,     Load_ERNW,     CH_ARRAY | CH_LAST},
 
};
 

	
 

	
 
/*
 
 * returns true if an engine is valid, of the specified type, and buildable by
 
 * the current player, false otherwise
 
 *
 
 * engine = index of the engine to check
 
 * type   = the type the engine should be of (VEH_xxx)
 
 */
 
bool IsEngineBuildable(uint engine, byte type)
 
void InitializeEngines(void)
 
{
 
	const Engine *e;
 

	
 
	// check if it's an engine that is in the engine array
 
	if (!IsEngineIndex(engine)) return false;
 

	
 
	e = GetEngine(engine);
 

	
 
	// check if it's an engine of specified type
 
	if (e->type != type) return false;
 

	
 
	// check if it's available
 
	if (!HASBIT(e->player_avail, _current_player)) return false;
 

	
 
	return true;
 
	/* Clean the engine renew pool and create 1 block in it */
 
	CleanPool(&_engine_renew_pool);
 
	AddBlockToPool(&_engine_renew_pool);
 
}
engine.h
Show inline comments
 
@@ -4,12 +4,13 @@
 
#define ENGINE_H
 

	
 
/** @file engine.h
 
  */
 

	
 
#include "sprite.h"
 
#include "pool.h"
 

	
 
typedef struct RailVehicleInfo {
 
	byte image_index;
 
	byte flags; /* 1=multihead engine, 2=wagon */
 
	byte base_cost;
 
	uint16 max_speed;
 
@@ -99,12 +100,16 @@ enum {
 
};
 

	
 
enum {
 
	NUM_VEHICLE_TYPES = 6
 
};
 

	
 
enum {
 
	INVALID_ENGINE = 0xFFFF,
 
};
 

	
 
void AddTypeToEngines(void);
 
void StartupEngines(void);
 

	
 
enum GlobalCargo {
 
	GC_PASSENGERS   =   0,
 
	GC_COAL         =   1,
 
@@ -280,7 +285,83 @@ static inline const RoadVehicleInfo* Roa
 
}
 

	
 
void UnloadWagonOverrides(void);
 
void UnloadCustomEngineSprites(void);
 
void UnloadCustomEngineNames(void);
 

	
 
/************************************************************************
 
 * Engine Replacement stuff
 
 ************************************************************************/
 

	
 
/**
 
 * Struct to store engine replacements. DO NOT USE outside of engine.c. Is
 
 * placed here so the only exception to this rule, the saveload code, can use
 
 * it.
 
 */
 
struct EngineRenew {
 
	uint16 index;
 
	EngineID from;
 
	EngineID to;
 
	struct EngineRenew *next;
 
};
 

	
 
typedef struct EngineRenew EngineRenew;
 

	
 
/**
 
 * Memory pool for engine renew elements. DO NOT USE outside of engine.c. Is
 
 * placed here so the only exception to this rule, the saveload code, can use
 
 * it.
 
 */
 
extern MemoryPool _engine_renew_pool;
 

	
 
/**
 
 * DO NOT USE outside of engine.c. Is
 
 * placed here so the only exception to this rule, the saveload code, can use
 
 * it.
 
 */
 
static inline EngineRenew *GetEngineRenew(uint16 index)
 
{
 
	return (EngineRenew*)GetItemFromPool(&_engine_renew_pool, index);
 
}
 

	
 

	
 
/**
 
 * A list to group EngineRenew directives together (such as per-player).
 
 */
 
typedef EngineRenew* EngineRenewList;
 

	
 
/**
 
 * Remove all engine replacement settings for the player.
 
 * @param  er The renewlist for a given player.
 
 * @return The new renewlist for the player.
 
 */
 
void RemoveAllEngineReplacement(EngineRenewList* erl);
 

	
 
/**
 
 * Retrieve the engine replacement in a given renewlist for an original engine type.
 
 * @param  erl The renewlist to search in.
 
 * @param  engine Engine type to be replaced.
 
 * @return The engine type to replace with, or INVALID_ENGINE if no
 
 * replacement is in the list.
 
 */
 
EngineID EngineReplacement(EngineRenewList erl, EngineID engine);
 

	
 
/**
 
 * Add an engine replacement to the given renewlist.
 
 * @param erl The renewlist to add to.
 
 * @param old_engine The original engine type.
 
 * @param new_engine The replacement engine type.
 
 * @param flags The calling command flags.
 
 * @return 0 on success, CMD_ERROR on failure.
 
 */
 
int32 AddEngineReplacement(EngineRenewList* erl, EngineID old_engine, EngineID new_engine, uint32 flags);
 

	
 
/**
 
 * Remove an engine replacement from a given renewlist.
 
 * @param erl The renewlist from which to remove the replacement
 
 * @param engine The original engine type.
 
 * @param flags The calling command flags.
 
 * @return 0 on success, CMD_ERROR on failure.
 
 */
 
int32 RemoveEngineReplacement(EngineRenewList* erl, EngineID engine, uint32 flags);
 

	
 
#endif /* ENGINE_H */
misc.c
Show inline comments
 
@@ -86,12 +86,13 @@ void SetDate(uint date)
 
#endif /* ENABLE_NETWORK */
 
}
 

	
 
void InitializeVehicles(void);
 
void InitializeWaypoints(void);
 
void InitializeDepot(void);
 
void InitializeEngines(void);
 
void InitializeOrders(void);
 
void InitializeClearLand(void);
 
void InitializeRail(void);
 
void InitializeRailGui(void);
 
void InitializeRoad(void);
 
void InitializeRoadGui(void);
 
@@ -139,12 +140,13 @@ void InitializeGame(int mode, uint size_
 
	if ((mode & IG_DATE_RESET) == IG_DATE_RESET) {
 
		uint starting = ConvertIntDate(_patches.starting_date);
 
		if ( starting == (uint)-1) starting = 10958;
 
		SetDate(starting);
 
	}
 

	
 
	InitializeEngines();
 
	InitializeVehicles();
 
	InitializeWaypoints();
 
	InitializeDepot();
 
	InitializeOrders();
 

	
 
	InitNewsItemStructs();
openttd.c
Show inline comments
 
@@ -1254,13 +1254,13 @@ bool AfterLoadGame(void)
 
	}
 

	
 
	/* 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_PLAYERS(p) {
 
			InitialiseEngineReplacement(p);
 
			p->engine_renew_list = NULL;
 
			p->engine_renew = false;
 
			p->engine_renew_months = -6;
 
			p->engine_renew_money = 100000;
 
		}
 
		if (_local_player < MAX_PLAYERS) {
 
			// Set the human controlled player to the patch settings
player.h
Show inline comments
 
/* $Id$ */
 

	
 
#ifndef PLAYER_H
 
#define PLAYER_H
 

	
 
#include "pool.h"
 
#include "aystar.h"
 
#include "rail.h"
 
#include "engine.h"
 

	
 
typedef struct PlayerEconomyEntry {
 
	int32 income;
 
@@ -185,13 +186,13 @@ typedef struct Player {
 
	PlayerAI ai;
 
	PlayerAiNew ainew;
 

	
 
	int64 yearly_expenses[3][13];
 
	PlayerEconomyEntry cur_economy;
 
	PlayerEconomyEntry old_economy[24];
 
	EngineID engine_replacement[TOTAL_NUM_ENGINES];
 
	EngineRenewList engine_renew_list; // Defined later
 
	bool engine_renew;
 
	bool renew_keep_length;
 
	int16 engine_renew_months;
 
	uint32 engine_renew_money;
 
} Player;
 

	
 
@@ -260,11 +261,51 @@ typedef struct HighScore {
 
VARDEF HighScore _highscore_table[5][5]; // 4 difficulty-settings (+ network); top 5
 
void SaveToHighScore(void);
 
void LoadFromHighScore(void);
 
int8 SaveHighScoreValue(const Player *p);
 
int8 SaveHighScoreValueNetwork(void);
 

	
 
void InitialiseEngineReplacement(Player *p);
 
EngineID EngineReplacement(const Player *p, EngineID engine);
 
bool EngineHasReplacement(const Player *p, EngineID engine);
 
/* Engine Replacement Functions */
 

	
 
/**
 
 * Remove all engine replacement settings for the given player.
 
 * @param p Player.
 
 */
 
static inline void RemoveAllEngineReplacementForPlayer(Player *p) { RemoveAllEngineReplacement(&p->engine_renew_list); }
 

	
 
/**
 
 * Retrieve the engine replacement for the given player and original engine type.
 
 * @param p Player.
 
 * @param engine Engine type.
 
 * @return The engine type to replace with, or INVALID_ENGINE if no
 
 * replacement is in the list.
 
 */
 
static inline EngineID EngineReplacementForPlayer(const Player *p, EngineID engine) { return EngineReplacement(p->engine_renew_list, engine); }
 

	
 
/**
 
 * Check if a player has a replacement set up for the given engine.
 
 * @param p Player.
 
 * @param  engine Engine type to be replaced.
 
 * @return true if a replacement was set up, false otherwise.
 
 */
 
static inline bool EngineHasReplacementForPlayer(const Player *p, EngineID engine) { return EngineReplacementForPlayer(p, engine) != INVALID_ENGINE; }
 

	
 
/**
 
 * Add an engine replacement for the player.
 
 * @param p Player.
 
 * @param old_engine The original engine type.
 
 * @param new_engine The replacement engine type.
 
 * @param flags The calling command flags.
 
 * @return 0 on success, CMD_ERROR on failure.
 
 */
 
static inline int32 AddEngineReplacementForPlayer(Player *p, EngineID old_engine, EngineID new_engine, uint32 flags) { return AddEngineReplacement(&p->engine_renew_list, old_engine, new_engine, flags); }
 

	
 
/**
 
 * Remove an engine replacement for the player.
 
 * @param p Player.
 
 * @param engine The original engine type.
 
 * @param flags The calling command flags.
 
 * @return 0 on success, CMD_ERROR on failure.
 
 */
 
static inline int32 RemoveEngineReplacementForPlayer(Player *p, EngineID engine, uint32 flags) {return RemoveEngineReplacement(&p->engine_renew_list, engine, flags); }
 

	
 
#endif /* PLAYER_H */
players.c
Show inline comments
 
@@ -20,12 +20,13 @@
 
#include "news.h"
 
#include "saveload.h"
 
#include "command.h"
 
#include "sound.h"
 
#include "network.h"
 
#include "variables.h"
 
#include "engine.h"
 
#include "ai/ai.h"
 

	
 
static const SpriteID cheeks_table[4] = {
 
	0x325, 0x326,
 
	0x390, 0x3B0,
 
};
 
@@ -484,13 +485,13 @@ Player *DoStartupNewPlayer(bool is_ai)
 

	
 
	p->avail_railtypes = GetPlayerRailtypes(p->index);
 
	p->inaugurated_year = _cur_year;
 
	p->face = Random();
 

	
 
	/* Engine renewal settings */
 
	InitialiseEngineReplacement(p);
 
	p->engine_renew_list = NULL;
 
	p->renew_keep_length = false;
 
	p->engine_renew = false;
 
	p->engine_renew_months = -6;
 
	p->engine_renew_money = 100000;
 

	
 
	GeneratePresidentName(p);
 
@@ -634,16 +635,12 @@ static void DeletePlayerStuff(PlayerID p
 
	DeleteName(p->name_1);
 
	DeleteName(p->president_name_1);
 
	p->name_1 = 0;
 
	p->president_name_1 = 0;
 
}
 

	
 

	
 
static int32 AddEngineReplacement(Player* p, EngineID old_engine, EngineID new_engine, uint32 flags);
 
static int32 RemoveEngineReplacement(Player* p, EngineID engine, uint32 flags);
 

	
 
/** Change engine renewal parameters
 
 * @param x,y unused
 
 * @param p1 bits 0-3 command
 
 * - p1 = 0 - change auto renew bool
 
 * - p1 = 1 - change auto renew months
 
 * - p1 = 2 - change auto renew money
 
@@ -731,15 +728,15 @@ int32 CmdReplaceVehicle(int x, int y, ui
 
					return CMD_ERROR;
 

	
 
				// make sure that the player can actually buy the new engine
 
				if (!HASBIT(GetEngine(new_engine_type)->player_avail, _current_player))
 
					return CMD_ERROR;
 

	
 
				cost = AddEngineReplacement(p, old_engine_type, new_engine_type, flags);
 
				cost = AddEngineReplacementForPlayer(p, old_engine_type, new_engine_type, flags);
 
			} else {
 
				cost = RemoveEngineReplacement(p, old_engine_type, flags);
 
				cost = RemoveEngineReplacementForPlayer(p, old_engine_type, flags);
 
			}
 

	
 
			if (IsLocalPlayer()) InvalidateWindow(WC_REPLACE_VEHICLE, GetEngine(old_engine_type)->type);
 

	
 
			return cost;
 
		}
 
@@ -900,12 +897,14 @@ int32 CmdPlayerCtrl(int x, int y, uint32
 

	
 
			/* Remove the company */
 
			ChangeOwnershipOfPlayerItems(p->index, OWNER_SPECTATOR);
 
			p->money64 = p->player_money = 100000000; // XXX - wtf?
 
			p->is_active = false;
 
		}
 
		RemoveAllEngineReplacementForPlayer(p);
 

	
 
	} break;
 

	
 
	case 3: { /* Merge a company (#1) into another company (#2), elimination company #1 */
 
		PlayerID pid_old = GB(p2,  0, 16);
 
		PlayerID pid_new = GB(p2, 16, 16);
 

	
 
@@ -1104,69 +1103,12 @@ void LoadFromHighScore(void)
 
	}
 

	
 
	/* Initialize end of game variable (when to show highscore chart) */
 
	 _patches.ending_date = 2051;
 
}
 

	
 
void InitialiseEngineReplacement(Player *p)
 
{
 
	EngineID engine;
 

	
 
	for (engine = 0; engine < TOTAL_NUM_ENGINES; engine++)
 
		p->engine_replacement[engine] = INVALID_ENGINE;
 
}
 

	
 
/**
 
 * Retrieve the engine replacement for the given player and original engine type.
 
 * @param p Player.
 
 * @param engine Engine type.
 
 * @return Assigned replacement engine.
 
 */
 
EngineID EngineReplacement(const Player *p, EngineID engine)
 
{
 
	return p->engine_replacement[engine];
 
}
 

	
 
/**
 
 * Check if an engine has a replacement set up.
 
 * @param p Player.
 
 * @param engine Engine type.
 
 * @return True if there is a replacement for the original engine type.
 
 */
 
bool EngineHasReplacement(const Player *p, EngineID engine)
 
{
 
	return EngineReplacement(p, engine) != INVALID_ENGINE;
 
}
 

	
 
/**
 
 * Add an engine replacement for the player.
 
 * @param p Player.
 
 * @param old_engine The original engine type.
 
 * @param new_engine The replacement engine type.
 
 * @param flags The calling command flags.
 
 * @return 0 on success, CMD_ERROR on failure.
 
 */
 
static int32 AddEngineReplacement(Player* p, EngineID old_engine, EngineID new_engine, uint32 flags)
 
{
 
	if (flags & DC_EXEC) p->engine_replacement[old_engine] = new_engine;
 
	return 0;
 
}
 

	
 
/**
 
 * Remove an engine replacement for the player.
 
 * @param p Player.
 
 * @param engine The original engine type.
 
 * @param flags The calling command flags.
 
 * @return 0 on success, CMD_ERROR on failure.
 
 */
 
static int32 RemoveEngineReplacement(Player* p, EngineID engine, uint32 flags)
 
{
 
	if (flags & DC_EXEC) p->engine_replacement[engine] = INVALID_ENGINE;
 
	return 0;
 
}
 

	
 
// Save/load of players
 
static const SaveLoad _player_desc[] = {
 
	SLE_VAR(Player,name_2,					SLE_UINT32),
 
	SLE_VAR(Player,name_1,					SLE_STRINGID),
 

	
 
	SLE_VAR(Player,president_name_1,SLE_UINT16),
 
@@ -1206,13 +1148,14 @@ static const SaveLoad _player_desc[] = {
 
	SLE_CONDARR(Player,yearly_expenses,	SLE_INT64, 3*13, 2, 255),
 

	
 
	SLE_CONDVAR(Player,is_ai,			SLE_UINT8, 2, 255),
 
	SLE_CONDVAR(Player,is_active,	SLE_UINT8, 4, 255),
 

	
 
	// Engine renewal settings
 
	SLE_CONDARR(Player,engine_replacement,  SLE_UINT16, 256, 16, 255),
 
	SLE_CONDARR(NullStruct,null,SLE_FILE_U16 | SLE_VAR_NULL, 256, 16, 18),
 
	SLE_CONDREF(Player,engine_renew_list, REF_ENGINE_RENEWS, 19, 255),
 
	SLE_CONDVAR(Player,engine_renew,         SLE_UINT8,      16, 255),
 
	SLE_CONDVAR(Player,engine_renew_months,  SLE_INT16,      16, 255),
 
	SLE_CONDVAR(Player,engine_renew_money,  SLE_UINT32,      16, 255),
 
	SLE_CONDVAR(Player,renew_keep_length,    SLE_UINT8,       2, 255),	// added with 16.1, but was blank since 2
 

	
 
	// reserve extra space in savegame here. (currently 63 bytes)
saveload.c
Show inline comments
 
@@ -26,13 +26,13 @@
 
#include "player.h"
 
#include "saveload.h"
 
#include "variables.h"
 
#include <setjmp.h>
 

	
 
enum {
 
	SAVEGAME_VERSION = 18,
 
	SAVEGAME_VERSION = 19,
 

	
 
};
 

	
 
uint16 _sl_version;       /// the major savegame version identifier
 
byte   _sl_minor_version; /// the minor savegame version, DO NOT USE!
 

	
 
@@ -1048,21 +1048,21 @@ static void UninitWriteZlib(void)
 
//************* END OF CODE *****************
 
//*******************************************
 

	
 
// these define the chunks
 
extern const ChunkHandler _misc_chunk_handlers[];
 
extern const ChunkHandler _player_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 _engine_chunk_handlers[];
 
extern const ChunkHandler _economy_chunk_handlers[];
 
extern const ChunkHandler _animated_tile_chunk_handlers[];
 

	
 
static const ChunkHandler * const _chunk_handlers[] = {
 
	_misc_chunk_handlers,
 
	_veh_chunk_handlers,
 
@@ -1104,12 +1104,13 @@ static uint ReferenceToInt(const void *o
 
		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;
 
		default: NOT_REACHED();
 
	}
 

	
 
	return 0; // avoid compiler warning
 
}
 

	
 
@@ -1159,12 +1160,17 @@ static void *IntToReference(uint index, 
 
		}
 
		case REF_ROADSTOPS: {
 
			if (!AddBlockIfNeeded(&_roadstop_pool, index))
 
				error("RoadStops: failed loading savegame: too many RoadStops");
 
			return GetRoadStop(index);
 
		}
 
		case REF_ENGINE_RENEWS: {
 
			if (!AddBlockIfNeeded(&_engine_renew_pool, index))
 
				error("EngineRenews: failed loading savegame: too many EngineRenews");
 
			return GetEngineRenew(index);
 
		}
 

	
 
		case REF_VEHICLE_OLD: {
 
			/* Old vehicles were saved differently:
 
			 * invalid vehicle was 0xFFFF,
 
			 * and the index was not - 1.. correct for this */
 
			index++;
saveload.h
Show inline comments
 
@@ -44,13 +44,14 @@ typedef struct {
 
typedef enum SLRefType {
 
	REF_ORDER       = 0,
 
	REF_VEHICLE     = 1,
 
	REF_STATION     = 2,
 
	REF_TOWN        = 3,
 
	REF_VEHICLE_OLD = 4,
 
	REF_ROADSTOPS   = 5
 
	REF_ROADSTOPS   = 5,
 
	REF_ENGINE_RENEWS = 6,
 
} SLRefType;
 

	
 

	
 
extern uint16 _sl_version;       /// the major savegame version identifier
 
extern byte   _sl_minor_version; /// the minor savegame version, DO NOT USE!
 

	
vehicle.c
Show inline comments
 
@@ -1615,13 +1615,13 @@ static int32 ReplaceVehicle(Vehicle **w,
 
	EngineID new_engine_type;
 
	const UnitID cached_unitnumber = old_v->unitnumber;
 
	bool new_front = false;
 
	Vehicle *new_v = NULL;
 
	char vehicle_name[32];
 

	
 
	new_engine_type = EngineReplacement(p, old_v->engine_type);
 
	new_engine_type = EngineReplacementForPlayer(p, old_v->engine_type);
 
	if (new_engine_type == INVALID_ENGINE) new_engine_type = old_v->engine_type;
 

	
 
	cost = DoCommand(old_v->x_pos, old_v->y_pos, new_engine_type, 1, flags, CMD_BUILD_VEH(old_v->type));
 
	if (CmdFailed(cost)) return cost;
 

	
 
	if (flags & DC_EXEC) {
 
@@ -1736,13 +1736,13 @@ static void MaybeReplaceVehicle(Vehicle 
 
			}
 

	
 
			// check if the vehicle should be replaced
 
			if (!p->engine_renew ||
 
					w->age - w->max_age < (p->engine_renew_months * 30) || // replace if engine is too old
 
					w->max_age == 0) { // rail cars got a max age of 0
 
				if (!EngineHasReplacement(p, w->engine_type)) // updates to a new model
 
				if (!EngineHasReplacementForPlayer(p, w->engine_type)) // updates to a new model
 
					continue;
 
			}
 

	
 
			/* Now replace the vehicle */
 
			temp_cost = ReplaceVehicle(&w, flags);
 

	
vehicle.h
Show inline comments
 
@@ -424,13 +424,12 @@ VARDEF VehicleID _new_ship_id;
 
VARDEF VehicleID _new_roadveh_id;
 
VARDEF VehicleID _new_vehicle_id;
 
VARDEF uint16 _aircraft_refit_capacity;
 
VARDEF byte _cmd_build_rail_veh_score;
 

	
 
#define INVALID_VEHICLE 0xFFFF
 
#define INVALID_ENGINE 0xFFFF
 

	
 
/* A lot of code calls for the invalidation of the status bar, which is widget 5.
 
 * Best is to have a virtual value for it when it needs to change again */
 
#define STATUS_BAR 5
 

	
 
#endif /* VEHICLE_H */
vehicle_gui.c
Show inline comments
 
@@ -419,13 +419,13 @@ static void train_engine_drawing_loop(in
 

	
 
	for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
 
		const Engine *e = GetEngine(i);
 
		const RailVehicleInfo *rvi = RailVehInfo(i);
 
		const EngineInfo *info = &_engine_info[i];
 

	
 
		if (!EngineHasReplacement(p, i) && _player_num_engines[i] == 0 && show_outdated) continue;
 
		if (!EngineHasReplacementForPlayer(p, i) && _player_num_engines[i] == 0 && show_outdated) continue;
 

	
 
		if (rvi->power == 0 && !show_cars)   // disables display of cars (works since they do not have power)
 
			continue;
 

	
 
		if (*sel == 0) *selected_id = i;
 

	
 
@@ -478,13 +478,13 @@ static void SetupScrollStuffForReplaceWi
 
			w->widget[16].color = _player_colors[_local_player];	// sets the colour of that art thing
 
			for (engine_id = 0; engine_id < NUM_TRAIN_ENGINES; engine_id++) {
 
				const Engine *e = GetEngine(engine_id);
 
				const EngineInfo *info = &_engine_info[engine_id];
 

	
 
				if (ENGINE_AVAILABLE && RailVehInfo(engine_id)->power && e->railtype == railtype) {
 
					if (_player_num_engines[engine_id] > 0 || EngineHasReplacement(p, engine_id)) {
 
					if (_player_num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) {
 
						if (sel[0] == 0) selected_id[0] = engine_id;
 
						count++;
 
						sel[0]--;
 
					}
 
					if (HASBIT(e->player_avail, _local_player)) {
 
						if (sel[1] == 0) selected_id[1] = engine_id;
 
@@ -499,13 +499,13 @@ static void SetupScrollStuffForReplaceWi
 
			int num = NUM_ROAD_ENGINES;
 
			const Engine* e = GetEngine(ROAD_ENGINES_INDEX);
 
			byte cargo;
 
			engine_id = ROAD_ENGINES_INDEX;
 

	
 
			do {
 
				if (_player_num_engines[engine_id] > 0 || EngineHasReplacement(p, engine_id)) {
 
				if (_player_num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) {
 
					if (sel[0] == 0) selected_id[0] = engine_id;
 
					count++;
 
					sel[0]--;
 
				}
 
			} while (++engine_id,++e,--num);
 

	
 
@@ -530,13 +530,13 @@ static void SetupScrollStuffForReplaceWi
 
			int num = NUM_SHIP_ENGINES;
 
			const Engine* e = GetEngine(SHIP_ENGINES_INDEX);
 
			byte cargo, refittable;
 
			engine_id = SHIP_ENGINES_INDEX;
 

	
 
			do {
 
				if (_player_num_engines[engine_id] > 0 || EngineHasReplacement(p, engine_id)) {
 
				if (_player_num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) {
 
					if (sel[0] == 0) selected_id[0] = engine_id;
 
					count++;
 
					sel[0]--;
 
				}
 
			} while (++engine_id,++e,--num);
 

	
 
@@ -563,13 +563,13 @@ static void SetupScrollStuffForReplaceWi
 
			int num = NUM_AIRCRAFT_ENGINES;
 
			byte subtype;
 
			const Engine* e = GetEngine(AIRCRAFT_ENGINES_INDEX);
 
			engine_id = AIRCRAFT_ENGINES_INDEX;
 

	
 
			do {
 
				if (_player_num_engines[engine_id] > 0 || EngineHasReplacement(p, engine_id)) {
 
				if (_player_num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) {
 
					count++;
 
					if (sel[0] == 0) selected_id[0] = engine_id;
 
					sel[0]--;
 
				}
 
			} while (++engine_id,++e,--num);
 

	
 
@@ -640,13 +640,13 @@ static void DrawEngineArrayInReplaceWind
 
			byte cargo;
 

	
 
			if (selected_id[0] >= ROAD_ENGINES_INDEX && selected_id[0] < SHIP_ENGINES_INDEX) {
 
				cargo = RoadVehInfo(selected_id[0])->cargo_type;
 

	
 
				do {
 
					if (_player_num_engines[engine_id] > 0 || EngineHasReplacement(p, engine_id)) {
 
					if (_player_num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) {
 
						if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
 
							DrawString(x+59, y+2, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10);
 
							DrawRoadVehEngine(x+29, y+6, engine_id, _player_num_engines[engine_id] > 0 ? SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)) : PALETTE_CRASH);
 
							SetDParam(0, _player_num_engines[engine_id]);
 
							DrawStringRightAligned(213, y+5, STR_TINY_BLACK, 0);
 
							y += 14;
 
@@ -675,13 +675,13 @@ static void DrawEngineArrayInReplaceWind
 

	
 
			if (selected_id[0] != INVALID_ENGINE) {
 
				cargo = ShipVehInfo(selected_id[0])->cargo_type;
 
				refittable = ShipVehInfo(selected_id[0])->refittable;
 

	
 
				do {
 
					if (_player_num_engines[engine_id] > 0 || EngineHasReplacement(p, engine_id)) {
 
					if (_player_num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) {
 
						if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
 
							DrawString(x+75, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10);
 
							DrawShipEngine(x+35, y+10, engine_id, _player_num_engines[engine_id] > 0 ? SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)) : PALETTE_CRASH);
 
							SetDParam(0, _player_num_engines[engine_id]);
 
							DrawStringRightAligned(213, y+15, STR_TINY_BLACK, 0);
 
							y += 24;
 
@@ -708,13 +708,13 @@ static void DrawEngineArrayInReplaceWind
 
				int num = NUM_AIRCRAFT_ENGINES;
 
				const Engine* e = GetEngine(AIRCRAFT_ENGINES_INDEX);
 
				EngineID engine_id = AIRCRAFT_ENGINES_INDEX;
 
				byte subtype = AircraftVehInfo(selected_id[0])->subtype;
 

	
 
				do {
 
					if (_player_num_engines[engine_id] > 0 || EngineHasReplacement(p, engine_id)) {
 
					if (_player_num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) {
 
						if (sel[0] == 0) selected_id[0] = engine_id;
 
						if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
 
							DrawString(x+62, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10);
 
							DrawAircraftEngine(x+29, y+10, engine_id, _player_num_engines[engine_id] > 0 ? SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)) : PALETTE_CRASH);
 
							SetDParam(0, _player_num_engines[engine_id]);
 
							DrawStringRightAligned(213, y+15, STR_TINY_BLACK, 0);
 
@@ -822,24 +822,24 @@ static void ReplaceVehicleWndProc(Window
 
				// or Both lists have the same vehicle selected
 
				// or The selected replacement engine has a replacement (to prevent loops)
 
				// or The right list (new replacement) has the existing replacement vehicle selected
 
				if (selected_id[0] == INVALID_ENGINE ||
 
						selected_id[1] == INVALID_ENGINE ||
 
						selected_id[0] == selected_id[1] ||
 
						EngineReplacement(p, selected_id[1]) != INVALID_ENGINE ||
 
						EngineReplacement(p, selected_id[0]) == selected_id[1]) {
 
						EngineReplacementForPlayer(p, selected_id[1]) != INVALID_ENGINE ||
 
						EngineReplacementForPlayer(p, selected_id[0]) == selected_id[1]) {
 
					SETBIT(w->disabled_state, 4);
 
				} else {
 
					CLRBIT(w->disabled_state, 4);
 
				}
 

	
 
				// Disable the "Stop Replacing" button if:
 
				//    The left list (existing vehicle) is empty
 
				// or The selected vehicle has no replacement set up
 
				if (selected_id[0] == INVALID_ENGINE ||
 
						!EngineHasReplacement(p, selected_id[0])) {
 
						!EngineHasReplacementForPlayer(p, selected_id[0])) {
 
					SETBIT(w->disabled_state, 6);
 
				} else {
 
					CLRBIT(w->disabled_state, 6);
 
				}
 

	
 
				// now the actual drawing of the window itself takes place
 
@@ -851,16 +851,16 @@ static void ReplaceVehicleWndProc(Window
 
				}
 

	
 
				DrawWindowWidgets(w);
 

	
 
				// sets up the string for the vehicle that is being replaced to
 
				if (selected_id[0] != INVALID_ENGINE) {
 
					if (!EngineHasReplacement(p, selected_id[0])) {
 
					if (!EngineHasReplacementForPlayer(p, selected_id[0])) {
 
						SetDParam(0, STR_NOT_REPLACING);
 
					} else {
 
						SetDParam(0, GetCustomEngineName(EngineReplacement(p, selected_id[0])));
 
						SetDParam(0, GetCustomEngineName(EngineReplacementForPlayer(p, selected_id[0])));
 
					}
 
				} else {
 
					SetDParam(0, STR_NOT_REPLACING_VEHICLE_SELECTED);
 
				}
 

	
 
				DrawString(145, (w->resize.step_height == 24 ? 67 : 87) + w->resize.step_height * w->vscroll.cap, STR_02BD, 0x10);
0 comments (0 inline, 0 general)