From fe1233310faf556845bc23d6583e77179b28c531 Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Tue, 25 Nov 2014 23:59:21 +0300 Subject: [PATCH] Centralize dispell mechanics --- lib/CSpellHandler.cpp | 6 ++ lib/CSpellHandler.h | 10 +-- lib/NetPacksLib.cpp | 26 +------- lib/SpellMechanics.cpp | 144 +++++++++++++++++++++++++++++++++++------ lib/SpellMechanics.h | 2 + 5 files changed, 143 insertions(+), 45 deletions(-) diff --git a/lib/CSpellHandler.cpp b/lib/CSpellHandler.cpp index d1bc7b6bc..2c54004c9 100644 --- a/lib/CSpellHandler.cpp +++ b/lib/CSpellHandler.cpp @@ -101,6 +101,12 @@ CSpell::~CSpell() delete mechanics; } +void CSpell::afterCast(BattleInfo * battle, const BattleSpellCast * packet) const +{ + mechanics->afterCast(battle, packet); +} + + void CSpell::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const { assert(env); diff --git a/lib/CSpellHandler.h b/lib/CSpellHandler.h index f21ad7bbc..d902333ba 100644 --- a/lib/CSpellHandler.h +++ b/lib/CSpellHandler.h @@ -31,6 +31,7 @@ class BattleInfo; struct CPackForClient; struct BattleSpellCast; + class CRandomGenerator; struct SpellSchoolInfo @@ -256,6 +257,10 @@ public: } friend class CSpellHandler; friend class Graphics; +public: + ///Client-Server events. Shall be called only when applying packets + void afterCast(BattleInfo * battle, const BattleSpellCast * packet) const; + private: void setIsOffensive(const bool val); void setIsRising(const bool val); @@ -323,10 +328,7 @@ public: { h & objects ; } -public: - ///Client-Server events. Shall be called only when applying packets - //void afterSpellCast(BattleInfo * battle, BattleSpellCast * packet) const; - + protected: CSpell * loadFromJson(const JsonNode & json) override; }; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index f97337886..60538d031 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -1343,29 +1343,9 @@ DLL_LINKAGE void BattleSpellCast::applyGs( CGameState *gs ) } } - //Handle spells removing effects from stacks - const CSpell *spell = SpellID(id).toSpell(); - const bool removeAllSpells = id == SpellID::DISPEL; - const bool removeHelpful = id == SpellID::DISPEL_HELPFUL_SPELLS; - - for(auto stackID : affectedCres) - { - if(vstd::contains(resisted, stackID)) - continue; - - CStack *s = gs->curB->getStack(stackID); - s->popBonuses([&](const Bonus *b) -> bool - { - //check for each bonus if it should be removed - const bool isSpellEffect = Selector::sourceType(Bonus::SPELL_EFFECT)(b); - const bool isPositiveSpell = Selector::positiveSpellEffects(b); - const int spellID = isSpellEffect ? b->sid : -1; - - return (removeHelpful && isPositiveSpell) - || (removeAllSpells && isSpellEffect) - || vstd::contains(spell->counteredSpells, spellID); - }); - } + const CSpell * spell = SpellID(id).toSpell(); + + spell->afterCast(gs->curB, this); } void actualizeEffect(CStack * s, const std::vector & ef) diff --git a/lib/SpellMechanics.cpp b/lib/SpellMechanics.cpp index 48b69a16f..66dd9700a 100644 --- a/lib/SpellMechanics.cpp +++ b/lib/SpellMechanics.cpp @@ -141,6 +141,8 @@ public: //bool adventureCast(const SpellCastContext & context) const override; void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const override; + + void afterCast(BattleInfo * battle, const BattleSpellCast * packet) const override; protected: virtual void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const; @@ -173,6 +175,14 @@ protected: void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override; }; +class CureMechanics: public DefaultSpellMechanics +{ +public: + CureMechanics(CSpell * s): DefaultSpellMechanics(s){}; + + void afterCast(BattleInfo * battle, const BattleSpellCast * packet) const override; +}; + class DeathStareMechnics: public DefaultSpellMechanics { public: @@ -185,9 +195,20 @@ class DispellHelpfulMechanics: public DefaultSpellMechanics { public: DispellHelpfulMechanics(CSpell * s): DefaultSpellMechanics(s){}; + + void afterCast(BattleInfo * battle, const BattleSpellCast * packet) const override; + ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override; }; +class DispellMechanics: public DefaultSpellMechanics +{ +public: + DispellMechanics(CSpell * s): DefaultSpellMechanics(s){}; + + void afterCast(BattleInfo * battle, const BattleSpellCast * packet) const override; +}; + class HypnotizeMechanics: public DefaultSpellMechanics { public: @@ -270,33 +291,39 @@ ISpellMechanics * ISpellMechanics::createMechanics(CSpell * s) { switch (s->id) { - case SpellID::CLONE: - return new CloneMechanics(s); - case SpellID::DISPEL_HELPFUL_SPELLS: - return new DispellHelpfulMechanics(s); - case SpellID::SACRIFICE: - return new SacrificeMechanics(s); + case SpellID::ACID_BREATH_DAMAGE: + return new AcidBreathDamageMechnics(s); case SpellID::CHAIN_LIGHTNING: return new ChainLightningMechanics(s); + case SpellID::CLONE: + return new CloneMechanics(s); + case SpellID::CURE: + return new CureMechanics(s); + case SpellID::DEATH_STARE: + return new DeathStareMechnics(s); + case SpellID::DISPEL: + return new DispellMechanics(s); + case SpellID::DISPEL_HELPFUL_SPELLS: + return new DispellHelpfulMechanics(s); case SpellID::FIRE_WALL: case SpellID::FORCE_FIELD: return new WallMechanics(s); + case SpellID::HYPNOTIZE: + return new HypnotizeMechanics(s); case SpellID::LAND_MINE: case SpellID::QUICKSAND: return new ObstacleMechanics(s); - case SpellID::TELEPORT: - return new TeleportMechanics(s); + case SpellID::REMOVE_OBSTACLE: + return new RemoveObstacleMechanics(s); + case SpellID::SACRIFICE: + return new SacrificeMechanics(s); case SpellID::SUMMON_FIRE_ELEMENTAL: case SpellID::SUMMON_EARTH_ELEMENTAL: case SpellID::SUMMON_WATER_ELEMENTAL: case SpellID::SUMMON_AIR_ELEMENTAL: return new SummonMechanics(s); - case SpellID::REMOVE_OBSTACLE: - return new RemoveObstacleMechanics(s); - case SpellID::DEATH_STARE: - return new DeathStareMechnics(s); - case SpellID::ACID_BREATH_DAMAGE: - return new AcidBreathDamageMechnics(s); + case SpellID::TELEPORT: + return new TeleportMechanics(s); default: if(s->isRisingSpell()) return new SpecialRisingSpellMechanics(s); @@ -307,11 +334,28 @@ ISpellMechanics * ISpellMechanics::createMechanics(CSpell * s) ///DefaultSpellMechanics +void DefaultSpellMechanics::afterCast(BattleInfo * battle, const BattleSpellCast * packet) const +{ + //TODO: may be move all from BattleSpellCast::applyGs here + + //handle countering spells + for(auto stackID : packet->affectedCres) + { + if(vstd::contains(packet->resisted, stackID)) + continue; + + CStack * s = battle->getStack(stackID); + s->popBonuses([&](const Bonus * b) -> bool + { + //check for each bonus if it should be removed + const bool isSpellEffect = Selector::sourceType(Bonus::SPELL_EFFECT)(b); + const int spellID = isSpellEffect ? b->sid : -1; + + return isSpellEffect && vstd::contains(owner->counteredSpells, spellID); + }); + } +} -//bool DefaultSpellMechanics::adventureCast(const SpellCastContext& context) const -//{ -// return false; //there is no general algorithm for casting adventure spells -//} void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const { @@ -893,6 +937,33 @@ ESpellCastProblem::ESpellCastProblem CloneMechanics::isImmuneByStack(const CGHer return DefaultSpellMechanics::isImmuneByStack(caster, obj); } +///CureMechanics +void CureMechanics::afterCast(BattleInfo * battle, const BattleSpellCast * packet) const +{ + DefaultSpellMechanics::afterCast(battle, packet); + + for(auto stackID : packet->affectedCres) + { + if(vstd::contains(packet->resisted, stackID)) + { + logGlobal->errorStream() << "Resistance to positive spell CURE"; + continue; + } + + CStack *s = battle->getStack(stackID); + s->popBonuses([&](const Bonus *b) -> bool + { + if(b->source == Bonus::SPELL_EFFECT) + { + CSpell * sp = SpellID(b->sid).toSpell(); + return sp->isNegative(); + } + return false; //not a spell effect + }); + } +} + + ///DeathStareMechnics void DeathStareMechnics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const { @@ -915,6 +986,24 @@ void DeathStareMechnics::applyBattleEffects(const SpellCastEnvironment * env, Ba ///DispellHelpfulMechanics +void DispellHelpfulMechanics::afterCast(BattleInfo * battle, const BattleSpellCast * packet) const +{ + DefaultSpellMechanics::afterCast(battle, packet); + + for(auto stackID : packet->affectedCres) + { + if(vstd::contains(packet->resisted, stackID)) + continue; + + CStack *s = battle->getStack(stackID); + s->popBonuses([&](const Bonus *b) -> bool + { + return Selector::positiveSpellEffects(b); + }); + } +} + + ESpellCastProblem::ESpellCastProblem DispellHelpfulMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const { TBonusListPtr spellBon = obj->getSpellBonuses(); @@ -936,6 +1025,25 @@ ESpellCastProblem::ESpellCastProblem DispellHelpfulMechanics::isImmuneByStack(co return DefaultSpellMechanics::isImmuneByStack(caster,obj); } +///DispellMechanics +void DispellMechanics::afterCast(BattleInfo * battle, const BattleSpellCast * packet) const +{ + DefaultSpellMechanics::afterCast(battle, packet); + + for(auto stackID : packet->affectedCres) + { + if(vstd::contains(packet->resisted, stackID)) + continue; + + CStack *s = battle->getStack(stackID); + s->popBonuses([&](const Bonus *b) -> bool + { + return Selector::sourceType(Bonus::SPELL_EFFECT)(b); + }); + } +} + + ///HypnotizeMechanics ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const { diff --git a/lib/SpellMechanics.h b/lib/SpellMechanics.h index 91ee4aefe..0c3b904f7 100644 --- a/lib/SpellMechanics.h +++ b/lib/SpellMechanics.h @@ -46,6 +46,8 @@ public: static ISpellMechanics * createMechanics(CSpell * s); + virtual void afterCast(BattleInfo * battle, const BattleSpellCast * packet) const = 0; + protected: CSpell * owner; };