Jelajahi Sumber

Do not try to cast EARTHQUAKE with no fort

AlexVinS 10 tahun lalu
induk
melakukan
c81d4203d7

+ 5 - 0
lib/CBattleCallback.cpp

@@ -1599,6 +1599,11 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
 	if(!spell->combatSpell)
 		return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL;
 
+	const ESpellCastProblem::ESpellCastProblem specificProblem = spell->canBeCasted(this);
+	
+	if(specificProblem != ESpellCastProblem::OK)
+		return specificProblem;	
+
 	if(spell->isNegative() || spell->hasEffects())
 	{
 		bool allStacksImmune = true;

+ 15 - 0
lib/spells/BattleSpellMechanics.cpp

@@ -236,6 +236,21 @@ void EarthquakeMechanics::applyBattleEffects(const SpellCastEnvironment * env, B
 	env->sendAndApply(&ca);
 }
 
+ESpellCastProblem::ESpellCastProblem EarthquakeMechanics::canBeCasted(const CBattleInfoCallback * cb) const
+{
+	if(nullptr == cb->battleGetDefendedTown())
+	{
+		return ESpellCastProblem::NO_APPROPRIATE_TARGET;		
+	}
+	
+	if(CGTownInstance::NONE == cb->battleGetDefendedTown()->fortLevel())
+	{
+		return ESpellCastProblem::NO_APPROPRIATE_TARGET;
+	}
+	
+	return ESpellCastProblem::OK;
+}
+
 ///HypnotizeMechanics
 ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
 {

+ 1 - 0
lib/spells/BattleSpellMechanics.h

@@ -48,6 +48,7 @@ class DLL_LINKAGE EarthquakeMechanics : public DefaultSpellMechanics
 {
 public:
 	EarthquakeMechanics(CSpell * s): DefaultSpellMechanics(s){};
+	ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb) const override;	
 protected:
 	void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;	
 };

+ 7 - 0
lib/spells/CDefaultSpellMechanics.cpp

@@ -712,6 +712,13 @@ std::set<const CStack *> DefaultSpellMechanics::getAffectedStacks(SpellTargeting
 	return attackedCres;
 }
 
+ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::canBeCasted(const CBattleInfoCallback * cb) const
+{
+	//no problems by default, this method is for spell-specific problems	
+	return ESpellCastProblem::OK;
+}
+
+
 ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
 {
 	//by default use general algorithm

+ 2 - 0
lib/spells/CDefaultSpellMechanics.h

@@ -33,6 +33,8 @@ public:
 	std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const override;
 	std::set<const CStack *> getAffectedStacks(SpellTargetingContext & ctx) const override;
 
+	ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb) const override;
+	
 	ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
 
 	virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override;

+ 5 - 0
lib/spells/CSpellHandler.cpp

@@ -234,6 +234,11 @@ ui32 CSpell::calculateDamage(const CGHeroInstance * caster, const CStack * affec
 	return ret;
 }
 
+ESpellCastProblem::ESpellCastProblem CSpell::canBeCasted(const CBattleInfoCallback * cb) const
+{
+	return mechanics->canBeCasted(cb);
+}
+
 std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const
 {
 	return mechanics->rangeInHexes(centralHex,schoolLvl,side,outDroppedHexes);

+ 8 - 3
lib/spells/CSpellHandler.h

@@ -246,9 +246,6 @@ public:
 	//internal, for use only by Mechanics classes
 	ESpellCastProblem::ESpellCastProblem isImmuneBy(const IBonusBearer *obj) 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 CGHeroInstance * caster, const CStack * obj) const;
-
 	//internal, for use only by Mechanics classes. applying secondary skills
 	ui32 calculateBonus(ui32 baseDamage, const CGHeroInstance * caster, const CStack * affectedCreature) const;
 
@@ -301,6 +298,14 @@ public:
 	}
 	friend class CSpellHandler;
 	friend class Graphics;
+public:
+	///internal interface (for callbacks)
+	
+	///Checks general but spell-specific problems for all casting modes. Use only during battle.
+	ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb) 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 CGHeroInstance * caster, const CStack * obj) const;
 public:
 	///Server logic. Has write access to GameState via packets.
 	///May be executed on client side by (future) non-cheat-proof scripts.

+ 4 - 2
lib/spells/ISpellMechanics.h

@@ -38,9 +38,11 @@ public:
 
 	virtual std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const = 0;
 	virtual std::set<const CStack *> getAffectedStacks(SpellTargetingContext & ctx) const = 0;
-
+	
+	virtual ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb) const = 0;
+	
 	virtual ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const = 0;
-
+	
 	virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const = 0;
 	virtual bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const = 0;
 	virtual void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const = 0;