Ver código fonte

Improvements to bonus system node types / propagators

- Node type is now set on construction and never changes
- Added army propagator that also checks for TOWN and HERO
- Renamed existing propagators to be in sync with enumeration
Ivan Savenko 4 meses atrás
pai
commit
6ac57a7cfc

+ 2 - 2
AI/Nullkiller/AIUtility.cpp

@@ -271,7 +271,7 @@ bool compareArmyStrength(const CArmedInstance * a1, const CArmedInstance * a2)
 
 double getArtifactBonusRelevance(const CGHeroInstance * hero, const std::shared_ptr<Bonus> & bonus)
 {
-	if (bonus->propagator && bonus->limiter && bonus->propagator->getPropagatorType() == CBonusSystemNode::BATTLE)
+	if (bonus->propagator && bonus->limiter && bonus->propagator->getPropagatorType() == BonusNodeType::BATTLE_WIDE)
 	{
 		// assume that this is battle wide / other side propagator+limiter
 		// consider it as fully relevant since we don't know about future combat when equipping artifacts
@@ -526,7 +526,7 @@ int32_t getArtifactBonusScoreImpl(const std::shared_ptr<Bonus> & bonus)
 
 int32_t getArtifactBonusScore(const std::shared_ptr<Bonus> & bonus)
 {
-	if (bonus->propagator && bonus->propagator->getPropagatorType() == CBonusSystemNode::BATTLE)
+	if (bonus->propagator && bonus->propagator->getPropagatorType() == BonusNodeType::BATTLE_WIDE)
 	{
 		if (bonus->limiter)
 		{

+ 1 - 1
AI/Nullkiller/Analyzers/ArmyManager.cpp

@@ -172,7 +172,7 @@ class TemporaryArmy : public CArmedInstance
 public:
 	void armyChanged() override {}
 	TemporaryArmy()
-		:CArmedInstance(nullptr, true)
+		:CArmedInstance(nullptr, BonusNodeType::UNKNOWN, true)
 	{
 	}
 };

+ 1 - 1
AI/Nullkiller/Pathfinding/Actors.h

@@ -31,7 +31,7 @@ public:
 	bool needsLastStack() const override;
 	std::shared_ptr<SpecialAction> getActorAction() const;
 
-	HeroExchangeArmy(): CArmedInstance(nullptr, true), requireBuyArmy(false) {}
+	HeroExchangeArmy(): CArmedInstance(nullptr, BonusNodeType::UNKNOWN, true), requireBuyArmy(false) {}
 };
 
 struct ExchangeResult

+ 1 - 1
lib/CCreatureHandler.cpp

@@ -313,8 +313,8 @@ si32 CCreature::maxAmount(const TResources &res) const //how many creatures can
 }
 
 CCreature::CCreature()
+	:CBonusSystemNode(BonusNodeType::CREATURE)
 {
-	setNodeType(CBonusSystemNode::CREATURE);
 	fightValue = AIValue = growth = hordeGrowth = ammMin = ammMax = 0;
 }
 

+ 9 - 8
lib/CCreatureSet.cpp

@@ -707,20 +707,22 @@ void CCreatureSet::serializeJson(JsonSerializeFormat & handler, const std::strin
 	}
 }
 
-CStackInstance::CStackInstance(IGameInfoCallback *cb, bool isHypothetic)
-	: CBonusSystemNode(isHypothetic)
+CStackInstance::CStackInstance(IGameInfoCallback *cb)
+	: CStackInstance(cb, BonusNodeType::STACK_INSTANCE, false)
+{}
+
+CStackInstance::CStackInstance(IGameInfoCallback *cb, BonusNodeType nodeType, bool isHypothetic)
+	: CBonusSystemNode(nodeType, isHypothetic)
 	, CStackBasicDescriptor(nullptr, 0)
 	, CArtifactSet(cb)
 	, GameCallbackHolder(cb)
 	, nativeTerrain(this, Selector::type()(BonusType::TERRAIN_NATIVE))
 	, initiative(this, Selector::type()(BonusType::STACKS_SPEED))
 	, totalExperience(0)
-{
-	setNodeType(STACK_INSTANCE);
-}
+{}
 
 CStackInstance::CStackInstance(IGameInfoCallback *cb, const CreatureID & id, TQuantity Count, bool isHypothetic)
-	: CStackInstance(cb, false)
+	: CStackInstance(cb, BonusNodeType::STACK_INSTANCE, false)
 {
 	setType(id);
 	setCount(Count);
@@ -1040,14 +1042,13 @@ CCommanderInstance::CCommanderInstance(IGameInfoCallback *cb)
 {}
 
 CCommanderInstance::CCommanderInstance(IGameInfoCallback *cb, const CreatureID & id)
-	: CStackInstance(cb)
+	: CStackInstance(cb, BonusNodeType::COMMANDER, false)
 	, name("Commando")
 {
 	alive = true;
 	level = 1;
 	setCount(1);
 	setType(nullptr);
-	setNodeType (CBonusSystemNode::COMMANDER);
 	secondarySkills.resize (ECommander::SPELL_POWER + 1);
 	setType(id);
 	//TODO - parse them

+ 2 - 1
lib/CCreatureSet.h

@@ -146,7 +146,8 @@ public:
 	virtual int getLevel() const; //different for regular stack and commander
 	CreatureID getCreatureID() const; //-1 if not available
 	std::string getName() const; //plural or singular
-	CStackInstance(IGameInfoCallback *cb, bool isHypothetic	= false);
+	CStackInstance(IGameInfoCallback *cb);
+	CStackInstance(IGameInfoCallback *cb, BonusNodeType nodeType, bool isHypothetic = false);
 	CStackInstance(IGameInfoCallback *cb, const CreatureID & id, TQuantity count, bool isHypothetic = false);
 	virtual ~CStackInstance() = default;
 

+ 1 - 1
lib/CPlayerState.cpp

@@ -22,7 +22,7 @@
 VCMI_LIB_NAMESPACE_BEGIN
 
 PlayerState::PlayerState(IGameInfoCallback *cb)
-	: CBonusSystemNode(PLAYER)
+	: CBonusSystemNode(BonusNodeType::PLAYER)
 	, GameCallbackHolder(cb)
 	, color(-1)
 	, human(false)

+ 4 - 4
lib/CStack.cpp

@@ -26,7 +26,7 @@ VCMI_LIB_NAMESPACE_BEGIN
 
 ///CStack
 CStack::CStack(const CStackInstance * Base, const PlayerColor & O, int I, BattleSide Side, const SlotID & S):
-	CBonusSystemNode(STACK_BATTLE),
+	CBonusSystemNode(BonusNodeType::STACK_BATTLE),
 	base(Base),
 	ID(I),
 	typeID(Base->getId()),
@@ -40,7 +40,7 @@ CStack::CStack(const CStackInstance * Base, const PlayerColor & O, int I, Battle
 }
 
 CStack::CStack():
-	CBonusSystemNode(STACK_BATTLE),
+	CBonusSystemNode(BonusNodeType::STACK_BATTLE),
 	owner(PlayerColor::NEUTRAL),
 	slot(SlotID(255)),
 	initialPosition(BattleHex())
@@ -48,7 +48,7 @@ CStack::CStack():
 }
 
 CStack::CStack(const CStackBasicDescriptor * stack, const PlayerColor & O, int I, BattleSide Side, const SlotID & S):
-	CBonusSystemNode(STACK_BATTLE),
+	CBonusSystemNode(BonusNodeType::STACK_BATTLE),
 	ID(I),
 	typeID(stack->getId()),
 	baseAmount(stack->getCount()),
@@ -155,7 +155,7 @@ const CGHeroInstance * CStack::getMyHero() const
 		return dynamic_cast<const CGHeroInstance *>(base->getArmy());
 	else //we are attached directly?
 		for(const CBonusSystemNode * n : getParentNodes())
-			if(n->getNodeType() == HERO)
+			if(n->getNodeType() == BonusNodeType::HERO)
 				return dynamic_cast<const CGHeroInstance *>(n);
 
 	return nullptr;

+ 2 - 2
lib/battle/BattleInfo.cpp

@@ -467,7 +467,8 @@ BattleInfo::BattleInfo(IGameInfoCallback *cb, const BattleLayout & layout):
 }
 
 BattleInfo::BattleInfo(IGameInfoCallback *cb)
-	:GameCallbackHolder(cb),
+	:CBonusSystemNode(BonusNodeType::BATTLE_WIDE),
+	GameCallbackHolder(cb),
 	sides({SideInBattle(cb), SideInBattle(cb)}),
 	layout(std::make_unique<BattleLayout>()),
 	round(-1),
@@ -477,7 +478,6 @@ BattleInfo::BattleInfo(IGameInfoCallback *cb)
 	tacticsSide(BattleSide::NONE),
 	tacticDistance(0)
 {
-	setNodeType(BATTLE);
 }
 
 BattleLayout BattleInfo::getLayout() const

+ 23 - 0
lib/bonuses/BonusEnum.h

@@ -276,6 +276,29 @@ enum class BonusValueType : uint8_t
 #undef BONUS_VALUE
 };
 
