diff --git a/client/adventureMap/AdventureMapInterface.cpp b/client/adventureMap/AdventureMapInterface.cpp index d09d6dd49..a00847ac7 100644 --- a/client/adventureMap/AdventureMapInterface.cpp +++ b/client/adventureMap/AdventureMapInterface.cpp @@ -47,6 +47,7 @@ #include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/pathfinder/CGPathNode.h" #include "../../lib/pathfinder/TurnInfo.h" +#include "../../lib/spells/adventure/AdventureSpellEffect.h" #include "../../lib/spells/ISpellMechanics.h" #include "../../lib/spells/Problem.h" @@ -612,13 +613,15 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition) if(spellBeingCasted) { - + const auto * hero = GAME->interface()->localState->getCurrentHero(); + const auto * spellEffect = spellBeingCasted->getAdventureMechanics().getEffectAs(hero); spells::detail::ProblemImpl problem; - if(isValidAdventureSpellTarget(targetPosition)) - ENGINE->cursor().set(spellBeingCasted->getAdventureMechanics().getCursorForTarget(GAME->interface()->cb.get(), GAME->interface()->localState->getCurrentHero(), targetPosition)); + if(spellEffect && spellEffect->canBeCastAtImpl(problem, GAME->interface()->cb.get(), hero, targetPosition)) + ENGINE->cursor().set(spellEffect->getCursorForTarget(GAME->interface()->cb.get(), hero, targetPosition)); else ENGINE->cursor().set(Cursor::Map::POINTER); + return; } diff --git a/client/mapView/MapRendererContext.cpp b/client/mapView/MapRendererContext.cpp index ce69f9842..5da7cd5c6 100644 --- a/client/mapView/MapRendererContext.cpp +++ b/client/mapView/MapRendererContext.cpp @@ -28,7 +28,7 @@ #include "../../lib/pathfinder/CGPathNode.h" #include "../../lib/spells/CSpellHandler.h" #include "../../lib/spells/ISpellMechanics.h" -#include "../../lib/spells/Problem.h" +#include "../../lib/spells/adventure/AdventureSpellEffect.h" MapRendererBaseContext::MapRendererBaseContext(const MapRendererContextState & viewState) : viewState(viewState) @@ -375,8 +375,8 @@ bool MapRendererAdventureContext::showSpellRange(const int3 & position) const if (!hero || !spell.hasValue()) return false; - spells::detail::ProblemImpl problem;; - return !spell.toSpell()->getAdventureMechanics().isTargetInRange(problem, GAME->interface()->cb.get(), hero, position); + const auto * spellEffect = spell.toSpell()->getAdventureMechanics().getEffectAs(hero); + return !spellEffect->isTargetInRange(GAME->interface()->cb.get(), hero, position); } MapRendererAdventureTransitionContext::MapRendererAdventureTransitionContext(const MapRendererContextState & viewState) diff --git a/lib/spells/ISpellMechanics.h b/lib/spells/ISpellMechanics.h index 71dae6d54..55ed17b08 100644 --- a/lib/spells/ISpellMechanics.h +++ b/lib/spells/ISpellMechanics.h @@ -30,6 +30,7 @@ class JsonNode; class CStack; class CGObjectInstance; class CGHeroInstance; +class IAdventureSpellEffect; namespace spells { @@ -354,13 +355,18 @@ public: virtual bool canBeCast(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const = 0; virtual bool canBeCastAt(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const = 0; - virtual bool isTargetInRange(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const = 0; - virtual std::string getCursorForTarget(const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const = 0; - virtual bool adventureCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const = 0; static std::unique_ptr createMechanics(const CSpell * s); + + template + const EffectType * getEffectAs(const spells::Caster * caster) const + { + return dynamic_cast(getEffect(caster)); + } protected: + virtual const IAdventureSpellEffect * getEffect(const spells::Caster * caster) const = 0; + const CSpell * owner; }; diff --git a/lib/spells/adventure/AdventureSpellEffect.cpp b/lib/spells/adventure/AdventureSpellEffect.cpp index 361691669..cf7958412 100644 --- a/lib/spells/adventure/AdventureSpellEffect.cpp +++ b/lib/spells/adventure/AdventureSpellEffect.cpp @@ -24,7 +24,7 @@ AdventureSpellRangedEffect::AdventureSpellRangedEffect(const JsonNode & config) { } -bool AdventureSpellRangedEffect::isTargetInRange(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const +bool AdventureSpellRangedEffect::isTargetInRange(const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const { if(!cb->isInTheMap(pos)) return false; diff --git a/lib/spells/adventure/AdventureSpellEffect.h b/lib/spells/adventure/AdventureSpellEffect.h index 4ad663f30..f1ffcf1b4 100644 --- a/lib/spells/adventure/AdventureSpellEffect.h +++ b/lib/spells/adventure/AdventureSpellEffect.h @@ -34,7 +34,6 @@ public: virtual void endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const {}; virtual bool canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const {return true;}; virtual bool canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const {return true;}; - virtual bool isTargetInRange(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const {return true;}; virtual std::string getCursorForTarget(const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const {return {};}; }; @@ -53,8 +52,9 @@ class AdventureSpellRangedEffect : public IAdventureSpellEffect public: AdventureSpellRangedEffect(const JsonNode & config); - bool isTargetInRange(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const final; - std::string getCursorForTarget(const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const override = 0; //must be implemented in derived + DLL_LINKAGE bool isTargetInRange(const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const; + std::string getCursorForTarget(const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const override = 0; //must be implemented in derived classes + bool canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const override = 0; //must be implemented in derived classes }; VCMI_LIB_NAMESPACE_END diff --git a/lib/spells/adventure/AdventureSpellMechanics.cpp b/lib/spells/adventure/AdventureSpellMechanics.cpp index fbdb58d68..ada8dd9ed 100644 --- a/lib/spells/adventure/AdventureSpellMechanics.cpp +++ b/lib/spells/adventure/AdventureSpellMechanics.cpp @@ -79,6 +79,11 @@ const AdventureSpellMechanics::LevelOptions & AdventureSpellMechanics::getLevel( return levelOptions.at(schoolLevel); } +const IAdventureSpellEffect * AdventureSpellMechanics::getEffect(const spells::Caster * caster) const +{ + return getLevel(caster).effect.get(); +} + bool AdventureSpellMechanics::canBeCast(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const { if(!owner->isAdventure()) @@ -125,16 +130,6 @@ bool AdventureSpellMechanics::canBeCastAt(spells::Problem & problem, const IGame return canBeCast(problem, cb, caster) && getLevel(caster).effect->canBeCastAtImpl(problem, cb, caster, pos); } -bool AdventureSpellMechanics::isTargetInRange(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const -{ - return getLevel(caster).effect->isTargetInRange(problem, cb, caster, pos); -} - -std::string AdventureSpellMechanics::getCursorForTarget(const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const -{ - return getLevel(caster).effect->getCursorForTarget(cb, caster, pos); -} - bool AdventureSpellMechanics::adventureCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const { spells::detail::ProblemImpl problem; diff --git a/lib/spells/adventure/AdventureSpellMechanics.h b/lib/spells/adventure/AdventureSpellMechanics.h index 08d5a765e..cad20504f 100644 --- a/lib/spells/adventure/AdventureSpellMechanics.h +++ b/lib/spells/adventure/AdventureSpellMechanics.h @@ -28,19 +28,17 @@ class AdventureSpellMechanics final : public IAdventureSpellMechanics, boost::no std::array levelOptions; + const LevelOptions & getLevel(const spells::Caster * caster) const; + void giveBonuses(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const; + public: AdventureSpellMechanics(const CSpell * s); ~AdventureSpellMechanics(); - const LevelOptions & getLevel(const spells::Caster * caster) const; - bool canBeCast(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const final; bool canBeCastAt(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const final; - bool isTargetInRange(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const final; - std::string getCursorForTarget(const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const final; bool adventureCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const final; - - void giveBonuses(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const; + const IAdventureSpellEffect * getEffect(const spells::Caster * caster) const final; void performCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const; }; diff --git a/lib/spells/adventure/DimensionDoorEffect.cpp b/lib/spells/adventure/DimensionDoorEffect.cpp index 99143c2c1..11f99ed30 100644 --- a/lib/spells/adventure/DimensionDoorEffect.cpp +++ b/lib/spells/adventure/DimensionDoorEffect.cpp @@ -62,7 +62,7 @@ bool DimensionDoorEffect::canBeCastImpl(spells::Problem & problem, const IGameIn bool DimensionDoorEffect::canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const { - if (!isTargetInRange(problem, cb, caster, pos)) + if (!isTargetInRange(cb, caster, pos)) return false; int3 casterPosition = caster->getHeroCaster()->getSightCenter(); diff --git a/lib/spells/adventure/RemoveObjectEffect.cpp b/lib/spells/adventure/RemoveObjectEffect.cpp index f75b43054..ea1dcfbf2 100644 --- a/lib/spells/adventure/RemoveObjectEffect.cpp +++ b/lib/spells/adventure/RemoveObjectEffect.cpp @@ -46,7 +46,7 @@ std::string RemoveObjectEffect::getCursorForTarget(const IGameInfoCallback * cb, bool RemoveObjectEffect::canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const { - if (!isTargetInRange(problem, cb, caster, pos)) + if (!isTargetInRange(cb, caster, pos)) return false; const TerrainTile * t = cb->getTile(pos);