|
@@ -1051,6 +1051,195 @@ int32 CmdRenameEngine(int x, int y, uint
|
|
|
}
|
|
|
|
|
|
|
|
|
/*
|
|
|
* 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),
|
|
@@ -1101,31 +1290,13 @@ static void LoadSave_ENGS(void)
|
|
|
|
|
|
const ChunkHandler _engine_chunk_handlers[] = {
|
|
|
{ 'ENGN', Save_ENGN, Load_ENGN, CH_ARRAY},
|
|
|
{ 'ENGS', LoadSave_ENGS, LoadSave_ENGS, CH_RIFF | CH_LAST},
|
|
|
{ '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);
|
|
|
}
|