1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-04-04 22:14:25 +02:00

Rewrite Beneficial spell selection

This commit is contained in:
AlexVinS 2014-12-02 00:24:36 +03:00
parent b0df8172f9
commit 64dccfec80

View File

@ -1891,24 +1891,56 @@ std::set<const CStack*> CBattleInfoCallback:: batteAdjacentCreatures(const CStac
SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) const SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) const
{ {
RETURN_IF_NOT_BATTLE(SpellID::NONE); RETURN_IF_NOT_BATTLE(SpellID::NONE);
std::vector<SpellID> possibleSpells; //This is complete list. No spells from mods.
//todo: this should be Spellbook of caster Stack
static const std::set<SpellID> allPossibleSpells =
{
SpellID::AIR_SHIELD,
SpellID::ANTI_MAGIC,
SpellID::BLESS,
SpellID::BLOODLUST,
SpellID::COUNTERSTRIKE,
SpellID::CURE,
SpellID::FIRE_SHIELD,
SpellID::FORTUNE,
SpellID::HASTE,
SpellID::MAGIC_MIRROR,
SpellID::MIRTH,
SpellID::PRAYER,
SpellID::PRECISION,
SpellID::PROTECTION_FROM_AIR,
SpellID::PROTECTION_FROM_EARTH,
SpellID::PROTECTION_FROM_FIRE,
SpellID::PROTECTION_FROM_WATER,
SpellID::SHIELD,
SpellID::SLAYER,
SpellID::STONE_SKIN
};
std::vector<SpellID> beneficialSpells;
for(const CSpell *spell : VLC->spellh->objects) auto getAliveEnemy = [=](const std::function<bool(const CStack * )> & pred)
{ {
if (spell->isPositive() && !spell->isRisingSpell()) //only positive and not rising return getStackIf([=](const CStack * stack)
{ {
if (subject->hasBonusFrom(Bonus::SPELL_EFFECT, spell->id) return pred(stack) && stack->owner != subject->owner && stack->alive();
|| battleCanCastThisSpellHere(subject->owner, spell, ECastingMode::CREATURE_ACTIVE_CASTING, subject->position) != ESpellCastProblem::OK) });
};
for(const SpellID spellID : allPossibleSpells)
{
if (subject->hasBonusFrom(Bonus::SPELL_EFFECT, spellID)
//TODO: this ability has special limitations
|| battleCanCastThisSpellHere(subject->owner, spellID.toSpell(), ECastingMode::CREATURE_ACTIVE_CASTING, subject->position) != ESpellCastProblem::OK)
continue; continue;
switch (spell->id) switch (spellID)
{ {
case SpellID::SHIELD: case SpellID::SHIELD:
case SpellID::FIRE_SHIELD: // not if all enemy units are shooters case SpellID::FIRE_SHIELD: // not if all enemy units are shooters
{ {
auto walker = getStackIf([&](const CStack *stack) //look for enemy, non-shooting stack auto walker = getAliveEnemy([&](const CStack * stack) //look for enemy, non-shooting stack
{ {
return stack->owner != subject->owner && !stack->shots; return !stack->shots;
}); });
if (!walker) if (!walker)
@ -1917,10 +1949,9 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
break; break;
case SpellID::AIR_SHIELD: //only against active shooters case SpellID::AIR_SHIELD: //only against active shooters
{ {
auto shooter = getAliveEnemy([&](const CStack * stack) //look for enemy, non-shooting stack
auto shooter = getStackIf([&](const CStack *stack) //look for enemy, non-shooting stack
{ {
return stack->owner != subject->owner && stack->hasBonusOfType(Bonus::SHOOTER) && stack->shots; return stack->hasBonusOfType(Bonus::SHOOTER) && stack->shots;
}); });
if (!shooter) if (!shooter)
continue; continue;
@ -1928,13 +1959,20 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
break; break;
case SpellID::ANTI_MAGIC: case SpellID::ANTI_MAGIC:
case SpellID::MAGIC_MIRROR: case SpellID::MAGIC_MIRROR:
case SpellID::PROTECTION_FROM_AIR:
case SpellID::PROTECTION_FROM_EARTH:
case SpellID::PROTECTION_FROM_FIRE:
case SpellID::PROTECTION_FROM_WATER:
{ {
if (!battleHasHero(subject->attackerOwned)) //only if there is enemy hero const ui8 enemySide = (ui8)subject->attackerOwned;
//todo: only if enemy has spellbook
if (!battleHasHero(enemySide)) //only if there is enemy hero
continue; continue;
} }
break; break;
case SpellID::CURE: //only damaged units - what about affected by curse? case SpellID::CURE: //only damaged units
{ {
//do not cast on affected by debuffs
if (subject->firstHPleft >= subject->MaxHealth()) if (subject->firstHPleft >= subject->MaxHealth())
continue; continue;
} }
@ -1953,31 +1991,26 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
break; break;
case SpellID::SLAYER://only if monsters are present case SpellID::SLAYER://only if monsters are present
{ {
auto kingMonster = getStackIf([&](const CStack *stack) -> bool //look for enemy, non-shooting stack auto kingMonster = getAliveEnemy([&](const CStack *stack) -> bool //look for enemy, non-shooting stack
{ {
const auto isKing = Selector::type(Bonus::KING1) const auto isKing = Selector::type(Bonus::KING1)
.Or(Selector::type(Bonus::KING2)) .Or(Selector::type(Bonus::KING2))
.Or(Selector::type(Bonus::KING3)); .Or(Selector::type(Bonus::KING3));
return stack->owner != subject->owner && stack->hasBonus(isKing); return stack->hasBonus(isKing);
}); });
if (!kingMonster) if (!kingMonster)
continue; continue;
} }
break; break;
case SpellID::TELEPORT: //issue 1928
case SpellID::CLONE: //not allowed
continue;
break;
}
possibleSpells.push_back(spell->id);
} }
beneficialSpells.push_back(spellID);
} }
if(!possibleSpells.empty()) if(!beneficialSpells.empty())
{ {
return *RandomGeneratorUtil::nextItem(possibleSpells, gs->getRandomGenerator()); return *RandomGeneratorUtil::nextItem(beneficialSpells, gs->getRandomGenerator());
} }
else else
{ {