diff options
Diffstat (limited to 'src/server')
26 files changed, 262 insertions, 95 deletions
| diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index ee70cb1dea2..5801aaa6a22 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -2931,6 +2931,8 @@ SpellCastResult WorldObject::CastSpell(CastSpellTargetArg const& targets, uint32      }      spell->m_customArg = args.CustomArg; +    spell->m_scriptResult = args.ScriptResult; +    spell->m_scriptWaitsForSpellHit = args.ScriptWaitsForSpellHit;      return spell->prepare(*targets.Targets, args.TriggeringAura);  } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 59c2f990f6a..a59c6b47328 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -22501,7 +22501,7 @@ UF::PVPInfo const* Player::GetPvpInfoForBracket(int8 bracket) const  }  bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc /*= nullptr*/, uint32 spellid /*= 0*/, uint32 preferredMountDisplay /*= 0*/, -    Optional<float> speed /*= {}*/) +    Optional<float> speed /*= {}*/, Optional<Scripting::v2::ActionResultSetter<MovementStopReason>> const& scriptResult /*= {}*/)  {      if (nodes.size() < 2)      { @@ -22681,18 +22681,19 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc          ModifyMoney(-int64(firstcost));          UpdateCriteria(CriteriaType::MoneySpentOnTaxis, firstcost);          GetSession()->SendActivateTaxiReply(ERR_TAXIOK); -        StartTaxiMovement(mount_display_id, sourcepath, 0, speed); +        StartTaxiMovement(mount_display_id, sourcepath, 0, speed, Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>(scriptResult));      }      return true;  } -bool Player::ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid /*= 0*/, Optional<float> speed /*= {}*/) +bool Player::ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid /*= 0*/, Optional<float> speed /*= {}*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>> const& scriptResult /*= {}*/)  {      TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(taxi_path_id);      if (!entry)          return false; -    return ActivateTaxiPathTo({ { entry->FromTaxiNode, entry->ToTaxiNode } }, nullptr, spellid, 0, speed); +    return ActivateTaxiPathTo({ { entry->FromTaxiNode, entry->ToTaxiNode } }, nullptr, spellid, 0, speed, scriptResult);  }  void Player::FinishTaxiFlight() @@ -22758,10 +22759,11 @@ void Player::ContinueTaxiFlight()          }      } -    StartTaxiMovement(mountDisplayId, path, startNode, {}); +    StartTaxiMovement(mountDisplayId, path, startNode, {}, {});  } -void Player::StartTaxiMovement(uint32 mountDisplayId, uint32 path, uint32 pathNode, Optional<float> speed) +void Player::StartTaxiMovement(uint32 mountDisplayId, uint32 path, uint32 pathNode, Optional<float> speed, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult)  {      // remove fake death      RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Interacting); @@ -22769,7 +22771,7 @@ void Player::StartTaxiMovement(uint32 mountDisplayId, uint32 path, uint32 pathNo      if (mountDisplayId)          Mount(mountDisplayId); -    GetMotionMaster()->MoveTaxiFlight(path, pathNode, speed); +    GetMotionMaster()->MoveTaxiFlight(path, pathNode, speed, std::move(scriptResult));  }  void Player::InitDataForForm(bool reapplyMods) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index e4b62c7bafc..9e28636a07f 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -103,6 +103,7 @@ enum InventoryType : uint8;  enum ItemClass : uint8;  enum LootError : uint8;  enum LootType : uint8; +enum class MovementStopReason : uint8;  enum PlayerRestState : uint8;  enum class PlayerCreateMode : int8;  enum RestTypes : uint8; @@ -1164,12 +1165,15 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>          PlayerTaxi m_taxi;          void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(GetRace(), GetClass(), GetLevel()); } -        bool ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc = nullptr, uint32 spellid = 0, uint32 preferredMountDisplay = 0, Optional<float> speed = {}); -        bool ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid = 0, Optional<float> speed = {}); +        bool ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc = nullptr, uint32 spellid = 0, uint32 preferredMountDisplay = 0, Optional<float> speed = {}, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>> const& scriptResult = {}); +        bool ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid = 0, Optional<float> speed = {}, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>> const& scriptResult = {});          void FinishTaxiFlight();          void CleanupAfterTaxiFlight();          void ContinueTaxiFlight(); -        void StartTaxiMovement(uint32 mountDisplayId, uint32 path, uint32 pathNode, Optional<float> speed); +        void StartTaxiMovement(uint32 mountDisplayId, uint32 path, uint32 pathNode, Optional<float> speed, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult);          bool IsDeveloper() const { return HasPlayerFlag(PLAYER_FLAGS_DEVELOPER); }          void SetDeveloper(bool on) { if (on) SetPlayerFlag(PLAYER_FLAGS_DEVELOPER); else RemovePlayerFlag(PLAYER_FLAGS_DEVELOPER); } diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 5fadcff5f58..7b43eea41ae 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -46,6 +46,7 @@  #include "GenericMovementGenerator.h"  #include "HomeMovementGenerator.h"  #include "IdleMovementGenerator.h" +#include "Memory.h"  #include "PointMovementGenerator.h"  #include "RandomMovementGenerator.h"  #include "SplineChainMovementGenerator.h" @@ -596,23 +597,31 @@ void MotionMaster::MoveTargetedHome()      }  } -void MotionMaster::MoveRandom(float wanderDistance, Optional<Milliseconds> duration, MovementSlot slot /*= MOTION_SLOT_DEFAULT*/) +void MotionMaster::MoveRandom(float wanderDistance /*= 0.0f*/, Optional<Milliseconds> duration /*= {}*/, MovementSlot slot /*= MOTION_SLOT_DEFAULT*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  {      if (_owner->GetTypeId() == TYPEID_UNIT)      {          TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveRandom: '{}', started random movement (spawnDist: {})", _owner->GetGUID(), wanderDistance); -        Add(new RandomMovementGenerator<Creature>(wanderDistance, duration), slot); +        Add(new RandomMovementGenerator<Creature>(wanderDistance, duration, std::move(scriptResult)), slot);      } +    else if (scriptResult) +        scriptResult->SetResult(MovementStopReason::Interrupted);  } -void MotionMaster::MoveFollow(Unit* target, float dist, ChaseAngle angle, Optional<Milliseconds> duration /*= {}*/, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/) +void MotionMaster::MoveFollow(Unit* target, float dist, ChaseAngle angle, Optional<Milliseconds> duration /*= {}*/, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  {      // Ignore movement request if target not exist      if (!target || target == _owner) +    { +        if (scriptResult) +            scriptResult->SetResult(MovementStopReason::Interrupted);          return; +    }      TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFollow: '{}', starts following '{}'", _owner->GetGUID(), target->GetGUID()); -    Add(new FollowMovementGenerator(target, dist, angle, duration), slot); +    Add(new FollowMovementGenerator(target, dist, angle, duration, std::move(scriptResult)), slot);  }  void MotionMaster::MoveChase(Unit* target, Optional<ChaseRange> dist, Optional<ChaseAngle> angle) @@ -639,29 +648,36 @@ void MotionMaster::MoveConfused()      }  } -void MotionMaster::MoveFleeing(Unit* enemy, Milliseconds time /*= 0ms*/) +void MotionMaster::MoveFleeing(Unit* enemy, Milliseconds time /*= 0ms*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  {      if (!enemy) +    { +        if (scriptResult) +            scriptResult->SetResult(MovementStopReason::Interrupted);          return; +    }      TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFleeing: '{}', flees from '{}' (time: {}ms)", _owner->GetGUID(), enemy->GetGUID(), time.count());      if (_owner->GetTypeId() == TYPEID_UNIT && time > 0ms) -        Add(new TimedFleeingMovementGenerator(enemy->GetGUID(), time)); +        Add(new TimedFleeingMovementGenerator(enemy->GetGUID(), time, std::move(scriptResult)));      else -        Add(new FleeingMovementGenerator(enemy->GetGUID())); +        Add(new FleeingMovementGenerator(enemy->GetGUID(), std::move(scriptResult)));  }  void MotionMaster::MovePoint(uint32 id, Position const& pos, bool generatePath/* = true*/, Optional<float> finalOrient/* = {}*/, Optional<float> speed /*= {}*/, -    MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/, Optional<float> closeEnoughDistance /*= {}*/) +    MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/, Optional<float> closeEnoughDistance /*= {}*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  { -    MovePoint(id, pos.m_positionX, pos.m_positionY, pos.m_positionZ, generatePath, finalOrient, speed, speedSelectionMode, closeEnoughDistance); +    MovePoint(id, pos.m_positionX, pos.m_positionY, pos.m_positionZ, generatePath, finalOrient, speed, speedSelectionMode, closeEnoughDistance, std::move(scriptResult));  }  void MotionMaster::MovePoint(uint32 id, float x, float y, float z, bool generatePath /*= true*/, Optional<float> finalOrient /*= {}*/, Optional<float> speed /*= {}*/, -    MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/, Optional<float> closeEnoughDistance /*= {}*/) +    MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/, Optional<float> closeEnoughDistance /*= {}*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  {      TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePoint: '{}', targeted point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID(), id, x, y, z); -    Add(new PointMovementGenerator(id, x, y, z, generatePath, speed, finalOrient, nullptr, nullptr, speedSelectionMode, closeEnoughDistance)); +    Add(new PointMovementGenerator(id, x, y, z, generatePath, speed, finalOrient, nullptr, nullptr, speedSelectionMode, closeEnoughDistance, std::move(scriptResult)));  }  void MotionMaster::MoveCloserAndStop(uint32 id, Unit* target, float distance) @@ -688,14 +704,15 @@ void MotionMaster::MoveCloserAndStop(uint32 id, Unit* target, float distance)  }  void MotionMaster::MoveLand(uint32 id, Position const& pos, Optional<int32> tierTransitionId /*= {}*/, Optional<float> velocity /*= {}*/, -    MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/) +    MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  {      TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveLand: '{}', landing point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID(), id, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());      std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)      {          init.MoveTo(PositionToVector3(pos), false); -        init.SetAnimation(AnimTier::Ground, tierTransitionId.value_or(0)); +        init.SetAnimation(AnimTier::Ground, tierTransitionId.value_or(1));          switch (speedSelectionMode)          {              case MovementWalkRunSpeedSelectionMode::ForceRun: @@ -711,18 +728,19 @@ void MotionMaster::MoveLand(uint32 id, Position const& pos, Optional<int32> tier          if (velocity)              init.SetVelocity(*velocity);      }; -    Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id)); +    Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id, { .ScriptResult = std::move(scriptResult) }));  }  void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, Optional<int32> tierTransitionId /*= {}*/, Optional<float> velocity /*= {}*/, -    MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/) +    MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  {      TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTakeoff: '{}', landing point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID(), id, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());      std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)      {          init.MoveTo(PositionToVector3(pos), false); -        init.SetAnimation(AnimTier::Hover, tierTransitionId.value_or(0)); +        init.SetAnimation(AnimTier::Hover, tierTransitionId.value_or(15));          switch (speedSelectionMode)          {              case MovementWalkRunSpeedSelectionMode::ForceRun: @@ -738,7 +756,7 @@ void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, Optional<int32> t          if (velocity)              init.SetVelocity(*velocity);      }; -    Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id)); +    Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id, { .ScriptResult = std::move(scriptResult) }));  }  void MotionMaster::MoveCharge(float x, float y, float z, float speed /*= SPEED_CHARGE*/, uint32 id /*= EVENT_CHARGE*/, bool generatePath /*= false*/, @@ -826,17 +844,24 @@ void MotionMaster::MoveJumpTo(float angle, float speedXY, float speedZ)  }  void MotionMaster::MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id/* = EVENT_JUMP*/, bool hasOrientation/* = false*/, -    JumpArrivalCastArgs const* arrivalCast /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/) +    JumpArrivalCastArgs const* arrivalCast /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  { -    MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), speedXY, speedZ, id, hasOrientation, arrivalCast, spellEffectExtraData); +    MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), speedXY, speedZ, id, hasOrientation, +        arrivalCast, spellEffectExtraData, std::move(scriptResult));  }  void MotionMaster::MoveJump(float x, float y, float z, float o, float speedXY, float speedZ, uint32 id /*= EVENT_JUMP*/, bool hasOrientation /* = false*/, -    JumpArrivalCastArgs const* arrivalCast /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/) +    JumpArrivalCastArgs const* arrivalCast /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  {      TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveJump: '{}', jumps to point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID(), id, x, y, z);      if (speedXY < 0.01f) +    { +        if (scriptResult) +            scriptResult->SetResult(MovementStopReason::Interrupted);          return; +    }      float moveTimeHalf = speedZ / Movement::gravity;      float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -speedZ); @@ -861,18 +886,23 @@ void MotionMaster::MoveJump(float x, float y, float z, float o, float speedXY, f      }      GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id, -        { .ArrivalSpellId = arrivalSpellId, .ArrivalSpellTarget = arrivalSpellTargetGuid }); +        { .ArrivalSpellId = arrivalSpellId, .ArrivalSpellTarget = arrivalSpellTargetGuid, .ScriptResult = std::move(scriptResult) });      movement->Priority = MOTION_PRIORITY_HIGHEST;      movement->BaseUnitState = UNIT_STATE_JUMPING;      Add(movement);  }  void MotionMaster::MoveJumpWithGravity(Position const& pos, float speedXY, float gravity, uint32 id/* = EVENT_JUMP*/, bool hasOrientation/* = false*/, -    JumpArrivalCastArgs const* arrivalCast /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/) +    JumpArrivalCastArgs const* arrivalCast /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  {      TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveJumpWithGravity: '{}', jumps to point Id: {} ({})", _owner->GetGUID(), id, pos.ToString());      if (speedXY < 0.01f) +    { +        if (scriptResult) +            scriptResult->SetResult(MovementStopReason::Interrupted);          return; +    }      std::function<void(Movement::MoveSplineInit&)> initializer = [=, effect = (spellEffectExtraData ? Optional<Movement::SpellEffectExtraData>(*spellEffectExtraData) : Optional<Movement::SpellEffectExtraData>())](Movement::MoveSplineInit& init)      { @@ -896,7 +926,7 @@ void MotionMaster::MoveJumpWithGravity(Position const& pos, float speedXY, float      }      GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id, -        { .ArrivalSpellId = arrivalSpellId, .ArrivalSpellTarget = arrivalSpellTargetGuid }); +        { .ArrivalSpellId = arrivalSpellId, .ArrivalSpellTarget = arrivalSpellTargetGuid, .ScriptResult = std::move(scriptResult) });      movement->Priority = MOTION_PRIORITY_HIGHEST;      movement->BaseUnitState = UNIT_STATE_JUMPING;      movement->AddFlag(MOVEMENTGENERATOR_FLAG_PERSIST_ON_DEATH); @@ -905,7 +935,8 @@ void MotionMaster::MoveJumpWithGravity(Position const& pos, float speedXY, float  void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount,      Optional<Milliseconds> duration /*= {}*/, Optional<float> speed /*= {}*/, -    MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/) +    MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  {      std::function<void(Movement::MoveSplineInit&)> initializer = [=, this](Movement::MoveSplineInit& init)      { @@ -953,7 +984,7 @@ void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool              init.SetVelocity(*speed);      }; -    Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, 0, { .Duration = duration })); +    Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, 0, { .Duration = duration, .ScriptResult = std::move(scriptResult) }));  }  void MotionMaster::MoveSmoothPath(uint32 pointId, Position const* pathPoints, size_t pathSize, bool walk, bool fly) @@ -1014,8 +1045,15 @@ void MotionMaster::ResumeSplineChain(SplineChainResumeInfo const& info)      Add(new SplineChainMovementGenerator(info));  } -void MotionMaster::MoveFall(uint32 id/* = 0*/) +void MotionMaster::MoveFall(uint32 id /*= 0*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  { +    auto setterScopeExit = Trinity::make_unique_ptr_with_deleter(&scriptResult, [](Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>* opt) +    { +        if (opt->has_value()) +            (*opt)->SetResult(MovementStopReason::Interrupted); +    }); +      // Use larger distance for vmap height search than in most other cases      float tz = _owner->GetMapHeight(_owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ(), true, MAX_FALL_DISTANCE);      if (tz <= INVALID_HEIGHT) @@ -1042,13 +1080,13 @@ void MotionMaster::MoveFall(uint32 id/* = 0*/)          return;      } -    std::function<void(Movement::MoveSplineInit&)> initializer = [=, this](Movement::MoveSplineInit& init) +    std::function<void(Movement::MoveSplineInit&)> initializer = [this, tz](Movement::MoveSplineInit& init)      {          init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), tz + _owner->GetHoverOffset(), false);          init.SetFall();      }; -    GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id); +    GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id, { .ScriptResult = std::move(*setterScopeExit.release()) });      movement->Priority = MOTION_PRIORITY_HIGHEST;      Add(movement);  } @@ -1079,7 +1117,8 @@ void MotionMaster::MoveSeekAssistanceDistract(uint32 time)          TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveSeekAssistanceDistract: '{}', attempted to call distract assistance.", _owner->GetGUID());  } -void MotionMaster::MoveTaxiFlight(uint32 path, uint32 pathnode, Optional<float> speed /*= {}*/) +void MotionMaster::MoveTaxiFlight(uint32 path, uint32 pathnode, Optional<float> speed /*= {}*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  {      if (_owner->GetTypeId() == TYPEID_PLAYER)      { @@ -1091,7 +1130,7 @@ void MotionMaster::MoveTaxiFlight(uint32 path, uint32 pathnode, Optional<float>              bool hasExisting = HasMovementGenerator([](MovementGenerator const* gen) { return gen->GetMovementGeneratorType() == FLIGHT_MOTION_TYPE; });              ASSERT(!hasExisting, "Duplicate flight path movement generator"); -            FlightPathMovementGenerator* movement = new FlightPathMovementGenerator(speed); +            FlightPathMovementGenerator* movement = new FlightPathMovementGenerator(speed, std::move(scriptResult));              movement->LoadPath(_owner->ToPlayer(), pathnode);              Add(movement);          } @@ -1112,36 +1151,45 @@ void MotionMaster::MoveDistract(uint32 timer, float orientation)      Add(new DistractMovementGenerator(timer, orientation));  } -void MotionMaster::MovePath(uint32 pathId, bool repeatable, Optional<Milliseconds> duration, Optional<float> speed, -    MovementWalkRunSpeedSelectionMode speedSelectionMode, Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd, -    Optional<float> wanderDistanceAtPathEnds, Optional<bool> followPathBackwardsFromEndToStart, bool generatePath) +void MotionMaster::MovePath(uint32 pathId, bool repeatable, Optional<Milliseconds> duration /*= {}*/, Optional<float> speed /*= {}*/, +    MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/, +    Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd /*= {}*/, +    Optional<float> wanderDistanceAtPathEnds /*= {}*/, Optional<bool> followPathBackwardsFromEndToStart /*= {}*/, bool generatePath /*= true*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  {      if (!pathId) +    { +        if (scriptResult) +            scriptResult->SetResult(MovementStopReason::Interrupted);          return; +    }      TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})",          _owner->GetGUID(), pathId, repeatable ? "YES" : "NO");      Add(new WaypointMovementGenerator<Creature>(pathId, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd, -        wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath), MOTION_SLOT_DEFAULT); +        wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath, std::move(scriptResult)), MOTION_SLOT_DEFAULT);  } -void MotionMaster::MovePath(WaypointPath const& path, bool repeatable, Optional<Milliseconds> duration, Optional<float> speed, -    MovementWalkRunSpeedSelectionMode speedSelectionMode, Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd, -    Optional<float> wanderDistanceAtPathEnds, Optional<bool> followPathBackwardsFromEndToStart, bool generatePath) +void MotionMaster::MovePath(WaypointPath const& path, bool repeatable, Optional<Milliseconds> duration /*= {}*/, Optional<float> speed /*= {}*/, +    MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/, +    Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd /*= {}*/, +    Optional<float> wanderDistanceAtPathEnds /*= {}*/, Optional<bool> followPathBackwardsFromEndToStart /*= {}*/, bool generatePath /*= true*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  {      TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})",          _owner->GetGUID(), path.Id, repeatable ? "YES" : "NO");      Add(new WaypointMovementGenerator<Creature>(path, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd, -        wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath), MOTION_SLOT_DEFAULT); +        wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath, std::move(scriptResult)), MOTION_SLOT_DEFAULT);  }  void MotionMaster::MoveRotate(uint32 id, RotateDirection direction, Optional<Milliseconds> time /*= {}*/, -    Optional<float> turnSpeed /*= {}*/, Optional<float> totalTurnAngle /*= {}*/) +    Optional<float> turnSpeed /*= {}*/, Optional<float> totalTurnAngle /*= {}*/, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)  {      TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveRotate: '{}', starts rotate (time: {}ms, turnSpeed: {}, totalTurnAngle: {}, direction: {})",          _owner->GetGUID(), time.value_or(0ms).count(), turnSpeed, totalTurnAngle, direction); -    Add(new RotateMovementGenerator(id, direction, time, turnSpeed, totalTurnAngle)); +    Add(new RotateMovementGenerator(id, direction, time, turnSpeed, totalTurnAngle, std::move(scriptResult)));  }  void MotionMaster::MoveFormation(Unit* leader, float range, float angle, uint32 point1, uint32 point2) diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index 87cee0adf85..2f2d4d9d6da 100644 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -156,16 +156,21 @@ class TC_GAME_API MotionMaster          void MoveIdle();          void MoveTargetedHome(); -        void MoveRandom(float wanderDistance = 0.0f, Optional<Milliseconds> duration = {}, MovementSlot slot = MOTION_SLOT_DEFAULT); -        void MoveFollow(Unit* target, float dist, ChaseAngle angle, Optional<Milliseconds> duration = {}, MovementSlot slot = MOTION_SLOT_ACTIVE); +        void MoveRandom(float wanderDistance = 0.0f, Optional<Milliseconds> duration = {}, MovementSlot slot = MOTION_SLOT_DEFAULT, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {}); +        void MoveFollow(Unit* target, float dist, ChaseAngle angle, Optional<Milliseconds> duration = {}, MovementSlot slot = MOTION_SLOT_ACTIVE, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          void MoveChase(Unit* target, Optional<ChaseRange> dist = {}, Optional<ChaseAngle> angle = {});          void MoveChase(Unit* target, float dist, float angle) { MoveChase(target, ChaseRange(dist), ChaseAngle(angle)); }          void MoveConfused(); -        void MoveFleeing(Unit* enemy, Milliseconds time = 0ms); +        void MoveFleeing(Unit* enemy, Milliseconds time = 0ms, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          void MovePoint(uint32 id, Position const& pos, bool generatePath = true, Optional<float> finalOrient = {}, Optional<float> speed = {}, -            MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default, Optional<float> closeEnoughDistance = {}); +            MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default, Optional<float> closeEnoughDistance = {}, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          void MovePoint(uint32 id, float x, float y, float z, bool generatePath = true, Optional<float> finalOrient = {}, Optional<float> speed = {}, -            MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default, Optional<float> closeEnoughDistance = {}); +            MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default, Optional<float> closeEnoughDistance = {}, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          /*           *  Makes the unit move toward the target until it is at a certain distance from it. The unit then stops.           *  Only works in 2D. @@ -174,37 +179,50 @@ class TC_GAME_API MotionMaster          void MoveCloserAndStop(uint32 id, Unit* target, float distance);          // These two movement types should only be used with creatures having landing/takeoff animations          void MoveLand(uint32 id, Position const& pos, Optional<int32> tierTransitionId = {}, Optional<float> velocity = {}, -            MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default); +            MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          void MoveTakeoff(uint32 id, Position const& pos, Optional<int32> tierTransitionId = {}, Optional<float> velocity = {}, -            MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default); +            MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE, bool generatePath = false, Unit const* target = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr);          void MoveCharge(PathGenerator const& path, float speed = SPEED_CHARGE, Unit const* target = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr);          void MoveKnockbackFrom(Position const& origin, float speedXY, float speedZ, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr);          void MoveJumpTo(float angle, float speedXY, float speedZ); -        void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = EVENT_JUMP, bool hasOrientation = false, JumpArrivalCastArgs const* arrivalCast = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr); -        void MoveJump(float x, float y, float z, float o, float speedXY, float speedZ, uint32 id = EVENT_JUMP, bool hasOrientation = false, JumpArrivalCastArgs const* arrivalCast = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr); -        void MoveJumpWithGravity(Position const& pos, float speedXY, float gravity, uint32 id = EVENT_JUMP, bool hasOrientation = false, JumpArrivalCastArgs const* arrivalCast = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr); +        void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = EVENT_JUMP, bool hasOrientation = false, +            JumpArrivalCastArgs const* arrivalCast = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {}); +        void MoveJump(float x, float y, float z, float o, float speedXY, float speedZ, uint32 id = EVENT_JUMP, bool hasOrientation = false, +            JumpArrivalCastArgs const* arrivalCast = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {}); +        void MoveJumpWithGravity(Position const& pos, float speedXY, float gravity, uint32 id = EVENT_JUMP, bool hasOrientation = false, +            JumpArrivalCastArgs const* arrivalCast = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount,              Optional<Milliseconds> duration = {}, Optional<float> speed = {}, -            MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default); +            MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          void MoveSmoothPath(uint32 pointId, Position const* pathPoints, size_t pathSize, bool walk = false, bool fly = false);          // Walk along spline chain stored in DB (script_spline_chain_meta and script_spline_chain_waypoints)          void MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk);          void MoveAlongSplineChain(uint32 pointId, std::vector<SplineChainLink> const& chain, bool walk);          void ResumeSplineChain(SplineChainResumeInfo const& info); -        void MoveFall(uint32 id = 0); +        void MoveFall(uint32 id = 0, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          void MoveSeekAssistance(float x, float y, float z);          void MoveSeekAssistanceDistract(uint32 timer); -        void MoveTaxiFlight(uint32 path, uint32 pathnode, Optional<float> speed = {}); +        void MoveTaxiFlight(uint32 path, uint32 pathnode, Optional<float> speed = {}, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          void MoveDistract(uint32 time, float orientation);          void MovePath(uint32 pathId, bool repeatable, Optional<Milliseconds> duration = {}, Optional<float> speed = {},              MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default,              Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd = {}, Optional<float> wanderDistanceAtPathEnds = {}, -            Optional<bool> followPathBackwardsFromEndToStart = {}, bool generatePath = true); +            Optional<bool> followPathBackwardsFromEndToStart = {}, bool generatePath = true, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          void MovePath(WaypointPath const& path, bool repeatable, Optional<Milliseconds> duration = {}, Optional<float> speed = {},              MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default,              Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd = {}, Optional<float> wanderDistanceAtPathEnds = {}, -            Optional<bool> followPathBackwardsFromEndToStart = {}, bool generatePath = true); +            Optional<bool> followPathBackwardsFromEndToStart = {}, bool generatePath = true, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          /**           * \brief Makes the Unit turn in place @@ -213,9 +231,11 @@ class TC_GAME_API MotionMaster           * \param time How long should this movement last, infinite if not set           * \param turnSpeed How fast should the unit rotate, in radians per second. Uses unit's turn speed if not set           * \param totalTurnAngle Total angle of the entire movement, infinite if not set +         * \param scriptResult Awaitable script result (for internal use)           */          void MoveRotate(uint32 id, RotateDirection direction, Optional<Milliseconds> time = {}, -            Optional<float> turnSpeed = {}, Optional<float> totalTurnAngle = {}); +            Optional<float> turnSpeed = {}, Optional<float> totalTurnAngle = {}, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          void MoveFormation(Unit* leader, float range, float angle, uint32 point1, uint32 point2);          void LaunchMoveSpline(std::function<void(Movement::MoveSplineInit& init)>&& initializer, uint32 id = 0, MovementGeneratorPriority priority = MOTION_PRIORITY_NORMAL, MovementGeneratorType type = EFFECT_MOTION_TYPE); diff --git a/src/server/game/Movement/MovementGenerator.cpp b/src/server/game/Movement/MovementGenerator.cpp index 455f91795a5..38844c0d821 100644 --- a/src/server/game/Movement/MovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerator.cpp @@ -25,7 +25,10 @@  #include "WaypointMovementGenerator.h"  #include <sstream> -MovementGenerator::~MovementGenerator() { } +MovementGenerator::~MovementGenerator() +{ +    SetScriptResult(MovementStopReason::Interrupted); +}  std::string MovementGenerator::GetDebugInfo() const  { @@ -38,6 +41,15 @@ std::string MovementGenerator::GetDebugInfo() const      return sstr.str();  } +void MovementGenerator::SetScriptResult(MovementStopReason reason) +{ +    if (ScriptResult) +    { +        ScriptResult->SetResult(reason); +        ScriptResult.reset(); +    } +} +  IdleMovementFactory::IdleMovementFactory() : MovementGeneratorCreator(IDLE_MOTION_TYPE) { }  MovementGenerator* IdleMovementFactory::Create(Unit* /*object*/) const diff --git a/src/server/game/Movement/MovementGenerator.h b/src/server/game/Movement/MovementGenerator.h index a2c43528e49..79d3a5b9191 100755 --- a/src/server/game/Movement/MovementGenerator.h +++ b/src/server/game/Movement/MovementGenerator.h @@ -22,6 +22,8 @@  #include "FactoryHolder.h"  #include "MovementDefines.h"  #include "ObjectRegistry.h" +#include "Optional.h" +#include "ScriptActionResult.h"  class Creature;  class Unit; @@ -85,6 +87,10 @@ class TC_GAME_API MovementGenerator          uint8 Priority;          uint16 Flags;          uint32 BaseUnitState; +        Optional<Scripting::v2::ActionResultSetter<MovementStopReason>> ScriptResult; + +    protected: +        void SetScriptResult(MovementStopReason reason);  };  template<class T, class D> diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp index bedeccbe350..3e03b58d28c 100644 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp @@ -26,12 +26,14 @@  #define MIN_QUIET_DISTANCE 28.0f  #define MAX_QUIET_DISTANCE 43.0f -FleeingMovementGenerator::FleeingMovementGenerator(ObjectGuid fleeTargetGUID) : _fleeTargetGUID(fleeTargetGUID), _timer(0) +FleeingMovementGenerator::FleeingMovementGenerator(ObjectGuid fleeTargetGUID, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/) : _fleeTargetGUID(fleeTargetGUID), _timer(0)  {      Mode = MOTION_MODE_DEFAULT;      Priority = MOTION_PRIORITY_HIGHEST;      Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING;      BaseUnitState = UNIT_STATE_FLEEING; +    ScriptResult = std::move(scriptResult);  }  MovementGeneratorType FleeingMovementGenerator::GetMovementGeneratorType() const @@ -89,7 +91,7 @@ void FleeingMovementGenerator::Deactivate(Unit* owner)      owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE);  } -void FleeingMovementGenerator::Finalize(Unit* owner, bool active, bool /*movementInform*/) +void FleeingMovementGenerator::Finalize(Unit* owner, bool active, bool movementInform)  {      AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); @@ -105,6 +107,9 @@ void FleeingMovementGenerator::Finalize(Unit* owner, bool active, bool /*movemen          else if (owner->IsPlayer())              owner->StopMoving();      } + +    if (movementInform) +        SetScriptResult(MovementStopReason::Finished);  }  void FleeingMovementGenerator::SetTargetLocation(Unit* owner) @@ -223,6 +228,8 @@ void TimedFleeingMovementGenerator::Finalize(Unit* owner, bool active, bool move      if (movementInform)      { +        SetScriptResult(MovementStopReason::Finished); +          Creature* ownerCreature = owner->ToCreature();          if (CreatureAI* AI = ownerCreature ? ownerCreature->AI() : nullptr)              AI->MovementInform(TIMED_FLEEING_MOTION_TYPE, 0); diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h index 3e039265963..d8a28e9e54b 100755 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h @@ -28,7 +28,8 @@ struct Position;  class FleeingMovementGenerator : public MovementGenerator  {      public: -        explicit FleeingMovementGenerator(ObjectGuid fleeTargetGUID); +        explicit FleeingMovementGenerator(ObjectGuid fleeTargetGUID, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          MovementGeneratorType GetMovementGeneratorType() const override; @@ -52,7 +53,9 @@ class FleeingMovementGenerator : public MovementGenerator  class TimedFleeingMovementGenerator : public FleeingMovementGenerator  {      public: -        explicit TimedFleeingMovementGenerator(ObjectGuid fleeTargetGUID, Milliseconds time) : FleeingMovementGenerator(fleeTargetGUID), _totalFleeTime(time) { } +        explicit TimedFleeingMovementGenerator(ObjectGuid fleeTargetGUID, Milliseconds time, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {}) +            : FleeingMovementGenerator(fleeTargetGUID, std::move(scriptResult)), _totalFleeTime(time) { }          bool Update(Unit*, uint32) override;          void Finalize(Unit*, bool, bool) override; diff --git a/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.cpp index 02184136e2c..0a95fad135e 100644 --- a/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.cpp @@ -32,7 +32,8 @@  #define SKIP_SPLINE_POINT_DISTANCE_SQ (40.f * 40.f)  #define PLAYER_FLIGHT_SPEED 32.0f -FlightPathMovementGenerator::FlightPathMovementGenerator(Optional<float> speed) +FlightPathMovementGenerator::FlightPathMovementGenerator(Optional<float> speed, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult)  {      _speed = speed;      _endGridX = 0.0f; @@ -44,6 +45,7 @@ FlightPathMovementGenerator::FlightPathMovementGenerator(Optional<float> speed)      Priority = MOTION_PRIORITY_HIGHEST;      Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING;      BaseUnitState = UNIT_STATE_IN_FLIGHT; +    ScriptResult = std::move(scriptResult);  }  MovementGeneratorType FlightPathMovementGenerator::GetMovementGeneratorType() const @@ -152,7 +154,7 @@ void FlightPathMovementGenerator::DoDeactivate(Player* /*owner*/)      AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED);  } -void FlightPathMovementGenerator::DoFinalize(Player* owner, bool active, bool/* movementInform*/) +void FlightPathMovementGenerator::DoFinalize(Player* owner, bool active, bool movementInform)  {      AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED);      if (!active) @@ -179,6 +181,9 @@ void FlightPathMovementGenerator::DoFinalize(Player* owner, bool active, bool/*      }      owner->RemovePlayerFlag(PLAYER_FLAGS_TAXI_BENCHMARK); + +    if (movementInform) +        SetScriptResult(MovementStopReason::Finished);  }  uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const diff --git a/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.h index 2abc4c275f4..ada9c742781 100644 --- a/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.h @@ -33,7 +33,8 @@ struct TaxiPathNodeEntry;  class FlightPathMovementGenerator : public MovementGeneratorMedium<Player, FlightPathMovementGenerator>, public PathMovementBase<Player, std::vector<TaxiPathNodeEntry const*>>  {      public: -        explicit FlightPathMovementGenerator(Optional<float> speed); +        explicit FlightPathMovementGenerator(Optional<float> speed, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult);          MovementGeneratorType GetMovementGeneratorType() const override;          bool GetResetPosition(Unit* owner, float& x, float& y, float& z) override; diff --git a/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.cpp index a1ad2219d88..475a30481e5 100644 --- a/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.cpp @@ -35,13 +35,15 @@ static void DoMovementInform(Unit* owner, Unit* target)          AI->MovementInform(FOLLOW_MOTION_TYPE, target->GetGUID().GetCounter());  } -FollowMovementGenerator::FollowMovementGenerator(Unit* target, float range, ChaseAngle angle, Optional<Milliseconds> duration) +FollowMovementGenerator::FollowMovementGenerator(Unit* target, float range, ChaseAngle angle, Optional<Milliseconds> duration, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)      : AbstractFollower(ASSERT_NOTNULL(target)), _range(range), _angle(angle), _checkTimer(CHECK_INTERVAL)  {      Mode = MOTION_MODE_DEFAULT;      Priority = MOTION_PRIORITY_NORMAL;      Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING;      BaseUnitState = UNIT_STATE_FOLLOW; +    ScriptResult = std::move(scriptResult);      if (duration)          _duration.emplace(*duration);  } @@ -196,13 +198,15 @@ void FollowMovementGenerator::Deactivate(Unit* owner)      owner->ClearUnitState(UNIT_STATE_FOLLOW_MOVE);  } -void FollowMovementGenerator::Finalize(Unit* owner, bool active, bool/* movementInform*/) +void FollowMovementGenerator::Finalize(Unit* owner, bool active, bool movementInform)  {      AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED);      if (active)      {          owner->ClearUnitState(UNIT_STATE_FOLLOW_MOVE);          UpdatePetSpeed(owner); +        if (movementInform) +            SetScriptResult(MovementStopReason::Finished);      }  } diff --git a/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.h index 27c3bd3bcf5..300ab9ce555 100644 --- a/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.h @@ -21,7 +21,6 @@  #include "AbstractFollower.h"  #include "MovementDefines.h"  #include "MovementGenerator.h" -#include "Optional.h"  #include "Position.h"  #include "Timer.h" @@ -33,7 +32,8 @@ class Unit;  class FollowMovementGenerator : public MovementGenerator, public AbstractFollower  {      public: -        explicit FollowMovementGenerator(Unit* target, float range, ChaseAngle angle, Optional<Milliseconds> duration); +        explicit FollowMovementGenerator(Unit* target, float range, ChaseAngle angle, Optional<Milliseconds> duration, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          ~FollowMovementGenerator();          void Initialize(Unit*) override; diff --git a/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.cpp index 7bd9d084bc4..090f129cd8a 100644 --- a/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.cpp @@ -40,6 +40,7 @@ GenericMovementGenerator::GenericMovementGenerator(std::function<void(Movement::          _duration.emplace(*args.Duration);          _durationTracksSpline = false;      } +    ScriptResult = std::move(args.ScriptResult);  }  void GenericMovementGenerator::Initialize(Unit* owner) @@ -101,6 +102,8 @@ void GenericMovementGenerator::MovementInform(Unit* owner)      if (_arrivalSpellId)          owner->CastSpell(ObjectAccessor::GetUnit(*owner, _arrivalSpellTargetGuid), _arrivalSpellId, true); +    SetScriptResult(MovementStopReason::Finished); +      if (Creature* creature = owner->ToCreature())      {          if (creature->AI()) diff --git a/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.h b/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.h index f9c46515e6b..f88b53c3fb0 100644 --- a/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.h @@ -32,6 +32,7 @@ struct GenericMovementGeneratorArgs      Optional<uint32> ArrivalSpellId;      Optional<ObjectGuid> ArrivalSpellTarget;      Optional<Milliseconds> Duration; +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>> ScriptResult;  };  class GenericMovementGenerator : public MovementGenerator diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp index 7aa6a59178c..1b524873841 100644 --- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp @@ -63,13 +63,16 @@ MovementGeneratorType IdleMovementGenerator::GetMovementGeneratorType() const  //----------------------------------------------------//  RotateMovementGenerator::RotateMovementGenerator(uint32 id, RotateDirection direction, Optional<Milliseconds> duration, -    Optional<float> turnSpeed, Optional<float> totalTurnAngle) : _id(id), _duration(duration), _turnSpeed(turnSpeed), _totalTurnAngle(totalTurnAngle), +    Optional<float> turnSpeed, Optional<float> totalTurnAngle, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult) : _id(id), _duration(duration), +    _turnSpeed(turnSpeed), _totalTurnAngle(totalTurnAngle),      _direction(direction), _diffSinceLastUpdate(0)  {      Mode = MOTION_MODE_DEFAULT;      Priority = MOTION_PRIORITY_NORMAL;      Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING;      BaseUnitState = UNIT_STATE_ROTATING; +    ScriptResult = std::move(scriptResult);  }  void RotateMovementGenerator::Initialize(Unit* owner) @@ -142,8 +145,12 @@ void RotateMovementGenerator::Finalize(Unit* owner, bool/* active*/, bool moveme  {      AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); -    if (movementInform && owner->GetTypeId() == TYPEID_UNIT) -        owner->ToCreature()->AI()->MovementInform(ROTATE_MOTION_TYPE, _id); +    if (movementInform) +    { +        SetScriptResult(MovementStopReason::Finished); +        if (owner->IsCreature()) +            owner->ToCreature()->AI()->MovementInform(ROTATE_MOTION_TYPE, _id); +    }  }  MovementGeneratorType RotateMovementGenerator::GetMovementGeneratorType() const diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h index d525b9200f8..6e9fe57ba9f 100755 --- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h @@ -43,7 +43,8 @@ class RotateMovementGenerator : public MovementGenerator          static constexpr float MIN_ANGLE_DELTA_FOR_FACING_UPDATE = 0.05f;          explicit RotateMovementGenerator(uint32 id, RotateDirection direction, Optional<Milliseconds> duration, -            Optional<float> turnSpeed, Optional<float> totalTurnAngle); +            Optional<float> turnSpeed, Optional<float> totalTurnAngle, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult);          void Initialize(Unit*) override;          void Reset(Unit*) override; diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp index a626e6ece49..60c4b73a8e8 100755 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp @@ -31,7 +31,7 @@  PointMovementGenerator::PointMovementGenerator(uint32 id, float x, float y, float z, bool generatePath, Optional<float> speed /*= {}*/, Optional<float> finalOrient /*= {}*/,      Unit const* faceTarget /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/,      MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/, -    Optional<float> closeEnoughDistance /*= {}*/) +    Optional<float> closeEnoughDistance /*= {}*/, Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)      : _movementId(id), _destination(x, y, z), _speed(speed), _generatePath(generatePath), _finalOrient(finalOrient),      i_faceTarget(faceTarget), _speedSelectionMode(speedSelectionMode), _closeEnoughDistance(closeEnoughDistance)  { @@ -39,6 +39,7 @@ PointMovementGenerator::PointMovementGenerator(uint32 id, float x, float y, floa      this->Priority = MOTION_PRIORITY_NORMAL;      this->Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING;      this->BaseUnitState = UNIT_STATE_ROAMING; +    this->ScriptResult = std::move(scriptResult);      if (spellEffectExtraData)          this->i_spellEffectExtra = std::make_unique<Movement::SpellEffectExtraData>(*spellEffectExtraData); @@ -195,6 +196,8 @@ void PointMovementGenerator::Finalize(Unit* owner, bool active, bool movementInf  void PointMovementGenerator::MovementInform(Unit* owner)  { +    SetScriptResult(MovementStopReason::Finished); +      // deliver EVENT_CHARGE to scripts, EVENT_CHARGE_PREPATH is just internal implementation detail of this movement generator      uint32 movementId = _movementId == EVENT_CHARGE_PREPATH ? uint32(EVENT_CHARGE) : _movementId; diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h index 8666a2ccc57..ea5ffc8ada3 100644 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h @@ -19,7 +19,6 @@  #define TRINITY_POINTMOVEMENTGENERATOR_H  #include "MovementGenerator.h" -#include "Optional.h"  #include "Position.h"  class Creature; @@ -34,7 +33,8 @@ class PointMovementGenerator : public MovementGenerator          explicit PointMovementGenerator(uint32 id, float x, float y, float z, bool generatePath, Optional<float> speed = {}, Optional<float> finalOrient = {},              Unit const* faceTarget = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr,              MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default, -            Optional<float> closeEnoughDistance = {}); +            Optional<float> closeEnoughDistance = {}, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          MovementGeneratorType GetMovementGeneratorType() const override; diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp index 1e2298ed088..e1ab9c3ad38 100644 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp @@ -18,24 +18,28 @@  #include "RandomMovementGenerator.h"  #include "Creature.h"  #include "CreatureAI.h" -#include "MovementDefines.h"  #include "MoveSpline.h"  #include "MoveSplineInit.h" +#include "MovementDefines.h"  #include "PathGenerator.h"  #include "Random.h"  template<class T> -RandomMovementGenerator<T>::RandomMovementGenerator(float distance, Optional<Milliseconds> duration) : _timer(0), _reference(), _wanderDistance(distance), _wanderSteps(0) +RandomMovementGenerator<T>::RandomMovementGenerator(float distance, Optional<Milliseconds> duration, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/) : _timer(0), _reference(), _wanderDistance(distance), _wanderSteps(0)  {      this->Mode = MOTION_MODE_DEFAULT;      this->Priority = MOTION_PRIORITY_NORMAL;      this->Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING;      this->BaseUnitState = UNIT_STATE_ROAMING; +    this->ScriptResult = std::move(scriptResult);      if (duration)          _duration.emplace(*duration);  } -template RandomMovementGenerator<Creature>::RandomMovementGenerator(float distance, Optional<Milliseconds> duration); +template +RandomMovementGenerator<Creature>::RandomMovementGenerator(float distance, Optional<Milliseconds> duration, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult);  template<class T>  MovementGeneratorType RandomMovementGenerator<T>::GetMovementGeneratorType() const @@ -265,6 +269,9 @@ void RandomMovementGenerator<Creature>::DoFinalize(Creature* owner, bool active,      }      if (movementInform && HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)) +    { +        SetScriptResult(MovementStopReason::Finished);          if (owner->IsAIEnabled())              owner->AI()->MovementInform(RANDOM_MOTION_TYPE, 0); +    }  } diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h index 5d6ff652f2b..f67b4096e70 100644 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h @@ -29,7 +29,8 @@ template<class T>  class RandomMovementGenerator : public MovementGeneratorMedium<T, RandomMovementGenerator<T>>  {      public: -        explicit RandomMovementGenerator(float distance = 0.0f, Optional<Milliseconds> duration = {}); +        explicit RandomMovementGenerator(float distance = 0.0f, Optional<Milliseconds> duration = {}, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          MovementGeneratorType GetMovementGeneratorType() const override; diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index afbaae40562..55f462d3f41 100644 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -30,7 +30,8 @@  WaypointMovementGenerator<Creature>::WaypointMovementGenerator(uint32 pathId, bool repeating, Optional<Milliseconds> duration, Optional<float> speed,      MovementWalkRunSpeedSelectionMode speedSelectionMode, Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd, -    Optional<float> wanderDistanceAtPathEnds, Optional<bool> followPathBackwardsFromEndToStart, bool generatePath) +    Optional<float> wanderDistanceAtPathEnds, Optional<bool> followPathBackwardsFromEndToStart, bool generatePath, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)      : _nextMoveTime(0), _pathId(pathId), _repeating(repeating), _loadedFromDB(true),      _speed(speed), _speedSelectionMode(speedSelectionMode), _waitTimeRangeAtPathEnd(std::move(waitTimeRangeAtPathEnd)),      _wanderDistanceAtPathEnds(wanderDistanceAtPathEnds), _followPathBackwardsFromEndToStart(followPathBackwardsFromEndToStart), _isReturningToStart(false), @@ -40,13 +41,15 @@ WaypointMovementGenerator<Creature>::WaypointMovementGenerator(uint32 pathId, bo      Priority = MOTION_PRIORITY_NORMAL;      Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING;      BaseUnitState = UNIT_STATE_ROAMING; +    ScriptResult = std::move(scriptResult);      if (duration)          _duration.emplace(*duration);  }  WaypointMovementGenerator<Creature>::WaypointMovementGenerator(WaypointPath const& path, bool repeating, Optional<Milliseconds> duration, Optional<float> speed,      MovementWalkRunSpeedSelectionMode speedSelectionMode, Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd, -    Optional<float> wanderDistanceAtPathEnds, Optional<bool> followPathBackwardsFromEndToStart, bool generatePath) +    Optional<float> wanderDistanceAtPathEnds, Optional<bool> followPathBackwardsFromEndToStart, bool generatePath, +    Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)      : _nextMoveTime(0), _pathId(0), _repeating(repeating), _loadedFromDB(false),      _speed(speed), _speedSelectionMode(speedSelectionMode), _waitTimeRangeAtPathEnd(std::move(waitTimeRangeAtPathEnd)),      _wanderDistanceAtPathEnds(wanderDistanceAtPathEnds), _followPathBackwardsFromEndToStart(followPathBackwardsFromEndToStart), _isReturningToStart(false), @@ -58,6 +61,7 @@ WaypointMovementGenerator<Creature>::WaypointMovementGenerator(WaypointPath cons      Priority = MOTION_PRIORITY_NORMAL;      Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING;      BaseUnitState = UNIT_STATE_ROAMING; +    ScriptResult = std::move(scriptResult);      if (duration)          _duration.emplace(*duration);  } @@ -166,6 +170,9 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff)          {              RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY);              AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED); +            AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); +            owner->UpdateCurrentWaypointInfo(0, 0); +            SetScriptResult(MovementStopReason::Finished);              return false;          }      } @@ -248,7 +255,7 @@ void WaypointMovementGenerator<Creature>::DoDeactivate(Creature* owner)      owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE);  } -void WaypointMovementGenerator<Creature>::DoFinalize(Creature* owner, bool active, bool/* movementInform*/) +void WaypointMovementGenerator<Creature>::DoFinalize(Creature* owner, bool active, bool movementInform)  {      AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED);      if (active) @@ -258,6 +265,9 @@ void WaypointMovementGenerator<Creature>::DoFinalize(Creature* owner, bool activ          // TODO: Research if this modification is needed, which most likely isnt          owner->SetWalk(false);      } + +    if (movementInform) +        SetScriptResult(MovementStopReason::Finished);  }  void WaypointMovementGenerator<Creature>::MovementInform(Creature* owner) @@ -353,6 +363,8 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun              // inform AI              if (CreatureAI* AI = owner->AI())                  AI->WaypointPathEnded(waypoint.Id, GetPath()->Id); + +            SetScriptResult(MovementStopReason::Finished);              return;          }      } @@ -391,7 +403,7 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun              init.SetAnimation(AnimTier::Ground);              break;          case WaypointMoveType::TakeOff: -            init.SetAnimation(AnimTier::Hover); +            init.SetAnimation(AnimTier::Fly);              break;          case WaypointMoveType::Run:              init.SetWalk(false); diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h index 8de8f5de52b..23d5cc1c7c6 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h @@ -38,11 +38,13 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium<Creat          explicit WaypointMovementGenerator(uint32 pathId, bool repeating, Optional<Milliseconds> duration = {}, Optional<float> speed = {},              MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default,              Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd = {}, Optional<float> wanderDistanceAtPathEnds = {}, -            Optional<bool> followPathBackwardsFromEndToStart = {}, bool generatePath = true); +            Optional<bool> followPathBackwardsFromEndToStart = {}, bool generatePath = true, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          explicit WaypointMovementGenerator(WaypointPath const& path, bool repeating, Optional<Milliseconds> duration, Optional<float> speed,              MovementWalkRunSpeedSelectionMode speedSelectionMode,              Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd, Optional<float> wanderDistanceAtPathEnds, -            Optional<bool> followPathBackwardsFromEndToStart, bool generatePath); +            Optional<bool> followPathBackwardsFromEndToStart, bool generatePath, +            Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});          ~WaypointMovementGenerator();          MovementGeneratorType GetMovementGeneratorType() const override; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 69163ed6066..3de0a179bcd 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3883,6 +3883,9 @@ void Spell::_cast(bool skipCheck)          handle_immediate();      } +    if (m_scriptResult && !m_scriptWaitsForSpellHit) +        m_scriptResult->SetResult(SPELL_CAST_OK); +      CallScriptAfterCastHandlers();      if (std::vector<int32> const* spell_triggered = sSpellMgr->GetSpellLinked(SPELL_LINK_CAST, m_spellInfo->Id)) @@ -4314,6 +4317,9 @@ void Spell::finish(SpellCastResult result)          return;      m_spellState = SPELL_STATE_FINISHED; +    if (m_scriptResult && (m_scriptWaitsForSpellHit || result != SPELL_CAST_OK)) +        m_scriptResult->SetResult(result); +      if (!m_caster)          return; diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 06b7cd1bb70..2da7e1d7e8a 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -609,6 +609,9 @@ class TC_GAME_API Spell          UsedSpellMods m_appliedMods; +        Optional<Scripting::v2::ActionResultSetter<SpellCastResult>> m_scriptResult; +        bool m_scriptWaitsForSpellHit = false; +          int32 GetCastTime() const { return m_casttime; }          int32 GetRemainingCastTime() const { return m_timer; }          bool IsAutoRepeat() const { return m_autoRepeat; } diff --git a/src/server/game/Spells/SpellDefines.h b/src/server/game/Spells/SpellDefines.h index ef9a3b0f79b..5d310348bee 100644 --- a/src/server/game/Spells/SpellDefines.h +++ b/src/server/game/Spells/SpellDefines.h @@ -24,6 +24,7 @@  #include "ObjectGuid.h"  #include "Optional.h"  #include "Position.h" +#include "ScriptActionResult.h"  #include <any>  #include <vector> @@ -38,6 +39,7 @@ class WorldObject;  enum Difficulty : uint8;  enum ProcFlags : uint32;  enum ProcFlags2 : int32; +enum SpellCastResult : int32;  namespace UF  { @@ -474,6 +476,8 @@ struct TC_GAME_API CastSpellExtraArgs      CastSpellExtraArgs& AddSpellMod(SpellValueMod mod, int32 val) { SpellValueOverrides.AddMod(mod, val); return *this; }      CastSpellExtraArgs& AddSpellBP0(int32 val) { return AddSpellMod(SPELLVALUE_BASE_POINT0, val); } // because i don't want to type SPELLVALUE_BASE_POINT0 300 times      CastSpellExtraArgs& SetCustomArg(std::any customArg) { CustomArg = std::move(customArg); return *this; } +    CastSpellExtraArgs& SetScriptResult(Scripting::v2::ActionResultSetter<SpellCastResult> scriptResult) { ScriptResult.emplace(std::move(scriptResult)); return *this; } +    CastSpellExtraArgs& SetScriptWaitsForSpellHit(bool scriptWaitsForSpellHit) { ScriptWaitsForSpellHit = scriptWaitsForSpellHit; return *this; }      TriggerCastFlags TriggerFlags = TRIGGERED_NONE;      Item* CastItem = nullptr; @@ -497,6 +501,9 @@ struct TC_GAME_API CastSpellExtraArgs          std::vector<std::pair<SpellValueMod, int32>> data;      } SpellValueOverrides;      std::any CustomArg; + +    Optional<Scripting::v2::ActionResultSetter<SpellCastResult>> ScriptResult; +    bool ScriptWaitsForSpellHit = false;  };  struct SpellCastVisual | 