+enum class BonusNodeType
+{
+	NONE = -1,
+	UNKNOWN,
+	STACK_INSTANCE,
+	STACK_BATTLE,
+	ARMY,
+	ARTIFACT,
+	CREATURE,
+	ARTIFACT_INSTANCE,
+	HERO,
+	PLAYER,
+	TEAM,
+	TOWN_AND_VISITOR,
+	BATTLE_WIDE,
+	COMMANDER,
+	GLOBAL_EFFECTS,
+	BOAT,
+	TOWN
+};
+
+
+
 extern DLL_LINKAGE const std::map<std::string, BonusValueType> bonusValueMap;
 extern DLL_LINKAGE const std::map<std::string, BonusSource> bonusSourceMap;
 extern DLL_LINKAGE const std::map<std::string, BonusDuration::Type> bonusDurationMap;

+ 16 - 24
lib/bonuses/CBonusSystemNode.cpp

@@ -172,21 +172,17 @@ std::shared_ptr<Bonus> CBonusSystemNode::getUpdatedBonus(const std::shared_ptr<B
 	return updater->createUpdatedBonus(b, * this);
 }
 
-CBonusSystemNode::CBonusSystemNode(bool isHypotetic):
-	nodeType(UNKNOWN),
+CBonusSystemNode::CBonusSystemNode(BonusNodeType NodeType, bool isHypotetic):
+	nodeType(NodeType),
 	cachedLast(0),
 	nodeChanged(0),
 	isHypotheticNode(isHypotetic)
 {
 }
 
