diff options
Diffstat (limited to 'src/server')
96 files changed, 2361 insertions, 1435 deletions
diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp index e41d104c380..4e8e035bf5b 100644 --- a/src/server/game/AI/CreatureAI.cpp +++ b/src/server/game/AI/CreatureAI.cpp @@ -160,9 +160,7 @@ void CreatureAI::TriggerAlert(Unit const* who) const me->SendAIReaction(AI_REACTION_ALERT); // Face the unit (stealthed player) and set distracted state for 5 seconds - me->GetMotionMaster()->MoveDistract(5 * IN_MILLISECONDS); - me->StopMoving(); - me->SetFacingTo(me->GetAbsoluteAngle(who)); + me->GetMotionMaster()->MoveDistract(5 * IN_MILLISECONDS, me->GetAbsoluteAngle(who)); } void CreatureAI::EnterEvadeMode(EvadeReason why) @@ -176,8 +174,8 @@ void CreatureAI::EnterEvadeMode(EvadeReason why) { if (Unit* owner = me->GetCharmerOrOwner()) { - me->GetMotionMaster()->Clear(false); - me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle()); } else { diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp index bb118886b79..fd9c7421c0f 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp @@ -204,7 +204,7 @@ void EscortAI::UpdateAI(uint32 diff) else if (_resume) { _resume = false; - if (MovementGenerator* movementGenerator = me->GetMotionMaster()->GetMotionSlot(MOTION_SLOT_IDLE)) + if (MovementGenerator* movementGenerator = me->GetMotionMaster()->GetCurrentMovementGenerator(MOTION_SLOT_DEFAULT)) movementGenerator->Resume(0); } } @@ -328,7 +328,7 @@ void EscortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false */, TC_LOG_DEBUG("scripts", "EscortAI::Start: (script: %s, creature entry: %u) is set to return home after waypoint end and instant respawn at waypoint end. Creature will never despawn.", me->GetScriptName().c_str(), me->GetEntry()); me->GetMotionMaster()->MoveIdle(); - me->GetMotionMaster()->Clear(MOTION_SLOT_ACTIVE); + me->GetMotionMaster()->Clear(MOTION_PRIORITY_NORMAL); // disable npcflags me->SetNpcFlags(UNIT_NPC_FLAG_NONE); @@ -366,7 +366,7 @@ void EscortAI::SetEscortPaused(bool on) if (on) { AddEscortState(STATE_ESCORT_PAUSED); - if (MovementGenerator* movementGenerator = me->GetMotionMaster()->GetMotionSlot(MOTION_SLOT_IDLE)) + if (MovementGenerator* movementGenerator = me->GetMotionMaster()->GetCurrentMovementGenerator(MOTION_SLOT_DEFAULT)) movementGenerator->Pause(0); } else diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 950b1d10fa3..f4a775bee69 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -113,7 +113,7 @@ void SmartAI::PausePath(uint32 delay, bool forced) { if (!HasEscortState(SMART_ESCORT_ESCORTING)) { - me->PauseMovement(delay, MOTION_SLOT_IDLE, forced); + me->PauseMovement(delay, MOTION_SLOT_DEFAULT, forced); if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) { std::pair<uint32, uint32> waypointInfo = me->GetCurrentWaypointInfo(); @@ -546,8 +546,11 @@ void SmartAI::JustReachedHome() CreatureGroup* formation = me->GetFormation(); if (!formation || formation->GetLeader() == me || !formation->IsFormed()) { - if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != WAYPOINT_MOTION_TYPE && me->GetWaypointPath()) - me->GetMotionMaster()->MovePath(me->GetWaypointPath(), true); + if (me->GetMotionMaster()->GetCurrentMovementGeneratorType(MOTION_SLOT_DEFAULT) != WAYPOINT_MOTION_TYPE) + { + if (me->GetWaypointPath()) + me->GetMotionMaster()->MovePath(me->GetWaypointPath(), true); + } else me->ResumeMovement(); } @@ -593,7 +596,8 @@ void SmartAI::AttackStart(Unit* who) if (who && me->Attack(who, mCanAutoAttack)) { - me->GetMotionMaster()->Clear(MOTION_SLOT_ACTIVE); + me->GetMotionMaster()->Clear(MOTION_PRIORITY_NORMAL); + me->PauseMovement(); if (mCanCombatMove) { @@ -772,13 +776,22 @@ void SmartAI::SetCombatMove(bool on) if (me->IsEngaged()) { - if (on && !me->HasReactState(REACT_PASSIVE) && me->GetVictim() && me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE) == MAX_MOTION_TYPE) + if (on) { - SetRun(mRun); - me->GetMotionMaster()->MoveChase(me->GetVictim()); + if (!me->HasReactState(REACT_PASSIVE) && me->GetVictim() && !me->GetMotionMaster()->HasMovementGenerator([](MovementGenerator const* movement) -> bool + { + return movement->Mode == MOTION_MODE_DEFAULT && movement->Priority == MOTION_PRIORITY_NORMAL; + })) + { + SetRun(mRun); + me->GetMotionMaster()->MoveChase(me->GetVictim()); + } } - else if (!on && me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE) == CHASE_MOTION_TYPE) - me->GetMotionMaster()->Clear(MOTION_SLOT_ACTIVE); + else if (MovementGenerator* movement = me->GetMotionMaster()->GetMovementGenerator([](MovementGenerator const* a) -> bool + { + return a->GetMovementGeneratorType() == CHASE_MOTION_TYPE && a->Mode == MOTION_MODE_DEFAULT && a->Priority == MOTION_PRIORITY_NORMAL; + })) + me->GetMotionMaster()->Remove(movement); } } diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index e0516b76abf..2d191d2082b 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1642,10 +1642,12 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u float attackAngle = float(e.action.setRangedMovement.angle) / 180.0f * float(M_PI); for (WorldObject* target : targets) + { if (Creature* creature = target->ToCreature()) if (IsSmart(creature) && creature->GetVictim()) if (ENSURE_AI(SmartAI, creature->AI())->CanCombatMove()) creature->GetMotionMaster()->MoveChase(creature->GetVictim(), attackDistance, attackAngle); + } break; } @@ -2323,16 +2325,16 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u target->ToUnit()->RemoveAllGameObjects(); break; } - case SMART_ACTION_STOP_MOTION: + case SMART_ACTION_REMOVE_MOVEMENT: { for (WorldObject* const target : targets) { if (IsUnit(target)) { - if (e.action.stopMotion.stopMovement) + if (e.action.removeMovement.movementType && e.action.removeMovement.movementType < MAX_MOTION_TYPE) + target->ToUnit()->GetMotionMaster()->Remove(MovementGeneratorType(e.action.removeMovement.movementType)); + if (e.action.removeMovement.forced) target->ToUnit()->StopMoving(); - if (e.action.stopMotion.movementExpired) - target->ToUnit()->GetMotionMaster()->MovementExpired(); } } break; diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 34ac2eea2ac..42353663540 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -25,7 +25,7 @@ #include "GameEventMgr.h" #include "InstanceScript.h" #include "Log.h" -#include "MotionMaster.h" +#include "MovementDefines.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "SpellInfo.h" @@ -1757,7 +1757,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_REMOVE_ALL_GAMEOBJECTS: case SMART_ACTION_SPAWN_SPAWNGROUP: case SMART_ACTION_DESPAWN_SPAWNGROUP: - case SMART_ACTION_STOP_MOTION: + case SMART_ACTION_REMOVE_MOVEMENT: break; default: TC_LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry " SI64FMTD " SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id); diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index dd29f0e3185..0e1fe59b06e 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -590,7 +590,7 @@ enum SMART_ACTION SMART_ACTION_LOAD_EQUIPMENT = 124, // id SMART_ACTION_TRIGGER_RANDOM_TIMED_EVENT = 125, // id min range, id max range SMART_ACTION_REMOVE_ALL_GAMEOBJECTS = 126, - SMART_ACTION_STOP_MOTION = 127, // stopMoving, movementExpired + SMART_ACTION_REMOVE_MOVEMENT = 127, // movementType, forced SMART_ACTION_PLAY_ANIMKIT = 128, // id, type (0 = oneShot, 1 = aiAnim, 2 = meleeAnim, 3 = movementAnim) SMART_ACTION_SCENE_PLAY = 129, // sceneId SMART_ACTION_SCENE_CANCEL = 130, // sceneId @@ -1162,9 +1162,9 @@ struct SmartAction struct { - uint32 stopMovement; - uint32 movementExpired; - } stopMotion; + uint32 movementType; + uint32 forced; + } removeMovement; struct { diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 9cae257d87b..faeee1e4b67 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -30,7 +30,6 @@ #include "LFGScripts.h" #include "Log.h" #include "Map.h" -#include "MotionMaster.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Player.h" @@ -1363,11 +1362,7 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false* if (!player->GetMap()->IsDungeon()) player->SetBattlegroundEntryPoint(); - if (player->IsInFlight()) - { - player->GetMotionMaster()->MovementExpired(); - player->CleanupAfterTaxiFlight(); - } + player->FinishTaxiFlight(); if (!player->TeleportTo(mapid, x, y, z, orientation)) error = LFG_TELEPORT_RESULT_NO_RETURN_LOCATION; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 08b57f37fed..162fd6fc1f0 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -371,7 +371,7 @@ void Creature::DisappearAndDie() bool Creature::IsReturningHome() const { - if (GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE) == HOME_MOTION_TYPE) + if (GetMotionMaster()->GetCurrentMovementGeneratorType() == HOME_MOTION_TYPE) return true; return false; @@ -817,8 +817,7 @@ void Creature::Update(uint32 diff) IsAIEnabled = true; if (!IsInEvadeMode() && !LastCharmerGUID.IsEmpty()) if (Unit* charmer = ObjectAccessor::GetUnit(*this, LastCharmerGUID)) - if (CanStartAttack(charmer, true)) - i_AI->AttackStart(charmer); + EngageWithTarget(charmer); LastCharmerGUID.Clear(); } @@ -1020,7 +1019,6 @@ void Creature::DoFleeToGetAssistance() UpdateSpeed(MOVE_RUN); if (!creature) - //SetFeared(true, EnsureVictim()->GetGUID(), 0, sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY)); /// @todo use 31365 SetControlled(true, UNIT_STATE_FLEEING); else @@ -1089,7 +1087,7 @@ void Creature::Motion_Initialize() m_formation->FormationReset(false); else if (m_formation->IsFormed()) { - GetMotionMaster()->MoveIdle(); //wait the order of leader + GetMotionMaster()->MoveIdle(); // wait the order of leader return; } } @@ -2230,8 +2228,9 @@ void Creature::Respawn(bool force) SetNativeDisplayId(display.CreatureDisplayID, display.DisplayScale); } - GetMotionMaster()->InitDefault(); - //Re-initialize reactstate that could be altered by movementgenerators + GetMotionMaster()->InitializeDefault(); + + // Re-initialize reactstate that could be altered by movementgenerators InitializeReactState(); if (IsAIEnabled) // reset the AI to be sure no dirty or uninitialized values will be used till next tick diff --git a/src/server/game/Entities/Creature/CreatureGroups.cpp b/src/server/game/Entities/Creature/CreatureGroups.cpp index 8e285f3e931..e54e3f33ec6 100644 --- a/src/server/game/Entities/Creature/CreatureGroups.cpp +++ b/src/server/game/Entities/Creature/CreatureGroups.cpp @@ -268,7 +268,7 @@ void CreatureGroup::FormationReset(bool dismiss) pair.first->GetMotionMaster()->Initialize(); else pair.first->GetMotionMaster()->MoveIdle(); - TC_LOG_DEBUG("entities.unit", "Set %s movement for member: %s", dismiss ? "default" : "idle", pair.first->GetGUID().ToString().c_str()); + TC_LOG_DEBUG("entities.unit", "CreatureGroup::FormationReset: Set %s movement for member %s", dismiss ? "default" : "idle", pair.first->GetGUID().ToString().c_str()); } } @@ -316,16 +316,16 @@ void CreatureGroup::LeaderMoveTo(Position const& destination, uint32 id /*= 0*/, if (!member->IsFlying()) member->UpdateGroundPositionZ(dx, dy, dz); - Position point(dx, dy, dz, destination.GetOrientation()); + member->SetHomePosition(dx, dy, dz, pathangle); + Position point(dx, dy, dz, destination.GetOrientation()); member->GetMotionMaster()->MoveFormation(id, point, moveType, !member->IsWithinDist(_leader, dist + MAX_DESYNC), orientation); - member->SetHomePosition(dx, dy, dz, pathangle); } } bool CreatureGroup::CanLeaderStartMoving() const { - for (auto const& pair : _members) + for (std::unordered_map<Creature*, FormationInfo*>::value_type const& pair : _members) { if (pair.first != _leader && pair.first->IsAlive()) { diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index f8eedbe9752..0350d2b3833 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -22735,9 +22735,18 @@ bool Player::ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid /*= 0*/) return ActivateTaxiPathTo(nodes, nullptr, spellid); } +void Player::FinishTaxiFlight() +{ + if (!IsInFlight()) + return; + + GetMotionMaster()->Remove(FLIGHT_MOTION_TYPE); + m_taxi.ClearTaxiDestinations(); // not destinations, clear source node +} + void Player::CleanupAfterTaxiFlight() { - m_taxi.ClearTaxiDestinations(); // not destinations, clear source node + m_taxi.ClearTaxiDestinations(); // not destinations, clear source node Dismount(); RemoveUnitFlag(UnitFlags(UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_TAXI_FLIGHT)); } @@ -25153,11 +25162,7 @@ void Player::SummonIfPossible(bool agree) return; // stop taxi flight at summon - if (IsInFlight()) - { - GetMotionMaster()->MovementExpired(); - CleanupAfterTaxiFlight(); - } + FinishTaxiFlight(); // drop flag at summon // this code can be reached only when GM is summoning player who carries flag, because player should be immune to summoning spells when he carries flag @@ -25554,13 +25559,9 @@ void Player::SetClientControl(Unit* target, bool allowMove) void Player::SetMover(Unit* target) { m_unitMovedByMe->m_playerMovingMe = nullptr; - if (m_unitMovedByMe->GetTypeId() == TYPEID_UNIT) - m_unitMovedByMe->GetMotionMaster()->Initialize(); m_unitMovedByMe = target; m_unitMovedByMe->m_playerMovingMe = this; - if (m_unitMovedByMe->GetTypeId() == TYPEID_UNIT) - m_unitMovedByMe->GetMotionMaster()->Initialize(); WorldPackets::Movement::MoveSetActiveMover packet; packet.MoverGUID = target->GetGUID(); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index f6ee48328ad..4695eb8d21a 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1120,9 +1120,10 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(getRace(), getClass(), getLevel()); } bool ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc = nullptr, uint32 spellid = 0, uint32 preferredMountDisplay = 0); bool ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid = 0); + void FinishTaxiFlight(); void CleanupAfterTaxiFlight(); void ContinueTaxiFlight() const; - // mount_id can be used in scripting calls + bool isAcceptWhispers() const { return (m_ExtraFlags & PLAYER_EXTRA_ACCEPT_WHISPERS) != 0; } void SetAcceptWhispers(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_ACCEPT_WHISPERS; else m_ExtraFlags &= ~PLAYER_EXTRA_ACCEPT_WHISPERS; } bool IsGameMaster() const { return (m_ExtraFlags & PLAYER_EXTRA_GM_ON) != 0; } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index a6d6b8b0bde..a1b85a33ff1 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -473,7 +473,7 @@ void Unit::Update(uint32 p_time) } UpdateSplineMovement(p_time); - i_motionMaster->UpdateMotion(p_time); + i_motionMaster->Update(p_time); } bool Unit::haveOffhandWeapon() const @@ -489,7 +489,7 @@ void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed, bool gen Movement::MoveSplineInit init(this); init.MoveTo(x, y, z, generatePath, forceDestination); init.SetVelocity(speed); - GetMotionMaster()->LaunchMoveSpline(std::move(init), 0, MOTION_SLOT_ACTIVE, POINT_MOTION_TYPE); + GetMotionMaster()->LaunchMoveSpline(std::move(init), 0, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE); } void Unit::UpdateSplineMovement(uint32 t_diff) @@ -8065,7 +8065,7 @@ void Unit::UpdateSpeed(UnitMoveType mtype) { if (GetMotionMaster()->GetCurrentMovementGeneratorType() == FOLLOW_MOTION_TYPE) { - Unit* followed = ASSERT_NOTNULL(dynamic_cast<AbstractFollower*>(GetMotionMaster()->top()))->GetTarget(); + Unit* followed = ASSERT_NOTNULL(dynamic_cast<AbstractFollower*>(GetMotionMaster()->GetCurrentMovementGenerator()))->GetTarget(); if (followed && followed->GetGUID() == GetOwnerGUID() && !followed->IsInCombat()) { float ownerSpeed = followed->GetSpeedRate(mtype); @@ -8206,7 +8206,7 @@ void Unit::setDeathState(DeathState s) // * Using 'call pet' on dead pets // * Using 'call stabled pet' // * Logging in with dead pets - GetMotionMaster()->Clear(false); + GetMotionMaster()->Clear(); GetMotionMaster()->MoveIdle(); } StopMoving(); @@ -9787,10 +9787,10 @@ void Unit::PauseMovement(uint32 timer/* = 0*/, uint8 slot/* = 0*/, bool forced/* if (IsInvalidMovementSlot(slot)) return; - if (MovementGenerator* movementGenerator = GetMotionMaster()->GetMotionSlot(MovementSlot(slot))) + if (MovementGenerator* movementGenerator = GetMotionMaster()->GetCurrentMovementGenerator(MovementSlot(slot))) movementGenerator->Pause(timer); - if (forced) + if (forced && GetMotionMaster()->GetCurrentSlot() == MovementSlot(slot)) StopMoving(); } @@ -9799,7 +9799,7 @@ void Unit::ResumeMovement(uint32 timer/* = 0*/, uint8 slot/* = 0*/) if (IsInvalidMovementSlot(slot)) return; - if (MovementGenerator* movementGenerator = GetMotionMaster()->GetMotionSlot(MovementSlot(slot))) + if (MovementGenerator* movementGenerator = GetMotionMaster()->GetCurrentMovementGenerator(MovementSlot(slot))) movementGenerator->Resume(timer); } @@ -10775,8 +10775,7 @@ void Unit::SetFeared(bool apply) { if (IsAlive()) { - if (GetMotionMaster()->GetCurrentMovementGeneratorType() == FLEEING_MOTION_TYPE) - GetMotionMaster()->MovementExpired(); + GetMotionMaster()->Remove(FLEEING_MOTION_TYPE); if (GetVictim()) SetTarget(EnsureVictim()->GetGUID()); } @@ -10801,8 +10800,7 @@ void Unit::SetConfused(bool apply) { if (IsAlive()) { - if (GetMotionMaster()->GetCurrentMovementGeneratorType() == CONFUSED_MOTION_TYPE) - GetMotionMaster()->MovementExpired(); + GetMotionMaster()->Remove(CONFUSED_MOTION_TYPE); if (GetVictim()) SetTarget(EnsureVictim()->GetGUID()); } @@ -10894,10 +10892,8 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au if (GetTypeId() == TYPEID_UNIT) { - if (MovementGenerator* movementGenerator = GetMotionMaster()->GetMotionSlot(MOTION_SLOT_IDLE)) - movementGenerator->Pause(0); - - GetMotionMaster()->Clear(MOTION_SLOT_ACTIVE); + PauseMovement(0, 0, false); + GetMotionMaster()->Clear(MOTION_PRIORITY_NORMAL); StopMoving(); @@ -11016,7 +11012,7 @@ void Unit::RemoveCharmedBy(Unit* charmer) RestoreFaction(); ///@todo Handle SLOT_IDLE motion resume - GetMotionMaster()->InitDefault(); + GetMotionMaster()->InitializeDefault(); if (Creature* creature = ToCreature()) { @@ -11085,8 +11081,6 @@ void Unit::RemoveCharmedBy(Unit* charmer) player->SetClientControl(this, true); } - EngageWithTarget(charmer); - // a guardian should always have charminfo if (playerCharmer && this != charmer->GetFirstControlled()) playerCharmer->SendRemoveControlBar(); @@ -11939,7 +11933,7 @@ void Unit::_ExitVehicle(Position const* exitPosition) init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), height, false); init.SetFacing(GetOrientation()); init.SetTransportExit(); - GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_VEHICLE_EXIT, MOTION_SLOT_CONTROLLED); + GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_VEHICLE_EXIT, MOTION_PRIORITY_HIGHEST); if (player) player->ResummonPetTemporaryUnSummonedIfAny(); @@ -12300,7 +12294,7 @@ void Unit::SetFacingTo(float ori, bool force) init.DisableTransportPathTransformations(); // It makes no sense to target global orientation init.SetFacing(ori); - //GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_FACE, MOTION_SLOT_CONTROLLED); + //GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_FACE, MOTION_PRIORITY_HIGHEST); init.Launch(); } @@ -12315,7 +12309,7 @@ void Unit::SetFacingToObject(WorldObject const* object, bool force) init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false); init.SetFacing(GetAbsoluteAngle(object)); // when on transport, GetAbsoluteAngle will still return global coordinates (and angle) that needs transforming - //GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_FACE, MOTION_SLOT_CONTROLLED); + //GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_FACE, MOTION_PRIORITY_HIGHEST); init.Launch(); } diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index 6025d5f8692..152751c91ad 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -847,7 +847,7 @@ bool VehicleJoinEvent::Execute(uint64, uint32) init.MoveTo(veSeat->AttachmentOffset.X, veSeat->AttachmentOffset.Y, veSeat->AttachmentOffset.Z, false, true); init.SetFacing(0.0f); init.SetTransportEnter(); - Passenger->GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_VEHICLE_BOARD, MOTION_SLOT_CONTROLLED); + Passenger->GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_VEHICLE_BOARD, MOTION_PRIORITY_HIGHEST); if (Creature* creature = Target->GetBase()->ToCreature()) { diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp index 15d34caa157..d1409b24626 100644 --- a/src/server/game/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Handlers/BattleGroundHandler.cpp @@ -31,7 +31,6 @@ #include "Group.h" #include "Language.h" #include "Log.h" -#include "MotionMaster.h" #include "NPCPackets.h" #include "Object.h" #include "ObjectAccessor.h" @@ -364,11 +363,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPackets::Battleground::Battl _player->SpawnCorpseBones(); } // stop taxi flight at port - if (_player->IsInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } + _player->FinishTaxiFlight(); WorldPackets::Battleground::BattlefieldStatusActive battlefieldStatus; sBattlegroundMgr->BuildBattlegroundStatusActive(&battlefieldStatus, bg, _player, battlefieldPort.Ticket.Id, _player->GetBattlegroundQueueJoinTime(bgQueueTypeId), bg->GetArenaType()); diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index ac873eb6d01..523bcc7c7a5 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -145,32 +145,32 @@ void WorldSession::HandleMoveWorldportAck() } // flight fast teleport case - if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) + if (GetPlayer()->IsInFlight()) { if (!_player->InBattleground()) { if (!seamlessTeleport) { // short preparations to continue flight - MovementGenerator* movementGenerator = GetPlayer()->GetMotionMaster()->top(); + MovementGenerator* movementGenerator = GetPlayer()->GetMotionMaster()->GetCurrentMovementGenerator(); movementGenerator->Initialize(GetPlayer()); } return; } // battleground state prepare, stop flight - GetPlayer()->GetMotionMaster()->MovementExpired(); - GetPlayer()->CleanupAfterTaxiFlight(); + GetPlayer()->FinishTaxiFlight(); } // resurrect character at enter into instance where his corpse exist after add to map - if (mEntry->IsDungeon() && !GetPlayer()->IsAlive()) + { if (GetPlayer()->GetCorpseLocation().GetMapId() == mEntry->ID) { GetPlayer()->ResurrectPlayer(0.5f, false); GetPlayer()->SpawnCorpseBones(); } + } bool allowMount = !mEntry->IsDungeon() || mEntry->IsBattlegroundOrArena(); if (mInstance) @@ -674,13 +674,11 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPackets::Movement::MoveSpline TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest); // far teleport case - if (curDestNode && curDestNode->ContinentID != GetPlayer()->GetMapId()) + if (curDestNode && curDestNode->ContinentID != GetPlayer()->GetMapId() && GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) { - if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) + if (FlightPathMovementGenerator* flight = dynamic_cast<FlightPathMovementGenerator*>(GetPlayer()->GetMotionMaster()->GetCurrentMovementGenerator())) { // short preparations to continue flight - FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); - flight->SetCurrentNodeAfterTeleport(); TaxiPathNodeEntry const* node = flight->GetPath()[flight->GetCurrentNode()]; flight->SkipCurrentNode(); diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index bb5e3323b11..67d9c4f00b0 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -153,7 +153,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe { case COMMAND_STAY: //flat=1792 //STAY pet->StopMoving(); - pet->GetMotionMaster()->Clear(false); + pet->GetMotionMaster()->Clear(); pet->GetMotionMaster()->MoveIdle(); charmInfo->SetCommandState(COMMAND_STAY); @@ -261,7 +261,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe break; case COMMAND_MOVE_TO: pet->StopMoving(); - pet->GetMotionMaster()->Clear(false); + pet->GetMotionMaster()->Clear(); pet->GetMotionMaster()->MovePoint(0, pos); charmInfo->SetCommandState(COMMAND_MOVE_TO); diff --git a/src/server/game/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp index 2b8c1098e8c..da4800ca319 100644 --- a/src/server/game/Handlers/TaxiHandler.cpp +++ b/src/server/game/Handlers/TaxiHandler.cpp @@ -130,7 +130,7 @@ void WorldSession::SendDoFlight(uint32 mountDisplayId, uint32 path, uint32 pathN if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - GetPlayer()->GetMotionMaster()->Clear(MOTION_SLOT_CONTROLLED); + GetPlayer()->GetMotionMaster()->Remove(FLIGHT_MOTION_TYPE); if (mountDisplayId) GetPlayer()->Mount(mountDisplayId); @@ -231,11 +231,10 @@ void WorldSession::SendActivateTaxiReply(ActivateTaxiReply reply) void WorldSession::HandleTaxiRequestEarlyLanding(WorldPackets::Taxi::TaxiRequestEarlyLanding& /*taxiRequestEarlyLanding*/) { - if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) + if (FlightPathMovementGenerator* flight = dynamic_cast<FlightPathMovementGenerator*>(GetPlayer()->GetMotionMaster()->GetCurrentMovementGenerator())) { if (GetPlayer()->m_taxi.RequestEarlyLanding()) { - FlightPathMovementGenerator* flight = static_cast<FlightPathMovementGenerator*>(GetPlayer()->GetMotionMaster()->top()); flight->LoadPath(GetPlayer(), flight->GetPath()[flight->GetCurrentNode()]->NodeIndex); flight->Reset(GetPlayer()); } diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index ad84dd0e38c..3e935230c24 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -1642,7 +1642,7 @@ bool Map::CreatureRespawnRelocation(Creature* c, bool diffGridOnly) if (CreatureCellRelocation(c, resp_cell)) { c->Relocate(resp_x, resp_y, resp_z, resp_o); - c->GetMotionMaster()->Initialize(); // prevent possible problems with default move generators + c->GetMotionMaster()->Initialize(); // prevent possible problems with default move generators //CreatureRelocationNotify(c, resp_cell, resp_cell.GetCellCoord()); c->UpdatePositionData(); c->UpdateObjectVisibility(false); diff --git a/src/server/game/Maps/MapScripts.cpp b/src/server/game/Maps/MapScripts.cpp index ad2c744b844..c82bb7212fa 100644 --- a/src/server/game/Maps/MapScripts.cpp +++ b/src/server/game/Maps/MapScripts.cpp @@ -849,7 +849,6 @@ void Map::ScriptsProcess() if (!cSource->IsAlive()) return; - cSource->GetMotionMaster()->MovementExpired(); cSource->GetMotionMaster()->MoveIdle(); switch (step.script->Movement.MovementType) diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 8a15659481c..402b89a8387 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -5764,7 +5764,8 @@ enum EventId EVENT_FACE = 1006, EVENT_VEHICLE_BOARD = 1007, - EVENT_VEHICLE_EXIT = 1008 + EVENT_VEHICLE_EXIT = 1008, + EVENT_ASSIST_MOVE = 1009, }; enum ResponseCodes diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index d2ebbf22faa..b03fbd08497 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -16,13 +16,15 @@ */ #include "MotionMaster.h" +#include "AbstractFollower.h" #include "Creature.h" #include "CreatureAISelector.h" +#include "Containers.h" #include "DB2Stores.h" +#include "Errors.h" #include "G3DPosition.hpp" #include "Log.h" #include "Map.h" -#include "MovementGenerator.h" #include "MoveSpline.h" #include "MoveSplineInit.h" #include "PathGenerator.h" @@ -31,6 +33,8 @@ #include "ScriptSystem.h" #include "Unit.h" #include "WaypointDefines.h" +#include <algorithm> +#include <iterator> #include "ChaseMovementGenerator.h" #include "ConfusedMovementGenerator.h" @@ -56,144 +60,465 @@ inline bool IsStatic(MovementGenerator* movement) return (movement == GetIdleMovementGenerator()); } +inline void MovementGeneratorPointerDeleter(MovementGenerator* a) +{ + if (a != nullptr && !IsStatic(a)) + delete a; +} + +void MovementGeneratorDeleter::operator()(MovementGenerator * a) +{ + MovementGeneratorPointerDeleter(a); +} + +bool MovementGeneratorComparator::operator()(MovementGenerator const* a, MovementGenerator const* b) const +{ + if (a->Mode > b->Mode) + return true; + else if (a->Mode == b->Mode) + return a->Priority > b->Priority; + + return false; +} + +MovementGeneratorInformation::MovementGeneratorInformation(MovementGeneratorType type, ObjectGuid targetGUID, std::string const& targetName) : Type(type), TargetGUID(targetGUID), TargetName(targetName) { } + +MotionMaster::MotionMaster(Unit* unit) : _owner(unit), _defaultGenerator(nullptr), _flags(MOTIONMASTER_FLAG_NONE) { } + MotionMaster::~MotionMaster() { - // clear ALL movement generators (including default) - while (!empty()) + _delayedActions.clear(); + + for (auto itr = _generators.begin(); itr != _generators.end(); itr = _generators.erase(itr)) + MovementGeneratorPointerDeleter(*itr); +} + +void MotionMaster::Initialize() +{ + if (HasFlag(MOTIONMASTER_FLAG_UPDATE)) { - MovementGenerator* movement = top(); - pop(); - if (movement && !IsStatic(movement)) - delete movement; + std::function<void()> action = [this]() + { + Initialize(); + }; + _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_INITIALIZE); + return; } - while (!_expireList.empty()) + DirectInitialize(); +} + +void MotionMaster::InitializeDefault() +{ + Add(FactorySelector::SelectMovementGenerator(_owner), MOTION_SLOT_DEFAULT); +} + +bool MotionMaster::Empty() const +{ + return !_defaultGenerator && _generators.empty(); +} + +uint32 MotionMaster::Size() const +{ + return _defaultGenerator ? 1 : 0 + uint32(_generators.size()); +} + +std::vector<MovementGeneratorInformation> MotionMaster::GetMovementGeneratorsInformation() const +{ + std::vector<MovementGeneratorInformation> list; + + if (_defaultGenerator) + list.emplace_back(_defaultGenerator->GetMovementGeneratorType(), ObjectGuid::Empty, std::string()); + + for (auto itr = _generators.begin(); itr != _generators.end(); ++itr) { - delete _expireList.back(); - _expireList.pop_back(); + MovementGenerator* movement = *itr; + MovementGeneratorType const type = movement->GetMovementGeneratorType(); + switch (type) + { + case CHASE_MOTION_TYPE: + case FOLLOW_MOTION_TYPE: + if (AbstractFollower* followInformation = dynamic_cast<AbstractFollower*>(movement)) + { + if (Unit* target = followInformation->GetTarget()) + list.emplace_back(type, target->GetGUID(), target->GetName()); + else + list.emplace_back(type, ObjectGuid::Empty, std::string()); + } + else + list.emplace_back(type, ObjectGuid::Empty, std::string()); + break; + default: + list.emplace_back(type, ObjectGuid::Empty, std::string()); + break; + } } + + return list; } -MovementGenerator* MotionMaster::top() const +MovementSlot MotionMaster::GetCurrentSlot() const { - ASSERT(!empty()); + if (!_generators.empty()) + return MOTION_SLOT_ACTIVE; - return _slot[_top]; + if (_defaultGenerator) + return MOTION_SLOT_DEFAULT; + + return MAX_MOTION_SLOT; } -void MotionMaster::Initialize() +MovementGenerator* MotionMaster::GetCurrentMovementGenerator() const +{ + if (!_generators.empty()) + return *_generators.begin(); + + if (_defaultGenerator) + return _defaultGenerator.get(); + + return nullptr; +} + +MovementGeneratorType MotionMaster::GetCurrentMovementGeneratorType() const +{ + if (Empty()) + return MAX_MOTION_TYPE; + + MovementGenerator const* movement = GetCurrentMovementGenerator(); + if (!movement) + return MAX_MOTION_TYPE; + + return movement->GetMovementGeneratorType(); +} + +MovementGeneratorType MotionMaster::GetCurrentMovementGeneratorType(MovementSlot slot) const +{ + if (Empty() || IsInvalidMovementSlot(slot)) + return MAX_MOTION_TYPE; + + if (slot == MOTION_SLOT_ACTIVE && !_generators.empty()) + return (*_generators.begin())->GetMovementGeneratorType(); + + if (slot == MOTION_SLOT_DEFAULT && _defaultGenerator) + return _defaultGenerator->GetMovementGeneratorType(); + + return MAX_MOTION_TYPE; +} + +MovementGenerator* MotionMaster::GetCurrentMovementGenerator(MovementSlot slot) const +{ + if (Empty() || IsInvalidMovementSlot(slot)) + return nullptr; + + if (slot == MOTION_SLOT_ACTIVE && !_generators.empty()) + return *_generators.begin(); + + if (slot == MOTION_SLOT_DEFAULT && _defaultGenerator) + return _defaultGenerator.get(); + + return nullptr; +} + +MovementGenerator* MotionMaster::GetMovementGenerator(std::function<bool(MovementGenerator const*)> const& filter, MovementSlot slot) const { - // clear ALL movement generators (including default) - while (!empty()) + if (Empty() || IsInvalidMovementSlot(slot)) + return nullptr; + + MovementGenerator* movement = nullptr; + switch (slot) { - MovementGenerator* curr = top(); - pop(); - if (curr) - DirectDelete(curr); + case MOTION_SLOT_DEFAULT: + if (_defaultGenerator && filter(_defaultGenerator.get())) + movement = _defaultGenerator.get(); + break; + case MOTION_SLOT_ACTIVE: + if (!_generators.empty()) + { + auto itr = std::find_if(_generators.begin(), _generators.end(), std::ref(filter)); + if (itr != _generators.end()) + movement = *itr; + } + break; + default: + break; } - InitDefault(); + return movement; } -// set new default movement generator -void MotionMaster::InitDefault() +bool MotionMaster::HasMovementGenerator(std::function<bool(MovementGenerator const*)> const& filter, MovementSlot slot) const { - Mutate(FactorySelector::SelectMovementGenerator(_owner), MOTION_SLOT_IDLE); + if (Empty() || IsInvalidMovementSlot(slot)) + return false; + + bool value = false; + switch (slot) + { + case MOTION_SLOT_DEFAULT: + if (_defaultGenerator && filter(_defaultGenerator.get())) + value = true; + break; + case MOTION_SLOT_ACTIVE: + if (!_generators.empty()) + { + auto itr = std::find_if(_generators.begin(), _generators.end(), std::ref(filter)); + value = itr != _generators.end(); + } + break; + default: + break; + } + + return value; } -void MotionMaster::UpdateMotion(uint32 diff) +void MotionMaster::Update(uint32 diff) { if (!_owner) return; - ASSERT(!empty()); + ASSERT(!Empty(), "MotionMaster:Update: update called without Initializing! (%s)", _owner->GetGUID().ToString().c_str()); - _cleanFlag |= MOTIONMMASTER_CLEANFLAG_UPDATE; - if (!top()->Update(_owner, diff)) + AddFlag(MOTIONMASTER_FLAG_UPDATE); + + MovementGenerator* top = GetCurrentMovementGenerator(); + if (HasFlag(MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING) && IsStatic(top)) { - _cleanFlag &= ~MOTIONMMASTER_CLEANFLAG_UPDATE; - MovementExpired(); + RemoveFlag(MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING); + top->Initialize(_owner); } - else - _cleanFlag &= ~MOTIONMMASTER_CLEANFLAG_UPDATE; + if (top->HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING)) + top->Initialize(_owner); + if (top->HasFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED)) + top->Reset(_owner); + + ASSERT(!top->HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING | MOVEMENTGENERATOR_FLAG_DEACTIVATED), "MotionMaster:Update: update called on an uninitialized top! (%s) (type: %u, flags: %u)", _owner->GetGUID().ToString().c_str(), top->GetMovementGeneratorType(), top->Flags); + + if (!top->Update(_owner, diff)) + { + ASSERT(top == GetCurrentMovementGenerator(), "MotionMaster::Update: top was modified while updating! (%s)", _owner->GetGUID().ToString().c_str()); + + // Since all the actions that modify any slot are delayed, this movement is guaranteed to be top + Pop(true, true); // Natural, and only, call to MovementInform + } + + RemoveFlag(MOTIONMASTER_FLAG_UPDATE); - if (!_expireList.empty()) - ClearExpireList(); + while (!_delayedActions.empty()) + { + _delayedActions.front().Resolve(); + _delayedActions.pop_front(); + } } -void MotionMaster::Clear(bool reset /*= true*/) +void MotionMaster::Add(MovementGenerator* movement, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/) { - if (_cleanFlag & MOTIONMMASTER_CLEANFLAG_UPDATE) + if (!movement) + return; + + if (IsInvalidMovementSlot(slot)) { - if (reset) - _cleanFlag |= MOTIONMMASTER_CLEANFLAG_RESET; - else - _cleanFlag &= ~MOTIONMMASTER_CLEANFLAG_RESET; - DelayedClean(); + delete movement; + return; + } + + if (HasFlag(MOTIONMASTER_FLAG_UPDATE)) + { + std::function<void()> action = [this, movement, slot]() + { + Add(movement, slot); + }; + _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_ADD); } else - DirectClean(reset); + DirectAdd(movement, slot); } -void MotionMaster::Clear(MovementSlot slot) +void MotionMaster::Remove(MovementGenerator* movement, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/) { - if (empty() || IsInvalidMovementSlot(slot)) + if (!movement || IsInvalidMovementSlot(slot)) return; - if (_cleanFlag & MOTIONMMASTER_CLEANFLAG_UPDATE) - DelayedClean(slot); - else - DirectClean(slot); + if (HasFlag(MOTIONMASTER_FLAG_UPDATE)) + { + std::function<void()> action = [this, movement, slot]() + { + Remove(movement, slot); + }; + _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_REMOVE); + return; + } + + if (Empty()) + return; + + switch (slot) + { + case MOTION_SLOT_DEFAULT: + if (_defaultGenerator && _defaultGenerator.get() == movement) + DirectClearDefault(); + break; + case MOTION_SLOT_ACTIVE: + if (!_generators.empty()) + { + auto itr = _generators.find(movement); + if (itr != _generators.end()) + { + MovementGenerator* pointer = *itr; + bool const top = GetCurrentMovementGenerator() == pointer; + _generators.erase(pointer); + Delete(pointer, top, false); + } + } + break; + default: + break; + } } -void MotionMaster::MovementExpired(bool reset /*= true*/) +void MotionMaster::Remove(MovementGeneratorType type, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/) { - if (_cleanFlag & MOTIONMMASTER_CLEANFLAG_UPDATE) + if (IsInvalidMovementGeneratorType(type) || IsInvalidMovementSlot(slot)) + return; + + if (HasFlag(MOTIONMASTER_FLAG_UPDATE)) { - if (reset) - _cleanFlag |= MOTIONMMASTER_CLEANFLAG_RESET; - else - _cleanFlag &= ~MOTIONMMASTER_CLEANFLAG_RESET; - DelayedExpire(); + std::function<void()> action = [this, type, slot]() + { + Remove(type, slot); + }; + _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_REMOVE_TYPE); + return; + } + + if (Empty()) + return; + + switch (slot) + { + case MOTION_SLOT_DEFAULT: + if (_defaultGenerator && _defaultGenerator->GetMovementGeneratorType() == type) + DirectClearDefault(); + break; + case MOTION_SLOT_ACTIVE: + if (!_generators.empty()) + { + auto itr = std::find_if(_generators.begin(), _generators.end(), [type](MovementGenerator const* a) -> bool + { + return a->GetMovementGeneratorType() == type; + }); + + if (itr != _generators.end()) + { + MovementGenerator* pointer = *itr; + bool const top = GetCurrentMovementGenerator() == pointer; + _generators.erase(pointer); + Delete(pointer, top, false); + } + } + break; + default: + break; } - else - DirectExpire(reset); } -MovementGeneratorType MotionMaster::GetCurrentMovementGeneratorType() const +void MotionMaster::Clear() { - if (empty()) - return MAX_MOTION_TYPE; + if (HasFlag(MOTIONMASTER_FLAG_UPDATE)) + { + std::function<void()> action = [this]() + { + Clear(); + }; + _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_CLEAR); + return; + } - MovementGenerator* movement = top(); - if (!movement) - return MAX_MOTION_TYPE; + if (!Empty()) + DirectClear(); +} - return movement->GetMovementGeneratorType(); +void MotionMaster::Clear(MovementSlot slot) +{ + if (IsInvalidMovementSlot(slot)) + return; + + if (HasFlag(MOTIONMASTER_FLAG_UPDATE)) + { + std::function<void()> action = [this, slot]() + { + Clear(slot); + }; + _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_CLEAR_SLOT); + return; + } + + if (Empty()) + return; + + switch (slot) + { + case MOTION_SLOT_DEFAULT: + DirectClearDefault(); + break; + case MOTION_SLOT_ACTIVE: + DirectClear(); + break; + default: + break; + } } -MovementGeneratorType MotionMaster::GetMotionSlotType(MovementSlot slot) const +void MotionMaster::Clear(MovementGeneratorMode mode) { - if (empty() || IsInvalidMovementSlot(slot) || !_slot[slot]) - return MAX_MOTION_TYPE; + if (HasFlag(MOTIONMASTER_FLAG_UPDATE)) + { + std::function<void()> action = [this, mode]() + { + Clear(mode); + }; + _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_CLEAR_MODE); + return; + } + + if (Empty()) + return; - return _slot[slot]->GetMovementGeneratorType(); + std::function<bool(MovementGenerator*)> criteria = [mode](MovementGenerator* a) -> bool + { + return a->Mode == mode; + }; + DirectClear(criteria); } -MovementGenerator* MotionMaster::GetMotionSlot(MovementSlot slot) const +void MotionMaster::Clear(MovementGeneratorPriority priority) { - if (empty() || IsInvalidMovementSlot(slot) || !_slot[slot]) - return nullptr; + if (HasFlag(MOTIONMASTER_FLAG_UPDATE)) + { + std::function<void()> action = [this, priority]() + { + Clear(priority); + }; + _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_CLEAR_PRIORITY); + return; + } - return _slot[slot]; + if (Empty()) + return; + + std::function<bool(MovementGenerator*)> criteria = [priority](MovementGenerator* a) -> bool + { + return a->Priority == priority; + }; + DirectClear(criteria); } void MotionMaster::PropagateSpeedChange() { - if (empty()) + if (Empty()) return; - MovementGenerator* movement = top(); + MovementGenerator* movement = GetCurrentMovementGenerator(); if (!movement) return; @@ -214,9 +539,7 @@ bool MotionMaster::GetDestination(float &x, float &y, float &z) void MotionMaster::MoveIdle() { - //! Should be preceded by MovementExpired or Clear if there's an overlying movementgenerator active - if (empty() || !IsStatic(top())) - Mutate(GetIdleMovementGenerator(), MOTION_SLOT_IDLE); + Add(GetIdleMovementGenerator(), MOTION_SLOT_DEFAULT); } void MotionMaster::MoveTargetedHome() @@ -228,18 +551,18 @@ void MotionMaster::MoveTargetedHome() return; } - Clear(false); + Clear(); Unit* target = owner->GetCharmerOrOwner(); if (!target) { TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTargetedHome: '%s', targeted home.", _owner->GetGUID().ToString().c_str()); - Mutate(new HomeMovementGenerator<Creature>(), MOTION_SLOT_ACTIVE); + Add(new HomeMovementGenerator<Creature>()); } else { TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTargetedHome: '%s', starts following '%s'", _owner->GetGUID().ToString().c_str(), target->GetGUID().ToString().c_str()); - Mutate(new FollowMovementGenerator(target, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE), MOTION_SLOT_ACTIVE); + Add(new FollowMovementGenerator(target, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE)); } } @@ -248,28 +571,28 @@ void MotionMaster::MoveRandom(float spawndist) if (_owner->GetTypeId() == TYPEID_UNIT) { TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveRandom: '%s', started random movement (spawnDist: %f)", _owner->GetGUID().ToString().c_str(), spawndist); - Mutate(new RandomMovementGenerator<Creature>(spawndist), MOTION_SLOT_IDLE); + Add(new RandomMovementGenerator<Creature>(spawndist), MOTION_SLOT_DEFAULT); } } -void MotionMaster::MoveFollow(Unit* target, float dist, ChaseAngle angle, MovementSlot slot) +void MotionMaster::MoveFollow(Unit* target, float dist, ChaseAngle angle, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/) { - // ignore movement request if target not exist + // Ignore movement request if target not exist if (!target || target == _owner) return; TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFollow: '%s', starts following '%s'", _owner->GetGUID().ToString().c_str(), target->GetGUID().ToString().c_str()); - Mutate(new FollowMovementGenerator(target, dist, angle), slot); + Add(new FollowMovementGenerator(target, dist, angle), slot); } void MotionMaster::MoveChase(Unit* target, Optional<ChaseRange> dist, Optional<ChaseAngle> angle) { - // ignore movement request if target not exist + // Ignore movement request if target not exist if (!target || target == _owner) return; TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveChase: '%s', starts chasing '%s'", _owner->GetGUID().ToString().c_str(), target->GetGUID().ToString().c_str()); - Mutate(new ChaseMovementGenerator(target, dist, angle), MOTION_SLOT_ACTIVE); + Add(new ChaseMovementGenerator(target, dist, angle)); } void MotionMaster::MoveConfused() @@ -277,12 +600,12 @@ void MotionMaster::MoveConfused() if (_owner->GetTypeId() == TYPEID_PLAYER) { TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveConfused: '%s', started confused movement.", _owner->GetGUID().ToString().c_str()); - Mutate(new ConfusedMovementGenerator<Player>(), MOTION_SLOT_CONTROLLED); + Add(new ConfusedMovementGenerator<Player>()); } else { TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveConfused: '%s', started confused movement.", _owner->GetGUID().ToString().c_str()); - Mutate(new ConfusedMovementGenerator<Creature>(), MOTION_SLOT_CONTROLLED); + Add(new ConfusedMovementGenerator<Creature>()); } } @@ -295,12 +618,12 @@ void MotionMaster::MoveFleeing(Unit* enemy, uint32 time) if (_owner->GetTypeId() == TYPEID_UNIT) { if (time) - Mutate(new TimedFleeingMovementGenerator(enemy->GetGUID(), time), MOTION_SLOT_CONTROLLED); + Add(new TimedFleeingMovementGenerator(enemy->GetGUID(), time)); else - Mutate(new FleeingMovementGenerator<Creature>(enemy->GetGUID()), MOTION_SLOT_CONTROLLED); + Add(new FleeingMovementGenerator<Creature>(enemy->GetGUID())); } else - Mutate(new FleeingMovementGenerator<Player>(enemy->GetGUID()), MOTION_SLOT_CONTROLLED); + Add(new FleeingMovementGenerator<Player>(enemy->GetGUID())); } void MotionMaster::MovePoint(uint32 id, Position const& pos, bool generatePath/* = true*/, Optional<float> finalOrient/* = {}*/) @@ -313,12 +636,12 @@ void MotionMaster::MovePoint(uint32 id, float x, float y, float z, bool generate if (_owner->GetTypeId() == TYPEID_PLAYER) { TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePoint: '%s', targeted point Id: %u (X: %f, Y: %f, Z: %f)", _owner->GetGUID().ToString().c_str(), id, x, y, z); - Mutate(new PointMovementGenerator<Player>(id, x, y, z, generatePath, 0.0f, nullptr, nullptr, finalOrient), MOTION_SLOT_ACTIVE); + Add(new PointMovementGenerator<Player>(id, x, y, z, generatePath, 0.0f, finalOrient)); } else { TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePoint: '%s', targeted point Id: %u (X: %f, Y: %f, Z: %f)", _owner->GetGUID().ToString().c_str(), id, x, y, z); - Mutate(new PointMovementGenerator<Creature>(id, x, y, z, generatePath, 0.0f, nullptr, nullptr, finalOrient), MOTION_SLOT_ACTIVE); + Add(new PointMovementGenerator<Creature>(id, x, y, z, generatePath, 0.0f, finalOrient)); } } @@ -334,11 +657,11 @@ void MotionMaster::MoveCloserAndStop(uint32 id, Unit* target, float distance) } else { - // we are already close enough. We just need to turn toward the target without changing position. + // We are already close enough. We just need to turn toward the target without changing position. Movement::MoveSplineInit init(_owner); init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ()); init.SetFacing(target); - Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id), MOTION_SLOT_ACTIVE); + Add(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id)); } } @@ -349,7 +672,7 @@ void MotionMaster::MoveLand(uint32 id, Position const& pos) Movement::MoveSplineInit init(_owner); init.MoveTo(PositionToVector3(pos)); init.SetAnimation(Movement::ToGround); - Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id), MOTION_SLOT_ACTIVE); + Add(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id)); } void MotionMaster::MoveTakeoff(uint32 id, Position const& pos) @@ -359,24 +682,31 @@ void MotionMaster::MoveTakeoff(uint32 id, Position const& pos) Movement::MoveSplineInit init(_owner); init.MoveTo(PositionToVector3(pos)); init.SetAnimation(Movement::ToFly); - Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id), MOTION_SLOT_ACTIVE); + Add(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id)); } void MotionMaster::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*/) { +/* if (_slot[MOTION_SLOT_CONTROLLED] && _slot[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE) return; - +*/ if (_owner->GetTypeId() == TYPEID_PLAYER) { TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveCharge: '%s', charging point Id: %u (X: %f, Y: %f, Z: %f)", _owner->GetGUID().ToString().c_str(), id, x, y, z); - Mutate(new PointMovementGenerator<Player>(id, x, y, z, generatePath, speed, target, spellEffectExtraData), MOTION_SLOT_CONTROLLED); + PointMovementGenerator<Player>* movement = new PointMovementGenerator<Player>(id, x, y, z, generatePath, speed, {}, target, spellEffectExtraData); + movement->Priority = MOTION_PRIORITY_HIGHEST; + movement->BaseUnitState = UNIT_STATE_CHARGING; + Add(movement); } else { TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveCharge: '%s', charging point Id: %u (X: %f, Y: %f, Z: %f)", _owner->GetGUID().ToString().c_str(), id, x, y, z); - Mutate(new PointMovementGenerator<Creature>(id, x, y, z, generatePath, speed, target, spellEffectExtraData), MOTION_SLOT_CONTROLLED); + PointMovementGenerator<Creature>* movement = new PointMovementGenerator<Creature>(id, x, y, z, generatePath, speed, {}, target, spellEffectExtraData); + movement->Priority = MOTION_PRIORITY_HIGHEST; + movement->BaseUnitState = UNIT_STATE_CHARGING; + Add(movement); } } @@ -400,7 +730,7 @@ void MotionMaster::MoveCharge(PathGenerator const& path, float speed /*= SPEED_C void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/) { - // this function may make players fall below map + // This function may make players fall below map if (_owner->GetTypeId() == TYPEID_PLAYER) return; @@ -422,12 +752,14 @@ void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, floa if (spellEffectExtraData) init.SetSpellEffectExtraData(*spellEffectExtraData); - Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, 0), MOTION_SLOT_CONTROLLED); + GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, 0); + movement->Priority = MOTION_PRIORITY_HIGHEST; + Add(movement); } void MotionMaster::MoveJumpTo(float angle, float speedXY, float speedZ) { - // this function may make players fall below map + // This function may make players fall below map if (_owner->GetTypeId() == TYPEID_PLAYER) return; @@ -475,7 +807,10 @@ void MotionMaster::MoveJump(float x, float y, float z, float o, float speedXY, f arrivalSpellTargetGuid = arrivalCast->Target; } - Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id, arrivalSpellId, arrivalSpellTargetGuid), MOTION_SLOT_CONTROLLED); + GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id, arrivalSpellId, arrivalSpellTargetGuid); + movement->Priority = MOTION_PRIORITY_HIGHEST; + movement->BaseUnitState = UNIT_STATE_JUMPING; + Add(movement); } void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount) @@ -512,7 +847,7 @@ void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool init.SetCyclic(); } - Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, 0), MOTION_SLOT_ACTIVE); + Add(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, 0)); } void MotionMaster::MoveSmoothPath(uint32 pointId, Position const* pathPoints, size_t pathSize, bool walk, bool fly) @@ -535,9 +870,9 @@ void MotionMaster::MoveSmoothPath(uint32 pointId, Position const* pathPoints, si init.SetWalk(walk); // This code is not correct - // GenericMovementGenerator does not affect UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE + // GenericMovementGenerator does not affect UNIT_STATE_ROAMING_MOVE // need to call PointMovementGenerator with various pointIds - Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, pointId), MOTION_SLOT_ACTIVE); + Add(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, pointId)); } void MotionMaster::MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk) @@ -559,7 +894,7 @@ void MotionMaster::MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool w void MotionMaster::MoveAlongSplineChain(uint32 pointId, std::vector<SplineChainLink> const& chain, bool walk) { - Mutate(new SplineChainMovementGenerator(pointId, chain, walk), MOTION_SLOT_ACTIVE); + Add(new SplineChainMovementGenerator(pointId, chain, walk)); } void MotionMaster::ResumeSplineChain(SplineChainResumeInfo const& info) @@ -569,12 +904,12 @@ void MotionMaster::ResumeSplineChain(SplineChainResumeInfo const& info) TC_LOG_ERROR("movement.motionmaster", "MotionMaster::ResumeSplineChain: '%s', tried to resume a spline chain from empty info.", _owner->GetGUID().ToString().c_str()); return; } - Mutate(new SplineChainMovementGenerator(info), MOTION_SLOT_ACTIVE); + Add(new SplineChainMovementGenerator(info)); } void MotionMaster::MoveFall(uint32 id/* = 0*/) { - // use larger distance for vmap height search than in most other cases + // 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) { @@ -589,7 +924,7 @@ void MotionMaster::MoveFall(uint32 id/* = 0*/) _owner->SetFall(true); - // don't run spline movement for players + // Don't run spline movement for players if (_owner->GetTypeId() == TYPEID_PLAYER) { _owner->ToPlayer()->SetFallInformation(0, _owner->GetPositionZ()); @@ -599,7 +934,10 @@ void MotionMaster::MoveFall(uint32 id/* = 0*/) Movement::MoveSplineInit init(_owner); init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), tz + _owner->GetHoverOffset(), false); init.SetFall(); - Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id), MOTION_SLOT_CONTROLLED); + + GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id); + movement->Priority = MOTION_PRIORITY_HIGHEST; + Add(movement); } void MotionMaster::MoveSeekAssistance(float x, float y, float z) @@ -610,7 +948,7 @@ void MotionMaster::MoveSeekAssistance(float x, float y, float z) _owner->AttackStop(); _owner->CastStop(); _owner->ToCreature()->SetReactState(REACT_PASSIVE); - Mutate(new AssistanceMovementGenerator(x, y, z), MOTION_SLOT_ACTIVE); + Add(new AssistanceMovementGenerator(EVENT_ASSIST_MOVE, x, y, z)); } else TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveSeekAssistance: '%s', attempted to seek assistance.", _owner->GetGUID().ToString().c_str()); @@ -621,7 +959,7 @@ void MotionMaster::MoveSeekAssistanceDistract(uint32 time) if (_owner->GetTypeId() == TYPEID_UNIT) { TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveSeekAssistanceDistract: '%s', is distracted after assistance call (Time: %u)", _owner->GetGUID().ToString().c_str(), time); - Mutate(new AssistanceDistractMovementGenerator(time), MOTION_SLOT_ACTIVE); + Add(new AssistanceDistractMovementGenerator(time, _owner->GetOrientation())); } else TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveSeekAssistanceDistract: '%s', attempted to call distract assistance.", _owner->GetGUID().ToString().c_str()); @@ -634,9 +972,13 @@ void MotionMaster::MoveTaxiFlight(uint32 path, uint32 pathnode) if (path < sTaxiPathNodesByPath.size()) { TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTaxiFlight: '%s', taxi to path Id: %u (node %u)", _owner->GetGUID().ToString().c_str(), path, pathnode); + + // Only one FLIGHT_MOTION_TYPE is allowed + Remove(FLIGHT_MOTION_TYPE); + FlightPathMovementGenerator* movement = new FlightPathMovementGenerator(); movement->LoadPath(_owner->ToPlayer(), pathnode); - Mutate(movement, MOTION_SLOT_CONTROLLED); + Add(movement); } else TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveTaxiFlight: '%s', attempted taxi to non-existing path Id: %u (node: %u)", _owner->GetGUID().ToString().c_str(), path, pathnode); @@ -645,17 +987,14 @@ void MotionMaster::MoveTaxiFlight(uint32 path, uint32 pathnode) TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveTaxiFlight: '%s', attempted taxi to path Id: %u (node: %u)", _owner->GetGUID().ToString().c_str(), path, pathnode); } -void MotionMaster::MoveDistract(uint32 timer) +void MotionMaster::MoveDistract(uint32 timer, float orientation) { +/* if (_slot[MOTION_SLOT_CONTROLLED]) return; - - if (_owner->GetTypeId() == TYPEID_PLAYER) - TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveDistract: '%s', distracted (timer: %u)", _owner->GetGUID().ToString().c_str(), timer); - else - TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveDistract: '%s', distracted (timer: %u)", _owner->GetGUID().ToString().c_str(), timer); - - Mutate(new DistractMovementGenerator(timer), MOTION_SLOT_CONTROLLED); +*/ + TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveDistract: '%s', distracted (timer: %u, orientation: %f)", _owner->GetGUID().ToString().c_str(), timer, orientation); + Add(new DistractMovementGenerator(timer, orientation)); } void MotionMaster::MovePath(uint32 pathId, bool repeatable) @@ -664,22 +1003,22 @@ void MotionMaster::MovePath(uint32 pathId, bool repeatable) return; TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '%s', starts moving over path Id: %u (repeatable: %s)", _owner->GetGUID().ToString().c_str(), pathId, repeatable ? "YES" : "NO"); - Mutate(new WaypointMovementGenerator<Creature>(pathId, repeatable), MOTION_SLOT_IDLE); + Add(new WaypointMovementGenerator<Creature>(pathId, repeatable), MOTION_SLOT_DEFAULT); } void MotionMaster::MovePath(WaypointPath& path, bool repeatable) { TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '%s', starts moving over path Id: %u (repeatable: %s)", _owner->GetGUID().ToString().c_str(), path.id, repeatable ? "YES" : "NO"); - Mutate(new WaypointMovementGenerator<Creature>(path, repeatable), MOTION_SLOT_IDLE); + Add(new WaypointMovementGenerator<Creature>(path, repeatable), MOTION_SLOT_DEFAULT); } -void MotionMaster::MoveRotate(uint32 time, RotateDirection direction) +void MotionMaster::MoveRotate(uint32 id, uint32 time, RotateDirection direction) { if (!time) return; TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveRotate: '%s', starts rotate (time: %u, direction: %u)", _owner->GetGUID().ToString().c_str(), time, direction); - Mutate(new RotateMovementGenerator(time, direction), MOTION_SLOT_ACTIVE); + Add(new RotateMovementGenerator(id, time, direction)); } void MotionMaster::MoveFormation(uint32 id, Position destination, uint32 moveType, bool forceRun /*= false*/, bool forceOrientation /*= false*/) @@ -687,49 +1026,85 @@ void MotionMaster::MoveFormation(uint32 id, Position destination, uint32 moveTyp if (_owner->GetTypeId() == TYPEID_UNIT) { TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFormation: '%s', targeted point Id: %u (X: %f, Y: %f, Z: %f)", _owner->GetGUID().ToString().c_str(), id, destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ()); - Mutate(new FormationMovementGenerator(id, destination, moveType, forceRun, forceOrientation), MOTION_SLOT_ACTIVE); + Add(new FormationMovementGenerator(id, destination, moveType, forceRun, forceOrientation)); } } -void MotionMaster::LaunchMoveSpline(Movement::MoveSplineInit&& init, uint32 id/*= 0*/, MovementSlot slot/*= MOTION_SLOT_ACTIVE*/, MovementGeneratorType type/*= EFFECT_MOTION_TYPE*/) +void MotionMaster::LaunchMoveSpline(Movement::MoveSplineInit&& init, uint32 id/*= 0*/, MovementGeneratorPriority priority/* = MOTION_PRIORITY_NORMAL*/, MovementGeneratorType type/*= EFFECT_MOTION_TYPE*/) { if (IsInvalidMovementGeneratorType(type)) { - TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::LaunchMoveSpline: '%s', tried to launch a spline with an invalid MovementGeneratorType: %u (Id: %u, Slot: %u)", _owner->GetGUID().ToString().c_str(), type, id, slot); + TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::LaunchMoveSpline: '%s', tried to launch a spline with an invalid MovementGeneratorType: %u (Id: %u, Priority: %u)", _owner->GetGUID().ToString().c_str(), type, id, priority); return; } - TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::LaunchMoveSpline: '%s', initiates spline Id: %u (Type: %u, Slot: %u)", _owner->GetGUID().ToString().c_str(), id, type, slot); - Mutate(new GenericMovementGenerator(std::move(init), type, id), slot); + TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::LaunchMoveSpline: '%s', initiates spline Id: %u (Type: %u, Priority: %u)", _owner->GetGUID().ToString().c_str(), id, type, priority); + + GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(init), type, id); + movement->Priority = priority; + Add(movement); } /******************** Private methods ********************/ -void MotionMaster::pop() +void MotionMaster::Pop(bool active, bool movementInform) { - if (empty()) - return; + MovementGenerator* pointer = *_generators.begin(); + _generators.erase(pointer); + Delete(pointer, active, movementInform); +} + +void MotionMaster::DirectInitialize() +{ + // Clear ALL movement generators (including default) + DirectClearDefault(); + DirectClear(); - _slot[_top] = nullptr; - while (!empty() && !top()) - --_top; + InitializeDefault(); } -bool MotionMaster::NeedInitTop() const +void MotionMaster::DirectClear() { - if (empty()) - return false; - return _initialize[_top]; + // First delete Top + if (!_generators.empty()) + Pop(true, false); + + // Then the rest + while (!_generators.empty()) + Pop(false, false); + + // Make sure the storage is empty + ClearBaseUnitStates(); } -void MotionMaster::InitTop() +void MotionMaster::DirectClearDefault() { - top()->Initialize(_owner); - _initialize[_top] = false; + if (_defaultGenerator) + DeleteDefault(_generators.empty(), false); } -void MotionMaster::Mutate(MovementGenerator *m, MovementSlot slot) +void MotionMaster::DirectClear(std::function<bool(MovementGenerator*)> const& filter) { + if (_generators.empty()) + return; + + MovementGenerator const* top = GetCurrentMovementGenerator(); + for (auto itr = _generators.begin(); itr != _generators.end();) + { + if (filter(*itr)) + { + MovementGenerator* movement = *itr; + itr = _generators.erase(itr); + Delete(movement, movement == top, false); + } + else + ++itr; + } +} + +void MotionMaster::DirectAdd(MovementGenerator* movement, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/) +{ +/* if (MovementGenerator* curr = _slot[slot]) { _slot[slot] = nullptr; // in case a new one is generated in this slot during directdelete @@ -751,131 +1126,108 @@ void MotionMaster::Mutate(MovementGenerator *m, MovementSlot slot) _initialize[slot] = false; m->Initialize(_owner); } -} +*/ -void MotionMaster::DirectClean(bool reset) -{ - while (size() > 1) - { - MovementGenerator* curr = top(); - pop(); - if (curr) - DirectDelete(curr); - } + /* + * NOTE: This mimics old behaviour: only one MOTION_SLOT_IDLE, MOTION_SLOT_ACTIVE, MOTION_SLOT_CONTROLLED + * On future changes support for multiple will be added + */ - if (empty()) - return; - - if (NeedInitTop()) - InitTop(); - else if (reset) - top()->Reset(_owner); -} - -void MotionMaster::DelayedClean() -{ - while (size() > 1) - { - MovementGenerator* curr = top(); - pop(); - if (curr) - DelayedDelete(curr); - } -} - -void MotionMaster::DirectClean(MovementSlot slot) -{ - if (MovementGenerator* motion = GetMotionSlot(slot)) - { - _slot[slot] = nullptr; - DirectDelete(motion); - } - - while (!empty() && !top()) - --_top; - - if (empty()) - Initialize(); - else if (NeedInitTop()) - InitTop(); -} - -void MotionMaster::DelayedClean(MovementSlot slot) -{ - if (MovementGenerator* motion = GetMotionSlot(slot)) + switch (slot) { - _slot[slot] = nullptr; - DelayedDelete(motion); + case MOTION_SLOT_DEFAULT: + if (_defaultGenerator) + _defaultGenerator->Finalize(_owner, _generators.empty(), false); + + _defaultGenerator = MovementGeneratorPointer(movement); + if (IsStatic(movement)) + AddFlag(MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING); + break; + case MOTION_SLOT_ACTIVE: + if (!_generators.empty()) + { + if (movement->Priority >= (*_generators.begin())->Priority) + { + MovementGenerator* pointer = *_generators.begin(); + if (movement->Priority == pointer->Priority) + { + _generators.erase(pointer); + Delete(pointer, true, false); + } + else + pointer->Deactivate(_owner); + } + else + { + auto itr = std::find_if(_generators.begin(), _generators.end(), [movement](MovementGenerator const* a) -> bool + { + return a->Priority == movement->Priority; + }); + + if (itr != _generators.end()) + { + MovementGenerator* pointer = *itr; + _generators.erase(pointer); + Delete(pointer, false, false); + } + } + } + else + _defaultGenerator->Deactivate(_owner); + + _generators.emplace(movement); + AddBaseUnitState(movement); + break; + default: + break; } - - while (!empty() && !top()) - --_top; } -void MotionMaster::DirectExpire(bool reset) +void MotionMaster::Delete(MovementGenerator* movement, bool active, bool movementInform) { - if (size() > 1) - { - MovementGenerator* curr = top(); - pop(); - DirectDelete(curr); - } - - while (!empty() && !top()) - --_top; + TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::Delete: deleting generator (Priority: %u, Flags: %u, BaseUnitState: %u, Type: %u), owner: '%s'", + movement->Priority, movement->Flags, movement->BaseUnitState, movement->GetMovementGeneratorType(), _owner->GetGUID().ToString().c_str()); - if (empty()) - Initialize(); - else if (NeedInitTop()) - InitTop(); - else if (reset) - top()->Reset(_owner); + movement->Finalize(_owner, active, movementInform); + ClearBaseUnitState(movement); + MovementGeneratorPointerDeleter(movement); } -void MotionMaster::DelayedExpire() +void MotionMaster::DeleteDefault(bool active, bool movementInform) { - if (size() > 1) - { - MovementGenerator* curr = top(); - pop(); - DelayedDelete(curr); - } + TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::DeleteDefault: deleting generator (Priority: %u, Flags: %u, BaseUnitState: %u, Type: %u), owner: '%s'", + _defaultGenerator->Priority, _defaultGenerator->Flags, _defaultGenerator->BaseUnitState, _defaultGenerator->GetMovementGeneratorType(), _owner->GetGUID().ToString().c_str()); - while (!empty() && !top()) - --_top; + _defaultGenerator->Finalize(_owner, active, movementInform); + _defaultGenerator = MovementGeneratorPointer(GetIdleMovementGenerator()); + AddFlag(MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING); } -void MotionMaster::DirectDelete(MovementGenerator* curr) +void MotionMaster::AddBaseUnitState(MovementGenerator const* movement) { - if (IsStatic(curr)) + if (!movement || !movement->BaseUnitState) return; - curr->Finalize(_owner); - delete curr; + _baseUnitStatesMap.emplace(movement->BaseUnitState, movement); + _owner->AddUnitState(movement->BaseUnitState); } -void MotionMaster::DelayedDelete(MovementGenerator* curr) +void MotionMaster::ClearBaseUnitState(MovementGenerator const* movement) { - TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::DelayedDelete: '%s', delayed deleting movement generator (type: %u)", _owner->GetGUID().ToString().c_str(), curr->GetMovementGeneratorType()); - if (IsStatic(curr)) + if (!movement || !movement->BaseUnitState) return; - _expireList.push_back(curr); + Trinity::Containers::MultimapErasePair(_baseUnitStatesMap, movement->BaseUnitState, movement); + if (_baseUnitStatesMap.count(movement->BaseUnitState) == 0) + _owner->ClearUnitState(movement->BaseUnitState); } -void MotionMaster::ClearExpireList() +void MotionMaster::ClearBaseUnitStates() { - for (auto itr : _expireList) - DirectDelete(itr); - - _expireList.clear(); - - if (empty()) - Initialize(); - else if (NeedInitTop()) - InitTop(); - else if (_cleanFlag & MOTIONMMASTER_CLEANFLAG_RESET) - top()->Reset(_owner); + uint32 unitState = 0; + for (auto itr = _baseUnitStatesMap.begin(); itr != _baseUnitStatesMap.end(); ++itr) + unitState |= itr->first; - _cleanFlag &= ~MOTIONMMASTER_CLEANFLAG_RESET; + _owner->ClearUnitState(unitState); + _baseUnitStatesMap.clear(); } diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index 5d78c875c7f..c02c71d3b53 100644 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -19,14 +19,19 @@ #define MOTIONMASTER_H #include "Common.h" +#include "ObjectGuid.h" #include "Optional.h" #include "MovementDefines.h" +#include "MovementGenerator.h" #include "SharedDefines.h" +#include <deque> +#include <functional> +#include <set> +#include <unordered_map> #include <vector> -class MovementGenerator; -class Unit; class PathGenerator; +class Unit; struct Position; struct SplineChainLink; struct SplineChainResumeInfo; @@ -38,38 +43,97 @@ namespace Movement struct SpellEffectExtraData; } -class TC_GAME_API MotionMaster +enum MotionMasterFlags : uint8 +{ + MOTIONMASTER_FLAG_NONE = 0x0, + MOTIONMASTER_FLAG_UPDATE = 0x1, // Update in progress + MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING = 0x2 +}; + +enum MotionMasterDelayedActionType : uint8 +{ + MOTIONMASTER_DELAYED_CLEAR = 0, + MOTIONMASTER_DELAYED_CLEAR_SLOT, + MOTIONMASTER_DELAYED_CLEAR_MODE, + MOTIONMASTER_DELAYED_CLEAR_PRIORITY, + MOTIONMASTER_DELAYED_ADD, + MOTIONMASTER_DELAYED_REMOVE, + MOTIONMASTER_DELAYED_REMOVE_TYPE, + MOTIONMASTER_DELAYED_INITIALIZE +}; + +struct MovementGeneratorDeleter +{ + void operator()(MovementGenerator* a); +}; + +struct MovementGeneratorComparator { public: - explicit MotionMaster(Unit* unit) : _owner(unit), _top(-1), _cleanFlag(MOTIONMMASTER_CLEANFLAG_NONE) - { - for (uint8 i = 0; i < MAX_MOTION_SLOT; ++i) - { - _slot[i] = nullptr; - _initialize[i] = true; - } - } - ~MotionMaster(); + bool operator()(MovementGenerator const* a, MovementGenerator const* b) const; +}; - bool empty() const { return (_top < 0); } - int size() const { return _top + 1; } - MovementGenerator* top() const; +struct MovementGeneratorInformation +{ + MovementGeneratorInformation(MovementGeneratorType type, ObjectGuid targetGUID, std::string const& targetName); - void Initialize(); - void InitDefault(); + MovementGeneratorType Type; + ObjectGuid TargetGUID; + std::string TargetName; +}; + +class MotionMasterDelayedAction +{ + public: + explicit MotionMasterDelayedAction(std::function<void()>&& action, MotionMasterDelayedActionType type) : Action(std::move(action)), Type(type) { } + ~MotionMasterDelayedAction() { } - void UpdateMotion(uint32 diff); + void Resolve() { Action(); } - void Clear(bool reset = true); - void Clear(MovementSlot slot); - void MovementExpired(bool reset = true); + std::function<void()> Action; + uint8 Type; +}; - MovementGeneratorType GetCurrentMovementGeneratorType() const; - MovementGeneratorType GetMotionSlotType(MovementSlot slot) const; - MovementGenerator* GetMotionSlot(MovementSlot slot) const; +class TC_GAME_API MotionMaster +{ + public: + explicit MotionMaster(Unit* unit); + ~MotionMaster(); - void PropagateSpeedChange(); + void Initialize(); + void InitializeDefault(); + bool Empty() const; + uint32 Size() const; + std::vector<MovementGeneratorInformation> GetMovementGeneratorsInformation() const; + MovementSlot GetCurrentSlot() const; + MovementGenerator* GetCurrentMovementGenerator() const; + MovementGeneratorType GetCurrentMovementGeneratorType() const; + MovementGeneratorType GetCurrentMovementGeneratorType(MovementSlot slot) const; + MovementGenerator* GetCurrentMovementGenerator(MovementSlot slot) const; + // Returns first found MovementGenerator that matches the given criteria + MovementGenerator* GetMovementGenerator(std::function<bool(MovementGenerator const*)> const& filter, MovementSlot slot = MOTION_SLOT_ACTIVE) const; + bool HasMovementGenerator(std::function<bool(MovementGenerator const*)> const& filter, MovementSlot slot = MOTION_SLOT_ACTIVE) const; + + void Update(uint32 diff); + void Add(MovementGenerator* movement, MovementSlot slot = MOTION_SLOT_ACTIVE); + // NOTE: MOTION_SLOT_DEFAULT will be autofilled with IDLE_MOTION_TYPE + void Remove(MovementGenerator* movement, MovementSlot slot = MOTION_SLOT_ACTIVE); + // Removes first found movement + // NOTE: MOTION_SLOT_DEFAULT will be autofilled with IDLE_MOTION_TYPE + void Remove(MovementGeneratorType type, MovementSlot slot = MOTION_SLOT_ACTIVE); + // NOTE: NOTE: MOTION_SLOT_DEFAULT wont be affected + void Clear(); + // Removes all movements for the given MovementSlot + // NOTE: MOTION_SLOT_DEFAULT will be autofilled with IDLE_MOTION_TYPE + void Clear(MovementSlot slot); + // Removes all movements with the given MovementGeneratorMode + // NOTE: MOTION_SLOT_DEFAULT wont be affected + void Clear(MovementGeneratorMode mode); + // Removes all movements with the given MovementGeneratorPriority + // NOTE: MOTION_SLOT_DEFAULT wont be affected + void Clear(MovementGeneratorPriority priority); + void PropagateSpeedChange(); bool GetDestination(float &x, float &y, float &z); void MoveIdle(); @@ -82,10 +146,11 @@ class TC_GAME_API MotionMaster void MoveFleeing(Unit* enemy, uint32 time = 0); void MovePoint(uint32 id, Position const& pos, bool generatePath = true, Optional<float> finalOrient = {}); void MovePoint(uint32 id, float x, float y, float z, bool generatePath = true, Optional<float> finalOrient = {}); - /* Makes the unit move toward the target until it is at a certain distance from it. The unit then stops. - Only works in 2D. - This method doesn't account for any movement done by the target. in other words, it only works if the target is stationary. - */ + /* + * Makes the unit move toward the target until it is at a certain distance from it. The unit then stops. + * Only works in 2D. + * This method doesn't account for any movement done by the target. in other words, it only works if the target is stationary. + */ 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); @@ -106,39 +171,41 @@ class TC_GAME_API MotionMaster void MoveSeekAssistance(float x, float y, float z); void MoveSeekAssistanceDistract(uint32 timer); void MoveTaxiFlight(uint32 path, uint32 pathnode); - void MoveDistract(uint32 time); + void MoveDistract(uint32 time, float orientation); void MovePath(uint32 pathId, bool repeatable); void MovePath(WaypointPath& path, bool repeatable); - void MoveRotate(uint32 time, RotateDirection direction); + void MoveRotate(uint32 id, uint32 time, RotateDirection direction); void MoveFormation(uint32 id, Position destination, uint32 moveType, bool forceRun = false, bool forceOrientation = false); - void LaunchMoveSpline(Movement::MoveSplineInit&& init, uint32 id = 0, MovementSlot slot = MOTION_SLOT_ACTIVE, MovementGeneratorType type = EFFECT_MOTION_TYPE); + void LaunchMoveSpline(Movement::MoveSplineInit&& init, uint32 id = 0, MovementGeneratorPriority priority = MOTION_PRIORITY_NORMAL, MovementGeneratorType type = EFFECT_MOTION_TYPE); private: - typedef std::vector<MovementGenerator*> MovementList; - - void pop(); - - bool NeedInitTop() const; - void InitTop(); - - void Mutate(MovementGenerator* m, MovementSlot slot); - - void DirectClean(bool reset); - void DelayedClean(); - void DirectClean(MovementSlot slot); - void DelayedClean(MovementSlot slot); - void DirectExpire(bool reset); - void DelayedExpire(); - void DirectDelete(MovementGenerator* curr); - void DelayedDelete(MovementGenerator* curr); - void ClearExpireList(); + typedef std::unique_ptr<MovementGenerator, MovementGeneratorDeleter> MovementGeneratorPointer; + typedef std::multiset<MovementGenerator*, MovementGeneratorComparator> MotionMasterContainer; + typedef std::unordered_multimap<uint32, MovementGenerator const*> MotionMasterUnitStatesContainer; + + void AddFlag(uint8 const flag) { _flags |= flag; } + bool HasFlag(uint8 const flag) const { return (_flags & flag) != 0; } + void RemoveFlag(uint8 const flag) { _flags &= ~flag; } + + void Pop(bool active, bool movementInform); + void DirectInitialize(); + void DirectClear(); + void DirectClearDefault(); + void DirectClear(std::function<bool(MovementGenerator*)> const& filter); + void DirectAdd(MovementGenerator* movement, MovementSlot slot); + + void Delete(MovementGenerator* movement, bool active, bool movementInform); + void DeleteDefault(bool active, bool movementInform); + void AddBaseUnitState(MovementGenerator const* movement); + void ClearBaseUnitState(MovementGenerator const* movement); + void ClearBaseUnitStates(); - MovementGenerator* _slot[MAX_MOTION_SLOT]; - bool _initialize[MAX_MOTION_SLOT]; - MovementList _expireList; Unit* _owner; - int _top; - uint8 _cleanFlag; + MovementGeneratorPointer _defaultGenerator; + MotionMasterContainer _generators; + MotionMasterUnitStatesContainer _baseUnitStatesMap; + std::deque<MotionMasterDelayedAction> _delayedActions; + uint8 _flags; }; #endif // MOTIONMASTER_H diff --git a/src/server/game/Movement/MovementDefines.h b/src/server/game/Movement/MovementDefines.h index 5e93e72eb76..3600e349aab 100644 --- a/src/server/game/Movement/MovementDefines.h +++ b/src/server/game/Movement/MovementDefines.h @@ -30,36 +30,41 @@ enum MovementGeneratorType : uint8 WAYPOINT_MOTION_TYPE = 2, // WaypointMovementGenerator.h MAX_DB_MOTION_TYPE = 3, // Below motion types can't be set in DB. CONFUSED_MOTION_TYPE = 4, // ConfusedMovementGenerator.h - CHASE_MOTION_TYPE = 5, // TargetedMovementGenerator.h + CHASE_MOTION_TYPE = 5, // ChaseMovementGenerator.h HOME_MOTION_TYPE = 6, // HomeMovementGenerator.h - FLIGHT_MOTION_TYPE = 7, // WaypointMovementGenerator.h + FLIGHT_MOTION_TYPE = 7, // FlightPathMovementGenerator.h POINT_MOTION_TYPE = 8, // PointMovementGenerator.h FLEEING_MOTION_TYPE = 9, // FleeingMovementGenerator.h DISTRACT_MOTION_TYPE = 10, // IdleMovementGenerator.h ASSISTANCE_MOTION_TYPE = 11, // PointMovementGenerator.h ASSISTANCE_DISTRACT_MOTION_TYPE = 12, // IdleMovementGenerator.h TIMED_FLEEING_MOTION_TYPE = 13, // FleeingMovementGenerator.h - FOLLOW_MOTION_TYPE = 14, - ROTATE_MOTION_TYPE = 15, + FOLLOW_MOTION_TYPE = 14, // FollowMovementGenerator.h + ROTATE_MOTION_TYPE = 15, // IdleMovementGenerator.h EFFECT_MOTION_TYPE = 16, SPLINE_CHAIN_MOTION_TYPE = 17, // SplineChainMovementGenerator.h FORMATION_MOTION_TYPE = 18, // FormationMovementGenerator.h MAX_MOTION_TYPE // limit }; -enum MovementSlot : uint8 +enum MovementGeneratorMode : uint8 { - MOTION_SLOT_IDLE = 0, - MOTION_SLOT_ACTIVE, - MOTION_SLOT_CONTROLLED, - MAX_MOTION_SLOT + MOTION_MODE_DEFAULT = 0, + MOTION_MODE_OVERRIDE }; -enum MotionMasterCleanFlags +enum MovementGeneratorPriority : uint8 { - MOTIONMMASTER_CLEANFLAG_NONE = 0, - MOTIONMMASTER_CLEANFLAG_UPDATE = 1, // Clear or Expire called from update - MOTIONMMASTER_CLEANFLAG_RESET = 2 // Flag if need top()->Reset() + MOTION_PRIORITY_NONE = 0, + MOTION_PRIORITY_NORMAL, + MOTION_PRIORITY_HIGHEST +}; + +enum MovementSlot : uint8 +{ + MOTION_SLOT_DEFAULT = 0, + MOTION_SLOT_ACTIVE, + MAX_MOTION_SLOT }; enum RotateDirection : uint8 diff --git a/src/server/game/Movement/MovementGenerator.h b/src/server/game/Movement/MovementGenerator.h index 03f96ba1538..235743dc429 100755 --- a/src/server/game/Movement/MovementGenerator.h +++ b/src/server/game/Movement/MovementGenerator.h @@ -27,22 +27,56 @@ class Unit; enum MovementGeneratorType : uint8; +enum MovementGeneratorFlags : uint16 +{ + MOVEMENTGENERATOR_FLAG_NONE = 0x000, + MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING = 0x001, + MOVEMENTGENERATOR_FLAG_INITIALIZED = 0x002, + MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING = 0x004, + MOVEMENTGENERATOR_FLAG_INTERRUPTED = 0x008, + MOVEMENTGENERATOR_FLAG_PAUSED = 0x010, + MOVEMENTGENERATOR_FLAG_TIMED_PAUSED = 0x020, + MOVEMENTGENERATOR_FLAG_DEACTIVATED = 0x040, + MOVEMENTGENERATOR_FLAG_INFORM_ENABLED = 0x080, + MOVEMENTGENERATOR_FLAG_FINALIZED = 0x100, + + MOVEMENTGENERATOR_FLAG_TRANSITORY = MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING | MOVEMENTGENERATOR_FLAG_INTERRUPTED +}; + class TC_GAME_API MovementGenerator { public: + MovementGenerator() : Mode(0), Priority(0), Flags(MOVEMENTGENERATOR_FLAG_NONE), BaseUnitState(0) { } virtual ~MovementGenerator(); + // on top first update virtual void Initialize(Unit*) = 0; - virtual void Finalize(Unit*) = 0; + // on top reassign virtual void Reset(Unit*) = 0; + // on top on MotionMaster::Update virtual bool Update(Unit*, uint32 diff) = 0; + // on current top if another movement replaces + virtual void Deactivate(Unit*) = 0; + // on movement delete + virtual void Finalize(Unit*, bool, bool) = 0; virtual MovementGeneratorType GetMovementGeneratorType() const = 0; virtual void UnitSpeedChanged() { } - virtual void Pause(uint32/* timer = 0*/) { } // timer in ms - virtual void Resume(uint32/* overrideTimer = 0*/) { } // timer in ms - - virtual bool GetResetPosition(Unit*, float&/* x*/, float&/* y*/, float&/* z*/) { return false; } // used by Evade code for select point to evade with expected restart default movement + // timer in ms + virtual void Pause(uint32/* timer = 0*/) { } + // timer in ms + virtual void Resume(uint32/* overrideTimer = 0*/) { } + // used by Evade code for select point to evade with expected restart default movement + virtual bool GetResetPosition(Unit*, float&/* x*/, float&/* y*/, float&/* z*/) { return false; } + + void AddFlag(uint16 const flag) { Flags |= flag; } + bool HasFlag(uint16 const flag) const { return (Flags & flag) != 0; } + void RemoveFlag(uint16 const flag) { Flags &= ~flag; } + + uint8 Mode; + uint8 Priority; + uint16 Flags; + uint32 BaseUnitState; }; template<class T, class D> @@ -54,11 +88,6 @@ class MovementGeneratorMedium : public MovementGenerator (static_cast<D*>(this))->DoInitialize(static_cast<T*>(owner)); } - void Finalize(Unit* owner) override - { - (static_cast<D*>(this))->DoFinalize(static_cast<T*>(owner)); - } - void Reset(Unit* owner) override { (static_cast<D*>(this))->DoReset(static_cast<T*>(owner)); @@ -68,6 +97,16 @@ class MovementGeneratorMedium : public MovementGenerator { return (static_cast<D*>(this))->DoUpdate(static_cast<T*>(owner), diff); } + + void Deactivate(Unit* owner) override + { + (static_cast<D*>(this))->DoDeactivate(static_cast<T*>(owner)); + } + + void Finalize(Unit* owner, bool active, bool movementInform) override + { + (static_cast<D*>(this))->DoFinalize(static_cast<T*>(owner), active, movementInform); + } }; typedef FactoryHolder<MovementGenerator, Unit, MovementGeneratorType> MovementGeneratorCreator; diff --git a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp index 490b98da128..c20e34c2bfb 100644 --- a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp @@ -31,14 +31,7 @@ static bool IsMutualChase(Unit* owner, Unit* target) if (target->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) return false; - return (static_cast<ChaseMovementGenerator const*>(target->GetMotionMaster()->top())->GetTarget() == owner); -} - -static void DoMovementInform(Unit* owner, Unit* target) -{ - if (Creature* cOwner = owner->ToCreature()) - if (CreatureAI* ai = cOwner->AI()) - ai->MovementInform(CHASE_MOTION_TYPE, target->GetGUID().GetCounter()); + return (dynamic_cast<ChaseMovementGenerator const*>(target->GetMotionMaster()->GetCurrentMovementGenerator())->GetTarget() == owner); } static bool PositionOkay(Unit* owner, Unit* target, Optional<float> minDistance, Optional<float> maxDistance, Optional<ChaseAngle> angle) @@ -51,14 +44,40 @@ static bool PositionOkay(Unit* owner, Unit* target, Optional<float> minDistance, return !angle || angle->IsAngleOkay(target->GetRelativeAngle(owner)); } -ChaseMovementGenerator::ChaseMovementGenerator(Unit* target, Optional<ChaseRange> range, Optional<ChaseAngle> angle) : AbstractFollower(ASSERT_NOTNULL(target)), _range(range), _angle(angle) {} +static void DoMovementInform(Unit* owner, Unit* target) +{ + if (owner->GetTypeId() != TYPEID_UNIT) + return; + + Creature* creatureOwner = owner->ToCreature(); + if (creatureOwner->IsAIEnabled && creatureOwner->AI()) + creatureOwner->AI()->MovementInform(CHASE_MOTION_TYPE, target->GetGUID().GetCounter()); +} + +ChaseMovementGenerator::ChaseMovementGenerator(Unit* target, Optional<ChaseRange> range, Optional<ChaseAngle> angle) : AbstractFollower(ASSERT_NOTNULL(target)), _range(range), _angle(angle) +{ + Mode = MOTION_MODE_DEFAULT; + Priority = MOTION_PRIORITY_NORMAL; + Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + BaseUnitState = UNIT_STATE_CHASE; +} ChaseMovementGenerator::~ChaseMovementGenerator() = default; void ChaseMovementGenerator::Initialize(Unit* owner) { - owner->AddUnitState(UNIT_STATE_CHASE); + RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING); + AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED); + owner->SetWalk(false); _path = nullptr; + _lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f); +} + +void ChaseMovementGenerator::Reset(Unit* owner) +{ + RemoveFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); + + Initialize(owner); } bool ChaseMovementGenerator::Update(Unit* owner, uint32 diff) @@ -83,13 +102,13 @@ bool ChaseMovementGenerator::Update(Unit* owner, uint32 diff) return true; } - bool const mutualChase = IsMutualChase(owner, target); - float const hitboxSum = owner->GetCombatReach() + target->GetCombatReach(); - float const minRange = _range ? _range->MinRange + hitboxSum : CONTACT_DISTANCE; - float const minTarget = (_range ? _range->MinTolerance : 0.0f) + hitboxSum; - float const maxRange = _range ? _range->MaxRange + hitboxSum : owner->GetMeleeRange(target); // melee range already includes hitboxes - float const maxTarget = _range ? _range->MaxTolerance + hitboxSum : CONTACT_DISTANCE + hitboxSum; - Optional<ChaseAngle> angle = mutualChase ? Optional<ChaseAngle>() : _angle; + bool const mutualChase = IsMutualChase(owner, target); + float const hitboxSum = owner->GetCombatReach() + target->GetCombatReach(); + float const minRange = _range ? _range->MinRange + hitboxSum : CONTACT_DISTANCE; + float const minTarget = (_range ? _range->MinTolerance : 0.0f) + hitboxSum; + float const maxRange = _range ? _range->MaxRange + hitboxSum : owner->GetMeleeRange(target); // melee range already includes hitboxes + float const maxTarget = _range ? _range->MaxTolerance + hitboxSum : CONTACT_DISTANCE + hitboxSum; + Optional<ChaseAngle> angle = mutualChase ? Optional<ChaseAngle>() : _angle; // if we're already moving, periodically check if we're already in the expected range... if (owner->HasUnitState(UNIT_STATE_CHASE_MOVE)) @@ -176,6 +195,7 @@ bool ChaseMovementGenerator::Update(Unit* owner, uint32 diff) if (cOwner) cOwner->SetCannotReachTarget(false); + owner->AddUnitState(UNIT_STATE_CHASE_MOVE); Movement::MoveSplineInit init(owner); @@ -191,9 +211,19 @@ bool ChaseMovementGenerator::Update(Unit* owner, uint32 diff) return true; } -void ChaseMovementGenerator::Finalize(Unit* owner) +void ChaseMovementGenerator::Deactivate(Unit* owner) { - owner->ClearUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE); - if (Creature* cOwner = owner->ToCreature()) - cOwner->SetCannotReachTarget(false); + AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); + owner->ClearUnitState(UNIT_STATE_CHASE_MOVE); +} + +void ChaseMovementGenerator::Finalize(Unit* owner, bool active, bool/* movementInform*/) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + if (active) + { + owner->ClearUnitState(UNIT_STATE_CHASE_MOVE); + if (Creature* cOwner = owner->ToCreature()) + cOwner->SetCannotReachTarget(false); + } } diff --git a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h index 72de4c6da0c..d8d35307efb 100644 --- a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h @@ -33,10 +33,11 @@ class ChaseMovementGenerator : public MovementGenerator, public AbstractFollower explicit ChaseMovementGenerator(Unit* target, Optional<ChaseRange> range = {}, Optional<ChaseAngle> angle = {}); ~ChaseMovementGenerator(); - void Initialize(Unit* owner) override; - void Reset(Unit* owner) override { Initialize(owner); } - bool Update(Unit* owner, uint32 diff) override; - void Finalize(Unit* owner) override; + void Initialize(Unit*) override; + void Reset(Unit*) override; + bool Update(Unit*, uint32) override; + void Deactivate(Unit*) override; + void Finalize(Unit*, bool, bool) override; MovementGeneratorType GetMovementGeneratorType() const override { return CHASE_MOTION_TYPE; } void UnitSpeedChanged() override { _lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f); } diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp index d949ea5655f..e61c8d4cafe 100755 --- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp @@ -25,7 +25,13 @@ #include "Random.h" template<class T> -ConfusedMovementGenerator<T>::~ConfusedMovementGenerator() = default; +ConfusedMovementGenerator<T>::ConfusedMovementGenerator() : _timer(0), _reference(0.f, 0.f, 0.f) +{ + this->Mode = MOTION_MODE_DEFAULT; + this->Priority = MOTION_PRIORITY_HIGHEST; + this->Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + this->BaseUnitState = UNIT_STATE_CONFUSED; +} template<class T> MovementGeneratorType ConfusedMovementGenerator<T>::GetMovementGeneratorType() const @@ -36,10 +42,13 @@ MovementGeneratorType ConfusedMovementGenerator<T>::GetMovementGeneratorType() c template<class T> void ConfusedMovementGenerator<T>::DoInitialize(T* owner) { + MovementGenerator::RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING); + MovementGenerator::AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED); + if (!owner || !owner->IsAlive()) return; - owner->AddUnitState(UNIT_STATE_CONFUSED); + // TODO: UNIT_FIELD_FLAGS should not be handled by generators owner->AddUnitFlag(UNIT_FLAG_CONFUSED); owner->StopMoving(); @@ -51,6 +60,8 @@ void ConfusedMovementGenerator<T>::DoInitialize(T* owner) template<class T> void ConfusedMovementGenerator<T>::DoReset(T* owner) { + MovementGenerator::RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_DEACTIVATED); + DoInitialize(owner); } @@ -62,20 +73,19 @@ bool ConfusedMovementGenerator<T>::DoUpdate(T* owner, uint32 diff) if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) { - _interrupt = true; + MovementGenerator::AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED); owner->StopMoving(); _path = nullptr; return true; } else - _interrupt = false; + MovementGenerator::RemoveFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED); // waiting for next move _timer.Update(diff); - if (!_interrupt && _timer.Passed() && owner->movespline->Finalized()) + if ((MovementGenerator::HasFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING) && !owner->movespline->Finalized()) || (_timer.Passed() && owner->movespline->Finalized())) { - // start moving - owner->AddUnitState(UNIT_STATE_CONFUSED_MOVE); + MovementGenerator::RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY); Position destination(_reference); float distance = 4.0f * frand(0.0f, 1.0f) - 2.0f; @@ -95,6 +105,8 @@ bool ConfusedMovementGenerator<T>::DoUpdate(T* owner, uint32 diff) return true; } + owner->AddUnitState(UNIT_STATE_CONFUSED_MOVE); + Movement::MoveSplineInit init(owner); init.MovebyPath(_path->GetPath()); init.SetWalk(true); @@ -106,32 +118,50 @@ bool ConfusedMovementGenerator<T>::DoUpdate(T* owner, uint32 diff) } template<class T> -void ConfusedMovementGenerator<T>::DoFinalize(T*) { } +void ConfusedMovementGenerator<T>::DoDeactivate(T* owner) +{ + MovementGenerator::AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); + owner->ClearUnitState(UNIT_STATE_CONFUSED_MOVE); +} + +template<class T> +void ConfusedMovementGenerator<T>::DoFinalize(T*, bool, bool) { } template<> -void ConfusedMovementGenerator<Player>::DoFinalize(Player* unit) +void ConfusedMovementGenerator<Player>::DoFinalize(Player* owner, bool active, bool/* movementInform*/) { - unit->RemoveUnitFlag(UNIT_FLAG_CONFUSED); - unit->ClearUnitState(UNIT_STATE_CONFUSED); - unit->StopMoving(); + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + + if (active) + { + owner->RemoveUnitFlag(UNIT_FLAG_CONFUSED); + owner->StopMoving(); + } } template<> -void ConfusedMovementGenerator<Creature>::DoFinalize(Creature* unit) +void ConfusedMovementGenerator<Creature>::DoFinalize(Creature* owner, bool active, bool/* movementInform*/) { - unit->RemoveUnitFlag(UNIT_FLAG_CONFUSED); - unit->ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE); - if (unit->GetVictim()) - unit->SetTarget(unit->EnsureVictim()->GetGUID()); + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + + if (active) + { + owner->RemoveUnitFlag(UNIT_FLAG_CONFUSED); + owner->ClearUnitState(UNIT_STATE_CONFUSED_MOVE); + if (owner->GetVictim()) + owner->SetTarget(owner->EnsureVictim()->GetGUID()); + } } -template ConfusedMovementGenerator<Player>::~ConfusedMovementGenerator(); -template ConfusedMovementGenerator<Creature>::~ConfusedMovementGenerator(); +template ConfusedMovementGenerator<Player>::ConfusedMovementGenerator(); +template ConfusedMovementGenerator<Creature>::ConfusedMovementGenerator(); template MovementGeneratorType ConfusedMovementGenerator<Player>::GetMovementGeneratorType() const; template MovementGeneratorType ConfusedMovementGenerator<Creature>::GetMovementGeneratorType() const; template void ConfusedMovementGenerator<Player>::DoInitialize(Player*); template void ConfusedMovementGenerator<Creature>::DoInitialize(Creature*); template void ConfusedMovementGenerator<Player>::DoReset(Player*); template void ConfusedMovementGenerator<Creature>::DoReset(Creature*); -template bool ConfusedMovementGenerator<Player>::DoUpdate(Player*, uint32 diff); -template bool ConfusedMovementGenerator<Creature>::DoUpdate(Creature*, uint32 diff); +template bool ConfusedMovementGenerator<Player>::DoUpdate(Player*, uint32); +template bool ConfusedMovementGenerator<Creature>::DoUpdate(Creature*, uint32); +template void ConfusedMovementGenerator<Player>::DoDeactivate(Player*); +template void ConfusedMovementGenerator<Creature>::DoDeactivate(Creature*); diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h index b571603ce36..22773470259 100755 --- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h @@ -25,25 +25,25 @@ class PathGenerator; template<class T> -class ConfusedMovementGenerator : public MovementGeneratorMedium< T, ConfusedMovementGenerator<T> > +class ConfusedMovementGenerator : public MovementGeneratorMedium<T, ConfusedMovementGenerator<T>> { public: - explicit ConfusedMovementGenerator() : _timer(0), _reference(0.f, 0.f, 0.f), _interrupt(false) { } - ~ConfusedMovementGenerator(); + explicit ConfusedMovementGenerator(); MovementGeneratorType GetMovementGeneratorType() const override; - void UnitSpeedChanged() override { } //TODO void DoInitialize(T*); - void DoFinalize(T*); void DoReset(T*); bool DoUpdate(T*, uint32); + void DoDeactivate(T*); + void DoFinalize(T*, bool, bool); + + void UnitSpeedChanged() override { ConfusedMovementGenerator<T>::AddFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING); } private: std::unique_ptr<PathGenerator> _path; TimeTracker _timer; Position _reference; - bool _interrupt; }; #endif diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp index 621cae86d12..536ffa736e1 100644 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp @@ -19,8 +19,8 @@ #include "Creature.h" #include "CreatureAI.h" #include "MovementDefines.h" -#include "MoveSplineInit.h" #include "MoveSpline.h" +#include "MoveSplineInit.h" #include "ObjectAccessor.h" #include "PathGenerator.h" #include "Player.h" @@ -31,7 +31,13 @@ #define MAX_QUIET_DISTANCE 43.0f template<class T> -FleeingMovementGenerator<T>::~FleeingMovementGenerator() = default; +FleeingMovementGenerator<T>::FleeingMovementGenerator(ObjectGuid fleeTargetGUID) : _fleeTargetGUID(fleeTargetGUID), _timer(0) +{ + this->Mode = MOTION_MODE_DEFAULT; + this->Priority = MOTION_PRIORITY_HIGHEST; + this->Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + this->BaseUnitState = UNIT_STATE_FLEEING; +} template<class T> MovementGeneratorType FleeingMovementGenerator<T>::GetMovementGeneratorType() const @@ -42,40 +48,24 @@ MovementGeneratorType FleeingMovementGenerator<T>::GetMovementGeneratorType() co template<class T> void FleeingMovementGenerator<T>::DoInitialize(T* owner) { - if (!owner) + MovementGenerator::RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING); + MovementGenerator::AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED); + + if (!owner || !owner->IsAlive()) return; + // TODO: UNIT_FIELD_FLAGS should not be handled by generators owner->AddUnitFlag(UNIT_FLAG_FLEEING); - owner->AddUnitState(UNIT_STATE_FLEEING); - SetTargetLocation(owner); - _path = nullptr; -} - -template<class T> -void FleeingMovementGenerator<T>::DoFinalize(T *) -{ -} - -template<> -void FleeingMovementGenerator<Player>::DoFinalize(Player* owner) -{ - owner->RemoveUnitFlag(UNIT_FLAG_FLEEING); - owner->ClearUnitState(UNIT_STATE_FLEEING); - owner->StopMoving(); -} -template<> -void FleeingMovementGenerator<Creature>::DoFinalize(Creature* owner) -{ - owner->RemoveUnitFlag(UNIT_FLAG_FLEEING); - owner->ClearUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE); - if (owner->GetVictim()) - owner->SetTarget(owner->EnsureVictim()->GetGUID()); + _path = nullptr; + SetTargetLocation(owner); } template<class T> void FleeingMovementGenerator<T>::DoReset(T* owner) { + MovementGenerator::RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_DEACTIVATED); + DoInitialize(owner); } @@ -87,37 +77,77 @@ bool FleeingMovementGenerator<T>::DoUpdate(T* owner, uint32 diff) if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) { - _interrupt = true; + MovementGenerator::AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED); owner->StopMoving(); _path = nullptr; return true; } else - _interrupt = false; + MovementGenerator::RemoveFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED); _timer.Update(diff); - if (!_interrupt && _timer.Passed() && owner->movespline->Finalized()) + if ((MovementGenerator::HasFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING) && !owner->movespline->Finalized()) || (_timer.Passed() && owner->movespline->Finalized())) + { + MovementGenerator::RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY); SetTargetLocation(owner); + } return true; } template<class T> +void FleeingMovementGenerator<T>::DoDeactivate(T* owner) +{ + MovementGenerator::AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); + owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE); +} + +template<class T> +void FleeingMovementGenerator<T>::DoFinalize(T*, bool, bool) +{ +} + +template<> +void FleeingMovementGenerator<Player>::DoFinalize(Player* owner, bool active, bool/* movementInform*/) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + + if (active) + { + owner->RemoveUnitFlag(UNIT_FLAG_FLEEING); + owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE); + owner->StopMoving(); + } +} + +template<> +void FleeingMovementGenerator<Creature>::DoFinalize(Creature* owner, bool active, bool/* movementInform*/) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + + if (active) + { + owner->RemoveUnitFlag(UNIT_FLAG_FLEEING); + owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE); + if (owner->GetVictim()) + owner->SetTarget(owner->EnsureVictim()->GetGUID()); + } +} + +template<class T> void FleeingMovementGenerator<T>::SetTargetLocation(T* owner) { - if (!owner) + if (!owner || !owner->IsAlive()) return; if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) { - _interrupt = true; + MovementGenerator::AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED); owner->StopMoving(); _path = nullptr; return; } - owner->AddUnitState(UNIT_STATE_FLEEING_MOVE); - Position destination = owner->GetPosition(); GetPoint(owner, destination); @@ -141,6 +171,8 @@ void FleeingMovementGenerator<T>::SetTargetLocation(T* owner) return; } + owner->AddUnitState(UNIT_STATE_FLEEING_MOVE); + Movement::MoveSplineInit init(owner); init.MovebyPath(_path->GetPath()); init.SetWalk(false); @@ -186,8 +218,8 @@ void FleeingMovementGenerator<T>::GetPoint(T* owner, Position &position) owner->MovePositionToFirstCollision(position, distance, angle); } -template FleeingMovementGenerator<Player>::~FleeingMovementGenerator(); -template FleeingMovementGenerator<Creature>::~FleeingMovementGenerator(); +template FleeingMovementGenerator<Player>::FleeingMovementGenerator(ObjectGuid); +template FleeingMovementGenerator<Creature>::FleeingMovementGenerator(ObjectGuid); template MovementGeneratorType FleeingMovementGenerator<Player>::GetMovementGeneratorType() const; template MovementGeneratorType FleeingMovementGenerator<Creature>::GetMovementGeneratorType() const; template void FleeingMovementGenerator<Player>::DoInitialize(Player*); @@ -196,6 +228,8 @@ template void FleeingMovementGenerator<Player>::DoReset(Player*); template void FleeingMovementGenerator<Creature>::DoReset(Creature*); template bool FleeingMovementGenerator<Player>::DoUpdate(Player*, uint32); template bool FleeingMovementGenerator<Creature>::DoUpdate(Creature*, uint32); +template void FleeingMovementGenerator<Player>::DoDeactivate(Player*); +template void FleeingMovementGenerator<Creature>::DoDeactivate(Creature*); template void FleeingMovementGenerator<Player>::SetTargetLocation(Player*); template void FleeingMovementGenerator<Creature>::SetTargetLocation(Creature*); template void FleeingMovementGenerator<Player>::GetPoint(Player*, Position &); @@ -203,29 +237,25 @@ template void FleeingMovementGenerator<Creature>::GetPoint(Creature*, Position & //---- TimedFleeingMovementGenerator -MovementGeneratorType TimedFleeingMovementGenerator::GetMovementGeneratorType() const -{ - return TIMED_FLEEING_MOTION_TYPE; -} - -bool TimedFleeingMovementGenerator::Update(Unit* owner, uint32 time_diff) +bool TimedFleeingMovementGenerator::Update(Unit* owner, uint32 diff) { - if (!owner->IsAlive()) + if (!owner || !owner->IsAlive()) return false; - _totalFleeTime.Update(time_diff); + _totalFleeTime.Update(diff); if (_totalFleeTime.Passed()) return false; - // This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, uint32) version - // This is done instead of casting Unit& to Creature& and call parent method, then we can use Unit directly - return MovementGeneratorMedium< Creature, FleeingMovementGenerator<Creature> >::Update(owner, time_diff); + return FleeingMovementGenerator<Creature>::DoUpdate(owner->ToCreature(), diff); } -void TimedFleeingMovementGenerator::Finalize(Unit* owner) +void TimedFleeingMovementGenerator::Finalize(Unit* owner, bool active, bool/* movementInform*/) { + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + if (!active) + return; + owner->RemoveUnitFlag(UNIT_FLAG_FLEEING); - owner->ClearUnitState(UNIT_STATE_FLEEING); owner->StopMoving(); if (Unit* victim = owner->GetVictim()) { @@ -236,3 +266,8 @@ void TimedFleeingMovementGenerator::Finalize(Unit* owner) } } } + +MovementGeneratorType TimedFleeingMovementGenerator::GetMovementGeneratorType() const +{ + return TIMED_FLEEING_MOTION_TYPE; +} diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h index b4b27c4dd38..1b44e92dff1 100755 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h @@ -27,28 +27,28 @@ class PathGenerator; struct Position; template<class T> -class FleeingMovementGenerator : public MovementGeneratorMedium< T, FleeingMovementGenerator<T> > +class FleeingMovementGenerator : public MovementGeneratorMedium<T, FleeingMovementGenerator<T>> { public: - explicit FleeingMovementGenerator(ObjectGuid fleeTargetGUID) : _fleeTargetGUID(fleeTargetGUID), _timer(0), _interrupt(false) { } - ~FleeingMovementGenerator(); + explicit FleeingMovementGenerator(ObjectGuid fleeTargetGUID); MovementGeneratorType GetMovementGeneratorType() const override; - void UnitSpeedChanged() override { } //TODO void DoInitialize(T*); - void DoFinalize(T*); void DoReset(T*); bool DoUpdate(T*, uint32); + void DoDeactivate(T*); + void DoFinalize(T*, bool, bool); + + void UnitSpeedChanged() override { FleeingMovementGenerator<T>::AddFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING); } private: void SetTargetLocation(T*); - void GetPoint(T*, Position &position); + void GetPoint(T*, Position& position); std::unique_ptr<PathGenerator> _path; ObjectGuid _fleeTargetGUID; TimeTracker _timer; - bool _interrupt; }; class TimedFleeingMovementGenerator : public FleeingMovementGenerator<Creature> @@ -56,9 +56,9 @@ class TimedFleeingMovementGenerator : public FleeingMovementGenerator<Creature> public: explicit TimedFleeingMovementGenerator(ObjectGuid fleeTargetGUID, uint32 time) : FleeingMovementGenerator<Creature>(fleeTargetGUID), _totalFleeTime(time) { } - MovementGeneratorType GetMovementGeneratorType() const override; bool Update(Unit*, uint32) override; - void Finalize(Unit*) override; + void Finalize(Unit*, bool, bool) override; + MovementGeneratorType GetMovementGeneratorType() const override; private: TimeTracker _totalFleeTime; diff --git a/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.cpp index 7e04a0ff831..ab8cbf734a8 100644 --- a/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.cpp @@ -25,8 +25,6 @@ #include "ObjectMgr.h" #include "Player.h" - //----------------------------------------------------// - #define FLIGHT_TRAVEL_UPDATE 100 #define TIMEDIFF_NEXT_WP 250 #define SKIP_SPLINE_POINT_DISTANCE_SQ (40.f * 40.f) @@ -39,103 +37,44 @@ FlightPathMovementGenerator::FlightPathMovementGenerator() _endGridY = 0.0f; _endMapId = 0; _preloadTargetNode = 0; -} - -uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const -{ - if (_currentNode >= _path.size()) - return _path.size(); - - uint32 curMapId = _path[_currentNode]->ContinentID; - for (uint32 itr = _currentNode; itr < _path.size(); ++itr) - if (_path[itr]->ContinentID != curMapId) - return itr; - return _path.size(); + Mode = MOTION_MODE_DEFAULT; + Priority = MOTION_PRIORITY_HIGHEST; + Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + BaseUnitState = UNIT_STATE_IN_FLIGHT; } -bool IsNodeIncludedInShortenedPath(TaxiPathNodeEntry const* p1, TaxiPathNodeEntry const* p2) +MovementGeneratorType FlightPathMovementGenerator::GetMovementGeneratorType() const { - return p1->ContinentID != p2->ContinentID || std::pow(p1->Loc.X - p2->Loc.X, 2) + std::pow(p1->Loc.Y - p2->Loc.Y, 2) > SKIP_SPLINE_POINT_DISTANCE_SQ; + return FLIGHT_MOTION_TYPE; } -void FlightPathMovementGenerator::LoadPath(Player* player, uint32 startNode /*= 0*/) +bool FlightPathMovementGenerator::GetResetPosition(Unit* /*owner*/, float& x, float& y, float& z) { - _path.clear(); - _currentNode = startNode; - _pointsForPathSwitch.clear(); - std::deque<uint32> const& taxi = player->m_taxi.GetPath(); - float discount = player->GetReputationPriceDiscount(player->m_taxi.GetFlightMasterFactionTemplate()); - for (uint32 src = 0, dst = 1; dst < taxi.size(); src = dst++) - { - uint32 path, cost; - sObjectMgr->GetTaxiPath(taxi[src], taxi[dst], path, cost); - if (path > sTaxiPathNodesByPath.size()) - return; - - TaxiPathNodeList const& nodes = sTaxiPathNodesByPath[path]; - if (!nodes.empty()) - { - TaxiPathNodeEntry const* start = nodes[0]; - TaxiPathNodeEntry const* end = nodes[nodes.size() - 1]; - bool passedPreviousSegmentProximityCheck = false; - for (uint32 i = 0; i < nodes.size(); ++i) - { - if (passedPreviousSegmentProximityCheck || !src || _path.empty() || IsNodeIncludedInShortenedPath(_path.back(), nodes[i])) - { - if ((!src || (IsNodeIncludedInShortenedPath(start, nodes[i]) && i >= 2)) && - (dst == taxi.size() - 1 || (IsNodeIncludedInShortenedPath(end, nodes[i]) && i < nodes.size() - 1))) - { - passedPreviousSegmentProximityCheck = true; - _path.push_back(nodes[i]); - } - } - else - { - _path.pop_back(); - --_pointsForPathSwitch.back().PathIndex; - } - } - } - - _pointsForPathSwitch.push_back({ uint32(_path.size() - 1), int64(ceil(cost * discount)) }); - } + TaxiPathNodeEntry const* node = _path[_currentNode]; + x = node->Loc.X; + y = node->Loc.Y; + z = node->Loc.Z; + return true; } -void FlightPathMovementGenerator::DoInitialize(Player* player) +void FlightPathMovementGenerator::DoInitialize(Player* owner) { - Reset(player); + RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING); + AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED); + + DoReset(owner); InitEndGridInfo(); } -void FlightPathMovementGenerator::DoFinalize(Player* player) +void FlightPathMovementGenerator::DoReset(Player* owner) { - // remove flag to prevent send object build movement packets for flight state and crash (movement generator already not at top of stack) - player->ClearUnitState(UNIT_STATE_IN_FLIGHT); + RemoveFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); - player->Dismount(); - player->RemoveUnitFlag(UnitFlags(UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_TAXI_FLIGHT)); + owner->CombatStopWithPets(); + owner->AddUnitFlag(UnitFlags(UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_TAXI_FLIGHT)); - if (player->m_taxi.empty()) - { - // update z position to ground and orientation for landing point - // this prevent cheating with landing point at lags - // when client side flight end early in comparison server side - player->StopMoving(); - player->SetFallInformation(0, player->GetPositionZ()); - } - - player->RemovePlayerFlag(PLAYER_FLAGS_TAXI_BENCHMARK); - player->RestoreDisplayId(); -} - -void FlightPathMovementGenerator::DoReset(Player* player) -{ - player->AddUnitState(UNIT_STATE_IN_FLIGHT); - player->CombatStopWithPets(); - player->AddUnitFlag(UnitFlags(UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_TAXI_FLIGHT)); - - Movement::MoveSplineInit init(player); + Movement::MoveSplineInit init(owner); uint32 end = GetPathAtMapEnd(); for (uint32 i = GetCurrentNode(); i != end; ++i) { @@ -151,23 +90,26 @@ void FlightPathMovementGenerator::DoReset(Player* player) init.Launch(); } -bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/) +bool FlightPathMovementGenerator::DoUpdate(Player* owner, uint32 /*diff*/) { - uint32 pointId = (uint32)player->movespline->currentPathIdx(); + if (!owner) + return false; + + uint32 pointId = owner->movespline->currentPathIdx() < 0 ? 0 : owner->movespline->currentPathIdx(); if (pointId > _currentNode) { bool departureEvent = true; do { - DoEventIfAny(player, _path[_currentNode], departureEvent); + DoEventIfAny(owner, _path[_currentNode], departureEvent); while (!_pointsForPathSwitch.empty() && _pointsForPathSwitch.front().PathIndex <= _currentNode) { _pointsForPathSwitch.pop_front(); - player->m_taxi.NextTaxiDestination(); + owner->m_taxi.NextTaxiDestination(); if (!_pointsForPathSwitch.empty()) { - player->UpdateCriteria(CriteriaType::MoneySpentOnTaxis, _pointsForPathSwitch.front().Cost); - player->ModifyMoney(-_pointsForPathSwitch.front().Cost); + owner->UpdateCriteria(CriteriaType::MoneySpentOnTaxis, _pointsForPathSwitch.front().Cost); + owner->ModifyMoney(-_pointsForPathSwitch.front().Cost); } } @@ -176,17 +118,107 @@ bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/) if (_currentNode == _preloadTargetNode) PreloadEndGrid(); + _currentNode += departureEvent ? 1 : 0; departureEvent = !departureEvent; } while (true); } - return _currentNode < (_path.size() - 1); + if (_currentNode >= (_path.size() - 1)) + { + AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED); + return false; + } + return true; } -MovementGeneratorType FlightPathMovementGenerator::GetMovementGeneratorType() const +void FlightPathMovementGenerator::DoDeactivate(Player* /*owner*/) { - return FLIGHT_MOTION_TYPE; + AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); +} + +void FlightPathMovementGenerator::DoFinalize(Player* owner, bool active, bool/* movementInform*/) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + if (!active) + return; + + owner->Dismount(); + owner->RemoveUnitFlag(UnitFlags(UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_TAXI_FLIGHT)); + + if (owner->m_taxi.empty()) + { + // update z position to ground and orientation for landing point + // this prevent cheating with landing point at lags + // when client side flight end early in comparison server side + owner->StopMoving(); + owner->SetFallInformation(0, owner->GetPositionZ()); + } + + owner->RemovePlayerFlag(PLAYER_FLAGS_TAXI_BENCHMARK); +} + +uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const +{ + if (_currentNode >= _path.size()) + return _path.size(); + + uint32 curMapId = _path[_currentNode]->ContinentID; + for (uint32 itr = _currentNode; itr < _path.size(); ++itr) + { + if (_path[itr]->ContinentID != curMapId) + return itr; + } + + return _path.size(); +} + +bool IsNodeIncludedInShortenedPath(TaxiPathNodeEntry const* p1, TaxiPathNodeEntry const* p2) +{ + return p1->ContinentID != p2->ContinentID || std::pow(p1->Loc.X - p2->Loc.X, 2) + std::pow(p1->Loc.Y - p2->Loc.Y, 2) > SKIP_SPLINE_POINT_DISTANCE_SQ; +} + +void FlightPathMovementGenerator::LoadPath(Player* owner, uint32 startNode /*= 0*/) +{ + _path.clear(); + _currentNode = startNode; + _pointsForPathSwitch.clear(); + std::deque<uint32> const& taxi = owner->m_taxi.GetPath(); + float discount = owner->GetReputationPriceDiscount(owner->m_taxi.GetFlightMasterFactionTemplate()); + for (uint32 src = 0, dst = 1; dst < taxi.size(); src = dst++) + { + uint32 path, cost; + sObjectMgr->GetTaxiPath(taxi[src], taxi[dst], path, cost); + if (path > sTaxiPathNodesByPath.size()) + return; + + TaxiPathNodeList const& nodes = sTaxiPathNodesByPath[path]; + if (!nodes.empty()) + { + TaxiPathNodeEntry const* start = nodes[0]; + TaxiPathNodeEntry const* end = nodes[nodes.size() - 1]; + bool passedPreviousSegmentProximityCheck = false; + for (uint32 i = 0; i < nodes.size(); ++i) + { + if (passedPreviousSegmentProximityCheck || !src || _path.empty() || IsNodeIncludedInShortenedPath(_path.back(), nodes[i])) + { + if ((!src || (IsNodeIncludedInShortenedPath(start, nodes[i]) && i >= 2)) && + (dst == taxi.size() - 1 || (IsNodeIncludedInShortenedPath(end, nodes[i]) && i < nodes.size() - 1))) + { + passedPreviousSegmentProximityCheck = true; + _path.push_back(nodes[i]); + } + } + else + { + _path.pop_back(); + --_pointsForPathSwitch.back().PathIndex; + } + } + } + + _pointsForPathSwitch.push_back({ uint32(_path.size() - 1), int64(ceil(cost * discount)) }); + } } void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport() @@ -205,29 +237,22 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport() } } -void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry const* node, bool departure) +void FlightPathMovementGenerator::DoEventIfAny(Player* owner, TaxiPathNodeEntry const* node, bool departure) { if (uint32 eventid = departure ? node->DepartureEventID : node->ArrivalEventID) { - TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node->NodeIndex, node->PathID, player->GetName().c_str()); - player->GetMap()->ScriptsStart(sEventScripts, eventid, player, player); + TC_LOG_DEBUG("maps.script", "FlightPathMovementGenerator::DoEventIfAny: taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node->NodeIndex, node->PathID, owner->GetName().c_str()); + owner->GetMap()->ScriptsStart(sEventScripts, eventid, owner, owner); } } -bool FlightPathMovementGenerator::GetResetPos(Player*, float& x, float& y, float& z) -{ - TaxiPathNodeEntry const* node = _path[_currentNode]; - x = node->Loc.X; - y = node->Loc.Y; - z = node->Loc.Z; - return true; -} - void FlightPathMovementGenerator::InitEndGridInfo() { - /*! Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will - be reinitialized for each flightmaster at the end of each spline (or stop) in the flight. */ - uint32 nodeCount = _path.size(); //! Number of nodes in path. + /*! + * Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will + * be reinitialized for each flightmaster at the end of each spline (or stop) in the flight. + */ + uint32 nodeCount = _path.size(); //! Number of nodes in path. _endMapId = _path[nodeCount - 1]->ContinentID; //! MapId of last node _preloadTargetNode = nodeCount - 3; _endGridX = _path[nodeCount - 1]->Loc.X; @@ -236,15 +261,15 @@ void FlightPathMovementGenerator::InitEndGridInfo() void FlightPathMovementGenerator::PreloadEndGrid() { - // used to preload the final grid where the flightmaster is + // Used to preload the final grid where the flightmaster is Map* endMap = sMapMgr->FindBaseNonInstanceMap(_endMapId); // Load the grid if (endMap) { - TC_LOG_DEBUG("misc", "Preloading rid (%f, %f) for map %u at node index %u/%u", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(_path.size() - 1)); + TC_LOG_DEBUG("movement.flightpath", "FlightPathMovementGenerator::PreloadEndGrid: preloading rid (%f, %f) for map %u at node index %u/%u", _endGridX, _endGridY, _endMapId, _preloadTargetNode, uint32(_path.size() - 1)); endMap->LoadGrid(_endGridX, _endGridY); } else - TC_LOG_DEBUG("misc", "Unable to determine map to preload flightmaster grid"); + TC_LOG_DEBUG("movement.flightpath", "FlightPathMovementGenerator::PreloadEndGrid: unable to determine map to preload flightmaster grid"); } diff --git a/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.h index 4f850ab3147..6dc32e9ec84 100644 --- a/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/FlightPathMovementGenerator.h @@ -15,8 +15,8 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef FlightPathMovementGenerator_h__ -#define FlightPathMovementGenerator_h__ +#ifndef TRINITY_FLIGHTPATHMOVEMENTGENERATOR_H +#define TRINITY_FLIGHTPATHMOVEMENTGENERATOR_H #include "MovementGenerator.h" #include "PathMovementBase.h" @@ -26,46 +26,46 @@ class Player; struct TaxiPathNodeEntry; /** -* FlightPathMovementGenerator generates movement of the player for the paths -* and hence generates ground and activities for the player. -*/ + * FlightPathMovementGenerator generates movement of the player for the paths + * and hence generates ground and activities for the player. + */ class FlightPathMovementGenerator : public MovementGeneratorMedium<Player, FlightPathMovementGenerator>, public PathMovementBase<Player, std::vector<TaxiPathNodeEntry const*>> { -public: - explicit FlightPathMovementGenerator(); - - void LoadPath(Player* player, uint32 startNode = 0); - void DoInitialize(Player*); - void DoReset(Player*); - void DoFinalize(Player*); - bool DoUpdate(Player*, uint32); - MovementGeneratorType GetMovementGeneratorType() const override; + public: + explicit FlightPathMovementGenerator(); - std::vector<TaxiPathNodeEntry const*> const& GetPath() { return _path; } - uint32 GetPathAtMapEnd() const; - bool HasArrived() const { return (_currentNode >= _path.size()); } - void SetCurrentNodeAfterTeleport(); - void SkipCurrentNode() { ++_currentNode; } - void DoEventIfAny(Player* player, TaxiPathNodeEntry const* node, bool departure); + MovementGeneratorType GetMovementGeneratorType() const override; + bool GetResetPosition(Unit* owner, float& x, float& y, float& z) override; - bool GetResetPos(Player*, float& x, float& y, float& z); - void InitEndGridInfo(); - void PreloadEndGrid(); + void DoInitialize(Player*); + void DoReset(Player*); + bool DoUpdate(Player*, uint32); + void DoDeactivate(Player*); + void DoFinalize(Player*, bool, bool); -private: + std::vector<TaxiPathNodeEntry const*> const& GetPath() { return _path; } + uint32 GetPathAtMapEnd() const; + bool HasArrived() const { return _currentNode >= _path.size(); } - float _endGridX; //! X coord of last node location - float _endGridY; //! Y coord of last node location - uint32 _endMapId; //! map Id of last node location - uint32 _preloadTargetNode; //! node index where preloading starts + void LoadPath(Player* owner, uint32 startNode = 0); + void SetCurrentNodeAfterTeleport(); + void SkipCurrentNode() { ++_currentNode; } + void DoEventIfAny(Player* owner, TaxiPathNodeEntry const* node, bool departure); + void InitEndGridInfo(); + void PreloadEndGrid(); - struct TaxiNodeChangeInfo - { - uint32 PathIndex; - int64 Cost; - }; + private: + float _endGridX; //! X coord of last node location + float _endGridY; //! Y coord of last node location + uint32 _endMapId; //! map Id of last node location + uint32 _preloadTargetNode; //! node index where preloading starts - std::deque<TaxiNodeChangeInfo> _pointsForPathSwitch; //! node indexes and costs where TaxiPath changes + struct TaxiNodeChangeInfo + { + uint32 PathIndex; + int64 Cost; + }; + std::deque<TaxiNodeChangeInfo> _pointsForPathSwitch; //! node indexes and costs where TaxiPath changes }; -#endif // FlightPathMovementGenerator_h__ +#endif // TRINITY_FLIGHTPATHMOVEMENTGENERATOR_H diff --git a/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.cpp index 9c83684dbca..c4b3e8cc571 100644 --- a/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.cpp @@ -16,6 +16,7 @@ */ #include "FollowMovementGenerator.h" +#include "Creature.h" #include "CreatureAI.h" #include "MoveSpline.h" #include "MoveSplineInit.h" @@ -25,17 +26,25 @@ #include "Unit.h" #include "Util.h" -FollowMovementGenerator::FollowMovementGenerator(Unit* target, float range, ChaseAngle angle) : AbstractFollower(ASSERT_NOTNULL(target)), _range(range), _angle(angle) {} -FollowMovementGenerator::~FollowMovementGenerator() = default; - static void DoMovementInform(Unit* owner, Unit* target) { if (owner->GetTypeId() != TYPEID_UNIT) return; - if (UnitAI* ai = owner->GetAI()) - static_cast<CreatureAI*>(ai)->MovementInform(FOLLOW_MOTION_TYPE, target->GetGUID().GetCounter()); + + Creature* creatureOwner = owner->ToCreature(); + if (creatureOwner->IsAIEnabled && creatureOwner->AI()) + creatureOwner->AI()->MovementInform(FOLLOW_MOTION_TYPE, target->GetGUID().GetCounter()); } +FollowMovementGenerator::FollowMovementGenerator(Unit* target, float range, ChaseAngle angle) : AbstractFollower(ASSERT_NOTNULL(target)), _range(range), _angle(angle) +{ + Mode = MOTION_MODE_DEFAULT; + Priority = MOTION_PRIORITY_NORMAL; + Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + BaseUnitState = UNIT_STATE_FOLLOW; +} +FollowMovementGenerator::~FollowMovementGenerator() = default; + static bool PositionOkay(Unit* owner, Unit* target, float range, Optional<ChaseAngle> angle = {}) { if (owner->GetExactDistSq(target) > square(owner->GetCombatReach() + target->GetCombatReach() + range)) @@ -46,15 +55,26 @@ static bool PositionOkay(Unit* owner, Unit* target, float range, Optional<ChaseA void FollowMovementGenerator::Initialize(Unit* owner) { - owner->AddUnitState(UNIT_STATE_FOLLOW); + RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING); + AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED); + + owner->StopMoving(); UpdatePetSpeed(owner); _path = nullptr; + _lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f); +} + +void FollowMovementGenerator::Reset(Unit* owner) +{ + RemoveFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); + + Initialize(owner); } bool FollowMovementGenerator::Update(Unit* owner, uint32 diff) { // owner might be dead or gone - if (!owner->IsAlive()) + if (!owner || !owner->IsAlive()) return false; // our target might have gone away @@ -125,8 +145,10 @@ bool FollowMovementGenerator::Update(Unit* owner, uint32 diff) // pets are allowed to "cheat" on pathfinding when following their master bool allowShortcut = false; if (Pet* oPet = owner->ToPet()) + { if (target->GetGUID() == oPet->GetOwnerGUID()) allowShortcut = true; + } bool success = _path->CalculatePath(x, y, z, allowShortcut); if (!success || (_path->GetPathType() & PATHFIND_NOPATH)) @@ -147,10 +169,20 @@ bool FollowMovementGenerator::Update(Unit* owner, uint32 diff) return true; } -void FollowMovementGenerator::Finalize(Unit* owner) +void FollowMovementGenerator::Deactivate(Unit* owner) { - owner->ClearUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE); - UpdatePetSpeed(owner); + AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); + owner->ClearUnitState(UNIT_STATE_FOLLOW_MOVE); +} + +void FollowMovementGenerator::Finalize(Unit* owner, bool active, bool/* movementInform*/) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + if (active) + { + owner->ClearUnitState(UNIT_STATE_FOLLOW_MOVE); + UpdatePetSpeed(owner); + } } void FollowMovementGenerator::UpdatePetSpeed(Unit* owner) diff --git a/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.h index 347cccdafc6..0140e991ac6 100644 --- a/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/FollowMovementGenerator.h @@ -34,10 +34,11 @@ class FollowMovementGenerator : public MovementGenerator, public AbstractFollowe explicit FollowMovementGenerator(Unit* target, float range, ChaseAngle angle); ~FollowMovementGenerator(); - void Initialize(Unit* owner) override; - void Reset(Unit* owner) override { Initialize(owner); } - bool Update(Unit* owner, uint32 diff) override; - void Finalize(Unit* owner) override; + void Initialize(Unit*) override; + void Reset(Unit*) override; + bool Update(Unit*, uint32) override; + void Deactivate(Unit*) override; + void Finalize(Unit*, bool, bool) override; MovementGeneratorType GetMovementGeneratorType() const override { return FOLLOW_MOTION_TYPE; } void UnitSpeedChanged() override { _lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f); } diff --git a/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.cpp index d7a228eef53..902803e41e7 100644 --- a/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.cpp @@ -19,8 +19,16 @@ #include "Creature.h" #include "CreatureAI.h" #include "MovementDefines.h" -#include "MoveSplineInit.h" #include "MoveSpline.h" +#include "MoveSplineInit.h" + +FormationMovementGenerator::FormationMovementGenerator(uint32 id, Position destination, uint32 moveType, bool run, bool orientation) : _movementId(id), _destination(destination), _moveType(moveType), _run(run), _orientation(orientation) +{ + Mode = MOTION_MODE_DEFAULT; + Priority = MOTION_PRIORITY_NORMAL; + Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + BaseUnitState = UNIT_STATE_ROAMING; +} MovementGeneratorType FormationMovementGenerator::GetMovementGeneratorType() const { @@ -29,11 +37,12 @@ MovementGeneratorType FormationMovementGenerator::GetMovementGeneratorType() con void FormationMovementGenerator::DoInitialize(Creature* owner) { - owner->AddUnitState(UNIT_STATE_ROAMING); + RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING); + AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED); if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) { - _interrupt = true; + AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED); owner->StopMoving(); return; } @@ -67,6 +76,14 @@ void FormationMovementGenerator::DoInitialize(Creature* owner) init.Launch(); } +void FormationMovementGenerator::DoReset(Creature* owner) +{ + RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_DEACTIVATED); + + owner->StopMoving(); + DoInitialize(owner); +} + bool FormationMovementGenerator::DoUpdate(Creature* owner, uint32 /*diff*/) { if (!owner) @@ -74,15 +91,14 @@ bool FormationMovementGenerator::DoUpdate(Creature* owner, uint32 /*diff*/) if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) { - _interrupt = true; + AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED); owner->StopMoving(); return true; } - if ((_interrupt && owner->movespline->Finalized()) || (_recalculateSpeed && !owner->movespline->Finalized())) + if ((HasFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED) && owner->movespline->Finalized()) || (HasFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING) && !owner->movespline->Finalized())) { - _recalculateSpeed = false; - _interrupt = false; + RemoveFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED | MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING); owner->AddUnitState(UNIT_STATE_ROAMING_MOVE); @@ -112,21 +128,29 @@ bool FormationMovementGenerator::DoUpdate(Creature* owner, uint32 /*diff*/) init.Launch(); } - return !owner->movespline->Finalized(); + if (owner->movespline->Finalized()) + { + RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY); + AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED); + return false; + } + return true; } -void FormationMovementGenerator::DoFinalize(Creature* owner) +void FormationMovementGenerator::DoDeactivate(Creature* owner) { - owner->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE); - - if (owner->movespline->Finalized()) - MovementInform(owner); + AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); + owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); } -void FormationMovementGenerator::DoReset(Creature* owner) +void FormationMovementGenerator::DoFinalize(Creature* owner, bool active, bool movementInform) { - owner->StopMoving(); - DoInitialize(owner); + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + if (active) + owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); + + if (movementInform && HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)) + MovementInform(owner); } void FormationMovementGenerator::MovementInform(Creature* owner) diff --git a/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.h index f9d46c23583..d00e6e3a73a 100644 --- a/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/FormationMovementGenerator.h @@ -23,19 +23,20 @@ class Creature; -class FormationMovementGenerator : public MovementGeneratorMedium< Creature, FormationMovementGenerator > +class FormationMovementGenerator : public MovementGeneratorMedium<Creature, FormationMovementGenerator> { public: - explicit FormationMovementGenerator(uint32 id, Position destination, uint32 moveType, bool run, bool orientation) : _movementId(id), _destination(destination), _moveType(moveType), _run(run), _orientation(orientation), _recalculateSpeed(false), _interrupt(false) { } + explicit FormationMovementGenerator(uint32 id, Position destination, uint32 moveType, bool run, bool orientation); MovementGeneratorType GetMovementGeneratorType() const override; void DoInitialize(Creature*); - void DoFinalize(Creature*); void DoReset(Creature*); bool DoUpdate(Creature*, uint32); + void DoDeactivate(Creature*); + void DoFinalize(Creature*, bool, bool); - void UnitSpeedChanged() override { _recalculateSpeed = true; } + void UnitSpeedChanged() override { AddFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING); } private: void MovementInform(Creature*); @@ -45,8 +46,6 @@ class FormationMovementGenerator : public MovementGeneratorMedium< Creature, For uint32 _moveType; bool _run; bool _orientation; - bool _recalculateSpeed; - bool _interrupt; }; #endif // TRINITY_FORMATIONMOVEMENTGENERATOR_H diff --git a/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.cpp index 254fcd34110..70f6861f8eb 100644 --- a/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.cpp @@ -18,27 +18,67 @@ #include "GenericMovementGenerator.h" #include "Creature.h" #include "CreatureAI.h" +#include "MovementDefines.h" #include "MoveSpline.h" #include "ObjectAccessor.h" #include "Unit.h" +GenericMovementGenerator::GenericMovementGenerator(Movement::MoveSplineInit&& splineInit, MovementGeneratorType type, uint32 id, + uint32 arrivalSpellId /*= 0*/, ObjectGuid const& arrivalSpellTargetGuid /*= ObjectGuid::Empty*/) + : _splineInit(std::move(splineInit)), _type(type), _pointId(id), _duration(0), + _arrivalSpellId(arrivalSpellId), _arrivalSpellTargetGuid(arrivalSpellTargetGuid) +{ + Mode = MOTION_MODE_DEFAULT; + Priority = MOTION_PRIORITY_NORMAL; + Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + BaseUnitState = UNIT_STATE_ROAMING; +} + void GenericMovementGenerator::Initialize(Unit* /*owner*/) { + if (HasFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED)) // Resume spline is not supported + { + RemoveFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + return; + } + + RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING); + AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED); + _duration.Reset(_splineInit.Launch()); } +void GenericMovementGenerator::Reset(Unit* owner) +{ + Initialize(owner); +} + bool GenericMovementGenerator::Update(Unit* owner, uint32 diff) { + if (!owner || HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED)) + return false; + _duration.Update(diff); - if (_duration.Passed()) + if (_duration.Passed() || owner->movespline->Finalized()) + { + AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED); return false; + } + return true; +} - return !owner->movespline->Finalized(); +void GenericMovementGenerator::Deactivate(Unit*) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); } -void GenericMovementGenerator::Finalize(Unit* owner) +void GenericMovementGenerator::Finalize(Unit* owner, bool/* active*/, bool movementInform) { - MovementInform(owner); + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + + if (movementInform && HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)) + MovementInform(owner); } void GenericMovementGenerator::MovementInform(Unit* owner) @@ -47,6 +87,8 @@ void GenericMovementGenerator::MovementInform(Unit* owner) owner->CastSpell(ObjectAccessor::GetUnit(*owner, _arrivalSpellTargetGuid), _arrivalSpellId, true); if (Creature* creature = owner->ToCreature()) + { if (creature->AI()) creature->AI()->MovementInform(_type, _pointId); + } } diff --git a/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.h b/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.h index 6db8009b897..bd9bfcf9680 100644 --- a/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/GenericMovementGenerator.h @@ -29,13 +29,14 @@ enum MovementGeneratorType : uint8; class GenericMovementGenerator : public MovementGenerator { public: - explicit GenericMovementGenerator(Movement::MoveSplineInit&& splineInit, MovementGeneratorType type, uint32 id, uint32 arrivalSpellId = 0, ObjectGuid const& arrivalSpellTargetGuid = ObjectGuid::Empty) - : _splineInit(std::move(splineInit)), _type(type), _pointId(id), _duration(0), _arrivalSpellId(arrivalSpellId), _arrivalSpellTargetGuid(arrivalSpellTargetGuid) { } + explicit GenericMovementGenerator(Movement::MoveSplineInit&& splineInit, MovementGeneratorType type, uint32 id, + uint32 arrivalSpellId = 0, ObjectGuid const& arrivalSpellTargetGuid = ObjectGuid::Empty); void Initialize(Unit*) override; - void Finalize(Unit*) override; - void Reset(Unit*) override { } + void Reset(Unit*) override; bool Update(Unit*, uint32) override; + void Deactivate(Unit*) override; + void Finalize(Unit*, bool, bool) override; MovementGeneratorType GetMovementGeneratorType() const override { return _type; } private: diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp index d058b70ef6f..46c14e27fb2 100644 --- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp @@ -18,11 +18,22 @@ #include "HomeMovementGenerator.h" #include "Creature.h" #include "CreatureAI.h" +#include "G3DPosition.hpp" #include "MotionMaster.h" #include "MovementDefines.h" #include "MoveSpline.h" #include "MoveSplineInit.h" -#include "PathGenerator.h" + +template<class T> +HomeMovementGenerator<T>::HomeMovementGenerator() +{ + this->Mode = MOTION_MODE_DEFAULT; + this->Priority = MOTION_PRIORITY_NORMAL; + this->Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + this->BaseUnitState = UNIT_STATE_ROAMING; +} + +template HomeMovementGenerator<Creature>::HomeMovementGenerator(); template<class T> MovementGeneratorType HomeMovementGenerator<T>::GetMovementGeneratorType() const @@ -38,29 +49,34 @@ void HomeMovementGenerator<T>::SetTargetLocation(T*) { } template<> void HomeMovementGenerator<Creature>::SetTargetLocation(Creature* owner) { + // if we are ROOT/STUNNED/DISTRACTED even after aura clear, finalize on next update - otherwise we would get stuck in evade if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED)) - { // if we are ROOT/STUNNED/DISTRACTED even after aura clear, finalize on next update - otherwise we would get stuck in evade - _skipToHome = true; + { + AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED); return; } + owner->ClearUnitState(UNIT_STATE_ALL_ERASABLE & ~UNIT_STATE_EVADE); + owner->AddUnitState(UNIT_STATE_ROAMING_MOVE); + + Position destination = owner->GetHomePosition(); Movement::MoveSplineInit init(owner); - float x, y, z, o; - // at apply we can select more nice return points base at current movegen - if (owner->GetMotionMaster()->empty() || !owner->GetMotionMaster()->top()->GetResetPosition(owner, x, y, z)) - { - owner->GetHomePosition(x, y, z, o); - init.SetFacing(o); - } - owner->UpdateAllowedPositionZ(x, y, z); - init.MoveTo(x, y, z); + + /* + * TODO: maybe this never worked, who knows, top is always this generator, so this code calls GetResetPosition on itself + * + * if (owner->GetMotionMaster()->empty() || !owner->GetMotionMaster()->top()->GetResetPosition(owner, x, y, z)) + * { + * owner->GetHomePosition(x, y, z, o); + * init.SetFacing(o); + * } + */ + + owner->UpdateAllowedPositionZ(destination.m_positionX, destination.m_positionY, destination.m_positionZ); + init.MoveTo(PositionToVector3(destination)); + init.SetFacing(destination.GetOrientation()); init.SetWalk(false); init.Launch(); - - _skipToHome = false; - _arrived = false; - - owner->ClearUnitState(UNIT_STATE_ALL_ERASABLE & ~UNIT_STATE_EVADE); } template<class T> @@ -69,23 +85,10 @@ void HomeMovementGenerator<T>::DoInitialize(T*) { } template<> void HomeMovementGenerator<Creature>::DoInitialize(Creature* owner) { - SetTargetLocation(owner); -} + RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING); + AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED); -template<class T> -void HomeMovementGenerator<T>::DoFinalize(T*) { } - -template<> -void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner) -{ - if (_arrived) - { - owner->ClearUnitState(UNIT_STATE_EVADE); - owner->SetWalk(true); - owner->LoadCreaturesAddon(); - owner->AI()->JustReachedHome(); - owner->SetSpawnHealth(); - } + SetTargetLocation(owner); } template<class T> @@ -94,6 +97,8 @@ void HomeMovementGenerator<T>::DoReset(T*) { } template<> void HomeMovementGenerator<Creature>::DoReset(Creature* owner) { + RemoveFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); + DoInitialize(owner); } @@ -106,6 +111,39 @@ bool HomeMovementGenerator<T>::DoUpdate(T*, uint32) template<> bool HomeMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 /*diff*/) { - _arrived = _skipToHome || owner->movespline->Finalized(); - return !_arrived; + if (HasFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED) || owner->movespline->Finalized()) + { + AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED); + return false; + } + return true; +} + +template<class T> +void HomeMovementGenerator<T>::DoDeactivate(T*) { } + +template<> +void HomeMovementGenerator<Creature>::DoDeactivate(Creature* owner) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); + owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); +} + +template<class T> +void HomeMovementGenerator<T>::DoFinalize(T*, bool, bool) { } + +template<> +void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner, bool active, bool movementInform) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + if (active) + owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE | UNIT_STATE_EVADE); + + if (movementInform && HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)) + { + owner->SetWalk(true); + owner->SetSpawnHealth(); + owner->LoadCreaturesAddon(); + owner->AI()->JustReachedHome(); + } } diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h index 3126b2ac6e2..3c0dbf696a9 100644 --- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h @@ -24,20 +24,18 @@ template <class T> class HomeMovementGenerator : public MovementGeneratorMedium< T, HomeMovementGenerator<T> > { public: - explicit HomeMovementGenerator() : _arrived(false), _skipToHome(false) { } + explicit HomeMovementGenerator(); MovementGeneratorType GetMovementGeneratorType() const override; void DoInitialize(T*); - void DoFinalize(T*); void DoReset(T*); bool DoUpdate(T*, uint32); + void DoDeactivate(T*); + void DoFinalize(T*, bool, bool); private: void SetTargetLocation(T*); - - bool _arrived; - bool _skipToHome; }; #endif diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp index 2089c0fc18d..a91a7c65df5 100644 --- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp @@ -18,20 +18,42 @@ #include "IdleMovementGenerator.h" #include "Creature.h" #include "CreatureAI.h" +#include "G3DPosition.hpp" #include "MovementDefines.h" -#include <G3D/g3dmath.h> +#include "MoveSpline.h" +#include "MoveSplineInit.h" +#include "Unit.h" +#include "advstd.h" -// StopMoving is needed to make unit stop if its last movement generator expires -// But it should not be sent otherwise there are many redundent packets +IdleMovementGenerator::IdleMovementGenerator() +{ + Mode = MOTION_MODE_DEFAULT; + Priority = MOTION_PRIORITY_NORMAL; + Flags = MOVEMENTGENERATOR_FLAG_INITIALIZED; + BaseUnitState = 0; +} + +/* + * TODO: "if (!owner->IsStopped())" is useless, each generator cleans their own STATE_MOVE, the result is that StopMoving is almost never called + * Old comment: "StopMoving is needed to make unit stop if its last movement generator expires but it should not be sent otherwise there are many redundent packets" + */ void IdleMovementGenerator::Initialize(Unit* owner) { - Reset(owner); + owner->StopMoving(); } void IdleMovementGenerator::Reset(Unit* owner) { - if (!owner->IsStopped()) - owner->StopMoving(); + owner->StopMoving(); +} + +void IdleMovementGenerator::Deactivate(Unit* /*owner*/) +{ +} + +void IdleMovementGenerator::Finalize(Unit* /*owner*/, bool/* active*/, bool/* movementInform*/) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); } MovementGeneratorType IdleMovementGenerator::GetMovementGeneratorType() const @@ -41,79 +63,149 @@ MovementGeneratorType IdleMovementGenerator::GetMovementGeneratorType() const //----------------------------------------------------// -void RotateMovementGenerator::Initialize(Unit* owner) +RotateMovementGenerator::RotateMovementGenerator(uint32 id, uint32 time, RotateDirection direction) : _id(id), _duration(time), _maxDuration(time), _direction(direction) { - if (!owner->IsStopped()) - owner->StopMoving(); + Mode = MOTION_MODE_DEFAULT; + Priority = MOTION_PRIORITY_NORMAL; + Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + BaseUnitState = UNIT_STATE_ROTATING; +} - if (owner->GetVictim()) - owner->SetInFront(owner->GetVictim()); +void RotateMovementGenerator::Initialize(Unit* owner) +{ + RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING); + AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED); + + owner->StopMoving(); + + /* + * TODO: This code should be handled somewhere else, like MovementInform + * + * if (owner->GetVictim()) + * owner->SetInFront(owner->GetVictim()); + * + * owner->AttackStop(); + */ +} +void RotateMovementGenerator::Reset(Unit* owner) +{ + RemoveFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); - owner->AddUnitState(UNIT_STATE_ROTATING); - owner->AttackStop(); + Initialize(owner); } bool RotateMovementGenerator::Update(Unit* owner, uint32 diff) { + if (!owner) + return false; + float angle = owner->GetOrientation(); angle += (float(diff) * static_cast<float>(M_PI * 2) / _maxDuration) * (_direction == ROTATE_DIRECTION_LEFT ? 1.0f : -1.0f); - angle = G3D::wrap(angle, 0.0f, float(G3D::twoPi())); + angle = advstd::clamp(angle, 0.0f, static_cast<float>(M_PI * 2)); - owner->SetOrientation(angle); // UpdateSplinePosition does not set orientation with UNIT_STATE_ROTATING - owner->SetFacingTo(angle); // Send spline movement to clients + Movement::MoveSplineInit init(owner); + init.MoveTo(PositionToVector3(*owner), false); + if (!owner->GetTransGUID().IsEmpty()) + init.DisableTransportPathTransformations(); + init.SetFacing(angle); + init.Launch(); if (_duration > diff) _duration -= diff; else + { + AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED); return false; + } return true; } -MovementGeneratorType RotateMovementGenerator::GetMovementGeneratorType() const +void RotateMovementGenerator::Deactivate(Unit*) { - return ROTATE_MOTION_TYPE; + AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); } -void RotateMovementGenerator::Finalize(Unit* owner) +void RotateMovementGenerator::Finalize(Unit* owner, bool/* active*/, bool movementInform) { - owner->ClearUnitState(UNIT_STATE_ROTATING); - if (owner->GetTypeId() == TYPEID_UNIT) - owner->ToCreature()->AI()->MovementInform(ROTATE_MOTION_TYPE, 0); + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + + if (movementInform && owner->GetTypeId() == TYPEID_UNIT) + owner->ToCreature()->AI()->MovementInform(ROTATE_MOTION_TYPE, _id); +} + +MovementGeneratorType RotateMovementGenerator::GetMovementGeneratorType() const +{ + return ROTATE_MOTION_TYPE; } //----------------------------------------------------// +DistractMovementGenerator::DistractMovementGenerator(uint32 timer, float orientation) : _timer(timer), _orientation(orientation) +{ + Mode = MOTION_MODE_DEFAULT; + Priority = MOTION_PRIORITY_HIGHEST; + Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + BaseUnitState = UNIT_STATE_DISTRACTED; +} + void DistractMovementGenerator::Initialize(Unit* owner) { + RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING); + AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED); + // Distracted creatures stand up if not standing if (!owner->IsStandState()) owner->SetStandState(UNIT_STAND_STATE_STAND); - owner->AddUnitState(UNIT_STATE_DISTRACTED); + Movement::MoveSplineInit init(owner); + init.MoveTo(PositionToVector3(*owner), false); + if (!owner->GetTransGUID().IsEmpty()) + init.DisableTransportPathTransformations(); + init.SetFacing(_orientation); + init.Launch(); } -void DistractMovementGenerator::Finalize(Unit* owner) +void DistractMovementGenerator::Reset(Unit* owner) { - owner->ClearUnitState(UNIT_STATE_DISTRACTED); + RemoveFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); - // If this is a creature, then return orientation to original position (for idle movement creatures) - if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()) - { - float angle = owner->ToCreature()->GetHomePosition().GetOrientation(); - owner->SetFacingTo(angle); - } + Initialize(owner); } -bool DistractMovementGenerator::Update(Unit* /*owner*/, uint32 diff) +bool DistractMovementGenerator::Update(Unit* owner, uint32 diff) { + if (!owner) + return false; + if (diff > _timer) + { + AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED); return false; + } _timer -= diff; return true; } +void DistractMovementGenerator::Deactivate(Unit*) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); +} + +void DistractMovementGenerator::Finalize(Unit* owner, bool/* active*/, bool movementInform) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + + // TODO: This code should be handled somewhere else + // If this is a creature, then return orientation to original position (for idle movement creatures) + if (movementInform && HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED) && owner->GetTypeId() == TYPEID_UNIT) + { + float angle = owner->ToCreature()->GetHomePosition().GetOrientation(); + owner->SetFacingTo(angle); + } +} + MovementGeneratorType DistractMovementGenerator::GetMovementGeneratorType() const { return DISTRACT_MOTION_TYPE; @@ -121,13 +213,20 @@ MovementGeneratorType DistractMovementGenerator::GetMovementGeneratorType() cons //----------------------------------------------------// -MovementGeneratorType AssistanceDistractMovementGenerator::GetMovementGeneratorType() const +AssistanceDistractMovementGenerator::AssistanceDistractMovementGenerator(uint32 timer, float orientation) : DistractMovementGenerator(timer, orientation) { - return ASSISTANCE_DISTRACT_MOTION_TYPE; + Priority = MOTION_PRIORITY_NORMAL; } -void AssistanceDistractMovementGenerator::Finalize(Unit* owner) +void AssistanceDistractMovementGenerator::Finalize(Unit* owner, bool/* active*/, bool movementInform) { - owner->ClearUnitState(UNIT_STATE_DISTRACTED); - owner->ToCreature()->SetReactState(REACT_AGGRESSIVE); + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + + if (movementInform && HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED) && owner->GetTypeId() == TYPEID_UNIT) + owner->ToCreature()->SetReactState(REACT_AGGRESSIVE); +} + +MovementGeneratorType AssistanceDistractMovementGenerator::GetMovementGeneratorType() const +{ + return ASSISTANCE_DISTRACT_MOTION_TYPE; } diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h index 5e41413c019..46d5d4d932b 100755 --- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h @@ -26,51 +26,57 @@ enum RotateDirection : uint8; class IdleMovementGenerator : public MovementGenerator { public: + explicit IdleMovementGenerator(); + void Initialize(Unit*) override; - void Finalize(Unit*) override { } void Reset(Unit*) override; bool Update(Unit*, uint32) override { return true; } + void Deactivate(Unit*) override; + void Finalize(Unit*, bool, bool) override; MovementGeneratorType GetMovementGeneratorType() const override; }; class RotateMovementGenerator : public MovementGenerator { public: - explicit RotateMovementGenerator(uint32 time, RotateDirection direction) : _duration(time), _maxDuration(time), _direction(direction) { } + explicit RotateMovementGenerator(uint32 id, uint32 time, RotateDirection direction); void Initialize(Unit*) override; - void Finalize(Unit*) override; - void Reset(Unit* owner) override { Initialize(owner); } + void Reset(Unit*) override; bool Update(Unit*, uint32) override; + void Deactivate(Unit*) override; + void Finalize(Unit*, bool, bool) override; MovementGeneratorType GetMovementGeneratorType() const override; private: - uint32 _duration, _maxDuration; + uint32 _id, _duration, _maxDuration; RotateDirection _direction; }; class DistractMovementGenerator : public MovementGenerator { public: - explicit DistractMovementGenerator(uint32 timer) : _timer(timer) { } + explicit DistractMovementGenerator(uint32 timer, float orientation); void Initialize(Unit*) override; - void Finalize(Unit*) override; - void Reset(Unit* owner) override { Initialize(owner); } + void Reset(Unit*) override; bool Update(Unit*, uint32) override; + void Deactivate(Unit*) override; + void Finalize(Unit*, bool, bool) override; MovementGeneratorType GetMovementGeneratorType() const override; private: uint32 _timer; + float _orientation; }; class AssistanceDistractMovementGenerator : public DistractMovementGenerator { public: - explicit AssistanceDistractMovementGenerator(uint32 timer) : DistractMovementGenerator(timer) { } + explicit AssistanceDistractMovementGenerator(uint32 timer, float orientation); + void Finalize(Unit*, bool, bool) override; MovementGeneratorType GetMovementGeneratorType() const override; - void Finalize(Unit*) override; }; #endif diff --git a/src/server/game/Movement/MovementGenerators/PathMovementBase.h b/src/server/game/Movement/MovementGenerators/PathMovementBase.h index 5b9be57ff7f..a11f06a20c3 100644 --- a/src/server/game/Movement/MovementGenerators/PathMovementBase.h +++ b/src/server/game/Movement/MovementGenerators/PathMovementBase.h @@ -23,15 +23,15 @@ template<class Entity, class BasePath> class PathMovementBase { -public: - PathMovementBase() : _path(), _currentNode(0) { } - virtual ~PathMovementBase() { }; + public: + PathMovementBase() : _path(), _currentNode(0) { } + virtual ~PathMovementBase() { }; - uint32 GetCurrentNode() const { return _currentNode; } + uint32 GetCurrentNode() const { return _currentNode; } -protected: - BasePath _path; - uint32 _currentNode; + protected: + BasePath _path; + uint32 _currentNode; }; #endif // PathMovementBase_h__ diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp index bb78cc881e2..7418f345b41 100755 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp @@ -28,6 +28,18 @@ //----- Point Movement Generator template<class T> +PointMovementGenerator<T>::PointMovementGenerator(uint32 id, float x, float y, float z, bool generatePath, float speed /*= 0.0f*/, Optional<float> finalOrient /*= {}*/, + Unit const* faceTarget /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/) + : _movementId(id), _destination(x, y, z), _speed(speed), _generatePath(generatePath), _finalOrient(finalOrient), + i_faceTarget(faceTarget), i_spellEffectExtra(spellEffectExtraData) +{ + this->Mode = MOTION_MODE_DEFAULT; + this->Priority = MOTION_PRIORITY_NORMAL; + this->Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + this->BaseUnitState = UNIT_STATE_ROAMING; +} + +template<class T> MovementGeneratorType PointMovementGenerator<T>::GetMovementGeneratorType() const { return POINT_MOTION_TYPE; @@ -36,17 +48,18 @@ MovementGeneratorType PointMovementGenerator<T>::GetMovementGeneratorType() cons template<class T> void PointMovementGenerator<T>::DoInitialize(T* owner) { + MovementGenerator::RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING); + MovementGenerator::AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED); + if (_movementId == EVENT_CHARGE_PREPATH) { - owner->AddUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE); + owner->AddUnitState(UNIT_STATE_ROAMING_MOVE); return; } - owner->AddUnitState(UNIT_STATE_ROAMING); - if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) { - _interrupt = true; + MovementGenerator::AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED); owner->StopMoving(); return; } @@ -72,25 +85,40 @@ void PointMovementGenerator<T>::DoInitialize(T* owner) } template<class T> +void PointMovementGenerator<T>::DoReset(T* owner) +{ + MovementGenerator::RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_DEACTIVATED); + + owner->StopMoving(); + DoInitialize(owner); +} + +template<class T> bool PointMovementGenerator<T>::DoUpdate(T* owner, uint32 /*diff*/) { if (!owner) return false; if (_movementId == EVENT_CHARGE_PREPATH) - return !owner->movespline->Finalized(); + { + if (owner->movespline->Finalized()) + { + MovementGenerator::AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED); + return false; + } + return true; + } if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) { - _interrupt = true; + MovementGenerator::AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED); owner->StopMoving(); return true; } - if ((_interrupt && owner->movespline->Finalized()) || (_recalculateSpeed && !owner->movespline->Finalized())) + if ((MovementGenerator::HasFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED) && owner->movespline->Finalized()) || (MovementGenerator::HasFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING) && !owner->movespline->Finalized())) { - _recalculateSpeed = false; - _interrupt = false; + MovementGenerator::RemoveFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED | MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING); owner->AddUnitState(UNIT_STATE_ROAMING_MOVE); @@ -105,23 +133,31 @@ bool PointMovementGenerator<T>::DoUpdate(T* owner, uint32 /*diff*/) creature->SignalFormationMovement(_destination, _movementId); } - return !owner->movespline->Finalized(); + if (owner->movespline->Finalized()) + { + MovementGenerator::RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY); + MovementGenerator::AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED); + return false; + } + return true; } template<class T> -void PointMovementGenerator<T>::DoFinalize(T* owner) +void PointMovementGenerator<T>::DoDeactivate(T* owner) { - owner->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE); - - if (owner->movespline->Finalized()) - MovementInform(owner); + MovementGenerator::AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); + owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); } template<class T> -void PointMovementGenerator<T>::DoReset(T* owner) +void PointMovementGenerator<T>::DoFinalize(T* owner, bool active, bool movementInform) { - owner->StopMoving(); - DoInitialize(owner); + MovementGenerator::AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + if (active) + owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); + + if (movementInform && MovementGenerator::HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)) + MovementInform(owner); } template<class T> @@ -134,30 +170,40 @@ void PointMovementGenerator<Creature>::MovementInform(Creature* owner) owner->AI()->MovementInform(POINT_MOTION_TYPE, _movementId); } +template PointMovementGenerator<Player>::PointMovementGenerator(uint32, float, float, float, bool, float, Optional<float>, Unit const*, Movement::SpellEffectExtraData const*); +template PointMovementGenerator<Creature>::PointMovementGenerator(uint32, float, float, float, bool, float, Optional<float>, Unit const*, Movement::SpellEffectExtraData const*); template MovementGeneratorType PointMovementGenerator<Player>::GetMovementGeneratorType() const; template MovementGeneratorType PointMovementGenerator<Creature>::GetMovementGeneratorType() const; template void PointMovementGenerator<Player>::DoInitialize(Player*); template void PointMovementGenerator<Creature>::DoInitialize(Creature*); -template void PointMovementGenerator<Player>::DoFinalize(Player*); -template void PointMovementGenerator<Creature>::DoFinalize(Creature*); template void PointMovementGenerator<Player>::DoReset(Player*); template void PointMovementGenerator<Creature>::DoReset(Creature*); template bool PointMovementGenerator<Player>::DoUpdate(Player*, uint32); template bool PointMovementGenerator<Creature>::DoUpdate(Creature*, uint32); +template void PointMovementGenerator<Player>::DoDeactivate(Player*); +template void PointMovementGenerator<Creature>::DoDeactivate(Creature*); +template void PointMovementGenerator<Player>::DoFinalize(Player*, bool, bool); +template void PointMovementGenerator<Creature>::DoFinalize(Creature*, bool, bool); //---- AssistanceMovementGenerator -MovementGeneratorType AssistanceMovementGenerator::GetMovementGeneratorType() const +void AssistanceMovementGenerator::Finalize(Unit* owner, bool active, bool movementInform) { - return ASSISTANCE_MOTION_TYPE; + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + if (active) + owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); + + if (movementInform && HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)) + { + Creature* ownerCreature = owner->ToCreature(); + ownerCreature->SetNoCallAssistance(false); + ownerCreature->CallAssistance(); + if (ownerCreature->IsAlive()) + ownerCreature->GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY)); + } } -void AssistanceMovementGenerator::Finalize(Unit* owner) +MovementGeneratorType AssistanceMovementGenerator::GetMovementGeneratorType() const { - owner->ClearUnitState(UNIT_STATE_ROAMING); - owner->StopMoving(); - owner->ToCreature()->SetNoCallAssistance(false); - owner->ToCreature()->CallAssistance(); - if (owner->IsAlive()) - owner->GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY)); + return ASSISTANCE_MOTION_TYPE; } diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h index bd3c1ad3380..4a2f1a2631a 100644 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h @@ -29,19 +29,23 @@ namespace Movement } template<class T> -class PointMovementGenerator : public MovementGeneratorMedium< T, PointMovementGenerator<T> > +class PointMovementGenerator : public MovementGeneratorMedium<T, PointMovementGenerator<T>> { public: - explicit PointMovementGenerator(uint32 id, float x, float y, float z, bool generatePath, float speed = 0.0f, Unit const* faceTarget = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr, Optional<float> finalOrient = {}) : _movementId(id), _destination(x, y, z), _speed(speed), i_faceTarget(faceTarget), i_spellEffectExtra(spellEffectExtraData), _generatePath(generatePath), _recalculateSpeed(false), _interrupt(false), _finalOrient(finalOrient) { } + explicit PointMovementGenerator(uint32 id, float x, float y, float z, bool generatePath, float speed = 0.0f, Optional<float> finalOrient = {}, + Unit const* faceTarget = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr); MovementGeneratorType GetMovementGeneratorType() const override; void DoInitialize(T*); - void DoFinalize(T*); void DoReset(T*); bool DoUpdate(T*, uint32); + void DoDeactivate(T*); + void DoFinalize(T*, bool, bool); - void UnitSpeedChanged() override { _recalculateSpeed = true; } + void UnitSpeedChanged() override { PointMovementGenerator<T>::AddFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING); } + + uint32 GetId() const { return _movementId; } private: void MovementInform(T*); @@ -49,22 +53,20 @@ class PointMovementGenerator : public MovementGeneratorMedium< T, PointMovementG uint32 _movementId; Position _destination; float _speed; - Unit const* i_faceTarget; - Movement::SpellEffectExtraData const* i_spellEffectExtra; bool _generatePath; - bool _recalculateSpeed; - bool _interrupt; //! if set then unit will turn to specified _orient in provided _pos Optional<float> _finalOrient; + Unit const* i_faceTarget; + Movement::SpellEffectExtraData const* i_spellEffectExtra; }; class AssistanceMovementGenerator : public PointMovementGenerator<Creature> { public: - explicit AssistanceMovementGenerator(float x, float y, float z) : PointMovementGenerator<Creature>(0, x, y, z, true) { } + explicit AssistanceMovementGenerator(uint32 id, float x, float y, float z) : PointMovementGenerator<Creature>(id, x, y, z, true) { } + void Finalize(Unit*, bool, bool) override; MovementGeneratorType GetMovementGeneratorType() const override; - void Finalize(Unit*) override; }; #endif diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp index 8c9844df6af..26d4268d15e 100644 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp @@ -19,15 +19,21 @@ #include "Creature.h" #include "Map.h" #include "MovementDefines.h" -#include "MoveSplineInit.h" #include "MoveSpline.h" +#include "MoveSplineInit.h" #include "PathGenerator.h" #include "Random.h" template<class T> -RandomMovementGenerator<T>::~RandomMovementGenerator() = default; +RandomMovementGenerator<T>::RandomMovementGenerator(float distance) : _timer(0), _reference(), _wanderDistance(distance) +{ + this->Mode = MOTION_MODE_DEFAULT; + this->Priority = MOTION_PRIORITY_NORMAL; + this->Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + this->BaseUnitState = UNIT_STATE_ROAMING; +} -template RandomMovementGenerator<Creature>::~RandomMovementGenerator(); +template RandomMovementGenerator<Creature>::RandomMovementGenerator(float/* distance*/); template<class T> MovementGeneratorType RandomMovementGenerator<T>::GetMovementGeneratorType() const @@ -43,10 +49,12 @@ void RandomMovementGenerator<T>::DoInitialize(T*) { } template<> void RandomMovementGenerator<Creature>::DoInitialize(Creature* owner) { + RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING); + AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED); + if (!owner || !owner->IsAlive()) return; - owner->AddUnitState(UNIT_STATE_ROAMING); _reference = owner->GetPosition(); owner->StopMoving(); @@ -58,22 +66,13 @@ void RandomMovementGenerator<Creature>::DoInitialize(Creature* owner) } template<class T> -void RandomMovementGenerator<T>::DoFinalize(T*) { } - -template<> -void RandomMovementGenerator<Creature>::DoFinalize(Creature* owner) -{ - owner->ClearUnitState(UNIT_STATE_ROAMING); - owner->StopMoving(); - owner->SetWalk(false); -} - -template<class T> void RandomMovementGenerator<T>::DoReset(T*) { } template<> void RandomMovementGenerator<Creature>::DoReset(Creature* owner) { + RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_DEACTIVATED); + DoInitialize(owner); } @@ -88,14 +87,12 @@ void RandomMovementGenerator<Creature>::SetRandomLocation(Creature* owner) if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) { - _interrupt = true; + AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED); owner->StopMoving(); _path = nullptr; return; } - owner->AddUnitState(UNIT_STATE_ROAMING_MOVE); - Position position(_reference); float distance = frand(0.f, 1.f) * _wanderDistance; float angle = frand(0.f, 1.f) * float(M_PI) * 2.f; @@ -116,6 +113,8 @@ void RandomMovementGenerator<Creature>::SetRandomLocation(Creature* owner) return; } + owner->AddUnitState(UNIT_STATE_ROAMING_MOVE); + Movement::MoveSplineInit init(owner); init.MovebyPath(_path->GetPath()); init.SetWalk(true); @@ -136,21 +135,51 @@ template<> bool RandomMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff) { if (!owner || !owner->IsAlive()) - return false; + return true; if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) { - _interrupt = true; + AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED); owner->StopMoving(); _path = nullptr; return true; } else - _interrupt = false; + RemoveFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED); _timer.Update(diff); - if (!_interrupt && _timer.Passed() && owner->movespline->Finalized()) + if ((HasFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING) && !owner->movespline->Finalized()) || (_timer.Passed() && owner->movespline->Finalized())) + { + RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY); SetRandomLocation(owner); + } return true; } + +template<class T> +void RandomMovementGenerator<T>::DoDeactivate(T*) { } + +template<> +void RandomMovementGenerator<Creature>::DoDeactivate(Creature* owner) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); + owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); +} + +template<class T> +void RandomMovementGenerator<T>::DoFinalize(T*, bool, bool) { } + +template<> +void RandomMovementGenerator<Creature>::DoFinalize(Creature* owner, bool active, bool/* movementInform*/) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + if (active) + { + owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); + owner->StopMoving(); + + // TODO: Research if this modification is needed, which most likely isnt + owner->SetWalk(false); + } +} diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h index 1788161f70d..cdb523e5d20 100644 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h @@ -25,19 +25,20 @@ class PathGenerator; template<class T> -class RandomMovementGenerator : public MovementGeneratorMedium< T, RandomMovementGenerator<T> > +class RandomMovementGenerator : public MovementGeneratorMedium<T, RandomMovementGenerator<T>> { public: - explicit RandomMovementGenerator(float distance = 0.0f) : _timer(0), _reference(), _wanderDistance(distance), _interrupt(false) { } - ~RandomMovementGenerator(); + explicit RandomMovementGenerator(float distance = 0.0f); MovementGeneratorType GetMovementGeneratorType() const override; - void UnitSpeedChanged() override { } //TODO void DoInitialize(T*); - void DoFinalize(T*); void DoReset(T*); bool DoUpdate(T*, uint32); + void DoDeactivate(T*); + void DoFinalize(T*, bool, bool); + + void UnitSpeedChanged() override { RandomMovementGenerator<T>::AddFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING); } private: void SetRandomLocation(T*); @@ -46,7 +47,6 @@ class RandomMovementGenerator : public MovementGeneratorMedium< T, RandomMovemen TimeTracker _timer; Position _reference; float _wanderDistance; - bool _interrupt; }; #endif diff --git a/src/server/game/Movement/MovementGenerators/SplineChainMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/SplineChainMovementGenerator.cpp index 476766aa1f6..3b72deafe53 100644 --- a/src/server/game/Movement/MovementGenerators/SplineChainMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/SplineChainMovementGenerator.cpp @@ -18,109 +18,143 @@ #include "SplineChainMovementGenerator.h" #include "Creature.h" #include "CreatureAI.h" +#include "Errors.h" #include "MotionMaster.h" #include "MovementDefines.h" -#include "MoveSplineInit.h" #include "MoveSpline.h" +#include "MoveSplineInit.h" #include "Log.h" +#include "Unit.h" + +SplineChainMovementGenerator::SplineChainMovementGenerator(uint32 id, std::vector<SplineChainLink> const& chain, bool walk) : _id(id), _chain(chain), _chainSize(chain.size()), _walk(walk), _nextIndex(0), _nextFirstWP(0), _msToNext(0) +{ + Mode = MOTION_MODE_DEFAULT; + Priority = MOTION_PRIORITY_NORMAL; + Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + BaseUnitState = UNIT_STATE_ROAMING; +} + +SplineChainMovementGenerator::SplineChainMovementGenerator(SplineChainResumeInfo const& info) : _id(info.PointID), _chain(*info.Chain), _chainSize(info.Chain->size()), _walk(info.IsWalkMode), _nextIndex(info.SplineIndex), _nextFirstWP(info.PointIndex), _msToNext(info.TimeToNext) +{ + Mode = MOTION_MODE_DEFAULT; + Priority = MOTION_PRIORITY_NORMAL; -uint32 SplineChainMovementGenerator::SendPathSpline(Unit* me, Movement::PointsArray const& wp) const + Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + if (info.SplineIndex >= info.Chain->size()) + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + + BaseUnitState = UNIT_STATE_ROAMING; +} + +uint32 SplineChainMovementGenerator::SendPathSpline(Unit* owner, Movement::PointsArray const& path) const { - uint32 numWp = wp.size(); - ASSERT(numWp > 1 && "Every path must have source & destination"); - Movement::MoveSplineInit init(me); - if (numWp > 2) - init.MovebyPath(wp); + uint32 nodeCount = path.size(); + ASSERT(nodeCount > 1, "SplineChainMovementGenerator::SendPathSpline: Every path must have source & destination (size > 1)! (%s)", owner->GetGUID().ToString().c_str()); + + Movement::MoveSplineInit init(owner); + if (nodeCount > 2) + init.MovebyPath(path); else - init.MoveTo(wp[1], false, true); + init.MoveTo(path[1], false, true); init.SetWalk(_walk); return init.Launch(); } -void SplineChainMovementGenerator::SendSplineFor(Unit* me, uint32 index, uint32& toNext) +void SplineChainMovementGenerator::SendSplineFor(Unit* owner, uint32 index, uint32& duration) { - ASSERT(index < _chainSize); - TC_LOG_DEBUG("movement.splinechain", "%s: Sending spline for %u.", me->GetGUID().ToString().c_str(), index); + ASSERT(index < _chainSize, "SplineChainMovementGenerator::SendSplineFor: referenced index (%u) higher than path size (%u)!", index, _chainSize); + TC_LOG_DEBUG("movement.splinechain", "SplineChainMovementGenerator::SendSplineFor: sending spline on index: %u. (%s)", index, owner->GetGUID().ToString().c_str()); SplineChainLink const& thisLink = _chain[index]; - uint32 actualDuration = SendPathSpline(me, thisLink.Points); + uint32 actualDuration = SendPathSpline(owner, thisLink.Points); if (actualDuration != thisLink.ExpectedDuration) { - TC_LOG_DEBUG("movement.splinechain", "%s: Sent spline for %u, duration is %u ms. Expected was %u ms (delta %d ms). Adjusting.", me->GetGUID().ToString().c_str(), index, actualDuration, thisLink.ExpectedDuration, int32(actualDuration) - int32(thisLink.ExpectedDuration)); - toNext = uint32(double(actualDuration)/double(thisLink.ExpectedDuration) * toNext); + TC_LOG_DEBUG("movement.splinechain", "SplineChainMovementGenerator::SendSplineFor: sent spline on index: %u, duration: %u ms. Expected duration: %u ms (delta %d ms). Adjusting. (%s)", index, actualDuration, thisLink.ExpectedDuration, int32(actualDuration) - int32(thisLink.ExpectedDuration), owner->GetGUID().ToString().c_str()); + duration = uint32(double(actualDuration) / double(thisLink.ExpectedDuration) * duration); } else { - TC_LOG_DEBUG("movement.splinechain", "%s: Sent spline for %u, duration is %u ms.", me->GetGUID().ToString().c_str(), index, actualDuration); + TC_LOG_DEBUG("movement.splinechain", "SplineChainMovementGenerator::SendSplineFor: sent spline on index %u, duration: %u ms. (%s)", index, actualDuration, owner->GetGUID().ToString().c_str()); } } -void SplineChainMovementGenerator::Initialize(Unit* me) +void SplineChainMovementGenerator::Initialize(Unit* owner) { - if (_chainSize) + RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING); + AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED); + + if (!_chainSize) { - if (_nextFirstWP) // this is a resumed movegen that has to start with a partial spline - { - if (finished) - return; - SplineChainLink const& thisLink = _chain[_nextIndex]; - if (_nextFirstWP >= thisLink.Points.size()) - { - TC_LOG_ERROR("movement.splinechain", "%s: Attempted to resume spline chain from invalid resume state (%u, %u).", me->GetGUID().ToString().c_str(), _nextIndex, _nextFirstWP); - _nextFirstWP = thisLink.Points.size()-1; - } - Movement::PointsArray partial(thisLink.Points.begin() + (_nextFirstWP-1), thisLink.Points.end()); - SendPathSpline(me, partial); - TC_LOG_DEBUG("movement.splinechain", "%s: Resumed spline chain generator from resume state.", me->GetGUID().ToString().c_str()); - ++_nextIndex; - if (_nextIndex >= _chainSize) - _msToNext = 0; - else if (!_msToNext) - _msToNext = 1; - _nextFirstWP = 0; - } - else + TC_LOG_ERROR("movement", "SplineChainMovementGenerator::Initialize: couldn't initialize generator, referenced spline is empty! (%s)", owner->GetGUID().ToString().c_str()); + return; + } + + if (_nextFirstWP) // this is a resumed movegen that has to start with a partial spline + { + if (HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED)) + return; + + SplineChainLink const& thisLink = _chain[_nextIndex]; + if (_nextFirstWP >= thisLink.Points.size()) { - _msToNext = std::max(_chain[_nextIndex].TimeToNext, 1u); - SendSplineFor(me, _nextIndex, _msToNext); - ++_nextIndex; - if (_nextIndex >= _chainSize) - _msToNext = 0; + TC_LOG_ERROR("movement.splinechain", "SplineChainMovementGenerator::Initialize: attempted to resume spline chain from invalid resume state, _nextFirstWP >= path size (_nextIndex: %u, _nextFirstWP: %u). (%s)", _nextIndex, _nextFirstWP, owner->GetGUID().ToString().c_str()); + _nextFirstWP = thisLink.Points.size() - 1; } + + owner->AddUnitState(UNIT_STATE_ROAMING_MOVE); + Movement::PointsArray partial(thisLink.Points.begin() + (_nextFirstWP-1), thisLink.Points.end()); + SendPathSpline(owner, partial); + + TC_LOG_DEBUG("movement.splinechain", "SplineChainMovementGenerator::Initialize: resumed spline chain generator from resume state. (%s)", owner->GetGUID().ToString().c_str()); + + ++_nextIndex; + if (_nextIndex >= _chainSize) + _msToNext = 0; + else if (!_msToNext) + _msToNext = 1; + _nextFirstWP = 0; } else { - TC_LOG_ERROR("movement", "SplineChainMovementGenerator::Initialize - empty spline chain passed for %s.", me->GetGUID().ToString().c_str()); + _msToNext = std::max(_chain[_nextIndex].TimeToNext, 1u); + SendSplineFor(owner, _nextIndex, _msToNext); + + ++_nextIndex; + if (_nextIndex >= _chainSize) + _msToNext = 0; } } -void SplineChainMovementGenerator::Finalize(Unit* me) +void SplineChainMovementGenerator::Reset(Unit* owner) { - if (!finished) - return; - Creature* cMe = me->ToCreature(); - if (cMe && cMe->IsAIEnabled) - cMe->AI()->MovementInform(SPLINE_CHAIN_MOTION_TYPE, _id); + RemoveFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); + + owner->StopMoving(); + Initialize(owner); } -bool SplineChainMovementGenerator::Update(Unit* me, uint32 diff) +bool SplineChainMovementGenerator::Update(Unit* owner, uint32 diff) { - if (finished) + if (!owner || HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED)) return false; // _msToNext being zero here means we're on the final spline if (!_msToNext) { - finished = me->movespline->Finalized(); - return !finished; + if (owner->movespline->Finalized()) + { + AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED); + return false; + } + return true; } if (_msToNext <= diff) { // Send next spline - TC_LOG_DEBUG("movement.splinechain", "%s: Should send spline %u (%u ms late).", me->GetGUID().ToString().c_str(), _nextIndex, diff - _msToNext); + TC_LOG_DEBUG("movement.splinechain", "SplineChainMovementGenerator::Update: sending spline on index %u (%u ms late). (%s)", _nextIndex, diff - _msToNext, owner->GetGUID().ToString().c_str()); _msToNext = std::max(_chain[_nextIndex].TimeToNext, 1u); - SendSplineFor(me, _nextIndex, _msToNext); + SendSplineFor(owner, _nextIndex, _msToNext); ++_nextIndex; if (_nextIndex >= _chainSize) { @@ -131,37 +165,69 @@ bool SplineChainMovementGenerator::Update(Unit* me, uint32 diff) } else _msToNext -= diff; + return true; } +void SplineChainMovementGenerator::Deactivate(Unit* owner) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); + owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); +} + +void SplineChainMovementGenerator::Finalize(Unit* owner, bool active, bool movementInform) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + + if (active) + owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); + + if (movementInform && HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)) + { + Creature* ownerCreature = owner->ToCreature(); + if (ownerCreature && ownerCreature->IsAIEnabled) + ownerCreature->AI()->MovementInform(SPLINE_CHAIN_MOTION_TYPE, _id); + } +} + MovementGeneratorType SplineChainMovementGenerator::GetMovementGeneratorType() const { return SPLINE_CHAIN_MOTION_TYPE; } -SplineChainResumeInfo SplineChainMovementGenerator::GetResumeInfo(Unit const* me) const +SplineChainResumeInfo SplineChainMovementGenerator::GetResumeInfo(Unit const* owner) const { if (!_nextIndex) return SplineChainResumeInfo(_id, &_chain, _walk, 0, 0, _msToNext); - if (me->movespline->Finalized()) + + if (owner->movespline->Finalized()) { if (_nextIndex < _chainSize) return SplineChainResumeInfo(_id, &_chain, _walk, _nextIndex, 0, 1u); else return SplineChainResumeInfo(); } - return SplineChainResumeInfo(_id, &_chain, _walk, uint8(_nextIndex - 1), uint8(me->movespline->_currentSplineIdx()), _msToNext); + + return SplineChainResumeInfo(_id, &_chain, _walk, uint8(_nextIndex - 1), uint8(owner->movespline->_currentSplineIdx()), _msToNext); } -/* static */ void SplineChainMovementGenerator::GetResumeInfo(Unit const* me, SplineChainResumeInfo& info) +/* static */ void SplineChainMovementGenerator::GetResumeInfo(Unit const* owner, uint32 id, SplineChainResumeInfo& info) { - if (MovementGenerator const* activeGenerator = me->GetMotionMaster()->GetMotionSlot(MOTION_SLOT_ACTIVE)) + std::function<bool(MovementGenerator const*)> criteria = [id](MovementGenerator const* movement) -> bool { - if (activeGenerator->GetMovementGeneratorType() == SPLINE_CHAIN_MOTION_TYPE) + if (movement->GetMovementGeneratorType() == SPLINE_CHAIN_MOTION_TYPE) { - info = reinterpret_cast<SplineChainMovementGenerator const*>(activeGenerator)->GetResumeInfo(me); - return; + SplineChainMovementGenerator const* splineChainMovement = dynamic_cast<SplineChainMovementGenerator const*>(movement); + return splineChainMovement && splineChainMovement->GetId() == id; } + return false; + }; + + if (MovementGenerator const* activeGenerator = owner->GetMotionMaster()->GetMovementGenerator(criteria)) + { + if (activeGenerator->GetMovementGeneratorType() == SPLINE_CHAIN_MOTION_TYPE) + info = reinterpret_cast<SplineChainMovementGenerator const*>(activeGenerator)->GetResumeInfo(owner); } - info.Chain = nullptr; + else + info.Chain = nullptr; } diff --git a/src/server/game/Movement/MovementGenerators/SplineChainMovementGenerator.h b/src/server/game/Movement/MovementGenerators/SplineChainMovementGenerator.h index 8abe8e81e48..05ccc6a69fd 100644 --- a/src/server/game/Movement/MovementGenerators/SplineChainMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/SplineChainMovementGenerator.h @@ -27,29 +27,31 @@ class Unit; class TC_GAME_API SplineChainMovementGenerator : public MovementGenerator { public: - explicit SplineChainMovementGenerator(uint32 id, std::vector<SplineChainLink> const& chain, bool walk = false) : _id(id), _chain(chain), _chainSize(chain.size()), _walk(walk), finished(false), _nextIndex(0), _nextFirstWP(0), _msToNext(0) { } - explicit SplineChainMovementGenerator(SplineChainResumeInfo const& info) : _id(info.PointID), _chain(*info.Chain), _chainSize(info.Chain->size()), _walk(info.IsWalkMode), finished(info.SplineIndex >= info.Chain->size()), _nextIndex(info.SplineIndex), _nextFirstWP(info.PointIndex), _msToNext(info.TimeToNext) { } - - void Initialize(Unit* me) override; - void Finalize(Unit* me) override; - void Reset(Unit* /*me*/) override { }; - bool Update(Unit* me, uint32 diff) override; + explicit SplineChainMovementGenerator(uint32 id, std::vector<SplineChainLink> const& chain, bool walk = false); + explicit SplineChainMovementGenerator(SplineChainResumeInfo const& info); + + void Initialize(Unit*) override; + void Reset(Unit*) override; + bool Update(Unit*, uint32) override; + void Deactivate(Unit*) override; + void Finalize(Unit*, bool, bool) override; MovementGeneratorType GetMovementGeneratorType() const override; // Builds info that can later be used to resume this spline chain movement at the current position - static void GetResumeInfo(Unit const* me, SplineChainResumeInfo& info); + static void GetResumeInfo(Unit const* owner, uint32 id, SplineChainResumeInfo& info); // Leaving the object method public for people that know what they're doing to use // But really, 99% of the time you should be using the static one instead - SplineChainResumeInfo GetResumeInfo(Unit const* me) const; + SplineChainResumeInfo GetResumeInfo(Unit const* owner) const; + uint32 GetId() const { return _id; } private: - void SendSplineFor(Unit* me, uint32 index, uint32& toNext); - uint32 SendPathSpline(Unit* me, Movement::PointsArray const& wp) const; + void SendSplineFor(Unit* owner, uint32 index, uint32& duration); + uint32 SendPathSpline(Unit* owner, Movement::PointsArray const& path) const; + uint32 const _id; std::vector<SplineChainLink> const& _chain; uint8 const _chainSize; bool const _walk; - bool finished; uint8 _nextIndex; uint8 _nextFirstWP; // only used for resuming uint32 _msToNext; diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index 0017f89e9f8..56a1bb1fb2f 100644 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -18,6 +18,7 @@ #include "WaypointMovementGenerator.h" #include "Creature.h" #include "CreatureAI.h" +#include "Errors.h" #include "Log.h" #include "Map.h" #include "MovementDefines.h" @@ -27,15 +28,22 @@ #include "Transport.h" #include "WaypointManager.h" -WaypointMovementGenerator<Creature>::WaypointMovementGenerator(uint32 pathId, bool repeating) : _nextMoveTime(0), _recalculateSpeed(false), _isArrivalDone(false), _pathId(pathId), - _repeating(repeating), _loadedFromDB(true), _stalled(false), _done(false) +WaypointMovementGenerator<Creature>::WaypointMovementGenerator(uint32 pathId, bool repeating) : _nextMoveTime(0), _pathId(pathId), _repeating(repeating), _loadedFromDB(true) { + Mode = MOTION_MODE_DEFAULT; + Priority = MOTION_PRIORITY_NORMAL; + Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + BaseUnitState = UNIT_STATE_ROAMING; } -WaypointMovementGenerator<Creature>::WaypointMovementGenerator(WaypointPath& path, bool repeating) : _nextMoveTime(0), _recalculateSpeed(false), _isArrivalDone(false), _pathId(0), - _repeating(repeating), _loadedFromDB(false), _stalled(false), _done(false) +WaypointMovementGenerator<Creature>::WaypointMovementGenerator(WaypointPath& path, bool repeating) : _nextMoveTime(0), _pathId(0), _repeating(repeating), _loadedFromDB(false) { _path = &path; + + Mode = MOTION_MODE_DEFAULT; + Priority = MOTION_PRIORITY_NORMAL; + Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING; + BaseUnitState = UNIT_STATE_ROAMING; } MovementGeneratorType WaypointMovementGenerator<Creature>::GetMovementGeneratorType() const @@ -43,51 +51,190 @@ MovementGeneratorType WaypointMovementGenerator<Creature>::GetMovementGeneratorT return WAYPOINT_MOTION_TYPE; } -void WaypointMovementGenerator<Creature>::DoInitialize(Creature* creature) +void WaypointMovementGenerator<Creature>::Pause(uint32 timer/* = 0*/) +{ + if (timer) + { + AddFlag(MOVEMENTGENERATOR_FLAG_TIMED_PAUSED); + _nextMoveTime.Reset(timer); + RemoveFlag(MOVEMENTGENERATOR_FLAG_PAUSED); + } + else + { + AddFlag(MOVEMENTGENERATOR_FLAG_PAUSED); + _nextMoveTime.Reset(1); // Needed so that Update does not behave as if node was reached + RemoveFlag(MOVEMENTGENERATOR_FLAG_TIMED_PAUSED); + } +} + +void WaypointMovementGenerator<Creature>::Resume(uint32 overrideTimer/* = 0*/) +{ + if (overrideTimer) + _nextMoveTime.Reset(overrideTimer); + + if (_nextMoveTime.Passed()) + _nextMoveTime.Reset(1); // Needed so that Update does not behave as if node was reached + + RemoveFlag(MOVEMENTGENERATOR_FLAG_PAUSED); +} + +bool WaypointMovementGenerator<Creature>::GetResetPosition(Unit* /*owner*/, float& x, float& y, float& z) { - _done = false; + // prevent a crash at empty waypoint path. + if (!_path || _path->nodes.empty()) + return false; + + ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::GetResetPosition: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id); + WaypointNode const &waypoint = _path->nodes.at(_currentNode); + + x = waypoint.x; + y = waypoint.y; + z = waypoint.z; + return true; +} + +void WaypointMovementGenerator<Creature>::DoInitialize(Creature* owner) +{ + RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING); if (_loadedFromDB) { if (!_pathId) - _pathId = creature->GetWaypointPath(); + _pathId = owner->GetWaypointPath(); _path = sWaypointMgr->GetPath(_pathId); } if (!_path) { - // No path id found for entry - TC_LOG_ERROR("sql.sql", "WaypointMovementGenerator::DoInitialize: creature %s (%s DB GUID: " UI64FMTD ") doesn't have waypoint path id: %u", creature->GetName().c_str(), creature->GetGUID().ToString().c_str(), creature->GetSpawnId(), _pathId); + TC_LOG_ERROR("sql.sql", "WaypointMovementGenerator::DoInitialize: couldn't load path for creature (%s) (_pathId: %u)", owner->GetGUID().ToString().c_str(), _pathId); return; } + owner->StopMoving(); + _nextMoveTime.Reset(1000); // inform AI - if (creature->IsAIEnabled) - creature->AI()->WaypointPathStarted(_path->id); + if (owner->IsAIEnabled) + owner->AI()->WaypointPathStarted(_path->id); } -void WaypointMovementGenerator<Creature>::DoFinalize(Creature* creature) +void WaypointMovementGenerator<Creature>::DoReset(Creature* owner) { - creature->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE); - creature->SetWalk(false); + RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_DEACTIVATED); + + owner->StopMoving(); + + if (!HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED) && _nextMoveTime.Passed()) + _nextMoveTime.Reset(1); // Needed so that Update does not behave as if node was reached } -void WaypointMovementGenerator<Creature>::DoReset(Creature* creature) +bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff) { - if (!_done && _nextMoveTime.Passed() && CanMove(creature)) - StartMove(creature); - else if (_done) + if (!owner || !owner->IsAlive()) + return true; + + if (HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED | MOVEMENTGENERATOR_FLAG_PAUSED) || !_path || _path->nodes.empty()) + return true; + + if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) + { + AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED); + owner->StopMoving(); + return true; + } + + if (HasFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED)) + { + /* + * relaunch only if + * - has a tiner? -> was it interrupted while not waiting aka moving? need to check both: + * -> has a timer - is it because its waiting to start next node? + * -> has a timer - is it because something set it while moving (like timed pause)? + * + * - doesnt have a timer? -> is movement valid? + * + * TODO: ((_nextMoveTime.Passed() && VALID_MOVEMENT) || (!_nextMoveTime.Passed() && !HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED))) + */ + if (HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED) && (_nextMoveTime.Passed() || !HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED))) + { + StartMove(owner, true); + return true; + } + + RemoveFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED); + } + + // if it's moving + if (!owner->movespline->Finalized()) { - // mimic IdleMovementGenerator - if (!creature->IsStopped()) - creature->StopMoving(); + // set home position at place (every MotionMaster::UpdateMotion) + if (owner->GetTransGUID().IsEmpty()) + owner->SetHomePosition(owner->GetPosition()); + + // relaunch movement if its speed has changed + if (HasFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING)) + StartMove(owner, true); } + else if (!_nextMoveTime.Passed()) // it's not moving, is there a timer? + { + if (UpdateTimer(diff)) + { + if (!HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED)) // initial movement call + { + StartMove(owner); + return true; + } + else if (!HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)) // timer set before node was reached, resume now + { + StartMove(owner, true); + return true; + } + } + else + return true; // keep waiting + } + else // not moving, no timer + { + if (HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED) && !HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)) + { + OnArrived(owner); // hooks and wait timer reset (if necessary) + AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED); // signals to future StartMove that it reached a node + } + + if (_nextMoveTime.Passed()) // OnArrived might have set a timer + StartMove(owner); // check path status, get next point and move if necessary & can + } + + return true; } -void WaypointMovementGenerator<Creature>::OnArrived(Creature* creature) +void WaypointMovementGenerator<Creature>::DoDeactivate(Creature* owner) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED); + owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); +} + +void WaypointMovementGenerator<Creature>::DoFinalize(Creature* owner, bool active, bool/* movementInform*/) +{ + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + if (active) + { + owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); + + // TODO: Research if this modification is needed, which most likely isnt + owner->SetWalk(false); + } +} + +void WaypointMovementGenerator<Creature>::MovementInform(Creature* owner) +{ + if (owner->AI()) + owner->AI()->MovementInform(WAYPOINT_MOTION_TYPE, _currentNode); +} + +void WaypointMovementGenerator<Creature>::OnArrived(Creature* owner) { if (!_path || _path->nodes.empty()) return; @@ -96,103 +243,105 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature* creature) WaypointNode const &waypoint = _path->nodes.at(_currentNode); if (waypoint.delay) { - creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE); + owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); _nextMoveTime.Reset(waypoint.delay); } if (waypoint.eventId && urand(0, 99) < waypoint.eventChance) { - TC_LOG_DEBUG("maps.script", "Creature movement start script %u at point %u for %s.", waypoint.eventId, _currentNode, creature->GetGUID().ToString().c_str()); - creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE); - creature->GetMap()->ScriptsStart(sWaypointScripts, waypoint.eventId, creature, nullptr); + TC_LOG_DEBUG("maps.script", "Creature movement start script %u at point %u for %s.", waypoint.eventId, _currentNode, owner->GetGUID().ToString().c_str()); + owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); + owner->GetMap()->ScriptsStart(sWaypointScripts, waypoint.eventId, owner, nullptr); } // inform AI - if (creature->IsAIEnabled) + if (owner->IsAIEnabled) { - creature->AI()->MovementInform(WAYPOINT_MOTION_TYPE, _currentNode); - creature->AI()->WaypointReached(waypoint.id, _path->id); + owner->AI()->MovementInform(WAYPOINT_MOTION_TYPE, _currentNode); + owner->AI()->WaypointReached(waypoint.id, _path->id); } - creature->UpdateCurrentWaypointInfo(waypoint.id, _path->id); + owner->UpdateCurrentWaypointInfo(waypoint.id, _path->id); } -void WaypointMovementGenerator<Creature>::StartMove(Creature* creature, bool relaunch/* = false*/) +void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaunch/* = false*/) { // sanity checks - if (!creature || !creature->IsAlive() || _done || !_path || _path->nodes.empty() || (relaunch && _isArrivalDone)) + if (!owner || !owner->IsAlive() || HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED) || !_path || _path->nodes.empty() || (relaunch && (HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED) || !HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED)))) return; - if (!relaunch) // on relaunch, can avoid this since its only called on valid movement + if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting() || (owner->IsFormationLeader() && !owner->IsFormationLeaderMoveAllowed())) // if cannot move OR cannot move because of formation { - if (!CanMove(creature) || (creature->IsFormationLeader() && !creature->IsFormationLeaderMoveAllowed())) // if cannot move OR cannot move because of formation - { - _nextMoveTime.Reset(1000); // delay 1s - return; - } + _nextMoveTime.Reset(1000); // delay 1s + return; } - bool transportPath = creature->GetTransport() != nullptr; + bool const transportPath = !owner->GetTransGUID().IsEmpty(); - if (_isArrivalDone) + if (HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED) && HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED)) { - ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id); - WaypointNode const &waypoint = _path->nodes.at(_currentNode); + if (ComputeNextNode()) + { + ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id); - if ((_currentNode == _path->nodes.size() - 1) && !_repeating) // If that's our last waypoint + // inform AI + if (owner->IsAIEnabled) + owner->AI()->WaypointStarted(_path->nodes[_currentNode].id, _path->id); + } + else { + WaypointNode const &waypoint = _path->nodes[_currentNode]; float x = waypoint.x; float y = waypoint.y; float z = waypoint.z; - float o = creature->GetOrientation(); + float o = owner->GetOrientation(); if (!transportPath) - creature->SetHomePosition(x, y, z, o); + owner->SetHomePosition(x, y, z, o); else { - if (Transport* trans = creature->GetTransport()) + if (Transport* trans = owner->GetTransport()) { o -= trans->GetOrientation(); - creature->SetTransportHomePosition(x, y, z, o); + owner->SetTransportHomePosition(x, y, z, o); trans->CalculatePassengerPosition(x, y, z, &o); - creature->SetHomePosition(x, y, z, o); + owner->SetHomePosition(x, y, z, o); } - else - transportPath = false; // else if (vehicle) - this should never happen, vehicle offsets are const } - _done = true; - creature->UpdateCurrentWaypointInfo(0, 0); + AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); + owner->UpdateCurrentWaypointInfo(0, 0); // inform AI - if (creature->IsAIEnabled) - creature->AI()->WaypointPathEnded(waypoint.id, _path->id); + if (owner->IsAIEnabled) + owner->AI()->WaypointPathEnded(waypoint.id, _path->id); return; } - - _currentNode = (_currentNode + 1) % _path->nodes.size(); + } + else if (!HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED)) + { + AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED); // inform AI - if (creature->IsAIEnabled) - creature->AI()->WaypointStarted(waypoint.id, _path->id); + if (owner->IsAIEnabled) + owner->AI()->WaypointStarted(_path->nodes[_currentNode].id, _path->id); } ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id); WaypointNode const &waypoint = _path->nodes[_currentNode]; Position formationDest(waypoint.x, waypoint.y, waypoint.z, (waypoint.orientation && waypoint.delay) ? waypoint.orientation : 0.0f); - _isArrivalDone = false; - _recalculateSpeed = false; + RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_INFORM_ENABLED | MOVEMENTGENERATOR_FLAG_TIMED_PAUSED); - creature->AddUnitState(UNIT_STATE_ROAMING_MOVE); + owner->AddUnitState(UNIT_STATE_ROAMING_MOVE); - Movement::MoveSplineInit init(creature); + Movement::MoveSplineInit init(owner); //! If creature is on transport, we assume waypoints set in DB are already transport offsets if (transportPath) { init.DisableTransportPathTransformations(); - if (TransportBase* trans = creature->GetDirectTransport()) + if (TransportBase* trans = owner->GetDirectTransport()) { float orientation = formationDest.GetOrientation(); trans->CalculatePassengerPosition(formationDest.m_positionX, formationDest.m_positionY, formationDest.m_positionZ, &orientation); @@ -229,95 +378,14 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* creature, bool rel init.Launch(); // inform formation - creature->SignalFormationMovement(formationDest, waypoint.id, waypoint.moveType, (waypoint.orientation && waypoint.delay) ? true : false); -} - -bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 diff) -{ - if (!creature || !creature->IsAlive()) - return true; - - if (_done || !_path || _path->nodes.empty()) - return true; - - if (_stalled || creature->HasUnitState(UNIT_STATE_NOT_MOVE) || creature->IsMovementPreventedByCasting()) - { - creature->StopMoving(); - return true; - } - - // if it's moving - if (!creature->movespline->Finalized()) - { - // set home position at place (every MotionMaster::UpdateMotion) - if (creature->GetTransGUID().IsEmpty()) - creature->SetHomePosition(creature->GetPosition()); - - // relaunch movement if its speed has changed - if (_recalculateSpeed) - StartMove(creature, true); - } - else - { - // check if there is a wait time for the next movement - if (!_nextMoveTime.Passed()) - { - // update timer since it's not moving - _nextMoveTime.Update(diff); - if (_nextMoveTime.Passed()) - { - _nextMoveTime.Reset(0); - StartMove(creature); // check path status, get next point and move if necessary & can - } - } - else // if it's not moving and there is no timer, assume node is reached - { - OnArrived(creature); // hooks and wait timer reset (if necessary) - _isArrivalDone = true; // signals to future StartMove that it reached a node - - if (_nextMoveTime.Passed()) - StartMove(creature); // check path status, get next point and move if necessary & can - } - } - - return true; + owner->SignalFormationMovement(formationDest, waypoint.id, waypoint.moveType, (waypoint.orientation && waypoint.delay) ? true : false); } -void WaypointMovementGenerator<Creature>::MovementInform(Creature* creature) +bool WaypointMovementGenerator<Creature>::ComputeNextNode() { - if (creature->AI()) - creature->AI()->MovementInform(WAYPOINT_MOTION_TYPE, _currentNode); -} - -bool WaypointMovementGenerator<Creature>::GetResetPos(Creature*, float& x, float& y, float& z) -{ - // prevent a crash at empty waypoint path. - if (!_path || _path->nodes.empty()) + if ((_currentNode == _path->nodes.size() - 1) && !_repeating) return false; - ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::GetResetPos: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id); - WaypointNode const &waypoint = _path->nodes.at(_currentNode); - - x = waypoint.x; - y = waypoint.y; - z = waypoint.z; + _currentNode = (_currentNode + 1) % _path->nodes.size(); return true; } - -void WaypointMovementGenerator<Creature>::Pause(uint32 timer/* = 0*/) -{ - _stalled = timer ? false : true; - _nextMoveTime.Reset(timer ? timer : 1); -} - -void WaypointMovementGenerator<Creature>::Resume(uint32 overrideTimer/* = 0*/) -{ - _stalled = false; - if (overrideTimer) - _nextMoveTime.Reset(overrideTimer); -} - -/*static*/ bool WaypointMovementGenerator<Creature>::CanMove(Creature* creature) -{ - return !creature->HasUnitState(UNIT_STATE_NOT_MOVE) && !creature->IsMovementPreventedByCasting(); -} diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h index 1be8373cfd4..c808cfb5492 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h @@ -18,19 +18,12 @@ #ifndef TRINITY_WAYPOINTMOVEMENTGENERATOR_H #define TRINITY_WAYPOINTMOVEMENTGENERATOR_H -/** - * @page PathMovementGenerator is used to generate movements - * of waypoints and flight paths. Each serves the purpose - * of generate activities so that it generates updated - * packets for the players. - */ - #include "MovementGenerator.h" #include "PathMovementBase.h" #include "Timer.h" class Creature; -struct TaxiPathNodeEntry; +class Unit; struct WaypointPath; template<class T> @@ -42,36 +35,42 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium<Creat public: explicit WaypointMovementGenerator(uint32 pathId = 0, bool repeating = true); explicit WaypointMovementGenerator(WaypointPath& path, bool repeating = true); - ~WaypointMovementGenerator() { _path = nullptr; } - void DoInitialize(Creature*); - void DoFinalize(Creature*); - void DoReset(Creature*); - bool DoUpdate(Creature*, uint32 diff); - MovementGeneratorType GetMovementGeneratorType() const override; - void UnitSpeedChanged() override { _recalculateSpeed = true; } + + void UnitSpeedChanged() override { AddFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING); } void Pause(uint32 timer = 0) override; void Resume(uint32 overrideTimer = 0) override; + bool GetResetPosition(Unit*, float& x, float& y, float& z) override; - void MovementInform(Creature*); - - bool GetResetPos(Creature*, float& x, float& y, float& z); + void DoInitialize(Creature*); + void DoReset(Creature*); + bool DoUpdate(Creature*, uint32); + void DoDeactivate(Creature*); + void DoFinalize(Creature*, bool, bool); private: + void MovementInform(Creature*); void OnArrived(Creature*); void StartMove(Creature*, bool relaunch = false); + bool ComputeNextNode(); + bool UpdateTimer(uint32 diff) + { + _nextMoveTime.Update(diff); + if (_nextMoveTime.Passed()) + { + _nextMoveTime.Reset(0); + return true; + } + return false; + } static bool CanMove(Creature*); TimeTrackerSmall _nextMoveTime; - bool _recalculateSpeed; - bool _isArrivalDone; uint32 _pathId; bool _repeating; bool _loadedFromDB; - bool _stalled; - bool _done; }; #endif diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index b5da3c00b0f..056ee76a5d8 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -2579,8 +2579,10 @@ void AuraEffect::HandleAuraAllowFlight(AuraApplication const* aurApp, uint8 mode target->SetCanTransitionBetweenSwimAndFly(apply); if (target->SetCanFly(apply)) + { if (!apply && !target->IsLevitating()) target->GetMotionMaster()->MoveFall(); + } } void AuraEffect::HandleAuraWaterWalk(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -2847,8 +2849,6 @@ void AuraEffect::HandleModPossess(AuraApplication const* aurApp, uint8 mode, boo void AuraEffect::HandleModPossessPet(AuraApplication const* aurApp, uint8 mode, bool apply) const { - // Used by spell "Eyes of the Beast" - if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; @@ -2856,7 +2856,7 @@ void AuraEffect::HandleModPossessPet(AuraApplication const* aurApp, uint8 mode, if (!caster || caster->GetTypeId() != TYPEID_PLAYER) return; - //seems it may happen that when removing it is no longer owner's pet + // seems it may happen that when removing it is no longer owner's pet //if (caster->ToPlayer()->GetPet() != target) // return; @@ -2865,15 +2865,11 @@ void AuraEffect::HandleModPossessPet(AuraApplication const* aurApp, uint8 mode, return; Pet* pet = target->ToPet(); - if (apply) { if (caster->ToPlayer()->GetPet() != pet) return; - // Must clear current motion or pet leashes back to owner after a few yards - // when under spell 'Eyes of the Beast' - pet->GetMotionMaster()->Clear(); pet->SetCharmedBy(caster, CHARM_TYPE_POSSESS, aurApp); } else @@ -2887,13 +2883,9 @@ void AuraEffect::HandleModPossessPet(AuraApplication const* aurApp, uint8 mode, // Reinitialize the pet bar or it will appear greyed out caster->ToPlayer()->PetSpellInitialize(); - // Follow owner only if not fighting or owner didn't click "stay" at new location - // This may be confusing because pet bar shows "stay" when under the spell but it retains - // the "follow" flag. Player MUST click "stay" while under the spell. + // TODO: remove this if (!pet->GetVictim() && !pet->GetCharmInfo()->HasCommandState(COMMAND_STAY)) - { pet->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, pet->GetFollowAngle()); - } } } } diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index b9137c8ab91..5a48f16948b 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -2216,11 +2216,7 @@ void Spell::EffectDistract() if (unitTarget->HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING)) return; - if (unitTarget->GetTypeId() == TYPEID_UNIT) - unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS); - - unitTarget->StopMoving(); - unitTarget->SetFacingTo(unitTarget->GetAbsoluteAngle(destTarget)); + unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS, unitTarget->GetAbsoluteAngle(destTarget)); } void Spell::EffectPickPocket() diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp index 7e0c3624cd5..3be61113c6d 100644 --- a/src/server/scripts/Commands/cs_go.cpp +++ b/src/server/scripts/Commands/cs_go.cpp @@ -27,7 +27,6 @@ EndScriptData */ #include "DatabaseEnv.h" #include "Language.h" #include "MapManager.h" -#include "MotionMaster.h" #include "ObjectMgr.h" #include "PhasingHandler.h" #include "Player.h" @@ -152,13 +151,9 @@ public: // stop flight if need if (player->IsInFlight()) - { - player->GetMotionMaster()->MovementExpired(); - player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + player->FinishTaxiFlight(); else - player->SaveRecallPosition(); + player->SaveRecallPosition(); // save only in non-flight case player->TeleportTo(mapId, x, y, z, o); return true; @@ -197,13 +192,9 @@ public: // stop flight if need if (player->IsInFlight()) - { - player->GetMotionMaster()->MovementExpired(); - player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + player->FinishTaxiFlight(); else - player->SaveRecallPosition(); + player->SaveRecallPosition(); // save only in non-flight case player->TeleportTo(gy->Loc); return true; @@ -239,13 +230,9 @@ public: // stop flight if need if (player->IsInFlight()) - { - player->GetMotionMaster()->MovementExpired(); - player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + player->FinishTaxiFlight(); else - player->SaveRecallPosition(); + player->SaveRecallPosition(); // save only in non-flight case Map* map = sMapMgr->CreateBaseMap(mapId); float z = std::max(map->GetStaticHeight(PhasingHandler::GetEmptyPhaseShift(), x, y, MAX_HEIGHT), map->GetWaterLevel(PhasingHandler::GetEmptyPhaseShift(), x, y)); @@ -289,13 +276,9 @@ public: // stop flight if need if (player->IsInFlight()) - { - player->GetMotionMaster()->MovementExpired(); - player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + player->FinishTaxiFlight(); else - player->SaveRecallPosition(); + player->SaveRecallPosition(); // save only in non-flight case player->TeleportTo(goData->spawnPoint); return true; @@ -352,13 +335,9 @@ public: // stop flight if need if (player->IsInFlight()) - { - player->GetMotionMaster()->MovementExpired(); - player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + player->FinishTaxiFlight(); else - player->SaveRecallPosition(); + player->SaveRecallPosition(); // save only in non-flight case Map* map = sMapMgr->CreateBaseMap(mapId); z = std::max(map->GetStaticHeight(PhasingHandler::GetEmptyPhaseShift(), x, y, MAX_HEIGHT), map->GetWaterLevel(PhasingHandler::GetEmptyPhaseShift(), x, y)); @@ -400,13 +379,9 @@ public: // stop flight if need if (player->IsInFlight()) - { - player->GetMotionMaster()->MovementExpired(); - player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + player->FinishTaxiFlight(); else - player->SaveRecallPosition(); + player->SaveRecallPosition(); // save only in non-flight case player->TeleportTo(node->ContinentID, node->Pos.X, node->Pos.Y, node->Pos.Z, player->GetOrientation()); return true; @@ -445,13 +420,9 @@ public: // stop flight if need if (player->IsInFlight()) - { - player->GetMotionMaster()->MovementExpired(); - player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + player->FinishTaxiFlight(); else - player->SaveRecallPosition(); + player->SaveRecallPosition(); // save only in non-flight case player->TeleportTo(at->ContinentID, at->Pos.X, at->Pos.Y, at->Pos.Z, player->GetOrientation()); return true; @@ -519,13 +490,9 @@ public: // stop flight if need if (player->IsInFlight()) - { - player->GetMotionMaster()->MovementExpired(); - player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + player->FinishTaxiFlight(); else - player->SaveRecallPosition(); + player->SaveRecallPosition(); // save only in non-flight case float z = std::max(map->GetStaticHeight(PhasingHandler::GetEmptyPhaseShift(), x, y, MAX_HEIGHT), map->GetWaterLevel(PhasingHandler::GetEmptyPhaseShift(), x, y)); @@ -580,13 +547,9 @@ public: // stop flight if need if (player->IsInFlight()) - { - player->GetMotionMaster()->MovementExpired(); - player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + player->FinishTaxiFlight(); else - player->SaveRecallPosition(); + player->SaveRecallPosition(); // save only in non-flight case player->TeleportTo(mapId, x, y, z, ort); return true; @@ -614,13 +577,12 @@ public: } Player* player = handler->GetSession()->GetPlayer(); + + // stop flight if need if (player->IsInFlight()) - { - player->GetMotionMaster()->MovementExpired(); - player->CleanupAfterTaxiFlight(); - } + player->FinishTaxiFlight(); else - player->SaveRecallPosition(); + player->SaveRecallPosition(); // save only in non-flight case ticket->TeleportTo(player); return true; @@ -658,13 +620,9 @@ public: // stop flight if need if (player->IsInFlight()) - { - player->GetMotionMaster()->MovementExpired(); - player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + player->FinishTaxiFlight(); else - player->SaveRecallPosition(); + player->SaveRecallPosition(); // save only in non-flight case player->TeleportTo(player->GetMapId(), x, y, z, o); return true; diff --git a/src/server/scripts/Commands/cs_group.cpp b/src/server/scripts/Commands/cs_group.cpp index 67358c03243..2f5c92a0082 100644 --- a/src/server/scripts/Commands/cs_group.cpp +++ b/src/server/scripts/Commands/cs_group.cpp @@ -24,7 +24,6 @@ #include "Language.h" #include "LFG.h" #include "Map.h" -#include "MotionMaster.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "PhasingHandler.h" @@ -144,13 +143,9 @@ public: // stop flight if need if (player->IsInFlight()) - { - player->GetMotionMaster()->MovementExpired(); - player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + player->FinishTaxiFlight(); else - player->SaveRecallPosition(); + player->SaveRecallPosition(); // save only in non-flight case // before GM float x, y, z; diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index ffc895f159a..db5c9be254a 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -20,12 +20,10 @@ #include "ArenaTeamMgr.h" #include "CellImpl.h" #include "CharacterCache.h" -#include "ChaseMovementGenerator.h" #include "Chat.h" #include "DatabaseEnv.h" #include "DB2Stores.h" #include "DisableMgr.h" -#include "FollowMovementGenerator.h" #include "GridNotifiers.h" #include "Group.h" #include "GroupMgr.h" @@ -41,7 +39,6 @@ #include "MMapFactory.h" #include "MotionMaster.h" #include "MovementDefines.h" -#include "MovementGenerator.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Opcodes.h" @@ -459,13 +456,9 @@ public: // stop flight if need if (_player->IsInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + _player->FinishTaxiFlight(); else - _player->SaveRecallPosition(); + _player->SaveRecallPosition(); // save only in non-flight case // to point to see at target with same orientation float x, y, z; @@ -494,13 +487,9 @@ public: // stop flight if need if (_player->IsInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + _player->FinishTaxiFlight(); else - _player->SaveRecallPosition(); + _player->SaveRecallPosition(); // save only in non-flight case _player->TeleportTo(map, x, y, z, _player->GetOrientation()); } @@ -590,14 +579,10 @@ public: ChatHandler(target->GetSession()).PSendSysMessage(LANG_SUMMONED_BY, handler->playerLink(_player->GetName()).c_str()); // stop flight if need - if (target->IsInFlight()) - { - target->GetMotionMaster()->MovementExpired(); - target->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + if (_player->IsInFlight()) + _player->FinishTaxiFlight(); else - target->SaveRecallPosition(); + _player->SaveRecallPosition(); // save only in non-flight case // before GM float x, y, z; @@ -899,12 +884,7 @@ public: return false; } - // stop flight if need - if (target->IsInFlight()) - { - target->GetMotionMaster()->MovementExpired(); - target->CleanupAfterTaxiFlight(); - } + target->FinishTaxiFlight(); target->Recall(); return true; @@ -2210,20 +2190,19 @@ public: handler->PSendSysMessage(LANG_MOVEGENS_LIST, (unit->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), unit->GetGUID().ToString().c_str()); - MotionMaster* motionMaster = unit->GetMotionMaster(); + if (unit->GetMotionMaster()->Empty()) + { + handler->SendSysMessage("Empty"); + return true; + } + float x, y, z; - motionMaster->GetDestination(x, y, z); + unit->GetMotionMaster()->GetDestination(x, y, z); - for (uint8 itr = 0; itr < MAX_MOTION_SLOT; ++itr) + std::vector<MovementGeneratorInformation> list = unit->GetMotionMaster()->GetMovementGeneratorsInformation(); + for (MovementGeneratorInformation info : list) { - MovementGenerator* movementGenerator = motionMaster->GetMotionSlot(MovementSlot(itr)); - if (!movementGenerator) - { - handler->SendSysMessage("Empty"); - continue; - } - - switch (movementGenerator->GetMovementGeneratorType()) + switch (info.Type) { case IDLE_MOTION_TYPE: handler->SendSysMessage(LANG_MOVEGENS_IDLE); @@ -2238,45 +2217,33 @@ public: handler->SendSysMessage(LANG_MOVEGENS_CONFUSED); break; case CHASE_MOTION_TYPE: - { - Unit* target = static_cast<ChaseMovementGenerator const*>(movementGenerator)->GetTarget(); - - if (!target) + if (info.TargetGUID.IsEmpty()) handler->SendSysMessage(LANG_MOVEGENS_CHASE_NULL); - else if (target->GetTypeId() == TYPEID_PLAYER) - handler->PSendSysMessage(LANG_MOVEGENS_CHASE_PLAYER, target->GetName().c_str(), target->GetGUID().ToString().c_str()); + else if (info.TargetGUID.IsPlayer()) + handler->PSendSysMessage(LANG_MOVEGENS_CHASE_PLAYER, info.TargetName.c_str(), info.TargetGUID.ToString().c_str()); else - handler->PSendSysMessage(LANG_MOVEGENS_CHASE_CREATURE, target->GetName().c_str(), target->GetGUID().ToString().c_str()); + handler->PSendSysMessage(LANG_MOVEGENS_CHASE_CREATURE, info.TargetName.c_str(), info.TargetGUID.ToString().c_str()); break; - } case FOLLOW_MOTION_TYPE: - { - Unit* target = static_cast<FollowMovementGenerator const*>(movementGenerator)->GetTarget(); - - if (!target) + if (info.TargetGUID.IsEmpty()) handler->SendSysMessage(LANG_MOVEGENS_FOLLOW_NULL); - else if (target->GetTypeId() == TYPEID_PLAYER) - handler->PSendSysMessage(LANG_MOVEGENS_FOLLOW_PLAYER, target->GetName().c_str(), target->GetGUID().ToString().c_str()); + else if (info.TargetGUID.IsPlayer()) + handler->PSendSysMessage(LANG_MOVEGENS_FOLLOW_PLAYER, info.TargetName.c_str(), info.TargetGUID.ToString().c_str()); else - handler->PSendSysMessage(LANG_MOVEGENS_FOLLOW_CREATURE, target->GetName().c_str(), target->GetGUID().ToString().c_str()); + handler->PSendSysMessage(LANG_MOVEGENS_FOLLOW_CREATURE, info.TargetName.c_str(), info.TargetGUID.ToString().c_str()); break; - } case HOME_MOTION_TYPE: - { if (unit->GetTypeId() == TYPEID_UNIT) handler->PSendSysMessage(LANG_MOVEGENS_HOME_CREATURE, x, y, z); else handler->SendSysMessage(LANG_MOVEGENS_HOME_PLAYER); break; - } case FLIGHT_MOTION_TYPE: handler->SendSysMessage(LANG_MOVEGENS_FLIGHT); break; case POINT_MOTION_TYPE: - { handler->PSendSysMessage(LANG_MOVEGENS_POINT, x, y, z); break; - } case FLEEING_MOTION_TYPE: handler->SendSysMessage(LANG_MOVEGENS_FEAR); break; @@ -2287,7 +2254,7 @@ public: handler->SendSysMessage(LANG_MOVEGENS_EFFECT); break; default: - handler->PSendSysMessage(LANG_MOVEGENS_UNKNOWN, movementGenerator->GetMovementGeneratorType()); + handler->PSendSysMessage(LANG_MOVEGENS_UNKNOWN, info.Type); break; } } diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index c5ec5bd5f75..c6b0805de0f 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -1370,7 +1370,7 @@ public: return true; } - //npc unfollow handling + // npc unfollow handling static bool HandleNpcUnFollowCommand(ChatHandler* handler, char const* /*args*/) { Player* player = handler->GetSession()->GetPlayer(); @@ -1383,26 +1383,24 @@ public: return false; } - if (/*creature->GetMotionMaster()->empty() ||*/ - creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != FOLLOW_MOTION_TYPE) + MovementGenerator* movement = creature->GetMotionMaster()->GetMovementGenerator([player](MovementGenerator const* a) -> bool { - handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU, creature->GetName().c_str()); - handler->SetSentErrorMessage(true); + if (a->GetMovementGeneratorType() == FOLLOW_MOTION_TYPE) + { + FollowMovementGenerator const* followMovement = dynamic_cast<FollowMovementGenerator const*>(a); + return followMovement && followMovement->GetTarget() == player; + } return false; - } - - FollowMovementGenerator const* mgen = static_cast<FollowMovementGenerator const*>((creature->GetMotionMaster()->top())); + }); - if (mgen->GetTarget() != player) + if (!movement) { handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU, creature->GetName().c_str()); handler->SetSentErrorMessage(true); return false; } - // reset movement - creature->GetMotionMaster()->MovementExpired(true); - + creature->GetMotionMaster()->Remove(movement); handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU_NOW, creature->GetName().c_str()); return true; } diff --git a/src/server/scripts/Commands/cs_tele.cpp b/src/server/scripts/Commands/cs_tele.cpp index 93b55b5d1ef..dc1ac20ac86 100644 --- a/src/server/scripts/Commands/cs_tele.cpp +++ b/src/server/scripts/Commands/cs_tele.cpp @@ -29,7 +29,6 @@ EndScriptData */ #include "Group.h" #include "Language.h" #include "MapManager.h" -#include "MotionMaster.h" #include "ObjectMgr.h" #include "PhasingHandler.h" #include "Player.h" @@ -186,13 +185,9 @@ public: // stop flight if need if (target->IsInFlight()) - { - target->GetMotionMaster()->MovementExpired(); - target->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + target->FinishTaxiFlight(); else - target->SaveRecallPosition(); + target->SaveRecallPosition(); // save only in non-flight case target->TeleportTo(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation); } @@ -284,13 +279,9 @@ public: // stop flight if need if (player->IsInFlight()) - { - player->GetMotionMaster()->MovementExpired(); - player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + player->FinishTaxiFlight(); else - player->SaveRecallPosition(); + player->SaveRecallPosition(); // save only in non-flight case player->TeleportTo(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation); } @@ -303,7 +294,7 @@ public: if (!*args) return false; - Player* me = handler->GetSession()->GetPlayer(); + Player* player = handler->GetSession()->GetPlayer(); // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r GameTele const* tele = handler->extractGameTeleFromLink((char*)args); @@ -314,7 +305,7 @@ public: return false; } - if (me->IsInCombat() && !handler->GetSession()->HasPermission(rbac::RBAC_PERM_COMMAND_TELE_NAME)) + if (player->IsInCombat() && !handler->GetSession()->HasPermission(rbac::RBAC_PERM_COMMAND_TELE_NAME)) { handler->SendSysMessage(LANG_YOU_IN_COMBAT); handler->SetSentErrorMessage(true); @@ -322,7 +313,7 @@ public: } MapEntry const* map = sMapStore.LookupEntry(tele->mapId); - if (!map || (map->IsBattlegroundOrArena() && (me->GetMapId() != tele->mapId || !me->IsGameMaster()))) + if (!map || (map->IsBattlegroundOrArena() && (player->GetMapId() != tele->mapId || !player->IsGameMaster()))) { handler->SendSysMessage(LANG_CANNOT_TELE_TO_BG); handler->SetSentErrorMessage(true); @@ -330,16 +321,12 @@ public: } // stop flight if need - if (me->IsInFlight()) - { - me->GetMotionMaster()->MovementExpired(); - me->CleanupAfterTaxiFlight(); - } - // save only in non-flight case + if (player->IsInFlight()) + player->FinishTaxiFlight(); else - me->SaveRecallPosition(); + player->SaveRecallPosition(); // save only in non-flight case - me->TeleportTo(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation); + player->TeleportTo(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation); return true; } }; diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp index 73b2583c5da..0a21c2da912 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp @@ -538,7 +538,7 @@ public: Talk(SAY_ATIESH); me->SetFacingTo(me->GetAbsoluteAngle(player)); me->ClearUnitState(UNIT_STATE_MOVING); - me->GetMotionMaster()->MoveDistract(7 * IN_MILLISECONDS); + me->GetMotionMaster()->MoveDistract(7 * IN_MILLISECONDS, me->GetAbsoluteAngle(who)); break; } } diff --git a/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp b/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp index 04e7e60d7c5..6f8157e3306 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp @@ -1021,7 +1021,7 @@ void PretendToDie(Creature* creature) creature->RemoveAllAuras(); creature->SetHealth(0); creature->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - creature->GetMotionMaster()->MovementExpired(false); + creature->GetMotionMaster()->Clear(); creature->GetMotionMaster()->MoveIdle(); creature->SetStandState(UNIT_STAND_STATE_DEAD); } diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp index 5314fa4388b..d94bf9c3ce5 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp @@ -391,7 +391,7 @@ class npc_eye_of_acherus : public CreatureScript Movement::MoveSplineInit init(me); init.MoveTo(EyeOFAcherusFallPoint.GetPositionX(), EyeOFAcherusFallPoint.GetPositionY(), EyeOFAcherusFallPoint.GetPositionZ(), false); init.SetFall(); - me->GetMotionMaster()->LaunchMoveSpline(std::move(init), POINT_EYE_FALL, MOTION_SLOT_ACTIVE, POINT_MOTION_TYPE); + me->GetMotionMaster()->LaunchMoveSpline(std::move(init), POINT_EYE_FALL, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE); } void OnCharmed(bool /*apply*/) override { } diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp index eebd0736f39..a92a344c6fb 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp @@ -78,7 +78,7 @@ public: z += 4.0f; x -= 3.5f; y -= 5.0f; - me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->Clear(); me->UpdatePosition(x, y, z, 0.0f); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp index 50687a89ac9..f3812ae24b2 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp @@ -322,7 +322,7 @@ public: DoCast(me, SPELL_HEAD_LANDS, true); DoCast(me, SPELL_HEAD, false); SaySound(SAY_LOST_HEAD); - me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveFleeing(caster->GetVictim()); } } @@ -337,7 +337,7 @@ public: wait = 1000; if (!me->GetVictim()) return; - me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveFleeing(me->GetVictim()); } else wait -= diff; @@ -602,7 +602,7 @@ public: me->SetFullHealth(); SaySound(SAY_REJOINED); DoCast(me, SPELL_HEAD); - caster->GetMotionMaster()->Clear(false); + caster->GetMotionMaster()->Clear(); caster->GetMotionMaster()->MoveFollow(me, 6, float(urand(0, 5))); } } @@ -677,7 +677,7 @@ public: if (wp_reached) { wp_reached = false; - me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MovePoint(id, FlightPoint[id]); } } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp index 935b5b21515..684a98927ee 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp @@ -128,19 +128,19 @@ public: Talk(SAY_MO_KILL); } - void DamageTaken(Unit* /*doneBy*/, uint32 &damage) override + void DamageTaken(Unit* /*doneBy*/, uint32& damage) override { - if (damage < me->GetHealth() || _bHasDied || _bFakeDeath) + if (damage <= me->GetHealth() || _bHasDied || _bFakeDeath) return; - //On first death, fake death and open door, as well as initiate whitemane if exist + // On first death, fake death and open door, as well as initiate whitemane if exist if (Unit* Whitemane = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_WHITEMANE))) { instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, IN_PROGRESS); Whitemane->GetMotionMaster()->MovePoint(1, 1163.113370f, 1398.856812f, 32.527786f); - me->GetMotionMaster()->MovementExpired(); + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveIdle(); me->SetHealth(0); diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp index 37040fde6d7..fd73ccfbb46 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp @@ -277,7 +277,7 @@ public: { case 0: //me->AttackStop(); - me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->Clear(); me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); me->StopMoving(); Talk(YELL_TAKEOFF); diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp index 87e7d87458d..c959dd6a251 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp @@ -407,7 +407,7 @@ public: if (!HasProtected) { - me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveIdle(); // All members of raid must get this buff @@ -494,7 +494,7 @@ public: switch (actionId) { case ACTION_ENRAGE: - me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveIdle(); Enraged = true; Talk(SAY_ENRAGE); diff --git a/src/server/scripts/Kalimdor/Firelands/boss_alysrazor.cpp b/src/server/scripts/Kalimdor/Firelands/boss_alysrazor.cpp index e0198304477..9af59225fdb 100644 --- a/src/server/scripts/Kalimdor/Firelands/boss_alysrazor.cpp +++ b/src/server/scripts/Kalimdor/Firelands/boss_alysrazor.cpp @@ -367,7 +367,7 @@ class npc_molten_barrage : public CreatureScript void AttackStart(Unit* target) override { if (target) - me->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f, MOTION_SLOT_IDLE); + me->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f, MOTION_SLOT_DEFAULT); } void IsSummonedBy(Unit* /*summoner*/) override diff --git a/src/server/scripts/Kalimdor/Firelands/firelands.cpp b/src/server/scripts/Kalimdor/Firelands/firelands.cpp index 6367bc88611..aaf01b371f2 100644 --- a/src/server/scripts/Kalimdor/Firelands/firelands.cpp +++ b/src/server/scripts/Kalimdor/Firelands/firelands.cpp @@ -79,7 +79,7 @@ void firelands_bossAI::EnterEvadeMode(EvadeReason why) { if (Unit* owner = me->GetCharmerOrOwner()) { - me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE); } else diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index 10df5692fa5..b07d285b8e8 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -824,7 +824,7 @@ class npc_anubarak_spike : public CreatureScript me->GetThreatManager().ResetAllThreat(); DoZoneInCombat(); AddThreat(who, 1000000.0f); - me->GetMotionMaster()->Clear(true); + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveChase(who); } diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp index 6fa26569833..c2bea8f0443 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -15,20 +15,24 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "ScriptMgr.h" #include "halls_of_reflection.h" +#include "Creature.h" +#include "EventProcessor.h" #include "InstanceScript.h" #include "MotionMaster.h" #include "MoveSplineInit.h" #include "ObjectAccessor.h" +#include "ObjectGuid.h" #include "Player.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" +#include "ScriptMgr.h" #include "Spell.h" #include "SpellInfo.h" #include "SpellScript.h" #include "TemporarySummon.h" #include "Transport.h" +#include "Unit.h" enum Text { @@ -344,12 +348,6 @@ Position const IceWallTargetPosition[] = { 5318.289f, 1749.184f, 771.9423f, 0.8726646f } // 4th Icewall }; -void GameObjectDeleteDelayEvent::DeleteGameObject() -{ - if (GameObject* go = ObjectAccessor::GetGameObject(*_owner, _gameObjectGUID)) - go->Delete(); -} - class npc_jaina_or_sylvanas_intro_hor : public CreatureScript { public: @@ -797,6 +795,33 @@ class npc_jaina_or_sylvanas_intro_hor : public CreatureScript } }; +class HoRGameObjectDeleteDelayEvent : public BasicEvent +{ + public: + explicit HoRGameObjectDeleteDelayEvent(Unit* owner, ObjectGuid gameObjectGUID) : _owner(owner), _gameObjectGUID(gameObjectGUID) { } + + void DeleteGameObject() + { + if (GameObject* go = ObjectAccessor::GetGameObject(*_owner, _gameObjectGUID)) + go->Delete(); + } + + bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override + { + DeleteGameObject(); + return true; + } + + void Abort(uint64 /*execTime*/) override + { + DeleteGameObject(); + } + + private: + Unit* _owner; + ObjectGuid _gameObjectGUID; +}; + class npc_jaina_or_sylvanas_escape_hor : public CreatureScript { public: @@ -894,7 +919,7 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript me->RemoveAurasDueToSpell(SPELL_SYLVANAS_DESTROY_ICE_WALL); _instance->HandleGameObject(_instance->GetGuidData(DATA_ICEWALL), true); - me->m_Events.AddEvent(new GameObjectDeleteDelayEvent(me, _instance->GetGuidData(DATA_ICEWALL)), me->m_Events.CalculateTime(5000)); + me->m_Events.AddEvent(new HoRGameObjectDeleteDelayEvent(me, _instance->GetGuidData(DATA_ICEWALL)), me->m_Events.CalculateTime(5000)); if (Creature* wallTarget = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_ICEWALL_TARGET))) wallTarget->DespawnOrUnsummon(); @@ -2123,13 +2148,10 @@ enum EscapeEvents EVENT_LUMBERING_ABOMINATION_CLEAVE }; -namespace hor -{ - -class StartMovementEvent : public BasicEvent +class HoRStartMovementEvent : public BasicEvent { public: - StartMovementEvent(Creature* owner) : _owner(owner) { } + explicit HoRStartMovementEvent(Creature* owner) : _owner(owner) { } bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override { @@ -2143,8 +2165,6 @@ class StartMovementEvent : public BasicEvent Creature* _owner; }; -} // namespace hor - struct npc_escape_event_trash : public ScriptedAI { npc_escape_event_trash(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } @@ -2197,7 +2217,7 @@ class npc_raging_ghoul : public CreatureScript me->CastSpell(me, SPELL_RAGING_GHOUL_SPAWN, true); me->SetReactState(REACT_PASSIVE); me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); - me->m_Events.AddEvent(new hor::StartMovementEvent(me), me->m_Events.CalculateTime(5000)); + me->m_Events.AddEvent(new HoRStartMovementEvent(me), me->m_Events.CalculateTime(5000)); npc_escape_event_trash::IsSummonedBy(summoner); } @@ -2263,7 +2283,7 @@ class npc_risen_witch_doctor : public CreatureScript me->CastSpell(me, SPELL_RISEN_WITCH_DOCTOR_SPAWN, true); me->SetReactState(REACT_PASSIVE); me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); - me->m_Events.AddEvent(new hor::StartMovementEvent(me), me->m_Events.CalculateTime(5000)); + me->m_Events.AddEvent(new HoRStartMovementEvent(me), me->m_Events.CalculateTime(5000)); npc_escape_event_trash::IsSummonedBy(summoner); } diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h index acfe6234da1..a9f82a9fb46 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h @@ -19,21 +19,20 @@ #define HALLS_OF_REFLECTION_H_ #include "CreatureAIImpl.h" -#include "EventProcessor.h" -#include "ObjectGuid.h" class Unit; #define HoRScriptName "instance_halls_of_reflection" -#define DataHeader "HOR" +#define DataHeader "HOR" uint32 const EncounterCount = 3; -/* Halls of Reflection encounters: - 0 - Falric - 1 - Marwyn - 2 - The Lich King -*/ +/* + * Halls of Reflection encounters: + * 0 - Falric + * 1 - Marwyn + * 2 - The Lich King + */ enum HORDataTypes { @@ -198,29 +197,6 @@ enum HORInstanceYells SAY_CAPTAIN_FINAL = 1 }; -class GameObjectDeleteDelayEvent : public BasicEvent -{ - public: - GameObjectDeleteDelayEvent(Unit* owner, ObjectGuid gameObjectGUID) : _owner(owner), _gameObjectGUID(gameObjectGUID) { } - - void DeleteGameObject(); - - bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override - { - DeleteGameObject(); - return true; - } - - void Abort(uint64 /*execTime*/) override - { - DeleteGameObject(); - } - - private: - Unit* _owner; - ObjectGuid _gameObjectGUID; -}; - template <class AI, class T> inline AI* GetHallsOfReflectionAI(T* obj) { diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp index 6c7694feebb..7609c5c6992 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp @@ -476,7 +476,7 @@ public: Movement::MoveSplineInit init(_owner); init.DisableTransportPathTransformations(); init.MoveTo(_dest.GetPositionX(), _dest.GetPositionY(), _dest.GetPositionZ(), false); - _owner->GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_CHARGE_PREPATH, MOTION_SLOT_ACTIVE, POINT_MOTION_TYPE); + _owner->GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_CHARGE_PREPATH, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE); return true; } @@ -570,7 +570,7 @@ struct gunship_npc_AI : public ScriptedAI Movement::MoveSplineInit init(me); init.DisableTransportPathTransformations(); init.MoveTo(x, y, z, false); - me->GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_CHARGE_PREPATH, MOTION_SLOT_ACTIVE, POINT_MOTION_TYPE); + me->GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_CHARGE_PREPATH, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE); } } @@ -937,7 +937,7 @@ class npc_high_overlord_saurfang_igb : public CreatureScript Movement::MoveSplineInit init(me); init.DisableTransportPathTransformations(); init.MovebyPath(path, 0); - me->GetMotionMaster()->LaunchMoveSpline(std::move(init), 0, MOTION_SLOT_ACTIVE, POINT_MOTION_TYPE); + me->GetMotionMaster()->LaunchMoveSpline(std::move(init), 0, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE); me->DespawnOrUnsummon(18000); } @@ -1201,7 +1201,7 @@ class npc_muradin_bronzebeard_igb : public CreatureScript Movement::MoveSplineInit init(me); init.DisableTransportPathTransformations(); init.MovebyPath(path, 0); - me->GetMotionMaster()->LaunchMoveSpline(std::move(init), 0, MOTION_SLOT_ACTIVE, POINT_MOTION_TYPE); + me->GetMotionMaster()->LaunchMoveSpline(std::move(init), 0, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE); me->DespawnOrUnsummon(18000); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp index 00fd567bb2a..0ec4ace8d67 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp @@ -22,6 +22,7 @@ #include "MoveSplineInit.h" #include "ObjectAccessor.h" #include "Player.h" +#include "PointMovementGenerator.h" #include "ScriptedCreature.h" #include "SpellAuras.h" #include "SpellScript.h" @@ -241,8 +242,16 @@ class boss_lord_marrowgar : public CreatureScript break; } case EVENT_BONE_STORM_END: - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE) - me->GetMotionMaster()->MovementExpired(); + if (MovementGenerator* movement = me->GetMotionMaster()->GetMovementGenerator([](MovementGenerator const* a) -> bool + { + if (a->GetMovementGeneratorType() == POINT_MOTION_TYPE) + { + PointMovementGenerator<Creature> const* pointMovement = dynamic_cast<PointMovementGenerator<Creature> const*>(a); + return pointMovement && pointMovement->GetId() == POINT_TARGET_BONESTORM_PLAYER; + } + return false; + })) + me->GetMotionMaster()->Remove(movement); me->GetMotionMaster()->MoveChase(me->GetVictim()); me->SetSpeedRate(MOVE_RUN, _baseSpeed); events.CancelEvent(EVENT_BONE_STORM_MOVE); @@ -472,7 +481,7 @@ class npc_bone_spike : public CreatureScript Movement::MoveSplineInit init(passenger); init.DisableTransportPathTransformations(); init.MoveTo(-0.02206125f, -0.02132235f, 5.514783f, false); - passenger->GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_VEHICLE_BOARD, MOTION_SLOT_CONTROLLED); + passenger->GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_VEHICLE_BOARD, MOTION_PRIORITY_HIGHEST); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index d09530233f7..7343575dade 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -242,8 +242,6 @@ class boss_professor_putricide : public CreatureScript _experimentState = EXPERIMENT_STATE_OOZE; me->SetReactState(REACT_DEFENSIVE); me->SetWalk(false); - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE) - me->GetMotionMaster()->MovementExpired(); if (instance->GetBossState(DATA_ROTFACE) == DONE && instance->GetBossState(DATA_FESTERGUT) == DONE) { diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index 6d249e6ce16..a1844f131c5 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -394,8 +394,7 @@ class boss_sindragosa : public CreatureScript me->SetDisableGravity(false); me->SetAnimTier(UNIT_BYTE1_FLAG_NONE, false); me->SetReactState(REACT_DEFENSIVE); - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE) - me->GetMotionMaster()->MovementExpired(); + _isInAirPhase = false; // trigger Asphyxiation EntryCheckPredicate pred(NPC_ICE_TOMB); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index 607c0952c34..9ab10f8d876 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -418,10 +418,10 @@ class FrozenThroneResetWorker } }; -class StartMovementEvent : public BasicEvent +class LichKingStartMovementEvent : public BasicEvent { public: - StartMovementEvent(Creature* summoner, Creature* owner) + LichKingStartMovementEvent(Creature* summoner, Creature* owner) : _summonerGuid(summoner->GetGUID()), _owner(owner) { } @@ -714,7 +714,7 @@ class boss_the_lich_king : public CreatureScript summon->CastSpell(summon, SPELL_RISEN_WITCH_DOCTOR_SPAWN, true); summon->SetReactState(REACT_PASSIVE); summon->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); - summon->m_Events.AddEvent(new StartMovementEvent(me, summon), summon->m_Events.CalculateTime(5000)); + summon->m_Events.AddEvent(new LichKingStartMovementEvent(me, summon), summon->m_Events.CalculateTime(5000)); break; case NPC_ICE_SPHERE: { @@ -1667,7 +1667,7 @@ class npc_strangulate_vehicle : public CreatureScript switch (eventId) { case EVENT_TELEPORT: - me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveIdle(); if (TempSummon* summ = me->ToTempSummon()) { diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index c521d04512d..422fd57eb0b 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -1292,7 +1292,7 @@ struct npc_argent_captainAI : public ScriptedAI me->SetReactState(REACT_DEFENSIVE); FollowAngle = me->GetAbsoluteAngle(crok) + me->GetOrientation(); FollowDist = me->GetDistance2d(crok); - me->GetMotionMaster()->MoveFollow(crok, FollowDist, FollowAngle, MOTION_SLOT_IDLE); + me->GetMotionMaster()->MoveFollow(crok, FollowDist, FollowAngle, MOTION_SLOT_DEFAULT); } me->setActive(true); @@ -1320,7 +1320,7 @@ struct npc_argent_captainAI : public ScriptedAI void EnterEvadeMode(EvadeReason why) override { // not yet following - if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != CHASE_MOTION_TYPE || IsUndead) + if (me->GetMotionMaster()->GetCurrentMovementGeneratorType(MOTION_SLOT_DEFAULT) != FOLLOW_MOTION_TYPE || IsUndead) { ScriptedAI::EnterEvadeMode(why); return; @@ -1331,9 +1331,9 @@ struct npc_argent_captainAI : public ScriptedAI if (!me->GetVehicle()) { - me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->Clear(); if (Creature* crok = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_CROK_SCOURGEBANE))) - me->GetMotionMaster()->MoveFollow(crok, FollowDist, FollowAngle, MOTION_SLOT_IDLE); + me->GetMotionMaster()->MoveFollow(crok, FollowDist, FollowAngle, MOTION_SLOT_DEFAULT); } Reset(); diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index 66915182e6b..b3ed1c677c1 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -500,7 +500,7 @@ public: DummyEntryCheckPredicate pred; summons.DoAction(ACTION_DELAYED_DESPAWN, pred); Talk(SAY_END_P_TWO); - me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->Clear(); me->StopMoving(); if (me->GetPositionZ() > 300.0f) events.ScheduleEvent(EVENT_DELAY_MOVE_TO_DESTROY_P, 5*IN_MILLISECONDS, 0, PHASE_TWO); diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp index 318daa780f1..10a669be163 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp @@ -417,21 +417,21 @@ public: } } - void DamageTaken(Unit* /*pDoneBy*/, uint32 &uiDamage) override + void DamageTaken(Unit* /*attacker*/, uint32& damage) override { - if (uiDamage > me->GetHealth()) + if (damage >= me->GetHealth()) { me->UpdateEntry(NPC_BRITTLE_GOLEM); me->SetHealth(1); - uiDamage = 0; + damage = 0; me->RemoveAllAuras(); me->AttackStop(); - // me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); //Set in DB - // me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); //Set in DB + // me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); // Set in DB + // me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); // Set in DB if (me->IsNonMeleeSpellCast(false)) me->InterruptNonMeleeSpells(false); - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) - me->GetMotionMaster()->MovementExpired(); + + me->GetMotionMaster()->Clear(); m_bIsFrozen = true; } } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 6e52598d11a..706bf99204a 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -357,7 +357,7 @@ class boss_algalon_the_observer : public CreatureScript Movement::MoveSplineInit init(me); init.MoveTo(AlgalonLandPos.GetPositionX(), AlgalonLandPos.GetPositionY(), AlgalonLandPos.GetPositionZ(), false); init.SetOrientationFixed(true); - me->GetMotionMaster()->LaunchMoveSpline(std::move(init), POINT_ALGALON_LAND, MOTION_SLOT_ACTIVE, POINT_MOTION_TYPE); + me->GetMotionMaster()->LaunchMoveSpline(std::move(init), POINT_ALGALON_LAND, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE); events.Reset(); events.SetPhase(PHASE_ROLE_PLAY); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp index 2bf2ae3b58f..e1ac92ff165 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -1134,7 +1134,7 @@ class boss_aerial_command_unit : public CreatureScript if (events.IsInPhase(PHASE_AERIAL_COMMAND_UNIT)) { - me->GetMotionMaster()->Clear(true); + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MovePoint(WP_AERIAL_P4_POS, VehicleRelocation[WP_AERIAL_P4_POS]); } else if (events.IsInPhase(PHASE_VOL7RON)) diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp index fc143e2727b..b78f7289f1e 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp @@ -335,7 +335,7 @@ struct boss_razorscale : public BossAI init.MovebyPath(path, 0); init.SetCyclic(); init.SetFly(); - me->GetMotionMaster()->LaunchMoveSpline(std::move(init), 0, MOTION_SLOT_ACTIVE, POINT_MOTION_TYPE); + me->GetMotionMaster()->LaunchMoveSpline(std::move(init), 0, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE); } bool CanAIAttack(Unit const* target) const override diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp index 3e3b103f312..01c7f92d576 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp @@ -641,7 +641,7 @@ class boss_thorim : public CreatureScript Movement::MoveSplineInit init(summon); init.MovebyPath(path); - summon->GetMotionMaster()->LaunchMoveSpline(std::move(init), 0, MOTION_SLOT_ACTIVE, POINT_MOTION_TYPE); + summon->GetMotionMaster()->LaunchMoveSpline(std::move(init), 0, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE); break; } case NPC_DARK_RUNE_CHAMPION: diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp index a8e9c27b93a..6b4b3a1aa1f 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp @@ -256,7 +256,7 @@ class npc_vrykul_skeleton : public CreatureScript events.ScheduleEvent(EVENT_DECREPIFY, urand(4, 6) * IN_MILLISECONDS); } - void DamageTaken(Unit* /*doneBy*/, uint32& damage) override + void DamageTaken(Unit* /*attacker*/, uint32& damage) override { if (damage >= me->GetHealth()) { @@ -273,7 +273,7 @@ class npc_vrykul_skeleton : public CreatureScript events.Reset(); events.ScheduleEvent(EVENT_RESURRECT, urand(18, 22) * IN_MILLISECONDS); - me->GetMotionMaster()->MovementExpired(false); + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveIdle(); } } diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp index 511bfde03d0..1505be8eca0 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp @@ -363,7 +363,7 @@ public: Movement::MoveSplineInit init(who); init.DisableTransportPathTransformations(); init.MoveTo(0.3320355f, 0.05355075f, 5.196949f, false); - who->GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_VEHICLE_BOARD, MOTION_SLOT_CONTROLLED); + who->GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_VEHICLE_BOARD, MOTION_PRIORITY_HIGHEST); me->setActive(true); me->SetFarVisible(true); diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp index 68ad8bfacd0..da00bc6e3f5 100644 --- a/src/server/scripts/Northrend/zone_borean_tundra.cpp +++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp @@ -718,7 +718,7 @@ public: owner->RemoveAllAurasExceptType(SPELL_AURA_DUMMY); owner->CombatStop(true); owner->GetThreatManager().ClearAllThreat(); - owner->GetMotionMaster()->Clear(false); + owner->GetMotionMaster()->Clear(); owner->GetMotionMaster()->MoveFollow(GetCaster(), 4.0f, 0.0f); owner->CastSpell(owner, SPELL_SUBDUED, true); GetCaster()->CastSpell(GetCaster(), SPELL_DRAKE_HATCHLING_SUBDUED, true); diff --git a/src/server/scripts/Northrend/zone_grizzly_hills.cpp b/src/server/scripts/Northrend/zone_grizzly_hills.cpp index 021fb8e7701..3dff0fff0ba 100644 --- a/src/server/scripts/Northrend/zone_grizzly_hills.cpp +++ b/src/server/scripts/Northrend/zone_grizzly_hills.cpp @@ -898,7 +898,7 @@ public: { _finished = false; me->SetVisible(true); - me->GetMotionMaster()->Clear(true); + me->GetMotionMaster()->Clear(); } void DoAction(int32 /*action*/) override diff --git a/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp b/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp index 4807a0fbcb5..bd0ff4a4ad2 100644 --- a/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp +++ b/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp @@ -151,8 +151,7 @@ class boss_nexusprince_shaffar : public CreatureScript // expire movement, will prevent from running right back to victim after cast // (but should MoveChase be used again at a certain time or should he not move?) - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) - me->GetMotionMaster()->MovementExpired(); + me->GetMotionMaster()->Clear(MOTION_PRIORITY_NORMAL); DoCast(me, SPELL_BLINK); break; diff --git a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp index 36d04389514..76d31bd203e 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp @@ -724,7 +724,7 @@ struct npc_ashtongue_sorcerer : public ScriptedAI { _inBanish = true; me->StopMoving(); - me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MovePoint(1, me->GetPositionX() + frand(-8.0f, 8.0f), me->GetPositionY() + frand(-8.0f, 8.0f), me->GetPositionZ()); _scheduler.Schedule(Seconds(1) + Milliseconds(500), [this](TaskContext sorcer_channel) diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp index 1a84c014d0f..1034a1f8039 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp @@ -248,7 +248,7 @@ public: { Talk(EMOTE_SPOUT); me->SetReactState(REACT_PASSIVE); - me->GetMotionMaster()->MoveRotate(20000, urand(0, 1) ? ROTATE_DIRECTION_LEFT : ROTATE_DIRECTION_RIGHT); + me->GetMotionMaster()->MoveRotate(0, 20000, urand(0, 1) ? ROTATE_DIRECTION_LEFT : ROTATE_DIRECTION_RIGHT); SpoutTimer = 45000; WhirlTimer = 20000; // whirl directly after spout RotTimer = 20000; @@ -266,7 +266,7 @@ public: else WhirlTimer -= diff; - if (CheckTimer <= diff)//check if there are players in melee range + if (CheckTimer <= diff) // check if there are players in melee range { InRange = false; Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers(); diff --git a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp index 8bacf1d283d..7d9a3956fd4 100644 --- a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp +++ b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp @@ -287,9 +287,6 @@ public: { if (GameObject* go = unit->FindNearestGameObject(GO_CARCASS, 10)) { - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) - me->GetMotionMaster()->MovementExpired(); - me->GetMotionMaster()->MoveIdle(); me->StopMoving(); @@ -328,7 +325,9 @@ public: { DoCastVictim(SPELL_NETHER_BREATH); CastTimer = 5000; - } else CastTimer -= diff; + } + else + CastTimer -= diff; DoMeleeAttackIfReady(); } diff --git a/src/server/scripts/Pet/pet_dk.cpp b/src/server/scripts/Pet/pet_dk.cpp index 1dbdf9aabcc..547b97df956 100644 --- a/src/server/scripts/Pet/pet_dk.cpp +++ b/src/server/scripts/Pet/pet_dk.cpp @@ -96,7 +96,7 @@ class npc_pet_dk_ebon_gargoyle : public CreatureScript float x = me->GetPositionX() + 20 * std::cos(me->GetOrientation()); float y = me->GetPositionY() + 20 * std::sin(me->GetOrientation()); float z = me->GetPositionZ() + 40; - me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MovePoint(0, x, y, z); // Despawn as soon as possible diff --git a/src/server/scripts/Pet/pet_mage.cpp b/src/server/scripts/Pet/pet_mage.cpp index 213c578aae7..f626159a650 100644 --- a/src/server/scripts/Pet/pet_mage.cpp +++ b/src/server/scripts/Pet/pet_mage.cpp @@ -190,8 +190,8 @@ class npc_pet_mage_mirror_image : public CreatureScript me->CombatStop(true); if (owner && !me->HasUnitState(UNIT_STATE_FOLLOW)) { - me->GetMotionMaster()->Clear(false); - me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle()); } } diff --git a/src/server/scripts/World/boss_emerald_dragons.cpp b/src/server/scripts/World/boss_emerald_dragons.cpp index 39b16715a71..10e814dc1e9 100644 --- a/src/server/scripts/World/boss_emerald_dragons.cpp +++ b/src/server/scripts/World/boss_emerald_dragons.cpp @@ -198,13 +198,13 @@ class npc_dream_fog : public CreatureScript if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) { _roamTimer = urand(15000, 30000); - me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveChase(target, 0.2f); } else { _roamTimer = 2500; - me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveRandom(25.0f); } // Seeping fog movement is slow enough for a player to be able to walk backwards and still outpace it diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 55801cdc7b2..83feb183d5c 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -2821,7 +2821,7 @@ public: init.DisableTransportPathTransformations(); init.MoveTo(x, y, z, false); init.SetFacing(o); - who->GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_VEHICLE_BOARD, MOTION_SLOT_CONTROLLED); + who->GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_VEHICLE_BOARD, MOTION_PRIORITY_HIGHEST); who->m_Events.AddEvent(new CastFoodSpell(who, _chairSpells.at(who->GetEntry())), who->m_Events.CalculateTime(1000)); if (Creature* creature = who->ToCreature()) creature->SetDisplayFromModel(0); diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index cb6e515885e..b26b2ae45dd 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -4035,7 +4035,9 @@ Logger.mmaps=3,Server #Logger.maps.script=3,Console Server #Logger.maps=3,Console Server #Logger.misc=3,Console Server +#Logger.movement.flightpath=3,Console Server #Logger.movement.motionmaster=3,Console Server +#Logger.movement.splinechain=3,Console Server #Logger.network=3,Console Server #Logger.network.opcode=3,Console Server #Logger.network.soap=3,Console Server |