Explorar o código

Extracted adventure spell mechanics to distinct class hierarchy.

AlexVinS %!s(int64=9) %!d(string=hai) anos
pai
achega
a23144b361

+ 84 - 2
lib/spells/AdventureSpellMechanics.cpp

@@ -15,12 +15,94 @@
 #include "../CRandomGenerator.h"
 #include "../CRandomGenerator.h"
 #include "../mapObjects/CGHeroInstance.h"
 #include "../mapObjects/CGHeroInstance.h"
 #include "../NetPacks.h"
 #include "../NetPacks.h"
-#include "../BattleState.h"
-#include "../CGameState.h"
 #include "../CGameInfoCallback.h"
 #include "../CGameInfoCallback.h"
 #include "../mapping/CMap.h"
 #include "../mapping/CMap.h"
 #include "../CPlayerState.h"
 #include "../CPlayerState.h"
 
 
+///AdventureSpellMechanics
+bool AdventureSpellMechanics::adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
+{
+	if(!owner->isAdventureSpell())
+	{
+		env->complain("Attempt to cast non adventure spell in adventure mode");
+		return false;
+	}
+
+	const CGHeroInstance * caster = parameters.caster;
+
+	if(caster->inTownGarrison)
+	{
+		env->complain("Attempt to cast an adventure spell in town garrison");
+		return false;
+	}
+
+	const int cost = caster->getSpellCost(owner);
+
+	if(!caster->canCastThisSpell(owner))
+	{
+		env->complain("Hero cannot cast this spell!");
+		return false;
+	}
+
+	if(caster->mana < cost)
+	{
+		env->complain("Hero doesn't have enough spell points to cast this spell!");
+		return false;
+	}
+
+	{
+		AdvmapSpellCast asc;
+		asc.caster = caster;
+		asc.spellID = owner->id;
+		env->sendAndApply(&asc);
+	}
+
+	switch(applyAdventureEffects(env, parameters))
+	{
+	case ESpellCastResult::OK:
+		{
+			SetMana sm;
+			sm.hid = caster->id;
+			sm.absolute = false;
+			sm.val = -cost;
+			env->sendAndApply(&sm);
+			return true;
+		}
+		break;
+	case ESpellCastResult::CANCEL:
+		return true;
+	}
+	return false;
+}
+
+ESpellCastResult AdventureSpellMechanics::applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
+{
+	if(owner->hasEffects())
+	{
+		const int schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
+
+		std::vector<Bonus> bonuses;
+
+		owner->getEffects(bonuses, schoolLevel);
+
+		for(Bonus b : bonuses)
+		{
+			GiveBonus gb;
+			gb.id = parameters.caster->id.getNum();
+			gb.bonus = b;
+			env->sendAndApply(&gb);
+		}
+
+		return ESpellCastResult::OK;
+	}
+	else
+	{
+		//There is no generic algorithm of adventure cast
+		env->complain("Unimplemented adventure spell");
+		return ESpellCastResult::ERROR;
+	}
+}
+
 ///SummonBoatMechanics
 ///SummonBoatMechanics
 ESpellCastResult SummonBoatMechanics::applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
 ESpellCastResult SummonBoatMechanics::applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
 {
 {

+ 28 - 13
lib/spells/AdventureSpellMechanics.h

@@ -10,47 +10,62 @@
 
 
 #pragma once
 #pragma once
 
 
-#include "CDefaultSpellMechanics.h"
+#include "ISpellMechanics.h"
 
 
-class ISpellMechanics;
-class DefaultSpellMechanics;
+enum class ESpellCastResult
+{
+	OK,
+	CANCEL,//cast failed but it is not an error
+	ERROR//internal error occurred
+};
+
+class DLL_LINKAGE AdventureSpellMechanics: public IAdventureSpellMechanics
+{
+public:
+	AdventureSpellMechanics(CSpell * s): IAdventureSpellMechanics(s){};
+
+	bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override final;
+protected:
+	///actual adventure cast implementation
+	virtual ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const;
+};
 
 
-class DLL_LINKAGE SummonBoatMechanics : public DefaultSpellMechanics
+class DLL_LINKAGE SummonBoatMechanics : public AdventureSpellMechanics
 {
 {
 public:
 public:
-	SummonBoatMechanics(CSpell * s): DefaultSpellMechanics(s){};
+	SummonBoatMechanics(CSpell * s): AdventureSpellMechanics(s){};
 protected:
 protected:
 	ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
 	ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
 };
 };
 
 
-class DLL_LINKAGE ScuttleBoatMechanics : public DefaultSpellMechanics
+class DLL_LINKAGE ScuttleBoatMechanics : public AdventureSpellMechanics
 {
 {
 public:
 public:
-	ScuttleBoatMechanics(CSpell * s): DefaultSpellMechanics(s){};
+	ScuttleBoatMechanics(CSpell * s): AdventureSpellMechanics(s){};
 protected:
 protected:
 	ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
 	ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
 };
 };
 
 
-class DLL_LINKAGE DimensionDoorMechanics : public DefaultSpellMechanics
+class DLL_LINKAGE DimensionDoorMechanics : public AdventureSpellMechanics
 {
 {
 public:
 public:
-	DimensionDoorMechanics(CSpell * s): DefaultSpellMechanics(s){};
+	DimensionDoorMechanics(CSpell * s): AdventureSpellMechanics(s){};
 protected:
 protected:
 	ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
 	ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
 };
 };
 
 
-class DLL_LINKAGE TownPortalMechanics : public DefaultSpellMechanics
+class DLL_LINKAGE TownPortalMechanics : public AdventureSpellMechanics
 {
 {
 public:
 public:
-	TownPortalMechanics(CSpell * s): DefaultSpellMechanics(s){};
+	TownPortalMechanics(CSpell * s): AdventureSpellMechanics(s){};
 protected:
 protected:
 	ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
 	ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
 };
 };
 
 
-class DLL_LINKAGE ViewMechanics : public DefaultSpellMechanics
+class DLL_LINKAGE ViewMechanics : public AdventureSpellMechanics
 {
 {
 public:
 public:
-	ViewMechanics(CSpell * s): DefaultSpellMechanics(s){};
+	ViewMechanics(CSpell * s): AdventureSpellMechanics(s){};
 protected:
 protected:
 	ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
 	ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
 	virtual bool filterObject(const CGObjectInstance * obj, const int spellLevel) const = 0;
 	virtual bool filterObject(const CGObjectInstance * obj, const int spellLevel) const = 0;

+ 0 - 83
lib/spells/CDefaultSpellMechanics.cpp

@@ -145,89 +145,6 @@ void DefaultSpellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCa
 	}
 	}
 }
 }
 
 
