From f0713c1d3643bd71895a6c52290454fecfebf28b Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Sun, 9 Jul 2017 16:55:10 +0300 Subject: [PATCH] Better handling of HYPNOTISED stacks in case of spellcasting --- lib/CStack.cpp | 2 +- lib/battle/CBattleInfoEssentials.cpp | 11 ++++++++++- lib/battle/CBattleInfoEssentials.h | 1 + lib/spells/BattleSpellMechanics.cpp | 21 +++++++++++---------- lib/spells/CDefaultSpellMechanics.cpp | 25 ++++--------------------- lib/spells/CSpellHandler.cpp | 23 +++-------------------- 6 files changed, 30 insertions(+), 53 deletions(-) diff --git a/lib/CStack.cpp b/lib/CStack.cpp index 00d4e9e05..e376981ca 100644 --- a/lib/CStack.cpp +++ b/lib/CStack.cpp @@ -807,7 +807,7 @@ int CStack::getEffectValue(const CSpell * spell) const const PlayerColor CStack::getOwner() const { - return owner; + return battle->battleGetOwner(this); } void CStack::getCasterName(MetaString & text) const diff --git a/lib/battle/CBattleInfoEssentials.cpp b/lib/battle/CBattleInfoEssentials.cpp index 44befb406..c3edbbe7a 100644 --- a/lib/battle/CBattleInfoEssentials.cpp +++ b/lib/battle/CBattleInfoEssentials.cpp @@ -360,8 +360,17 @@ bool CBattleInfoEssentials::battleMatchOwner(const CStack * attacker, const CSta return true; else if(attacker == defender) return positivness; + else + return battleMatchOwner(battleGetOwner(attacker), defender, positivness); +} + +bool CBattleInfoEssentials::battleMatchOwner(const PlayerColor & attacker, const CStack * defender, const boost::logic::tribool positivness /* = false*/) const +{ + RETURN_IF_NOT_BATTLE(false); + if(boost::logic::indeterminate(positivness)) + return true; else if(defender->owner != battleGetOwner(defender)) return true; //mind controlled unit is attackable for both sides else - return (battleGetOwner(attacker) == battleGetOwner(defender)) == positivness; + return (attacker == battleGetOwner(defender)) == positivness; } diff --git a/lib/battle/CBattleInfoEssentials.h b/lib/battle/CBattleInfoEssentials.h index 5086318b8..0d8156a6c 100644 --- a/lib/battle/CBattleInfoEssentials.h +++ b/lib/battle/CBattleInfoEssentials.h @@ -101,4 +101,5 @@ public: ///check that stacks are controlled by same|other player(s) depending on positiveness ///mind control included bool battleMatchOwner(const CStack * attacker, const CStack * defender, const boost::logic::tribool positivness = false) const; + bool battleMatchOwner(const PlayerColor & attacker, const CStack * defender, const boost::logic::tribool positivness = false) const; }; diff --git a/lib/spells/BattleSpellMechanics.cpp b/lib/spells/BattleSpellMechanics.cpp index 0392a04c1..b40e6bd0d 100644 --- a/lib/spells/BattleSpellMechanics.cpp +++ b/lib/spells/BattleSpellMechanics.cpp @@ -915,22 +915,23 @@ SpecialRisingSpellMechanics::SpecialRisingSpellMechanics(const CSpell * s): ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const { - //find alive possible target - const CStack * stackToHeal = cb->getStackIf([ctx, this](const CStack * s) + auto mainFilter = [cb, ctx, this](const CStack * s) -> bool { - const bool ownerMatches = !ctx.ti.smart || s->owner == ctx.caster->getOwner(); - - return ownerMatches && s->isValidTarget(false) && s->coversPos(ctx.destination) && ESpellCastProblem::OK == owner->isImmuneByStack(ctx.caster, s); + const bool ownerMatches = !ctx.ti.smart || cb->battleMatchOwner(ctx.caster->getOwner(), s, owner->getPositiveness()); + return ownerMatches && s->coversPos(ctx.destination) && ESpellCastProblem::OK == owner->isImmuneByStack(ctx.caster, s); + }; + //find alive possible target + const CStack * stackToHeal = cb->getStackIf([mainFilter](const CStack * s) + { + return s->isValidTarget(false) && mainFilter(s); }); if(nullptr == stackToHeal) { //find dead possible target if there is no alive target - stackToHeal = cb->getStackIf([ctx, this](const CStack * s) + stackToHeal = cb->getStackIf([mainFilter](const CStack * s) { - const bool ownerMatches = !ctx.ti.smart || s->owner == ctx.caster->getOwner(); - - return ownerMatches && s->isValidTarget(true) && s->coversPos(ctx.destination) && ESpellCastProblem::OK == owner->isImmuneByStack(ctx.caster, s); + return s->isValidTarget(true) && mainFilter(s); }); //we have found dead target @@ -940,7 +941,7 @@ ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::canBeCast(cons { const CStack * other = cb->getStackIf([hex, stackToHeal](const CStack * s) { - return s->isValidTarget(false) && s->coversPos(hex) && s != stackToHeal; + return s->isValidTarget(true) && s->coversPos(hex) && s != stackToHeal; }); if(nullptr != other) return ESpellCastProblem::NO_APPROPRIATE_TARGET;//alive stack blocks resurrection diff --git a/lib/spells/CDefaultSpellMechanics.cpp b/lib/spells/CDefaultSpellMechanics.cpp index 1415d1398..b6662791d 100644 --- a/lib/spells/CDefaultSpellMechanics.cpp +++ b/lib/spells/CDefaultSpellMechanics.cpp @@ -652,10 +652,9 @@ std::vector DefaultSpellMechanics::calculateAffectedStacks(const auto mainFilter = [=](const CStack * s) { - const bool positiveToAlly = owner->isPositive() && s->owner == ctx.caster->getOwner(); - const bool negativeToEnemy = owner->isNegative() && s->owner != ctx.caster->getOwner(); + const bool ownerMatches = cb->battleMatchOwner(ctx.caster->getOwner(), s, owner->getPositiveness()); const bool validTarget = s->isValidTarget(!ctx.ti.onlyAlive); //todo: this should be handled by spell class - const bool positivenessFlag = !ctx.ti.smart || owner->isNeutral() || positiveToAlly || negativeToEnemy; + const bool positivenessFlag = !ctx.ti.smart || ownerMatches; return positivenessFlag && validTarget; }; @@ -719,28 +718,12 @@ ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::canBeCast(const CBat { std::vector affected = getAffectedStacks(cb, ctx); - //allow to cast spell if affects is at least one smart target + //allow to cast spell if it affects at least one smart target bool targetExists = false; for(const CStack * stack : affected) { - bool casterStack = stack->owner == ctx.caster->getOwner(); - - switch (owner->positiveness) - { - case CSpell::POSITIVE: - if(casterStack) - targetExists = true; - break; - case CSpell::NEUTRAL: - targetExists = true; - break; - case CSpell::NEGATIVE: - if(!casterStack) - targetExists = true; - break; - } - + targetExists = cb->battleMatchOwner(ctx.caster->getOwner(), stack, owner->getPositiveness()); if(targetExists) break; } diff --git a/lib/spells/CSpellHandler.cpp b/lib/spells/CSpellHandler.cpp index 9144ac663..b426d8866 100644 --- a/lib/spells/CSpellHandler.cpp +++ b/lib/spells/CSpellHandler.cpp @@ -219,26 +219,9 @@ ESpellCastProblem::ESpellCastProblem CSpell::canBeCast(const CBattleInfoCallback for(const CStack * stack : cb->battleGetAllStacks()) { - bool immune = !(stack->isValidTarget(!tinfo.onlyAlive) && ESpellCastProblem::OK == isImmuneByStack(caster, stack)); - bool casterStack = stack->owner == caster->getOwner(); - - if(!immune) - { - switch (positiveness) - { - case CSpell::POSITIVE: - if(casterStack) - targetExists = true; - break; - case CSpell::NEUTRAL: - targetExists = true; - break; - case CSpell::NEGATIVE: - if(!casterStack) - targetExists = true; - break; - } - } + const bool immune = !(stack->isValidTarget(!tinfo.onlyAlive) && ESpellCastProblem::OK == isImmuneByStack(caster, stack)); + const bool ownerMatches = cb->battleMatchOwner(caster->getOwner(), stack, getPositiveness()); + targetExists = !immune && ownerMatches; if(targetExists) break; }