-
Notifications
You must be signed in to change notification settings - Fork 6k
/
MotionMaster.h
281 lines (251 loc) · 15.8 KB
/
MotionMaster.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOTIONMASTER_H
#define MOTIONMASTER_H
#include "Common.h"
#include "Duration.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 PathGenerator;
class Unit;
struct Position;
struct SplineChainLink;
struct SplineChainResumeInfo;
struct WaypointPath;
enum UnitMoveType : uint8;
namespace Movement
{
class MoveSplineInit;
struct SpellEffectExtraData;
}
enum MotionMasterFlags : uint8
{
MOTIONMASTER_FLAG_NONE = 0x0,
MOTIONMASTER_FLAG_UPDATE = 0x1, // Update in progress
MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING = 0x2, // Static movement (MOTION_SLOT_DEFAULT) hasn't been initialized
MOTIONMASTER_FLAG_INITIALIZATION_PENDING = 0x4, // MotionMaster is stalled until signaled
MOTIONMASTER_FLAG_INITIALIZING = 0x8, // MotionMaster is initializing
MOTIONMASTER_FLAG_DELAYED = MOTIONMASTER_FLAG_UPDATE | MOTIONMASTER_FLAG_INITIALIZATION_PENDING
};
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:
bool operator()(MovementGenerator const* a, MovementGenerator const* b) const;
};
struct MovementGeneratorInformation
{
MovementGeneratorInformation(MovementGeneratorType type, ObjectGuid targetGUID, std::string const& targetName);
MovementGeneratorType Type;
ObjectGuid TargetGUID;
std::string TargetName;
};
static bool EmptyValidator()
{
return true;
}
class TC_GAME_API MotionMaster
{
public:
typedef std::function<void()> DelayedActionDefine;
typedef std::function<bool()> DelayedActionValidator;
class DelayedAction
{
public:
explicit DelayedAction(DelayedActionDefine&& action, DelayedActionValidator&& validator, MotionMasterDelayedActionType type) : Action(std::move(action)), Validator(std::move(validator)), Type(type) { }
explicit DelayedAction(DelayedActionDefine&& action, MotionMasterDelayedActionType type) : Action(std::move(action)), Validator(EmptyValidator), Type(type) { }
~DelayedAction() { }
void Resolve() { if (Validator()) Action(); }
DelayedActionDefine Action;
DelayedActionValidator Validator;
uint8 Type;
};
explicit MotionMaster(Unit* unit);
~MotionMaster();
void Initialize();
void InitializeDefault();
void AddToWorld();
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: 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);
bool StopOnDeath();
void MoveIdle();
void MoveTargetedHome();
void MoveRandom(float wanderDistance = 0.0f, Optional<Milliseconds> duration = {}, MovementSlot slot = MOTION_SLOT_DEFAULT,
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
void MoveFollow(Unit* target, float dist, ChaseAngle angle, Optional<Milliseconds> duration = {}, MovementSlot slot = MOTION_SLOT_ACTIVE,
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
void MoveChase(Unit* target, Optional<ChaseRange> dist = {}, Optional<ChaseAngle> angle = {});
void MoveChase(Unit* target, float dist, float angle) { MoveChase(target, ChaseRange(dist), ChaseAngle(angle)); }
void MoveConfused();
void MoveFleeing(Unit* enemy, Milliseconds time = 0ms,
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
void MovePoint(uint32 id, Position const& pos, bool generatePath = true, Optional<float> finalOrient = {}, Optional<float> speed = {},
MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default, Optional<float> closeEnoughDistance = {},
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
void MovePoint(uint32 id, float x, float y, float z, bool generatePath = true, Optional<float> finalOrient = {}, Optional<float> speed = {},
MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default, Optional<float> closeEnoughDistance = {},
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
/*
* Makes the unit move toward the target until it is at a certain distance from it. The unit then stops.
* Only works in 2D.
* 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, Optional<int32> tierTransitionId = {}, Optional<float> velocity = {},
MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default,
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
void MoveTakeoff(uint32 id, Position const& pos, Optional<int32> tierTransitionId = {}, Optional<float> velocity = {},
MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default,
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE, bool generatePath = false, Unit const* target = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr);
void MoveCharge(PathGenerator const& path, float speed = SPEED_CHARGE, Unit const* target = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr);
void MoveKnockbackFrom(Position const& origin, float speedXY, float speedZ, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr);
void MoveJumpTo(float angle, float speedXY, float speedZ);
void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = EVENT_JUMP, bool hasOrientation = false,
JumpArrivalCastArgs const* arrivalCast = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr,
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
void MoveJump(float x, float y, float z, float o, float speedXY, float speedZ, uint32 id = EVENT_JUMP, bool hasOrientation = false,
JumpArrivalCastArgs const* arrivalCast = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr,
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
void MoveJumpWithGravity(Position const& pos, float speedXY, float gravity, uint32 id = EVENT_JUMP, bool hasOrientation = false,
JumpArrivalCastArgs const* arrivalCast = nullptr, Movement::SpellEffectExtraData const* spellEffectExtraData = nullptr,
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount,
Optional<Milliseconds> duration = {}, Optional<float> speed = {},
MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default,
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
void MoveCyclicPath(uint32 pathId, bool enforceFly = false,
Optional<Milliseconds> duration = {}, Optional<float> speed = {},
MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default,
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
void MoveSmoothPath(uint32 pointId, Position const* pathPoints, size_t pathSize, bool walk = false, bool fly = false);
// Walk along spline chain stored in DB (script_spline_chain_meta and script_spline_chain_waypoints)
void MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk);
void MoveAlongSplineChain(uint32 pointId, std::vector<SplineChainLink> const& chain, bool walk);
void ResumeSplineChain(SplineChainResumeInfo const& info);
void MoveFall(uint32 id = 0,
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
void MoveSeekAssistance(float x, float y, float z);
void MoveSeekAssistanceDistract(uint32 timer);
void MoveTaxiFlight(uint32 path, uint32 pathnode, Optional<float> speed = {},
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
void MoveDistract(uint32 time, float orientation);
void MovePath(uint32 pathId, bool repeatable, Optional<Milliseconds> duration = {}, Optional<float> speed = {},
MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default,
Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd = {}, Optional<float> wanderDistanceAtPathEnds = {},
Optional<bool> followPathBackwardsFromEndToStart = {}, bool generatePath = true,
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
void MovePath(WaypointPath const& path, bool repeatable, Optional<Milliseconds> duration = {}, Optional<float> speed = {},
MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default,
Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd = {}, Optional<float> wanderDistanceAtPathEnds = {},
Optional<bool> followPathBackwardsFromEndToStart = {}, bool generatePath = true,
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
/**
* \brief Makes the Unit turn in place
* \param id Movement identifier, later passed to script MovementInform hooks
* \param direction Rotation direction
* \param time How long should this movement last, infinite if not set
* \param turnSpeed How fast should the unit rotate, in radians per second. Uses unit's turn speed if not set
* \param totalTurnAngle Total angle of the entire movement, infinite if not set
* \param scriptResult Awaitable script result (for internal use)
*/
void MoveRotate(uint32 id, RotateDirection direction, Optional<Milliseconds> time = {},
Optional<float> turnSpeed = {}, Optional<float> totalTurnAngle = {},
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult = {});
void MoveFormation(Unit* leader, float range, float angle, uint32 point1, uint32 point2);
void LaunchMoveSpline(std::function<void(Movement::MoveSplineInit& init)>&& initializer, uint32 id = 0, MovementGeneratorPriority priority = MOTION_PRIORITY_NORMAL, MovementGeneratorType type = EFFECT_MOTION_TYPE);
void CalculateJumpSpeeds(float dist, UnitMoveType moveType, float speedMultiplier, float minHeight, float maxHeight, float& speedXY, float& speedZ) const;
private:
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 ResolveDelayedActions();
void Remove(MotionMasterContainer::iterator iterator, bool active, bool movementInform);
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();
Unit* _owner;
MovementGeneratorPointer _defaultGenerator;
MotionMasterContainer _generators;
MotionMasterUnitStatesContainer _baseUnitStatesMap;
std::deque<DelayedAction> _delayedActions;
uint8 _flags;
};
#endif // MOTIONMASTER_H