summaryrefslogtreecommitdiff
path: root/engine.c
diff options
context:
space:
mode:
authorpeter1138 <peter1138@openttd.org>2006-01-12 15:52:18 +0000
committerpeter1138 <peter1138@openttd.org>2006-01-12 15:52:18 +0000
commit90aff7a026c8e833d78e932575995485c2da9e47 (patch)
tree2a159338918aa7b1a61fab6e18f4e28ae2b27950 /engine.c
parent28ca056d56bb716e125745c16876408527fdc278 (diff)
downloadopenttd-90aff7a026c8e833d78e932575995485c2da9e47.tar.xz
(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)
Diffstat (limited to 'engine.c')
-rw-r--r--engine.c221
1 files changed, 196 insertions, 25 deletions
diff --git a/engine.c b/engine.c
index a2e717f1e..56693a00c 100644
--- a/engine.c
+++ b/engine.c
@@ -1051,6 +1051,195 @@ int32 CmdRenameEngine(int x, int y, uint32 flags, uint32 p1, uint32 p2)
}
+/*
+ * 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),
@@ -1100,32 +1289,14 @@ 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},
+ { '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);
}