TrinityCore
Loading...
Searching...
No Matches
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
49
54
55bool FlightPathMovementGenerator::GetResetPosition(Unit* /*owner*/, float& x, float& y, float& z)
56{
58 x = node->Loc.X;
59 y = node->Loc.Y;
60 z = node->Loc.Z;
61 return true;
62}
63
73
75{
77
78 owner->CombatStopWithPets();
80
81 uint32 end = GetPathAtMapEnd();
82 uint32 currentNodeId = GetCurrentNode();
83
84 if (currentNodeId == end)
85 {
86 TC_LOG_DEBUG("movement.flightpath", "FlightPathMovementGenerator::DoReset: trying to start a flypath from the end point. {}", owner->GetDebugInfo());
87 return false;
88 }
89
90 Movement::MoveSplineInit init(owner);
91 init.Path().reserve(end - currentNodeId + 1);
92 // Providing a starting vertex since the taxi paths do not provide such
93 init.Path().emplace_back(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ());
94 for (uint32 i = currentNodeId; i != end; ++i)
95 init.Path().emplace_back(_path[i]->Loc.X, _path[i]->Loc.Y, _path[i]->Loc.Z);
96
98 init.SetFly();
99 init.SetSmooth();
100 init.SetUncompressed();
101 init.SetWalk(true);
102 init.SetVelocity(_speed.value_or(PLAYER_FLIGHT_SPEED));
103 init.Launch();
104 return true;
105}
106
108{
109 if (!owner)
110 return false;
111
112 // skipping the first spline path point because it's our starting point and not a taxi path point
113 uint32 pointId = owner->movespline->currentPathIdx() <= 0 ? 0 : owner->movespline->currentPathIdx() - 1;
114 if (pointId > _currentNode && _currentNode < _path.size() - 1)
115 {
116 bool departureEvent = true;
117 do
118 {
119 ASSERT(_currentNode < _path.size(), "Point Id: %u\n%s", pointId, owner->GetDebugInfo().c_str());
120
121 DoEventIfAny(owner, _path[_currentNode], departureEvent);
122 while (!_pointsForPathSwitch.empty() && _pointsForPathSwitch.front().PathIndex <= _currentNode)
123 {
124 _pointsForPathSwitch.pop_front();
126 if (!_pointsForPathSwitch.empty())
127 {
129 owner->ModifyMoney(-_pointsForPathSwitch.front().Cost);
130 }
131 }
132
133 if (pointId == _currentNode)
134 break;
135
137 PreloadEndGrid(owner);
138
139 _currentNode += departureEvent ? 1 : 0;
140 departureEvent = !departureEvent;
141 } while (_currentNode < _path.size() - 1);
142 }
143
144 if (_currentNode >= (_path.size() - 1))
145 {
147 return false;
148 }
149 return true;
150}
151
156
157void FlightPathMovementGenerator::DoFinalize(Player* owner, bool active, bool movementInform)
158{
160 if (!active)
161 return;
162
164 owner->Dismount();
166
167 // update z position to ground and orientation for landing point
168 // this prevent cheating with landing point at lags
169 // when client side flight end early in comparison server side
170 owner->StopMoving();
171
172 // When the player reaches the last flight point, teleport to destination taxi node location
173 if (!_path.empty() && (_path.size() < 2 || !(_path[_path.size() - 2]->Flags & TAXI_PATH_NODE_FLAG_TELEPORT)))
174 {
175 TaxiPathEntry const* lastPath = sTaxiPathStore.AssertEntry(_path.back()->PathID);
176 if (TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(lastPath->ToTaxiNode))
177 {
178 owner->SetFallInformation(0, node->Pos.Z);
179 owner->TeleportTo(node->ContinentID, node->Pos.X, node->Pos.Y, node->Pos.Z, owner->GetOrientation());
180 }
181 }
182
184
185 if (movementInform)
187}
188
190{
191 if (_currentNode >= _path.size())
192 return _path.size();
193
194 uint32 curMapId = _path[_currentNode]->ContinentID;
195 for (uint32 itr = _currentNode; itr < _path.size(); ++itr)
196 {
197 if (_path[itr]->ContinentID != curMapId)
198 return itr;
199 if (itr > 0 && _path[itr - 1]->Flags & TAXI_PATH_NODE_FLAG_TELEPORT)
200 return itr;
201 }
202
203 return _path.size();
204}
205
207{
208 return p1->ContinentID != p2->ContinentID
209 || std::pow(p1->Loc.X - p2->Loc.X, 2) + std::pow(p1->Loc.Y - p2->Loc.Y, 2) > SKIP_SPLINE_POINT_DISTANCE_SQ
211 || (p2->Flags & TAXI_PATH_NODE_FLAG_STOP && p2->Delay);
212}
213
215{
216 _path.clear();
217 _currentNode = startNode;
218 _pointsForPathSwitch.clear();
219 std::deque<uint32> const& taxi = owner->m_taxi.GetPath();
220 float discount = owner->GetReputationPriceDiscount(owner->m_taxi.GetFlightMasterFactionTemplate());
221 for (uint32 src = 0, dst = 1; dst < taxi.size(); src = dst++)
222 {
223 uint32 path, cost;
224 sObjectMgr->GetTaxiPath(taxi[src], taxi[dst], path, cost);
225 if (path >= sTaxiPathNodesByPath.size())
226 return;
227
228 TaxiPathNodeList const& nodes = sTaxiPathNodesByPath[path];
229 if (!nodes.empty())
230 {
231 TaxiPathNodeEntry const* start = nodes[0];
232 TaxiPathNodeEntry const* end = nodes[nodes.size() - 1];
233 bool passedPreviousSegmentProximityCheck = false;
234 for (uint32 i = 0; i < nodes.size(); ++i)
235 {
236 if (passedPreviousSegmentProximityCheck || !src || _path.empty() || IsNodeIncludedInShortenedPath(_path.back(), nodes[i]))
237 {
238 if ((!src || (IsNodeIncludedInShortenedPath(start, nodes[i]) && i >= 2)) &&
239 (dst == taxi.size() - 1 || (IsNodeIncludedInShortenedPath(end, nodes[i]) && (i < nodes.size() - 1 || _path.empty()))) &&
240 (!(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
241 {
242 passedPreviousSegmentProximityCheck = true;
243 _path.push_back(nodes[i]);
244 }
245 }
246 else
247 {
248 _path.pop_back();
249 --_pointsForPathSwitch.back().PathIndex;
250 }
251 }
252 }
253
254 _pointsForPathSwitch.push_back({ uint32(std::max<std::size_t>(_path.size(), 1) - 1), int64(ceil(cost * discount)) });
255 }
256}
257
259{
260 if (_path.empty() || _currentNode >= _path.size())
261 return;
262
264 for (size_t i = _currentNode + 1; i < _path.size(); ++i)
265 {
266 if (_path[i]->ContinentID != map0 || _path[i - 1]->Flags & TAXI_PATH_NODE_FLAG_TELEPORT)
267 {
268 _currentNode = i;
269 return;
270 }
271 }
272}
273
275{
276 ASSERT(node, "%s", owner->GetDebugInfo().c_str());
277
278 if (uint32 eventid = departure ? node->DepartureEventID : node->ArrivalEventID)
279 {
280 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());
281 GameEvents::Trigger(eventid, owner, owner);
282 }
283}
284
286{
291 uint32 nodeCount = _path.size(); // Number of nodes in path.
292 ASSERT(nodeCount, "FlightPathMovementGenerator::InitEndGridInfo() called with empty _path");
293 _endMapId = _path[nodeCount - 1]->ContinentID; // MapId of last node
294 if (nodeCount < 3)
296 else
297 _preloadTargetNode = nodeCount - 3;
298
299 while (_path[_preloadTargetNode]->ContinentID != _endMapId)
301
302 _endGridX = _path[nodeCount - 1]->Loc.X;
303 _endGridY = _path[nodeCount - 1]->Loc.Y;
304}
305
307{
308 // Used to preload the final grid where the flightmaster is
309 Map* endMap = owner->GetMap();
310
311 // Load the grid
312 if (endMap)
313 {
314 TC_LOG_DEBUG("movement.flightpath", "FlightPathMovementGenerator::PreloadEndGrid: preloading grid ({}, {}) for map {} at node index {}/{}", _endGridX, _endGridY, _endMapId, _preloadTargetNode, uint32(_path.size() - 1));
315 endMap->LoadGrid(_endGridX, _endGridY);
316 }
317 else
318 TC_LOG_DEBUG("movement.flightpath", "FlightPathMovementGenerator::PreloadEndGrid: unable to determine map to preload flightmaster grid");
319}
320
322{
323 if (index >= _path.size())
324 return 0;
325
326 return _path[index]->PathID;
327}
328
330{
331 std::stringstream sstr;
332 sstr << std::boolalpha
335 << "Start Path Id: " << GetPathId(0)
336 << " Path Size: " << _path.size()
337 << " HasArrived: " << HasArrived()
338 << " End Grid X: " << _endGridX
339 << " End Grid Y: " << _endGridY
340 << " End Map Id: " << _endMapId
341 << " Preloaded Target Node: " << _preloadTargetNode;
342 return sstr.str();
343}
DB2Storage< TaxiNodesEntry > sTaxiNodesStore("TaxiNodes.db2", &TaxiNodesLoadInfo::Instance)
TaxiPathNodesByPath sTaxiPathNodesByPath
DB2Storage< TaxiPathEntry > sTaxiPathStore("TaxiPath.db2", &TaxiPathLoadInfo::Instance)
std::vector< TaxiPathNodeEntry const * > TaxiPathNodeList
Definition DB2Stores.h:374
@ TAXI_PATH_NODE_FLAG_TELEPORT
Definition DBCEnums.h:2836
@ TAXI_PATH_NODE_FLAG_STOP
Definition DBCEnums.h:2837
int64_t int64
Definition Define.h:149
uint32_t uint32
Definition Define.h:154
#define ASSERT
Definition Errors.h:72
#define PLAYER_FLIGHT_SPEED
bool IsNodeIncludedInShortenedPath(TaxiPathNodeEntry const *p1, TaxiPathNodeEntry const *p2)
#define SKIP_SPLINE_POINT_DISTANCE_SQ
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:173
@ 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:1873
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
@ PLAYER_FLAGS_TAXI_BENCHMARK
Definition Player.h:529
@ UNIT_FLAG_ON_TAXI
@ UNIT_FLAG_REMOVE_CLIENT_CONTROL
@ UNIT_STATE_IN_FLIGHT
Definition Unit.h:283
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
FlightPathMovementGenerator(Optional< float > speed, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult)
Definition Map.h:227
void LoadGrid(float x, float y)
Definition Map.cpp:370
void SetScriptResult(MovementStopReason reason)
void AddFlag(uint16 const flag)
Scripting::v2::ActionResultSetter< MovementStopReason > ScriptResult
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
uint32 GetCurrentNode() const
std::deque< uint32 > const & GetPath() const
Definition PlayerTaxi.h:86
FactionTemplateEntry const * GetFlightMasterFactionTemplate() const
uint32 NextTaxiDestination()
Definition PlayerTaxi.h:80
void ClearTaxiDestinations()
Definition PlayerTaxi.h:75
bool ModifyMoney(int64 amount, bool sendError=true)
Definition Player.cpp:24800
void RemovePlayerFlag(PlayerFlags flags)
Definition Player.h:2897
float GetReputationPriceDiscount(Creature const *creature) const
Definition Player.cpp:25808
void SetFallInformation(uint32 time, float z)
Definition Player.cpp:27437
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition Player.cpp:27532
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={}, uint32 teleportSpellId=0)
Definition Player.cpp:1181
PlayerTaxi m_taxi
Definition Player.h:1277
std::string GetDebugInfo() const override
Definition Player.cpp:31388
Definition Unit.h:647
void StopMoving(bool force=false)
Definition Unit.cpp:10753
void Dismount()
Definition Unit.cpp:8336
std::unique_ptr< Movement::MoveSpline > movespline
Definition Unit.h:1854
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:861
void RemoveUnitFlag(UnitFlags flags)
Definition Unit.h:862
void CombatStopWithPets(bool includingCast=false)
Definition Unit.cpp:6059
Map * GetMap() const
Definition Object.h:411
std::string const & GetName() const
Definition Object.h:342
TC_GAME_API void Trigger(uint32 gameEventId, WorldObject *source, WorldObject *target)
constexpr float GetPositionX() const
Definition Position.h:87
constexpr float GetPositionY() const
Definition Position.h:88
constexpr float GetOrientation() const
Definition Position.h:90
constexpr float GetPositionZ() const
Definition Position.h:89
DBCPosition3D Loc