diff --git a/src/newgrf_commons.cpp b/src/newgrf_commons.cpp index 071e4a108a..2508fa2726 100644 --- a/src/newgrf_commons.cpp +++ b/src/newgrf_commons.cpp @@ -312,10 +312,11 @@ void ObjectOverrideManager::SetEntitySpec(ObjectSpec *spec) return; } - extern ObjectSpec _object_specs[NUM_OBJECTS]; + extern std::vector _object_specs; /* Now that we know we can use the given id, copy the spec to its final destination. */ - memcpy(&_object_specs[type], spec, sizeof(*spec)); + if (type >= _object_specs.size()) _object_specs.resize(type + 1); + _object_specs[type] = *spec; } /** diff --git a/src/newgrf_object.cpp b/src/newgrf_object.cpp index c7c2c770ee..a14f8d19ae 100644 --- a/src/newgrf_object.cpp +++ b/src/newgrf_object.cpp @@ -29,7 +29,12 @@ ObjectOverrideManager _object_mngr(NEW_OBJECT_OFFSET, NUM_OBJECTS, INVALID_OBJEC extern const ObjectSpec _original_objects[NEW_OBJECT_OFFSET]; /** All the object specifications. */ -ObjectSpec _object_specs[NUM_OBJECTS]; +std::vector _object_specs; + +size_t ObjectSpec::Count() +{ + return _object_specs.size(); +} /** * Get the specification associated with a specific ObjectType. @@ -38,7 +43,11 @@ ObjectSpec _object_specs[NUM_OBJECTS]; */ /* static */ const ObjectSpec *ObjectSpec::Get(ObjectType index) { + /* Empty object if index is out of range -- this might happen if NewGRFs are changed. */ + static ObjectSpec empty = {}; + assert(index < NUM_OBJECTS); + if (index >= _object_specs.size()) return ∅ return &_object_specs[index]; } @@ -87,7 +96,7 @@ bool ObjectSpec::IsAvailable() const */ uint ObjectSpec::Index() const { - return this - _object_specs; + return this - _object_specs.data(); } /** @@ -106,14 +115,13 @@ uint ObjectSpec::Index() const void ResetObjects() { /* Clean the pool. */ - for (uint16 i = 0; i < NUM_OBJECTS; i++) { - _object_specs[i] = {}; - } + _object_specs.clear(); /* And add our originals. */ - MemCpyT(_object_specs, _original_objects, lengthof(_original_objects)); + _object_specs.resize(lengthof(_original_objects)); for (uint16 i = 0; i < lengthof(_original_objects); i++) { + _object_specs[i] = _original_objects[i]; _object_specs[i].grf_prop.local_id = i; } diff --git a/src/newgrf_object.h b/src/newgrf_object.h index f283e36407..df6958074e 100644 --- a/src/newgrf_object.h +++ b/src/newgrf_object.h @@ -99,6 +99,7 @@ struct ObjectSpec { bool IsAvailable() const; uint Index() const; + static size_t Count(); static const ObjectSpec *Get(ObjectType index); static const ObjectSpec *GetByTile(TileIndex tile); diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp index 5f37b6d1c7..ce423273f4 100644 --- a/src/object_cmd.cpp +++ b/src/object_cmd.cpp @@ -207,7 +207,7 @@ CommandCost CmdBuildObject(DoCommandFlag flags, TileIndex tile, ObjectType type, { CommandCost cost(EXPENSES_CONSTRUCTION); - if (type >= NUM_OBJECTS) return CMD_ERROR; + if (type >= ObjectSpec::Count()) return CMD_ERROR; const ObjectSpec *spec = ObjectSpec::Get(type); if (_game_mode == GM_NORMAL && !spec->IsAvailable() && !_generating_world) return CMD_ERROR; if ((_game_mode == GM_EDITOR || _generating_world) && !spec->WasEverAvailable()) return CMD_ERROR; @@ -388,7 +388,7 @@ CommandCost CmdBuildObjectArea(DoCommandFlag flags, TileIndex tile, TileIndex st { if (start_tile >= Map::Size()) return CMD_ERROR; - if (type >= NUM_OBJECTS) return CMD_ERROR; + if (type >= ObjectSpec::Count()) return CMD_ERROR; const ObjectSpec *spec = ObjectSpec::Get(type); if (view >= spec->views) return CMD_ERROR; @@ -792,7 +792,7 @@ static bool TryBuildTransmitter() void GenerateObjects() { /* Set a guestimate on how much we progress */ - SetGeneratingWorldProgress(GWP_OBJECT, NUM_OBJECTS); + SetGeneratingWorldProgress(GWP_OBJECT, (uint)ObjectSpec::Count()); /* Determine number of water tiles at map border needed for freeform_edges */ uint num_water_tiles = 0; @@ -808,7 +808,7 @@ void GenerateObjects() } /* Iterate over all possible object types */ - for (uint i = 0; i < NUM_OBJECTS; i++) { + for (uint i = 0; i < ObjectSpec::Count(); i++) { const ObjectSpec *spec = ObjectSpec::Get(i); /* Continue, if the object was never available till now or shall not be placed */ diff --git a/src/object_gui.cpp b/src/object_gui.cpp index 7fb8e93c6f..b617115d1e 100644 --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -275,11 +275,11 @@ public: uint height[2] = {0, 0}; // The height for the different views; in this case views 1/2 and 4. /* Get the height and view information. */ - for (int i = 0; i < NUM_OBJECTS; i++) { + for (int i = 0; i < ObjectSpec::Count(); i++) { const ObjectSpec *spec = ObjectSpec::Get(i); if (!spec->IsEverAvailable()) continue; two_wide |= spec->views >= 2; - height[spec->views / 4] = std::max(ObjectSpec::Get(i)->height, height[spec->views / 4]); + height[spec->views / 4] = std::max(spec->height, height[spec->views / 4]); } /* Determine the pixel heights. */ diff --git a/src/script/api/script_objecttype.cpp b/src/script/api/script_objecttype.cpp index 7d74d9b8b8..842bdac4b7 100644 --- a/src/script/api/script_objecttype.cpp +++ b/src/script/api/script_objecttype.cpp @@ -19,7 +19,7 @@ /* static */ bool ScriptObjectType::IsValidObjectType(ObjectType object_type) { - if (object_type >= NUM_OBJECTS) return false; + if (object_type >= ObjectSpec::Count()) return false; return ObjectSpec::Get(object_type)->IsEverAvailable(); } diff --git a/src/script/api/script_objecttypelist.cpp b/src/script/api/script_objecttypelist.cpp index 0086260b20..0bb52b0576 100644 --- a/src/script/api/script_objecttypelist.cpp +++ b/src/script/api/script_objecttypelist.cpp @@ -15,7 +15,7 @@ ScriptObjectTypeList::ScriptObjectTypeList() { - for (int i = 0; i < NUM_OBJECTS; i++) { + for (int i = 0; i < ObjectSpec::Count(); i++) { const ObjectSpec *spec = ObjectSpec::Get(i); if (!spec->IsEverAvailable()) continue; this->AddItem(i);