TrinityCore
FlightPathMovementGenerator.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 "DB2Stores.h"
20#include "GameEventSender.h"
21#include "Log.h"
22#include "Map.h"
23#include "MovementDefines.h"
24#include "MoveSpline.h"
25#include "MoveSplineInit.h"
26#include "ObjectMgr.h"
27#include "Player.h"
28#include <sstream>
29
30#define FLIGHT_TRAVEL_UPDATE 100
31#define TIMEDIFF_NEXT_WP 250
32#define SKIP_SPLINE_POINT_DISTANCE_SQ (40.f * 40.f)
33#define PLAYER_FLIGHT_SPEED 32.0f
34
36{
37 _currentNode = 0;
38 _endGridX = 0.0f;
39 _endGridY = 0.0f;
40 _endMapId = 0;
42
47}
48
50{
51 return FLIGHT_MOTION_TYPE;
52}
53
54bool FlightPathMovementGenerator::GetResetPosition(Unit* /*owner*/, float& x, float& y, float& z)
55{
57 x = node->Loc.X;
58 y = node->Loc.Y;
59 z = node->Loc.Z;
60 return true;
61}
62
64{
67
68 DoReset(owner);
70}
71
73{
75
76 owner->CombatStopWithPets();
78
79 uint32 end = GetPathAtMapEnd();
80 uint32 currentNodeId = GetCurrentNode();
81
82 if (currentNodeId == end)
83 {
84 TC_LOG_DEBUG("movement.flightpath", "FlightPathMovementGenerator::DoReset: trying to start a flypath from the end point. {}", owner->GetDebugInfo());
85 return;
86 }
87
88 Movement::MoveSplineInit init(owner);
89 // Providing a starting vertex since the taxi paths do not provide such
90 init.Path().push_back(G3D::Vector3(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ()));
91 for (uint32 i = currentNodeId; i != end; ++i)
92 {
93 G3D::Vector3 vertice(_path[i]->Loc.X, _path[i]->Loc.Y, _path[i]->Loc.Z);
94 init.Path().push_back(vertice);
95 }
97 init.SetFly();
98 init.SetSmooth();
99 init.SetUncompressed();
100 init.SetWalk(true);
102 init.Launch();
103}
104
106{
107 if (!owner)
108 return false;
109
110 // skipping the first spline path point because it's our starting point and not a taxi path point
111 uint32 pointId = owner->movespline->currentPathIdx() <= 0 ? 0 : owner->movespline->currentPathIdx() - 1;
112 if (pointId > _currentNode && _currentNode < _path.size() - 1)
113 {
114 bool departureEvent = true;
115 do
116 {
117 ASSERT(_currentNode < _path.size(), "Point Id: %u\n%s", pointId, owner->GetDebugInfo().c_str());
118
119 DoEventIfAny(owner, _path[_currentNode], departureEvent);
120 while (!_pointsForPathSwitch.empty() && _pointsForPathSwitch.front().PathIndex <= _currentNode)
121 {
122 _pointsForPathSwitch.pop_front();
124 if (!_pointsForPathSwitch.empty())
125 {
127 owner->ModifyMoney(-_pointsForPathSwitch.front().Cost);
128 }
129 }
130
131 if (pointId == _currentNode)
132 break;
133
135 PreloadEndGrid(owner);
136
137 _currentNode += departureEvent ? 1 : 0;
138 departureEvent = !departureEvent;
139 } while (_currentNode < _path.size() - 1);
140 }
141
142 if (_currentNode >= (_path.size() - 1))
143 {
145 return false;
146 }
147 return true;
148}
149
151{
153}
154
155void FlightPathMovementGenerator::DoFinalize(Player* owner, bool active, bool/* movementInform*/)
156{
158 if (!active)
159 return;
160
162 owner->Dismount();
164
165 // update z position to ground and orientation for landing point
166 // this prevent cheating with landing point at lags
167 // when client side flight end early in comparison server side
168 owner->StopMoving();
169
170 // When the player reaches the last flight point, teleport to destination taxi node location
171 if (!_path.empty() && (_path.size() < 2 || !(_path[_path.size() - 2]->Flags & TAXI_PATH_NODE_FLAG_TELEPORT)))
172 {
173 TaxiPathEntry const* lastPath = sTaxiPathStore.AssertEntry(_path.back()->PathID);
174 if (TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(lastPath->ToTaxiNode))
175 {
176 owner->SetFallInformation(0, node->Pos.Z);
177 owner->TeleportTo(node->ContinentID, node->Pos.X, node->Pos.Y, node->Pos.Z, owner->GetOrientation());
178 }
179 }
180
182}
183
185{
186 if (_currentNode >= _path.size())
187 return _path.size();
188
189 uint32 curMapId = _path[_currentNode]->ContinentID;
190 for (uint32 itr = _currentNode; itr < _path.size(); ++itr)
191 {
192 if (_path[itr]->ContinentID != curMapId)
193 return itr;
194 if (itr > 0 && _path[itr - 1]->Flags & TAXI_PATH_NODE_FLAG_TELEPORT)
195 return itr;
196 }
197
198 return _path.size();
199}
200
202{
203 return p1->ContinentID != p2->ContinentID
204 || std::pow(p1->Loc.X - p2->Loc.X, 2) + std::pow(p1->Loc.Y - p2->Loc.Y, 2) > SKIP_SPLINE_POINT_DISTANCE_SQ
206 || (p2->Flags & TAXI_PATH_NODE_FLAG_STOP && p2->Delay);
207}
208
210{
211 _path.clear();
212 _currentNode = startNode;
213 _pointsForPathSwitch.clear();
214 std::deque<uint32> const& taxi = owner->m_taxi.GetPath();
215 float discount = owner->GetReputationPriceDiscount(owner->m_taxi.GetFlightMasterFactionTemplate());
216 for (uint32 src = 0, dst = 1; dst < taxi.size(); src = dst++)
217 {
218 uint32 path, cost;
219 sObjectMgr->GetTaxiPath(taxi[src], taxi[dst], path, cost);
220 if (path >= sTaxiPathNodesByPath.size())
221 return;
222
223 TaxiPathNodeList const& nodes = sTaxiPathNodesByPath[path];
224 if (!nodes.empty())
225 {
226 TaxiPathNodeEntry const* start = nodes[0];
227 TaxiPathNodeEntry const* end = nodes[nodes.size() - 1];
228 bool passedPreviousSegmentProximityCheck = false;
229 for (uint32 i = 0; i < nodes.size(); ++i)
230 {
231 if (passedPreviousSegmentProximityCheck || !src || _path.empty() || IsNodeIncludedInShortenedPath(_path.back(), nodes[i]))
232 {
233 if ((!src || (IsNodeIncludedInShortenedPath(start, nodes[i]) && i >= 2)) &&
234 (dst == taxi.size() - 1 || (IsNodeIncludedInShortenedPath(end, nodes[i]) && (i < nodes.size() - 1 || _path.empty()))) &&
235 (!(nodes[i]->Flags & TAXI_PATH_NODE_FLAG_TELEPORT) || _path.empty() || !(_path.back()->Flags & TAXI_PATH_NODE_FLAG_TELEPORT))) // skip consecutive teleports, only keep the first one
236 {
237 passedPreviousSegmentProximityCheck = true;
238 _path.push_back(nodes[i]);
239 }
240 }
241 else
242 {
243 _path.pop_back();
244 --_pointsForPathSwitch.back().PathIndex;
245 }
246 }
247 }
248
249 _pointsForPathSwitch.push_back({ uint32(std::max<std::size_t>(_path.size(), 1) - 1), int64(ceil(cost * discount)) });
250 }
251}
252
254{
255 if (_path.empty() || _currentNode >= _path.size())
256 return;
257
258 uint32 map0 = _path[_currentNode]->ContinentID;
259 for (size_t i = _currentNode + 1; i < _path.size(); ++i)
260 {
261 if (_path[i]->ContinentID != map0 || _path[i - 1]->Flags & TAXI_PATH_NODE_FLAG_TELEPORT)
262 {
263 _currentNode = i;
264 return;
265 }
266 }
267}
268
270{
271 ASSERT(node, "%s", owner->GetDebugInfo().c_str());
272
273 if (uint32 eventid = departure ? node->DepartureEventID : node->ArrivalEventID)
274 {
275 TC_LOG_DEBUG("maps.script", "FlightPathMovementGenerator::DoEventIfAny: taxi {} event {} of node {} of path {} for player {}", departure ? "departure" : "arrival", eventid, node->NodeIndex, node->PathID, owner->GetName());
276 GameEvents::Trigger(eventid, owner, owner);
277 }
278}
279
281{
286 uint32 nodeCount = _path.size(); // Number of nodes in path.
287 ASSERT(nodeCount, "FlightPathMovementGenerator::InitEndGridInfo() called with empty _path");
288 _endMapId = _path[nodeCount - 1]->ContinentID; // MapId of last node
289 if (nodeCount < 3)
291 else
292 _preloadTargetNode = nodeCount - 3;
293
294 while (_path[_preloadTargetNode]->ContinentID != _endMapId)
296
297 _endGridX = _path[nodeCount - 1]->Loc.X;
298 _endGridY = _path[nodeCount - 1]->Loc.Y;
299}
300
302{
303 // Used to preload the final grid where the flightmaster is
304 Map* endMap = owner->GetMap();
305
306 // Load the grid
307 if (endMap)
308 {
309 TC_LOG_DEBUG("movement.flightpath", "FlightPathMovementGenerator::PreloadEndGrid: preloading grid ({}, {}) for map {} at node index {}/{}", _endGridX, _endGridY, _endMapId, _preloadTargetNode, uint32(_path.size() - 1));
310 endMap->LoadGrid(_endGridX, _endGridY);
311 }
312 else
313 TC_LOG_DEBUG("movement.flightpath", "FlightPathMovementGenerator::PreloadEndGrid: unable to determine map to preload flightmaster grid");
314}
315
317{
318 if (index >= _path.size())
319 return 0;
320
321 return _path[index]->PathID;
322}
323
325{
326 std::stringstream sstr;
327 sstr << std::boolalpha
330 << "Start Path Id: " << GetPathId(0)
331 << " Path Size: " << _path.size()
332 << " HasArrived: " << HasArrived()
333 << " End Grid X: " << _endGridX
334 << " End Grid Y: " << _endGridY
335 << " End Map Id: " << _endMapId
336 << " Preloaded Target Node: " << _preloadTargetNode;
337 return sstr.str();
338}
DB2Storage< TaxiNodesEntry > sTaxiNodesStore("TaxiNodes.db2", &TaxiNodesLoadInfo::Instance)
TaxiPathNodesByPath sTaxiPathNodesByPath
Definition: DB2Stores.cpp:383
DB2Storage< TaxiPathEntry > sTaxiPathStore("TaxiPath.db2", &TaxiPathLoadInfo::Instance)
std::vector< TaxiPathNodeEntry const * > TaxiPathNodeList
Definition: DB2Stores.h:332
@ TAXI_PATH_NODE_FLAG_TELEPORT
Definition: DBCEnums.h:2152
@ TAXI_PATH_NODE_FLAG_STOP
Definition: DBCEnums.h:2153
int64_t int64
Definition: Define.h:137
uint32_t uint32
Definition: Define.h:142
#define ASSERT
Definition: Errors.h:68
#define PLAYER_FLIGHT_SPEED
bool IsNodeIncludedInShortenedPath(TaxiPathNodeEntry const *p1, TaxiPathNodeEntry const *p2)
#define SKIP_SPLINE_POINT_DISTANCE_SQ
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
@ MOTION_MODE_DEFAULT
@ MOTION_PRIORITY_HIGHEST
MovementGeneratorType
@ FLIGHT_MOTION_TYPE
@ MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING
@ MOVEMENTGENERATOR_FLAG_DEACTIVATED
@ MOVEMENTGENERATOR_FLAG_FINALIZED
@ MOVEMENTGENERATOR_FLAG_INFORM_ENABLED
@ MOVEMENTGENERATOR_FLAG_INITIALIZED
#define sObjectMgr
Definition: ObjectMgr.h:1946
@ PLAYER_FLAGS_TAXI_BENCHMARK
Definition: Player.h:445
@ UNIT_FLAG_ON_TAXI
Definition: UnitDefines.h:164
@ UNIT_FLAG_REMOVE_CLIENT_CONTROL
Definition: UnitDefines.h:146
@ UNIT_STATE_IN_FLIGHT
Definition: Unit.h:263
float _endGridY
Y coord of last node location.
bool GetResetPosition(Unit *owner, float &x, float &y, float &z) override
uint32 _preloadTargetNode
node index where preloading starts
std::string GetDebugInfo() const override
void DoEventIfAny(Player *owner, TaxiPathNodeEntry const *node, bool departure)
MovementGeneratorType GetMovementGeneratorType() const override
void LoadPath(Player *owner, uint32 startNode=0)
float _endGridX
X coord of last node location.
std::deque< TaxiNodeChangeInfo > _pointsForPathSwitch
node indexes and costs where TaxiPath changes
uint32 _endMapId
map Id of last node location
Definition: Map.h:189
void LoadGrid(float x, float y)
Definition: Map.cpp:405
void AddFlag(uint16 const flag)
void RemoveFlag(uint16 const flag)
virtual std::string GetDebugInfo() const
void SetWalk(bool enable)
void SetFirstPointId(int32 pointId)
void SetVelocity(float velocity)
virtual std::string GetDebugInfo() const
std::deque< uint32 > const & GetPath() const
Definition: PlayerTaxi.h:81
FactionTemplateEntry const * GetFlightMasterFactionTemplate() const
Definition: PlayerTaxi.cpp:240
uint32 NextTaxiDestination()
Definition: PlayerTaxi.h:75
void ClearTaxiDestinations()
Definition: PlayerTaxi.h:70
bool ModifyMoney(int64 amount, bool sendError=true)
Definition: Player.cpp:24098
void RemovePlayerFlag(PlayerFlags flags)
Definition: Player.h:2739
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={})
Definition: Player.cpp:1250
float GetReputationPriceDiscount(Creature const *creature) const
Definition: Player.cpp:25133
void SetFallInformation(uint32 time, float z)
Definition: Player.cpp:26672
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition: Player.cpp:26767
PlayerTaxi m_taxi
Definition: Player.h:1166
std::string GetDebugInfo() const override
Definition: Player.cpp:30123
Definition: Unit.h:627
void Dismount()
Definition: Unit.cpp:7920
void StopMoving()
Definition: Unit.cpp:10049
std::unique_ptr< Movement::MoveSpline > movespline
Definition: Unit.h:1766
void SetUnitFlag(UnitFlags flags)
Definition: Unit.h:833
void RemoveUnitFlag(UnitFlags flags)
Definition: Unit.h:834
void CombatStopWithPets(bool includingCast=false)
Definition: Unit.cpp:5855
Map * GetMap() const
Definition: Object.h:624
std::string const & GetName() const
Definition: Object.h:555
TC_GAME_API void Trigger(uint32 gameEventId, WorldObject *source, WorldObject *target)
constexpr float GetPositionX() const
Definition: Position.h:76
constexpr float GetPositionY() const
Definition: Position.h:77
constexpr float GetOrientation() const
Definition: Position.h:79
constexpr float GetPositionZ() const
Definition: Position.h:78
DBCPosition3D Loc