diff --git a/AI/BattleAI/BattleAI.cpp b/AI/BattleAI/BattleAI.cpp index cc4da6bf6..275cfc5c2 100644 --- a/AI/BattleAI/BattleAI.cpp +++ b/AI/BattleAI/BattleAI.cpp @@ -194,8 +194,7 @@ void CBattleAI::attemptCastingSpell() std::vector possibleSpells; vstd::copy_if(VLC->spellh->objects, std::back_inserter(possibleSpells), [this, hero] (const CSpell *s) -> bool { - auto problem = getCbc()->battleCanCastThisSpell(hero, s, ECastingMode::HERO_CASTING); - return problem == ESpellCastProblem::OK; + return s->canBeCast(getCbc().get(), ECastingMode::HERO_CASTING, hero) == ESpellCastProblem::OK; }); LOGFL("I can cast %d spells.", possibleSpells.size()); diff --git a/client/windows/CSpellWindow.cpp b/client/windows/CSpellWindow.cpp index 15c012e7c..ed4c0c3f1 100644 --- a/client/windows/CSpellWindow.cpp +++ b/client/windows/CSpellWindow.cpp @@ -549,7 +549,7 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState) //we will cast a spell if(mySpell->isCombatSpell() && owner->myInt->battleInt) //if battle window is open { - ESpellCastProblem::ESpellCastProblem problem = owner->myInt->cb->battleCanCastThisSpell(owner->myHero, mySpell, ECastingMode::HERO_CASTING); + ESpellCastProblem::ESpellCastProblem problem = mySpell->canBeCast(owner->myInt->cb.get(), ECastingMode::HERO_CASTING, owner->myHero); switch (problem) { case ESpellCastProblem::OK: diff --git a/lib/CBattleCallback.cpp b/lib/CBattleCallback.cpp index 8e8c84feb..0cbeb40bb 100644 --- a/lib/CBattleCallback.cpp +++ b/lib/CBattleCallback.cpp @@ -1708,43 +1708,6 @@ std::vector CBattleInfoCallback::getAttackableBattleHexes() const return attackableBattleHexes; } -ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell(const ISpellCaster * caster, const CSpell * spell, ECastingMode::ECastingMode mode) const -{ - RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID); - if(caster == nullptr) - { - logGlobal->errorStream() << "CBattleInfoCallback::battleCanCastThisSpell: no spellcaster."; - return ESpellCastProblem::INVALID; - } - - ESpellCastProblem::ESpellCastProblem genProblem = battleCanCastSpell(caster, mode); - if(genProblem != ESpellCastProblem::OK) - return genProblem; - - switch(mode) - { - case ECastingMode::HERO_CASTING: - { - const CGHeroInstance * castingHero = dynamic_cast(caster);//todo: unify hero|creature spell cost - if(!castingHero) - { - logGlobal->error("battleCanCastThisSpell: invalid caster"); - return ESpellCastProblem::INVALID; - } - - if(!castingHero->getArt(ArtifactPosition::SPELLBOOK)) - return ESpellCastProblem::NO_SPELLBOOK; - if(!castingHero->canCastThisSpell(spell)) - return ESpellCastProblem::HERO_DOESNT_KNOW_SPELL; - if(castingHero->mana < battleGetSpellCost(spell, castingHero)) //not enough mana - return ESpellCastProblem::NOT_ENOUGH_MANA; - } - break; - } - - return spell->canBeCast(this, mode, caster); -} - ui32 CBattleInfoCallback::battleGetSpellCost(const CSpell * sp, const CGHeroInstance * caster) const { RETURN_IF_NOT_BATTLE(-1); diff --git a/lib/CBattleCallback.h b/lib/CBattleCallback.h index 9676806a0..b1e45ca59 100644 --- a/lib/CBattleCallback.h +++ b/lib/CBattleCallback.h @@ -293,7 +293,6 @@ public: si8 battleMaxSpellLevel(ui8 side) const; //calculates minimum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, 0 is returned ui32 battleGetSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //returns cost of given spell ESpellCastProblem::ESpellCastProblem battleCanCastSpell(const ISpellCaster * caster, ECastingMode::ECastingMode mode) const; //returns true if there are no general issues preventing from casting a spell - ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(const ISpellCaster * caster, const CSpell * spell, ECastingMode::ECastingMode mode) const; //checks if given player can cast given spell SpellID battleGetRandomStackSpell(CRandomGenerator & rand, const CStack * stack, ERandomSpell mode) const; SpellID getRandomBeneficialSpell(CRandomGenerator & rand, const CStack * subject) const; diff --git a/lib/spells/CSpellHandler.cpp b/lib/spells/CSpellHandler.cpp index c8ff206e1..7ea37f1dc 100644 --- a/lib/spells/CSpellHandler.cpp +++ b/lib/spells/CSpellHandler.cpp @@ -157,6 +157,31 @@ ui32 CSpell::calculateDamage(const ISpellCaster * caster, const CStack * affecte ESpellCastProblem::ESpellCastProblem CSpell::canBeCast(const CBattleInfoCallback * cb, ECastingMode::ECastingMode mode, const ISpellCaster * caster) const { + ESpellCastProblem::ESpellCastProblem genProblem = cb->battleCanCastSpell(caster, mode); + if(genProblem != ESpellCastProblem::OK) + return genProblem; + + switch(mode) + { + case ECastingMode::HERO_CASTING: + { + const CGHeroInstance * castingHero = dynamic_cast(caster);//todo: unify hero|creature spell cost + if(!castingHero) + { + logGlobal->debug("CSpell::canBeCast: invalid caster"); + return ESpellCastProblem::NO_HERO_TO_CAST_SPELL; + } + + if(!castingHero->getArt(ArtifactPosition::SPELLBOOK)) + return ESpellCastProblem::NO_SPELLBOOK; + if(!castingHero->canCastThisSpell(this)) + return ESpellCastProblem::HERO_DOESNT_KNOW_SPELL; + if(castingHero->mana < cb->battleGetSpellCost(this, castingHero)) //not enough mana + return ESpellCastProblem::NOT_ENOUGH_MANA; + } + break; + } + if(!isCombatSpell()) return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL; @@ -383,7 +408,7 @@ void CSpell::getEffects(std::vector & lst, const int level) const ESpellCastProblem::ESpellCastProblem CSpell::canBeCastAt(const CBattleInfoCallback * cb, const ISpellCaster * caster, ECastingMode::ECastingMode mode, BattleHex destination) const { - ESpellCastProblem::ESpellCastProblem problem = cb->battleCanCastThisSpell(caster, this, mode); + ESpellCastProblem::ESpellCastProblem problem = canBeCast(cb, mode, caster); if(problem != ESpellCastProblem::OK) return problem; diff --git a/lib/spells/ISpellMechanics.cpp b/lib/spells/ISpellMechanics.cpp index 4259bd74c..9ffc6ec1b 100644 --- a/lib/spells/ISpellMechanics.cpp +++ b/lib/spells/ISpellMechanics.cpp @@ -89,7 +89,7 @@ void BattleSpellCastParameters::cast(const SpellCastEnvironment * env) bool BattleSpellCastParameters::castIfPossible(const SpellCastEnvironment * env) { - if(ESpellCastProblem::OK == cb->battleCanCastThisSpell(caster, spell, mode)) + if(ESpellCastProblem::OK == spell->canBeCast(cb, mode, caster)) { cast(env); return true; diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index e18e6e9d9..bf5161fa6 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -4458,7 +4458,7 @@ bool CGameHandler::makeCustomAction(BattleAction &ba) if (ba.selectedStack >= 0) parameters.aimToStack(gs->curB->battleGetStackByID(ba.selectedStack, false)); - ESpellCastProblem::ESpellCastProblem escp = gs->curB->battleCanCastThisSpell(h, s, ECastingMode::HERO_CASTING);//todo: should we check aimed cast? + ESpellCastProblem::ESpellCastProblem escp = s->canBeCast(gs->curB, ECastingMode::HERO_CASTING, h);//todo: should we check aimed cast? if (escp != ESpellCastProblem::OK) { logGlobal->warn("Spell cannot be cast! Problem: %d", escp);