From 2a39c401b8503759516a93c49dfa09d030002d13 Mon Sep 17 00:00:00 2001 From: Dmitry Orlov Date: Thu, 19 Aug 2021 01:45:28 +0300 Subject: [PATCH] Feature: Opposite Side Limiter. Added: Old saves support. --- lib/CCreatureHandler.cpp | 14 +++++++ lib/CCreatureHandler.h | 5 +++ lib/CCreatureSet.h | 2 +- lib/HeroBonus.cpp | 62 +++++++++++++++++++++++++++---- lib/HeroBonus.h | 8 ++++ lib/JsonNode.cpp | 43 +-------------------- lib/mapObjects/CGHeroInstance.cpp | 4 +- lib/mapObjects/CGTownInstance.h | 2 +- lib/serializer/CSerializer.h | 2 +- server/CGameHandler.cpp | 4 +- 10 files changed, 89 insertions(+), 57 deletions(-) diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index dad373cac..7f9170635 100644 --- a/lib/CCreatureHandler.cpp +++ b/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) { diff --git a/lib/CCreatureHandler.h b/lib/CCreatureHandler.h index dfdcd3e01..25c608ab9 100644 --- a/lib/CCreatureHandler.h +++ b/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 diff --git a/lib/CCreatureSet.h b/lib/CCreatureSet.h index a63e9cfe2..cc6557865 100644 --- a/lib/CCreatureSet.h +++ b/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 diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index 27d674269..4c6c99077 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -833,7 +833,7 @@ std::shared_ptr 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(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(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::addUpdater(TUpdaterPtr Updater) return this->shared_from_this(); } +void Bonus::createOppositeLimiter() +{ + if(limiter) + { + if(!dynamic_cast(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(); + } +} + +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(CBonusSystemNode::BATTLE); + } +} + +void Bonus::updateOppositeBonuses() +{ + if(effectRange == Bonus::ONLY_ENEMY_ARMY) + { + createBattlePropagator(); + createOppositeLimiter(); + } + else if(limiter && dynamic_cast(limiter.get())) + { + createBattlePropagator(); + effectRange = Bonus::ONLY_ENEMY_ARMY; + } +} + IUpdater::~IUpdater() { } diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index c5d9e7c74..55c5629e8 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -455,6 +455,10 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this { h & updater; } + if(version < 801 && !h.saving) //Opposite Side bonuses are introduced + { + updateOppositeBonuses(); + } } template @@ -522,6 +526,10 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this std::shared_ptr addLimiter(TLimiterPtr Limiter); //returns this for convenient chain-calls std::shared_ptr addPropagator(TPropagatorPtr Propagator); //returns this for convenient chain-calls std::shared_ptr 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); diff --git a/lib/JsonNode.cpp b/lib/JsonNode.cpp index 4b6ec3cde..d8a8dbd9a 100644 --- a/lib/JsonNode.cpp +++ b/lib/JsonNode.cpp @@ -751,38 +751,6 @@ std::shared_ptr JsonUtils::parseBuildingBonus(const JsonNode &ability, Bu return b; } -inline void createOppositeLimiter(Bonus * b) -{ - if(b->limiter) - { - if(!dynamic_cast(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(); - } -} - -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(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(b->limiter.get())) - { - createBattlePropagator(b); - b->effectRange = Bonus::ONLY_ENEMY_ARMY; - } + b->updateOppositeBonuses(); return true; } diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 428b532fc..d6810aec4 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/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; diff --git a/lib/mapObjects/CGTownInstance.h b/lib/mapObjects/CGTownInstance.h index be1d53a20..4338c5ed6 100644 --- a/lib/mapObjects/CGTownInstance.h +++ b/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; } diff --git a/lib/serializer/CSerializer.h b/lib/serializer/CSerializer.h index 57fad1833..33579ad84 100644 --- a/lib/serializer/CSerializer.h +++ b/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"; diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 0b17ab18a..4df8e5bd0 100644 --- a/server/CGameHandler.cpp +++ b/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);