mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Extract SpellMechanics to separate file
This commit is contained in:
		| @@ -83,6 +83,7 @@ set(lib_SRCS | ||||
| 		VCMI_Lib.cpp | ||||
| 		VCMIDirs.cpp | ||||
| 		IHandlerBase.cpp | ||||
|                 SpellMechanics.cpp | ||||
|  | ||||
| 		IGameCallback.cpp | ||||
| 		CGameInfoCallback.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; | ||||
| 	} | ||||
| 	 | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
| class DLL_LINKAGE CSpellMechanics | ||||
| ///callback to be provided by server | ||||
| class DLL_LINKAGE SpellCastEnvironment | ||||
| { | ||||
| public: | ||||
| 	CSpellMechanics(CSpell * s); | ||||
| 	virtual ~CSpellMechanics();	 | ||||
| 	virtual void sendAndApply(CPackForClient * info) = 0; | ||||
| }; | ||||
|  | ||||
| ///helper struct | ||||
| struct DLL_LINKAGE SpellCastContext | ||||
| { | ||||
| public: | ||||
| 	SpellCastEnvironment * env; | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE ISpellMechanics | ||||
| { | ||||
| public: | ||||
| 	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
									
								
								lib/SpellMechanics.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								lib/SpellMechanics.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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
									
								
								lib/SpellMechanics.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								lib/SpellMechanics.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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){};		 | ||||
| }; | ||||
| @@ -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" /> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user