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
{
return owner;
return battle->battleGetOwner(this);
}
void CStack::getCasterName(MetaString & text) const

View File

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

View File

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

View File

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

View File

@ -652,10 +652,9 @@ std::vector<const CStack *> 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<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;
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;
}

View File

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