-CBonusSystemNode::CBonusSystemNode(ENodeTypes NodeType):
-	nodeType(NodeType),
-	cachedLast(0),
-	nodeChanged(0),
-	isHypotheticNode(false)
-{
-}
+CBonusSystemNode::CBonusSystemNode(BonusNodeType NodeType):
+	CBonusSystemNode(NodeType, false)
+{}
 
 CBonusSystemNode::~CBonusSystemNode()
 {
@@ -250,8 +246,8 @@ void CBonusSystemNode::detachFrom(CBonusSystemNode & parent)
 	}
 	else
 	{
-		logBonus->error("Error on Detach. Node %s (nodeType=%d) has not parent %s (nodeType=%d)"
-			, nodeShortInfo(), nodeType, parent.nodeShortInfo(), parent.nodeType);
+		logBonus->error("Error on Detach. Node %s (nodeType=%d) has not parent %s (nodeType=%d)",
+			nodeShortInfo(), static_cast<int>(nodeType), parent.nodeShortInfo(), static_cast<int>(parent.nodeType));
 	}
 
 	if(!isHypothetic())
@@ -260,8 +256,8 @@ void CBonusSystemNode::detachFrom(CBonusSystemNode & parent)
 			parent.children -= this;
 		else
 		{
-			logBonus->error("Error on Detach. Node %s (nodeType=%d) is not a child of %s (nodeType=%d)"
-							, nodeShortInfo(), nodeType, parent.nodeShortInfo(), parent.nodeType);
+			logBonus->error("Error on Detach. Node %s (nodeType=%d) is not a child of %s (nodeType=%d)",
+				nodeShortInfo(), static_cast<int>(nodeType), parent.nodeShortInfo(), static_cast<int>(parent.nodeType));
 		}
 	}
 	parent.nodeHasChanged();
@@ -284,8 +280,8 @@ void CBonusSystemNode::detachFromSource(const CBonusSystemNode & parent)
 	}
 	else
 	{
-		logBonus->error("Error on Detach. Node %s (nodeType=%d) has not parent %s (nodeType=%d)"
-			, nodeShortInfo(), nodeType, parent.nodeShortInfo(), parent.nodeType);
+		logBonus->error("Error on Detach. Node %s (nodeType=%d) has not parent %s (nodeType=%d)",
+			nodeShortInfo(), static_cast<int>(nodeType), parent.nodeShortInfo(), static_cast<int>(parent.nodeType));
 	}
 
 	nodeHasChanged();
@@ -361,9 +357,10 @@ bool CBonusSystemNode::actsAsBonusSourceOnly() const
 {
 	switch(nodeType)
 	{
-	case CREATURE:
-	case ARTIFACT:
-	case ARTIFACT_INSTANCE:
+	case BonusNodeType::CREATURE:
+	case BonusNodeType::ARTIFACT:
+	case BonusNodeType::ARTIFACT_INSTANCE:
+	case BonusNodeType::BOAT:
 		return true;
 	default:
 		return false;
@@ -549,7 +546,7 @@ void CBonusSystemNode::exportBonuses()
 		exportBonus(b);
 }
 
-CBonusSystemNode::ENodeTypes CBonusSystemNode::getNodeType() const
+BonusNodeType CBonusSystemNode::getNodeType() const
 {
 	return nodeType;
 }
@@ -559,11 +556,6 @@ const TCNodesVector& CBonusSystemNode::getParentNodes() const
 	return parentsToInherit;
 }
 
