From 70d9be844713532f240d95e0bece37e4385a795d Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Mon, 28 Sep 2015 16:06:26 +0300 Subject: [PATCH] Use ISpellCaster in battle callback --- client/battle/CBattleInterface.cpp | 12 +++++-- lib/CBattleCallback.cpp | 55 ++++++++++++----------------- lib/CBattleCallback.h | 9 +++-- lib/spells/BattleSpellMechanics.cpp | 4 +-- lib/spells/CSpellHandler.cpp | 8 ++--- lib/spells/CSpellHandler.h | 5 +-- server/CGameHandler.cpp | 10 +++--- 7 files changed, 47 insertions(+), 56 deletions(-) diff --git a/client/battle/CBattleInterface.cpp b/client/battle/CBattleInterface.cpp index ec05cb895..fe998a0b5 100644 --- a/client/battle/CBattleInterface.cpp +++ b/client/battle/CBattleInterface.cpp @@ -2470,10 +2470,16 @@ bool CBattleInterface::isCastingPossibleHere (const CStack * sactive, const CSta if (sp) { - if (creatureCasting) - isCastingPossible = (curInt->cb->battleCanCreatureCastThisSpell (sp, myNumber) == ESpellCastProblem::OK); + const ISpellCaster * caster = creatureCasting ? dynamic_cast(sactive) : dynamic_cast(curInt->cb->battleGetMyHero()); + if(caster == nullptr) + { + isCastingPossible = false;//just in case + } else - isCastingPossible = (curInt->cb->battleCanCastThisSpell (sp, myNumber) == ESpellCastProblem::OK); + { + const ECastingMode::ECastingMode mode = creatureCasting ? ECastingMode::CREATURE_ACTIVE_CASTING : ECastingMode::HERO_CASTING; + isCastingPossible = (curInt->cb->battleCanCastThisSpellHere(caster, sp, mode, myNumber) == ESpellCastProblem::OK); + } } else isCastingPossible = false; diff --git a/lib/CBattleCallback.cpp b/lib/CBattleCallback.cpp index a9f356a5e..4a5c3193a 100644 --- a/lib/CBattleCallback.cpp +++ b/lib/CBattleCallback.cpp @@ -1592,9 +1592,15 @@ std::vector CBattleInfoCallback::getAttackableBattleHexes() const return attackableBattleHexes; } -ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell( PlayerColor player, const CSpell * spell, ECastingMode::ECastingMode mode ) const +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; + } + const PlayerColor player = caster->getOwner(); const ui8 side = playerToSide(player); if(!battleDoWeKnowAbout(side)) return ESpellCastProblem::INVALID; @@ -1603,16 +1609,11 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell if(genProblem != ESpellCastProblem::OK) return genProblem; - //Casting hero, set only if he is an actual caster. - const CGHeroInstance *castingHero = mode == ECastingMode::HERO_CASTING - ? battleGetFightingHero(side) - : nullptr; - - switch(mode) { case ECastingMode::HERO_CASTING: { + const CGHeroInstance * castingHero = dynamic_cast(caster);//todo: unify hero|creature spell cost assert(castingHero); if(!castingHero->canCastThisSpell(spell)) return ESpellCastProblem::HERO_DOESNT_KNOW_SPELL; @@ -1622,7 +1623,6 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell break; } - if(!spell->combatSpell) return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL; @@ -1639,7 +1639,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell auto stacks = spell->isNegative() ? battleAliveStacks(!side) : battleAliveStacks(); for(auto stack : stacks) { - if(ESpellCastProblem::OK == spell->isImmuneByStack(castingHero, stack)) + if(ESpellCastProblem::OK == spell->isImmuneByStack(caster, stack)) { allStacksImmune = false; break; @@ -1659,7 +1659,6 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell case CSpell::CREATURE: if(mode == ECastingMode::HERO_CASTING) { - const CGHeroInstance * caster = battleGetFightingHero(side); const CSpell::TargetInfo ti(spell, caster->getSpellSchoolLevel(spell)); bool targetExists = false; @@ -1777,10 +1776,16 @@ ui32 CBattleInfoCallback::battleGetSpellCost(const CSpell * sp, const CGHeroInst return ret - manaReduction + manaIncrease; } -ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpellHere( PlayerColor player, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest ) const +ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpellHere(const ISpellCaster * caster, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest) const { RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID); - ESpellCastProblem::ESpellCastProblem moreGeneralProblem = battleCanCastThisSpell(player, spell, mode); + if(caster == nullptr) + { + logGlobal->errorStream() << "CBattleInfoCallback::battleCanCastThisSpellHere: no spellcaster."; + return ESpellCastProblem::INVALID; + } + const PlayerColor player = caster->getOwner(); + ESpellCastProblem::ESpellCastProblem moreGeneralProblem = battleCanCastThisSpell(caster, spell, mode); if(moreGeneralProblem != ESpellCastProblem::OK) return moreGeneralProblem; @@ -1843,11 +1848,6 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell if(spell->isPositive() && aliveStack->owner != player) return ESpellCastProblem::NO_APPROPRIATE_TARGET; } - - const CGHeroInstance * caster = nullptr; - if (mode == ECastingMode::HERO_CASTING) - caster = battleGetFightingHero(playerToSide(player)); - return spell->isImmuneAt(this, caster, mode, dest); } @@ -1930,7 +1930,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co { 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) + || battleCanCastThisSpellHere(subject, spellID.toSpell(), ECastingMode::CREATURE_ACTIVE_CASTING, subject->position) != ESpellCastProblem::OK) continue; switch (spellID) @@ -2168,21 +2168,12 @@ ESpellCastProblem::ESpellCastProblem CPlayerBattleCallback::battleCanCastThisSpe { RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID); ASSERT_IF_CALLED_WITH_PLAYER - return CBattleInfoCallback::battleCanCastThisSpell(*player, spell, ECastingMode::HERO_CASTING); -} -ESpellCastProblem::ESpellCastProblem CPlayerBattleCallback::battleCanCastThisSpell(const CSpell * spell, BattleHex destination) const -{ - RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID); - ASSERT_IF_CALLED_WITH_PLAYER - return battleCanCastThisSpellHere(*player, spell, ECastingMode::HERO_CASTING, destination); -} - -ESpellCastProblem::ESpellCastProblem CPlayerBattleCallback::battleCanCreatureCastThisSpell(const CSpell * spell, BattleHex destination) const -{ - RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID); - ASSERT_IF_CALLED_WITH_PLAYER - return battleCanCastThisSpellHere(*player, spell, ECastingMode::CREATURE_ACTIVE_CASTING, destination); + const ISpellCaster * hero = battleGetMyHero(); + if(hero == nullptr) + return ESpellCastProblem::INVALID; + else + return CBattleInfoCallback::battleCanCastThisSpell(hero, spell, ECastingMode::HERO_CASTING); } bool CPlayerBattleCallback::battleCanFlee() const diff --git a/lib/CBattleCallback.h b/lib/CBattleCallback.h index f16b6f1af..19f5bf1d2 100644 --- a/lib/CBattleCallback.h +++ b/lib/CBattleCallback.h @@ -15,6 +15,7 @@ class CGameState; class CGTownInstance; class CGHeroInstance; class CStack; +class ISpellCaster; class CSpell; struct BattleInfo; struct CObstacleInstance; @@ -280,9 +281,8 @@ 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(PlayerColor player, ECastingMode::ECastingMode mode) const; //returns true if there are no general issues preventing from casting a spell - ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(PlayerColor player, const CSpell * spell, ECastingMode::ECastingMode mode) const; //checks if given player can cast given spell - ESpellCastProblem::ESpellCastProblem battleCanCastThisSpellHere(PlayerColor player, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest) const; //checks if given player can cast given spell at given tile in given mode - ESpellCastProblem::ESpellCastProblem battleCanCreatureCastThisSpell(const CSpell * spell, BattleHex destination) const; //determines if creature can cast a spell here + ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(const ISpellCaster * caster, const CSpell * spell, ECastingMode::ECastingMode mode) const; //checks if given player can cast given spell + ESpellCastProblem::ESpellCastProblem battleCanCastThisSpellHere(const ISpellCaster * caster, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest) const; //checks if given player can cast given spell at given tile in given mode std::vector battleGetPossibleTargets(PlayerColor player, const CSpell *spell) const; SpellID battleGetRandomStackSpell(const CStack * stack, ERandomSpell mode) const; @@ -326,8 +326,7 @@ public: bool battleCanFlee() const; //returns true if caller can flee from the battle TStacks battleGetStacks(EStackOwnership whose = MINE_AND_ENEMY, bool onlyAlive = true) const; //returns stacks on battlefield ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell) const; //determines if given spell can be cast (and returns problem description) - ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell, BattleHex destination) const; //if hero can cast spell here - ESpellCastProblem::ESpellCastProblem battleCanCreatureCastThisSpell(const CSpell * spell, BattleHex destination) const; //determines if creature can cast a spell here + int battleGetSurrenderCost() const; //returns cost of surrendering battle, -1 if surrendering is not possible bool battleCanCastSpell(ESpellCastProblem::ESpellCastProblem *outProblem = nullptr) const; //returns true, if caller can cast a spell. If not, if pointer is given via arg, the reason will be written. diff --git a/lib/spells/BattleSpellMechanics.cpp b/lib/spells/BattleSpellMechanics.cpp index 91b5fc715..66464c53a 100644 --- a/lib/spells/BattleSpellMechanics.cpp +++ b/lib/spells/BattleSpellMechanics.cpp @@ -139,8 +139,6 @@ ESpellCastProblem::ESpellCastProblem CloneMechanics::isImmuneByStack(const ISpel return ESpellCastProblem::STACK_IMMUNE_TO_SPELL; if(obj->cloneID != -1) return ESpellCastProblem::STACK_IMMUNE_TO_SPELL; - //TODO: how about stacks casting Clone? - //currently Clone cast by stack is assumed Expert level ui8 schoolLevel; if(caster) { @@ -148,7 +146,7 @@ ESpellCastProblem::ESpellCastProblem CloneMechanics::isImmuneByStack(const ISpel } else { - schoolLevel = 3; + schoolLevel = 3;//todo: remove } if(schoolLevel < 3) diff --git a/lib/spells/CSpellHandler.cpp b/lib/spells/CSpellHandler.cpp index 0f401cdf6..48f1c5514 100644 --- a/lib/spells/CSpellHandler.cpp +++ b/lib/spells/CSpellHandler.cpp @@ -23,7 +23,6 @@ #include "../CModHandler.h" #include "../StringConstants.h" -#include "../mapObjects/CGHeroInstance.h" #include "../BattleState.h" #include "../CBattleCallback.h" #include "../CGameState.h" //todo: remove @@ -303,7 +302,7 @@ void CSpell::getEffects(std::vector & lst, const int level) const } } -ESpellCastProblem::ESpellCastProblem CSpell::isImmuneAt(const CBattleInfoCallback * cb, const CGHeroInstance * caster, ECastingMode::ECastingMode mode, BattleHex destination) const +ESpellCastProblem::ESpellCastProblem CSpell::isImmuneAt(const CBattleInfoCallback * cb, const ISpellCaster * caster, ECastingMode::ECastingMode mode, BattleHex destination) const { // Get all stacks at destination hex. only alive if not rising spell TStacks stacks = cb->battleGetStacksIf([=](const CStack * s){ @@ -385,9 +384,8 @@ int CSpell::adjustRawDamage(const ISpellCaster * caster, const CStack * affected ret /= 100; } } - - ret = caster->getSpellBonus(this, ret, affectedCreature); - + if(caster != nullptr) + ret = caster->getSpellBonus(this, ret, affectedCreature); return ret; } diff --git a/lib/spells/CSpellHandler.h b/lib/spells/CSpellHandler.h index bb6963c01..332b7396e 100644 --- a/lib/spells/CSpellHandler.h +++ b/lib/spells/CSpellHandler.h @@ -213,8 +213,6 @@ public: bool hasEffects() const; void getEffects(std::vector &lst, const int level) const; - ///checks for creature immunity / anything that prevent casting *at given hex* - doesn't take into account general problems such as not having spellbook or mana points etc. - ESpellCastProblem::ESpellCastProblem isImmuneAt(const CBattleInfoCallback * cb, const CGHeroInstance * caster, ECastingMode::ECastingMode mode, BattleHex destination) const; ///calculate spell damage on stack taking caster`s secondary skills and affectedCreature`s bonuses into account ui32 calculateDamage(const ISpellCaster * caster, const CStack * affectedCreature, int spellSchoolLevel, int usedSpellPower) const; @@ -271,6 +269,9 @@ public: ///Checks general but spell-specific problems for all casting modes. Use only during battle. ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const; + ///checks for creature immunity / anything that prevent casting *at given hex* - doesn't take into account general problems such as not having spellbook or mana points etc. + ESpellCastProblem::ESpellCastProblem isImmuneAt(const CBattleInfoCallback * cb, const ISpellCaster * caster, ECastingMode::ECastingMode mode, BattleHex destination) const; + ///checks for creature immunity / anything that prevent casting *at given target* - doesn't take into account general problems such as not having spellbook or mana points etc. ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const; public: diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 96b51b7ed..42e328b26 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -4073,7 +4073,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba ) parameters.mode = ECastingMode::HERO_CASTING; parameters.selectedStack = gs->curB->battleGetStackByID(ba.selectedStack, false); - ESpellCastProblem::ESpellCastProblem escp = gs->curB->battleCanCastThisSpell(h->tempOwner, s, ECastingMode::HERO_CASTING); + ESpellCastProblem::ESpellCastProblem escp = gs->curB->battleCanCastThisSpell(h, s, ECastingMode::HERO_CASTING);//todo: should we check aimed cast(battleCanCastThisSpellHere)? if(escp != ESpellCastProblem::OK) { logGlobal->warnStream() << "Spell cannot be cast!"; @@ -4217,7 +4217,7 @@ void CGameHandler::stackTurnTrigger(const CStack * st) const CSpell * spell = SpellID(spellID).toSpell(); bl.remove_if([&bonus](Bonus * b){return b==bonus;}); - if (gs->curB->battleCanCastThisSpell(st->owner, spell, ECastingMode::ENCHANTER_CASTING) == ESpellCastProblem::OK) + if (gs->curB->battleCanCastThisSpell(st, spell, ECastingMode::ENCHANTER_CASTING) == ESpellCastProblem::OK) { BattleSpellCastParameters parameters(gs->curB, st, spell); parameters.spellLvl = bonus->val; @@ -4277,7 +4277,7 @@ void CGameHandler::handleDamageFromObstacle(const CObstacleInstance &obstacle, c //helper info const SpellCreatedObstacle *spellObstacle = dynamic_cast(&obstacle); //not nice but we may need spell params const ui8 side = !curStack->attackerOwned; //if enemy is defending (false = 0), side of enemy hero is 1 (true) - const CGHeroInstance *hero = gs->curB->battleGetFightingHero(side); + const CGHeroInstance *hero = gs->curB->battleGetFightingHero(side);//FIXME: there may be no hero - landmines in Tower if(obstacle.obstacleType == CObstacleInstance::MOAT) { @@ -4916,7 +4916,7 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta int destination = oneOfAttacked->position; const CSpell * spell = SpellID(spellID).toSpell(); - if(gs->curB->battleCanCastThisSpellHere(attacker->owner, spell, ECastingMode::AFTER_ATTACK_CASTING, oneOfAttacked->position) != ESpellCastProblem::OK) + if(gs->curB->battleCanCastThisSpellHere(attacker, spell, ECastingMode::AFTER_ATTACK_CASTING, oneOfAttacked->position) != ESpellCastProblem::OK) continue; //check if spell should be cast (probability handling) @@ -4926,8 +4926,6 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta //casting if (castMe) //stacks use 0 spell power. If needed, default = 3 or custom value is used { - const CSpell * spell = SpellID(spellID).toSpell(); - BattleSpellCastParameters parameters(gs->curB, attacker, spell); parameters.spellLvl = spellLevel; parameters.effectLevel = spellLevel;