Browse Source

Fixed http://bugs.vcmi.eu/view.php?id=2541

AlexVinS 9 years ago
parent
commit
c5440a1c6c

+ 2 - 2
client/battle/CBattleInterface.cpp

@@ -2050,8 +2050,8 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
 			case ANY_LOCATION:
 				if (myNumber > -1) //TODO: this should be checked for all actions
 				{
-					creatureCasting = stackCanCastSpell && !spellDestSelectMode; //as isCastingPossibleHere is not called
-					legalAction = true;
+					if(isCastingPossibleHere (sactive, shere, myNumber))
+						legalAction = true;
 				}
 				break;
 			case AIMED_SPELL_CREATURE:

+ 15 - 3
lib/spells/CDefaultSpellMechanics.cpp

@@ -624,7 +624,7 @@ std::vector<BattleHex> DefaultSpellMechanics::rangeInHexes(BattleHex centralHex,
 	return ret;
 }
 
-std::vector<const CStack *> DefaultSpellMechanics::getAffectedStacks(const CBattleInfoCallback * cb, SpellTargetingContext & ctx) const
+std::vector<const CStack *> DefaultSpellMechanics::getAffectedStacks(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const
 {
 	std::vector<const CStack *> attackedCres = calculateAffectedStacks(cb, ctx);
 	handleImmunities(cb, ctx, attackedCres);
@@ -707,8 +707,13 @@ ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::canBeCast(const CBat
 
 ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const
 {
-	//no problems by default, this method is for spell-specific problems
-	//common problems handled by CSpell
+	if(ctx.mode == ECastingMode::CREATURE_ACTIVE_CASTING || ctx.mode == ECastingMode::HERO_CASTING)
+	{
+		std::vector<const CStack *> affected = getAffectedStacks(cb, ctx);
+		if(affected.empty())
+			return ESpellCastProblem::NO_APPROPRIATE_TARGET;
+	}
+
 	return ESpellCastProblem::OK;
 }
 
@@ -836,6 +841,13 @@ bool DefaultSpellMechanics::requiresCreatureTarget() const
 	return true;
 }
 
+ESpellCastProblem::ESpellCastProblem SpecialSpellMechanics::canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const
+{
+	//no problems by default
+	//common problems handled by CSpell
+	return ESpellCastProblem::OK;
+}
+
 std::vector<const CStack *> SpecialSpellMechanics::calculateAffectedStacks(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const
 {
 	return std::vector<const CStack *>();

+ 3 - 1
lib/spells/CDefaultSpellMechanics.h

@@ -48,7 +48,7 @@ public:
 	DefaultSpellMechanics(CSpell * s): ISpellMechanics(s){};
 
 	std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const override;
-	std::vector<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, SpellTargetingContext & ctx) const override final;
+	std::vector<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override final;
 
 	ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const override;
 	ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override;
@@ -91,6 +91,8 @@ class DLL_LINKAGE SpecialSpellMechanics : public DefaultSpellMechanics
 {
 public:
 	SpecialSpellMechanics(CSpell * s): DefaultSpellMechanics(s){};
+
+	ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override;
 protected:
 	std::vector<const CStack *> calculateAffectedStacks(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override;
 };

+ 2 - 76
lib/spells/CSpellHandler.cpp

@@ -214,7 +214,7 @@ std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl,
 std::vector<const CStack *> CSpell::getAffectedStacks(const CBattleInfoCallback * cb, ECastingMode::ECastingMode mode, const ISpellCaster * caster, int spellLvl, BattleHex destination) const
 {
 	SpellTargetingContext ctx(this, mode, caster, spellLvl, destination);
-	return mechanics->getAffectedStacks(cb, ctx);;
+	return mechanics->getAffectedStacks(cb, ctx);
 }
 
 CSpell::ETargetType CSpell::getTargetType() const
@@ -362,81 +362,7 @@ ESpellCastProblem::ESpellCastProblem CSpell::canBeCastAt(const CBattleInfoCallba
 {
 	SpellTargetingContext ctx(this, mode, caster, caster->getSpellSchoolLevel(this), destination);
 
-	ESpellCastProblem::ESpellCastProblem specific = mechanics->canBeCast(cb, ctx);
-
-	if(specific != ESpellCastProblem::OK)
-		return specific;
-
-	//todo: this should be moved to mechanics
-	//rising spells handled by mechanics
-	if(ctx.ti.onlyAlive && getTargetType() == CSpell::CREATURE)
-	{
-		const CStack * aliveStack = cb->getStackIf([destination](const CStack * s)
-		{
-			return s->isValidTarget(false) && s->coversPos(destination);
-		});
-
-		if(!aliveStack)
-			return ESpellCastProblem::NO_APPROPRIATE_TARGET;
-		if(ctx.ti.smart && isNegative() && aliveStack->owner == caster->getOwner())
-			return ESpellCastProblem::NO_APPROPRIATE_TARGET;
-		if(ctx.ti.smart && isPositive() && aliveStack->owner != caster->getOwner())
-			return ESpellCastProblem::NO_APPROPRIATE_TARGET;
-	}
-
-	return isImmuneAt(cb, caster, mode, destination);
-}
-
-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)
-	{
-		return s->coversPos(destination) && s->isValidTarget(isRisingSpell());
-	});
-
-	if(!stacks.empty())
-	{
-		bool allImmune = true;
-
-		ESpellCastProblem::ESpellCastProblem problem = ESpellCastProblem::INVALID;
-
-		for(auto s : stacks)
-		{
-			ESpellCastProblem::ESpellCastProblem res = isImmuneByStack(caster,s);
-
-			if(res == ESpellCastProblem::OK)
-			{
-				allImmune = false;
-			}
-			else
-			{
-				problem = res;
-			}
-		}
-
-		if(allImmune)
-			return problem;
-	}
-	else //no target stack on this tile
-	{
-		if(getTargetType() == CSpell::CREATURE)
-		{
-			if(caster && mode == ECastingMode::HERO_CASTING) //TODO why???
-			{
-				const CSpell::TargetInfo ti(this, caster->getSpellSchoolLevel(this), mode);
-
-				if(!ti.massive)
-					return ESpellCastProblem::WRONG_SPELL_TARGET;
-			}
-			else
-			{
- 				return ESpellCastProblem::WRONG_SPELL_TARGET;
-			}
-		}
-	}
-
-	return ESpellCastProblem::OK;
+	return mechanics->canBeCast(cb, ctx);
 }
 
 int CSpell::adjustRawDamage(const ISpellCaster * caster, const CStack * affectedCreature, int rawDamage) const

+ 0 - 4
lib/spells/CSpellHandler.h

@@ -298,10 +298,6 @@ public://internal, for use only by Mechanics classes
 	ESpellCastProblem::ESpellCastProblem internalIsImmune(const ISpellCaster * caster, const CStack *obj) const;
 
 private:
-
-	///checks for creature immunity *at given hex*.
-	ESpellCastProblem::ESpellCastProblem isImmuneAt(const CBattleInfoCallback * cb, const ISpellCaster * caster, ECastingMode::ECastingMode mode, BattleHex destination) const;
-
 	void setIsOffensive(const bool val);
 	void setIsRising(const bool val);
 

+ 1 - 1
lib/spells/ISpellMechanics.h

@@ -107,7 +107,7 @@ public:
 	virtual ~ISpellMechanics(){};
 
 	virtual std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const = 0;
-	virtual std::vector<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, SpellTargetingContext & ctx) const = 0;
+	virtual std::vector<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const = 0;
 
 	virtual ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const = 0;