mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Rewrite Beneficial spell selection
This commit is contained in:
parent
b0df8172f9
commit
64dccfec80
@ -1891,93 +1891,126 @@ 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
|
||||||
for(const CSpell *spell : VLC->spellh->objects)
|
static const std::set<SpellID> allPossibleSpells =
|
||||||
{
|
{
|
||||||
if (spell->isPositive() && !spell->isRisingSpell()) //only positive and not rising
|
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;
|
||||||
|
|
||||||
|
auto getAliveEnemy = [=](const std::function<bool(const CStack * )> & pred)
|
||||||
|
{
|
||||||
|
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)
|
});
|
||||||
continue;
|
};
|
||||||
|
|
||||||
switch (spell->id)
|
for(const SpellID spellID : allPossibleSpells)
|
||||||
{
|
{
|
||||||
case SpellID::SHIELD:
|
if (subject->hasBonusFrom(Bonus::SPELL_EFFECT, spellID)
|
||||||
case SpellID::FIRE_SHIELD: // not if all enemy units are shooters
|
//TODO: this ability has special limitations
|
||||||
{
|
|| battleCanCastThisSpellHere(subject->owner, spellID.toSpell(), ECastingMode::CREATURE_ACTIVE_CASTING, subject->position) != ESpellCastProblem::OK)
|
||||||
auto walker = getStackIf([&](const CStack *stack) //look for enemy, non-shooting stack
|
continue;
|
||||||
{
|
|
||||||
return stack->owner != subject->owner && !stack->shots;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!walker)
|
switch (spellID)
|
||||||
continue;
|
{
|
||||||
}
|
case SpellID::SHIELD:
|
||||||
break;
|
case SpellID::FIRE_SHIELD: // not if all enemy units are shooters
|
||||||
case SpellID::AIR_SHIELD: //only against active shooters
|
{
|
||||||
|
auto walker = getAliveEnemy([&](const CStack * stack) //look for enemy, non-shooting stack
|
||||||
{
|
{
|
||||||
|
return !stack->shots;
|
||||||
|
});
|
||||||
|
|
||||||
auto shooter = getStackIf([&](const CStack *stack) //look for enemy, non-shooting stack
|
if (!walker)
|
||||||
{
|
continue;
|
||||||
return stack->owner != subject->owner && stack->hasBonusOfType(Bonus::SHOOTER) && stack->shots;
|
|
||||||
});
|
|
||||||
if (!shooter)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SpellID::ANTI_MAGIC:
|
|
||||||
case SpellID::MAGIC_MIRROR:
|
|
||||||
{
|
|
||||||
if (!battleHasHero(subject->attackerOwned)) //only if there is enemy hero
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SpellID::CURE: //only damaged units - what about affected by curse?
|
|
||||||
{
|
|
||||||
if (subject->firstHPleft >= subject->MaxHealth())
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SpellID::BLOODLUST:
|
|
||||||
{
|
|
||||||
if (subject->shots) //if can shoot - only if enemy uits are adjacent
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SpellID::PRECISION:
|
|
||||||
{
|
|
||||||
if (!(subject->hasBonusOfType(Bonus::SHOOTER) && subject->shots))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SpellID::SLAYER://only if monsters are present
|
|
||||||
{
|
|
||||||
auto kingMonster = getStackIf([&](const CStack *stack) -> bool //look for enemy, non-shooting stack
|
|
||||||
{
|
|
||||||
const auto isKing = Selector::type(Bonus::KING1)
|
|
||||||
.Or(Selector::type(Bonus::KING2))
|
|
||||||
.Or(Selector::type(Bonus::KING3));
|
|
||||||
|
|
||||||
return stack->owner != subject->owner && stack->hasBonus(isKing);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!kingMonster)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SpellID::TELEPORT: //issue 1928
|
|
||||||
case SpellID::CLONE: //not allowed
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
possibleSpells.push_back(spell->id);
|
break;
|
||||||
|
case SpellID::AIR_SHIELD: //only against active shooters
|
||||||
|
{
|
||||||
|
auto shooter = getAliveEnemy([&](const CStack * stack) //look for enemy, non-shooting stack
|
||||||
|
{
|
||||||
|
return stack->hasBonusOfType(Bonus::SHOOTER) && stack->shots;
|
||||||
|
});
|
||||||
|
if (!shooter)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SpellID::ANTI_MAGIC:
|
||||||
|
case SpellID::MAGIC_MIRROR:
|
||||||
|
case SpellID::PROTECTION_FROM_AIR:
|
||||||
|
case SpellID::PROTECTION_FROM_EARTH:
|
||||||
|
case SpellID::PROTECTION_FROM_FIRE:
|
||||||
|
case SpellID::PROTECTION_FROM_WATER:
|
||||||
|
{
|
||||||
|
const ui8 enemySide = (ui8)subject->attackerOwned;
|
||||||
|
//todo: only if enemy has spellbook
|
||||||
|
if (!battleHasHero(enemySide)) //only if there is enemy hero
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SpellID::CURE: //only damaged units
|
||||||
|
{
|
||||||
|
//do not cast on affected by debuffs
|
||||||
|
if (subject->firstHPleft >= subject->MaxHealth())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SpellID::BLOODLUST:
|
||||||
|
{
|
||||||
|
if (subject->shots) //if can shoot - only if enemy uits are adjacent
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SpellID::PRECISION:
|
||||||
|
{
|
||||||
|
if (!(subject->hasBonusOfType(Bonus::SHOOTER) && subject->shots))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SpellID::SLAYER://only if monsters are present
|
||||||
|
{
|
||||||
|
auto kingMonster = getAliveEnemy([&](const CStack *stack) -> bool //look for enemy, non-shooting stack
|
||||||
|
{
|
||||||
|
const auto isKing = Selector::type(Bonus::KING1)
|
||||||
|
.Or(Selector::type(Bonus::KING2))
|
||||||
|
.Or(Selector::type(Bonus::KING3));
|
||||||
|
|
||||||
|
return stack->hasBonus(isKing);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!kingMonster)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
beneficialSpells.push_back(spellID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!possibleSpells.empty())
|
if(!beneficialSpells.empty())
|
||||||
{
|
{
|
||||||
return *RandomGeneratorUtil::nextItem(possibleSpells, gs->getRandomGenerator());
|
return *RandomGeneratorUtil::nextItem(beneficialSpells, gs->getRandomGenerator());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user