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:
parent
00bd1bd100
commit
f0713c1d36
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user