-bool DefaultSpellMechanics::adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
-{
-	if(!owner->isAdventureSpell())
-	{
-		env->complain("Attempt to cast non adventure spell in adventure mode");
-		return false;
-	}
-
-	const CGHeroInstance * caster = parameters.caster;
-
-	if(caster->inTownGarrison)
-	{
-		env->complain("Attempt to cast an adventure spell in town garrison");
-		return false;
-	}
-
-	const int cost = caster->getSpellCost(owner);
-
-	if(!caster->canCastThisSpell(owner))
-	{
-		env->complain("Hero cannot cast this spell!");
-		return false;
-	}
-
-	if(caster->mana < cost)
-	{
-		env->complain("Hero doesn't have enough spell points to cast this spell!");
-		return false;
-	}
-
-	{
-		AdvmapSpellCast asc;
-		asc.caster = caster;
-		asc.spellID = owner->id;
-		env->sendAndApply(&asc);
-	}
-
-	switch(applyAdventureEffects(env, parameters))
-	{
-	case ESpellCastResult::OK:
-		{
-			SetMana sm;
-			sm.hid = caster->id;
-			sm.absolute = false;
-			sm.val = -cost;
-			env->sendAndApply(&sm);
-			return true;
-		}
-		break;
-	case ESpellCastResult::CANCEL:
-		return true;
-	}
-	return false;
-}
-
-ESpellCastResult DefaultSpellMechanics::applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
-{
-	if(owner->hasEffects())
-	{
-		const int schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
-
-		std::vector<Bonus> bonuses;
-
-		owner->getEffects(bonuses, schoolLevel);
-
-		for(Bonus b : bonuses)
-		{
-			GiveBonus gb;
-			gb.id = parameters.caster->id.getNum();
-			gb.bonus = b;
-			env->sendAndApply(&gb);
-		}
-
-		return ESpellCastResult::OK;
-	}
-	else
-	{
-		//There is no generic algorithm of adventure cast
-		env->complain("Unimplemented adventure spell");
-		return ESpellCastResult::ERROR;
-	}
-}
-
 void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const
 void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const
 {
 {
 	logGlobal->debugStream() << "Started spell cast. Spell: "<<owner->name<<"; mode:"<<parameters.mode;
 	logGlobal->debugStream() << "Started spell cast. Spell: "<<owner->name<<"; mode:"<<parameters.mode;

+ 1 - 11
lib/spells/CDefaultSpellMechanics.h

@@ -25,13 +25,6 @@ struct SpellCastContext
 	StacksInjured & si;
 	StacksInjured & si;
 };
 };
 
 
