@@ -753,6 +753,12 @@ namespace vstd
if(i < 0) return -i;
return i;
}
+
+ ///C++23
+ template< class Enum > constexpr std::underlying_type_t<Enum> to_underlying( Enum e ) noexcept
+ {
+ return static_cast<std::underlying_type_t<Enum>>(e);
+ }
using vstd::operator-=;
@@ -16,6 +16,7 @@ VCMI_LIB_NAMESPACE_BEGIN
class FactionID;
enum class ETerrainId;
+enum class EAlignment : uint8_t;
template<typename T> class Identifier;
class DLL_LINKAGE Faction : public EntityT<FactionID>
@@ -23,6 +24,7 @@ class DLL_LINKAGE Faction : public EntityT<FactionID>
public:
virtual bool hasTown() const = 0;
virtual Identifier<ETerrainId> getNativeTerrain() const = 0;
+ virtual EAlignment getAlignment() const = 0;
};
VCMI_LIB_NAMESPACE_END
@@ -256,7 +256,7 @@ bool CCreature::isDoubleWide() const
*/
bool CCreature::isGood () const
{
- return (*VLC->townh)[faction]->alignment == EAlignment::GOOD;
+ return VLC->factions()->getByIndex(faction)->getAlignment() == EAlignment::GOOD;
/**
@@ -265,7 +265,7 @@ bool CCreature::isGood () const
bool CCreature::isEvil () const
- return (*VLC->townh)[faction]->alignment == EAlignment::EVIL;
+ return VLC->factions()->getByIndex(faction)->getAlignment() == EAlignment::EVIL;
si32 CCreature::maxAmount(const TResources &res) const //how many creatures can be bought
@@ -147,9 +147,9 @@ bool CHeroClass::isMagicHero() const
return affinity == MAGIC;
-EAlignment::EAlignment CHeroClass::getAlignment() const
+EAlignment CHeroClass::getAlignment() const
- return ((*VLC->townh)[faction]->alignment);
+ return VLC->factions()->getByIndex(faction)->getAlignment();
int32_t CHeroClass::getIndex() const
@@ -196,7 +196,7 @@ public:
secSkillProbability[i] = 0;
- EAlignment::EAlignment getAlignment() const;
+ EAlignment getAlignment() const;
class DLL_LINKAGE CHeroClassHandler : public CHandlerBase<HeroClassID, HeroClass, CHeroClass, HeroClassService>
@@ -161,6 +161,11 @@ bool CFaction::hasTown() const
return town != nullptr;
+EAlignment CFaction::getAlignment() const
+{
+ return alignment;
+}
TerrainId CFaction::getNativeTerrain() const
return nativeTerrain;
@@ -1006,11 +1011,11 @@ CFaction * CTownHandler::loadFromJson(const std::string & scope, const JsonNode
faction->creatureBg120 = source["creatureBackground"]["120px"].String();
faction->creatureBg130 = source["creatureBackground"]["130px"].String();
- int alignment = vstd::find_pos(EAlignment::names, source["alignment"].String());
+ int alignment = vstd::find_pos(GameConstants::ALIGNMENT_NAMES, source["alignment"].String());
if (alignment == -1)
faction->alignment = EAlignment::NEUTRAL;
else
- faction->alignment = static_cast<EAlignment::EAlignment>(alignment);
+ faction->alignment = static_cast<EAlignment>(alignment);
auto preferUndergound = source["preferUndergroundPlacement"];
faction->preferUndergroundPlacement = preferUndergound.isNull() ? false : preferUndergound.Bool();
@@ -194,7 +194,7 @@ class DLL_LINKAGE CFaction : public Faction
TerrainId nativeTerrain;
- EAlignment::EAlignment alignment = EAlignment::NEUTRAL;
+ EAlignment alignment = EAlignment::NEUTRAL;
bool preferUndergroundPlacement = false;
CTown * town = nullptr; //NOTE: can be null
@@ -218,6 +218,7 @@ public:
bool hasTown() const override;
TerrainId getNativeTerrain() const override;
+ EAlignment getAlignment() const override;
void updateFrom(const JsonNode & data);
void serializeJson(JsonSerializeFormat & handler);
@@ -428,10 +428,7 @@ public:
ID_LIKE_OPERATORS(SecondarySkill, SecondarySkill::ESecondarySkill)
-namespace EAlignment
-{
- enum EAlignment { GOOD, EVIL, NEUTRAL };
-}
+enum class EAlignment : uint8_t { GOOD, EVIL, NEUTRAL };
namespace ETownType//deprecated
@@ -2401,12 +2401,7 @@ JsonNode CreatureFactionLimiter::toJsonNode() const
return root;
-CreatureAlignmentLimiter::CreatureAlignmentLimiter()
- : alignment(-1)
-
-CreatureAlignmentLimiter::CreatureAlignmentLimiter(si8 Alignment)
+CreatureAlignmentLimiter::CreatureAlignmentLimiter(EAlignment Alignment)
: alignment(Alignment)
@@ -2429,7 +2424,7 @@ ILimiter::EDecision CreatureAlignmentLimiter::limit(const BonusLimitationContext
std::string CreatureAlignmentLimiter::toString() const
boost::format fmt("CreatureAlignmentLimiter(alignment=%s)");
- fmt % EAlignment::names[alignment];
+ fmt % GameConstants::ALIGNMENT_NAMES[vstd::to_underlying(alignment)];
return fmt.str();
@@ -2438,7 +2433,7 @@ JsonNode CreatureAlignmentLimiter::toJsonNode() const
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
root["type"].String() = "CREATURE_ALIGNMENT_LIMITER";
- root["parameters"].Vector().push_back(JsonUtils::stringNode(EAlignment::names[alignment]));
+ root["parameters"].Vector().push_back(JsonUtils::stringNode(GameConstants::ALIGNMENT_NAMES[vstd::to_underlying(alignment)]));
@@ -1127,9 +1127,8 @@ public:
class DLL_LINKAGE CreatureAlignmentLimiter : public ILimiter //applies only to creatures of given alignment
- si8 alignment;
- CreatureAlignmentLimiter();
- CreatureAlignmentLimiter(si8 Alignment);
+ EAlignment alignment;
+ CreatureAlignmentLimiter(EAlignment Alignment = EAlignment::NEUTRAL);
EDecision limit(const BonusLimitationContext &context) const override;
std::string toString() const override;
@@ -743,11 +743,11 @@ std::shared_ptr<ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter)
else if(limiterType == "CREATURE_ALIGNMENT_LIMITER")
- int alignment = vstd::find_pos(EAlignment::names, parameters[0].String());
+ int alignment = vstd::find_pos(GameConstants::ALIGNMENT_NAMES, parameters[0].String());
if(alignment == -1)
logMod->error("Error: invalid alignment %s.", parameters[0].String());
- return std::make_shared<CreatureAlignmentLimiter>(alignment);
+ return std::make_shared<CreatureAlignmentLimiter>(static_cast<EAlignment>(alignment));
else if(limiterType == "CREATURE_FACTION_LIMITER")
@@ -25,11 +25,8 @@ namespace GameConstants
const std::string PLAYER_COLOR_NAMES [PlayerColor::PLAYER_LIMIT_I] = {
"red", "blue", "tan", "green", "orange", "purple", "teal", "pink"
- const std::string names [3] = {"good", "evil", "neutral"};
+ const std::string ALIGNMENT_NAMES [3] = {"good", "evil", "neutral"};
namespace PrimarySkill
@@ -93,7 +93,7 @@ void CArmedInstance::updateMoraleBonusFromArmy()
for(TFaction f : factions)
- if ((*VLC->townh)[f]->alignment != EAlignment::EVIL)
+ if (VLC->factions()->getByIndex(f)->getAlignment() != EAlignment::EVIL)
mixableFactions++;
if (mixableFactions > 0)
@@ -957,7 +957,7 @@ void CGHeroInstance::pushPrimSkill( PrimarySkill::PrimarySkill which, int val )
addNewBonus(std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::HERO_BASE_SKILL, val, id.getNum(), which));
-EAlignment::EAlignment CGHeroInstance::getAlignment() const
+EAlignment CGHeroInstance::getAlignment() const
return type->heroClass->getAlignment();
@@ -166,7 +166,7 @@ public:
bool spellbookContainsSpell(const SpellID & spell) const;
void removeSpellbook();
const std::set<SpellID> & getSpellsInSpellbook() const;
bool needsLastStack()const override;
ui32 getTileCost(const TerrainTile & dest, const TerrainTile & from, const TurnInfo * ti) const; //move cost - applying pathfinding skill, road and terrain modifiers. NOT includes diagonal move penalty, last move levelling