1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-06 09:09:40 +02:00

Removed hardcoded checks for Summon Boat spell

This commit is contained in:
Ivan Savenko
2025-07-11 17:11:01 +03:00
parent 7a1ede1e38
commit b0c511149d
10 changed files with 68 additions and 26 deletions

View File

@@ -92,7 +92,7 @@ namespace AIPathfinding
void SummonBoatAction::execute(AIGateway * ai, const CGHeroInstance * hero) const void SummonBoatAction::execute(AIGateway * ai, const CGHeroInstance * hero) const
{ {
Goals::AdventureSpellCast(hero, SpellID::SUMMON_BOAT).accept(ai); Goals::AdventureSpellCast(hero, usedSpell).accept(ai);
} }
const ChainActor * SummonBoatAction::getActor(const ChainActor * sourceActor) const const ChainActor * SummonBoatAction::getActor(const ChainActor * sourceActor) const
@@ -139,10 +139,8 @@ namespace AIPathfinding
int32_t SummonBoatAction::getManaCost(const CGHeroInstance * hero) const int32_t SummonBoatAction::getManaCost(const CGHeroInstance * hero) const
{ {
SpellID summonBoat = SpellID::SUMMON_BOAT;
// FIXME: this should be hero->getSpellCost, however currently queries to bonus system are too slow // FIXME: this should be hero->getSpellCost, however currently queries to bonus system are too slow
return summonBoat.toSpell()->getCost(0); return usedSpell.toSpell()->getCost(0);
} }
} }

View File