-void CBonusSystemNode::setNodeType(CBonusSystemNode::ENodeTypes type)
-{
-	nodeType = type;
-}
-
 BonusList & CBonusSystemNode::getExportedBonusList()
 {
 	return exportedBonuses;

+ 4 - 12
lib/bonuses/CBonusSystemNode.h

@@ -26,13 +26,6 @@ using TCNodesVector = std::vector<const CBonusSystemNode *>;
 class DLL_LINKAGE CBonusSystemNode : public virtual IBonusBearer, public virtual Serializeable, public boost::noncopyable
 {
 public:
-	enum ENodeTypes
-	{
-		NONE = -1, 
-		UNKNOWN, STACK_INSTANCE, STACK_BATTLE, SPECIALTY, ARTIFACT, CREATURE, ARTIFACT_INSTANCE, HERO, PLAYER, TEAM,
-		TOWN_AND_VISITOR, BATTLE, COMMANDER, GLOBAL_EFFECTS, ALL_CREATURES, TOWN
-	};
-
 	struct HashStringCompare {
 		static size_t hash(const std::string& data)
 		{
@@ -53,7 +46,7 @@ private:
 	TNodesVector parentsToPropagate; // we may attach our bonuses to them
 	TNodesVector children;
 
-	ENodeTypes nodeType;
+	BonusNodeType nodeType;
 	bool isHypotheticNode;
 
 	mutable BonusList cachedBonuses;
@@ -97,8 +90,8 @@ protected:
 	void exportBonuses();
 
 public:
-	explicit CBonusSystemNode(bool isHypotetic = false);
-	explicit CBonusSystemNode(ENodeTypes NodeType);
+	explicit CBonusSystemNode(BonusNodeType nodeType, bool isHypotetic);
+	explicit CBonusSystemNode(BonusNodeType nodeType);
 	virtual ~CBonusSystemNode();
 
 	TConstBonusListPtr getAllBonuses(const CSelector &selector, const std::string &cachingStr = "") const override;
@@ -130,8 +123,7 @@ public:
 
 	BonusList & getExportedBonusList();
 	const BonusList & getExportedBonusList() const;
-	CBonusSystemNode::ENodeTypes getNodeType() const;
-	void setNodeType(CBonusSystemNode::ENodeTypes type);
+	BonusNodeType getNodeType() const;
 	const TCNodesVector & getParentNodes() const;
 
 	void nodeHasChanged();

+ 9 - 9
lib/bonuses/Limiters.cpp

@@ -45,7 +45,7 @@ static const CStack * retrieveStackBattle(const CBonusSystemNode * node)
 {
 	switch(node->getNodeType())
 	{
-	case CBonusSystemNode::STACK_BATTLE:
+	case BonusNodeType::STACK_BATTLE:
 		return dynamic_cast<const CStack *>(node);
 	default:
 		return nullptr;
@@ -56,9 +56,9 @@ static const CStackInstance * retrieveStackInstance(const CBonusSystemNode * nod
 {
 	switch(node->getNodeType())
 	{
-	case CBonusSystemNode::STACK_INSTANCE:
+	case BonusNodeType::STACK_INSTANCE:
 		return (dynamic_cast<const CStackInstance *>(node));
-	case CBonusSystemNode::STACK_BATTLE:
+	case BonusNodeType::STACK_BATTLE:
 		return (dynamic_cast<const CStack *>(node))->base;
 	default:
 		return nullptr;
@@ -69,9 +69,9 @@ static const CCreature * retrieveCreature(const CBonusSystemNode *node)
 {
 	switch(node->getNodeType())
 	{
-	case CBonusSystemNode::CREATURE:
+	case BonusNodeType::CREATURE:
 		return (dynamic_cast<const CCreature *>(node));
-	case CBonusSystemNode::STACK_BATTLE:
+	case BonusNodeType::STACK_BATTLE:
 		return (dynamic_cast<const CStack *>(node))->unitType();
 	default:
 		const CStackInstance * csi = retrieveStackInstance(node);
@@ -262,7 +262,7 @@ CreatureTerrainLimiter::CreatureTerrainLimiter(TerrainId terrain):
 
 ILimiter::EDecision CreatureTerrainLimiter::limit(const BonusLimitationContext &context) const
 {
-	if (context.node.getNodeType() != CBonusSystemNode::STACK_BATTLE && context.node.getNodeType() != CBonusSystemNode::STACK_INSTANCE)
+	if (context.node.getNodeType() != BonusNodeType::STACK_BATTLE && context.node.getNodeType() != BonusNodeType::STACK_INSTANCE)
 		return ILimiter::EDecision::NOT_APPLICABLE;
 
 	if (terrainType == ETerrainId::NATIVE_TERRAIN)
@@ -277,7 +277,7 @@ ILimiter::EDecision CreatureTerrainLimiter::limit(const BonusLimitationContext &
 
 		// TODO: CStack and CStackInstance need some common base type that represents any stack
 		// Closest existing class is ACreature, however it is also used as base for CCreature, which is not a stack
-		if (context.node.getNodeType() == CBonusSystemNode::STACK_BATTLE)
+		if (context.node.getNodeType() == BonusNodeType::STACK_BATTLE)
 		{
 			const auto * unit = dynamic_cast<const CStack *>(&context.node);
 			auto unitNativeTerrain = unit->getFactionID().toEntity(LIBRARY)->getNativeTerrain();
@@ -294,7 +294,7 @@ ILimiter::EDecision CreatureTerrainLimiter::limit(const BonusLimitationContext &
 	}
 	else
 	{
-		if (context.node.getNodeType() == CBonusSystemNode::STACK_BATTLE)
+		if (context.node.getNodeType() == BonusNodeType::STACK_BATTLE)
 		{
 			const auto * unit = dynamic_cast<const CStack *>(&context.node);
 			if (unit->getCurrentTerrain() == terrainType)
@@ -462,7 +462,7 @@ ILimiter::EDecision RankRangeLimiter::limit(const BonusLimitationContext &contex
 	const CStackInstance * csi = retrieveStackInstance(&context.node);
 	if(csi)
 	{
-		if (csi->getNodeType() == CBonusSystemNode::COMMANDER) //no stack exp bonuses for commander creatures
+		if (csi->getNodeType() == BonusNodeType::COMMANDER) //no stack exp bonuses for commander creatures
 			return ILimiter::EDecision::DISCARD;
 		if (csi->getExpRank() > minRank && csi->getExpRank() < maxRank)
 			return ILimiter::EDecision::ACCEPT;

+ 26 - 12
lib/bonuses/Propagators.cpp

@@ -16,37 +16,51 @@ VCMI_LIB_NAMESPACE_BEGIN
 
 const std::map<std::string, TPropagatorPtr> bonusPropagatorMap =
 {
-	{"BATTLE_WIDE", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::BATTLE)},
-	{"VISITED_TOWN_AND_VISITOR", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::TOWN_AND_VISITOR)},
-	{"PLAYER_PROPAGATOR", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::PLAYER)},
-	{"HERO", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::HERO)},
-	{"TEAM_PROPAGATOR", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::TEAM)}, //untested
-	{"GLOBAL_EFFECT", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::GLOBAL_EFFECTS)}
-}; //untested
+	{"BATTLE_WIDE", std::make_shared<CPropagatorNodeType>(BonusNodeType::BATTLE_WIDE)},
+	{"TOWN_AND_VISITOR", std::make_shared<CPropagatorNodeType>(BonusNodeType::TOWN_AND_VISITOR)},
+	{"PLAYER", std::make_shared<CPropagatorNodeType>(BonusNodeType::PLAYER)},
+	{"HERO", std::make_shared<CPropagatorNodeType>(BonusNodeType::HERO)},
+	{"TOWN", std::make_shared<CPropagatorNodeType>(BonusNodeType::TOWN)},
+	{"ARMY", std::make_shared<CPropagatorNodeType>(BonusNodeType::ARMY)},
+	{"TEAM", std::make_shared<CPropagatorNodeType>(BonusNodeType::TEAM)},
+	{"GLOBAL_EFFECT", std::make_shared<CPropagatorNodeType>(BonusNodeType::GLOBAL_EFFECTS)},
+
+	// deprecated, for compatibility
+	{"VISITED_TOWN_AND_VISITOR", std::make_shared<CPropagatorNodeType>(BonusNodeType::TOWN_AND_VISITOR)},
+	{"PLAYER_PROPAGATOR", std::make_shared<CPropagatorNodeType>(BonusNodeType::PLAYER)},
+	{"TEAM_PROPAGATOR", std::make_shared<CPropagatorNodeType>(BonusNodeType::TEAM)},
+
+};
 
 bool IPropagator::shouldBeAttached(CBonusSystemNode *dest) const
 {
 	return false;
 }
 
-CBonusSystemNode::ENodeTypes IPropagator::getPropagatorType() const
+BonusNodeType IPropagator::getPropagatorType() const
 {
-	return CBonusSystemNode::ENodeTypes::NONE;
+	return BonusNodeType::NONE;
 }
 
-CPropagatorNodeType::CPropagatorNodeType(CBonusSystemNode::ENodeTypes NodeType)
+CPropagatorNodeType::CPropagatorNodeType(BonusNodeType NodeType)
 	: nodeType(NodeType)
 {
 }
 
-CBonusSystemNode::ENodeTypes CPropagatorNodeType::getPropagatorType() const
+BonusNodeType CPropagatorNodeType::getPropagatorType() const
 {
 	return nodeType;
 }
 
 bool CPropagatorNodeType::shouldBeAttached(CBonusSystemNode *dest) const
 {
-	return nodeType == dest->getNodeType();
+	if (nodeType == dest->getNodeType())
+		return true;
+
+	if (nodeType == BonusNodeType::ARMY)
+		return dest->getNodeType() == BonusNodeType::HERO || dest->getNodeType() == BonusNodeType::TOWN;
+
+	return false;
 }
 
 VCMI_LIB_NAMESPACE_END

+ 4 - 4
lib/bonuses/Propagators.h

@@ -23,7 +23,7 @@ class DLL_LINKAGE IPropagator : public Serializeable
 public:
 	virtual ~IPropagator() = default;
 	virtual bool shouldBeAttached(CBonusSystemNode *dest) const;
-	virtual CBonusSystemNode::ENodeTypes getPropagatorType() const;
+	virtual BonusNodeType getPropagatorType() const;
 
 	template <typename Handler> void serialize(Handler &h)
 	{}
@@ -31,12 +31,12 @@ public:
 
 class DLL_LINKAGE CPropagatorNodeType : public IPropagator
 {
-	CBonusSystemNode::ENodeTypes nodeType;
+	BonusNodeType nodeType;
 
 public:
-	CPropagatorNodeType(CBonusSystemNode::ENodeTypes NodeType = CBonusSystemNode::ENodeTypes::UNKNOWN);
+	CPropagatorNodeType(BonusNodeType NodeType = BonusNodeType::UNKNOWN);
 	bool shouldBeAttached(CBonusSystemNode *dest) const override;
-	CBonusSystemNode::ENodeTypes getPropagatorType() const override;
+	BonusNodeType getPropagatorType() const override;
 
 	template <typename Handler> void serialize(Handler &h)
 	{

+ 9 - 9
lib/bonuses/Updaters.cpp

@@ -41,7 +41,7 @@ GrowsWithLevelUpdater::GrowsWithLevelUpdater(int valPer20, int stepSize)
 
 std::shared_ptr<Bonus> GrowsWithLevelUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context) const
 {
-	if(context.getNodeType() == CBonusSystemNode::HERO)
+	if(context.getNodeType() == BonusNodeType::HERO)
 	{
 		int level = dynamic_cast<const CGHeroInstance &>(context).level;
 		int steps = stepSize ? level / stepSize : level;
@@ -74,7 +74,7 @@ JsonNode GrowsWithLevelUpdater::toJsonNode() const
 
 std::shared_ptr<Bonus> TimesHeroLevelUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context) const
 {
-	if(context.getNodeType() == CBonusSystemNode::HERO)
+	if(context.getNodeType() == BonusNodeType::HERO)
 	{
 		int level = dynamic_cast<const CGHeroInstance &>(context).level;
 		auto newBonus = std::make_shared<Bonus>(*b);
@@ -96,7 +96,7 @@ JsonNode TimesHeroLevelUpdater::toJsonNode() const
 
 std::shared_ptr<Bonus> TimesHeroLevelDivideStackLevelUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context) const
 {
-	if(context.getNodeType() == CBonusSystemNode::HERO)
+	if(context.getNodeType() == BonusNodeType::HERO)
 	{
 		auto newBonus = TimesHeroLevelUpdater::createUpdatedBonus(b, context);
 		newBonus->updater = divideStackLevel;
@@ -124,13 +124,13 @@ std::shared_ptr<Bonus> TimesStackSizeUpdater::apply(const std::shared_ptr<Bonus>
 
 std::shared_ptr<Bonus> TimesStackSizeUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context) const
 {
-	if(context.getNodeType() == CBonusSystemNode::STACK_INSTANCE || context.getNodeType() == CBonusSystemNode::COMMANDER)
+	if(context.getNodeType() == BonusNodeType::STACK_INSTANCE || context.getNodeType() == BonusNodeType::COMMANDER)
 	{
 		int count = dynamic_cast<const CStackInstance &>(context).getCount();
 		return apply(b, count);
 	}
 
-	if(context.getNodeType() == CBonusSystemNode::STACK_BATTLE)
+	if(context.getNodeType() == BonusNodeType::STACK_BATTLE)
 	{
 		const auto & stack = dynamic_cast<const CStack &>(context);
 		return apply(b, stack.getCount());
@@ -158,13 +158,13 @@ std::shared_ptr<Bonus> TimesStackLevelUpdater::apply(const std::shared_ptr<Bonus
 
 std::shared_ptr<Bonus> TimesStackLevelUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context) const
 {
-	if(context.getNodeType() == CBonusSystemNode::STACK_INSTANCE || context.getNodeType() == CBonusSystemNode::COMMANDER)
+	if(context.getNodeType() == BonusNodeType::STACK_INSTANCE || context.getNodeType() == BonusNodeType::COMMANDER)
 	{
 		int level = dynamic_cast<const CStackInstance &>(context).getLevel();
 		return apply(b, level);
 	}
 
-	if(context.getNodeType() == CBonusSystemNode::STACK_BATTLE)
+	if(context.getNodeType() == BonusNodeType::STACK_BATTLE)
 	{
 		const auto & stack = dynamic_cast<const CStack &>(context);
 		//update if stack doesn't have an instance (summons, war machines)
@@ -202,13 +202,13 @@ std::shared_ptr<Bonus> DivideStackLevelUpdater::apply(const std::shared_ptr<Bonu
 
 std::shared_ptr<Bonus> DivideStackLevelUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context) const
 {
-	if(context.getNodeType() == CBonusSystemNode::STACK_INSTANCE || context.getNodeType() == CBonusSystemNode::COMMANDER)
+	if(context.getNodeType() == BonusNodeType::STACK_INSTANCE || context.getNodeType() == BonusNodeType::COMMANDER)
 	{
 		int level = dynamic_cast<const CStackInstance &>(context).getLevel();
 		return apply(b, level);
 	}
 
-	if(context.getNodeType() == CBonusSystemNode::STACK_BATTLE)
+	if(context.getNodeType() == BonusNodeType::STACK_BATTLE)
 	{
 		const auto & stack = dynamic_cast<const CStack &>(context);
 		//update if stack doesn't have an instance (summons, war machines)

+ 2 - 2
lib/entities/artifact/CArtifact.cpp

@@ -293,10 +293,10 @@ bool CChargedArtifact::getRemoveOnDepletion() const
 }
 
 CArtifact::CArtifact()
-	: iconIndex(ArtifactID::NONE),
+	: CBonusSystemNode(BonusNodeType::ARTIFACT),
+	iconIndex(ArtifactID::NONE),
 	price(0)
 {
-	setNodeType(ARTIFACT);
 	possibleSlots[ArtBearer::HERO]; //we want to generate map entry even if it will be empty
 	possibleSlots[ArtBearer::CREATURE]; //we want to generate map entry even if it will be empty
 	possibleSlots[ArtBearer::COMMANDER];

+ 1 - 1
lib/entities/artifact/CArtifactInstance.cpp

@@ -224,7 +224,7 @@ CArtifactInstance::CArtifactInstance(IGameInfoCallback *cb, const CArtifact * ar
 }
 
 CArtifactInstance::CArtifactInstance(IGameInfoCallback *cb)
-	: CBonusSystemNode(ARTIFACT_INSTANCE)
+	: CBonusSystemNode(BonusNodeType::ARTIFACT_INSTANCE)
 	, CCombinedArtifactInstance(cb)
 {
 }

+ 2 - 2
lib/entities/faction/CTownHandler.cpp

@@ -251,10 +251,10 @@ void CTownHandler::loadBuildingBonuses(const JsonNode & source, BonusList & bonu
 			bonus->description.appendTextID(building->getNameTextID());
 
 		//JsonUtils::parseBuildingBonus produces UNKNOWN type propagator instead of empty.
-		assert(bonus->propagator == nullptr || bonus->propagator->getPropagatorType() != CBonusSystemNode::ENodeTypes::UNKNOWN);
+		assert(bonus->propagator == nullptr || bonus->propagator->getPropagatorType() != BonusNodeType::UNKNOWN);
 
 		if(bonus->propagator != nullptr
-			&& bonus->propagator->getPropagatorType() == CBonusSystemNode::ENodeTypes::UNKNOWN)
+			&& bonus->propagator->getPropagatorType() == BonusNodeType::UNKNOWN)
 				bonus->addPropagator(emptyPropagator());
 		building->addNewBonus(bonus, bonusList);
 	}

+ 3 - 4
lib/gameState/CGameState.cpp

@@ -152,9 +152,9 @@ int CGameState::getDate(Date mode) const
 }
 
 CGameState::CGameState()
+	:globalEffects(BonusNodeType::GLOBAL_EFFECTS)
 {
 	heroesPool = std::make_unique<TavernHeroesPool>(this);
-	globalEffects.setNodeType(CBonusSystemNode::GLOBAL_EFFECTS);
 }
 
 CGameState::~CGameState()
@@ -1596,9 +1596,8 @@ CGHeroInstance * CGameState::getUsedHero(const HeroTypeID & hid) const
 }
 
 TeamState::TeamState()
-{
-	setNodeType(TEAM);
-}
+	:CBonusSystemNode(BonusNodeType::TEAM)
+{}
 
 CArtifactInstance * CGameState::createScroll(const SpellID & spellId)
 {

+ 3 - 3
lib/mapObjects/CArmedInstance.cpp

@@ -42,13 +42,13 @@ void CArmedInstance::randomizeArmy(FactionID type)
 }
 
 CArmedInstance::CArmedInstance(IGameInfoCallback *cb)
-	:CArmedInstance(cb, false)
+	:CArmedInstance(cb, BonusNodeType::ARMY, false)
 {
 }
 
-CArmedInstance::CArmedInstance(IGameInfoCallback *cb, bool isHypothetic):
+CArmedInstance::CArmedInstance(IGameInfoCallback *cb, BonusNodeType nodeType, bool isHypothetic):
 	CGObjectInstance(cb),
-	CBonusSystemNode(isHypothetic),
+	CBonusSystemNode(nodeType, isHypothetic),
 	nonEvilAlignmentMix(this, Selector::type()(BonusType::NONEVIL_ALIGNMENT_MIX)), // Take Angelic Alliance troop-mixing freedom of non-evil units into account.
 	battle(nullptr)
 {

+ 1 - 1
lib/mapObjects/CArmedInstance.h

@@ -51,7 +51,7 @@ public:
 	//////////////////////////////////////////////////////////////////////////
 
 	CArmedInstance(IGameInfoCallback *cb);
-	CArmedInstance(IGameInfoCallback *cb, bool isHypothetic);
+	CArmedInstance(IGameInfoCallback *cb, BonusNodeType nodeType, bool isHypothetic);
 
 	PlayerColor getOwner() const override
 	{

+ 5 - 1
lib/mapObjects/CGDwelling.cpp

@@ -50,7 +50,11 @@ void CGDwellingRandomizationInfo::serializeJson(JsonSerializeFormat & handler)
 }
 
 CGDwelling::CGDwelling(IGameInfoCallback *cb):
-	CArmedInstance(cb)
+	CGDwelling(cb, BonusNodeType::ARMY)
+{}
+
+CGDwelling::CGDwelling(IGameInfoCallback *cb, BonusNodeType nodeType):
+	CArmedInstance(cb, nodeType, false)
 {}
 
 CGDwelling::~CGDwelling() = default;

+ 1 - 0
lib/mapObjects/CGDwelling.h

@@ -39,6 +39,7 @@ public:
 	std::optional<CGDwellingRandomizationInfo> randomizationInfo; //random dwelling options; not serialized
 	TCreaturesSet creatures; //creatures[level] -> <vector of alternative ids (base creature and upgrades, creatures amount>
 
+	CGDwelling(IGameInfoCallback *cb, BonusNodeType nodeType);
 	CGDwelling(IGameInfoCallback *cb);
 	~CGDwelling() override;
 

+ 1 - 2
lib/mapObjects/CGHeroInstance.cpp

@@ -244,7 +244,7 @@ int CGHeroInstance::movementPointsLimitCached(bool onLand, const TurnInfo * ti)
 }
 
 CGHeroInstance::CGHeroInstance(IGameInfoCallback * cb)
-	: CArmedInstance(cb),
+	: CArmedInstance(cb, BonusNodeType::HERO, false),
 	CArtifactSet(cb),
 	tacticFormationEnabled(false),
 	inTownGarrison(false),
@@ -259,7 +259,6 @@ CGHeroInstance::CGHeroInstance(IGameInfoCallback * cb)
 	turnInfoCache(std::make_unique<TurnInfoCache>(this)),
 	manaPerKnowledgeCached(this, Selector::type()(BonusType::MANA_PER_KNOWLEDGE_PERCENTAGE))
 {
-	setNodeType(HERO);
 	ID = Obj::HERO;
 	secSkills.emplace_back(SecondarySkill::NONE, -1);
 }

+ 2 - 7
lib/mapObjects/CGTownInstance.cpp

@@ -261,8 +261,9 @@ TownFortifications CGTownInstance::fortificationsLevel() const
 }
 
 CGTownInstance::CGTownInstance(IGameInfoCallback *cb):
-	CGDwelling(cb),
+	CGDwelling(cb, BonusNodeType::TOWN),
 	IMarket(cb),
+	townAndVis(BonusNodeType::TOWN_AND_VISITOR),
 	built(0),
 	destroyed(0),
 	identifier(0),
@@ -271,7 +272,6 @@ CGTownInstance::CGTownInstance(IGameInfoCallback *cb):
 	spellResearchAcceptedCounter(0),
 	spellResearchAllowed(true)
 {
-	setNodeType(CBonusSystemNode::TOWN);
 	attachTo(townAndVis);
 }
 
@@ -1209,11 +1209,6 @@ GrowthInfo::Entry::Entry(int _count, std::string fullDescription):
 {
 }
 
-CTownAndVisitingHero::CTownAndVisitingHero()
-{
-	setNodeType(TOWN_AND_VISITOR);
-}
-
 int GrowthInfo::totalGrowth() const
 {
 	int ret = 0;

+ 1 - 7
lib/mapObjects/CGTownInstance.h

@@ -26,12 +26,6 @@ struct DamageRange;
 template<typename ContainedClass>
 class LogicalExpression;
 
-class DLL_LINKAGE CTownAndVisitingHero : public CBonusSystemNode
-{
-public:
-	CTownAndVisitingHero();
-};
-
 struct DLL_LINKAGE GrowthInfo
 {
 	struct Entry
@@ -61,7 +55,7 @@ class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public I
 public:
 	enum EFortLevel {NONE = 0, FORT = 1, CITADEL = 2, CASTLE = 3};
 
-	CTownAndVisitingHero townAndVis;
+	CBonusSystemNode townAndVis;
 	si32 built; //how many buildings has been built this turn
 	si32 destroyed; //how many buildings has been destroyed this turn
 	ui32 identifier; //special identifier from h3m (only > RoE maps)

+ 5 - 0
lib/mapObjects/FlaggableMapObject.cpp

@@ -22,6 +22,11 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
+FlaggableMapObject::FlaggableMapObject(IGameInfoCallback *cb)
+	:CGObjectInstance(cb)
+	,CBonusSystemNode(BonusNodeType::UNKNOWN)
+{}
+
 const IOwnableObject * FlaggableMapObject::asOwnable() const
 {
 	return this;

+ 1 - 1
lib/mapObjects/FlaggableMapObject.h

@@ -25,7 +25,7 @@ class DLL_LINKAGE FlaggableMapObject final : public CGObjectInstance, public IOw
 	void initBonuses();
 
 public:
-	using CGObjectInstance::CGObjectInstance;
+	FlaggableMapObject(IGameInfoCallback *cb);
 
 	void onHeroVisit(IGameEventCallback & gameEvents, const CGHeroInstance * h) const override;
 	void initObj(IGameRandomizer & gameRandomizer) override;

+ 2 - 1
lib/mapObjects/MiscObjects.cpp

@@ -930,7 +930,7 @@ void CGGarrison::addAntimagicGarrisonBonus()
 	bonus->type = BonusType::BLOCK_ALL_MAGIC;
 	bonus->source = BonusSource::OBJECT_TYPE;
 	bonus->sid = BonusSourceID(this->ID);
-	bonus->propagator = std::make_shared<CPropagatorNodeType>(CBonusSystemNode::BATTLE);
+	bonus->propagator = std::make_shared<CPropagatorNodeType>(BonusNodeType::BATTLE_WIDE);
 	bonus->duration = BonusDuration::PERMANENT;
 	this->addNewBonus(bonus);
 }
@@ -987,6 +987,7 @@ void CGMagi::onHeroVisit(IGameEventCallback & gameEvents, const CGHeroInstance *
 
 CGBoat::CGBoat(IGameInfoCallback * cb)
 	: CGObjectInstance(cb)
+	, CBonusSystemNode(BonusNodeType::BOAT)
 {
 	direction = 4;
 	layer = EPathfindingLayer::SAIL;

+ 1 - 1
lib/serializer/RegisterTypes.h

@@ -86,7 +86,7 @@ void registerTypes(Serializer &s)
 	s.template registerType<CGUniversity>(23);
 	s.template registerType<CGHeroPlaceholder>(24);
 	s.template registerType<CArmedInstance>(25);
-	s.template registerType<CBonusSystemNode>(26);
+//	s.template registerType<CBonusSystemNode>(26);
 	s.template registerType<CCreatureSet>(27);
 	s.template registerType<CGHeroInstance>(28);
 	s.template registerType<CGDwelling>(30);