-enum class ESpellCastResult
-{
-	OK,
-	CANCEL,//cast failed but it is not an error
-	ERROR//internal error occurred
-};
-
 class DLL_LINKAGE DefaultSpellMechanics : public ISpellMechanics
 class DLL_LINKAGE DefaultSpellMechanics : public ISpellMechanics
 {
 {
 public:
 public:
@@ -46,7 +39,7 @@ public:
 	ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
 	ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
 
 
 	virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override;
 	virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override;
-	bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override final;
+
 	void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const override final;
 	void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const override final;
 
 
 	void battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet,
 	void battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet,
@@ -54,9 +47,6 @@ public:
 protected:
 protected:
 	virtual void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const;
 	virtual void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const;
 
 
-	///actual adventure cast implementation
-	virtual ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const;
-
 	void doDispell(BattleInfo * battle, const BattleSpellCast * packet, const CSelector & selector) const;
 	void doDispell(BattleInfo * battle, const BattleSpellCast * packet, const CSelector & selector) const;
 private:
 private:
 	void castMagicMirror(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const;
 	void castMagicMirror(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const;

+ 10 - 9
lib/spells/CSpellHandler.cpp

@@ -91,14 +91,15 @@ CSpell::CSpell():
 	defaultProbability(0),
 	defaultProbability(0),
 	isRising(false), isDamage(false), isOffensive(false),
 	isRising(false), isDamage(false), isOffensive(false),
 	targetType(ETargetType::NO_TARGET),
 	targetType(ETargetType::NO_TARGET),
-	mechanics(nullptr)
+	mechanics(),
+	adventureMechanics()
 {
 {
 	levels.resize(GameConstants::SPELL_SCHOOL_LEVELS);
 	levels.resize(GameConstants::SPELL_SCHOOL_LEVELS);
 }
 }
 
 
 CSpell::~CSpell()
 CSpell::~CSpell()
 {
 {
-	delete mechanics;
+
 }
 }
 
 
 void CSpell::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
 void CSpell::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
@@ -110,7 +111,12 @@ bool CSpell::adventureCast(const SpellCastEnvironment * env, AdventureSpellCastP
 {
 {
 	assert(env);
 	assert(env);
 
 
-	return mechanics->adventureCast(env, parameters);
+	if(!adventureMechanics.get())
+	{
+		env->complain("Invalid adventure spell cast attempt!");
+		return false;
+	}
+	return adventureMechanics->adventureCast(env, parameters);
 }
 }
 
 
 void CSpell::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const
 void CSpell::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const
@@ -622,13 +628,8 @@ void CSpell::setup()
 
 
 void CSpell::setupMechanics()
 void CSpell::setupMechanics()
 {
 {
-	if(nullptr != mechanics)
-	{
-		logGlobal->errorStream() << "Spell " << this->name << ": mechanics already set";
-		delete mechanics;
-	}
-
 	mechanics = ISpellMechanics::createMechanics(this);
 	mechanics = ISpellMechanics::createMechanics(this);
+	adventureMechanics = IAdventureSpellMechanics::createMechanics(this);
 }
 }
 
 
 ///CSpell::AnimationInfo
 ///CSpell::AnimationInfo

+ 3 - 1
lib/spells/CSpellHandler.h

@@ -20,6 +20,7 @@
 class CGObjectInstance;
 class CGObjectInstance;
 class CSpell;
 class CSpell;
 class ISpellMechanics;
 class ISpellMechanics;
+class IAdventureSpellMechanics;
 class CLegacyConfigParser;
 class CLegacyConfigParser;
 class CGHeroInstance;
 class CGHeroInstance;
 class CStack;
 class CStack;
@@ -338,7 +339,8 @@ private:
 
 
 	std::vector<LevelInfo> levels;
 	std::vector<LevelInfo> levels;
 
 
-	ISpellMechanics * mechanics;//(!) do not serialize
+	std::unique_ptr<ISpellMechanics> mechanics;//(!) do not serialize
+	std::unique_ptr<IAdventureSpellMechanics> adventureMechanics;//(!) do not serialize
 };
 };
 
 
 bool DLL_LINKAGE isInScreenRange(const int3 &center, const int3 &pos); //for spells like Dimension Door
 bool DLL_LINKAGE isInScreenRange(const int3 &center, const int3 &pos); //for spells like Dimension Door

+ 47 - 32
lib/spells/ISpellMechanics.cpp

@@ -83,72 +83,87 @@ ISpellMechanics::ISpellMechanics(CSpell * s):
 
 
 }
 }
 
 
-ISpellMechanics * ISpellMechanics::createMechanics(CSpell * s)
+std::unique_ptr<ISpellMechanics> ISpellMechanics::createMechanics(CSpell * s)
 {
 {
 	switch (s->id)
 	switch (s->id)
 	{
 	{
 	case SpellID::ANTI_MAGIC:
 	case SpellID::ANTI_MAGIC:
-		return new AntimagicMechanics(s);
+		return make_unique<AntimagicMechanics>(s);
 	case SpellID::ACID_BREATH_DAMAGE:
 	case SpellID::ACID_BREATH_DAMAGE:
-		return new AcidBreathDamageMechanics(s);
+		return make_unique<AcidBreathDamageMechanics>(s);
 	case SpellID::CHAIN_LIGHTNING:
 	case SpellID::CHAIN_LIGHTNING:
-		return new ChainLightningMechanics(s);
+		return make_unique<ChainLightningMechanics>(s);
 	case SpellID::CLONE:
 	case SpellID::CLONE:
-		return new CloneMechanics(s);
+		return make_unique<CloneMechanics>(s);
 	case SpellID::CURE:
 	case SpellID::CURE:
-		return new CureMechanics(s);
+		return make_unique<CureMechanics>(s);
 	case SpellID::DEATH_STARE:
 	case SpellID::DEATH_STARE:
-		return new DeathStareMechanics(s);
+		return make_unique<DeathStareMechanics>(s);
 	case SpellID::DISPEL:
 	case SpellID::DISPEL:
-		return new DispellMechanics(s);
+		return make_unique<DispellMechanics>(s);
 	case SpellID::DISPEL_HELPFUL_SPELLS:
 	case SpellID::DISPEL_HELPFUL_SPELLS:
-		return new DispellHelpfulMechanics(s);
+		return make_unique<DispellHelpfulMechanics>(s);
 	case SpellID::EARTHQUAKE:
 	case SpellID::EARTHQUAKE:
-		return new EarthquakeMechanics(s);
+		return make_unique<EarthquakeMechanics>(s);
 	case SpellID::FIRE_WALL:
 	case SpellID::FIRE_WALL:
 	case SpellID::FORCE_FIELD:
 	case SpellID::FORCE_FIELD:
-		return new WallMechanics(s);
+		return make_unique<WallMechanics>(s);
 	case SpellID::HYPNOTIZE:
 	case SpellID::HYPNOTIZE:
-		return new HypnotizeMechanics(s);
+		return make_unique<HypnotizeMechanics>(s);
 	case SpellID::LAND_MINE:
 	case SpellID::LAND_MINE:
 	case SpellID::QUICKSAND:
 	case SpellID::QUICKSAND:
-		return new ObstacleMechanics(s);
+		return make_unique<ObstacleMechanics>(s);
 	case SpellID::REMOVE_OBSTACLE:
 	case SpellID::REMOVE_OBSTACLE:
-		return new RemoveObstacleMechanics(s);
+		return make_unique<RemoveObstacleMechanics>(s);
 	case SpellID::SACRIFICE:
 	case SpellID::SACRIFICE:
-		return new SacrificeMechanics(s);
+		return make_unique<SacrificeMechanics>(s);
 	case SpellID::SUMMON_FIRE_ELEMENTAL:
 	case SpellID::SUMMON_FIRE_ELEMENTAL:
-		return new SummonMechanics(s, CreatureID::FIRE_ELEMENTAL);
+		return make_unique<SummonMechanics>(s, CreatureID::FIRE_ELEMENTAL);
 	case SpellID::SUMMON_EARTH_ELEMENTAL:
 	case SpellID::SUMMON_EARTH_ELEMENTAL:
-		return new SummonMechanics(s, CreatureID::EARTH_ELEMENTAL);
+		return make_unique<SummonMechanics>(s, CreatureID::EARTH_ELEMENTAL);
 	case SpellID::SUMMON_WATER_ELEMENTAL:
 	case SpellID::SUMMON_WATER_ELEMENTAL:
-		return new SummonMechanics(s, CreatureID::WATER_ELEMENTAL);
+		return make_unique<SummonMechanics>(s, CreatureID::WATER_ELEMENTAL);
 	case SpellID::SUMMON_AIR_ELEMENTAL:
 	case SpellID::SUMMON_AIR_ELEMENTAL:
-		return new SummonMechanics(s, CreatureID::AIR_ELEMENTAL);
+		return make_unique<SummonMechanics>(s, CreatureID::AIR_ELEMENTAL);
 	case SpellID::TELEPORT:
 	case SpellID::TELEPORT:
-		return new TeleportMechanics(s);
+		return make_unique<TeleportMechanics>(s);
+	default:
+		if(s->isRisingSpell())
+			return make_unique<SpecialRisingSpellMechanics>(s);
+		else
+			return make_unique<DefaultSpellMechanics>(s);
+	}
+}
+
+//IAdventureSpellMechanics
+IAdventureSpellMechanics::IAdventureSpellMechanics(CSpell * s):
+	owner(s)
+{
+
+}
+
+std::unique_ptr<IAdventureSpellMechanics> IAdventureSpellMechanics::createMechanics(CSpell * s)
+{
+	switch (s->id)
+	{
 	case SpellID::SUMMON_BOAT:
 	case SpellID::SUMMON_BOAT:
-		return new SummonBoatMechanics(s);
+		return make_unique<SummonBoatMechanics>(s);
 	case SpellID::SCUTTLE_BOAT:
 	case SpellID::SCUTTLE_BOAT:
-		return new ScuttleBoatMechanics(s);
+		return make_unique<ScuttleBoatMechanics>(s);
 	case SpellID::DIMENSION_DOOR:
 	case SpellID::DIMENSION_DOOR:
-		return new DimensionDoorMechanics(s);
+		return make_unique<DimensionDoorMechanics>(s);
 	case SpellID::FLY:
 	case SpellID::FLY:
 	case SpellID::WATER_WALK:
 	case SpellID::WATER_WALK:
 	case SpellID::VISIONS:
 	case SpellID::VISIONS:
 	case SpellID::DISGUISE:
 	case SpellID::DISGUISE:
-		return new DefaultSpellMechanics(s); //implemented using bonus system
+		return make_unique<AdventureSpellMechanics>(s); //implemented using bonus system
 	case SpellID::TOWN_PORTAL:
 	case SpellID::TOWN_PORTAL:
-		return new TownPortalMechanics(s);
+		return make_unique<TownPortalMechanics>(s);
 	case SpellID::VIEW_EARTH:
 	case SpellID::VIEW_EARTH:
-		return new ViewEarthMechanics(s);
+		return make_unique<ViewEarthMechanics>(s);
 	case SpellID::VIEW_AIR:
 	case SpellID::VIEW_AIR:
-		return new ViewAirMechanics(s);
+		return make_unique<ViewAirMechanics>(s);
 	default:
 	default:
-		if(s->isRisingSpell())
-			return new SpecialRisingSpellMechanics(s);
-		else
-			return new DefaultSpellMechanics(s);
+		return std::unique_ptr<IAdventureSpellMechanics>();
 	}
 	}
 }
 }
-

+ 20 - 8
lib/spells/ISpellMechanics.h

@@ -76,12 +76,6 @@ private:
 	void prepare(const CSpell * spell);
 	void prepare(const CSpell * spell);
 };
 };
 
 
-struct DLL_LINKAGE AdventureSpellCastParameters
-{
-	const CGHeroInstance * caster;
-	int3 pos;
-};
-
 struct DLL_LINKAGE SpellTargetingContext
 struct DLL_LINKAGE SpellTargetingContext
 {
 {
 	CSpell::TargetInfo ti;
 	CSpell::TargetInfo ti;
@@ -112,13 +106,31 @@ public:
 	virtual ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const = 0;
 	virtual ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const = 0;
 
 
 	virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) 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;
 	virtual void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const = 0;
 
 
 	virtual void battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet,
 	virtual void battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet,
 		const std::string & casterName, const CStack * attackedStack, bool & displayDamage) const = 0;
 		const std::string & casterName, const CStack * attackedStack, bool & displayDamage) const = 0;
 
 
-	static ISpellMechanics * createMechanics(CSpell * s);
+	static std::unique_ptr<ISpellMechanics> createMechanics(CSpell * s);
+protected:
+	CSpell * owner;
+};
+
+struct DLL_LINKAGE AdventureSpellCastParameters
+{
+	const CGHeroInstance * caster;
+	int3 pos;
+};
+
+class DLL_LINKAGE IAdventureSpellMechanics
+{
+public:
+	IAdventureSpellMechanics(CSpell * s);
+	virtual ~IAdventureSpellMechanics() = default;
+
+	virtual bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const = 0;
+
+	static std::unique_ptr<IAdventureSpellMechanics> createMechanics(CSpell * s);
 protected:
 protected:
 	CSpell * owner;
 	CSpell * owner;
 };
 };