1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-04-25 12:14:46 +02:00

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

This commit is contained in:
Dmitry Orlov 2021-08-19 01:45:28 +03:00
parent 25d9ea1ddf
commit 2a39c401b8
10 changed files with 89 additions and 57 deletions

@ -392,6 +392,20 @@ void CCreature::fillWarMachine()
warMachine = ArtifactID::NONE; //this creature is not artifact 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() CCreatureHandler::CCreatureHandler()
: expAfterUpgrade(0) : expAfterUpgrade(0)
{ {

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

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

@ -833,7 +833,7 @@ std::shared_ptr<const Bonus> IBonusBearer::getBonus(const CSelector &selector) c
const CStack * retrieveStackBattle(const CBonusSystemNode * node) const CStack * retrieveStackBattle(const CBonusSystemNode * node)
{ {
switch (node->getNodeType()) switch(node->getNodeType())
{ {
case CBonusSystemNode::STACK_BATTLE: case CBonusSystemNode::STACK_BATTLE:
return static_cast<const CStack*>(node); return static_cast<const CStack*>(node);
@ -844,7 +844,7 @@ const CStack * retrieveStackBattle(const CBonusSystemNode * node)
const CStackInstance * retrieveStackInstance(const CBonusSystemNode * node) const CStackInstance * retrieveStackInstance(const CBonusSystemNode * node)
{ {
switch (node->getNodeType()) switch(node->getNodeType())
{ {
case CBonusSystemNode::STACK_INSTANCE: case CBonusSystemNode::STACK_INSTANCE:
return (static_cast<const CStackInstance *>(node)); return (static_cast<const CStackInstance *>(node));
@ -857,15 +857,15 @@ const CStackInstance * retrieveStackInstance(const CBonusSystemNode * node)
PlayerColor CBonusSystemNode::retrieveNodeOwner(const CBonusSystemNode * node) PlayerColor CBonusSystemNode::retrieveNodeOwner(const CBonusSystemNode * node)
{ {
if (!node) if(!node)
return PlayerColor::CANNOT_DETERMINE; return PlayerColor::CANNOT_DETERMINE;
const CStack * stack = retrieveStackBattle(node); const CStack * stack = retrieveStackBattle(node);
if (stack) if(stack)
return stack->owner; return stack->owner;
const CStackInstance * csi = retrieveStackInstance(node); const CStackInstance * csi = retrieveStackInstance(node);
if (csi && csi->armyObj) if(csi && csi->armyObj)
return csi->armyObj->getOwner(); return csi->armyObj->getOwner();
return PlayerColor::NEUTRAL; return PlayerColor::NEUTRAL;
@ -1377,10 +1377,10 @@ void CBonusSystemNode::removedRedDescendant(CBonusSystemNode *descendant)
TNodes redParents; TNodes redParents;
getRedAncestors(redParents); //get all red parents recursively getRedAncestors(redParents); //get all red parents recursively
for (auto parent : redParents) for(auto parent : redParents)
{ {
for (auto b : parent->exportedBonuses) for(auto b : parent->exportedBonuses)
if (b->propagator) if(b->propagator)
descendant->unpropagateBonus(b); descendant->unpropagateBonus(b);
} }
} }
@ -2336,6 +2336,52 @@ std::shared_ptr<Bonus> Bonus::addUpdater(TUpdaterPtr Updater)
return this->shared_from_this(); 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() IUpdater::~IUpdater()
{ {
} }

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

@ -751,38 +751,6 @@ std::shared_ptr<Bonus> JsonUtils::parseBuildingBonus(const JsonNode &ability, Bu
return b; 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) bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
{ {
const JsonNode *value; const JsonNode *value;
@ -878,16 +846,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
break; break;
} }
} }
if(b->effectRange == Bonus::ONLY_ENEMY_ARMY) b->updateOppositeBonuses();
{
createBattlePropagator(b);
createOppositeLimiter(b);
}
else if(b->limiter && dynamic_cast<OppositeSideLimiter *>(b->limiter.get()))
{
createBattlePropagator(b);
b->effectRange = Bonus::ONLY_ENEMY_ARMY;
}
return true; return true;
} }

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

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

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

@ -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 garrisonSwapOnSiege(heroDefender->visitedTown->id); //return defending visitor from garrison to its rightful place
} }
//give exp //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]); 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]); changePrimSkill(heroDefender, PrimarySkill::EXPERIENCE, battleResult.data->exp[1]);
queries.popIfTop(battleQuery); queries.popIfTop(battleQuery);