TrinityCore
Loading...
Searching...
No Matches
WaypointMovementGenerator.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
19#include "Creature.h"
20#include "CreatureAI.h"
21#include "Errors.h"
22#include "Log.h"
23#include "Map.h"
24#include "MovementDefines.h"
25#include "MoveSpline.h"
26#include "MoveSplineInit.h"
27#include "ObjectMgr.h"
28#include "Transport.h"
29#include "WaypointManager.h"
30
31WaypointMovementGenerator<Creature>::WaypointMovementGenerator(uint32 pathId, bool repeating) : _nextMoveTime(0), _pathId(pathId), _repeating(repeating), _loadedFromDB(true)
32{
33 Priority = MOTION_PRIORITY_NORMAL;
35 BaseUnitState = UNIT_STATE_ROAMING;
36}
37
38WaypointMovementGenerator<Creature>::WaypointMovementGenerator(WaypointPath& path, bool repeating) : _nextMoveTime(0), _pathId(0), _repeating(repeating), _loadedFromDB(false)
39{
40 _path = &path;
41
42 Priority = MOTION_PRIORITY_NORMAL;
44 BaseUnitState = UNIT_STATE_ROAMING;
45}
46
51
53{
54 if (timer)
55 {
56 // Don't try to paused an already paused generator
58 return;
59
61 _nextMoveTime.Reset(timer);
63 }
64 else
65 {
67 _nextMoveTime.Reset(1); // Needed so that Update does not behave as if node was reached
69 }
70}
71
73{
74 if (overrideTimer)
75 _nextMoveTime.Reset(overrideTimer);
76
77 if (_nextMoveTime.Passed())
78 _nextMoveTime.Reset(1); // Needed so that Update does not behave as if node was reached
79
81}
82
83bool WaypointMovementGenerator<Creature>::GetResetPosition(Unit* /*owner*/, float& x, float& y, float& z)
84{
85 // prevent a crash at empty waypoint path.
86 if (!_path || _path->nodes.empty())
87 return false;
88
89 ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::GetResetPosition: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id);
90 WaypointNode const &waypoint = _path->nodes.at(_currentNode);
91
92 x = waypoint.x;
93 y = waypoint.y;
94 z = waypoint.z;
95 return true;
96}
97
99{
101
102 if (_loadedFromDB)
103 {
104 if (!_pathId)
105 _pathId = owner->GetWaypointPath();
106
107 _path = sWaypointMgr->GetPath(_pathId);
108 }
109
110 if (!_path)
111 {
112 TC_LOG_ERROR("sql.sql", "WaypointMovementGenerator::DoInitialize: couldn't load path for creature ({}) (_pathId: {})", owner->GetGUID().ToString(), _pathId);
113 return false;
114 }
115
116 owner->StopMoving();
117
118 _nextMoveTime.Reset(1000);
119 return true;
120}
121
123{
125
126 owner->StopMoving();
127
128 if (!HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED) && _nextMoveTime.Passed())
129 _nextMoveTime.Reset(1); // Needed so that Update does not behave as if node was reached
130 return true;
131}
132
134{
135 if (!owner || !owner->IsAlive())
136 return true;
137
138 if (HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED | MOVEMENTGENERATOR_FLAG_PAUSED) || !_path || _path->nodes.empty())
139 return true;
140
142 {
144 owner->StopMoving();
145 return true;
146 }
147
149 {
150 /*
151 * relaunch only if
152 * - has a tiner? -> was it interrupted while not waiting aka moving? need to check both:
153 * -> has a timer - is it because its waiting to start next node?
154 * -> has a timer - is it because something set it while moving (like timed pause)?
155 *
156 * - doesnt have a timer? -> is movement valid?
157 *
158 * TODO: ((_nextMoveTime.Passed() && VALID_MOVEMENT) || (!_nextMoveTime.Passed() && !HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)))
159 */
160 if (HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED) && (_nextMoveTime.Passed() || !HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)))
161 {
162 StartMove(owner, true);
163 return true;
164 }
165
167 }
168
169 // if it's moving
170 if (!owner->movespline->Finalized())
171 {
172 // set home position at place (every MotionMaster::UpdateMotion)
174 owner->SetHomePosition(owner->GetPosition());
175
176 // relaunch movement if its speed has changed
178 StartMove(owner, true);
179 }
180 else if (!_nextMoveTime.Passed()) // it's not moving, is there a timer?
181 {
182 if (UpdateTimer(diff))
183 {
184 if (!HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED)) // initial movement call
185 {
186 StartMove(owner);
187 return true;
188 }
189 else if (!HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)) // timer set before node was reached, resume now
190 {
191 StartMove(owner, true);
192 return true;
193 }
194 }
195 else
196 return true; // keep waiting
197 }
198 else // not moving, no timer
199 {
201 {
202 OnArrived(owner); // hooks and wait timer reset (if necessary)
203 AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED); // signals to future StartMove that it reached a node
204 }
205
206 if (_nextMoveTime.Passed()) // OnArrived might have set a timer
207 StartMove(owner); // check path status, get next point and move if necessary & can
208 }
209
210 return true;
211}
212
218
219void WaypointMovementGenerator<Creature>::DoFinalize(Creature* owner, bool active, bool/* movementInform*/)
220{
222 if (active)
223 {
225
226 // TODO: Research if this modification is needed, which most likely isnt
227 owner->SetWalk(false);
228 }
229}
230
232{
233 if (owner->AI())
234 owner->AI()->MovementInform(WAYPOINT_MOTION_TYPE, _currentNode);
235}
236
238{
239 if (!_path || _path->nodes.empty())
240 return;
241
242 ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::OnArrived: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id);
243 WaypointNode const& waypoint = _path->nodes[_currentNode];
244 if (waypoint.delay)
245 {
247 _nextMoveTime.Reset(waypoint.delay);
248 }
249
250 // scripts can invalidate current path, store what we need
251 uint32 waypointId = waypoint.id;
252 uint32 pathId = _path->id;
253 if (waypoint.eventId && urand(0, 99) < waypoint.eventChance)
254 {
255 TC_LOG_DEBUG("maps.script", "Creature movement start script {} at point {} for {}.", waypoint.eventId, _currentNode, owner->GetGUID().ToString());
257 owner->GetMap()->ScriptsStart(sWaypointScripts, waypoint.eventId, owner, nullptr);
258 }
259
260 // inform AI
261 if (CreatureAI* AI = owner->AI())
262 {
263 AI->MovementInform(WAYPOINT_MOTION_TYPE, _currentNode);
264 AI->WaypointReached(waypointId, pathId);
265 }
266
267 owner->UpdateCurrentWaypointInfo(waypointId, pathId);
268}
269
270void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaunch/* = false*/)
271{
272 // sanity checks
273 if (!owner || !owner->IsAlive() || HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED) || !_path || _path->nodes.empty() || (relaunch && (HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED) || !HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED))))
274 return;
275
276 if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting() || (owner->IsFormationLeader() && !owner->IsFormationLeaderMoveAllowed())) // if cannot move OR cannot move because of formation
277 {
278 _nextMoveTime.Reset(1000); // delay 1s
279 return;
280 }
281
282 bool const transportPath = owner->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && !owner->GetTransGUID().IsEmpty();
283
285 {
286 if (ComputeNextNode())
287 {
288 ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id);
289
290 // inform AI
291 if (CreatureAI* AI = owner->AI())
292 AI->WaypointStarted(_path->nodes[_currentNode].id, _path->id);
293 }
294 else
295 {
296 WaypointNode const &waypoint = _path->nodes[_currentNode];
297 float x = waypoint.x;
298 float y = waypoint.y;
299 float z = waypoint.z;
300 float o = owner->GetOrientation();
301
302 if (!transportPath)
303 owner->SetHomePosition(x, y, z, o);
304 else
305 {
306 if (Transport* trans = owner->GetTransport())
307 {
308 o -= trans->GetOrientation();
309 owner->SetTransportHomePosition(x, y, z, o);
310 trans->CalculatePassengerPosition(x, y, z, &o);
311 owner->SetHomePosition(x, y, z, o);
312 }
313 // else if (vehicle) - this should never happen, vehicle offsets are const
314 }
316 owner->UpdateCurrentWaypointInfo(0, 0);
317
318 // inform AI
319 if (CreatureAI* AI = owner->AI())
320 AI->WaypointPathEnded(waypoint.id, _path->id);
321 return;
322 }
323 }
324 else if (!HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED))
325 {
327
328 // inform AI
329 if (CreatureAI* AI = owner->AI())
330 AI->WaypointStarted(_path->nodes[_currentNode].id, _path->id);
331 }
332
333 ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id);
334 WaypointNode const &waypoint = _path->nodes[_currentNode];
335
337
339
340 Movement::MoveSplineInit init(owner);
341
343 if (transportPath)
345
348 init.MoveTo(waypoint.x, waypoint.y, waypoint.z);
349
350 if (waypoint.orientation.has_value() && waypoint.delay > 0)
351 init.SetFacing(*waypoint.orientation);
352
353 switch (waypoint.moveType)
354 {
357 break;
360 break;
362 init.SetWalk(false);
363 break;
365 init.SetWalk(true);
366 break;
367 default:
368 break;
369 }
370
371 init.Launch();
372
373 // inform formation
375}
376
378{
379 if ((_currentNode == _path->nodes.size() - 1) && !_repeating)
380 return false;
381
382 _currentNode = (_currentNode + 1) % _path->nodes.size();
383 return true;
384}
385
387{
388 std::stringstream sstr;
389 sstr << PathMovementBase::GetDebugInfo() << "\n"
391 return sstr.str();
392}
uint32_t uint32
Definition Define.h:133
#define ASSERT
Definition Errors.h:68
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
@ MOTION_PRIORITY_NORMAL
MovementGeneratorType
@ WAYPOINT_MOTION_TYPE
@ MOVEMENTGENERATOR_FLAG_TIMED_PAUSED
@ MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING
@ MOVEMENTGENERATOR_FLAG_PAUSED
@ MOVEMENTGENERATOR_FLAG_DEACTIVATED
@ MOVEMENTGENERATOR_FLAG_FINALIZED
@ MOVEMENTGENERATOR_FLAG_TRANSITORY
@ MOVEMENTGENERATOR_FLAG_INTERRUPTED
@ MOVEMENTGENERATOR_FLAG_INFORM_ENABLED
@ MOVEMENTGENERATOR_FLAG_INITIALIZED
@ MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING
ScriptMapMap sWaypointScripts
Definition ObjectMgr.cpp:61
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
@ MOVEMENTFLAG_ONTRANSPORT
@ UNIT_STATE_NOT_MOVE
Definition Unit.h:265
@ UNIT_STATE_ROAMING_MOVE
Definition Unit.h:243
@ UNIT_STATE_LOST_CONTROL
Definition Unit.h:261
@ UNIT_STATE_ROAMING
Definition Unit.h:224
@ WAYPOINT_MOVE_TYPE_RUN
@ WAYPOINT_MOVE_TYPE_LAND
@ WAYPOINT_MOVE_TYPE_TAKEOFF
@ WAYPOINT_MOVE_TYPE_WALK
#define sWaypointMgr
virtual void MovementInform(uint32, uint32)
Definition CreatureAI.h:173
void SetHomePosition(float x, float y, float z, float o)
Definition Creature.h:293
uint32 GetWaypointPath() const
Definition Creature.h:303
void SignalFormationMovement()
Definition Creature.cpp:349
bool IsFormationLeaderMoveAllowed() const
Definition Creature.cpp:360
void UpdateCurrentWaypointInfo(uint32 nodeId, uint32 pathId)
Definition Creature.h:308
bool IsFormationLeader() const
Definition Creature.cpp:341
void SetTransportHomePosition(float x, float y, float z, float o)
Definition Creature.h:298
CreatureAI * AI() const
Definition Creature.h:154
bool IsMovementPreventedByCasting() const override
void ScriptsStart(std::map< uint32, std::multimap< uint32, ScriptInfo > > const &scripts, uint32 id, Object *source, Object *target)
Put scripts in the execution queue.
virtual std::string GetDebugInfo() const
void MoveTo(Vector3 const &destination, bool generatePath=true, bool forceDestination=false)
void SetWalk(bool enable)
void SetFacing(float angle)
void SetAnimation(AnimTier anim)
bool Finalized() const
Definition MoveSpline.h:121
bool IsEmpty() const
Definition ObjectGuid.h:172
std::string ToString() const
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
virtual std::string GetDebugInfo() const
Definition Unit.h:769
void ClearUnitState(uint32 f)
Definition Unit.h:877
Movement::MoveSpline * movespline
Definition Unit.h:1804
void StopMoving(bool force=false)
Definition Unit.cpp:10312
bool IsAlive() const
Definition Unit.h:1234
void AddUnitState(uint32 f)
Definition Unit.h:875
bool HasUnitMovementFlag(uint32 f) const
Definition Unit.h:1678
bool SetWalk(bool enable)
Definition Unit.cpp:13268
ObjectGuid GetTransGUID() const override
Definition Unit.cpp:11856
bool HasUnitState(const uint32 f) const
Definition Unit.h:876
Map * GetMap() const
Definition Object.h:449
Transport * GetTransport() const
Definition Object.h:564
float GetOrientation() const
Definition Position.h:82
void GetPosition(float &x, float &y) const
Definition Position.h:84
Optional< float > orientation