Переглянути джерело

Adventure spell API refactoring to ease use by AI

Ivan Savenko 3 місяців тому
батько
коміт
7a1ede1e38

+ 6 - 3
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<AdventureSpellRangedEffect>(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;
 	}
 

+ 3 - 3
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<AdventureSpellRangedEffect>(hero);
+	return !spellEffect->isTargetInRange(GAME->interface()->cb.get(), hero, position);
 }
 
 MapRendererAdventureTransitionContext::MapRendererAdventureTransitionContext(const MapRendererContextState & viewState)

+ 9 - 3
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<IAdventureSpellMechanics> createMechanics(const CSpell * s);
+
+	template<typename EffectType>
+	const EffectType * getEffectAs(const spells::Caster * caster) const
+	{
+		return dynamic_cast<const EffectType *>(getEffect(caster));
+	}
 protected:
+	virtual const IAdventureSpellEffect * getEffect(const spells::Caster * caster) const = 0;
+
 	const CSpell * owner;
 };
 

+ 1 - 1
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;

+ 3 - 3
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

+ 5 - 10
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;

+ 4 - 6
lib/spells/adventure/AdventureSpellMechanics.h

@@ -28,19 +28,17 @@ class AdventureSpellMechanics final : public IAdventureSpellMechanics, boost::no
 
 	std::array<LevelOptions, GameConstants::SPELL_SCHOOL_LEVELS> 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;
 };
 

+ 1 - 1
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();

+ 1 - 1
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);