diff --git a/lib/spells/AdventureSpellMechanics.cpp b/lib/spells/AdventureSpellMechanics.cpp index 4aaf8e756..6bf90ed3b 100644 --- a/lib/spells/AdventureSpellMechanics.cpp +++ b/lib/spells/AdventureSpellMechanics.cpp @@ -119,29 +119,31 @@ ESpellCastResult AdventureSpellMechanics::applyAdventureEffects(SpellCastEnviron ESpellCastResult AdventureSpellMechanics::beginCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const { - return ESpellCastResult::OK; + return ESpellCastResult::OK; +} + +void AdventureSpellMechanics::endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const +{ + // no-op, only for implementation in derived classes } void AdventureSpellMechanics::performCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const { + const auto level = parameters.caster->getSpellSchoolLevel(owner); + const auto cost = owner->getCost(level); + AdvmapSpellCast asc; asc.casterID = ObjectInstanceID(parameters.caster->getCasterUnitId()); asc.spellID = owner->id; env->apply(&asc); ESpellCastResult result = applyAdventureEffects(env, parameters); - endCast(env, parameters, result); -} - -void AdventureSpellMechanics::endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters, const ESpellCastResult result) const -{ - const auto level = parameters.caster->getSpellSchoolLevel(owner); - const auto cost = owner->getCost(level); switch(result) { case ESpellCastResult::OK: parameters.caster->spendMana(env, cost); + endCast(env, parameters); break; default: break; @@ -427,10 +429,17 @@ ESpellCastResult DimensionDoorMechanics::applyAdventureEffects(SpellCastEnvironm smp.val = 0; env->apply(&smp); + return ESpellCastResult::OK; +} + +void DimensionDoorMechanics::endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const +{ + int3 casterPosition = parameters.caster->getHeroCaster()->getSightCenter(); + const TerrainTile * dest = env->getCb()->getTile(parameters.pos); + const TerrainTile * curr = env->getCb()->getTile(casterPosition); + if(dest->isClear(curr)) env->moveHero(ObjectInstanceID(parameters.caster->getCasterUnitId()), parameters.caster->getHeroCaster()->convertFromVisitablePos(parameters.pos), true); - - return ESpellCastResult::OK; } ///TownPortalMechanics @@ -526,6 +535,26 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(SpellCastEnvironment return ESpellCastResult::ERROR; } + return ESpellCastResult::OK; +} + +void TownPortalMechanics::endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const +{ + const int moveCost = movementCost(parameters); + const CGTownInstance * destination = nullptr; + + if(parameters.caster->getSpellSchoolLevel(owner) < 2) + { + std::vector pool = getPossibleTowns(env, parameters); + destination = findNearestTown(env, parameters, pool); + } + else + { + const TerrainTile & tile = env->getMap()->getTile(parameters.pos); + auto * const topObj = tile.topVisitableObj(false); + destination = dynamic_cast(topObj); + } + if(env->moveHero(ObjectInstanceID(parameters.caster->getCasterUnitId()), parameters.caster->getHeroCaster()->convertFromVisitablePos(destination->visitablePos()), true)) { SetMovePoints smp; @@ -533,7 +562,6 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(SpellCastEnvironment smp.val = std::max(0, parameters.caster->getHeroCaster()->movementPointsRemaining() - moveCost); env->apply(&smp); } - return ESpellCastResult::OK; } ESpellCastResult TownPortalMechanics::beginCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const diff --git a/lib/spells/AdventureSpellMechanics.h b/lib/spells/AdventureSpellMechanics.h index 5ee2c02a0..4b745d66d 100644 --- a/lib/spells/AdventureSpellMechanics.h +++ b/lib/spells/AdventureSpellMechanics.h @@ -18,10 +18,10 @@ class CGTownInstance; enum class ESpellCastResult { - OK, - CANCEL,//cast failed but it is not an error + OK, // cast successful + CANCEL, // cast failed but it is not an error, no mana has been spent PENDING, - ERROR//internal error occurred + ERROR// error occured, for example invalid request from player }; class AdventureSpellMechanics : public IAdventureSpellMechanics @@ -37,11 +37,11 @@ protected: ///actual adventure cast implementation virtual ESpellCastResult applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const; virtual ESpellCastResult beginCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const; + virtual void endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const; virtual bool canBeCastImpl(spells::Problem & problem, const CGameInfoCallback * cb, const spells::Caster * caster) const; virtual bool canBeCastAtImpl(spells::Problem & problem, const CGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const; void performCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const; - void endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters, const ESpellCastResult result) const; }; class SummonBoatMechanics final : public AdventureSpellMechanics @@ -73,6 +73,7 @@ protected: bool canBeCastAtImpl(spells::Problem & problem, const CGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const override; ESpellCastResult applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override; + void endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override; }; class TownPortalMechanics final : public AdventureSpellMechanics @@ -82,6 +83,7 @@ public: protected: ESpellCastResult applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override; ESpellCastResult beginCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override; + void endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override; private: const CGTownInstance * findNearestTown(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters, const std::vector & pool) const; int32_t movementCost(const AdventureSpellCastParameters & parameters) const;