|
|
@@ -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 ¢er, const int3 &pos)
|
|
|
@@ -527,6 +658,7 @@ bool DLL_LINKAGE isInScreenRange(const int3 ¢er, 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)
|