Explorar o código

Merge branch 'dispellFixes' into develop

AlexVinS %!s(int64=10) %!d(string=hai) anos
pai
achega
e5b9f76717

+ 6 - 0
client/battle/CBattleInterface.cpp

@@ -2177,6 +2177,10 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
 					legalAction = true;
 				}
 				break;
+			case ANY_CREATURE:
+				if (shere && shere->alive() && isCastingPossibleHere (sactive, shere, myNumber))
+					legalAction = true;
+				break;				
 			case HOSTILE_CREATURE_SPELL:
 				if (shere && shere->alive() && !ourStack && isCastingPossibleHere (sactive, shere, myNumber))
 					legalAction = true;
@@ -2372,6 +2376,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
 				break;
 			case HOSTILE_CREATURE_SPELL:
 			case FRIENDLY_CREATURE_SPELL:
+			case ANY_CREATURE:
 				sp = CGI->spellh->objects[creatureCasting ? creatureSpellToCast : spellToCast->additionalInfo]; //necessary if creature has random Genie spell at same time
 				consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[27]) % sp->name % shere->getName()); //Cast %s on %s
 				switch (sp->id)
@@ -2442,6 +2447,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
 	{
 		switch (illegalAction)
 		{
+			case ANY_CREATURE:
 			case HOSTILE_CREATURE_SPELL:
 			case FRIENDLY_CREATURE_SPELL:
 			case RANDOM_GENIE_SPELL:

+ 11 - 6
config/spells/other.json

@@ -106,15 +106,20 @@
 			"cast": "DISPELL"
 		},
 		"levels" : {
-			"base":{
-				"range" : "0"
+ 			"base":{
+				"targetModifier":{"smart":true},			
+ 				"range" : "0"
+ 			},
+			"advanced":{
+				"targetModifier":{"smart":false}			
 			},
-			"expert":{
-				"range" : "X"
-			}
+ 			"expert":{
+				"targetModifier":{"smart":false},			
+ 				"range" : "X"
+ 			}
 		},
 		"flags" : {
-			"indifferent": true
+			"positive": true
 		}
 	},
 	"cure" : {

+ 67 - 3
lib/spells/BattleSpellMechanics.cpp

@@ -14,6 +14,31 @@
 #include "../NetPacks.h"
 #include "../BattleState.h"
 
+///AntimagicMechanics
+void AntimagicMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
+{
+	DefaultSpellMechanics::applyBattle(battle, packet);
+
+	for(auto stackID : packet->affectedCres)
+	{
+		if(vstd::contains(packet->resisted, stackID))
+		{
+			logGlobal->errorStream() << "Resistance to positive spell " << owner->name;
+			continue;
+		}
+
+		CStack * s = battle->getStack(stackID);
+		s->popBonuses([&](const Bonus *b) -> bool
+		{
+			if(b->source == Bonus::SPELL_EFFECT)
+			{				
+				return b->sid != owner->id; //effect from this spell
+			}
+			return false; //not a spell effect
+		});
+	}	
+}
+
 ///ChainLightningMechanics
 std::set<const CStack *> ChainLightningMechanics::getAffectedStacks(SpellTargetingContext & ctx) const
 {
@@ -142,7 +167,10 @@ void DispellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast *
 	for(auto stackID : packet->affectedCres)
 	{
 		if(vstd::contains(packet->resisted, stackID))
+		{
+			logGlobal->errorStream() << "Resistance to DISPELL";
 			continue;
+		}
 
 		CStack *s = battle->getStack(stackID);
 		s->popBonuses([&](const Bonus *b) -> bool
@@ -152,6 +180,42 @@ void DispellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast *
 	}
 }
 
+ESpellCastProblem::ESpellCastProblem DispellMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
+{
+	//DISPELL ignores all immunities, so do not call default
+	std::stringstream cachingStr;
+	cachingStr << "source_" << Bonus::SPELL_EFFECT;
+
+	if(obj->hasBonus(Selector::sourceType(Bonus::SPELL_EFFECT), cachingStr.str()))
+	{
+		return ESpellCastProblem::OK;
+	}
+
+	return ESpellCastProblem::WRONG_SPELL_TARGET;
+}
+
+void DispellMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
+{
+	DefaultSpellMechanics::applyBattleEffects(env, parameters, ctx);
+
+	if(parameters.spellLvl > 2)
+	{
+		//expert DISPELL also removes spell-created obstacles
+		ObstaclesRemoved packet;
+
+		for(const auto obstacle : parameters.cb->obstacles)
+		{
+			if(obstacle->obstacleType == CObstacleInstance::FIRE_WALL
+				|| obstacle->obstacleType == CObstacleInstance::FORCE_FIELD
+				|| obstacle->obstacleType == CObstacleInstance::LAND_MINE)
+				packet.obstacles.insert(obstacle->uniqueID);
+		}
+
+		if(!packet.obstacles.empty())
+			env->sendAndApply(&packet);
+	}
+}
+
 ///EarthquakeMechanics
 void EarthquakeMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
 {
@@ -421,7 +485,7 @@ void RemoveObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * en
 ESpellCastProblem::ESpellCastProblem SacrificeMechanics::canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const
 {
 	// for sacrifice we have to check for 2 targets (one dead to resurrect and one living to destroy)
-	
+
 	bool targetExists = false;
 	bool targetToSacrificeExists = false;
 
@@ -442,9 +506,9 @@ ESpellCastProblem::ESpellCastProblem SacrificeMechanics::canBeCasted(const CBatt
 			if(targetExists && targetToSacrificeExists)
 				break;
 		}
-		
+
 	}
-	
+
 	if(targetExists && targetToSacrificeExists)
 		return ESpellCastProblem::OK;
 	else

+ 14 - 3
lib/spells/BattleSpellMechanics.h

@@ -12,6 +12,14 @@
 
 #include "CDefaultSpellMechanics.h"
 
+class DLL_LINKAGE AntimagicMechanics : public DefaultSpellMechanics
+{
+public:
+	AntimagicMechanics(CSpell * s): DefaultSpellMechanics(s){};	
+	
+	void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final;	
+};
+
 class DLL_LINKAGE ChainLightningMechanics : public DefaultSpellMechanics
 {
 public:
@@ -40,17 +48,20 @@ class DLL_LINKAGE DispellMechanics : public DefaultSpellMechanics
 {
 public:
 	DispellMechanics(CSpell * s): DefaultSpellMechanics(s){};
+	ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
 
 	void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final;
+protected:
+	void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
 };
 
 class DLL_LINKAGE EarthquakeMechanics : public DefaultSpellMechanics
 {
 public:
 	EarthquakeMechanics(CSpell * s): DefaultSpellMechanics(s){};
-	ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const override;	
+	ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const override;
 protected:
-	void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;	
+	void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
 };
 
 class DLL_LINKAGE HypnotizeMechanics : public DefaultSpellMechanics
@@ -115,7 +126,7 @@ class DLL_LINKAGE SummonMechanics : public DefaultSpellMechanics
 public:
 	SummonMechanics(CSpell * s): DefaultSpellMechanics(s){};
 
-	ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const override;	
+	ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const override;
 protected:
 	void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
 };

+ 0 - 1
lib/spells/CDefaultSpellMechanics.cpp

@@ -216,7 +216,6 @@ bool DefaultSpellMechanics::applyAdventureEffects(const SpellCastEnvironment * e
 	}
 }
 
-
 void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const
 {
 	BattleSpellCast sc;

+ 2 - 0
lib/spells/ISpellMechanics.cpp

@@ -28,6 +28,8 @@ ISpellMechanics * ISpellMechanics::createMechanics(CSpell * s)
 {
 	switch (s->id)
 	{
+	case SpellID::ANTI_MAGIC:
+		return new AntimagicMechanics(s);
 	case SpellID::ACID_BREATH_DAMAGE:
 		return new AcidBreathDamageMechanics(s);
 	case SpellID::CHAIN_LIGHTNING: