Browse Source

Extract SpellMechanics to separate file

AlexVinS 11 years ago
parent
commit
5ba53da9bf
6 changed files with 218 additions and 156 deletions
  1. 1 0
      lib/CMakeLists.txt
  2. 7 150
      lib/CSpellHandler.cpp
  3. 30 6
      lib/CSpellHandler.h
  4. 112 0
      lib/SpellMechanics.cpp
  5. 66 0
      lib/SpellMechanics.h
  6. 2 0
      lib/VCMI_lib.cbp

+ 1 - 0
lib/CMakeLists.txt

@@ -83,6 +83,7 @@ set(lib_SRCS
 		VCMI_Lib.cpp
 		VCMIDirs.cpp
 		IHandlerBase.cpp
+                SpellMechanics.cpp
 
 		IGameCallback.cpp
 		CGameInfoCallback.cpp

+ 7 - 150
lib/CSpellHandler.cpp

@@ -13,6 +13,10 @@
 #include "mapObjects/CGHeroInstance.h"
 #include "BattleState.h"
 
+#include "SpellMechanics.h"
+
+
+
 /*
  * CSpellHandler.cpp, part of VCMI engine
  *
@@ -132,160 +136,13 @@ namespace SRSLPraserHelpers
 }
 
 
-///CSpellMechanics
-CSpellMechanics::CSpellMechanics(CSpell * s):
+///ISpellMechanics
+ISpellMechanics::ISpellMechanics(CSpell * s):
 	owner(s)
 {
 	
 }
 
-CSpellMechanics::~CSpellMechanics()
-{
-	
-}
-
-ESpellCastProblem::ESpellCastProblem CSpellMechanics::isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj)
-{
-	//by default use general algorithm
-	return owner->isImmuneBy(obj);
-}
-
-namespace
-{
-	class CloneMechnics: public CSpellMechanics
-	{
-	public:
-		CloneMechnics(CSpell * s): CSpellMechanics(s){};
-		ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj) override;
-	};
-	
-	class DispellHelpfulMechanics: public CSpellMechanics
-	{
-	public:
-		DispellHelpfulMechanics(CSpell * s): CSpellMechanics(s){};
-		ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj) override;	
-	};
-	
-	class HypnotizeMechanics: public CSpellMechanics
-	{
-	public:
-		HypnotizeMechanics(CSpell * s): CSpellMechanics(s){};	
-		ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj) override;	
-	};
-	
-	///all rising spells
-	class RisingSpellMechanics: public CSpellMechanics
-	{
-	public:
-		RisingSpellMechanics(CSpell * s): CSpellMechanics(s){};		
-		
-	};
-	
-	///all rising spells but SACRIFICE
-	class SpecialRisingSpellMechanics: public RisingSpellMechanics
-	{
-	public:
-		SpecialRisingSpellMechanics(CSpell * s): RisingSpellMechanics(s){};
-		ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj) override;						
-	};
-	
-	class SacrificeMechanics: public RisingSpellMechanics
-	{
-	public:
-		SacrificeMechanics(CSpell * s): RisingSpellMechanics(s){};		
-	};
-	
-	///CloneMechanics
-	ESpellCastProblem::ESpellCastProblem CloneMechnics::isImmuneByStack(const CGHeroInstance* caster, ECastingMode::ECastingMode mode, const CStack * obj)
-	{
-		//can't clone already cloned creature
-		if (vstd::contains(obj->state, EBattleStackState::CLONED))
-			return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
-		//TODO: how about stacks casting Clone?
-		//currently Clone casted by stack is assumed Expert level
-		ui8 schoolLevel;
-		if (caster)
-		{
-			schoolLevel = caster->getSpellSchoolLevel(owner);
-		}
-		else
-		{
-			schoolLevel = 3;
-		}
-
-		if (schoolLevel < 3)
-		{
-			int maxLevel = (std::max(schoolLevel, (ui8)1) + 4);
-			int creLevel = obj->getCreature()->level;
-			if (maxLevel < creLevel) //tier 1-5 for basic, 1-6 for advanced, any level for expert
-				return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
-		}
-		//use default algorithm only if there is no mechanics-related problem		
-		return CSpellMechanics::isImmuneByStack(caster,mode,obj);	
-	}
-	
-	///DispellHelpfulMechanics
-	ESpellCastProblem::ESpellCastProblem DispellHelpfulMechanics::isImmuneByStack(const CGHeroInstance* caster, ECastingMode::ECastingMode mode, const CStack* obj)
-	{
-		TBonusListPtr spellBon = obj->getSpellBonuses();
-		bool hasPositiveSpell = false;
-		for(const Bonus * b : *spellBon)
-		{
-			if(SpellID(b->sid).toSpell()->isPositive())
-			{
-				hasPositiveSpell = true;
-				break;
-			}
-		}
-		if(!hasPositiveSpell)
-		{
-			return ESpellCastProblem::NO_SPELLS_TO_DISPEL;
-		}
-		
-		//use default algorithm only if there is no mechanics-related problem		
-		return CSpellMechanics::isImmuneByStack(caster,mode,obj);	
-	}
-	
-	///HypnotizeMechanics
-	ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const CGHeroInstance* caster, ECastingMode::ECastingMode mode, const CStack* obj)
-	{
-		if(nullptr != caster) //do not resist hypnotize casted after attack, for example
-		{
-			//TODO: what with other creatures casting hypnotize, Faerie Dragons style?
-			ui64 subjectHealth = (obj->count - 1) * obj->MaxHealth() + obj->firstHPleft;
-			//apply 'damage' bonus for hypnotize, including hero specialty
-			ui64 maxHealth = owner->calculateBonus(caster->getPrimSkillLevel(PrimarySkill::SPELL_POWER)
-				* owner->power + owner->getPower(caster->getSpellSchoolLevel(owner)), caster, obj);
-			if (subjectHealth > maxHealth)
-				return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
-		}			
-		return CSpellMechanics::isImmuneByStack(caster,mode,obj);
-	}
-	
-	
-	///SpecialRisingSpellMechanics
-	ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::isImmuneByStack(const CGHeroInstance* caster, ECastingMode::ECastingMode mode, const CStack* obj)
-	{
-        // following does apply to resurrect and animate dead(?) only
-        // for sacrifice health calculation and health limit check don't matter
-
-		if(obj->count >= obj->baseAmount)
-			return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
-		
-		if (caster) //FIXME: Archangels can cast immune stack
-		{
-			auto maxHealth = owner->calculateHealedHP (caster, obj);
-			if (maxHealth < obj->MaxHealth()) //must be able to rise at least one full creature
-				return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
-		}	
-		
-		return CSpellMechanics::isImmuneByStack(caster,mode,obj);	
-	}
-	
-	
-}
-
-
 ///CSpell::LevelInfo
 CSpell::LevelInfo::LevelInfo()
 	:description(""),cost(0),power(0),AIValue(0),smartTarget(true),range("0")
@@ -804,7 +661,7 @@ void CSpell::setupMechanics()
 		if(isRisingSpell())
 			mechanics = new SpecialRisingSpellMechanics(this);
 		else	
-			mechanics = new CSpellMechanics(this);
+			mechanics = new DefaultSpellMechanics(this);
 		break;
 	}
 	

+ 30 - 6
lib/CSpellHandler.h

@@ -23,6 +23,8 @@ class CSpell;
 class CGHeroInstance;
 class CStack;
 
+struct CPackForClient;
+
 struct SpellSchoolInfo
 {
 	ESpellSchool id; //backlink
@@ -59,15 +61,37 @@ static SpellSchoolInfo spellSchoolConfig[4] =
 	}
 };
 
-class CPackForClient;
+///callback to be provided by server
+class DLL_LINKAGE SpellCastEnvironment
+{
+public:
+	virtual void sendAndApply(CPackForClient * info) = 0;
+};
+
+///helper struct
+struct DLL_LINKAGE SpellCastContext
+{
+public:
+	SpellCastEnvironment * env;
+};
 
-class DLL_LINKAGE CSpellMechanics
+class DLL_LINKAGE ISpellMechanics
 {
 public:
-	CSpellMechanics(CSpell * s);
-	virtual ~CSpellMechanics();	
+	ISpellMechanics(CSpell * s);
+	virtual ~ISpellMechanics(){};	
+	
+	virtual ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj) = 0;
+	
+    /** \brief 
+     *
+     * \param 
+     * \return true if no error
+     *
+     */                           
+	virtual bool adventureCast(SpellCastContext & context) = 0; 
+	virtual bool battleCast(SpellCastContext & context) = 0; 	
 	
-	virtual ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj);
 protected:
 	CSpell * owner;	
 };
