Files
CypherCore/Source/Game/Handlers/TaxiHandler.cs
T
2025-06-09 00:04:23 -04:00

216 lines
8.8 KiB
C#

// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
using Framework.Constants;
using Game.DataStorage;
using Game.Entities;
using Game.Movement;
using Game.Networking;
using Game.Networking.Packets;
using System.Collections.Generic;
using System.Linq;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.EnableTaxiNode, Processing = PacketProcessing.ThreadSafe)]
void HandleEnableTaxiNodeOpcode(EnableTaxiNode enableTaxiNode)
{
Creature unit = GetPlayer().GetNPCIfCanInteractWith(enableTaxiNode.Unit, NPCFlags.FlightMaster, NPCFlags2.None);
if (unit != null)
SendLearnNewTaxiNode(unit);
}
[WorldPacketHandler(ClientOpcodes.TaxiNodeStatusQuery, Processing = PacketProcessing.ThreadSafe)]
void HandleTaxiNodeStatusQuery(TaxiNodeStatusQuery taxiNodeStatusQuery)
{
SendTaxiStatus(taxiNodeStatusQuery.UnitGUID);
}
public void SendTaxiStatus(ObjectGuid guid)
{
// cheating checks
Player player = GetPlayer();
Creature unit = ObjectAccessor.GetCreature(player, guid);
if (unit == null || unit.IsHostileTo(player) || !unit.HasNpcFlag(NPCFlags.FlightMaster))
{
Log.outDebug(LogFilter.Network, "WorldSession.SendTaxiStatus - {0} not found.", guid.ToString());
return;
}
// find taxi node
uint nearest = Global.ObjectMgr.GetNearestTaxiNode(unit.GetPositionX(), unit.GetPositionY(), unit.GetPositionZ(), unit.GetMapId(), player.GetTeam());
TaxiNodeStatusPkt data = new();
data.Unit = guid;
if (nearest == 0)
data.Status = TaxiNodeStatus.None;
else if (unit.GetReactionTo(player) >= ReputationRank.Neutral)
data.Status = player.m_taxi.IsTaximaskNodeKnown(nearest) ? TaxiNodeStatus.Learned : TaxiNodeStatus.Unlearned;
else
data.Status = TaxiNodeStatus.NotEligible;
SendPacket(data);
}
[WorldPacketHandler(ClientOpcodes.TaxiQueryAvailableNodes, Processing = PacketProcessing.ThreadSafe)]
void HandleTaxiQueryAvailableNodes(TaxiQueryAvailableNodes taxiQueryAvailableNodes)
{
// cheating checks
Creature unit = GetPlayer().GetNPCIfCanInteractWith(taxiQueryAvailableNodes.Unit, NPCFlags.FlightMaster, NPCFlags2.None);
if (unit == null)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTaxiQueryAvailableNodes - {0} not found or you can't interact with him.", taxiQueryAvailableNodes.Unit.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
// unknown taxi node case
if (SendLearnNewTaxiNode(unit))
return;
// known taxi node case
SendTaxiMenu(unit);
}
public void SendTaxiMenu(Creature unit)
{
// find current node
uint curloc = Global.ObjectMgr.GetNearestTaxiNode(unit.GetPositionX(), unit.GetPositionY(), unit.GetPositionZ(), unit.GetMapId(), GetPlayer().GetTeam());
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.
ShowTaxiNodes data = new();
ShowTaxiNodesWindowInfo windowInfo = new();
windowInfo.UnitGUID = unit.GetGUID();
windowInfo.CurrentNode = (int)curloc;
data.WindowInfo = windowInfo;
GetPlayer().m_taxi.AppendTaximaskTo(data, lastTaxiCheaterState);
byte[] reachableNodes = new byte[DB2Manager.TaxiNodesMask.Length];
TaxiPathGraph.GetReachableNodesMask(CliDB.TaxiNodesStorage.LookupByKey(curloc), reachableNodes);
for (var i = 0; i < reachableNodes.Length; ++i)
{
data.CanLandNodes[i] &= reachableNodes[i];
data.CanUseNodes[i] &= reachableNodes[i];
}
SendPacket(data);
GetPlayer().SetTaxiCheater(lastTaxiCheaterState);
}
public bool SendLearnNewTaxiNode(Creature unit)
{
// find current node
uint curloc = Global.ObjectMgr.GetNearestTaxiNode(unit.GetPositionX(), unit.GetPositionY(), unit.GetPositionZ(), unit.GetMapId(), GetPlayer().GetTeam());
if (curloc == 0)
return true;
if (GetPlayer().m_taxi.SetTaximaskNode(curloc))
{
SendPacket(new NewTaxiPath(curloc));
TaxiNodeStatusPkt data = new();
data.Unit = unit.GetGUID();
data.Status = TaxiNodeStatus.Learned;
SendPacket(data);
GetPlayer().UpdateCriteria(CriteriaType.LearnTaxiNode, curloc);
return true;
}
else
return false;
}
public void SendDiscoverNewTaxiNode(uint nodeid)
{
if (GetPlayer().m_taxi.SetTaximaskNode(nodeid))
SendPacket(new NewTaxiPath(nodeid));
}
[WorldPacketHandler(ClientOpcodes.ActivateTaxi, Processing = PacketProcessing.ThreadSafe)]
void HandleActivateTaxi(ActivateTaxi activateTaxi)
{
Creature unit = GetPlayer().GetNPCIfCanInteractWith(activateTaxi.Vendor, NPCFlags.FlightMaster, NPCFlags2.None);
if (unit == null)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleActivateTaxiOpcode - {0} not found or you can't interact with it.", activateTaxi.Vendor.ToString());
SendActivateTaxiReply(ActivateTaxiReply.TooFarAway);
return;
}
uint curloc = Global.ObjectMgr.GetNearestTaxiNode(unit.GetPositionX(), unit.GetPositionY(), unit.GetPositionZ(), unit.GetMapId(), GetPlayer().GetTeam());
if (curloc == 0)
return;
TaxiNodesRecord from = CliDB.TaxiNodesStorage.LookupByKey(curloc);
TaxiNodesRecord to = CliDB.TaxiNodesStorage.LookupByKey(activateTaxi.Node);
if (to == null)
return;
if (!GetPlayer().IsTaxiCheater())
{
if (!GetPlayer().m_taxi.IsTaximaskNodeKnown(curloc) || !GetPlayer().m_taxi.IsTaximaskNodeKnown(activateTaxi.Node))
{
SendActivateTaxiReply(ActivateTaxiReply.NotVisited);
return;
}
}
uint preferredMountDisplay = 0;
MountRecord mount = CliDB.MountStorage.LookupByKey(activateTaxi.FlyingMountID);
if (mount != null)
{
if (GetPlayer().HasSpell(mount.SourceSpellID))
{
var mountDisplays = Global.DB2Mgr.GetMountDisplays(mount.Id);
if (mountDisplays != null)
{
List<MountXDisplayRecord> usableDisplays = mountDisplays.Where(mountDisplay => ConditionManager.IsPlayerMeetingCondition(GetPlayer(), mountDisplay.PlayerConditionID)).ToList();
if (!usableDisplays.Empty())
preferredMountDisplay = usableDisplays.SelectRandom().CreatureDisplayInfoID;
}
}
}
List<uint> nodes = new();
TaxiPathGraph.GetCompleteNodeRoute(from, to, GetPlayer(), nodes);
GetPlayer().ActivateTaxiPathTo(nodes, unit, 0, preferredMountDisplay);
}
public void SendActivateTaxiReply(ActivateTaxiReply reply = ActivateTaxiReply.Ok)
{
ActivateTaxiReplyPkt data = new();
data.Reply = reply;
SendPacket(data);
}
[WorldPacketHandler(ClientOpcodes.TaxiRequestEarlyLanding, Processing = PacketProcessing.ThreadSafe)]
void HandleTaxiRequestEarlyLanding(TaxiRequestEarlyLanding taxiRequestEarlyLanding)
{
if (GetPlayer().GetMotionMaster().GetCurrentMovementGenerator() is FlightPathMovementGenerator flight)
{
if (GetPlayer().m_taxi.RequestEarlyLanding())
{
flight.LoadPath(GetPlayer(), (uint)flight.GetPath()[(int)flight.GetCurrentNode()].NodeIndex);
flight.Reset(GetPlayer());
}
}
}
}
}