mirror of
https://github.com/vcmi/vcmi.git
synced 2025-06-02 23:07:36 +02:00
Fixed Genie spellcasting logic to account for spell immunities
This commit is contained in:
parent
822677af77
commit
85de3143ff
@ -70,8 +70,9 @@ std::vector<BattleHex> BattleEvaluator::getBrokenWallMoatHexes() const
|
|||||||
std::optional<PossibleSpellcast> BattleEvaluator::findBestCreatureSpell(const CStack *stack)
|
std::optional<PossibleSpellcast> BattleEvaluator::findBestCreatureSpell(const CStack *stack)
|
||||||
{
|
{
|
||||||
//TODO: faerie dragon type spell should be selected by server
|
//TODO: faerie dragon type spell should be selected by server
|
||||||
SpellID creatureSpellToCast = cb->getBattle(battleID)->battleGetRandomStackSpell(CRandomGenerator::getDefault(), stack, CBattleInfoCallback::RANDOM_AIMED);
|
SpellID creatureSpellToCast = cb->getBattle(battleID)->getRandomCastedSpell(CRandomGenerator::getDefault(), stack);
|
||||||
if(stack->hasBonusOfType(BonusType::SPELLCASTER) && stack->canCast() && creatureSpellToCast != SpellID::NONE)
|
|
||||||
|
if(stack->canCast() && creatureSpellToCast != SpellID::NONE)
|
||||||
{
|
{
|
||||||
const CSpell * spell = creatureSpellToCast.toSpell();
|
const CSpell * spell = creatureSpellToCast.toSpell();
|
||||||
|
|
||||||
|
@ -616,8 +616,8 @@ bool BattleActionsController::actionIsLegal(PossiblePlayerBattleAction action, B
|
|||||||
case PossiblePlayerBattleAction::RANDOM_GENIE_SPELL:
|
case PossiblePlayerBattleAction::RANDOM_GENIE_SPELL:
|
||||||
if(targetStack && targetStackOwned && targetStack != owner.stacksController->getActiveStack() && targetStack->alive()) //only positive spells for other allied creatures
|
if(targetStack && targetStackOwned && targetStack != owner.stacksController->getActiveStack() && targetStack->alive()) //only positive spells for other allied creatures
|
||||||
{
|
{
|
||||||
int spellID = owner.getBattle()->battleGetRandomStackSpell(CRandomGenerator::getDefault(), targetStack, CBattleInfoCallback::RANDOM_GENIE);
|
SpellID spellID = owner.getBattle()->getRandomBeneficialSpell(CRandomGenerator::getDefault(), owner.stacksController->getActiveStack(), targetStack);
|
||||||
return spellID > -1;
|
return spellID != SpellID::NONE;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -887,7 +887,7 @@ void BattleActionsController::tryActivateStackSpellcasting(const CStack *casterS
|
|||||||
{
|
{
|
||||||
// faerie dragon can cast only one, randomly selected spell until their next move
|
// faerie dragon can cast only one, randomly selected spell until their next move
|
||||||
//TODO: faerie dragon type spell should be selected by server
|
//TODO: faerie dragon type spell should be selected by server
|
||||||
const auto * spellToCast = owner.getBattle()->battleGetRandomStackSpell(CRandomGenerator::getDefault(), casterStack, CBattleInfoCallback::RANDOM_AIMED).toSpell();
|
const auto * spellToCast = owner.getBattle()->getRandomCastedSpell(CRandomGenerator::getDefault(), casterStack).toSpell();
|
||||||
|
|
||||||
if (spellToCast)
|
if (spellToCast)
|
||||||
creatureSpells.push_back(spellToCast);
|
creatureSpells.push_back(spellToCast);
|
||||||
|
@ -324,22 +324,6 @@ std::set<BattleHex> CBattleInfoCallback::battleGetAttackedHexes(const battle::Un
|
|||||||
return attackedHexes;
|
return attackedHexes;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpellID CBattleInfoCallback::battleGetRandomStackSpell(CRandomGenerator & rand, const CStack * stack, ERandomSpell mode) const
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case RANDOM_GENIE:
|
|
||||||
return getRandomBeneficialSpell(rand, stack); //target
|
|
||||||
break;
|
|
||||||
case RANDOM_AIMED:
|
|
||||||
return getRandomCastedSpell(rand, stack); //caster
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logGlobal->error("Incorrect mode of battleGetRandomSpell (%d)", static_cast<int>(mode));
|
|
||||||
return SpellID::NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const CStack* CBattleInfoCallback::battleGetStackByPos(BattleHex pos, bool onlyAlive) const
|
const CStack* CBattleInfoCallback::battleGetStackByPos(BattleHex pos, bool onlyAlive) const
|
||||||
{
|
{
|
||||||
RETURN_IF_NOT_BATTLE(nullptr);
|
RETURN_IF_NOT_BATTLE(nullptr);
|
||||||
@ -1610,7 +1594,7 @@ std::set<const battle::Unit *> CBattleInfoCallback::battleAdjacentUnits(const ba
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpellID CBattleInfoCallback::getRandomBeneficialSpell(CRandomGenerator & rand, const CStack * subject) const
|
SpellID CBattleInfoCallback::getRandomBeneficialSpell(CRandomGenerator & rand, const battle::Unit * caster, const battle::Unit * subject) const
|
||||||
{
|
{
|
||||||
RETURN_IF_NOT_BATTLE(SpellID::NONE);
|
RETURN_IF_NOT_BATTLE(SpellID::NONE);
|
||||||
//This is complete list. No spells from mods.
|
//This is complete list. No spells from mods.
|
||||||
@ -1658,9 +1642,19 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(CRandomGenerator & rand, c
|
|||||||
std::stringstream cachingStr;
|
std::stringstream cachingStr;
|
||||||
cachingStr << "source_" << vstd::to_underlying(BonusSource::SPELL_EFFECT) << "id_" << spellID.num;
|
cachingStr << "source_" << vstd::to_underlying(BonusSource::SPELL_EFFECT) << "id_" << spellID.num;
|
||||||
|
|
||||||
if(subject->hasBonus(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(spellID)), Selector::all, cachingStr.str())
|
if(subject->hasBonus(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(spellID)), Selector::all, cachingStr.str()))
|
||||||
//TODO: this ability has special limitations
|
continue;
|
||||||
|| !(spellID.toSpell()->canBeCast(this, spells::Mode::CREATURE_ACTIVE, subject)))
|
|
||||||
|
auto spellPtr = spellID.toSpell();
|
||||||
|
spells::Target target;
|
||||||
|
target.emplace_back(subject);
|
||||||
|
|
||||||
|
spells::BattleCast cast(this, caster, spells::Mode::CREATURE_ACTIVE, spellPtr);
|
||||||
|
|
||||||
|
auto m = spellPtr->battleMechanics(&cast);
|
||||||
|
spells::detail::ProblemImpl problem;
|
||||||
|
|
||||||
|
if (!m->canBeCastAt(target, problem))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
switch (spellID.toEnum())
|
switch (spellID.toEnum())
|
||||||
@ -1703,7 +1697,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(CRandomGenerator & rand, c
|
|||||||
case SpellID::CURE: //only damaged units
|
case SpellID::CURE: //only damaged units
|
||||||
{
|
{
|
||||||
//do not cast on affected by debuffs
|
//do not cast on affected by debuffs
|
||||||
if(!subject->canBeHealed())
|
if(subject->getFirstHPleft() == subject->getMaxHealth())
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -52,11 +52,6 @@ struct DLL_LINKAGE BattleClientInterfaceData
|
|||||||
class DLL_LINKAGE CBattleInfoCallback : public virtual CBattleInfoEssentials
|
class DLL_LINKAGE CBattleInfoCallback : public virtual CBattleInfoEssentials
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum ERandomSpell
|
|
||||||
{
|
|
||||||
RANDOM_GENIE, RANDOM_AIMED
|
|
||||||
};
|
|
||||||
|
|
||||||
std::optional<int> battleIsFinished() const override; //return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw
|
std::optional<int> battleIsFinished() const override; //return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw
|
||||||
|
|
||||||
std::vector<std::shared_ptr<const CObstacleInstance>> battleGetAllObstaclesOnPos(BattleHex tile, bool onlyBlocking = true) const override;
|
std::vector<std::shared_ptr<const CObstacleInstance>> battleGetAllObstaclesOnPos(BattleHex tile, bool onlyBlocking = true) const override;
|
||||||
@ -121,8 +116,7 @@ public:
|
|||||||
int32_t battleGetSpellCost(const spells::Spell * sp, const CGHeroInstance * caster) const; //returns cost of given spell
|
int32_t battleGetSpellCost(const spells::Spell * sp, const CGHeroInstance * caster) const; //returns cost of given spell
|
||||||
ESpellCastProblem battleCanCastSpell(const spells::Caster * caster, spells::Mode mode) const; //returns true if there are no general issues preventing from casting a spell
|
ESpellCastProblem battleCanCastSpell(const spells::Caster * caster, spells::Mode mode) const; //returns true if there are no general issues preventing from casting a spell
|
||||||
|
|
||||||
SpellID battleGetRandomStackSpell(CRandomGenerator & rand, const CStack * stack, ERandomSpell mode) const;
|
SpellID getRandomBeneficialSpell(CRandomGenerator & rand, const battle::Unit * caster, const battle::Unit * target) const;
|
||||||
SpellID getRandomBeneficialSpell(CRandomGenerator & rand, const CStack * subject) const;
|
|
||||||
SpellID getRandomCastedSpell(CRandomGenerator & rand, const CStack * caster) const; //called at the beginning of turn for Faerie Dragon
|
SpellID getRandomCastedSpell(CRandomGenerator & rand, const CStack * caster) const; //called at the beginning of turn for Faerie Dragon
|
||||||
|
|
||||||
std::vector<PossiblePlayerBattleAction> getClientActionsForStack(const CStack * stack, const BattleClientInterfaceData & data);
|
std::vector<PossiblePlayerBattleAction> getClientActionsForStack(const CStack * stack, const BattleClientInterfaceData & data);
|
||||||
|
@ -411,24 +411,48 @@ bool BattleActionProcessor::doUnitSpellAction(const CBattleInfoCallback & battle
|
|||||||
std::shared_ptr<const Bonus> randSpellcaster = stack->getBonus(Selector::type()(BonusType::RANDOM_SPELLCASTER));
|
std::shared_ptr<const Bonus> randSpellcaster = stack->getBonus(Selector::type()(BonusType::RANDOM_SPELLCASTER));
|
||||||
std::shared_ptr<const Bonus> spellcaster = stack->getBonus(Selector::typeSubtype(BonusType::SPELLCASTER, BonusSubtypeID(spellID)));
|
std::shared_ptr<const Bonus> spellcaster = stack->getBonus(Selector::typeSubtype(BonusType::SPELLCASTER, BonusSubtypeID(spellID)));
|
||||||
|
|
||||||
//TODO special bonus for genies ability
|
if (!spellcaster && !randSpellcaster)
|
||||||
if (randSpellcaster && battle.battleGetRandomStackSpell(gameHandler->getRandomGenerator(), stack, CBattleInfoCallback::RANDOM_AIMED) == SpellID::NONE)
|
|
||||||
spellID = battle.battleGetRandomStackSpell(gameHandler->getRandomGenerator(), stack, CBattleInfoCallback::RANDOM_GENIE);
|
|
||||||
|
|
||||||
if (spellID == SpellID::NONE)
|
|
||||||
gameHandler->complain("That stack can't cast spells!");
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
const CSpell * spell = SpellID(spellID).toSpell();
|
gameHandler->complain("That stack can't cast spells!");
|
||||||
spells::BattleCast parameters(&battle, stack, spells::Mode::CREATURE_ACTIVE, spell);
|
return false;
|
||||||
int32_t spellLvl = 0;
|
|
||||||
if(spellcaster)
|
|
||||||
vstd::amax(spellLvl, spellcaster->val);
|
|
||||||
if(randSpellcaster)
|
|
||||||
vstd::amax(spellLvl, randSpellcaster->val);
|
|
||||||
parameters.setSpellLevel(spellLvl);
|
|
||||||
parameters.cast(gameHandler->spellEnv, target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (randSpellcaster)
|
||||||
|
{
|
||||||
|
if (target.size() != 1)
|
||||||
|
{
|
||||||
|
gameHandler->complain("Invalid target for random spellcaster!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const battle::Unit * subject = target[0].unitValue;
|
||||||
|
if (target[0].unitValue == nullptr)
|
||||||
|
subject = battle.battleGetStackByPos(target[0].hexValue, true);
|
||||||
|
|
||||||
|
if (subject == nullptr)
|
||||||
|
{
|
||||||
|
gameHandler->complain("Invalid target for random spellcaster!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
spellID = battle.getRandomBeneficialSpell(gameHandler->getRandomGenerator(), stack, subject);
|
||||||
|
|
||||||
|
if (spellID == SpellID::NONE)
|
||||||
|
{
|
||||||
|
gameHandler->complain("That stack can't cast spells!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CSpell * spell = SpellID(spellID).toSpell();
|
||||||
|
spells::BattleCast parameters(&battle, stack, spells::Mode::CREATURE_ACTIVE, spell);
|
||||||
|
int32_t spellLvl = 0;
|
||||||
|
if(spellcaster)
|
||||||
|
vstd::amax(spellLvl, spellcaster->val);
|
||||||
|
if(randSpellcaster)
|
||||||
|
vstd::amax(spellLvl, randSpellcaster->val);
|
||||||
|
parameters.setSpellLevel(spellLvl);
|
||||||
|
parameters.cast(gameHandler->spellEnv, target);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user