fix(Core/Movement): Improvements to taxi flight movement generator: (#12347)
Changed multi-segment taxi paths to fly nearby flight masters along the way, not directly through them. Taxi cost on multi-segment paths is now charged per segment when it is started. Properly send taxi node status on login, as well as if the taxi master is out of range. Apply reputation discount to all points in multi-segment paths. Properly clean up list of taxi destinations upon arrival at final node. Teleport players to the destination taxi node location instead of their current ground position. Don't start a spline with just 1 point in FlightPathMovementGenerator Source: TrinityCore.
This commit is contained in:
parent
7f9ea035de
commit
572a680c16
13 changed files with 347 additions and 189 deletions
|
|
@ -270,35 +270,71 @@ void WaypointMovementGenerator<Creature>::MovementInform(Creature* creature)
|
|||
uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const
|
||||
{
|
||||
if (i_currentNode >= i_path.size())
|
||||
{
|
||||
return i_path.size();
|
||||
}
|
||||
|
||||
uint32 curMapId = i_path[i_currentNode]->mapid;
|
||||
for (uint32 i = i_currentNode; i < i_path.size(); ++i)
|
||||
{
|
||||
if (i_path[i]->mapid != curMapId)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return i_path.size();
|
||||
}
|
||||
|
||||
#define SKIP_SPLINE_POINT_DISTANCE_SQ (40.0f * 40.0f)
|
||||
|
||||
bool IsNodeIncludedInShortenedPath(TaxiPathNodeEntry const* p1, TaxiPathNodeEntry const* p2)
|
||||
{
|
||||
return p1->mapid != p2->mapid || std::pow(p1->x - p2->x, 2) + std::pow(p1->y - p2->y, 2) > SKIP_SPLINE_POINT_DISTANCE_SQ;
|
||||
}
|
||||
|
||||
void FlightPathMovementGenerator::LoadPath(Player* player)
|
||||
{
|
||||
_pointsForPathSwitch.clear();
|
||||
std::vector<uint32> const& taxi = player->m_taxi.GetPath();
|
||||
for (uint32 src = player->m_taxi.GetTaxiSegment(), dst = player->m_taxi.GetTaxiSegment() + 1; dst < taxi.size(); src = dst++)
|
||||
std::deque<uint32> const& taxi = player->m_taxi.GetPath();
|
||||
float discount = player->GetReputationPriceDiscount(player->m_taxi.GetFlightMasterFactionTemplate());
|
||||
for (uint32 src = 0, dst = 1; dst < taxi.size(); src = dst++)
|
||||
{
|
||||
uint32 path, cost;
|
||||
sObjectMgr->GetTaxiPath(taxi[src], taxi[dst], path, cost);
|
||||
if (path > sTaxiPathNodesByPath.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TaxiPathNodeList const& nodes = sTaxiPathNodesByPath[path];
|
||||
if (!nodes.empty())
|
||||
{
|
||||
TaxiPathNodeEntry const* start = nodes[0];
|
||||
TaxiPathNodeEntry const* end = nodes[nodes.size() - 1];
|
||||
bool passedPreviousSegmentProximityCheck = false;
|
||||
for (uint32 i = 0; i < nodes.size(); ++i)
|
||||
i_path.push_back(nodes[i]);
|
||||
{
|
||||
sMapMgr->CreateMap(nodes[i]->mapid, player)->SummonCreature(1, { nodes[i]->x, nodes[i]->y, nodes[i]->z, 0.0f })->SetLevel(i ? i : 1);
|
||||
|
||||
if (passedPreviousSegmentProximityCheck || !src || i_path.empty() || IsNodeIncludedInShortenedPath(i_path[i_path.size() - 1], nodes[i]))
|
||||
{
|
||||
if ((!src || (IsNodeIncludedInShortenedPath(start, nodes[i]) && i >= 2)) &&
|
||||
(dst == taxi.size() - 1 || (IsNodeIncludedInShortenedPath(end, nodes[i]) && i < nodes.size() - 1)))
|
||||
{
|
||||
passedPreviousSegmentProximityCheck = true;
|
||||
i_path.push_back(nodes[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i_path.pop_back();
|
||||
--_pointsForPathSwitch.back().PathIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_pointsForPathSwitch.push_back(uint32(i_path.size() - 1));
|
||||
_pointsForPathSwitch.push_back({ uint32(i_path.size() - 1), int32(ceil(cost * discount)) });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -313,7 +349,8 @@ void FlightPathMovementGenerator::DoFinalize(Player* player)
|
|||
// remove flag to prevent send object build movement packets for flight state and crash (movement generator already not at top of stack)
|
||||
player->ClearUnitState(UNIT_STATE_IN_FLIGHT);
|
||||
|
||||
// xinef: this should be cleaned by CleanupAfterTaxiFlight(); function!
|
||||
uint32 taxiNodeId = player->m_taxi.GetTaxiDestination();
|
||||
player->m_taxi.ClearTaxiDestinations();
|
||||
player->Dismount();
|
||||
player->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
|
||||
|
||||
|
|
@ -324,7 +361,13 @@ void FlightPathMovementGenerator::DoFinalize(Player* player)
|
|||
// this prevent cheating with landing point at lags
|
||||
// when client side flight end early in comparison server side
|
||||
player->StopMoving();
|
||||
player->SetFallInformation(GameTime::GetGameTime().count(), player->GetPositionZ());
|
||||
|
||||
// When the player reaches the last flight point, teleport to destination taxi node location
|
||||
if (TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(taxiNodeId))
|
||||
{
|
||||
player->SetFallInformation(GameTime::GetGameTime().count(), player->GetPositionZ());
|
||||
player->TeleportTo(node->map_id, node->x, node->y, node->z, player->GetOrientation());
|
||||
}
|
||||
}
|
||||
|
||||
player->RemovePlayerFlag(PLAYER_FLAGS_TAXI_BENCHMARK);
|
||||
|
|
@ -334,13 +377,23 @@ void FlightPathMovementGenerator::DoFinalize(Player* player)
|
|||
|
||||
void FlightPathMovementGenerator::DoReset(Player* player)
|
||||
{
|
||||
uint32 end = GetPathAtMapEnd();
|
||||
uint32 currentNodeId = GetCurrentNode();
|
||||
|
||||
if (currentNodeId == end)
|
||||
{
|
||||
LOG_DEBUG("movement.flightpath", "FlightPathMovementGenerator::DoReset: trying to start a flypath from the end point. {}", player->GetGUID().ToString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
player->getHostileRefMgr().setOnlineOfflineState(false);
|
||||
player->AddUnitState(UNIT_STATE_IN_FLIGHT);
|
||||
player->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
|
||||
|
||||
Movement::MoveSplineInit init(player);
|
||||
uint32 end = GetPathAtMapEnd();
|
||||
for (uint32 i = GetCurrentNode(); i < end; ++i)
|
||||
// Providing a starting vertex since the taxi paths do not provide such
|
||||
init.Path().push_back(G3D::Vector3(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()));
|
||||
for (uint32 i = currentNodeId; i != end; ++i)
|
||||
{
|
||||
G3D::Vector3 vertice(i_path[i]->x, i_path[i]->y, i_path[i]->z);
|
||||
init.Path().push_back(vertice);
|
||||
|
|
@ -353,77 +406,40 @@ void FlightPathMovementGenerator::DoReset(Player* player)
|
|||
|
||||
bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/)
|
||||
{
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
// xinef: map was switched
|
||||
if (_mapSwitch)
|
||||
{
|
||||
DoInitialize(player);
|
||||
_mapSwitch = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 pointId = (uint32)player->movespline->currentPathIdx();
|
||||
if (pointId > i_currentNode)
|
||||
// skipping the first spline path point because it's our starting point and not a taxi path point
|
||||
uint32 pointId = player->movespline->currentPathIdx() <= 0 ? 0 : player->movespline->currentPathIdx() - 1;
|
||||
if (pointId > i_currentNode && i_currentNode < i_path.size() - 1)
|
||||
{
|
||||
bool departureEvent = true;
|
||||
do
|
||||
{
|
||||
if (i_currentNode >= i_path.size())
|
||||
{
|
||||
LOG_INFO("misc", "TAXI NODE WAS GREATER THAN PATH SIZE, {}, POINTID: {}, NODESIZE: {}, CURRENT: {}",
|
||||
player->GetGUID().ToString(), pointId, i_path.size(), i_currentNode);
|
||||
player->CleanupAfterTaxiFlight();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (i_path[i_currentNode]->mapid != player->GetMapId())
|
||||
{
|
||||
LOG_INFO("misc", "Player on different map, curmap: {}, pointmap: {}, nodesize: {}, currentnode: {}", player->GetMapId(), i_path[i_currentNode]->mapid, i_path.size(), i_currentNode);
|
||||
player->CleanupAfterTaxiFlight();
|
||||
return false;
|
||||
}
|
||||
ASSERT(i_currentNode < i_path.size(), "Point Id: {}\n{}", pointId, player->GetGUID().ToString().c_str());
|
||||
|
||||
DoEventIfAny(player, i_path[i_currentNode], departureEvent);
|
||||
|
||||
// xinef: erase any previous points
|
||||
uint32 curSize = _pointsForPathSwitch.size();
|
||||
while (!_pointsForPathSwitch.empty() && _pointsForPathSwitch.front() <= i_currentNode)
|
||||
while (!_pointsForPathSwitch.empty() && _pointsForPathSwitch.front().PathIndex <= i_currentNode)
|
||||
{
|
||||
_pointsForPathSwitch.pop_front();
|
||||
|
||||
// xinef: switch destination only once
|
||||
if (curSize != _pointsForPathSwitch.size())
|
||||
player->m_taxi.NextTaxiDestination();
|
||||
if (!_pointsForPathSwitch.empty())
|
||||
{
|
||||
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, _pointsForPathSwitch.front().Cost);
|
||||
player->ModifyMoney(-_pointsForPathSwitch.front().Cost);
|
||||
}
|
||||
}
|
||||
|
||||
if (pointId == i_currentNode)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (i_currentNode == _preloadTargetNode && player->GetMapId() == _endMapId)
|
||||
if (i_currentNode == _preloadTargetNode)
|
||||
{
|
||||
PreloadEndGrid();
|
||||
i_currentNode += (uint32)departureEvent;
|
||||
}
|
||||
|
||||
i_currentNode += departureEvent ? 1 : 0;
|
||||
departureEvent = !departureEvent;
|
||||
|
||||
// xinef: map should be switched, do not rely on client packets QQ
|
||||
if (i_currentNode + 1 < i_path.size() && i_path[i_currentNode + 1]->mapid != player->GetMapId())
|
||||
{
|
||||
++i_currentNode;
|
||||
_mapSwitch = true;
|
||||
player->TeleportTo(i_path[i_currentNode]->mapid, i_path[i_currentNode]->x, i_path[i_currentNode]->y, i_path[i_currentNode]->z, player->GetOrientation(), TELE_TO_NOT_LEAVE_TAXI);
|
||||
return true;
|
||||
}
|
||||
|
||||
// xinef: reached the end
|
||||
if (i_currentNode >= i_path.size() - 1)
|
||||
{
|
||||
player->CleanupAfterTaxiFlight();
|
||||
player->SetFallInformation(GameTime::GetGameTime().count(), player->GetPositionZ());
|
||||
if (player->pvpInfo.IsHostile)
|
||||
player->CastSpell(player, 2479, true);
|
||||
|
||||
return false;
|
||||
}
|
||||
} while (true);
|
||||
} while (i_currentNode < i_path.size() - 1);
|
||||
}
|
||||
|
||||
return i_currentNode < (i_path.size() - 1);
|
||||
|
|
@ -432,7 +448,9 @@ bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/)
|
|||
void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
|
||||
{
|
||||
if (i_path.empty() || i_currentNode >= i_path.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 map0 = i_path[i_currentNode]->mapid;
|
||||
for (size_t i = i_currentNode + 1; i < i_path.size(); ++i)
|
||||
|
|
@ -449,11 +467,20 @@ void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry
|
|||
{
|
||||
if (uint32 eventid = departure ? node->departureEventID : node->arrivalEventID)
|
||||
{
|
||||
LOG_DEBUG("maps.script", "Taxi {} event {} of node {} of path {} for player {}", departure ? "departure" : "arrival", eventid, node->index, node->path, player->GetName());
|
||||
LOG_DEBUG("maps.script", "Taxi {} event {} of node {} of path {} for player {}", departure ? "departure" : "arrival", eventid, node->index, node->path, player->GetName().c_str());
|
||||
player->GetMap()->ScriptsStart(sEventScripts, eventid, player, player);
|
||||
}
|
||||
}
|
||||
|
||||
bool FlightPathMovementGenerator::GetResetPos(Player*, float& x, float& y, float& z)
|
||||
{
|
||||
TaxiPathNodeEntry const* node = i_path[i_currentNode];
|
||||
x = node->x;
|
||||
y = node->y;
|
||||
z = node->z;
|
||||
return true;
|
||||
}
|
||||
|
||||
void FlightPathMovementGenerator::InitEndGridInfo()
|
||||
{
|
||||
/*! Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will
|
||||
|
|
@ -485,11 +512,11 @@ void FlightPathMovementGenerator::PreloadEndGrid()
|
|||
// Load the grid
|
||||
if (endMap)
|
||||
{
|
||||
LOG_DEBUG("movement", "Preloading rid ({}, {}) for map {} at node index {}/{}", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path.size() - 1));
|
||||
LOG_DEBUG("misc", "Preloading grid ({}, {}) for map %u at node index {}/{}", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path.size() - 1));
|
||||
endMap->LoadGrid(_endGridX, _endGridY);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("movement", "Unable to determine map to preload flightmaster grid");
|
||||
LOG_DEBUG("misc", "Unable to determine map to preload flightmaster grid");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue