瀏覽代碼

Feature: Opposite Side Limiter. Added: Old saves support.

Dmitry Orlov 4 年之前
父節點
當前提交
2a39c401b8

+ 14 - 0
lib/CCreatureHandler.cpp

@@ -392,6 +392,20 @@ void CCreature::fillWarMachine()
 	warMachine = ArtifactID::NONE; //this creature is not artifact
 }
 
+void CCreature::updateOppositeBonuses()
+{
+	auto & bonusList = getExportedBonusList();
+	for(auto & bonus : bonusList)
+	{
+		if(bonus->effectRange == Bonus::ONLY_ENEMY_ARMY //Opposite Side bonuses should not be exported from CREATURE node.
+			|| (bonus->propagator && bonus->propagator->getPropagatorType() == CBonusSystemNode::BATTLE))
+		{
+			bonus->effectRange == Bonus::ONLY_ENEMY_ARMY;
+			bonus->propagator.reset();
+		}
+	}
+}
+
 CCreatureHandler::CCreatureHandler()
 	: expAfterUpgrade(0)
 {

+ 5 - 0
lib/CCreatureHandler.h

@@ -223,12 +223,17 @@ public:
 		{
 			fillWarMachine();
 		}
+		if(version < 801 && !h.saving) // Opposite bonuses are introduced
+		{
+			updateOppositeBonuses();
+		}
 	}
 
 	CCreature();
 
 private:
 	void fillWarMachine();
+	void updateOppositeBonuses();
 };
 
 class DLL_LINKAGE CCreatureHandler : public CHandlerBase<CreatureID, Creature, CCreature, CreatureService>

+ 1 - 1
lib/CCreatureSet.h

@@ -102,7 +102,7 @@ public:
 
 private:
 	void copyOppositeBonusesFromCreature(const CCreature * creature);
-	STRONG_INLINE void removeOppositeBonuses();
+	inline void removeOppositeBonuses();
 };
 
 class DLL_LINKAGE CCommanderInstance : public CStackInstance

+ 54 - 8
lib/HeroBonus.cpp

@@ -833,7 +833,7 @@ std::shared_ptr<const Bonus> IBonusBearer::getBonus(const CSelector &selector) c
 
 const CStack * retrieveStackBattle(const CBonusSystemNode * node)
 {
-	switch (node->getNodeType())
+	switch(node->getNodeType())
 	{
 	case CBonusSystemNode::STACK_BATTLE:
 		return static_cast<const CStack*>(node);
@@ -844,7 +844,7 @@ const CStack * retrieveStackBattle(const CBonusSystemNode * node)
 
 const CStackInstance * retrieveStackInstance(const CBonusSystemNode * node)
 {
-	switch (node->getNodeType())
+	switch(node->getNodeType())
 	{
 	case CBonusSystemNode::STACK_INSTANCE:
 		return (static_cast<const CStackInstance *>(node));
@@ -857,15 +857,15 @@ const CStackInstance * retrieveStackInstance(const CBonusSystemNode * node)
 
 PlayerColor CBonusSystemNode::retrieveNodeOwner(const CBonusSystemNode * node)
 {
-	if (!node)
+	if(!node)
 		return PlayerColor::CANNOT_DETERMINE;
 
 	const CStack * stack = retrieveStackBattle(node);
-	if (stack)
+	if(stack)
 		return stack->owner;
 
 	const CStackInstance * csi = retrieveStackInstance(node);
-	if (csi && csi->armyObj)
+	if(csi && csi->armyObj)
 		return csi->armyObj->getOwner();
 
 	return PlayerColor::NEUTRAL;
@@ -1377,10 +1377,10 @@ void CBonusSystemNode::removedRedDescendant(CBonusSystemNode *descendant)
 	TNodes redParents;
 	getRedAncestors(redParents); //get all red parents recursively
 
-	for (auto parent : redParents)
+	for(auto parent : redParents)
 	{
-		for (auto b : parent->exportedBonuses)
-			if (b->propagator)
+		for(auto b : parent->exportedBonuses)
+			if(b->propagator)
 				descendant->unpropagateBonus(b);
 	}
 }
@@ -2336,6 +2336,52 @@ std::shared_ptr<Bonus> Bonus::addUpdater(TUpdaterPtr Updater)
 	return this->shared_from_this();
 }
 
+void Bonus::createOppositeLimiter()
+{
+	if(limiter)
+	{
+		if(!dynamic_cast<OppositeSideLimiter *>(limiter.get()))
+		{
+			logMod->error("Wrong Limiter will be ignored: The 'ONLY_ENEMY_ARMY' effectRange is only compatible with the 'OPPOSITE_SIDE' limiter.");
+			limiter.reset(new OppositeSideLimiter());
+		}
+	}
+	else
+	{
+		limiter = std::make_shared<OppositeSideLimiter>();
+	}
+}
+
+void Bonus::createBattlePropagator()
+{
+	if(propagator)
+	{
+		if(propagator->getPropagatorType() != CBonusSystemNode::BATTLE)
+		{
+			logMod->error("Wrong Propagator will be ignored: The 'ONLY_ENEMY_ARMY' effectRange is only compatible with the 'BATTLE_WIDE' propagator.");
+			propagator.reset(new CPropagatorNodeType(CBonusSystemNode::BATTLE));
+		}
+	}
+	else
+	{
+		propagator = std::make_shared<CPropagatorNodeType>(CBonusSystemNode::BATTLE);
+	}
+}
+
+void Bonus::updateOppositeBonuses()
+{
+	if(effectRange == Bonus::ONLY_ENEMY_ARMY)
+	{
+		createBattlePropagator();
+		createOppositeLimiter();
+	}
+	else if(limiter && dynamic_cast<OppositeSideLimiter *>(limiter.get()))
+	{
+		createBattlePropagator();
+		effectRange = Bonus::ONLY_ENEMY_ARMY;
+	}
+}
+
 IUpdater::~IUpdater()
 {
 }

+ 8 - 0
lib/HeroBonus.h

@@ -455,6 +455,10 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
 		{
 			h & updater;
 		}
+		if(version < 801 && !h.saving) //Opposite Side bonuses are introduced
+		{
+			updateOppositeBonuses();
+		}
 	}
 
 	template <typename Ptr>
@@ -522,6 +526,10 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
 	std::shared_ptr<Bonus> addLimiter(TLimiterPtr Limiter); //returns this for convenient chain-calls
 	std::shared_ptr<Bonus> addPropagator(TPropagatorPtr Propagator); //returns this for convenient chain-calls
 	std::shared_ptr<Bonus> addUpdater(TUpdaterPtr Updater); //returns this for convenient chain-calls
+
+	inline void createOppositeLimiter();
+	inline void createBattlePropagator();
+	void updateOppositeBonuses();
 };
 
 DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus);

+ 1 - 42
lib/JsonNode.cpp

@@ -751,38 +751,6 @@ std::shared_ptr<Bonus> JsonUtils::parseBuildingBonus(const JsonNode &ability, Bu
 	return b;
 }
 
-inline void createOppositeLimiter(Bonus * b)
-{
-	if(b->limiter)
-	{
-		if(!dynamic_cast<OppositeSideLimiter *>(b->limiter.get()))
-		{
-			logMod->error("Wrong Limiter will be ignored: The 'ONLY_ENEMY_ARMY' effectRange is only compatible with the 'OPPOSITE_SIDE' limiter.");
-			b->limiter.reset(new OppositeSideLimiter());
-		}
-	}
-	else
-	{
-		b->limiter = std::make_shared<OppositeSideLimiter>();
-	}
-}
-
-inline void createBattlePropagator(Bonus * b)
-{
-	if(b->propagator)
-	{
-		if(b->propagator->getPropagatorType() != CBonusSystemNode::BATTLE)
-		{
-			logMod->error("Wrong Propagator will be ignored: The 'ONLY_ENEMY_ARMY' effectRange is only compatible with the 'BATTLE_WIDE' propagator.");
-			b->propagator.reset(new CPropagatorNodeType(CBonusSystemNode::BATTLE));
-		}
-	}
-	else
-	{
-		b->propagator = std::make_shared<CPropagatorNodeType>(CBonusSystemNode::BATTLE);
-	}
-}
-
 bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
 {
 	const JsonNode *value;
@@ -878,16 +846,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
 			break;
 		}
 	}
-	if(b->effectRange == Bonus::ONLY_ENEMY_ARMY)
-	{
-		createBattlePropagator(b);
-		createOppositeLimiter(b);
-	}
-	else if(b->limiter && dynamic_cast<OppositeSideLimiter *>(b->limiter.get()))
-	{
-		createBattlePropagator(b);
-		b->effectRange = Bonus::ONLY_ENEMY_ARMY;
-	}
+	b->updateOppositeBonuses();
 	return true;
 }
 

+ 2 - 2
lib/mapObjects/CGHeroInstance.cpp

@@ -1089,9 +1089,9 @@ CBonusSystemNode * CGHeroInstance::whereShouldBeAttachedOnSiege(CGameState * gs)
 
 CBonusSystemNode * CGHeroInstance::whereShouldBeAttached(CGameState * gs)
 {
-	if (visitedTown)
+	if(visitedTown)
 	{
-		if (inTownGarrison)
+		if(inTownGarrison)
 			return visitedTown;
 		else
 			return &visitedTown->townAndVis;

+ 1 - 1
lib/mapObjects/CGTownInstance.h

@@ -352,7 +352,7 @@ public:
 	void afterAddToMap(CMap * map) override;
 	static void reset();
 
-	STRONG_INLINE bool isBattleOutsideTown(const CGHeroInstance * defendingHero) const
+	inline bool isBattleOutsideTown(const CGHeroInstance * defendingHero) const
 	{
 		return defendingHero && garrisonHero && defendingHero != garrisonHero;
 	}

+ 1 - 1
lib/serializer/CSerializer.h

@@ -12,7 +12,7 @@
 #include "../ConstTransitivePtr.h"
 #include "../GameConstants.h"
 
-const ui32 SERIALIZATION_VERSION = 800;
+const ui32 SERIALIZATION_VERSION = 801;
 const ui32 MINIMAL_SERIALIZATION_VERSION = 753;
 const std::string SAVEGAME_MAGIC = "VCMISVG";
 

+ 2 - 2
server/CGameHandler.cpp

@@ -904,9 +904,9 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance * heroAttacker, con
 		garrisonSwapOnSiege(heroDefender->visitedTown->id); //return defending visitor from garrison to its rightful place
 	}
 	//give exp
-	if (battleResult.data->exp[0] && heroAttacker && battleResult.get()->winner == BattleSide::ATTACKER)
+	if(battleResult.data->exp[0] && heroAttacker && battleResult.get()->winner == BattleSide::ATTACKER)
 		changePrimSkill(heroAttacker, PrimarySkill::EXPERIENCE, battleResult.data->exp[0]);
-	else if (battleResult.data->exp[1] && heroDefender && battleResult.get()->winner == BattleSide::DEFENDER)
+	else if(battleResult.data->exp[1] && heroDefender && battleResult.get()->winner == BattleSide::DEFENDER)
 		changePrimSkill(heroDefender, PrimarySkill::EXPERIENCE, battleResult.data->exp[1]);
 
 	queries.popIfTop(battleQuery);