@@ -24,7 +24,13 @@ namespace AIPathfinding
class SummonBoatAction : public VirtualBoatAction class SummonBoatAction : public VirtualBoatAction
{ {
SpellID usedSpell;
public: public:
SummonBoatAction(SpellID usedSpell)
: usedSpell(usedSpell)
{
}
void execute(AIGateway * ai, const CGHeroInstance * hero) const override; void execute(AIGateway * ai, const CGHeroInstance * hero) const override;
virtual void applyOnDestination( virtual void applyOnDestination(

View File

@@ -12,6 +12,8 @@
#include "../../Engine/Nullkiller.h" #include "../../Engine/Nullkiller.h"
#include "../../../../lib/pathfinder/CPathfinder.h" #include "../../../../lib/pathfinder/CPathfinder.h"
#include "../../../../lib/pathfinder/TurnInfo.h" #include "../../../../lib/pathfinder/TurnInfo.h"
#include "../../../../lib/spells/ISpellMechanics.h"
#include "../../../../lib/spells/adventure/SummonBoatEffect.h"
namespace NKAI namespace NKAI
{ {
@@ -159,13 +161,21 @@ namespace AIPathfinding
for(const CGHeroInstance * hero : nodeStorage->getAllHeroes()) for(const CGHeroInstance * hero : nodeStorage->getAllHeroes())
{ {
auto summonBoatSpell = SpellID(SpellID::SUMMON_BOAT).toSpell(); for (const auto & spell : LIBRARY->spellh->objects)
if(hero->canCastThisSpell(summonBoatSpell)
&& hero->getSpellSchoolLevel(summonBoatSpell) >= MasteryLevel::ADVANCED)
{ {
// TODO: For lower school level we might need to check the existence of some boat if (!spell || !spell->isAdventure())
summonableVirtualBoats[hero] = std::make_shared<SummonBoatAction>(); continue;
auto effect = spell->getAdventureMechanics().getEffectAs<SummonBoatEffect>(hero);
if (!effect || !hero->canCastThisSpell(spell.get()))
continue;
if (effect->canCreateNewBoat() && effect->getSuccessChance(hero) == 100)
{
// TODO: For lower school level we might need to check the existence of some boat
summonableVirtualBoats[hero] = std::make_shared<SummonBoatAction>(spell->id);
}
} }
} }
} }

View File

@@ -23,7 +23,7 @@ namespace AIPathfinding
Goals::TSubgoal SummonBoatAction::whatToDo(const HeroPtr & hero) const Goals::TSubgoal SummonBoatAction::whatToDo(const HeroPtr & hero) const
{ {
return Goals::sptr(Goals::AdventureSpellCast(hero, SpellID::SUMMON_BOAT)); return Goals::sptr(Goals::AdventureSpellCast(hero, usedSpell));
} }
void SummonBoatAction::applyOnDestination( void SummonBoatAction::applyOnDestination(
@@ -53,8 +53,6 @@ namespace AIPathfinding
uint32_t SummonBoatAction::getManaCost(const CGHeroInstance * hero) const uint32_t SummonBoatAction::getManaCost(const CGHeroInstance * hero) const
{ {
SpellID summonBoat = SpellID::SUMMON_BOAT; return hero->getSpellCost(usedSpell.toSpell());
return hero->getSpellCost(summonBoat.toSpell());
} }
} }

View File

@@ -34,9 +34,11 @@ namespace AIPathfinding
class SummonBoatAction : public VirtualBoatAction class SummonBoatAction : public VirtualBoatAction
{ {
SpellID usedSpell;
public: public:
SummonBoatAction() SummonBoatAction(SpellID usedSpell)
:VirtualBoatAction(AINodeStorage::CAST_CHAIN) :VirtualBoatAction(AINodeStorage::CAST_CHAIN)
,usedSpell(usedSpell)
{ {
} }

View File

@@ -10,6 +10,9 @@
#include "StdInc.h" #include "StdInc.h"
#include "AILayerTransitionRule.h" #include "AILayerTransitionRule.h"
#include "../../../../lib/spells/ISpellMechanics.h"
#include "../../../../lib/spells/adventure/SummonBoatEffect.h"
namespace AIPathfinding namespace AIPathfinding
{ {
AILayerTransitionRule::AILayerTransitionRule(CPlayerSpecificInfoCallback * cb, VCAI * ai, std::shared_ptr<AINodeStorage> nodeStorage) AILayerTransitionRule::AILayerTransitionRule(CPlayerSpecificInfoCallback * cb, VCAI * ai, std::shared_ptr<AINodeStorage> nodeStorage)
@@ -74,13 +77,22 @@ namespace AIPathfinding
} }
auto hero = nodeStorage->getHero(); auto hero = nodeStorage->getHero();
auto summonBoatSpell = SpellID(SpellID::SUMMON_BOAT).toSpell();
if(hero->canCastThisSpell(summonBoatSpell) for (const auto & spell : LIBRARY->spellh->objects)
&& hero->getSpellSchoolLevel(summonBoatSpell) >= MasteryLevel::ADVANCED)
{ {
// TODO: For lower school level we might need to check the existence of some boat if (!spell || !spell->isAdventure())
summonableVirtualBoat.reset(new SummonBoatAction()); continue;
auto effect = spell->getAdventureMechanics().getEffectAs<SummonBoatEffect>(hero);
if (!effect || !hero->canCastThisSpell(spell.get()))
continue;
if (effect->canCreateNewBoat() && effect->getSuccessChance(hero) == 100)
{
// TODO: For lower school level we might need to check the existence of some boat
summonableVirtualBoat.reset(new SummonBoatAction(spell->id));
}
} }
} }

View File

@@ -67,6 +67,10 @@ VCMI_LIB_NAMESPACE_BEGIN
getName = reinterpret_cast<TGetNameFun>(dlsym(dll, "GetAiName")); getName = reinterpret_cast<TGetNameFun>(dlsym(dll, "GetAiName"));
getAI = reinterpret_cast<TGetAIFun>(dlsym(dll, methodName.c_str())); getAI = reinterpret_cast<TGetAIFun>(dlsym(dll, methodName.c_str()));
} }
else
{
logGlobal->error("Cannot open dynamic library '%s'. Reason: %s", libpath.string(), dlerror());
}
#endif // VCMI_WINDOWS #endif // VCMI_WINDOWS
if (!dll) if (!dll)

View File

@@ -43,7 +43,7 @@ public:
AdventureSpellEffect() = default; AdventureSpellEffect() = default;
}; };
class AdventureSpellRangedEffect : public IAdventureSpellEffect class DLL_LINKAGE AdventureSpellRangedEffect : public IAdventureSpellEffect
{ {
int rangeX; int rangeX;
int rangeY; int rangeY;
@@ -52,7 +52,7 @@ class AdventureSpellRangedEffect : public IAdventureSpellEffect
public: public:
AdventureSpellRangedEffect(const JsonNode & config); AdventureSpellRangedEffect(const JsonNode & config);
DLL_LINKAGE bool isTargetInRange(const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const; 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 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 bool canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const override = 0; //must be implemented in derived classes
}; };

View File

@@ -28,6 +28,17 @@ SummonBoatEffect::SummonBoatEffect(const CSpell * s, const JsonNode & config)
{ {
} }
bool SummonBoatEffect::canCreateNewBoat() const
{
return createNewBoat;
}
int SummonBoatEffect::getSuccessChance(const spells::Caster * caster) const
{
const auto schoolLevel = caster->getSpellSchoolLevel(owner);
return owner->getLevelPower(schoolLevel);
}
bool SummonBoatEffect::canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const bool SummonBoatEffect::canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const
{ {
if(!caster->getHeroCaster()) if(!caster->getHeroCaster())
@@ -56,10 +67,8 @@ bool SummonBoatEffect::canBeCastImpl(spells::Problem & problem, const IGameInfoC
ESpellCastResult SummonBoatEffect::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const ESpellCastResult SummonBoatEffect::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{ {
const auto schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
//check if spell works at all //check if spell works at all
if(env->getRNG()->nextInt(0, 99) >= owner->getLevelPower(schoolLevel)) //power is % chance of success if(env->getRNG()->nextInt(0, 99) >= getSuccessChance(parameters.caster)) //power is % chance of success
{ {
InfoWindow iw; InfoWindow iw;
iw.player = parameters.caster->getCasterOwner(); iw.player = parameters.caster->getCasterOwner();

View File

@@ -14,7 +14,7 @@
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
class SummonBoatEffect final : public IAdventureSpellEffect class DLL_LINKAGE SummonBoatEffect final : public IAdventureSpellEffect
{ {
const CSpell * owner; const CSpell * owner;
bool useExistingBoat; bool useExistingBoat;
@@ -23,6 +23,9 @@ class SummonBoatEffect final : public IAdventureSpellEffect
public: public:
SummonBoatEffect(const CSpell * s, const JsonNode & config); SummonBoatEffect(const CSpell * s, const JsonNode & config);
bool canCreateNewBoat() const;
int getSuccessChance(const spells::Caster * caster) const;
protected: protected:
bool canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const final; bool canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const final;