mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-22 21:26:23 +00:00
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.
303 lines
9.8 KiB
C++
303 lines
9.8 KiB
C++
/*
|
|
* This file is part of the AzerothCore 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 Affero General Public License as published by the
|
|
* Free Software Foundation; either version 3 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 Affero 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/>.
|
|
*/
|
|
|
|
#include "GameTime.h"
|
|
#include "ObjectMgr.h"
|
|
#include "Opcodes.h"
|
|
#include "Player.h"
|
|
#include "ScriptMgr.h"
|
|
#include "UpdateMask.h"
|
|
#include "WaypointMovementGenerator.h"
|
|
#include "WorldPacket.h"
|
|
#include "WorldSession.h"
|
|
|
|
void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPacket& recvData)
|
|
{
|
|
LOG_DEBUG("network", "WORLD: Received CMSG_TAXINODE_STATUS_QUERY");
|
|
|
|
ObjectGuid guid;
|
|
|
|
recvData >> guid;
|
|
SendTaxiStatus(guid);
|
|
}
|
|
|
|
void WorldSession::SendTaxiStatus(ObjectGuid guid)
|
|
{
|
|
Player* const player = GetPlayer();
|
|
Creature* unit = ObjectAccessor::GetCreature(*player, guid);
|
|
if (!unit || unit->IsHostileTo(player) || !unit->HasNpcFlag(UNIT_NPC_FLAG_FLIGHTMASTER))
|
|
{
|
|
LOG_DEBUG("network", "WorldSession::SendTaxiStatus - Unit ({}) not found.", guid.ToString());
|
|
return;
|
|
}
|
|
|
|
// find taxi node
|
|
uint32 nearest = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), player->GetTeamId());
|
|
if (!nearest)
|
|
{
|
|
return;
|
|
}
|
|
|
|
WorldPacket data(SMSG_TAXINODE_STATUS, 9);
|
|
data << guid;
|
|
data << uint8(player->m_taxi.IsTaximaskNodeKnown(nearest) ? 1 : 0);
|
|
SendPacket(&data);
|
|
LOG_DEBUG("network", "WORLD: Sent SMSG_TAXINODE_STATUS");
|
|
}
|
|
|
|
void WorldSession::HandleTaxiQueryAvailableNodes(WorldPacket& recvData)
|
|
{
|
|
LOG_DEBUG("network", "WORLD: Received CMSG_TAXIQUERYAVAILABLENODES");
|
|
|
|
ObjectGuid guid;
|
|
recvData >> guid;
|
|
|
|
// cheating checks
|
|
Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER);
|
|
if (!unit)
|
|
{
|
|
LOG_DEBUG("network", "WORLD: HandleTaxiQueryAvailableNodes - Unit ({}) not found or you can't interact with him.", guid.ToString());
|
|
return;
|
|
}
|
|
|
|
// remove fake death
|
|
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
|
|
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
|
|
|
// unknown taxi node case
|
|
if (SendLearnNewTaxiNode(unit))
|
|
return;
|
|
|
|
// known taxi node case
|
|
SendTaxiMenu(unit);
|
|
}
|
|
|
|
void WorldSession::SendTaxiMenu(Creature* unit)
|
|
{
|
|
// find current node
|
|
uint32 curloc = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeamId());
|
|
|
|
if (curloc == 0)
|
|
return;
|
|
|
|
bool lastTaxiCheaterState = GetPlayer()->isTaxiCheater();
|
|
if (unit->GetEntry() == 29480) GetPlayer()->SetTaxiCheater(true); // Grimwing in Ebon Hold, special case. NOTE: Not perfect, Zul'Aman should not be included according to WoWhead, and I think taxicheat includes it.
|
|
|
|
LOG_DEBUG("network", "WORLD: CMSG_TAXINODE_STATUS_QUERY {} ", curloc);
|
|
|
|
WorldPacket data(SMSG_SHOWTAXINODES, (4 + 8 + 4 + 8 * 4));
|
|
data << uint32(1);
|
|
data << unit->GetGUID();
|
|
data << uint32(curloc);
|
|
GetPlayer()->m_taxi.AppendTaximaskTo(data, GetPlayer()->isTaxiCheater());
|
|
SendPacket(&data);
|
|
|
|
LOG_DEBUG("network", "WORLD: Sent SMSG_SHOWTAXINODES");
|
|
|
|
GetPlayer()->SetTaxiCheater(lastTaxiCheaterState);
|
|
}
|
|
|
|
void WorldSession::SendDoFlight(uint32 mountDisplayId, uint32 path, uint32 pathNode)
|
|
{
|
|
// remove fake death
|
|
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
|
|
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
|
|
|
while (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE)
|
|
GetPlayer()->GetMotionMaster()->MovementExpired(false);
|
|
|
|
if (mountDisplayId)
|
|
GetPlayer()->Mount(mountDisplayId);
|
|
|
|
if (Creature* critter = ObjectAccessor::GetCreature(*GetPlayer(), GetPlayer()->GetCritterGUID()))
|
|
{
|
|
critter->DespawnOrUnsummon();
|
|
}
|
|
|
|
GetPlayer()->GetMotionMaster()->MoveTaxiFlight(path, pathNode);
|
|
|
|
sScriptMgr->AnticheatSetSkipOnePacketForASH(GetPlayer(), true);
|
|
}
|
|
|
|
bool WorldSession::SendLearnNewTaxiNode(Creature* unit)
|
|
{
|
|
// find current node
|
|
uint32 curloc = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeamId());
|
|
|
|
if (curloc == 0)
|
|
return true; // `true` send to avoid WorldSession::SendTaxiMenu call with one more curlock seartch with same false result.
|
|
|
|
if (GetPlayer()->m_taxi.SetTaximaskNode(curloc))
|
|
{
|
|
WorldPacket msg(SMSG_NEW_TAXI_PATH, 0);
|
|
SendPacket(&msg);
|
|
|
|
WorldPacket update(SMSG_TAXINODE_STATUS, 9);
|
|
update << unit->GetGUID();
|
|
update << uint8(1);
|
|
SendPacket(&update);
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void WorldSession::SendDiscoverNewTaxiNode(uint32 nodeid)
|
|
{
|
|
if (GetPlayer()->m_taxi.SetTaximaskNode(nodeid))
|
|
{
|
|
WorldPacket msg(SMSG_NEW_TAXI_PATH, 0);
|
|
SendPacket(&msg);
|
|
}
|
|
}
|
|
|
|
void WorldSession::HandleActivateTaxiExpressOpcode(WorldPacket& recvData)
|
|
{
|
|
LOG_DEBUG("network", "WORLD: Received CMSG_ACTIVATETAXIEXPRESS");
|
|
|
|
ObjectGuid guid;
|
|
uint32 node_count;
|
|
|
|
recvData >> guid >> node_count;
|
|
|
|
Creature* npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER);
|
|
if (!npc)
|
|
{
|
|
LOG_DEBUG("network", "WORLD: HandleActivateTaxiExpressOpcode - Unit ({}) not found or you can't interact with it.", guid.ToString());
|
|
SendActivateTaxiReply(ERR_TAXITOOFARAWAY);
|
|
return;
|
|
}
|
|
std::vector<uint32> nodes;
|
|
|
|
for (uint32 i = 0; i < node_count; ++i)
|
|
{
|
|
uint32 node;
|
|
recvData >> node;
|
|
|
|
if (!GetPlayer()->m_taxi.IsTaximaskNodeKnown(node) && !GetPlayer()->isTaxiCheater())
|
|
{
|
|
SendActivateTaxiReply(ERR_TAXINOTVISITED);
|
|
recvData.rfinish();
|
|
return;
|
|
}
|
|
|
|
nodes.push_back(node);
|
|
}
|
|
|
|
if (nodes.empty())
|
|
return;
|
|
|
|
LOG_DEBUG("network", "WORLD: Received CMSG_ACTIVATETAXIEXPRESS from {} to {}", nodes.front(), nodes.back());
|
|
|
|
GetPlayer()->ActivateTaxiPathTo(nodes, npc, 0);
|
|
}
|
|
|
|
void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData)
|
|
{
|
|
LOG_DEBUG("network", "WORLD: Received CMSG_MOVE_SPLINE_DONE");
|
|
|
|
ObjectGuid guid; // used only for proper packet read
|
|
recvData >> guid.ReadAsPacked();
|
|
|
|
MovementInfo movementInfo; // used only for proper packet read
|
|
movementInfo.guid = guid;
|
|
ReadMovementInfo(recvData, &movementInfo);
|
|
|
|
recvData.read_skip<uint32>(); // spline id
|
|
|
|
// in taxi flight packet received in 2 case:
|
|
// 1) end taxi path in far (multi-node) flight
|
|
// 2) switch from one map to other in case multim-map taxi path
|
|
// we need process only (1)
|
|
|
|
uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination();
|
|
if (curDest)
|
|
{
|
|
TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest);
|
|
|
|
// far teleport case
|
|
if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId() && GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE)
|
|
{
|
|
if (FlightPathMovementGenerator* flight = dynamic_cast<FlightPathMovementGenerator*>(GetPlayer()->GetMotionMaster()->top()))
|
|
{
|
|
// short preparations to continue flight
|
|
flight->SetCurrentNodeAfterTeleport();
|
|
TaxiPathNodeEntry const* node = flight->GetPath()[flight->GetCurrentNode()];
|
|
flight->SkipCurrentNode();
|
|
|
|
GetPlayer()->TeleportTo(curDestNode->map_id, node->x, node->y, node->z, GetPlayer()->GetOrientation(), TELE_TO_NOT_LEAVE_TAXI);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// at this point only 1 node is expected (final destination)
|
|
if (GetPlayer()->m_taxi.GetPath().size() != 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GetPlayer()->CleanupAfterTaxiFlight();
|
|
GetPlayer()->SetFallInformation(GameTime::GetGameTime().count(), GetPlayer()->GetPositionZ());
|
|
if (GetPlayer()->pvpInfo.IsHostile)
|
|
{
|
|
GetPlayer()->CastSpell(GetPlayer(), 2479, true);
|
|
}
|
|
}
|
|
|
|
void WorldSession::HandleActivateTaxiOpcode(WorldPacket& recvData)
|
|
{
|
|
LOG_DEBUG("network", "WORLD: Received CMSG_ACTIVATETAXI");
|
|
|
|
ObjectGuid guid;
|
|
std::vector<uint32> nodes;
|
|
nodes.resize(2);
|
|
GetPlayer()->SetCanTeleport(true);
|
|
recvData >> guid >> nodes[0] >> nodes[1];
|
|
LOG_DEBUG("network", "WORLD: Received CMSG_ACTIVATETAXI from {} to {}", nodes[0], nodes[1]);
|
|
Creature* npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER);
|
|
if (!npc)
|
|
{
|
|
LOG_DEBUG("network", "WORLD: HandleActivateTaxiOpcode - Unit ({}) not found or you can't interact with it.", guid.ToString());
|
|
SendActivateTaxiReply(ERR_TAXITOOFARAWAY);
|
|
return;
|
|
}
|
|
|
|
if (!GetPlayer()->isTaxiCheater())
|
|
{
|
|
if (!GetPlayer()->m_taxi.IsTaximaskNodeKnown(nodes[0]) || !GetPlayer()->m_taxi.IsTaximaskNodeKnown(nodes[1]))
|
|
{
|
|
SendActivateTaxiReply(ERR_TAXINOTVISITED);
|
|
return;
|
|
}
|
|
}
|
|
|
|
GetPlayer()->ActivateTaxiPathTo(nodes, npc, 0);
|
|
}
|
|
|
|
void WorldSession::SendActivateTaxiReply(ActivateTaxiReply reply)
|
|
{
|
|
GetPlayer()->SetCanTeleport(true);
|
|
WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
|
|
data << uint32(reply);
|
|
SendPacket(&data);
|
|
|
|
LOG_DEBUG("network", "WORLD: Sent SMSG_ACTIVATETAXIREPLY");
|
|
}
|