1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-26 22:57:00 +02:00

Extract some spell imuunity mechanics + draft of overall design (UNTESTED)

This commit is contained in:
AlexVinS 2014-11-12 06:59:53 +03:00
parent a49da360d2
commit 61d6bca3ff
2 changed files with 162 additions and 4 deletions

View File

@ -10,6 +10,9 @@
#include "CModHandler.h"
#include "StringConstants.h"
#include "mapObjects/CGHeroInstance.h"
#include "BattleState.h"
/*
* CSpellHandler.cpp, part of VCMI engine
*
@ -128,6 +131,96 @@ namespace SRSLPraserHelpers
}
}
///CSpellMechanics
CSpellMechanics::CSpellMechanics(CSpell * s):
owner(s)
{
}
CSpellMechanics::~CSpellMechanics()
{
}
ESpellCastProblem::ESpellCastProblem CSpellMechanics::isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj)
{
//by default no immunity
return ESpellCastProblem::OK;
}
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;
};
///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;
}
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;
}
return CSpellMechanics::isImmuneByStack(caster,mode,obj);
}
}
///CSpell::LevelInfo
CSpell::LevelInfo::LevelInfo()
:description(""),cost(0),power(0),AIValue(0),smartTarget(true),range("0")
{
@ -139,7 +232,7 @@ CSpell::LevelInfo::~LevelInfo()
}
///CSpell
CSpell::CSpell():
id(SpellID::NONE), level(0),
earth(false), water(false), fire(false), air(false),
@ -148,13 +241,15 @@ CSpell::CSpell():
mainEffectAnim(-1),
defaultProbability(0),
isRising(false), isDamage(false), isOffensive(false),
targetType(ETargetType::NO_TARGET)
targetType(ETargetType::NO_TARGET),
mechanics(nullptr)
{
levels.resize(GameConstants::SPELL_SCHOOL_LEVELS);
}
CSpell::~CSpell()
{
delete mechanics;
}
const CSpell::LevelInfo & CSpell::getLevelInfo(const int level) const
@ -495,6 +590,18 @@ ESpellCastProblem::ESpellCastProblem CSpell::isImmuneBy(const IBonusBearer* obj)
return ESpellCastProblem::NOT_DECIDED;
}
ESpellCastProblem::ESpellCastProblem CSpell::isImmuneByStack(const CGHeroInstance* caster, ECastingMode::ECastingMode mode, const CStack* obj) const
{
const auto immuneResult = isImmuneBy(obj);
if (ESpellCastProblem::NOT_DECIDED != immuneResult)
return immuneResult;
return mechanics->isImmuneByStack(caster,mode,obj);
}
void CSpell::setIsOffensive(const bool val)
{
isOffensive = val;
@ -516,6 +623,30 @@ void CSpell::setIsRising(const bool val)
}
}
void CSpell::setupMechanics()
{
if(nullptr != mechanics)
{
logGlobal->errorStream() << "Spell " << this->name << " mechanics already set";
delete mechanics;
mechanics = nullptr;
}
switch (id)
{
case SpellID::CLONE:
mechanics = new CloneMechnics(this);
break;
case SpellID::DISPEL_HELPFUL_SPELLS:
mechanics = new DispellHelpfulMechanics(this);
break;
default:
mechanics = new CSpellMechanics(this);
break;
}
}
bool DLL_LINKAGE isInScreenRange(const int3 &center, const int3 &pos)
@ -527,6 +658,7 @@ bool DLL_LINKAGE isInScreenRange(const int3 &center, const int3 &pos)
return false;
}
///CSpellHandler
CSpellHandler::CSpellHandler()
{
@ -854,9 +986,12 @@ void CSpellHandler::afterLoadFinalization()
{
//FIXME: it is a bad place for this code, should refactor loadFromJson to know object id during loading
for(auto spell: objects)
{
for(auto & level: spell->levels)
for(auto & bonus: level.effects)
bonus.sid = spell->id;
spell->setupMechanics();
}
}
void CSpellHandler::beforeValidate(JsonNode & object)

View File

@ -19,6 +19,20 @@
class CLegacyConfigParser;
struct BattleHex;
class CSpell;
class CGHeroInstance;
class CStack;
class DLL_LINKAGE CSpellMechanics
{
public:
CSpellMechanics(CSpell * s);
virtual ~CSpellMechanics();
virtual ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj);
protected:
CSpell * owner;
};
class DLL_LINKAGE CSpell
{
@ -109,6 +123,9 @@ public:
void getEffects(std::vector<Bonus> &lst, const int level) const;
ESpellCastProblem::ESpellCastProblem isImmuneBy(const IBonusBearer *obj) const;
//checks for creature immunity / anything that prevent casting *at given hex* - doesn't take into acount general problems such as not having spellbook or mana points etc.
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, ECastingMode::ECastingMode mode, const CStack * obj) const;
si32 getCost(const int skillLevel) const;
@ -147,7 +164,9 @@ public:
h & castSound & iconBook & iconEffect & iconScenarioBonus & iconScroll;
h & levels;
if(!h.saving)
setupMechanics();
}
friend class CSpellHandler;
friend class Graphics;
@ -155,7 +174,9 @@ public:
private:
void setIsOffensive(const bool val);
void setIsRising(const bool val);
//call this after load or deserialization. cant be done in constructor.
void setupMechanics();
private:
si32 defaultProbability;
@ -186,6 +207,8 @@ private:
std::string castSound;
std::vector<LevelInfo> levels;
CSpellMechanics * mechanics;//(!) do not serialize
};