mirror of
https://github.com/vcmi/vcmi.git
synced 2025-09-16 09:26:28 +02:00
Extracted adventure spell mechanics to distinct class hierarchy.
This commit is contained in:
@@ -15,12 +15,94 @@
|
||||
#include "../CRandomGenerator.h"
|
||||
#include "../mapObjects/CGHeroInstance.h"
|
||||
#include "../NetPacks.h"
|
||||
#include "../BattleState.h"
|
||||
#include "../CGameState.h"
|
||||
#include "../CGameInfoCallback.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../CPlayerState.h"
|
||||
|
||||
///AdventureSpellMechanics
|
||||
bool AdventureSpellMechanics::adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
if(!owner->isAdventureSpell())
|
||||
{
|
||||
env->complain("Attempt to cast non adventure spell in adventure mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
const CGHeroInstance * caster = parameters.caster;
|
||||
|
||||
if(caster->inTownGarrison)
|
||||
{
|
||||
env->complain("Attempt to cast an adventure spell in town garrison");
|
||||
return false;
|
||||
}
|
||||
|
||||
const int cost = caster->getSpellCost(owner);
|
||||
|
||||
if(!caster->canCastThisSpell(owner))
|
||||
{
|
||||
env->complain("Hero cannot cast this spell!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(caster->mana < cost)
|
||||
{
|
||||
env->complain("Hero doesn't have enough spell points to cast this spell!");
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
AdvmapSpellCast asc;
|
||||
asc.caster = caster;
|
||||
asc.spellID = owner->id;
|
||||
env->sendAndApply(&asc);
|
||||
}
|
||||
|
||||
switch(applyAdventureEffects(env, parameters))
|
||||
{
|
||||
case ESpellCastResult::OK:
|
||||
{
|
||||
SetMana sm;
|
||||
sm.hid = caster->id;
|
||||
sm.absolute = false;
|
||||
sm.val = -cost;
|
||||
env->sendAndApply(&sm);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case ESpellCastResult::CANCEL:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ESpellCastResult AdventureSpellMechanics::applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
if(owner->hasEffects())
|
||||
{
|
||||
const int schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
|
||||
|
||||
std::vector<Bonus> bonuses;
|
||||
|
||||
owner->getEffects(bonuses, schoolLevel);
|
||||
|
||||
for(Bonus b : bonuses)
|
||||
{
|
||||
GiveBonus gb;
|
||||
gb.id = parameters.caster->id.getNum();
|
||||
gb.bonus = b;
|
||||
env->sendAndApply(&gb);
|
||||
}
|
||||
|
||||
return ESpellCastResult::OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
//There is no generic algorithm of adventure cast
|
||||
env->complain("Unimplemented adventure spell");
|
||||
return ESpellCastResult::ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
///SummonBoatMechanics
|
||||
ESpellCastResult SummonBoatMechanics::applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
|
@@ -10,47 +10,62 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CDefaultSpellMechanics.h"
|
||||
#include "ISpellMechanics.h"
|
||||
|
||||
class ISpellMechanics;
|
||||
class DefaultSpellMechanics;
|
||||
enum class ESpellCastResult
|
||||
{
|
||||
OK,
|
||||
CANCEL,//cast failed but it is not an error
|
||||
ERROR//internal error occurred
|
||||
};
|
||||
|
||||
class DLL_LINKAGE SummonBoatMechanics : public DefaultSpellMechanics
|
||||
class DLL_LINKAGE AdventureSpellMechanics: public IAdventureSpellMechanics
|
||||
{
|
||||
public:
|
||||
SummonBoatMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
AdventureSpellMechanics(CSpell * s): IAdventureSpellMechanics(s){};
|
||||
|
||||
bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override final;
|
||||
protected:
|
||||
///actual adventure cast implementation
|
||||
virtual ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE SummonBoatMechanics : public AdventureSpellMechanics
|
||||
{
|
||||
public:
|
||||
SummonBoatMechanics(CSpell * s): AdventureSpellMechanics(s){};
|
||||
protected:
|
||||
ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ScuttleBoatMechanics : public DefaultSpellMechanics
|
||||
class DLL_LINKAGE ScuttleBoatMechanics : public AdventureSpellMechanics
|
||||
{
|
||||
public:
|
||||
ScuttleBoatMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
ScuttleBoatMechanics(CSpell * s): AdventureSpellMechanics(s){};
|
||||
protected:
|
||||
ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE DimensionDoorMechanics : public DefaultSpellMechanics
|
||||
class DLL_LINKAGE DimensionDoorMechanics : public AdventureSpellMechanics
|
||||
{
|
||||
public:
|
||||
DimensionDoorMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
DimensionDoorMechanics(CSpell * s): AdventureSpellMechanics(s){};
|
||||
protected:
|
||||
ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE TownPortalMechanics : public DefaultSpellMechanics
|
||||
class DLL_LINKAGE TownPortalMechanics : public AdventureSpellMechanics
|
||||
{
|
||||
public:
|
||||
TownPortalMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
TownPortalMechanics(CSpell * s): AdventureSpellMechanics(s){};
|
||||
protected:
|
||||
ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ViewMechanics : public DefaultSpellMechanics
|
||||
class DLL_LINKAGE ViewMechanics : public AdventureSpellMechanics
|
||||
{
|
||||
public:
|
||||
ViewMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
ViewMechanics(CSpell * s): AdventureSpellMechanics(s){};
|
||||
protected:
|
||||
ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
|
||||
virtual bool filterObject(const CGObjectInstance * obj, const int spellLevel) const = 0;
|
||||
|
@@ -145,89 +145,6 @@ void DefaultSpellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCa
|
||||
}
|
||||
}
|
||||
|
||||
bool DefaultSpellMechanics::adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
if(!owner->isAdventureSpell())
|
||||
{
|
||||
env->complain("Attempt to cast non adventure spell in adventure mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
const CGHeroInstance * caster = parameters.caster;
|
||||
|
||||
if(caster->inTownGarrison)
|
||||
{
|
||||
env->complain("Attempt to cast an adventure spell in town garrison");
|
||||
return false;
|
||||
}
|
||||
|
||||
const int cost = caster->getSpellCost(owner);
|
||||
|
||||
if(!caster->canCastThisSpell(owner))
|
||||
{
|
||||
env->complain("Hero cannot cast this spell!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(caster->mana < cost)
|
||||
{
|
||||
env->complain("Hero doesn't have enough spell points to cast this spell!");
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
AdvmapSpellCast asc;
|
||||
asc.caster = caster;
|
||||
asc.spellID = owner->id;
|
||||
env->sendAndApply(&asc);
|
||||
}
|
||||
|
||||
switch(applyAdventureEffects(env, parameters))
|
||||
{
|
||||
case ESpellCastResult::OK:
|
||||
{
|
||||
SetMana sm;
|
||||
sm.hid = caster->id;
|
||||
sm.absolute = false;
|
||||
sm.val = -cost;
|
||||
env->sendAndApply(&sm);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case ESpellCastResult::CANCEL:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ESpellCastResult DefaultSpellMechanics::applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
if(owner->hasEffects())
|
||||
{
|
||||
const int schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
|
||||
|
||||
std::vector<Bonus> bonuses;
|
||||
|
||||
owner->getEffects(bonuses, schoolLevel);
|
||||
|
||||
for(Bonus b : bonuses)
|
||||
{
|
||||
GiveBonus gb;
|
||||
gb.id = parameters.caster->id.getNum();
|
||||
gb.bonus = b;
|
||||
env->sendAndApply(&gb);
|
||||
}
|
||||
|
||||
return ESpellCastResult::OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
//There is no generic algorithm of adventure cast
|
||||
env->complain("Unimplemented adventure spell");
|
||||
return ESpellCastResult::ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const
|
||||
{
|
||||
logGlobal->debugStream() << "Started spell cast. Spell: "<<owner->name<<"; mode:"<<parameters.mode;
|
||||
|
@@ -25,13 +25,6 @@ struct SpellCastContext
|
||||
StacksInjured & si;
|
||||
};
|
||||
|
||||
enum class ESpellCastResult
|
||||
{
|
||||
OK,
|
||||
CANCEL,//cast failed but it is not an error
|
||||
ERROR//internal error occurred
|
||||
};
|
||||
|
||||
class DLL_LINKAGE DefaultSpellMechanics : public ISpellMechanics
|
||||
{
|
||||
public:
|
||||
@@ -46,7 +39,7 @@ public:
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
|
||||
|
||||
virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override;
|
||||
bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override final;
|
||||
|
||||
void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const override final;
|
||||
|
||||
void battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet,
|
||||
@@ -54,9 +47,6 @@ public:
|
||||
protected:
|
||||
virtual void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const;
|
||||
|
||||
///actual adventure cast implementation
|
||||
virtual ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const;
|
||||
|
||||
void doDispell(BattleInfo * battle, const BattleSpellCast * packet, const CSelector & selector) const;
|
||||
private:
|
||||
void castMagicMirror(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const;
|
||||
|
@@ -91,14 +91,15 @@ CSpell::CSpell():
|
||||
defaultProbability(0),
|
||||
isRising(false), isDamage(false), isOffensive(false),
|
||||
targetType(ETargetType::NO_TARGET),
|
||||
mechanics(nullptr)
|
||||
mechanics(),
|
||||
adventureMechanics()
|
||||
{
|
||||
levels.resize(GameConstants::SPELL_SCHOOL_LEVELS);
|
||||
}
|
||||
|
||||
CSpell::~CSpell()
|
||||
{
|
||||
delete mechanics;
|
||||
|
||||
}
|
||||
|
||||
void CSpell::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
|
||||
@@ -110,7 +111,12 @@ bool CSpell::adventureCast(const SpellCastEnvironment * env, AdventureSpellCastP
|
||||
{
|
||||
assert(env);
|
||||
|
||||
return mechanics->adventureCast(env, parameters);
|
||||
if(!adventureMechanics.get())
|
||||
{
|
||||
env->complain("Invalid adventure spell cast attempt!");
|
||||
return false;
|
||||
}
|
||||
return adventureMechanics->adventureCast(env, parameters);
|
||||
}
|
||||
|
||||
void CSpell::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const
|
||||
@@ -622,13 +628,8 @@ void CSpell::setup()
|
||||
|
||||
void CSpell::setupMechanics()
|
||||
{
|
||||
if(nullptr != mechanics)
|
||||
{
|
||||
logGlobal->errorStream() << "Spell " << this->name << ": mechanics already set";
|
||||
delete mechanics;
|
||||
}
|
||||
|
||||
mechanics = ISpellMechanics::createMechanics(this);
|
||||
adventureMechanics = IAdventureSpellMechanics::createMechanics(this);
|
||||
}
|
||||
|
||||
///CSpell::AnimationInfo
|
||||
|
@@ -20,6 +20,7 @@
|
||||
class CGObjectInstance;
|
||||
class CSpell;
|
||||
class ISpellMechanics;
|
||||
class IAdventureSpellMechanics;
|
||||
class CLegacyConfigParser;
|
||||
class CGHeroInstance;
|
||||
class CStack;
|
||||
@@ -338,7 +339,8 @@ private:
|
||||
|
||||
std::vector<LevelInfo> levels;
|
||||
|
||||
ISpellMechanics * mechanics;//(!) do not serialize
|
||||
std::unique_ptr<ISpellMechanics> mechanics;//(!) do not serialize
|
||||
std::unique_ptr<IAdventureSpellMechanics> adventureMechanics;//(!) do not serialize
|
||||
};
|
||||
|
||||
bool DLL_LINKAGE isInScreenRange(const int3 ¢er, const int3 &pos); //for spells like Dimension Door
|
||||
|
@@ -83,72 +83,87 @@ ISpellMechanics::ISpellMechanics(CSpell * s):
|
||||
|
||||
}
|
||||
|
||||
ISpellMechanics * ISpellMechanics::createMechanics(CSpell * s)
|
||||
std::unique_ptr<ISpellMechanics> ISpellMechanics::createMechanics(CSpell * s)
|
||||
{
|
||||
switch (s->id)
|
||||
{
|
||||
case SpellID::ANTI_MAGIC:
|
||||
return new AntimagicMechanics(s);
|
||||
return make_unique<AntimagicMechanics>(s);
|
||||
case SpellID::ACID_BREATH_DAMAGE:
|
||||
return new AcidBreathDamageMechanics(s);
|
||||
return make_unique<AcidBreathDamageMechanics>(s);
|
||||
case SpellID::CHAIN_LIGHTNING:
|
||||
return new ChainLightningMechanics(s);
|
||||
return make_unique<ChainLightningMechanics>(s);
|
||||
case SpellID::CLONE:
|
||||
return new CloneMechanics(s);
|
||||
return make_unique<CloneMechanics>(s);
|
||||
case SpellID::CURE:
|
||||
return new CureMechanics(s);
|
||||
return make_unique<CureMechanics>(s);
|
||||
case SpellID::DEATH_STARE:
|
||||
return new DeathStareMechanics(s);
|
||||
return make_unique<DeathStareMechanics>(s);
|
||||
case SpellID::DISPEL:
|
||||
return new DispellMechanics(s);
|
||||
return make_unique<DispellMechanics>(s);
|
||||
case SpellID::DISPEL_HELPFUL_SPELLS:
|
||||
return new DispellHelpfulMechanics(s);
|
||||
return make_unique<DispellHelpfulMechanics>(s);
|
||||
case SpellID::EARTHQUAKE:
|
||||
return new EarthquakeMechanics(s);
|
||||
return make_unique<EarthquakeMechanics>(s);
|
||||
case SpellID::FIRE_WALL:
|
||||
case SpellID::FORCE_FIELD:
|
||||
return new WallMechanics(s);
|
||||
return make_unique<WallMechanics>(s);
|
||||
case SpellID::HYPNOTIZE:
|
||||
return new HypnotizeMechanics(s);
|
||||
return make_unique<HypnotizeMechanics>(s);
|
||||
case SpellID::LAND_MINE:
|
||||
case SpellID::QUICKSAND:
|
||||
return new ObstacleMechanics(s);
|
||||
return make_unique<ObstacleMechanics>(s);
|
||||
case SpellID::REMOVE_OBSTACLE:
|
||||
return new RemoveObstacleMechanics(s);
|
||||
return make_unique<RemoveObstacleMechanics>(s);
|
||||
case SpellID::SACRIFICE:
|
||||
return new SacrificeMechanics(s);
|
||||
return make_unique<SacrificeMechanics>(s);
|
||||
case SpellID::SUMMON_FIRE_ELEMENTAL:
|
||||
return new SummonMechanics(s, CreatureID::FIRE_ELEMENTAL);
|
||||
return make_unique<SummonMechanics>(s, CreatureID::FIRE_ELEMENTAL);
|
||||
case SpellID::SUMMON_EARTH_ELEMENTAL:
|
||||
return new SummonMechanics(s, CreatureID::EARTH_ELEMENTAL);
|
||||
return make_unique<SummonMechanics>(s, CreatureID::EARTH_ELEMENTAL);
|
||||
case SpellID::SUMMON_WATER_ELEMENTAL:
|
||||
return new SummonMechanics(s, CreatureID::WATER_ELEMENTAL);
|
||||
return make_unique<SummonMechanics>(s, CreatureID::WATER_ELEMENTAL);
|
||||
case SpellID::SUMMON_AIR_ELEMENTAL:
|
||||
return new SummonMechanics(s, CreatureID::AIR_ELEMENTAL);
|
||||
return make_unique<SummonMechanics>(s, CreatureID::AIR_ELEMENTAL);
|
||||
case SpellID::TELEPORT:
|
||||
return new TeleportMechanics(s);
|
||||
return make_unique<TeleportMechanics>(s);
|
||||
default:
|
||||
if(s->isRisingSpell())
|
||||
return make_unique<SpecialRisingSpellMechanics>(s);
|
||||
else
|
||||
return make_unique<DefaultSpellMechanics>(s);
|
||||
}
|
||||
}
|
||||
|
||||
//IAdventureSpellMechanics
|
||||
IAdventureSpellMechanics::IAdventureSpellMechanics(CSpell * s):
|
||||
owner(s)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<IAdventureSpellMechanics> IAdventureSpellMechanics::createMechanics(CSpell * s)
|
||||
{
|
||||
switch (s->id)
|
||||
{
|
||||
case SpellID::SUMMON_BOAT:
|
||||
return new SummonBoatMechanics(s);
|
||||
return make_unique<SummonBoatMechanics>(s);
|
||||
case SpellID::SCUTTLE_BOAT:
|
||||
return new ScuttleBoatMechanics(s);
|
||||
return make_unique<ScuttleBoatMechanics>(s);
|
||||
case SpellID::DIMENSION_DOOR:
|
||||
return new DimensionDoorMechanics(s);
|
||||
return make_unique<DimensionDoorMechanics>(s);
|
||||
case SpellID::FLY:
|
||||
case SpellID::WATER_WALK:
|
||||
case SpellID::VISIONS:
|
||||
case SpellID::DISGUISE:
|
||||
return new DefaultSpellMechanics(s); //implemented using bonus system
|
||||
return make_unique<AdventureSpellMechanics>(s); //implemented using bonus system
|
||||
case SpellID::TOWN_PORTAL:
|
||||
return new TownPortalMechanics(s);
|
||||
return make_unique<TownPortalMechanics>(s);
|
||||
case SpellID::VIEW_EARTH:
|
||||
return new ViewEarthMechanics(s);
|
||||
return make_unique<ViewEarthMechanics>(s);
|
||||
case SpellID::VIEW_AIR:
|
||||
return new ViewAirMechanics(s);
|
||||
return make_unique<ViewAirMechanics>(s);
|
||||
default:
|
||||
if(s->isRisingSpell())
|
||||
return new SpecialRisingSpellMechanics(s);
|
||||
else
|
||||
return new DefaultSpellMechanics(s);
|
||||
return std::unique_ptr<IAdventureSpellMechanics>();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -76,12 +76,6 @@ private:
|
||||
void prepare(const CSpell * spell);
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE AdventureSpellCastParameters
|
||||
{
|
||||
const CGHeroInstance * caster;
|
||||
int3 pos;
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE SpellTargetingContext
|
||||
{
|
||||
CSpell::TargetInfo ti;
|
||||
@@ -112,13 +106,31 @@ public:
|
||||
virtual ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const = 0;
|
||||
|
||||
virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const = 0;
|
||||
virtual bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const = 0;
|
||||
virtual void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const = 0;
|
||||
|
||||
virtual void battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet,
|
||||
const std::string & casterName, const CStack * attackedStack, bool & displayDamage) const = 0;
|
||||
|
||||
static ISpellMechanics * createMechanics(CSpell * s);
|
||||
static std::unique_ptr<ISpellMechanics> createMechanics(CSpell * s);
|
||||
protected:
|
||||
CSpell * owner;
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE AdventureSpellCastParameters
|
||||
{
|
||||
const CGHeroInstance * caster;
|
||||
int3 pos;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE IAdventureSpellMechanics
|
||||
{
|
||||
public:
|
||||
IAdventureSpellMechanics(CSpell * s);
|
||||
virtual ~IAdventureSpellMechanics() = default;
|
||||
|
||||
virtual bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const = 0;
|
||||
|
||||
static std::unique_ptr<IAdventureSpellMechanics> createMechanics(CSpell * s);
|
||||
protected:
|
||||
CSpell * owner;
|
||||
};
|
||||
|
Reference in New Issue
Block a user