mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
Extract SpellMechanics to separate file
This commit is contained in:
parent
22178151aa
commit
5ba53da9bf
@ -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" />
|
||||
|
Loading…
Reference in New Issue
Block a user