1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Better handling of HYPNOTISED stacks in case of spellcasting

This commit is contained in:
AlexVinS 2017-07-09 16:55:10 +03:00
parent 00bd1bd100
commit f0713c1d36
6 changed files with 30 additions and 53 deletions

View File

@ -807,7 +807,7 @@ int CStack::getEffectValue(const CSpell * spell) const
const PlayerColor CStack::getOwner() const const PlayerColor CStack::getOwner() const
{ {
return owner; return battle->battleGetOwner(this);
} }
void CStack::getCasterName(MetaString & text) const void CStack::getCasterName(MetaString & text) const

View File

@ -360,8 +360,17 @@ bool CBattleInfoEssentials::battleMatchOwner(const CStack * attacker, const CSta
return true; return true;
else if(attacker == defender) else if(attacker == defender)
return positivness; 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)) else if(defender->owner != battleGetOwner(defender))
return true; //mind controlled unit is attackable for both sides return true; //mind controlled unit is attackable for both sides
else else
return (battleGetOwner(attacker) == battleGetOwner(defender)) == positivness; return (attacker == battleGetOwner(defender)) == positivness;
} }

View File

@ -101,4 +101,5 @@ public:
///check that stacks are controlled by same|other player(s) depending on positiveness ///check that stacks are controlled by same|other player(s) depending on positiveness
///mind control included ///mind control included
bool battleMatchOwner(const CStack * attacker, const CStack * defender, const boost::logic::tribool positivness = false) const; 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;
}; };

View File

@ -915,22 +915,23 @@ SpecialRisingSpellMechanics::SpecialRisingSpellMechanics(const CSpell * s):
ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const
{ {
//find alive possible target auto mainFilter = [cb, ctx, this](const CStack * s) -> bool
const CStack * stackToHeal = cb->getStackIf([ctx, this](const CStack * s)
{ {
const bool ownerMatches = !ctx.ti.smart || s->owner == ctx.caster->getOwner(); 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);
return ownerMatches && s->isValidTarget(false) && 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) if(nullptr == stackToHeal)
{ {
//find dead possible target if there is no alive target //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 s->isValidTarget(true) && mainFilter(s);
return ownerMatches && s->isValidTarget(true) && s->coversPos(ctx.destination) && ESpellCastProblem::OK == owner->isImmuneByStack(ctx.caster, s);
}); });
//we have found dead target //we have found dead target
@ -940,7 +941,7 @@ ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::canBeCast(cons
{ {
const CStack * other = cb->getStackIf([hex, stackToHeal](const CStack * s) 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) if(nullptr != other)
return ESpellCastProblem::NO_APPROPRIATE_TARGET;//alive stack blocks resurrection return ESpellCastProblem::NO_APPROPRIATE_TARGET;//alive stack blocks resurrection

View File

@ -652,10 +652,9 @@ std::vector<const CStack *> DefaultSpellMechanics::calculateAffectedStacks(const
auto mainFilter = [=](const CStack * s) auto mainFilter = [=](const CStack * s)
{ {
const bool positiveToAlly = owner->isPositive() && s->owner == ctx.caster->getOwner(); const bool ownerMatches = cb->battleMatchOwner(ctx.caster->getOwner(), s, owner->getPositiveness());
const bool negativeToEnemy = owner->isNegative() && s->owner != ctx.caster->getOwner();
const bool validTarget = s->isValidTarget(!ctx.ti.onlyAlive); //todo: this should be handled by spell class 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; return positivenessFlag && validTarget;
}; };
@ -719,28 +718,12 @@ ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::canBeCast(const CBat
{ {
std::vector<const CStack *> affected = getAffectedStacks(cb, ctx); std::vector<const CStack *> 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; bool targetExists = false;
for(const CStack * stack : affected) for(const CStack * stack : affected)
{ {
bool casterStack = stack->owner == ctx.caster->getOwner(); targetExists = cb->battleMatchOwner(ctx.caster->getOwner(), stack, owner->getPositiveness());
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;
}
if(targetExists) if(targetExists)
break; break;
} }

View File

@ -219,26 +219,9 @@ ESpellCastProblem::ESpellCastProblem CSpell::canBeCast(const CBattleInfoCallback
for(const CStack * stack : cb->battleGetAllStacks()) for(const CStack * stack : cb->battleGetAllStacks())
{ {
bool immune = !(stack->isValidTarget(!tinfo.onlyAlive) && ESpellCastProblem::OK == isImmuneByStack(caster, stack)); const bool immune = !(stack->isValidTarget(!tinfo.onlyAlive) && ESpellCastProblem::OK == isImmuneByStack(caster, stack));
bool casterStack = stack->owner == caster->getOwner(); const bool ownerMatches = cb->battleMatchOwner(caster->getOwner(), stack, getPositiveness());
targetExists = !immune && ownerMatches;
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;
}
}
if(targetExists) if(targetExists)
break; break;
} }