diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 8d1acfb988..6be30415e8 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -5689,14 +5689,14 @@ static const CallbackResultSpriteGroup *NewCallbackResultSpriteGroup(uint16 grou /* Helper function to either create a callback or link to a previously * defined spritegroup. */ -static const SpriteGroup *GetGroupFromGroupID(byte setid, byte type, uint16 groupid) +static const SpriteGroup *GetGroupFromGroupID(uint16 setid, byte type, uint16 groupid) { if (HasBit(groupid, 15)) { return NewCallbackResultSpriteGroup(groupid); } - if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) { - grfmsg(1, "GetGroupFromGroupID(0x%02X:0x%02X): Groupid 0x%04X does not exist, leaving empty", setid, type, groupid); + if ((size_t)groupid >= _cur.spritegroups.size() || _cur.spritegroups[groupid] == nullptr) { + grfmsg(1, "GetGroupFromGroupID(0x%04X:0x%02X): Groupid 0x%04X does not exist, leaving empty", setid, type, groupid); return nullptr; } @@ -5707,6 +5707,8 @@ static const SpriteGroup *GetGroupFromGroupID(byte setid, byte type, uint16 grou static const SpriteGroup *GetGroupByID(uint16 groupid) { + if ((size_t)groupid >= _cur.spritegroups.size()) return nullptr; + const SpriteGroup *result = _cur.spritegroups[groupid]; return result; } @@ -5719,14 +5721,14 @@ static const SpriteGroup *GetGroupByID(uint16 groupid) * @param spriteid Raw value from the GRF for the new spritegroup; describes either the return value or the referenced spritegroup. * @return Created spritegroup. */ -static const SpriteGroup *CreateGroupFromGroupID(byte feature, byte setid, byte type, uint16 spriteid) +static const SpriteGroup *CreateGroupFromGroupID(byte feature, uint16 setid, byte type, uint16 spriteid) { if (HasBit(spriteid, 15)) { return NewCallbackResultSpriteGroup(spriteid); } if (!_cur.IsValidSpriteSet(feature, spriteid)) { - grfmsg(1, "CreateGroupFromGroupID(0x%02X:0x%02X): Sprite set %u invalid", setid, type, spriteid); + grfmsg(1, "CreateGroupFromGroupID(0x%04X:0x%02X): Sprite set %u invalid", setid, type, spriteid); return nullptr; } @@ -5787,6 +5789,7 @@ static void NewSpriteGroup(ByteReader *buf) * * B feature see action 1 * B set-id ID of this particular definition + * This is an extended byte if feature "more_action2_ids" is tested for * B type/num-entries * if 80 or greater, this is a randomized or variational * list definition, see below @@ -5802,7 +5805,7 @@ static void NewSpriteGroup(ByteReader *buf) return; } - uint8 setid = buf->ReadByte(); + uint16 setid = HasBit(_cur.grffile->observed_feature_tests, GFTOF_MORE_ACTION2_IDS) ? buf->ReadExtendedByte() : buf->ReadByte(); uint8 type = buf->ReadByte(); /* Sprite Groups are created here but they are allocated from a pool, so @@ -6188,6 +6191,7 @@ static void NewSpriteGroup(ByteReader *buf) } } + if ((size_t)setid >= _cur.spritegroups.size()) _cur.spritegroups.resize(setid + 1); _cur.spritegroups[setid] = act_group; } @@ -6250,7 +6254,7 @@ static CargoID TranslateCargo(uint8 feature, uint8 ctype) static bool IsValidGroupID(uint16 groupid, const char *function) { - if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) { + if ((size_t)groupid >= _cur.spritegroups.size() || _cur.spritegroups[groupid] == nullptr) { grfmsg(1, "%s: Spritegroup 0x%04X out of range or empty, skipping.", function, groupid); return false; } diff --git a/src/newgrf_extension.cpp b/src/newgrf_extension.cpp index 45af5f5d2b..8794260218 100644 --- a/src/newgrf_extension.cpp +++ b/src/newgrf_extension.cpp @@ -61,6 +61,7 @@ extern const GRFFeatureInfo _grf_feature_list[] = { GRFFeatureInfo("road_stops", 7), GRFFeatureInfo("new_landscape", 2), GRFFeatureInfo("more_objects_per_grf", 1, GFTOF_MORE_OBJECTS_PER_GRF), + GRFFeatureInfo("more_action2_ids", 1, GFTOF_MORE_ACTION2_IDS), GRFFeatureInfo(), }; diff --git a/src/newgrf_extension.h b/src/newgrf_extension.h index d06beb050f..9cc6705473 100644 --- a/src/newgrf_extension.h +++ b/src/newgrf_extension.h @@ -91,6 +91,7 @@ enum Action2VariableRemapIds { enum GRFFeatureTestObservationFlag : uint8 { GFTOF_MORE_OBJECTS_PER_GRF = 0, + GFTOF_MORE_ACTION2_IDS, GFTOF_INVALID = 0xFF, }; diff --git a/src/newgrf_internal.h b/src/newgrf_internal.h index 1dca36dad3..da18417dd1 100644 --- a/src/newgrf_internal.h +++ b/src/newgrf_internal.h @@ -20,8 +20,6 @@ #include "3rdparty/cpp-btree/btree_map.h" #include -static const uint MAX_SPRITEGROUP = UINT8_MAX; ///< Maximum GRF-local ID for a spritegroup. - /** Base GRF ID for OpenTTD's base graphics GRFs. */ static const uint32 OPENTTD_GRAPHICS_BASE_GRF_ID = BSWAP32(0xFF4F5400); @@ -66,7 +64,7 @@ public: int skip_sprites; ///< Number of pseudo sprites to skip before processing the next one. (-1 to skip to end of file) /* Currently referenceable spritegroups */ - const SpriteGroup *spritegroups[MAX_SPRITEGROUP + 1]; + std::vector spritegroups; /* VarAction2 temporary storage variable tracking */ btree::btree_map group_temp_store_variable_tracking; @@ -124,7 +122,7 @@ public: this->spritesets[i].clear(); } - memset(this->spritegroups, 0, sizeof(this->spritegroups)); + this->spritegroups.clear(); this->group_temp_store_variable_tracking.clear(); this->group_temp_store_variable_tracking_storage.EmptyArena();