From ec8d31bbfc4391c4d9d77b5b5b89431e70cc7385 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 18 Aug 2023 13:38:19 +0300 Subject: [PATCH] First step at unifying game identifiers code --- AI/VCAI/Goals/CollectRes.cpp | 4 +- client/adventureMap/CResDataBar.h | 5 - client/lobby/OptionsTab.cpp | 16 +- include/vcmi/Creature.h | 4 +- include/vcmi/Entity.h | 7 +- include/vcmi/Faction.h | 4 +- include/vcmi/FactionMember.h | 4 +- include/vcmi/spells/Spell.h | 6 +- lib/CCreatureHandler.cpp | 2 +- lib/CGameInfoCallback.cpp | 2 +- lib/CHeroHandler.cpp | 2 +- lib/CTownHandler.cpp | 4 +- lib/CTownHandler.h | 4 +- lib/GameConstants.cpp | 27 +- lib/GameConstants.h | 393 ++++++++++++++----------- lib/ResourceSet.cpp | 6 +- lib/ResourceSet.h | 10 - lib/StringConstants.h | 2 +- lib/gameState/CGameState.cpp | 2 +- lib/mapObjects/CGTownInstance.cpp | 2 +- lib/mapObjects/MiscObjects.cpp | 2 +- lib/mapping/MapFormatJson.cpp | 2 +- lib/mapping/MapReaderH3M.cpp | 2 +- lib/rmg/CMapGenOptions.cpp | 2 +- lib/rmg/CMapGenOptions.h | 3 - lib/rmg/CMapGenerator.cpp | 2 +- lib/rmg/CRmgTemplate.cpp | 12 +- lib/rmg/CZonePlacer.cpp | 4 +- lib/rmg/modificators/TownPlacer.cpp | 2 +- lib/spells/AdventureSpellMechanics.cpp | 2 +- lib/spells/CSpellHandler.cpp | 2 +- server/CVCMIServer.cpp | 10 +- test/entity/CCreatureTest.cpp | 2 +- test/mock/mock_Creature.h | 2 +- 34 files changed, 294 insertions(+), 261 deletions(-) diff --git a/AI/VCAI/Goals/CollectRes.cpp b/AI/VCAI/Goals/CollectRes.cpp index 8494952e2..d0832c3e3 100644 --- a/AI/VCAI/Goals/CollectRes.cpp +++ b/AI/VCAI/Goals/CollectRes.cpp @@ -170,10 +170,10 @@ TSubgoal CollectRes::whatToDoToTrade() int howManyCanWeBuy = 0; for (GameResID i = EGameResID::WOOD; i <= EGameResID::GOLD; ++i) { - if (GameResID(i) == resID) + if (i.getNum() == resID) continue; int toGive = -1, toReceive = -1; - m->getOffer(GameResID(i), resID, toGive, toReceive, EMarketMode::RESOURCE_RESOURCE); + m->getOffer(i, resID, toGive, toReceive, EMarketMode::RESOURCE_RESOURCE); assert(toGive > 0 && toReceive > 0); howManyCanWeBuy += toReceive * (ai->ah->freeResources()[i] / toGive); } diff --git a/client/adventureMap/CResDataBar.h b/client/adventureMap/CResDataBar.h index d4696cd26..c9bc01286 100644 --- a/client/adventureMap/CResDataBar.h +++ b/client/adventureMap/CResDataBar.h @@ -11,11 +11,6 @@ #include "../gui/CIntObject.h" -VCMI_LIB_NAMESPACE_BEGIN -enum class EGameResID : int8_t; -using GameResID = Identifier; -VCMI_LIB_NAMESPACE_END - /// Resources bar which shows information about how many gold, crystals,... you have /// Current date is displayed too class CResDataBar : public CIntObject diff --git a/client/lobby/OptionsTab.cpp b/client/lobby/OptionsTab.cpp index 87968c2dd..67dee51f9 100644 --- a/client/lobby/OptionsTab.cpp +++ b/client/lobby/OptionsTab.cpp @@ -94,7 +94,7 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex(bool big) TOWN_RANDOM = 38, TOWN_NONE = 39, // Special frames in ITPA HERO_RANDOM = 163, HERO_NONE = 164 // Special frames in PortraitsSmall }; - auto factionIndex = settings.castle >= CGI->townh->size() ? 0 : settings.castle; + auto factionIndex = settings.castle.getNum() >= CGI->townh->size() ? 0 : settings.castle.getNum(); switch(type) { @@ -191,7 +191,7 @@ std::string OptionsTab::CPlayerSettingsHelper::getName() return CGI->generaltexth->allTexts[522]; default: { - auto factionIndex = settings.castle >= CGI->townh->size() ? 0 : settings.castle; + auto factionIndex = settings.castle.getNum() >= CGI->townh->size() ? 0 : settings.castle.getNum(); return (*CGI->townh)[factionIndex]->getNameTranslated(); } } @@ -233,7 +233,7 @@ std::string OptionsTab::CPlayerSettingsHelper::getTitle() switch(type) { case OptionsTab::TOWN: - return (settings.castle < 0) ? CGI->generaltexth->allTexts[103] : CGI->generaltexth->allTexts[80]; + return (settings.castle.getNum() < 0) ? CGI->generaltexth->allTexts[103] : CGI->generaltexth->allTexts[80]; case OptionsTab::HERO: return (settings.hero < 0) ? CGI->generaltexth->allTexts[101] : CGI->generaltexth->allTexts[77]; case OptionsTab::BONUS: @@ -255,7 +255,7 @@ std::string OptionsTab::CPlayerSettingsHelper::getTitle() } std::string OptionsTab::CPlayerSettingsHelper::getSubtitle() { - auto factionIndex = settings.castle >= CGI->townh->size() ? 0 : settings.castle; + auto factionIndex = settings.castle.getNum() >= CGI->townh->size() ? 0 : settings.castle.getNum(); auto heroIndex = settings.hero >= CGI->heroh->size() ? 0 : settings.hero; switch(type) @@ -299,7 +299,7 @@ std::string OptionsTab::CPlayerSettingsHelper::getSubtitle() std::string OptionsTab::CPlayerSettingsHelper::getDescription() { - auto factionIndex = settings.castle >= CGI->townh->size() ? 0 : settings.castle; + auto factionIndex = settings.castle.getNum() >= CGI->townh->size() ? 0 : settings.castle.getNum(); switch(type) { @@ -386,7 +386,7 @@ void OptionsTab::CPlayerOptionTooltipBox::genTownWindow() pos = Rect(0, 0, 228, 290); genHeader(); labelAssociatedCreatures = std::make_shared(pos.w / 2 + 8, 122, FONT_MEDIUM, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[79]); - auto factionIndex = settings.castle >= CGI->townh->size() ? 0 : settings.castle; + auto factionIndex = settings.castle.getNum() >= CGI->townh->size() ? 0 : settings.castle.getNum(); std::vector> components; const CTown * town = (*CGI->townh)[factionIndex]->town; @@ -784,7 +784,7 @@ void OptionsTab::SelectedBox::update() void OptionsTab::SelectedBox::showPopupWindow(const Point & cursorPosition) { // cases when we do not need to display a message - if(settings.castle == PlayerSettings::NONE && CPlayerSettingsHelper::type == TOWN) + if(settings.castle.getNum() == PlayerSettings::NONE && CPlayerSettingsHelper::type == TOWN) return; if(settings.hero == PlayerSettings::NONE && !SEL->getPlayerInfo(settings.color.getNum()).hasCustomMainHero() && CPlayerSettingsHelper::type == HERO) return; @@ -932,7 +932,7 @@ void OptionsTab::PlayerOptionsEntry::hideUnavailableButtons() buttonTownRight->enable(); } - if((pi->defaultHero() != -1 || s->castle < 0) //fixed hero + if((pi->defaultHero() != -1 || s->castle.getNum() < 0) //fixed hero || foreignPlayer) //or not our player { buttonHeroLeft->disable(); diff --git a/include/vcmi/Creature.h b/include/vcmi/Creature.h index 736d16043..645d144ab 100644 --- a/include/vcmi/Creature.h +++ b/include/vcmi/Creature.h @@ -16,7 +16,7 @@ VCMI_LIB_NAMESPACE_BEGIN class CreatureID; class ResourceSet; -enum class EGameResID : int8_t; +class GameResID; /// Base class for creatures and battle stacks class DLL_LINKAGE ACreature: public AFactionMember @@ -63,7 +63,7 @@ public: virtual int32_t getBaseSpeed() const = 0; virtual int32_t getBaseShots() const = 0; - virtual int32_t getRecruitCost(Identifier resIndex) const = 0; + virtual int32_t getRecruitCost(GameResID resIndex) const = 0; virtual ResourceSet getFullRecruitCost() const = 0; virtual bool hasUpgrades() const = 0; diff --git a/include/vcmi/Entity.h b/include/vcmi/Entity.h index f91130d7b..34ccc2757 100644 --- a/include/vcmi/Entity.h +++ b/include/vcmi/Entity.h @@ -14,8 +14,7 @@ VCMI_LIB_NAMESPACE_BEGIN class IBonusBearer; class FactionID; -enum class ETerrainId; -template class Identifier; +class TerrainId; class DLL_LINKAGE IConstBonusProvider { @@ -26,9 +25,9 @@ public: class DLL_LINKAGE INativeTerrainProvider { public: - virtual Identifier getNativeTerrain() const = 0; + virtual TerrainId getNativeTerrain() const = 0; virtual FactionID getFaction() const = 0; - virtual bool isNativeTerrain(Identifier terrain) const; + virtual bool isNativeTerrain(TerrainId terrain) const; }; class DLL_LINKAGE Entity diff --git a/include/vcmi/Faction.h b/include/vcmi/Faction.h index 8d98ae075..2bc959567 100644 --- a/include/vcmi/Faction.h +++ b/include/vcmi/Faction.h @@ -16,14 +16,14 @@ VCMI_LIB_NAMESPACE_BEGIN class FactionID; enum class EAlignment : uint8_t; -enum class EBoatId : int32_t; +class BoatId; class DLL_LINKAGE Faction : public EntityT, public INativeTerrainProvider { public: virtual bool hasTown() const = 0; virtual EAlignment getAlignment() const = 0; - virtual EBoatId getBoatType() const = 0; + virtual BoatId getBoatType() const = 0; }; VCMI_LIB_NAMESPACE_END diff --git a/include/vcmi/FactionMember.h b/include/vcmi/FactionMember.h index 722ac7117..508d1092f 100644 --- a/include/vcmi/FactionMember.h +++ b/include/vcmi/FactionMember.h @@ -27,7 +27,7 @@ public: /** Returns native terrain considering some terrain bonuses. */ - virtual Identifier getNativeTerrain() const; + virtual TerrainId getNativeTerrain() const; /** Returns magic resistance considering some bonuses. */ @@ -71,4 +71,4 @@ public: int luckValAndBonusList(std::shared_ptr & bonusList) const; }; -VCMI_LIB_NAMESPACE_END \ No newline at end of file +VCMI_LIB_NAMESPACE_END diff --git a/include/vcmi/spells/Spell.h b/include/vcmi/spells/Spell.h index bc9a80217..38a9a247b 100644 --- a/include/vcmi/spells/Spell.h +++ b/include/vcmi/spells/Spell.h @@ -15,7 +15,7 @@ VCMI_LIB_NAMESPACE_BEGIN class SpellID; -enum class ESpellSchool: int8_t; +class SpellSchool; namespace spells { @@ -24,7 +24,7 @@ class Caster; class DLL_LINKAGE Spell: public EntityT { public: - using SchoolCallback = std::function &, bool &)>; + using SchoolCallback = std::function; ///calculate spell damage on stack taking caster`s secondary skills into account virtual int64_t calculateDamage(const Caster * caster) const = 0; @@ -43,7 +43,7 @@ public: virtual bool isSpecial() const = 0; virtual bool isMagical() const = 0; //Should this spell considered as magical effect or as ability (like dendroid's bind) - virtual bool hasSchool(Identifier school) const = 0; + virtual bool hasSchool(SpellSchool school) const = 0; virtual void forEachSchool(const SchoolCallback & cb) const = 0; virtual const std::string & getCastSound() const = 0; virtual int32_t getCost(const int32_t skillLevel) const = 0; diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index 9640eb199..78de10cdf 100644 --- a/lib/CCreatureHandler.cpp +++ b/lib/CCreatureHandler.cpp @@ -161,7 +161,7 @@ int32_t CCreature::getBaseShots() const int32_t CCreature::getRecruitCost(GameResID resIndex) const { - if(resIndex >= 0 && resIndex < cost.size()) + if(resIndex.getNum() >= 0 && resIndex.getNum() < cost.size()) return cost[resIndex]; else return 0; diff --git a/lib/CGameInfoCallback.cpp b/lib/CGameInfoCallback.cpp index 4784d1e48..e430d2249 100644 --- a/lib/CGameInfoCallback.cpp +++ b/lib/CGameInfoCallback.cpp @@ -42,7 +42,7 @@ int CGameInfoCallback::getResource(PlayerColor Player, GameResID which) const { const PlayerState *p = getPlayerState(Player); ERROR_RET_VAL_IF(!p, "No player info!", -1); - ERROR_RET_VAL_IF(p->resources.size() <= which || which < 0, "No such resource!", -1); + ERROR_RET_VAL_IF(p->resources.size() <= which.getNum() || which.getNum() < 0, "No such resource!", -1); return p->resources[which]; } diff --git a/lib/CHeroHandler.cpp b/lib/CHeroHandler.cpp index 78adc3b0e..5bda9995d 100644 --- a/lib/CHeroHandler.cpp +++ b/lib/CHeroHandler.cpp @@ -345,7 +345,7 @@ std::vector CHeroClassHandler::loadLegacyData() for(const auto & name : NSecondarySkill::names) entry["secondarySkills"][name].Float() = parser.readNumber(); - for(const auto & name : ETownType::names) + for(const auto & name : NFaction::names) entry["tavern"][name].Float() = parser.readNumber(); parser.endLine(); diff --git a/lib/CTownHandler.cpp b/lib/CTownHandler.cpp index abff75760..85471ec32 100644 --- a/lib/CTownHandler.cpp +++ b/lib/CTownHandler.cpp @@ -184,7 +184,7 @@ EAlignment CFaction::getAlignment() const return alignment; } -EBoatId CFaction::getBoatType() const +BoatId CFaction::getBoatType() const { return boatType.toEnum(); } @@ -1034,7 +1034,7 @@ CFaction * CTownHandler::loadFromJson(const std::string & scope, const JsonNode faction->creatureBg120 = source["creatureBackground"]["120px"].String(); faction->creatureBg130 = source["creatureBackground"]["130px"].String(); - faction->boatType = EBoatId::CASTLE; //Do not crash + faction->boatType = BoatId::CASTLE; //Do not crash if (!source["boat"].isNull()) { VLC->identifiers()->requestIdentifier("core:boat", source["boat"], [=](int32_t boatTypeID) diff --git a/lib/CTownHandler.h b/lib/CTownHandler.h index 66aec6196..0b4b40a08 100644 --- a/lib/CTownHandler.h +++ b/lib/CTownHandler.h @@ -207,7 +207,7 @@ public: /// Boat that will be used by town shipyard (if any) /// and for placing heroes directly on boat (in map editor, water prisons & taverns) - BoatId boatType = BoatId(EBoatId::CASTLE); + BoatId boatType = BoatId::CASTLE; CTown * town = nullptr; //NOTE: can be null @@ -232,7 +232,7 @@ public: bool hasTown() const override; TerrainId getNativeTerrain() const override; EAlignment getAlignment() const override; - EBoatId getBoatType() const override; + BoatId getBoatType() const override; void updateFrom(const JsonNode & data); void serializeJson(JsonSerializeFormat & handler); diff --git a/lib/GameConstants.cpp b/lib/GameConstants.cpp index 733596428..f059f9b19 100644 --- a/lib/GameConstants.cpp +++ b/lib/GameConstants.cpp @@ -191,20 +191,7 @@ std::string PlayerColor::getStrCap(bool L10n) const return ret; } -const FactionID FactionID::NONE = FactionID(-2); -const FactionID FactionID::DEFAULT = FactionID(-1); -const FactionID FactionID::CASTLE = FactionID(0); -const FactionID FactionID::RAMPART = FactionID(1); -const FactionID FactionID::TOWER = FactionID(2); -const FactionID FactionID::INFERNO = FactionID(3); -const FactionID FactionID::NECROPOLIS = FactionID(4); -const FactionID FactionID::DUNGEON = FactionID(5); -const FactionID FactionID::STRONGHOLD = FactionID(6); -const FactionID FactionID::FORTRESS = FactionID(7); -const FactionID FactionID::CONFLUX = FactionID(8); -const FactionID FactionID::NEUTRAL = FactionID(9); - -si32 FactionID::decode(const std::string & identifier) +si32 FactionIDBase::decode(const std::string & identifier) { auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), entityType(), identifier); if(rawId) @@ -213,32 +200,32 @@ si32 FactionID::decode(const std::string & identifier) return FactionID::DEFAULT; } -std::string FactionID::encode(const si32 index) +std::string FactionIDBase::encode(const si32 index) { return VLC->factions()->getByIndex(index)->getJsonKey(); } -std::string FactionID::entityType() +std::string FactionIDBase::entityType() { return "faction"; } -si32 TerrainID::decode(const std::string & identifier) +si32 TerrainIdBase::decode(const std::string & identifier) { auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), entityType(), identifier); if(rawId) return rawId.value(); else - return static_cast(ETerrainId::NONE); + return static_cast(TerrainId::NONE); } -std::string TerrainID::encode(const si32 index) +std::string TerrainIdBase::encode(const si32 index) { return VLC->terrainTypeHandler->getByIndex(index)->getJsonKey(); } -std::string TerrainID::entityType() +std::string TerrainIdBase::entityType() { return "terrain"; } diff --git a/lib/GameConstants.h b/lib/GameConstants.h index 23214e1a1..ee023ad61 100644 --- a/lib/GameConstants.h +++ b/lib/GameConstants.h @@ -33,6 +33,7 @@ class CSkill; class CGameInfoCallback; class CNonConstInfoCallback; + struct IdTag {}; @@ -203,74 +204,6 @@ public: } }; -template < typename T> -class Identifier : public IdTag -{ -public: - using EnumType = T; - using NumericType = typename std::underlying_type::type; - -private: - NumericType num; - -public: - constexpr NumericType getNum() const - { - return num; - } - - constexpr EnumType toEnum() const - { - return static_cast(num); - } - - template void serialize(Handler &h, const int version) - { - h & num; - } - - constexpr explicit Identifier(NumericType _num = -1) - { - num = _num; - } - - /* implicit */constexpr Identifier(EnumType _num): - num(static_cast(_num)) - { - } - - constexpr void advance(int change) - { - num += change; - } - - constexpr bool operator == (const Identifier & b) const { return num == b.num; } - constexpr bool operator <= (const Identifier & b) const { return num <= b.num; } - constexpr bool operator >= (const Identifier & b) const { return num >= b.num; } - constexpr bool operator != (const Identifier & b) const { return num != b.num; } - constexpr bool operator < (const Identifier & b) const { return num < b.num; } - constexpr bool operator > (const Identifier & b) const { return num > b.num; } - - constexpr Identifier & operator++() - { - ++num; - return *this; - } - - constexpr Identifier operator++(int) - { - Identifier ret(*this); - ++num; - return ret; - } - - constexpr operator NumericType() const - { - return num; - } -}; - - template std::ostream & operator << (std::ostream & os, BaseForID id); @@ -282,13 +215,85 @@ std::ostream & operator << (std::ostream & os, BaseForID id) return os << static_cast(id.getNum()); } -template -std::ostream & operator << (std::ostream & os, Identifier id) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class EntityBase { - //We use common type with short to force char and unsigned char to be promoted and formatted as numbers. - typedef typename std::common_type::NumericType>::type Number; - return os << static_cast(id.getNum()); -} +public: + int32_t num; +}; + +template +class EntityIdentifier : public T +{ + using EnumType = typename T::Type; + + static_assert(std::is_same_v, int32_t>, "Entity Identifier must use int32_t"); +public: + constexpr int32_t getNum() const + { + return T::num; + } + + constexpr EnumType toEnum() const + { + return static_cast(T::num); + } + + template void serialize(Handler &h, const int version) + { + h & T::num; + } + + constexpr EntityIdentifier(const EnumType & enumValue) + { + T::num = static_cast(enumValue); + } + + constexpr EntityIdentifier(int32_t _num = -1) + { + T::num = _num; + } + + constexpr void advance(int change) + { + T::num += change; + } + + constexpr bool operator == (const EnumType & b) const { return T::num == static_cast(b); } + constexpr bool operator <= (const EnumType & b) const { return T::num <= static_cast(b); } + constexpr bool operator >= (const EnumType & b) const { return T::num >= static_cast(b); } + constexpr bool operator != (const EnumType & b) const { return T::num != static_cast(b); } + constexpr bool operator < (const EnumType & b) const { return T::num < static_cast(b); } + constexpr bool operator > (const EnumType & b) const { return T::num > static_cast(b); } + + constexpr bool operator == (const EntityIdentifier & b) const { return T::num == b.num; } + constexpr bool operator <= (const EntityIdentifier & b) const { return T::num <= b.num; } + constexpr bool operator >= (const EntityIdentifier & b) const { return T::num >= b.num; } + constexpr bool operator != (const EntityIdentifier & b) const { return T::num != b.num; } + constexpr bool operator < (const EntityIdentifier & b) const { return T::num < b.num; } + constexpr bool operator > (const EntityIdentifier & b) const { return T::num > b.num; } + + constexpr EntityIdentifier & operator++() + { + ++T::num; + return *this; + } + + constexpr EntityIdentifier operator++(int) + { + EntityIdentifier ret(*this); + ++T::num; + return ret; + } + + constexpr operator int32_t () const + { + return T::num; + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ArtifactInstanceID : public BaseForID { @@ -398,11 +403,6 @@ class TeleportChannelID : public BaseForID friend class CNonConstInfoCallback; }; -// #ifndef INSTANTIATE_BASE_FOR_ID_HERE -// extern template std::ostream & operator << (std::ostream & os, BaseForID id); -// extern template std::ostream & operator << (std::ostream & os, BaseForID id); -// #endif - // Enum declarations namespace PrimarySkill { @@ -410,10 +410,10 @@ namespace PrimarySkill EXPERIENCE = 4}; //for some reason changePrimSkill uses it } -class SecondarySkill +class SecondarySkillBase : public EntityBase { public: - enum ESecondarySkill + enum Type : int32_t { WRONG = -2, DEFAULT = -1, @@ -422,61 +422,51 @@ public: SCHOLAR, TACTICS, ARTILLERY, LEARNING, OFFENCE, ARMORER, INTELLIGENCE, SORCERY, RESISTANCE, FIRST_AID, SKILL_SIZE }; - static_assert(GameConstants::SKILL_QUANTITY == SKILL_SIZE, "Incorrect number of skills"); - - SecondarySkill(ESecondarySkill _num = WRONG) : num(_num) - {} - - ID_LIKE_CLASS_COMMON(SecondarySkill, ESecondarySkill) - - ESecondarySkill num; }; -ID_LIKE_OPERATORS(SecondarySkill, SecondarySkill::ESecondarySkill) +class SecondarySkill : public EntityIdentifier +{ +public: + using EntityIdentifier::EntityIdentifier; +}; enum class EAlignment : uint8_t { GOOD, EVIL, NEUTRAL }; -namespace ETownType//deprecated +class FactionIDBase : public EntityBase { - enum ETownType +public: + enum Type : int32_t { + NONE = -2, + DEFAULT = -1, + RANDOM = -1, ANY = -1, - CASTLE, RAMPART, TOWER, INFERNO, NECROPOLIS, DUNGEON, STRONGHOLD, FORTRESS, CONFLUX, NEUTRAL + CASTLE, + RAMPART, + TOWER, + INFERNO, + NECROPOLIS, + DUNGEON, + STRONGHOLD, + FORTRESS, + CONFLUX, + NEUTRAL }; -} - -class FactionID : public BaseForID -{ - INSTID_LIKE_CLASS_COMMON(FactionID, si32) - - DLL_LINKAGE static const FactionID NONE; - DLL_LINKAGE static const FactionID DEFAULT; - DLL_LINKAGE static const FactionID CASTLE; - DLL_LINKAGE static const FactionID RAMPART; - DLL_LINKAGE static const FactionID TOWER; - DLL_LINKAGE static const FactionID INFERNO; - DLL_LINKAGE static const FactionID NECROPOLIS; - DLL_LINKAGE static const FactionID DUNGEON; - DLL_LINKAGE static const FactionID STRONGHOLD; - DLL_LINKAGE static const FactionID FORTRESS; - DLL_LINKAGE static const FactionID CONFLUX; - DLL_LINKAGE static const FactionID NEUTRAL; static si32 decode(const std::string& identifier); static std::string encode(const si32 index); static std::string entityType(); }; -class TerrainID +class FactionID : public EntityIdentifier { - //Dummy class used only for serialization public: - static si32 decode(const std::string & identifier); - static std::string encode(const si32 index); - static std::string entityType(); + using EntityIdentifier::EntityIdentifier; }; +using ETownType = FactionID; + class BuildingID { public: @@ -953,27 +943,50 @@ public: ID_LIKE_OPERATORS(Obj, Obj::EObj) -enum class Road : int8_t +class RoadIsBase : public EntityBase { - NO_ROAD = 0, - FIRST_REGULAR_ROAD = 1, - DIRT_ROAD = 1, - GRAVEL_ROAD = 2, - COBBLESTONE_ROAD = 3, - ORIGINAL_ROAD_COUNT //+1 +public: + enum Type : int32_t + { + NO_ROAD = 0, + FIRST_REGULAR_ROAD = 1, + DIRT_ROAD = 1, + GRAVEL_ROAD = 2, + COBBLESTONE_ROAD = 3, + ORIGINAL_ROAD_COUNT //+1 + }; }; -enum class River : int8_t +class RoadId : public EntityIdentifier { - NO_RIVER = 0, - FIRST_REGULAR_RIVER = 1, - WATER_RIVER = 1, - ICY_RIVER = 2, - MUD_RIVER = 3, - LAVA_RIVER = 4, - ORIGINAL_RIVER_COUNT //+1 +public: + using EntityIdentifier::EntityIdentifier; }; +class RiverIdBase : public EntityBase +{ +public: + enum Type : int32_t + { + NO_RIVER = 0, + FIRST_REGULAR_RIVER = 1, + WATER_RIVER = 1, + ICY_RIVER = 2, + MUD_RIVER = 3, + LAVA_RIVER = 4, + ORIGINAL_RIVER_COUNT //+1 + }; +}; + +class RiverId : public EntityIdentifier +{ +public: + using EntityIdentifier::EntityIdentifier; +}; + +using River = RiverId; +using Road = RoadId; + namespace SecSkillLevel { enum SecSkillLevel @@ -1296,37 +1309,58 @@ class BattleField : public BaseForID DLL_LINKAGE const BattleFieldInfo * getInfo() const; }; -enum class EBoatId : int32_t +class BoatIdBase : public EntityBase { - NONE = -1, - NECROPOLIS = 0, - CASTLE, - FORTRESS +public: + enum Type : int32_t + { + NONE = -1, + NECROPOLIS = 0, + CASTLE, + FORTRESS + }; }; -using BoatId = Identifier; - -enum class ETerrainId { - NATIVE_TERRAIN = -4, - ANY_TERRAIN = -3, - NONE = -1, - FIRST_REGULAR_TERRAIN = 0, - DIRT = 0, - SAND, - GRASS, - SNOW, - SWAMP, - ROUGH, - SUBTERRANEAN, - LAVA, - WATER, - ROCK, - ORIGINAL_REGULAR_TERRAIN_COUNT = ROCK +class BoatId : public EntityIdentifier +{ +public: + using EntityIdentifier::EntityIdentifier; }; -using TerrainId = Identifier; -using RoadId = Identifier; -using RiverId = Identifier; +class TerrainIdBase : public EntityBase +{ +public: + enum Type : int32_t + { + NATIVE_TERRAIN = -4, + ANY_TERRAIN = -3, + NONE = -1, + FIRST_REGULAR_TERRAIN = 0, + DIRT = 0, + SAND, + GRASS, + SNOW, + SWAMP, + ROUGH, + SUBTERRANEAN, + LAVA, + WATER, + ROCK, + ORIGINAL_REGULAR_TERRAIN_COUNT = ROCK + }; + + static si32 decode(const std::string & identifier); + static std::string encode(const si32 index); + static std::string entityType(); +}; + +class TerrainId : public EntityIdentifier +{ +public: + using EntityIdentifier::EntityIdentifier; +}; + +using ETerrainId = TerrainId; class ObstacleInfo; class Obstacle : public BaseForID @@ -1336,16 +1370,26 @@ class Obstacle : public BaseForID DLL_LINKAGE const ObstacleInfo * getInfo() const; }; -enum class ESpellSchool: int8_t +class SpellSchoolBase : public EntityBase { - ANY = -1, - AIR = 0, - FIRE = 1, - WATER = 2, - EARTH = 3, +public: + enum Type : int32_t + { + ANY = -1, + AIR = 0, + FIRE = 1, + WATER = 2, + EARTH = 3, + }; }; -using SpellSchool = Identifier; +class SpellSchool : public EntityIdentifier +{ +public: + using EntityIdentifier::EntityIdentifier; +}; + +using ESpellSchool = SpellSchool; enum class EMetaclass: ui8 { @@ -1387,6 +1431,27 @@ enum class EBattleResult : int8_t SURRENDER = 2 }; +class GameResIDBase : public EntityBase +{ +public: + enum Type : int32_t + { + WOOD = 0, MERCURY, ORE, SULFUR, CRYSTAL, GEMS, GOLD, MITHRIL, + COUNT, + + WOOD_AND_ORE = 127, // special case for town bonus resource + INVALID = -1 + }; +}; + +class GameResID : public EntityIdentifier +{ +public: + using EntityIdentifier::EntityIdentifier; +}; + +using EGameResID = GameResID; + // Typedef declarations using TExpType = si64; using TQuantity = si32; diff --git a/lib/ResourceSet.cpp b/lib/ResourceSet.cpp index 50f2c48b6..56fc50442 100644 --- a/lib/ResourceSet.cpp +++ b/lib/ResourceSet.cpp @@ -119,7 +119,7 @@ std::string ResourceSet::toString() const bool ResourceSet::nziterator::valid() const { - return cur.resType < GameConstants::RESOURCE_QUANTITY && cur.resVal; + return cur.resType < GameResID::COUNT && cur.resVal; } ResourceSet::nziterator ResourceSet::nziterator::operator++() @@ -150,9 +150,9 @@ void ResourceSet::nziterator::advance() do { ++cur.resType; - } while(cur.resType < GameConstants::RESOURCE_QUANTITY && !(cur.resVal=rs[cur.resType])); + } while(cur.resType < GameResID::COUNT && !(cur.resVal=rs[cur.resType])); - if(cur.resType >= GameConstants::RESOURCE_QUANTITY) + if(cur.resType >= GameResID::COUNT) cur.resVal = -1; } diff --git a/lib/ResourceSet.h b/lib/ResourceSet.h index 6d879f715..1b4d5908d 100644 --- a/lib/ResourceSet.h +++ b/lib/ResourceSet.h @@ -22,16 +22,6 @@ class JsonSerializeFormat; class ResourceSet; -enum class EGameResID : int8_t -{ - WOOD = 0, MERCURY, ORE, SULFUR, CRYSTAL, GEMS, GOLD, MITHRIL, - - WOOD_AND_ORE = 127, // special case for town bonus resource - INVALID = -1 -}; - -using GameResID = Identifier; - //class to be representing a vector of resource class ResourceSet { diff --git a/lib/StringConstants.h b/lib/StringConstants.h index ff0facbd8..7a8013330 100644 --- a/lib/StringConstants.h +++ b/lib/StringConstants.h @@ -68,7 +68,7 @@ namespace EBuildingType }; } -namespace ETownType +namespace NFaction { const std::string names [GameConstants::F_NUMBER] = { diff --git a/lib/gameState/CGameState.cpp b/lib/gameState/CGameState.cpp index 54342be77..1fd9dfa82 100644 --- a/lib/gameState/CGameState.cpp +++ b/lib/gameState/CGameState.cpp @@ -697,7 +697,7 @@ void CGameState::initRandomFactionsForPlayers() logGlobal->debug("\tPicking random factions for players"); for(auto & elem : scenarioOps->playerInfos) { - if(elem.second.castle==-1) + if(elem.second.castle==FactionID::RANDOM) { auto randomID = getRandomGenerator().nextInt((int)map->players[elem.first.getNum()].allowedFactions.size() - 1); auto iter = map->players[elem.first.getNum()].allowedFactions.begin(); diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index d54f2f657..0472e809a 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -516,7 +516,7 @@ void CGTownInstance::newTurn(CRandomGenerator & rand) const std::vector nativeCrits; //slots for(const auto & elem : Slots()) { - if (elem.second->type->getFaction() == subID) //native + if (elem.second->type->getFaction() == getFaction()) //native { nativeCrits.push_back(elem.first); //collect matching slots } diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index f5a46e999..b0d0434e6 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -914,7 +914,7 @@ void CGWitchHut::serializeJsonOptions(JsonSerializeFormat & handler) if(handler.saving) { - for(si32 i = 0; i < skillCount; ++i) + for(SecondarySkill i(0); i < SecondarySkill(skillCount); ++i) if(vstd::contains(allowedAbilities, i)) temp[i] = true; } diff --git a/lib/mapping/MapFormatJson.cpp b/lib/mapping/MapFormatJson.cpp index 0b2eed219..e1dd3ff3c 100644 --- a/lib/mapping/MapFormatJson.cpp +++ b/lib/mapping/MapFormatJson.cpp @@ -396,7 +396,7 @@ void CMapFormatJson::serializeAllowedFactions(JsonSerializeFormat & handler, std if(handler.saving) { for(auto faction : VLC->townh->objects) - if(faction->town && vstd::contains(value, faction->getIndex())) + if(faction->town && vstd::contains(value, faction->getId())) temp[static_cast(faction->getIndex())] = true; } diff --git a/lib/mapping/MapReaderH3M.cpp b/lib/mapping/MapReaderH3M.cpp index feba9e023..7827f25c4 100644 --- a/lib/mapping/MapReaderH3M.cpp +++ b/lib/mapping/MapReaderH3M.cpp @@ -161,7 +161,7 @@ RiverId MapReaderH3M::readRiver() SecondarySkill MapReaderH3M::readSkill() { SecondarySkill result(readUInt8()); - assert(result < features.skillsCount); + assert(result.getNum() < features.skillsCount); return remapIdentifier(result);; } diff --git a/lib/rmg/CMapGenOptions.cpp b/lib/rmg/CMapGenOptions.cpp index 3201943eb..1a0265327 100644 --- a/lib/rmg/CMapGenOptions.cpp +++ b/lib/rmg/CMapGenOptions.cpp @@ -506,7 +506,7 @@ const CRmgTemplate * CMapGenOptions::getPossibleTemplate(CRandomGenerator & rand return *RandomGeneratorUtil::nextItem(templates, rand); } -CMapGenOptions::CPlayerSettings::CPlayerSettings() : color(0), startingTown(RANDOM_TOWN), playerType(EPlayerType::AI), team(TeamID::NO_TEAM) +CMapGenOptions::CPlayerSettings::CPlayerSettings() : color(0), startingTown(FactionID::RANDOM), playerType(EPlayerType::AI), team(TeamID::NO_TEAM) { } diff --git a/lib/rmg/CMapGenOptions.h b/lib/rmg/CMapGenOptions.h index aa5683ede..2e25fd671 100644 --- a/lib/rmg/CMapGenOptions.h +++ b/lib/rmg/CMapGenOptions.h @@ -53,9 +53,6 @@ public: TeamID getTeam() const; void setTeam(const TeamID & value); - /// Constant for a random town selection. - static const si32 RANDOM_TOWN = -1; - private: PlayerColor color; si32 startingTown; diff --git a/lib/rmg/CMapGenerator.cpp b/lib/rmg/CMapGenerator.cpp index 8ce615a14..69527411f 100644 --- a/lib/rmg/CMapGenerator.cpp +++ b/lib/rmg/CMapGenerator.cpp @@ -174,7 +174,7 @@ std::string CMapGenerator::getMapDescription() const { ss << ", " << GameConstants::PLAYER_COLOR_NAMES[pSettings.getColor().getNum()] << " is human"; } - if(pSettings.getStartingTown() != CMapGenOptions::CPlayerSettings::RANDOM_TOWN) + if(pSettings.getStartingTown() != FactionID::RANDOM) { ss << ", " << GameConstants::PLAYER_COLOR_NAMES[pSettings.getColor().getNum()] << " town choice is " << (*VLC->townh)[pSettings.getStartingTown()]->getNameTranslated(); diff --git a/lib/rmg/CRmgTemplate.cpp b/lib/rmg/CRmgTemplate.cpp index 8c4580230..b8032bc01 100644 --- a/lib/rmg/CRmgTemplate.cpp +++ b/lib/rmg/CRmgTemplate.cpp @@ -374,15 +374,15 @@ void ZoneOptions::serializeJson(JsonSerializeFormat & handler) if(terrainTypeLikeZone == NO_ZONE) { - handler.serializeIdArray("terrainTypes", terrainTypes, std::set()); - handler.serializeIdArray("bannedTerrains", bannedTerrains, std::set()); + handler.serializeIdArray("terrainTypes", terrainTypes); + handler.serializeIdArray("bannedTerrains", bannedTerrains); } handler.serializeBool("townsAreSameType", townsAreSameType, false); - handler.serializeIdArray("allowedMonsters", monsterTypes, std::set()); - handler.serializeIdArray("bannedMonsters", bannedMonsters, std::set()); - handler.serializeIdArray("allowedTowns", townTypes, std::set()); - handler.serializeIdArray("bannedTowns", bannedTownTypes, std::set()); + handler.serializeIdArray("allowedMonsters", monsterTypes); + handler.serializeIdArray("bannedMonsters", bannedMonsters); + handler.serializeIdArray("allowedTowns", townTypes); + handler.serializeIdArray("bannedTowns", bannedTownTypes); { //TODO: add support for std::map to serializeEnum diff --git a/lib/rmg/CZonePlacer.cpp b/lib/rmg/CZonePlacer.cpp index abfb73421..07c56688f 100644 --- a/lib/rmg/CZonePlacer.cpp +++ b/lib/rmg/CZonePlacer.cpp @@ -442,13 +442,13 @@ void CZonePlacer::prepareZones(TZoneMap &zones, TZoneVector &zonesVector, const { auto player = PlayerColor(*owner - 1); auto playerSettings = map.getMapGenOptions().getPlayersSettings(); - si32 faction = CMapGenOptions::CPlayerSettings::RANDOM_TOWN; + si32 faction = FactionID::RANDOM; if (vstd::contains(playerSettings, player)) faction = playerSettings[player].getStartingTown(); else logGlobal->error("Can't find info for player %d (starting zone)", player.getNum()); - if (faction == CMapGenOptions::CPlayerSettings::RANDOM_TOWN) //TODO: check this after a town has already been randomized + if (faction == FactionID::RANDOM) //TODO: check this after a town has already been randomized zonesToPlace.push_back(zone); else { diff --git a/lib/rmg/modificators/TownPlacer.cpp b/lib/rmg/modificators/TownPlacer.cpp index ecb12d7b6..1f046588e 100644 --- a/lib/rmg/modificators/TownPlacer.cpp +++ b/lib/rmg/modificators/TownPlacer.cpp @@ -60,7 +60,7 @@ void TownPlacer::placeTowns(ObjectManager & manager) player = PlayerColor(player_id); zone.setTownType(map.getMapGenOptions().getPlayersSettings().find(player)->second.getStartingTown()); - if(zone.getTownType() == CMapGenOptions::CPlayerSettings::RANDOM_TOWN) + if(zone.getTownType() == FactionID::RANDOM) zone.setTownType(getRandomTownType(true)); } else //no player - randomize town diff --git a/lib/spells/AdventureSpellMechanics.cpp b/lib/spells/AdventureSpellMechanics.cpp index 63126b36f..7802c4fa2 100644 --- a/lib/spells/AdventureSpellMechanics.cpp +++ b/lib/spells/AdventureSpellMechanics.cpp @@ -215,7 +215,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment { NewObject no; no.ID = Obj::BOAT; - no.subID = BoatId(EBoatId::NECROPOLIS); + no.subID = BoatId::NECROPOLIS; no.targetPos = summonPos; env->apply(&no); } diff --git a/lib/spells/CSpellHandler.cpp b/lib/spells/CSpellHandler.cpp index 22c6ef28e..acfc219b3 100644 --- a/lib/spells/CSpellHandler.cpp +++ b/lib/spells/CSpellHandler.cpp @@ -608,7 +608,7 @@ std::vector CSpellHandler::loadLegacyData() auto & chances = lineNode["gainChance"].Struct(); - for(const auto & name : ETownType::names) + for(const auto & name : NFaction::names) chances[name].Integer() = static_cast(parser.readNumber()); auto AIVals = parser.readNumArray(GameConstants::SPELL_SCHOOL_LEVELS); diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp index d72f78d0c..10affe144 100644 --- a/server/CVCMIServer.cpp +++ b/server/CVCMIServer.cpp @@ -840,10 +840,10 @@ void CVCMIServer::optionNextCastle(PlayerColor player, int dir) auto & allowed = getPlayerInfo(player.getNum()).allowedFactions; const bool allowRandomTown = getPlayerInfo(player.getNum()).isFactionRandom; - if(cur == PlayerSettings::NONE) //no change + if(cur.getNum() == PlayerSettings::NONE) //no change return; - if(cur == PlayerSettings::RANDOM) //first/last available + if(cur.getNum() == PlayerSettings::RANDOM) //first/last available { if(dir > 0) cur = *allowed.begin(); //id of first town @@ -880,7 +880,7 @@ void CVCMIServer::optionNextCastle(PlayerColor player, int dir) { s.hero = PlayerSettings::RANDOM; } - if(cur < 0 && s.bonus == PlayerSettings::RESOURCE) + if(cur.getNum() < 0 && s.bonus == PlayerSettings::RESOURCE) s.bonus = PlayerSettings::RANDOM; } @@ -935,7 +935,7 @@ void CVCMIServer::setCampaignBonus(int bonusId) void CVCMIServer::optionNextHero(PlayerColor player, int dir) { PlayerSettings & s = si->playerInfos[player]; - if(s.castle < 0 || s.hero == PlayerSettings::NONE) + if(s.castle.getNum() < 0 || s.hero == PlayerSettings::NONE) return; if(s.hero == PlayerSettings::RANDOM) // first/last available @@ -1004,7 +1004,7 @@ void CVCMIServer::optionNextBonus(PlayerColor player, int dir) if(ret < PlayerSettings::RANDOM) ret = PlayerSettings::RESOURCE; - if(s.castle == PlayerSettings::RANDOM && ret == PlayerSettings::RESOURCE) //random castle - can't be resource + if(s.castle.getNum() == PlayerSettings::RANDOM && ret == PlayerSettings::RESOURCE) //random castle - can't be resource { if(dir < 0) ret = PlayerSettings::GOLD; diff --git a/test/entity/CCreatureTest.cpp b/test/entity/CCreatureTest.cpp index 11ddce729..78fc13bc8 100644 --- a/test/entity/CCreatureTest.cpp +++ b/test/entity/CCreatureTest.cpp @@ -99,7 +99,7 @@ TEST_F(CCreatureTest, JsonUpdate) EXPECT_EQ(subject->getFightValue(), 2420); EXPECT_EQ(subject->getLevel(), 6); - EXPECT_EQ(subject->getFaction(), 55); + EXPECT_EQ(subject->getFaction().getNum(), 55); EXPECT_TRUE(subject->isDoubleWide()); } diff --git a/test/mock/mock_Creature.h b/test/mock/mock_Creature.h index 2ce93f407..7df167aec 100644 --- a/test/mock/mock_Creature.h +++ b/test/mock/mock_Creature.h @@ -57,7 +57,7 @@ public: MOCK_CONST_METHOD1(getCost, int32_t(int32_t)); MOCK_CONST_METHOD0(isDoubleWide, bool()); - MOCK_CONST_METHOD1(getRecruitCost, int32_t(Identifier)); + MOCK_CONST_METHOD1(getRecruitCost, int32_t(GameResID)); MOCK_CONST_METHOD0(getFullRecruitCost, ResourceSet()); MOCK_CONST_METHOD0(hasUpgrades, bool()); };