@@ -262,7 +286,7 @@ private:
 
 	std::vector<LevelInfo> levels;
 	
-	CSpellMechanics * mechanics;//(!) do not serialize
+	ISpellMechanics * mechanics;//(!) do not serialize
 };
 
 

+ 112 - 0
lib/SpellMechanics.cpp

@@ -0,0 +1,112 @@
+/*
+ * SpellMechanics.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#include "StdInc.h"
+#include "SpellMechanics.h"
+
+#include "mapObjects/CGHeroInstance.h"
+#include "BattleState.h"
+
+///DefaultSpellMechanics
+ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj)
+{
+	//by default use general algorithm
+	return owner->isImmuneBy(obj);
+}
+
+///CloneMechanics
+ESpellCastProblem::ESpellCastProblem CloneMechnics::isImmuneByStack(const CGHeroInstance* caster, ECastingMode::ECastingMode mode, const CStack * obj)
+{
+	//can't clone already cloned creature
+	if (vstd::contains(obj->state, EBattleStackState::CLONED))
+		return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
+	//TODO: how about stacks casting Clone?
+	//currently Clone casted by stack is assumed Expert level
+	ui8 schoolLevel;
+	if (caster)
+	{
+		schoolLevel = caster->getSpellSchoolLevel(owner);
+	}
+	else
+	{
+		schoolLevel = 3;
+	}
+
+	if (schoolLevel < 3)
+	{
+		int maxLevel = (std::max(schoolLevel, (ui8)1) + 4);
+		int creLevel = obj->getCreature()->level;
+		if (maxLevel < creLevel) //tier 1-5 for basic, 1-6 for advanced, any level for expert
+			return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
+	}
+	//use default algorithm only if there is no mechanics-related problem		
+	return DefaultSpellMechanics::isImmuneByStack(caster,mode,obj);	
+}
+
+///DispellHelpfulMechanics
+ESpellCastProblem::ESpellCastProblem DispellHelpfulMechanics::isImmuneByStack(const CGHeroInstance* caster, ECastingMode::ECastingMode mode, const CStack* obj)
+{
+	TBonusListPtr spellBon = obj->getSpellBonuses();
+	bool hasPositiveSpell = false;
+	for(const Bonus * b : *spellBon)
+	{
+		if(SpellID(b->sid).toSpell()->isPositive())
+		{
+			hasPositiveSpell = true;
+			break;
+		}
+	}
+	if(!hasPositiveSpell)
+	{
+		return ESpellCastProblem::NO_SPELLS_TO_DISPEL;
+	}
+	
+	//use default algorithm only if there is no mechanics-related problem		
+	return DefaultSpellMechanics::isImmuneByStack(caster,mode,obj);	
+}
+
+///HypnotizeMechanics
+ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const CGHeroInstance* caster, ECastingMode::ECastingMode mode, const CStack* obj)
+{
+	if(nullptr != caster) //do not resist hypnotize casted after attack, for example
+	{
+		//TODO: what with other creatures casting hypnotize, Faerie Dragons style?
+		ui64 subjectHealth = (obj->count - 1) * obj->MaxHealth() + obj->firstHPleft;
+		//apply 'damage' bonus for hypnotize, including hero specialty
+		ui64 maxHealth = owner->calculateBonus(caster->getPrimSkillLevel(PrimarySkill::SPELL_POWER)
+			* owner->power + owner->getPower(caster->getSpellSchoolLevel(owner)), caster, obj);
+		if (subjectHealth > maxHealth)
+			return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
+	}			
+	return DefaultSpellMechanics::isImmuneByStack(caster,mode,obj);
+}
+
+
+///SpecialRisingSpellMechanics
+ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::isImmuneByStack(const CGHeroInstance* caster, ECastingMode::ECastingMode mode, const CStack* obj)
+{
+	// following does apply to resurrect and animate dead(?) only
+	// for sacrifice health calculation and health limit check don't matter
+
+	if(obj->count >= obj->baseAmount)
+		return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
+	
+	if (caster) //FIXME: Archangels can cast immune stack
+	{
+		auto maxHealth = owner->calculateHealedHP (caster, obj);
+		if (maxHealth < obj->MaxHealth()) //must be able to rise at least one full creature
+			return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
+	}	
+	
+	return DefaultSpellMechanics::isImmuneByStack(caster,mode,obj);	
+}
+
+	
+

+ 66 - 0
lib/SpellMechanics.h

@@ -0,0 +1,66 @@
+/*
+ * SpellMechanics.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+ 
+#pragma once
+
+#include "CSpellHandler.h"
+
+class DefaultSpellMechanics: public ISpellMechanics
+{
+public:
+	DefaultSpellMechanics(CSpell * s): ISpellMechanics(s){};
+	ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj) override;
+	
+	bool adventureCast(SpellCastContext & context) override; 
+	bool battleCast(SpellCastContext & context) override; 
+};
+
+class CloneMechnics: public DefaultSpellMechanics
+{
+public:
+	CloneMechnics(CSpell * s): DefaultSpellMechanics(s){};
+	ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj) override;
+};
+
+class DispellHelpfulMechanics: public DefaultSpellMechanics
+{
+public:
+	DispellHelpfulMechanics(CSpell * s): DefaultSpellMechanics(s){};
+	ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj) override;	
+};
+
+class HypnotizeMechanics: public DefaultSpellMechanics
+{
+public:
+	HypnotizeMechanics(CSpell * s): DefaultSpellMechanics(s){};	
+	ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj) override;	
+};
+
+///all rising spells
+class RisingSpellMechanics: public DefaultSpellMechanics
+{
+public:
+	RisingSpellMechanics(CSpell * s): DefaultSpellMechanics(s){};		
+	
+};
+
+///all rising spells but SACRIFICE
+class SpecialRisingSpellMechanics: public RisingSpellMechanics
+{
+public:
+	SpecialRisingSpellMechanics(CSpell * s): RisingSpellMechanics(s){};
+	ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj) override;						
+};
+
+class SacrificeMechanics: public RisingSpellMechanics
+{
+public:
+	SacrificeMechanics(CSpell * s): RisingSpellMechanics(s){};		
+};

+ 2 - 0
lib/VCMI_lib.cbp

@@ -185,6 +185,8 @@
 		<Unit filename="ResourceSet.cpp" />
 		<Unit filename="ResourceSet.h" />
 		<Unit filename="ScopeGuard.h" />
+		<Unit filename="SpellMechanics.cpp" />
+		<Unit filename="SpellMechanics.h" />
 		<Unit filename="StartInfo.h" />
 		<Unit filename="StdInc.h">
 			<Option weight="0" />