Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
TargetedMovementGenerator.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "ByteBuffer.h"
7#include "Creature.h"
8#include "CreatureAI.h"
9#include "Errors.h"
10#include "MoveSpline.h"
11#include "MoveSplineInit.h"
12#include "PetTransportSupport.h"
13#include "Player.h"
15#include "World.h"
16
17namespace
18{
19 float const TransportPetFollowTolerance = 0.25f;
20}
21
22template<class T, typename D>
24{
25 if (!i_target.isValid() || !i_target->IsInWorld())
26 return;
27
28 if (owner->HasUnitState(UNIT_STATE_NOT_MOVE))
29 return;
30
31 if (owner->GetTypeId() == TypeID::TYPEID_UNIT && !i_target->isInAccessiblePlaceFor(owner->ToCreature()))
32 return;
33
34 float x, y, z;
35
37 owner->GetOwnerGUID() == i_target->GetGUID(), owner->GetTransport() != NULL,
38 owner->GetTransport() && owner->GetTransport() == i_target->GetTransport(), i_offset > 0.0f))
39 {
41 i_target->GetTransOffsetX(), i_target->GetTransOffsetY(), i_target->GetTransOffsetZ(), i_target->GetTransOffsetO(),
42 i_target->GetCombatReach(), 0.0f, i_offset, i_angle);
43
44 if (!Skyfire::PetTransport::ShouldMoveTransportPetToFollowOffset(owner->GetTransOffsetX(), owner->GetTransOffsetY(),
45 owner->GetTransOffsetZ(), offset.X, offset.Y, offset.Z, TransportPetFollowTolerance))
46 return;
47
48 delete i_path;
49 i_path = NULL;
50
51 D::_addUnitStateMove(owner);
52 i_targetReached = false;
53 i_recalculateTravel = false;
54 owner->AddUnitState(UNIT_STATE_CHASE);
55
56 Movement::MoveSplineInit init(owner);
57 init.DisableTransportPathTransformations();
58 init.MoveTo(offset.X, offset.Y, offset.Z, false, true);
59 init.SetWalk(((D*)this)->EnableWalking());
60 if (i_angle == 0.f)
61 init.SetFacing(i_target.getTarget());
62
63 init.Launch();
64 return;
65 }
66
67 if (updateDestination || !i_path)
68 {
69 if (!i_offset)
70 {
71 // to nearest contact position
72 i_target->GetContactPoint(owner, x, y, z);
73 }
74 else
75 {
76 float dist;
77 float size;
78
79 // Pets need special handling.
80 // We need to subtract GetObjectSize() because it gets added back further down the chain
81 // and that makes pets too far away. Subtracting it allows pets to properly
82 // be (GetCombatReach() + i_offset) away.
83 // Only applies when i_target is pet's owner otherwise pets and mobs end up
84 // doing a "dance" while fighting
85 if (owner->IsPet() && i_target->GetTypeId() == TypeID::TYPEID_PLAYER)
86 {
87 dist = i_target->GetCombatReach();
88 size = i_target->GetCombatReach() - i_target->GetObjectSize();
89 }
90 else
91 {
92 dist = i_offset + 1.0f;
93 size = owner->GetObjectSize();
94 }
95
96 if (i_target->IsWithinDistInMap(owner, dist))
97 return;
98
99 // to at i_offset distance from target and i_angle from target facing
100 i_target->GetClosePoint(x, y, z, size, i_offset, i_angle);
101 }
102 }
103 else
104 {
105 // the destination has not changed, we just need to refresh the path (usually speed change)
106 G3D::Vector3 end = i_path->GetEndPosition();
107 x = end.x;
108 y = end.y;
109 z = end.z;
110 }
111
112 if (!i_path)
113 i_path = new PathGenerator(owner);
114
115 // allow pets to use shortcut if no path found when following their master
116 bool forceDest = (owner->GetTypeId() == TypeID::TYPEID_UNIT && owner->ToCreature()->IsPet()
117 && owner->HasUnitState(UNIT_STATE_FOLLOW));
118
119 bool result = i_path->CalculatePath(x, y, z, forceDest);
120 if (!result || (i_path->GetPathType() & PATHFIND_NOPATH))
121 {
122 // Cant reach target
123 i_recalculateTravel = true;
124 return;
125 }
126
127 D::_addUnitStateMove(owner);
128 i_targetReached = false;
129 i_recalculateTravel = false;
130 owner->AddUnitState(UNIT_STATE_CHASE);
131
132 Movement::MoveSplineInit init(owner);
133 init.MovebyPath(i_path->GetPath());
134 init.SetWalk(((D*)this)->EnableWalking());
135 // Using the same condition for facing target as the one that is used for SetInFront on movement end
136 // - applies to ChaseMovementGenerator mostly
137 if (i_angle == 0.f)
138 init.SetFacing(i_target.getTarget());
139
140 init.Launch();
141}
142
143template<class T, typename D>
145{
146 if (!i_target.isValid() || !i_target->IsInWorld())
147 return false;
148
149 if (!owner || !owner->IsAlive())
150 return false;
151
152 if (owner->HasUnitState(UNIT_STATE_NOT_MOVE))
153 {
154 D::_clearUnitStateMove(owner);
155 return true;
156 }
157
158 // prevent movement while casting spells with cast time or channel time
159 if (owner->HasUnitState(UNIT_STATE_CASTING))
160 {
161 if (!owner->IsStopped())
162 owner->StopMoving();
163 return true;
164 }
165
166 // prevent crash after creature killed pet
167 if (static_cast<D*>(this)->_lostTarget(owner))
168 {
169 D::_clearUnitStateMove(owner);
170 return true;
171 }
172
173 bool targetMoved = false;
174 i_recheckDistance.Update(time_diff);
175 if (i_recheckDistance.Passed())
176 {
177 i_recheckDistance.Reset(100);
178 //More distance let have better performance, less distance let have more sensitive reaction at target move.
179 float allowed_dist = owner->GetCombatReach() + sWorld->getRate(Rates::RATE_TARGET_POS_RECALCULATION_RANGE);
180 G3D::Vector3 dest = owner->movespline->FinalDestination();
181
182 if (owner->GetTypeId() == TypeID::TYPEID_UNIT && owner->ToCreature()->CanFly())
183 targetMoved = !i_target->IsWithinDist3d(dest.x, dest.y, dest.z, allowed_dist);
184 else
185 targetMoved = !i_target->IsWithinDist2d(dest.x, dest.y, allowed_dist);
186 }
187
188 if (i_recalculateTravel || targetMoved)
189 _setTargetLocation(owner, targetMoved);
190
191 if (owner->movespline->Finalized())
192 {
193 static_cast<D*>(this)->MovementInform(owner);
194 if (i_angle == 0.f && !owner->HasInArc(0.01f, i_target.getTarget()))
195 owner->SetInFront(i_target.getTarget());
196
197 if (!i_targetReached)
198 {
199 i_targetReached = true;
200 static_cast<D*>(this)->_reachTarget(owner);
201 }
202 }
203
204 return true;
205}
206
207//-----------------------------------------------//
208template<class T>
210{
211 if (owner->IsWithinMeleeRange(this->i_target.getTarget()))
212 owner->Attack(this->i_target.getTarget(), true);
213}
214
215template<>
221
222template<>
229
230template<class T>
232{
233 owner->ClearUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE);
234}
235
236template<class T>
238{
239 DoInitialize(owner);
240}
241
242template<class T>
244
245template<>
247{
248 // Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
249 if (unit->AI())
250 unit->AI()->MovementInform(CHASE_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
251}
252
253//-----------------------------------------------//
254template<>
256{
257 return i_target.isValid() && i_target->IsWalking();
258}
259
260template<>
262{
263 return false;
264}
265
266template<>
268{
269 // nothing to do for Player
270}
271
272template<>
274{
275 // pet only sync speed with owner
277 if (!owner->IsPet() || !owner->IsInWorld() || !i_target.isValid() || i_target->GetGUID() != owner->GetOwnerGUID())
278 return;
279
280 owner->UpdateSpeed(MOVE_RUN, true);
281 owner->UpdateSpeed(MOVE_WALK, true);
282 owner->UpdateSpeed(MOVE_SWIM, true);
283}
284
285template<>
292
293template<>
300
301template<class T>
303{
304 owner->ClearUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE);
305 _updateSpeed(owner);
306}
307
308template<class T>
310{
311 DoInitialize(owner);
312}
313
314template<class T>
316
317template<>
319{
320 // Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
321 if (unit->AI())
322 unit->AI()->MovementInform(FOLLOW_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
323}
324
325//-----------------------------------------------//
334
342
std::uint32_t uint32
Definition Define.h:77
@ CHASE_MOTION_TYPE
@ FOLLOW_MOTION_TYPE
@ TYPEID_PLAYER
Definition Object.h:55
@ TYPEID_UNIT
Definition Object.h:54
@ PATHFIND_NOPATH
@ UNIT_STATE_NOT_MOVE
Definition Unit.h:549
@ UNIT_STATE_CHASE
Definition Unit.h:517
@ UNIT_STATE_CHASE_MOVE
Definition Unit.h:537
@ UNIT_STATE_FOLLOW
Definition Unit.h:521
@ UNIT_STATE_FOLLOW_MOVE
Definition Unit.h:538
@ UNIT_STATE_CASTING
Definition Unit.h:527
@ MOVE_SWIM
Definition Unit.h:558
@ MOVE_RUN
Definition Unit.h:556
@ MOVE_WALK
Definition Unit.h:555
virtual void MovementInform(uint32, uint32)
Definition CreatureAI.h:118
CreatureAI * AI() const
Definition Creature.h:483
bool EnableWalking() const
void _updateSpeed(T *owner)
bool IsInWorld() const
Definition Object.h:114
void _setTargetLocation(T *owner, bool updateDestination)
bool IsPet() const
Definition Unit.h:1511
void AddUnitState(uint32 f)
Definition Unit.h:1481
bool SetWalk(bool enable)
Definition Unit.cpp:9137
void UpdateSpeed(UnitMoveType mtype, bool forced)
Definition Unit.cpp:4173
uint64 GetOwnerGUID() const
Definition Unit.h:2050
#define sWorld
Definition World.h:910
@ RATE_TARGET_POS_RECALCULATION_RANGE
Definition World.h:433
bool ShouldMoveTransportPetToFollowOffset(float currentX, float currentY, float currentZ, float desiredX, float desiredY, float desiredZ, float tolerance)
PassengerOffset CalculateFollowerPosition(float ownerX, float ownerY, float ownerZ, float ownerO, float ownerObjectSize, float petObjectSize, float followDistance, float followAngle)
bool ShouldUseTransportLocalPetFollow(bool followerIsPet, bool targetIsOwner, bool followerHasTransport, bool targetOnSameTransport, bool hasFollowOffset)