1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Use ISpellCaster in battle callback

This commit is contained in:
AlexVinS 2015-09-28 16:06:26 +03:00
parent 75c2566410
commit 70d9be8447
7 changed files with 47 additions and 56 deletions

View File

@ -2470,10 +2470,16 @@ bool CBattleInterface::isCastingPossibleHere (const CStack * sactive, const CSta
if (sp) if (sp)
{ {
if (creatureCasting) const ISpellCaster * caster = creatureCasting ? dynamic_cast<const ISpellCaster *>(sactive) : dynamic_cast<const ISpellCaster *>(curInt->cb->battleGetMyHero());
isCastingPossible = (curInt->cb->battleCanCreatureCastThisSpell (sp, myNumber) == ESpellCastProblem::OK); if(caster == nullptr)
{
isCastingPossible = false;//just in case
}
else 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 else
isCastingPossible = false; isCastingPossible = false;

View File

@ -1592,9 +1592,15 @@ std::vector<BattleHex> CBattleInfoCallback::getAttackableBattleHexes() const
return attackableBattleHexes; 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); 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); const ui8 side = playerToSide(player);
if(!battleDoWeKnowAbout(side)) if(!battleDoWeKnowAbout(side))
return ESpellCastProblem::INVALID; return ESpellCastProblem::INVALID;
@ -1603,16 +1609,11 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
if(genProblem != ESpellCastProblem::OK) if(genProblem != ESpellCastProblem::OK)
return genProblem; return genProblem;
//Casting hero, set only if he is an actual caster.
const CGHeroInstance *castingHero = mode == ECastingMode::HERO_CASTING
? battleGetFightingHero(side)
: nullptr;
switch(mode) switch(mode)
{ {
case ECastingMode::HERO_CASTING: case ECastingMode::HERO_CASTING:
{ {
const CGHeroInstance * castingHero = dynamic_cast<const CGHeroInstance *>(caster);//todo: unify hero|creature spell cost
assert(castingHero); assert(castingHero);
if(!castingHero->canCastThisSpell(spell)) if(!castingHero->canCastThisSpell(spell))
return ESpellCastProblem::HERO_DOESNT_KNOW_SPELL; return ESpellCastProblem::HERO_DOESNT_KNOW_SPELL;
@ -1622,7 +1623,6 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
break; break;
} }
if(!spell->combatSpell) if(!spell->combatSpell)
return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL; return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL;
@ -1639,7 +1639,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
auto stacks = spell->isNegative() ? battleAliveStacks(!side) : battleAliveStacks(); auto stacks = spell->isNegative() ? battleAliveStacks(!side) : battleAliveStacks();
for(auto stack : stacks) for(auto stack : stacks)
{ {
if(ESpellCastProblem::OK == spell->isImmuneByStack(castingHero, stack)) if(ESpellCastProblem::OK == spell->isImmuneByStack(caster, stack))
{ {
allStacksImmune = false; allStacksImmune = false;
break; break;
@ -1659,7 +1659,6 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
case CSpell::CREATURE: case CSpell::CREATURE:
if(mode == ECastingMode::HERO_CASTING) if(mode == ECastingMode::HERO_CASTING)
{ {
const CGHeroInstance * caster = battleGetFightingHero(side);
const CSpell::TargetInfo ti(spell, caster->getSpellSchoolLevel(spell)); const CSpell::TargetInfo ti(spell, caster->getSpellSchoolLevel(spell));
bool targetExists = false; bool targetExists = false;
@ -1777,10 +1776,16 @@ ui32 CBattleInfoCallback::battleGetSpellCost(const CSpell * sp, const CGHeroInst
return ret - manaReduction + manaIncrease; 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); 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) if(moreGeneralProblem != ESpellCastProblem::OK)
return moreGeneralProblem; return moreGeneralProblem;
@ -1843,11 +1848,6 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
if(spell->isPositive() && aliveStack->owner != player) if(spell->isPositive() && aliveStack->owner != player)
return ESpellCastProblem::NO_APPROPRIATE_TARGET; 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); 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) if (subject->hasBonusFrom(Bonus::SPELL_EFFECT, spellID)
//TODO: this ability has special limitations //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; continue;
switch (spellID) switch (spellID)
@ -2168,21 +2168,12 @@ ESpellCastProblem::ESpellCastProblem CPlayerBattleCallback::battleCanCastThisSpe
{ {
RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID); RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID);
ASSERT_IF_CALLED_WITH_PLAYER ASSERT_IF_CALLED_WITH_PLAYER
return CBattleInfoCallback::battleCanCastThisSpell(*player, spell, ECastingMode::HERO_CASTING);
}
ESpellCastProblem::ESpellCastProblem CPlayerBattleCallback::battleCanCastThisSpell(const CSpell * spell, BattleHex destination) const const ISpellCaster * hero = battleGetMyHero();
{ if(hero == nullptr)
RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID); return ESpellCastProblem::INVALID;
ASSERT_IF_CALLED_WITH_PLAYER else
return battleCanCastThisSpellHere(*player, spell, ECastingMode::HERO_CASTING, destination); return CBattleInfoCallback::battleCanCastThisSpell(hero, spell, ECastingMode::HERO_CASTING);
}
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);
} }
bool CPlayerBattleCallback::battleCanFlee() const bool CPlayerBattleCallback::battleCanFlee() const

View File

@ -15,6 +15,7 @@ class CGameState;
class CGTownInstance; class CGTownInstance;
class CGHeroInstance; class CGHeroInstance;
class CStack; class CStack;
class ISpellCaster;
class CSpell; class CSpell;
struct BattleInfo; struct BattleInfo;
struct CObstacleInstance; 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 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 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 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 battleCanCastThisSpell(const ISpellCaster * caster, 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 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
ESpellCastProblem::ESpellCastProblem battleCanCreatureCastThisSpell(const CSpell * spell, BattleHex destination) const; //determines if creature can cast a spell here
std::vector<BattleHex> battleGetPossibleTargets(PlayerColor player, const CSpell *spell) const; std::vector<BattleHex> battleGetPossibleTargets(PlayerColor player, const CSpell *spell) const;
SpellID battleGetRandomStackSpell(const CStack * stack, ERandomSpell mode) 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 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 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) 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 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. 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.

View File

@ -139,8 +139,6 @@ ESpellCastProblem::ESpellCastProblem CloneMechanics::isImmuneByStack(const ISpel
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL; return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
if(obj->cloneID != -1) if(obj->cloneID != -1)
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL; return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
//TODO: how about stacks casting Clone?
//currently Clone cast by stack is assumed Expert level
ui8 schoolLevel; ui8 schoolLevel;
if(caster) if(caster)
{ {
@ -148,7 +146,7 @@ ESpellCastProblem::ESpellCastProblem CloneMechanics::isImmuneByStack(const ISpel
} }
else else
{ {
schoolLevel = 3; schoolLevel = 3;//todo: remove
} }
if(schoolLevel < 3) if(schoolLevel < 3)

View File

@ -23,7 +23,6 @@
#include "../CModHandler.h" #include "../CModHandler.h"
#include "../StringConstants.h" #include "../StringConstants.h"
#include "../mapObjects/CGHeroInstance.h"
#include "../BattleState.h" #include "../BattleState.h"
#include "../CBattleCallback.h" #include "../CBattleCallback.h"
#include "../CGameState.h" //todo: remove #include "../CGameState.h" //todo: remove
@ -303,7 +302,7 @@ void CSpell::getEffects(std::vector<Bonus> & 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 // Get all stacks at destination hex. only alive if not rising spell
TStacks stacks = cb->battleGetStacksIf([=](const CStack * s){ TStacks stacks = cb->battleGetStacksIf([=](const CStack * s){
@ -385,9 +384,8 @@ int CSpell::adjustRawDamage(const ISpellCaster * caster, const CStack * affected
ret /= 100; ret /= 100;
} }
} }
if(caster != nullptr)
ret = caster->getSpellBonus(this, ret, affectedCreature); ret = caster->getSpellBonus(this, ret, affectedCreature);
return ret; return ret;
} }

View File

@ -213,8 +213,6 @@ public:
bool hasEffects() const; bool hasEffects() const;
void getEffects(std::vector<Bonus> &lst, const int level) const; void getEffects(std::vector<Bonus> &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 ///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; 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. ///Checks general but spell-specific problems for all casting modes. Use only during battle.
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const; 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. ///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; ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const;
public: public:

View File

@ -4073,7 +4073,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
parameters.mode = ECastingMode::HERO_CASTING; parameters.mode = ECastingMode::HERO_CASTING;
parameters.selectedStack = gs->curB->battleGetStackByID(ba.selectedStack, false); 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) if(escp != ESpellCastProblem::OK)
{ {
logGlobal->warnStream() << "Spell cannot be cast!"; logGlobal->warnStream() << "Spell cannot be cast!";
@ -4217,7 +4217,7 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
const CSpell * spell = SpellID(spellID).toSpell(); const CSpell * spell = SpellID(spellID).toSpell();
bl.remove_if([&bonus](Bonus * b){return b==bonus;}); 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); BattleSpellCastParameters parameters(gs->curB, st, spell);
parameters.spellLvl = bonus->val; parameters.spellLvl = bonus->val;
@ -4277,7 +4277,7 @@ void CGameHandler::handleDamageFromObstacle(const CObstacleInstance &obstacle, c
//helper info //helper info
const SpellCreatedObstacle *spellObstacle = dynamic_cast<const SpellCreatedObstacle*>(&obstacle); //not nice but we may need spell params const SpellCreatedObstacle *spellObstacle = dynamic_cast<const SpellCreatedObstacle*>(&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 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) if(obstacle.obstacleType == CObstacleInstance::MOAT)
{ {
@ -4916,7 +4916,7 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
int destination = oneOfAttacked->position; int destination = oneOfAttacked->position;
const CSpell * spell = SpellID(spellID).toSpell(); 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; continue;
//check if spell should be cast (probability handling) //check if spell should be cast (probability handling)
@ -4926,8 +4926,6 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
//casting //casting
if (castMe) //stacks use 0 spell power. If needed, default = 3 or custom value is used 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); BattleSpellCastParameters parameters(gs->curB, attacker, spell);
parameters.spellLvl = spellLevel; parameters.spellLvl = spellLevel;
parameters.effectLevel = spellLevel; parameters.effectLevel = spellLevel;