diff --git a/doc/EventAI.txt b/doc/EventAI.txt index 2724977a75c..8dd2d1d7297 100644 --- a/doc/EventAI.txt +++ b/doc/EventAI.txt @@ -161,7 +161,7 @@ For all ACTION_T_RANDOM Actions, When a Particular Param is selected for the Eve 45 ACTION_T_THROW_AI_EVENT EventType, Radius, Target Throws an AIEvent of type (Param1) to nearby friendly Npcs in range of (Param2), Invoker of event is Target 46 ACTION_T_SET_THROW_MASK EventTypeMask Marks for which AIEvents the npc will throw AIEvents on its own. 47 ACTION_T_SET_STAND_STATE StandState Set the unit stand state (Param1) of the current creature. -48 ACTION_T_CHANGE_MOVEMENT MovementType, WanderDistance Change the unit movement type (Param1). If the movement type is Random Movement (1), the WanderDistance (Param2) must be provided. If the movement type is Waypoint Movement (2), Param2 is PathId. Param3 is asDefault. +48 ACTION_T_CHANGE_MOVEMENT MovementType, WanderDistance Change the unit movement type (Param1). If the movement type is Random Movement (1), the WanderDistance (Param2) must be provided. If the movement type is Waypoint Movement (2), Param2 is PathId. Param3 0x1 is asDefault, 0x2 forces waypoint, path or linear path movement to use waypoint_path table PathId 49 ACTION_T_REUSE 50 ACTION_T_SET_REACT_STATE ReactState Change react state of the creature 51 ACTION_T_PAUSE_WAYPOINTS DoPause Pause waypoints of creature diff --git a/doc/script_commands.txt b/doc/script_commands.txt index c94f59eaa13..5ebe5e04110 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -260,9 +260,10 @@ Defining a buddy could be done in several way: * datalog = movie id 20 SCRIPT_COMMAND_MOVEMENT resultingSource = Creature - * datalong = MovementType (0:idle, 1:random, 2:waypoint, 3:path) + * datalong = MovementType (0:idle, 1:random, 2:waypoint, 3:path, 4:linear) * datalong2 = wanderDistance (for random movement), pathId (for waypoint movement) - * datalong3 = timer for timed random movement or pass target to waypoint and path movegen (by default, source targets self) + * datalong3 = 0x1 - timer for timed random movement or pass target to waypoint and path movegen (by default, source targets self) + * 0x2 - for waypoint, path and linear path - uses pathId from waypoint_path table * data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL: RandomMovement around current position * dataint = enum ForcedMovement diff --git a/src/game/AI/EventAI/CreatureEventAI.cpp b/src/game/AI/EventAI/CreatureEventAI.cpp index 1b2e25491e2..2ad9489c863 100644 --- a/src/game/AI/EventAI/CreatureEventAI.cpp +++ b/src/game/AI/EventAI/CreatureEventAI.cpp @@ -1189,7 +1189,7 @@ bool CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 } case ACTION_T_CHANGE_MOVEMENT: { - if (action.changeMovement.asDefault) + if (action.changeMovement.flags & CHANGE_MOVEMENT_FLAG_AS_DEFAULT) m_defaultMovement = MovementGeneratorType(action.changeMovement.movementType); switch (action.changeMovement.movementType) { @@ -1200,15 +1200,34 @@ bool CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 m_creature->GetMotionMaster()->MoveRandomAroundPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), float(action.changeMovement.wanderORpathID)); break; case WAYPOINT_MOTION_TYPE: + { m_creature->StopMoving(); m_creature->GetMotionMaster()->Clear(false, true); - m_creature->GetMotionMaster()->MoveWaypoint(action.changeMovement.wanderORpathID); + WaypointPathOrigin origin = PATH_NO_PATH; + if (action.changeMovement.flags & CHANGE_MOVEMENT_FLAG_WAYPOINT_PATH) + origin = PATH_FROM_WAYPOINT_PATH; + m_creature->GetMotionMaster()->MoveWaypoint(action.changeMovement.wanderORpathID, origin); + break; + } + case PATH_MOTION_TYPE: + { + m_creature->StopMoving(); + WaypointPathOrigin origin = PATH_NO_PATH; + if (action.changeMovement.flags & CHANGE_MOVEMENT_FLAG_WAYPOINT_PATH) + origin = PATH_FROM_WAYPOINT_PATH; + m_creature->GetMotionMaster()->MovePath(action.changeMovement.wanderORpathID, origin); break; + } case LINEAR_WP_MOTION_TYPE: + { m_creature->StopMoving(); m_creature->GetMotionMaster()->Clear(false, true); - m_creature->GetMotionMaster()->MoveLinearWP(action.changeMovement.wanderORpathID); + WaypointPathOrigin origin = PATH_NO_PATH; + if (action.changeMovement.flags & CHANGE_MOVEMENT_FLAG_WAYPOINT_PATH) + origin = PATH_FROM_WAYPOINT_PATH; + m_creature->GetMotionMaster()->MoveLinearWP(action.changeMovement.wanderORpathID, origin); break; + } } break; } diff --git a/src/game/AI/EventAI/CreatureEventAI.h b/src/game/AI/EventAI/CreatureEventAI.h index 9be6d65eca3..c85b0a7fd47 100644 --- a/src/game/AI/EventAI/CreatureEventAI.h +++ b/src/game/AI/EventAI/CreatureEventAI.h @@ -229,6 +229,13 @@ enum DespawnAggregation : uint32 AGGREGATION_DEATH = 0x4, }; +enum ChangeMovementFlags : uint32 +{ + CHANGE_MOVEMENT_FLAG_AS_DEFAULT = 0x1, + CHANGE_MOVEMENT_FLAG_WAYPOINT_PATH = 0x2, + CHANGE_MOVEMENT_MAX = 0x3, +}; + struct CreatureEventAI_Action { EventAI_ActionType type: 16; @@ -480,7 +487,7 @@ struct CreatureEventAI_Action { uint32 movementType; uint32 wanderORpathID; - uint32 asDefault; + uint32 flags; } changeMovement; // ACTION_T_REUSE = 49 struct diff --git a/src/game/AI/EventAI/CreatureEventAIMgr.cpp b/src/game/AI/EventAI/CreatureEventAIMgr.cpp index dfd40a59f56..0eadb99eacd 100644 --- a/src/game/AI/EventAI/CreatureEventAIMgr.cpp +++ b/src/game/AI/EventAI/CreatureEventAIMgr.cpp @@ -903,10 +903,10 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() { sLog.outErrorEventAI("Event %u Action %u uses invalid movement type %u (must be smaller than %u)", eventId, j + 1, action.changeMovement.movementType, MAX_DB_MOTION_TYPE); } - if (action.changeMovement.asDefault > 1) + if (action.changeMovement.flags > CHANGE_MOVEMENT_MAX) { - sLog.outErrorEventAI("Event %u Action %u uses invalid default movement setting %u. Setting to 0.", eventId, j + 1, action.changeMovement.asDefault); - action.changeMovement.asDefault = 0; + sLog.outErrorEventAI("Event %u Action %u uses invalid flags setting %u. Setting to 0.", eventId, j + 1, action.changeMovement.flags); + action.changeMovement.flags = 0; } break; case ACTION_T_SET_REACT_STATE: diff --git a/src/game/AI/ScriptDevAI/base/escort_ai.cpp b/src/game/AI/ScriptDevAI/base/escort_ai.cpp index caf5406ce3d..08208c3ae49 100644 --- a/src/game/AI/ScriptDevAI/base/escort_ai.cpp +++ b/src/game/AI/ScriptDevAI/base/escort_ai.cpp @@ -232,7 +232,7 @@ void npc_escortAI::SetRun(bool run) } // TODO: get rid of this many variables passed in function. -void npc_escortAI::Start(bool run, const Player* player, const Quest* quest, bool instantRespawn, bool canLoopPath) +void npc_escortAI::Start(bool run, const Player* player, const Quest* quest, bool instantRespawn, bool canLoopPath, uint32 waypointPath) { if (m_creature->GetVictim()) { @@ -246,7 +246,15 @@ void npc_escortAI::Start(bool run, const Player* player, const Quest* quest, boo return; } - if (!sWaypointMgr.GetPathFromOrigin(m_creature->GetEntry(), m_creature->GetGUIDLow(), m_waypointPathID, PATH_FROM_EXTERNAL)) + uint32 pathId = m_waypointPathID; + WaypointPathOrigin origin = PATH_FROM_EXTERNAL; + if (waypointPath) + { + pathId = waypointPath; + origin = PATH_FROM_WAYPOINT_PATH; + } + + if (!sWaypointMgr.GetPathFromOrigin(m_creature->GetEntry(), m_creature->GetGUIDLow(), pathId, origin)) { script_error_log("EscortAI attempt to start escorting for %s, but has no waypoints loaded.", m_creature->GetScriptName().data()); return; @@ -276,7 +284,7 @@ void npc_escortAI::Start(bool run, const Player* player, const Quest* quest, boo // Start moving along the path with 2500ms delay m_creature->GetMotionMaster()->Clear(false, true); - m_creature->GetMotionMaster()->MoveWaypoint(m_waypointPathID, PATH_FROM_EXTERNAL, 2500); + m_creature->GetMotionMaster()->MoveWaypoint(pathId, origin, 2500); JustStartedEscort(); } diff --git a/src/game/AI/ScriptDevAI/base/escort_ai.h b/src/game/AI/ScriptDevAI/base/escort_ai.h index 020caa75a09..78c8ac2a947 100644 --- a/src/game/AI/ScriptDevAI/base/escort_ai.h +++ b/src/game/AI/ScriptDevAI/base/escort_ai.h @@ -39,7 +39,7 @@ struct npc_escortAI : public ScriptedAI virtual void WaypointReached(uint32 pointId) = 0; virtual void WaypointStart(uint32 /*pointId*/) {} - void Start(bool run = false, const Player* player = nullptr, const Quest* quest = nullptr, bool instantRespawn = false, bool canLoopPath = false); + void Start(bool run = false, const Player* player = nullptr, const Quest* quest = nullptr, bool instantRespawn = false, bool canLoopPath = false, uint32 waypointPath = 0); void SetRun(bool run = true); void SetEscortPaused(bool paused); diff --git a/src/game/DBScripts/ScriptMgr.cpp b/src/game/DBScripts/ScriptMgr.cpp index 7d63da5e380..aaea9c69cf7 100644 --- a/src/game/DBScripts/ScriptMgr.cpp +++ b/src/game/DBScripts/ScriptMgr.cpp @@ -2047,7 +2047,7 @@ bool ScriptAction::ExecuteDbscriptCommand(WorldObject* pSource, WorldObject* pTa if (m_script->movement.movementType == WAYPOINT_MOTION_TYPE || m_script->movement.movementType == PATH_MOTION_TYPE) { - if (m_script->movement.timerOrPassTarget && !pTarget) + if ((m_script->movement.timerOrPassTarget & 0x1) && !pTarget) { DETAIL_FILTER_LOG(LOG_FILTER_DB_SCRIPT, " DB-SCRIPTS: Process table `%s` id %u, SCRIPT_COMMAND_MOVEMENT called for movement change to %u with source guid %s, pass target true and target nullptr: skipping.", m_table, m_script->id, m_script->movement.movementType, pSource->GetGuidStr().c_str()); break; @@ -2073,28 +2073,43 @@ bool ScriptAction::ExecuteDbscriptCommand(WorldObject* pSource, WorldObject* pTa } break; case WAYPOINT_MOTION_TYPE: + { source->StopMoving(); source->GetMotionMaster()->Clear(false, true); - if (!m_script->movement.timerOrPassTarget) + WaypointPathOrigin origin = PATH_NO_PATH; + if (m_script->movement.timerOrPassTarget & 0x2) + origin = PATH_FROM_WAYPOINT_PATH; + if (!m_script->movement.timerOrPassTarget & 0x1) source->GetMotionMaster()->MoveWaypoint(m_script->movement.wanderORpathId); else source->GetMotionMaster()->MoveWaypoint(m_script->movement.wanderORpathId, 0, 0, 0, ForcedMovement(m_script->textId[0]), pTarget->GetObjectGuid()); break; + } case PATH_MOTION_TYPE: + { source->StopMoving(); - if (!m_script->movement.timerOrPassTarget) + WaypointPathOrigin origin = PATH_NO_PATH; + if (m_script->movement.timerOrPassTarget & 0x2) + origin = PATH_FROM_WAYPOINT_PATH; + if (!m_script->movement.timerOrPassTarget & 0x1) source->GetMotionMaster()->MovePath(m_script->movement.wanderORpathId); else source->GetMotionMaster()->MovePath(m_script->movement.wanderORpathId, PATH_NO_PATH, ForcedMovement(m_script->textId[0]), false, 0.f, false, pTarget->GetObjectGuid()); break; + } case LINEAR_WP_MOTION_TYPE: + { source->StopMoving(); source->GetMotionMaster()->Clear(false, true); - if (!m_script->movement.timerOrPassTarget) + WaypointPathOrigin origin = PATH_NO_PATH; + if (m_script->movement.timerOrPassTarget & 0x2) + origin = PATH_FROM_WAYPOINT_PATH; + if (!m_script->movement.timerOrPassTarget & 0x1) source->GetMotionMaster()->MoveLinearWP(m_script->movement.wanderORpathId); else source->GetMotionMaster()->MoveLinearWP(m_script->movement.wanderORpathId, 0, 0, 0, ForcedMovement(m_script->textId[0]), pTarget->GetObjectGuid()); break; + } } break;