1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +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

View File

@ -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)
{

View File

@ -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>

View File

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

View File

@ -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()
{
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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";

View File

@ -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);