Ported .Net Core commits:
hondacrx: - Initial commit: Switch to .Net Core 2.0 - Fix build and removed not needed files Fabi: - Updated solution platforms. - Changed folder structure. - Change library target framework to netstandard2.0. - Updated solution platforms again... - Removed windows specific kernel32 function usage (Ctrl-C handler).
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
void SendNotInArenaTeamPacket(ArenaTypes type)
|
||||
{
|
||||
ArenaError arenaError = new ArenaError();
|
||||
arenaError.ErrorType = ArenaErrorType.NoTeam;
|
||||
arenaError.TeamSize = (byte)type; // team type (2=2v2, 3=3v3, 5=5v5), can be used for custom types...
|
||||
SendPacket(arenaError);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.ArtifactAddPower)]
|
||||
void HandleArtifactAddPower(ArtifactAddPower artifactAddPower)
|
||||
{
|
||||
if (!_player.GetGameObjectIfCanInteractWith(artifactAddPower.ForgeGUID, GameObjectTypes.ArtifactForge))
|
||||
return;
|
||||
|
||||
Item artifact = _player.GetItemByGuid(artifactAddPower.ArtifactGUID);
|
||||
if (!artifact)
|
||||
return;
|
||||
|
||||
ulong xpCost = 0;
|
||||
GtArtifactLevelXPRecord cost = CliDB.ArtifactLevelXPGameTable.GetRow(artifact.GetTotalPurchasedArtifactPowers() + 1);
|
||||
if (cost != null)
|
||||
xpCost = (ulong)(artifact.GetModifier(ItemModifier.ArtifactTier) == 1 ? cost.XP2 : cost.XP);
|
||||
|
||||
if (xpCost > artifact.GetUInt64Value(ItemFields.ArtifactXp))
|
||||
return;
|
||||
|
||||
if (artifactAddPower.PowerChoices.Empty())
|
||||
return;
|
||||
|
||||
ItemDynamicFieldArtifactPowers artifactPower = artifact.GetArtifactPower(artifactAddPower.PowerChoices[0].ArtifactPowerID);
|
||||
if (artifactPower == null)
|
||||
return;
|
||||
|
||||
ArtifactPowerRecord artifactPowerEntry = CliDB.ArtifactPowerStorage.LookupByKey(artifactPower.ArtifactPowerId);
|
||||
if (artifactPowerEntry == null)
|
||||
return;
|
||||
|
||||
if (artifactAddPower.PowerChoices[0].Rank != artifactPower.PurchasedRank + 1 ||
|
||||
artifactAddPower.PowerChoices[0].Rank > artifactPowerEntry.MaxRank)
|
||||
return;
|
||||
|
||||
var artifactPowerLinks = Global.DB2Mgr.GetArtifactPowerLinks(artifactPower.ArtifactPowerId);
|
||||
if (artifactPowerLinks != null)
|
||||
{
|
||||
bool hasAnyLink = false;
|
||||
foreach (uint artifactPowerLinkId in artifactPowerLinks)
|
||||
{
|
||||
ArtifactPowerRecord artifactPowerLink = CliDB.ArtifactPowerStorage.LookupByKey(artifactPowerLinkId);
|
||||
if (artifactPowerLink == null)
|
||||
continue;
|
||||
|
||||
ItemDynamicFieldArtifactPowers artifactPowerLinkLearned = artifact.GetArtifactPower(artifactPowerLinkId);
|
||||
if (artifactPowerLinkLearned == null)
|
||||
continue;
|
||||
|
||||
if (artifactPowerLinkLearned.PurchasedRank >= artifactPowerLink.MaxRank)
|
||||
{
|
||||
hasAnyLink = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasAnyLink)
|
||||
return;
|
||||
}
|
||||
|
||||
ArtifactPowerRankRecord artifactPowerRank = Global.DB2Mgr.GetArtifactPowerRank(artifactPower.ArtifactPowerId, (byte)(artifactPower.CurrentRankWithBonus + 1 - 1)); // need data for next rank, but -1 because of how db2 data is structured
|
||||
if (artifactPowerRank == null)
|
||||
return;
|
||||
|
||||
ItemDynamicFieldArtifactPowers newPower = artifactPower;
|
||||
++newPower.PurchasedRank;
|
||||
++newPower.CurrentRankWithBonus;
|
||||
artifact.SetArtifactPower(newPower);
|
||||
|
||||
if (artifact.IsEquipped())
|
||||
{
|
||||
_player.ApplyArtifactPowerRank(artifact, artifactPowerRank, true);
|
||||
|
||||
foreach (ItemDynamicFieldArtifactPowers power in artifact.GetArtifactPowers())
|
||||
{
|
||||
ArtifactPowerRecord scaledArtifactPowerEntry = CliDB.ArtifactPowerStorage.LookupByKey(power.ArtifactPowerId);
|
||||
if (!scaledArtifactPowerEntry.Flags.HasAnyFlag(ArtifactPowerFlag.ScalesWithNumPowers))
|
||||
continue;
|
||||
|
||||
ArtifactPowerRankRecord scaledArtifactPowerRank = Global.DB2Mgr.GetArtifactPowerRank(scaledArtifactPowerEntry.Id, 0);
|
||||
if (scaledArtifactPowerRank == null)
|
||||
continue;
|
||||
|
||||
ItemDynamicFieldArtifactPowers newScaledPower = power;
|
||||
++newScaledPower.CurrentRankWithBonus;
|
||||
artifact.SetArtifactPower(newScaledPower);
|
||||
|
||||
_player.ApplyArtifactPowerRank(artifact, scaledArtifactPowerRank, false);
|
||||
_player.ApplyArtifactPowerRank(artifact, scaledArtifactPowerRank, true);
|
||||
}
|
||||
}
|
||||
|
||||
artifact.SetUInt64Value(ItemFields.ArtifactXp, artifact.GetUInt64Value(ItemFields.ArtifactXp) - xpCost);
|
||||
artifact.SetState(ItemUpdateState.Changed, _player);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ArtifactSetAppearance)]
|
||||
void HandleArtifactSetAppearance(ArtifactSetAppearance artifactSetAppearance)
|
||||
{
|
||||
if (!_player.GetGameObjectIfCanInteractWith(artifactSetAppearance.ForgeGUID, GameObjectTypes.ArtifactForge))
|
||||
return;
|
||||
|
||||
ArtifactAppearanceRecord artifactAppearance = CliDB.ArtifactAppearanceStorage.LookupByKey(artifactSetAppearance.ArtifactAppearanceID);
|
||||
if (artifactAppearance == null)
|
||||
return;
|
||||
|
||||
Item artifact = _player.GetItemByGuid(artifactSetAppearance.ArtifactGUID);
|
||||
if (!artifact)
|
||||
return;
|
||||
|
||||
ArtifactAppearanceSetRecord artifactAppearanceSet = CliDB.ArtifactAppearanceSetStorage.LookupByKey(artifactAppearance.ArtifactAppearanceSetID);
|
||||
if (artifactAppearanceSet == null || artifactAppearanceSet.ArtifactID != artifact.GetTemplate().GetArtifactID())
|
||||
return;
|
||||
|
||||
PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(artifactAppearance.PlayerConditionID);
|
||||
if (playerCondition != null)
|
||||
if (!ConditionManager.IsPlayerMeetingCondition(_player, playerCondition))
|
||||
return;
|
||||
|
||||
artifact.SetAppearanceModId(artifactAppearance.AppearanceModID);
|
||||
artifact.SetModifier(ItemModifier.ArtifactAppearanceId, artifactAppearance.Id);
|
||||
artifact.SetState(ItemUpdateState.Changed, _player);
|
||||
Item childItem = _player.GetChildItemByGuid(artifact.GetChildItem());
|
||||
if (childItem)
|
||||
{
|
||||
childItem.SetAppearanceModId(artifactAppearance.AppearanceModID);
|
||||
childItem.SetState(ItemUpdateState.Changed, _player);
|
||||
}
|
||||
|
||||
if (artifact.IsEquipped())
|
||||
{
|
||||
// change weapon appearance
|
||||
_player.SetVisibleItemSlot(artifact.GetSlot(), artifact);
|
||||
if (childItem)
|
||||
_player.SetVisibleItemSlot(childItem.GetSlot(), childItem);
|
||||
|
||||
// change druid form appearance
|
||||
if (artifactAppearance.ShapeshiftDisplayID != 0 && artifactAppearance.ModifiesShapeshiftFormDisplay != 0 && _player.GetShapeshiftForm() == (ShapeShiftForm)artifactAppearance.ModifiesShapeshiftFormDisplay)
|
||||
_player.RestoreDisplayId();
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ConfirmArtifactRespec)]
|
||||
void HandleConfirmArtifactRespec(ConfirmArtifactRespec confirmArtifactRespec)
|
||||
{
|
||||
if (!_player.GetNPCIfCanInteractWith(confirmArtifactRespec.NpcGUID, NPCFlags.ArtifactPowerRespec))
|
||||
return;
|
||||
|
||||
Item artifact = _player.GetItemByGuid(confirmArtifactRespec.ArtifactGUID);
|
||||
if (!artifact)
|
||||
return;
|
||||
|
||||
ulong xpCost = 0;
|
||||
GtArtifactLevelXPRecord cost = CliDB.ArtifactLevelXPGameTable.GetRow(artifact.GetTotalPurchasedArtifactPowers() + 1);
|
||||
if (cost != null)
|
||||
xpCost = (ulong)(artifact.GetModifier(ItemModifier.ArtifactTier) == 1 ? cost.XP2 : cost.XP);
|
||||
|
||||
if (xpCost > artifact.GetUInt64Value(ItemFields.ArtifactXp))
|
||||
return;
|
||||
|
||||
ulong newAmount = artifact.GetUInt64Value(ItemFields.ArtifactXp) - xpCost;
|
||||
for (uint i = 0; i <= artifact.GetTotalPurchasedArtifactPowers(); ++i)
|
||||
{
|
||||
GtArtifactLevelXPRecord cost1 = CliDB.ArtifactLevelXPGameTable.GetRow(i);
|
||||
if (cost1 != null)
|
||||
newAmount += (ulong)(artifact.GetModifier(ItemModifier.ArtifactTier) == 1 ? cost1.XP2 : cost1.XP);
|
||||
}
|
||||
|
||||
foreach (ItemDynamicFieldArtifactPowers artifactPower in artifact.GetArtifactPowers())
|
||||
{
|
||||
byte oldPurchasedRank = artifactPower.PurchasedRank;
|
||||
if (oldPurchasedRank == 0)
|
||||
continue;
|
||||
|
||||
ItemDynamicFieldArtifactPowers newPower = artifactPower;
|
||||
newPower.PurchasedRank -= oldPurchasedRank;
|
||||
newPower.CurrentRankWithBonus -= oldPurchasedRank;
|
||||
artifact.SetArtifactPower(newPower);
|
||||
|
||||
if (artifact.IsEquipped())
|
||||
{
|
||||
ArtifactPowerRankRecord artifactPowerRank = Global.DB2Mgr.GetArtifactPowerRank(artifactPower.ArtifactPowerId, 0);
|
||||
if (artifactPowerRank != null)
|
||||
_player.ApplyArtifactPowerRank(artifact, artifactPowerRank, false);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (ItemDynamicFieldArtifactPowers power in artifact.GetArtifactPowers())
|
||||
{
|
||||
ArtifactPowerRecord scaledArtifactPowerEntry = CliDB.ArtifactPowerStorage.LookupByKey(power.ArtifactPowerId);
|
||||
if (!scaledArtifactPowerEntry.Flags.HasAnyFlag(ArtifactPowerFlag.ScalesWithNumPowers))
|
||||
continue;
|
||||
|
||||
ArtifactPowerRankRecord scaledArtifactPowerRank = Global.DB2Mgr.GetArtifactPowerRank(scaledArtifactPowerEntry.Id, 0);
|
||||
if (scaledArtifactPowerRank == null)
|
||||
continue;
|
||||
|
||||
ItemDynamicFieldArtifactPowers newScaledPower = power;
|
||||
newScaledPower.CurrentRankWithBonus = 0;
|
||||
artifact.SetArtifactPower(newScaledPower);
|
||||
|
||||
_player.ApplyArtifactPowerRank(artifact, scaledArtifactPowerRank, false);
|
||||
}
|
||||
|
||||
artifact.SetUInt64Value(ItemFields.ArtifactXp, newAmount);
|
||||
artifact.SetState(ItemUpdateState.Changed, _player);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,673 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.Dynamic;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Mails;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.AuctionHelloRequest)]
|
||||
void HandleAuctionHelloOpcode(AuctionHelloRequest packet)
|
||||
{
|
||||
Creature unit = GetPlayer().GetNPCIfCanInteractWith(packet.Guid, NPCFlags.Auctioneer);
|
||||
if (!unit)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionHelloOpcode - {0} not found or you can't interact with him.", packet.Guid.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
SendAuctionHello(packet.Guid, unit);
|
||||
}
|
||||
|
||||
public void SendAuctionHello(ObjectGuid guid, Creature unit)
|
||||
{
|
||||
if (GetPlayer().getLevel() < WorldConfig.GetIntValue(WorldCfg.AuctionLevelReq))
|
||||
{
|
||||
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.AuctionReq), WorldConfig.GetIntValue(WorldCfg.AuctionLevelReq));
|
||||
return;
|
||||
}
|
||||
|
||||
AuctionHouseRecord ahEntry = Global.AuctionMgr.GetAuctionHouseEntry(unit.getFaction());
|
||||
if (ahEntry == null)
|
||||
return;
|
||||
|
||||
AuctionHelloResponse packet = new AuctionHelloResponse();
|
||||
packet.Guid = guid;
|
||||
packet.OpenForBusiness = true; // 3.3.3: 1 - AH enabled, 0 - AH disabled
|
||||
SendPacket(packet);
|
||||
}
|
||||
|
||||
public void SendAuctionCommandResult(AuctionEntry auction, AuctionAction action, AuctionError errorCode, uint bidError = 0)
|
||||
{
|
||||
AuctionCommandResult auctionCommandResult = new AuctionCommandResult();
|
||||
auctionCommandResult.InitializeAuction(auction);
|
||||
auctionCommandResult.Command = action;
|
||||
auctionCommandResult.ErrorCode = errorCode;
|
||||
SendPacket(auctionCommandResult);
|
||||
}
|
||||
|
||||
public void SendAuctionOutBidNotification(AuctionEntry auction, Item item)
|
||||
{
|
||||
AuctionOutBidNotification packet = new AuctionOutBidNotification();
|
||||
packet.BidAmount = auction.bid;
|
||||
packet.MinIncrement = auction.GetAuctionOutBid();
|
||||
packet.Info.Initialize(auction, item);
|
||||
SendPacket(packet);
|
||||
}
|
||||
|
||||
public void SendAuctionClosedNotification(AuctionEntry auction, float mailDelay, bool sold, Item item)
|
||||
{
|
||||
AuctionClosedNotification packet = new AuctionClosedNotification();
|
||||
packet.Info.Initialize(auction, item);
|
||||
packet.ProceedsMailDelay = mailDelay;
|
||||
packet.Sold = sold;
|
||||
SendPacket(packet);
|
||||
}
|
||||
|
||||
public void SendAuctionWonNotification(AuctionEntry auction, Item item)
|
||||
{
|
||||
AuctionWonNotification packet = new AuctionWonNotification();
|
||||
packet.Info.Initialize(auction, item);
|
||||
SendPacket(packet);
|
||||
}
|
||||
|
||||
public void SendAuctionOwnerBidNotification(AuctionEntry auction, Item item)
|
||||
{
|
||||
AuctionOwnerBidNotification packet = new AuctionOwnerBidNotification();
|
||||
packet.Info.Initialize(auction, item);
|
||||
packet.Bidder = ObjectGuid.Create(HighGuid.Player, auction.bidder);
|
||||
packet.MinIncrement = auction.GetAuctionOutBid();
|
||||
SendPacket(packet);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AuctionSellItem)]
|
||||
void HandleAuctionSellItem(AuctionSellItem packet)
|
||||
{
|
||||
foreach (var aitem in packet.Items)
|
||||
if (aitem.Guid.IsEmpty() || aitem.UseCount == 0 || aitem.UseCount > 1000)
|
||||
return;
|
||||
|
||||
if (packet.MinBid == 0 || packet.RunTime == 0)
|
||||
return;
|
||||
|
||||
if (packet.MinBid > PlayerConst.MaxMoneyAmount || packet.BuyoutPrice > PlayerConst.MaxMoneyAmount)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionSellItem - Player {0} ({1}) attempted to sell item with higher price than max gold amount.", GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
|
||||
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError);
|
||||
return;
|
||||
}
|
||||
|
||||
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.Auctioneer, NPCFlags.Auctioneer);
|
||||
if (!creature)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionSellItem - {0} not found or you can't interact with him.", packet.Auctioneer.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
uint houseId = 0;
|
||||
AuctionHouseRecord auctionHouseEntry = Global.AuctionMgr.GetAuctionHouseEntry(creature.getFaction(), ref houseId);
|
||||
if (auctionHouseEntry == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionSellItem - {0} has wrong faction.", packet.Auctioneer.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
packet.RunTime *= Time.Minute;
|
||||
switch (packet.RunTime)
|
||||
{
|
||||
case 1 * SharedConst.MinAuctionTime:
|
||||
case 2 * SharedConst.MinAuctionTime:
|
||||
case 4 * SharedConst.MinAuctionTime:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
uint finalCount = 0;
|
||||
foreach (var packetItem in packet.Items)
|
||||
{
|
||||
Item aitem = GetPlayer().GetItemByGuid(packetItem.Guid);
|
||||
if (!aitem)
|
||||
{
|
||||
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.ItemNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Global.AuctionMgr.GetAItem(aitem.GetGUID().GetCounter()) || !aitem.CanBeTraded() || aitem.IsNotEmptyBag() ||
|
||||
aitem.GetTemplate().GetFlags().HasAnyFlag(ItemFlags.Conjured) || aitem.GetUInt32Value(ItemFields.Duration) != 0 ||
|
||||
aitem.GetCount() < packetItem.UseCount)
|
||||
{
|
||||
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError);
|
||||
return;
|
||||
}
|
||||
|
||||
finalCount += packetItem.UseCount;
|
||||
}
|
||||
|
||||
if (packet.Items.Empty())
|
||||
{
|
||||
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError);
|
||||
return;
|
||||
}
|
||||
|
||||
if (finalCount == 0)
|
||||
{
|
||||
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if there are 2 identical guids, in this case user is most likely cheating
|
||||
for (int i = 0; i < packet.Items.Count; ++i)
|
||||
{
|
||||
for (int j = i + 1; j < packet.Items.Count; ++j)
|
||||
{
|
||||
if (packet.Items[i].Guid == packet.Items[j].Guid)
|
||||
{
|
||||
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var packetItem in packet.Items)
|
||||
{
|
||||
Item aitem = GetPlayer().GetItemByGuid(packetItem.Guid);
|
||||
|
||||
if (aitem.GetMaxStackCount() < finalCount)
|
||||
{
|
||||
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Item item = GetPlayer().GetItemByGuid(packet.Items[0].Guid);
|
||||
|
||||
uint auctionTime = (uint)(packet.RunTime * WorldConfig.GetFloatValue(WorldCfg.RateAuctionTime));
|
||||
AuctionHouseObject auctionHouse = Global.AuctionMgr.GetAuctionsMap(creature.getFaction());
|
||||
|
||||
ulong deposit = Global.AuctionMgr.GetAuctionDeposit(auctionHouseEntry, packet.RunTime, item, finalCount);
|
||||
if (!GetPlayer().HasEnoughMoney(deposit))
|
||||
{
|
||||
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.NotEnoughtMoney);
|
||||
return;
|
||||
}
|
||||
|
||||
AuctionEntry AH = new AuctionEntry();
|
||||
SQLTransaction trans;
|
||||
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionAuction))
|
||||
AH.auctioneer = 23442; ///@TODO - HARDCODED DB GUID, BAD BAD BAD
|
||||
else
|
||||
AH.auctioneer = creature.GetSpawnId();
|
||||
|
||||
// Required stack size of auction matches to current item stack size, just move item to auctionhouse
|
||||
if (packet.Items.Count == 1 && item.GetCount() == packet.Items[0].UseCount)
|
||||
{
|
||||
if (HasPermission(RBACPermissions.LogGmTrade))
|
||||
{
|
||||
Log.outCommand(GetAccountId(), "GM {0} (Account: {1}) create auction: {2} (Entry: {3} Count: {4})",
|
||||
GetPlayerName(), GetAccountId(), item.GetTemplate().GetName(), item.GetEntry(), item.GetCount());
|
||||
}
|
||||
|
||||
AH.Id = Global.ObjectMgr.GenerateAuctionID();
|
||||
AH.itemGUIDLow = item.GetGUID().GetCounter();
|
||||
AH.itemEntry = item.GetEntry();
|
||||
AH.itemCount = item.GetCount();
|
||||
AH.owner = GetPlayer().GetGUID().GetCounter();
|
||||
AH.startbid = (uint)packet.MinBid;
|
||||
AH.bidder = 0;
|
||||
AH.bid = 0;
|
||||
AH.buyout = (uint)packet.BuyoutPrice;
|
||||
AH.expire_time = Time.UnixTime + auctionTime;
|
||||
AH.deposit = deposit;
|
||||
AH.etime = packet.RunTime;
|
||||
AH.auctionHouseEntry = auctionHouseEntry;
|
||||
|
||||
Log.outInfo(LogFilter.Network, "CMSG_AUCTION_SELL_ITEM: {0} {1} is selling item {2} {3} to auctioneer {4} with count {5} with initial bid {6} with buyout {7} and with time {8} (in sec) in auctionhouse {9}",
|
||||
GetPlayer().GetGUID().ToString(), GetPlayer().GetName(), item.GetGUID().ToString(), item.GetTemplate().GetName(), AH.auctioneer, item.GetCount(), packet.MinBid, packet.BuyoutPrice, auctionTime, AH.GetHouseId());
|
||||
Global.AuctionMgr.AddAItem(item);
|
||||
auctionHouse.AddAuction(AH);
|
||||
|
||||
GetPlayer().MoveItemFromInventory(item.GetBagSlot(), item.GetSlot(), true);
|
||||
|
||||
trans = new SQLTransaction();
|
||||
item.DeleteFromInventoryDB(trans);
|
||||
item.SaveToDB(trans);
|
||||
AH.SaveToDB(trans);
|
||||
GetPlayer().SaveInventoryAndGoldToDB(trans);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
SendAuctionCommandResult(AH, AuctionAction.SellItem, AuctionError.Ok);
|
||||
|
||||
GetPlayer().UpdateCriteria(CriteriaTypes.CreateAuction, 1);
|
||||
}
|
||||
else // Required stack size of auction does not match to current item stack size, clone item and set correct stack size
|
||||
{
|
||||
Item newItem = item.CloneItem(finalCount, GetPlayer());
|
||||
if (!newItem)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "CMSG_AuctionAction.SellItem: Could not create clone of item {0}", item.GetEntry());
|
||||
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError);
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasPermission(RBACPermissions.LogGmTrade))
|
||||
{
|
||||
Log.outCommand(GetAccountId(), "GM {0} (Account: {1}) create auction: {2} (Entry: {3} Count: {4})",
|
||||
GetPlayerName(), GetAccountId(), newItem.GetTemplate().GetName(), newItem.GetEntry(), newItem.GetCount());
|
||||
}
|
||||
|
||||
AH.Id = Global.ObjectMgr.GenerateAuctionID();
|
||||
AH.itemGUIDLow = newItem.GetGUID().GetCounter();
|
||||
AH.itemEntry = newItem.GetEntry();
|
||||
AH.itemCount = newItem.GetCount();
|
||||
AH.owner = GetPlayer().GetGUID().GetCounter();
|
||||
AH.startbid = (uint)packet.MinBid;
|
||||
AH.bidder = 0;
|
||||
AH.bid = 0;
|
||||
AH.buyout = (uint)packet.BuyoutPrice;
|
||||
AH.expire_time = Time.UnixTime + auctionTime;
|
||||
AH.deposit = deposit;
|
||||
AH.etime = packet.RunTime;
|
||||
AH.auctionHouseEntry = auctionHouseEntry;
|
||||
|
||||
Log.outInfo(LogFilter.Network, "CMSG_AuctionAction.SellItem: {0} {1} is selling {2} {3} to auctioneer {4} with count {5} with initial bid {6} with buyout {7} and with time {8} (in sec) in auctionhouse {9}",
|
||||
GetPlayer().GetGUID().ToString(), GetPlayer().GetName(), newItem.GetGUID().ToString(), newItem.GetTemplate().GetName(), AH.auctioneer, newItem.GetCount(), packet.MinBid, packet.BuyoutPrice, auctionTime, AH.GetHouseId());
|
||||
Global.AuctionMgr.AddAItem(newItem);
|
||||
auctionHouse.AddAuction(AH);
|
||||
|
||||
foreach (var packetItem in packet.Items)
|
||||
{
|
||||
Item item2 = GetPlayer().GetItemByGuid(packetItem.Guid);
|
||||
|
||||
// Item stack count equals required count, ready to delete item - cloned item will be used for auction
|
||||
if (item2.GetCount() == packetItem.UseCount)
|
||||
{
|
||||
GetPlayer().MoveItemFromInventory(item2.GetBagSlot(), item2.GetSlot(), true);
|
||||
|
||||
trans = new SQLTransaction();
|
||||
item2.DeleteFromInventoryDB(trans);
|
||||
item2.DeleteFromDB(trans);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
}
|
||||
else // Item stack count is bigger than required count, update item stack count and save to database - cloned item will be used for auction
|
||||
{
|
||||
item2.SetCount(item2.GetCount() - packetItem.UseCount);
|
||||
item2.SetState(ItemUpdateState.Changed, GetPlayer());
|
||||
GetPlayer().ItemRemovedQuestCheck(item2.GetEntry(), packetItem.UseCount);
|
||||
item2.SendUpdateToPlayer(GetPlayer());
|
||||
|
||||
trans = new SQLTransaction();
|
||||
item2.SaveToDB(trans);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
}
|
||||
}
|
||||
|
||||
trans = new SQLTransaction();
|
||||
newItem.SaveToDB(trans);
|
||||
AH.SaveToDB(trans);
|
||||
GetPlayer().SaveInventoryAndGoldToDB(trans);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
SendAuctionCommandResult(AH, AuctionAction.SellItem, AuctionError.Ok);
|
||||
|
||||
GetPlayer().UpdateCriteria(CriteriaTypes.CreateAuction, 1);
|
||||
}
|
||||
|
||||
GetPlayer().ModifyMoney(-(long)deposit);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AuctionPlaceBid)]
|
||||
void HandleAuctionPlaceBid(AuctionPlaceBid packet)
|
||||
{
|
||||
if (packet.AuctionItemID == 0 || packet.BidAmount == 0)
|
||||
return; // check for cheaters
|
||||
|
||||
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.Auctioneer, NPCFlags.Auctioneer);
|
||||
if (!creature)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionPlaceBid - {0} not found or you can't interact with him.", packet.Auctioneer.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
AuctionHouseObject auctionHouse = Global.AuctionMgr.GetAuctionsMap(creature.getFaction());
|
||||
|
||||
AuctionEntry auction = auctionHouse.GetAuction(packet.AuctionItemID);
|
||||
Player player = GetPlayer();
|
||||
|
||||
if (auction == null || auction.owner == player.GetGUID().GetCounter())
|
||||
{
|
||||
//you cannot bid your own auction:
|
||||
SendAuctionCommandResult(null, AuctionAction.PlaceBid, AuctionError.BidOwn);
|
||||
return;
|
||||
}
|
||||
|
||||
// impossible have online own another character (use this for speedup check in case online owner)
|
||||
ObjectGuid ownerGuid = ObjectGuid.Create(HighGuid.Player, auction.owner);
|
||||
Player auction_owner = Global.ObjAccessor.FindPlayer(ownerGuid);
|
||||
if (!auction_owner && ObjectManager.GetPlayerAccountIdByGUID(ownerGuid) == player.GetSession().GetAccountId())
|
||||
{
|
||||
//you cannot bid your another character auction:
|
||||
SendAuctionCommandResult(null, AuctionAction.PlaceBid, AuctionError.BidOwn);
|
||||
return;
|
||||
}
|
||||
|
||||
// cheating
|
||||
if (packet.BidAmount <= auction.bid || packet.BidAmount < auction.startbid)
|
||||
return;
|
||||
|
||||
// price too low for next bid if not buyout
|
||||
if ((packet.BidAmount < auction.buyout || auction.buyout == 0) && packet.BidAmount < auction.bid + auction.GetAuctionOutBid())
|
||||
{
|
||||
// client already test it but just in case ...
|
||||
SendAuctionCommandResult(auction, AuctionAction.PlaceBid, AuctionError.HigherBid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.HasEnoughMoney(packet.BidAmount))
|
||||
{
|
||||
// client already test it but just in case ...
|
||||
SendAuctionCommandResult(auction, AuctionAction.PlaceBid, AuctionError.NotEnoughtMoney);
|
||||
return;
|
||||
}
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
if (packet.BidAmount < auction.buyout || auction.buyout == 0)
|
||||
{
|
||||
if (auction.bidder > 0)
|
||||
{
|
||||
if (auction.bidder == player.GetGUID().GetCounter())
|
||||
player.ModifyMoney(-(long)(packet.BidAmount - auction.bid));
|
||||
else
|
||||
{
|
||||
// mail to last bidder and return money
|
||||
Global.AuctionMgr.SendAuctionOutbiddedMail(auction, packet.BidAmount, GetPlayer(), trans);
|
||||
player.ModifyMoney(-(long)packet.BidAmount);
|
||||
}
|
||||
}
|
||||
else
|
||||
player.ModifyMoney(-(long)packet.BidAmount);
|
||||
|
||||
auction.bidder = player.GetGUID().GetCounter();
|
||||
auction.bid = (uint)packet.BidAmount;
|
||||
GetPlayer().UpdateCriteria(CriteriaTypes.HighestAuctionBid, packet.BidAmount);
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_AUCTION_BID);
|
||||
stmt.AddValue(0, auction.bidder);
|
||||
stmt.AddValue(1, auction.bid);
|
||||
stmt.AddValue(2, auction.Id);
|
||||
trans.Append(stmt);
|
||||
|
||||
SendAuctionCommandResult(auction, AuctionAction.PlaceBid, AuctionError.Ok);
|
||||
|
||||
// Not sure if we must send this now.
|
||||
Player owner = Global.ObjAccessor.FindConnectedPlayer(ObjectGuid.Create(HighGuid.Player, auction.owner));
|
||||
Item item = Global.AuctionMgr.GetAItem(auction.itemGUIDLow);
|
||||
if (owner && item)
|
||||
owner.GetSession().SendAuctionOwnerBidNotification(auction, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
//buyout:
|
||||
if (player.GetGUID().GetCounter() == auction.bidder)
|
||||
player.ModifyMoney(-(long)(auction.buyout - auction.bid));
|
||||
else
|
||||
{
|
||||
player.ModifyMoney(-(long)auction.buyout);
|
||||
if (auction.bidder != 0) //buyout for bidded auction ..
|
||||
Global.AuctionMgr.SendAuctionOutbiddedMail(auction, auction.buyout, GetPlayer(), trans);
|
||||
}
|
||||
auction.bidder = player.GetGUID().GetCounter();
|
||||
auction.bid = auction.buyout;
|
||||
GetPlayer().UpdateCriteria(CriteriaTypes.HighestAuctionBid, auction.buyout);
|
||||
|
||||
SendAuctionCommandResult(auction, AuctionAction.PlaceBid, AuctionError.Ok);
|
||||
|
||||
//- Mails must be under transaction control too to prevent data loss
|
||||
Global.AuctionMgr.SendAuctionSalePendingMail(auction, trans);
|
||||
Global.AuctionMgr.SendAuctionSuccessfulMail(auction, trans);
|
||||
Global.AuctionMgr.SendAuctionWonMail(auction, trans);
|
||||
|
||||
auction.DeleteFromDB(trans);
|
||||
|
||||
Global.AuctionMgr.RemoveAItem(auction.itemGUIDLow);
|
||||
auctionHouse.RemoveAuction(auction);
|
||||
}
|
||||
|
||||
player.SaveInventoryAndGoldToDB(trans);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AuctionRemoveItem)]
|
||||
void HandleAuctionRemoveItem(AuctionRemoveItem packet)
|
||||
{
|
||||
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.Auctioneer, NPCFlags.Auctioneer);
|
||||
if (!creature)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionRemoveItem - {0} not found or you can't interact with him.", packet.Auctioneer.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
AuctionHouseObject auctionHouse = Global.AuctionMgr.GetAuctionsMap(creature.getFaction());
|
||||
|
||||
AuctionEntry auction = auctionHouse.GetAuction((uint)packet.AuctionItemID);
|
||||
Player player = GetPlayer();
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
if (auction != null && auction.owner == player.GetGUID().GetCounter())
|
||||
{
|
||||
Item pItem = Global.AuctionMgr.GetAItem(auction.itemGUIDLow);
|
||||
if (pItem)
|
||||
{
|
||||
if (auction.bidder > 0) // If we have a bidder, we have to send him the money he paid
|
||||
{
|
||||
ulong auctionCut = auction.GetAuctionCut();
|
||||
if (!player.HasEnoughMoney(auctionCut)) //player doesn't have enough money, maybe message needed
|
||||
return;
|
||||
Global.AuctionMgr.SendAuctionCancelledToBidderMail(auction, trans);
|
||||
player.ModifyMoney(-(long)auctionCut);
|
||||
}
|
||||
|
||||
// item will deleted or added to received mail list
|
||||
new MailDraft(auction.BuildAuctionMailSubject(MailAuctionAnswers.Canceled), AuctionEntry.BuildAuctionMailBody(0, 0, auction.buyout, auction.deposit, 0))
|
||||
.AddItem(pItem)
|
||||
.SendMailTo(trans, new MailReceiver(player), new MailSender(auction), MailCheckMask.Copied);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outError(LogFilter.Network, "Auction id: {0} got non existing item (item guid : {1})!", auction.Id, auction.itemGUIDLow);
|
||||
SendAuctionCommandResult(null, AuctionAction.Cancel, AuctionError.DatabaseError);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SendAuctionCommandResult(null, AuctionAction.Cancel, AuctionError.DatabaseError);
|
||||
//this code isn't possible ... maybe there should be assert
|
||||
Log.outError(LogFilter.Network, "CHEATER: {0} tried to cancel auction (id: {1}) of another player or auction is null", player.GetGUID().ToString(), packet.AuctionItemID);
|
||||
return;
|
||||
}
|
||||
|
||||
//inform player, that auction is removed
|
||||
SendAuctionCommandResult(auction, AuctionAction.Cancel, AuctionError.Ok);
|
||||
|
||||
// Now remove the auction
|
||||
player.SaveInventoryAndGoldToDB(trans);
|
||||
auction.DeleteFromDB(trans);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
Global.AuctionMgr.RemoveAItem(auction.itemGUIDLow);
|
||||
auctionHouse.RemoveAuction(auction);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AuctionListBidderItems)]
|
||||
void HandleAuctionListBidderItems(AuctionListBidderItems packet)
|
||||
{
|
||||
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.Auctioneer, NPCFlags.Auctioneer);
|
||||
if (!creature)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionListBidderItems - {0} not found or you can't interact with him.", packet.Auctioneer.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
AuctionHouseObject auctionHouse = Global.AuctionMgr.GetAuctionsMap(creature.getFaction());
|
||||
|
||||
AuctionListBidderItemsResult result = new AuctionListBidderItemsResult();
|
||||
|
||||
Player player = GetPlayer();
|
||||
auctionHouse.BuildListBidderItems(result, player, ref result.TotalCount);
|
||||
result.DesiredDelay = 300;
|
||||
SendPacket(result);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AuctionListOwnerItems)]
|
||||
void HandleAuctionListOwnerItems(AuctionListOwnerItems packet)
|
||||
{
|
||||
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.Auctioneer, NPCFlags.Auctioneer);
|
||||
if (!creature)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionListOwnerItems - {0} not found or you can't interact with him.", packet.Auctioneer.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
AuctionHouseObject auctionHouse = Global.AuctionMgr.GetAuctionsMap(creature.getFaction());
|
||||
|
||||
AuctionListOwnerItemsResult result = new AuctionListOwnerItemsResult();
|
||||
|
||||
auctionHouse.BuildListOwnerItems(result, GetPlayer(), ref result.TotalCount);
|
||||
result.DesiredDelay = 300;
|
||||
SendPacket(result);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AuctionListItems)]
|
||||
void HandleAuctionListItems(AuctionListItems packet)
|
||||
{
|
||||
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.Auctioneer, NPCFlags.Auctioneer);
|
||||
if (!creature)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionListItems - {0} not found or you can't interact with him.", packet.Auctioneer.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
AuctionHouseObject auctionHouse = Global.AuctionMgr.GetAuctionsMap(creature.getFaction());
|
||||
|
||||
|
||||
Optional<AuctionSearchFilters> filters = new Optional<AuctionSearchFilters>();
|
||||
|
||||
AuctionListItemsResult result = new AuctionListItemsResult();
|
||||
if (!packet.ClassFilters.Empty())
|
||||
{
|
||||
filters.HasValue = true;
|
||||
|
||||
foreach (var classFilter in packet.ClassFilters)
|
||||
{
|
||||
if (!classFilter.SubClassFilters.Empty())
|
||||
{
|
||||
foreach (var subClassFilter in classFilter.SubClassFilters)
|
||||
{
|
||||
filters.Value.Classes[classFilter.ItemClass].SubclassMask |= (AuctionSearchFilters.FilterType)(1 << subClassFilter.ItemSubclass);
|
||||
filters.Value.Classes[classFilter.ItemClass].InvTypes[subClassFilter.ItemSubclass] = subClassFilter.InvTypeMask;
|
||||
}
|
||||
}
|
||||
else
|
||||
filters.Value.Classes[classFilter.ItemClass].SubclassMask = AuctionSearchFilters.FilterType.SkipSubclass;
|
||||
}
|
||||
}
|
||||
|
||||
auctionHouse.BuildListAuctionItems(result, GetPlayer(), packet.Name.ToLower(), packet.Offset, packet.MinLevel, packet.MaxLevel, packet.OnlyUsable, filters, packet.Quality);
|
||||
|
||||
result.DesiredDelay = WorldConfig.GetUIntValue(WorldCfg.AuctionSearchDelay);
|
||||
result.OnlyUsable = packet.OnlyUsable;
|
||||
SendPacket(result);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AuctionListPendingSales)]
|
||||
void HandleAuctionListPendingSales(AuctionListPendingSales packet)
|
||||
{
|
||||
AuctionListPendingSalesResult result = new AuctionListPendingSalesResult();
|
||||
result.TotalNumRecords = 0;
|
||||
SendPacket(result);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AuctionReplicateItems)]
|
||||
void HandleReplicateItems(AuctionReplicateItems packet)
|
||||
{
|
||||
/* Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(packet.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER);
|
||||
if (!creature)
|
||||
{
|
||||
TC_LOG_DEBUG("network", "WORLD: HandleReplicateItems - {0} not found or you can't interact with him.", packet.Auctioneer.ToString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
|
||||
|
||||
WorldPackets::AuctionHouse::AuctionReplicateResponse response;
|
||||
|
||||
auctionHouse->BuildReplicate(response, GetPlayer(), packet.ChangeNumberGlobal, packet.ChangeNumberCursor, packet.ChangeNumberTombstone, packet.Count);
|
||||
*/
|
||||
//@todo implement this properly
|
||||
AuctionReplicateResponse response = new AuctionReplicateResponse();
|
||||
response.ChangeNumberCursor = packet.ChangeNumberCursor;
|
||||
response.ChangeNumberGlobal = packet.ChangeNumberGlobal;
|
||||
response.ChangeNumberTombstone = packet.ChangeNumberTombstone;
|
||||
response.DesiredDelay = WorldConfig.GetUIntValue(WorldCfg.AuctionSearchDelay) * 5;
|
||||
response.Result = 0;
|
||||
SendPacket(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
public void SendAuthResponse(BattlenetRpcErrorCode code, bool queued, uint queuePos = 0)
|
||||
{
|
||||
AuthResponse response = new AuthResponse();
|
||||
response.Result = code;
|
||||
|
||||
if (code == BattlenetRpcErrorCode.Ok)
|
||||
{
|
||||
response.SuccessInfo.HasValue = true;
|
||||
|
||||
response.SuccessInfo.Value = new AuthResponse.AuthSuccessInfo();
|
||||
response.SuccessInfo.Value.AccountExpansionLevel = (byte)GetExpansion();
|
||||
response.SuccessInfo.Value.ActiveExpansionLevel = (byte)GetExpansion();
|
||||
response.SuccessInfo.Value.VirtualRealmAddress = Global.WorldMgr.GetVirtualRealmAddress();
|
||||
response.SuccessInfo.Value.Time = (uint)Time.UnixTime;
|
||||
|
||||
var realm = Global.WorldMgr.GetRealm();
|
||||
|
||||
// Send current home realm. Also there is no need to send it later in realm queries.
|
||||
response.SuccessInfo.Value.VirtualRealms.Add(new VirtualRealmInfo(realm.Id.GetAddress(), true, false, realm.Name, realm.NormalizedName));
|
||||
|
||||
if (HasPermission(RBACPermissions.UseCharacterTemplates))
|
||||
foreach (var templ in Global.CharacterTemplateDataStorage.GetCharacterTemplates().Values)
|
||||
response.SuccessInfo.Value.Templates.Add(templ);
|
||||
|
||||
response.SuccessInfo.Value.AvailableClasses = Global.ObjectMgr.GetClassExpansionRequirements();
|
||||
response.SuccessInfo.Value.AvailableRaces = Global.ObjectMgr.GetRaceExpansionRequirements();
|
||||
}
|
||||
|
||||
if (queued)
|
||||
{
|
||||
response.WaitInfo.HasValue = true;
|
||||
response.WaitInfo.Value.WaitCount = queuePos;
|
||||
}
|
||||
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
public void SendAuthWaitQue(uint position)
|
||||
{
|
||||
if (position != 0)
|
||||
{
|
||||
WaitQueueUpdate waitQueueUpdate = new WaitQueueUpdate();
|
||||
waitQueueUpdate.WaitInfo.WaitCount = position;
|
||||
waitQueueUpdate.WaitInfo.WaitTime = 0;
|
||||
waitQueueUpdate.WaitInfo.HasFCM = false;
|
||||
SendPacket(waitQueueUpdate);
|
||||
}
|
||||
else
|
||||
SendPacket(new WaitQueueFinish());
|
||||
}
|
||||
|
||||
public void SendClientCacheVersion(uint version)
|
||||
{
|
||||
ClientCacheVersion cache = new ClientCacheVersion();
|
||||
cache.CacheVersion = version;
|
||||
SendPacket(cache);//enabled it
|
||||
}
|
||||
|
||||
public void SendSetTimeZoneInformation()
|
||||
{
|
||||
/// @todo: replace dummy values
|
||||
SetTimeZoneInformation packet = new SetTimeZoneInformation();
|
||||
packet.ServerTimeTZ = "Europe/Paris";
|
||||
packet.GameTimeTZ = "Europe/Paris";
|
||||
|
||||
SendPacket(packet);//enabled it
|
||||
}
|
||||
|
||||
public void SendFeatureSystemStatusGlueScreen()
|
||||
{
|
||||
FeatureSystemStatusGlueScreen features = new FeatureSystemStatusGlueScreen();
|
||||
features.BpayStoreAvailable = false;
|
||||
features.BpayStoreDisabledByParentalControls = false;
|
||||
features.CharUndeleteEnabled = WorldConfig.GetBoolValue(WorldCfg.FeatureSystemCharacterUndeleteEnabled);
|
||||
features.BpayStoreEnabled = WorldConfig.GetBoolValue(WorldCfg.FeatureSystemBpayStoreEnabled);
|
||||
|
||||
SendPacket(features);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.AutobankItem)]
|
||||
void HandleAutoBankItem(AutoBankItem packet)
|
||||
{
|
||||
if (!CanUseBank())
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleAutoBankItemOpcode - {0} not found or you can't interact with him.", m_currentBankerGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
Item item = GetPlayer().GetItemByPos(packet.Bag, packet.Slot);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
List<ItemPosCount> dest = new List<ItemPosCount>();
|
||||
InventoryResult msg = GetPlayer().CanBankItem(ItemConst.NullBag, ItemConst.NullSlot, dest, item, false);
|
||||
if (msg != InventoryResult.Ok)
|
||||
{
|
||||
GetPlayer().SendEquipError(msg, item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dest.Count == 1 && dest[0].pos == item.GetPos())
|
||||
{
|
||||
GetPlayer().SendEquipError(InventoryResult.CantSwap, item);
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().RemoveItem(packet.Bag, packet.Slot, true);
|
||||
GetPlayer().ItemRemovedQuestCheck(item.GetEntry(), item.GetCount());
|
||||
GetPlayer().BankItem(dest, item, true);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BankerActivate)]
|
||||
void HandleBankerActivate(Hello packet)
|
||||
{
|
||||
Creature unit = GetPlayer().GetNPCIfCanInteractWith(packet.Unit, NPCFlags.Banker);
|
||||
if (!unit)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandleBankerActivate: {0} not found or you can not interact with him.", packet.Unit.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
SendShowBank(packet.Unit);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AutostoreBankItem)]
|
||||
void HandleAutoStoreBankItem(AutoStoreBankItem packet)
|
||||
{
|
||||
if (!CanUseBank())
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleAutoBankItemOpcode - {0} not found or you can't interact with him.", m_currentBankerGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
Item item = GetPlayer().GetItemByPos(packet.Bag, packet.Slot);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
if (Player.IsBankPos(packet.Bag, packet.Slot)) // moving from bank to inventory
|
||||
{
|
||||
List<ItemPosCount> dest = new List<ItemPosCount>();
|
||||
InventoryResult msg = GetPlayer().CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, dest, item, false);
|
||||
if (msg != InventoryResult.Ok)
|
||||
{
|
||||
GetPlayer().SendEquipError(msg, item);
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().RemoveItem(packet.Bag, packet.Slot, true);
|
||||
Item storedItem = GetPlayer().StoreItem(dest, item, true);
|
||||
if (storedItem)
|
||||
GetPlayer().ItemAddedQuestCheck(storedItem.GetEntry(), storedItem.GetCount());
|
||||
}
|
||||
else // moving from inventory to bank
|
||||
{
|
||||
List<ItemPosCount> dest = new List<ItemPosCount>();
|
||||
InventoryResult msg = GetPlayer().CanBankItem(ItemConst.NullBag, ItemConst.NullSlot, dest, item, false);
|
||||
if (msg != InventoryResult.Ok)
|
||||
{
|
||||
GetPlayer().SendEquipError(msg, item);
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().RemoveItem(packet.Bag, packet.Slot, true);
|
||||
GetPlayer().BankItem(dest, item, true);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BuyBankSlot)]
|
||||
void HandleBuyBankSlot(BuyBankSlot packet)
|
||||
{
|
||||
if (!CanUseBank(packet.Guid))
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleBuyBankSlot - {0} not found or you can't interact with him.", packet.Guid.ToString());
|
||||
|
||||
uint slot = GetPlayer().GetBankBagSlotCount();
|
||||
// next slot
|
||||
++slot;
|
||||
|
||||
BankBagSlotPricesRecord slotEntry = CliDB.BankBagSlotPricesStorage.LookupByKey(slot);
|
||||
if (slotEntry == null)
|
||||
return;
|
||||
|
||||
uint price = slotEntry.Cost;
|
||||
if (!GetPlayer().HasEnoughMoney(price))
|
||||
return;
|
||||
|
||||
GetPlayer().SetBankBagSlotCount((byte)slot);
|
||||
GetPlayer().ModifyMoney(-price);
|
||||
GetPlayer().UpdateCriteria(CriteriaTypes.BuyBankSlot);
|
||||
}
|
||||
|
||||
public void SendShowBank(ObjectGuid guid)
|
||||
{
|
||||
m_currentBankerGUID = guid;
|
||||
ShowBank packet = new ShowBank();
|
||||
packet.Guid = guid;
|
||||
SendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.BattleFields;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
/// <summary>
|
||||
/// This send to player windows for invite player to join the war.
|
||||
/// </summary>
|
||||
/// <param name="queueId">The queue id of Bf</param>
|
||||
/// <param name="zoneId">The zone where the battle is (4197 for wg)</param>
|
||||
/// <param name="acceptTime">Time in second that the player have for accept</param>
|
||||
public void SendBfInvitePlayerToWar(ulong queueId, uint zoneId, uint acceptTime)
|
||||
{
|
||||
BFMgrEntryInvite bfMgrEntryInvite = new BFMgrEntryInvite();
|
||||
bfMgrEntryInvite.QueueID = queueId;
|
||||
bfMgrEntryInvite.AreaID = (int)zoneId;
|
||||
bfMgrEntryInvite.ExpireTime = Time.UnixTime + acceptTime;
|
||||
SendPacket(bfMgrEntryInvite);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This send invitation to player to join the queue.
|
||||
/// </summary>
|
||||
/// <param name="queueId">The queue id of Bf</param>
|
||||
/// <param name="battleState">Battlefield State</param>
|
||||
public void SendBfInvitePlayerToQueue(ulong queueId, BattlefieldState battleState)
|
||||
{
|
||||
BFMgrQueueInvite bfMgrQueueInvite = new BFMgrQueueInvite();
|
||||
bfMgrQueueInvite.QueueID = queueId;
|
||||
bfMgrQueueInvite.BattleState = battleState;
|
||||
SendPacket(bfMgrQueueInvite);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This send packet for inform player that he join queue.
|
||||
/// </summary>
|
||||
/// <param name="queueId">The queue id of Bf</param>
|
||||
/// <param name="zoneId">The zone where the battle is (4197 for wg)</param>
|
||||
/// <param name="battleStatus">Battlefield status</param>
|
||||
/// <param name="canQueue">if able to queue</param>
|
||||
/// <param name="loggingIn">on log in send queue status</param>
|
||||
public void SendBfQueueInviteResponse(ulong queueId, uint zoneId, BattlefieldState battleStatus, bool canQueue = true, bool loggingIn = false)
|
||||
{
|
||||
BFMgrQueueRequestResponse bfMgrQueueRequestResponse = new BFMgrQueueRequestResponse();
|
||||
bfMgrQueueRequestResponse.QueueID = queueId;
|
||||
bfMgrQueueRequestResponse.AreaID = (int)zoneId;
|
||||
bfMgrQueueRequestResponse.Result = (sbyte)(canQueue ? 1 : 0);
|
||||
bfMgrQueueRequestResponse.BattleState = battleStatus;
|
||||
bfMgrQueueRequestResponse.LoggingIn = loggingIn;
|
||||
SendPacket(bfMgrQueueRequestResponse);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is call when player accept to join war.
|
||||
/// </summary>
|
||||
/// <param name="queueId">The queue id of Bf</param>
|
||||
/// <param name="relocated">Whether player is added to Bf on the spot or teleported from queue</param>
|
||||
/// <param name="onOffense">Whether player belongs to attacking team or not</param>
|
||||
public void SendBfEntered(ulong queueId, bool relocated, bool onOffense)
|
||||
{
|
||||
BFMgrEntering bfMgrEntering = new BFMgrEntering();
|
||||
bfMgrEntering.ClearedAFK = _player.isAFK();
|
||||
bfMgrEntering.Relocated = relocated;
|
||||
bfMgrEntering.OnOffense = onOffense;
|
||||
bfMgrEntering.QueueID = queueId;
|
||||
SendPacket(bfMgrEntering);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is call when player leave battlefield zone.
|
||||
/// </summary>
|
||||
/// <param name="queueId">The queue id of Bf</param>
|
||||
/// <param name="queueId">The queue id of Bf</param>
|
||||
/// <param name="battleState">Battlefield status</param>
|
||||
/// <param name="relocated">Whether player is added to Bf on the spot or teleported from queue</param>
|
||||
/// <param name="reason">Reason why player left battlefield</param>
|
||||
public void SendBfLeaveMessage(ulong queueId, BattlefieldState battleState, bool relocated, BFLeaveReason reason = BFLeaveReason.Exited)
|
||||
{
|
||||
BFMgrEjected bfMgrEjected = new BFMgrEjected();
|
||||
bfMgrEjected.QueueID = queueId;
|
||||
bfMgrEjected.Reason = reason;
|
||||
bfMgrEjected.BattleState = battleState;
|
||||
bfMgrEjected.Relocated = relocated;
|
||||
SendPacket(bfMgrEjected);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send by client on clicking in accept or refuse of invitation windows for join game.
|
||||
/// </summary>
|
||||
//[WorldPacketHandler(ClientOpcodes.BfMgrEntryInviteResponse)]
|
||||
void HandleBfEntryInviteResponse(BFMgrEntryInviteResponse bfMgrEntryInviteResponse)
|
||||
{
|
||||
BattleField bf = Global.BattleFieldMgr.GetBattlefieldByQueueId(bfMgrEntryInviteResponse.QueueID);
|
||||
if (bf == null)
|
||||
return;
|
||||
|
||||
// If player accept invitation
|
||||
if (bfMgrEntryInviteResponse.AcceptedInvite)
|
||||
{
|
||||
bf.PlayerAcceptInviteToWar(GetPlayer());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetPlayer().GetZoneId() == bf.GetZoneId())
|
||||
bf.KickPlayerFromBattlefield(GetPlayer().GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send by client when he click on accept for queue.
|
||||
/// </summary>
|
||||
//[WorldPacketHandler(ClientOpcodes.BfMgrQueueInviteResponse)]
|
||||
void HandleBfQueueInviteResponse(BFMgrQueueInviteResponse bfMgrQueueInviteResponse)
|
||||
{
|
||||
BattleField bf = Global.BattleFieldMgr.GetBattlefieldByQueueId(bfMgrQueueInviteResponse.QueueID);
|
||||
if (bf == null)
|
||||
return;
|
||||
|
||||
if (bfMgrQueueInviteResponse.AcceptedInvite)
|
||||
bf.PlayerAcceptInviteToQueue(GetPlayer());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send by client when exited battlefield
|
||||
/// </summary>
|
||||
//[WorldPacketHandler(ClientOpcodes.BfMgrQueueExitRequest)]
|
||||
void HandleBfExitRequest(BFMgrQueueExitRequest bfMgrQueueExitRequest)
|
||||
{
|
||||
BattleField bf = Global.BattleFieldMgr.GetBattlefieldByQueueId(bfMgrQueueExitRequest.QueueID);
|
||||
if (bf == null)
|
||||
return;
|
||||
|
||||
bf.AskToLeaveQueue(GetPlayer());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,694 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Arenas;
|
||||
using Game.BattleFields;
|
||||
using Game.BattleGrounds;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.BattlemasterHello)]
|
||||
void HandleBattlemasterHello(Hello hello)
|
||||
{
|
||||
Creature unit = GetPlayer().GetNPCIfCanInteractWith(hello.Unit, NPCFlags.BattleMaster);
|
||||
if (!unit)
|
||||
return;
|
||||
|
||||
// Stop the npc if moving
|
||||
unit.StopMoving();
|
||||
|
||||
BattlegroundTypeId bgTypeId = Global.BattlegroundMgr.GetBattleMasterBG(unit.GetEntry());
|
||||
|
||||
if (!GetPlayer().GetBGAccessByLevel(bgTypeId))
|
||||
{
|
||||
// temp, must be gossip message...
|
||||
SendNotification(CypherStrings.YourBgLevelReqError);
|
||||
return;
|
||||
}
|
||||
|
||||
Global.BattlegroundMgr.SendBattlegroundList(GetPlayer(), hello.Unit, bgTypeId);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BattlemasterJoin)]
|
||||
void HandleBattlemasterJoin(BattlemasterJoin battlemasterJoin)
|
||||
{
|
||||
bool isPremade = false;
|
||||
Group grp = null;
|
||||
|
||||
BattlefieldStatusFailed battlefieldStatusFailed;
|
||||
|
||||
uint bgTypeId_ = (uint)(battlemasterJoin.QueueID & 0xFFFF);
|
||||
if (!CliDB.BattlemasterListStorage.ContainsKey(bgTypeId_))
|
||||
{
|
||||
Log.outError(LogFilter.Network, "Battleground: invalid bgtype ({0}) received. possible cheater? player guid {1}", bgTypeId_, GetPlayer().GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (Global.DisableMgr.IsDisabledFor(DisableType.Battleground, bgTypeId_, null))
|
||||
{
|
||||
GetPlayer().SendSysMessage(CypherStrings.BgDisabled);
|
||||
return;
|
||||
}
|
||||
BattlegroundTypeId bgTypeId = (BattlegroundTypeId)bgTypeId_;
|
||||
|
||||
// can do this, since it's Battleground, not arena
|
||||
BattlegroundQueueTypeId bgQueueTypeId = Global.BattlegroundMgr.BGQueueTypeId(bgTypeId, 0);
|
||||
BattlegroundQueueTypeId bgQueueTypeIdRandom = Global.BattlegroundMgr.BGQueueTypeId(BattlegroundTypeId.RB, 0);
|
||||
|
||||
// ignore if player is already in BG
|
||||
if (GetPlayer().InBattleground())
|
||||
return;
|
||||
|
||||
// get bg instance or bg template if instance not found
|
||||
Battleground bg = Global.BattlegroundMgr.GetBattlegroundTemplate(bgTypeId);
|
||||
if (!bg)
|
||||
return;
|
||||
|
||||
// expected bracket entry
|
||||
PvpDifficultyRecord bracketEntry = Global.DB2Mgr.GetBattlegroundBracketByLevel(bg.GetMapId(), GetPlayer().getLevel());
|
||||
if (bracketEntry == null)
|
||||
return;
|
||||
|
||||
GroupJoinBattlegroundResult err = GroupJoinBattlegroundResult.None;
|
||||
// check queue conditions
|
||||
if (!battlemasterJoin.JoinAsGroup)
|
||||
{
|
||||
if (GetPlayer().isUsingLfg())
|
||||
{
|
||||
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatusFailed, bg, GetPlayer(), 0, 0, GroupJoinBattlegroundResult.LfgCantUseBattleground);
|
||||
SendPacket(battlefieldStatusFailed);
|
||||
return;
|
||||
}
|
||||
|
||||
// check Deserter debuff
|
||||
if (!GetPlayer().CanJoinToBattleground(bg))
|
||||
{
|
||||
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatusFailed, bg, GetPlayer(), 0, 0, GroupJoinBattlegroundResult.Deserters);
|
||||
SendPacket(battlefieldStatusFailed);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer().GetBattlegroundQueueIndex(bgQueueTypeIdRandom) < SharedConst.MaxPlayerBGQueues)
|
||||
{
|
||||
// player is already in random queue
|
||||
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatusFailed, bg, GetPlayer(), 0, 0, GroupJoinBattlegroundResult.InRandomBg);
|
||||
SendPacket(battlefieldStatusFailed);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer().InBattlegroundQueue() && bgTypeId == BattlegroundTypeId.RB)
|
||||
{
|
||||
// player is already in queue, can't start random queue
|
||||
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatusFailed, bg, GetPlayer(), 0, 0, GroupJoinBattlegroundResult.InNonRandomBg);
|
||||
SendPacket(battlefieldStatusFailed);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if already in queue
|
||||
if (GetPlayer().GetBattlegroundQueueIndex(bgQueueTypeId) < SharedConst.MaxPlayerBGQueues)
|
||||
return; // player is already in this queue
|
||||
|
||||
// check if has free queue slots
|
||||
if (!GetPlayer().HasFreeBattlegroundQueueId())
|
||||
{
|
||||
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatusFailed, bg, GetPlayer(), 0, 0, GroupJoinBattlegroundResult.TooManyQueues);
|
||||
SendPacket(battlefieldStatusFailed);
|
||||
return;
|
||||
}
|
||||
|
||||
// check Freeze debuff
|
||||
if (_player.HasAura(9454))
|
||||
return;
|
||||
|
||||
BattlegroundQueue bgQueue = Global.BattlegroundMgr.GetBattlegroundQueue(bgQueueTypeId);
|
||||
GroupQueueInfo ginfo = bgQueue.AddGroup(GetPlayer(), null, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0);
|
||||
|
||||
uint avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry.GetBracketId());
|
||||
uint queueSlot = GetPlayer().AddBattlegroundQueueId(bgQueueTypeId);
|
||||
|
||||
BattlefieldStatusQueued battlefieldStatusQueued;
|
||||
Global.BattlegroundMgr.BuildBattlegroundStatusQueued(out battlefieldStatusQueued, bg, GetPlayer(), queueSlot, ginfo.JoinTime, avgTime, ginfo.ArenaType, false);
|
||||
SendPacket(battlefieldStatusQueued);
|
||||
|
||||
|
||||
Log.outDebug(LogFilter.Battleground, "Battleground: player joined queue for bg queue type {0} bg type {1}: GUID {2}, NAME {3}",
|
||||
bgQueueTypeId, bgTypeId, GetPlayer().GetGUID().ToString(), GetPlayer().GetName());
|
||||
}
|
||||
else
|
||||
{
|
||||
grp = GetPlayer().GetGroup();
|
||||
|
||||
if (!grp)
|
||||
return;
|
||||
|
||||
if (grp.GetLeaderGUID() != GetPlayer().GetGUID())
|
||||
return;
|
||||
|
||||
ObjectGuid errorGuid;
|
||||
err = grp.CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg.GetMaxPlayersPerTeam(), false, 0, out errorGuid);
|
||||
isPremade = (grp.GetMembersCount() >= bg.GetMinPlayersPerTeam());
|
||||
|
||||
BattlegroundQueue bgQueue = Global.BattlegroundMgr.GetBattlegroundQueue(bgQueueTypeId);
|
||||
GroupQueueInfo ginfo = null;
|
||||
uint avgTime = 0;
|
||||
|
||||
if (err == 0)
|
||||
{
|
||||
Log.outDebug(LogFilter.Battleground, "Battleground: the following players are joining as group:");
|
||||
ginfo = bgQueue.AddGroup(GetPlayer(), grp, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0);
|
||||
avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry.GetBracketId());
|
||||
}
|
||||
|
||||
for (GroupReference refe = grp.GetFirstMember(); refe != null; refe = refe.next())
|
||||
{
|
||||
Player member = refe.GetSource();
|
||||
if (!member)
|
||||
continue; // this should never happen
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
BattlefieldStatusFailed battlefieldStatus;
|
||||
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatus, bg, GetPlayer(), 0, 0, err, errorGuid);
|
||||
member.SendPacket(battlefieldStatus);
|
||||
continue;
|
||||
}
|
||||
|
||||
// add to queue
|
||||
uint queueSlot = member.AddBattlegroundQueueId(bgQueueTypeId);
|
||||
|
||||
BattlefieldStatusQueued battlefieldStatusQueued;
|
||||
Global.BattlegroundMgr.BuildBattlegroundStatusQueued(out battlefieldStatusQueued, bg, member, queueSlot, ginfo.JoinTime, avgTime, ginfo.ArenaType, true);
|
||||
member.SendPacket(battlefieldStatusQueued);
|
||||
Log.outDebug(LogFilter.Battleground, "Battleground: player joined queue for bg queue type {0} bg type {1}: GUID {2}, NAME {3}",
|
||||
bgQueueTypeId, bgTypeId, member.GetGUID().ToString(), member.GetName());
|
||||
}
|
||||
Log.outDebug(LogFilter.Battleground, "Battleground: group end");
|
||||
}
|
||||
|
||||
Global.BattlegroundMgr.ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, bracketEntry.GetBracketId());
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PvpLogData)]
|
||||
void HandlePVPLogData(PVPLogDataRequest packet)
|
||||
{
|
||||
Battleground bg = GetPlayer().GetBattleground();
|
||||
if (!bg)
|
||||
return;
|
||||
|
||||
// Prevent players from sending BuildPvpLogDataPacket in an arena except for when sent in Battleground.EndBattleground.
|
||||
if (bg.isArena())
|
||||
return;
|
||||
|
||||
PVPLogData pvpLogData;
|
||||
bg.BuildPvPLogDataPacket(out pvpLogData);
|
||||
SendPacket(pvpLogData);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BattlefieldList)]
|
||||
void HandleBattlefieldList(BattlefieldListRequest battlefieldList)
|
||||
{
|
||||
BattlemasterListRecord bl = CliDB.BattlemasterListStorage.LookupByKey(battlefieldList.ListID);
|
||||
if (bl == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Battleground, "BattlegroundHandler: invalid bgtype ({0}) with player (Name: {1}, GUID: {2}) received.", battlefieldList.ListID, GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
Global.BattlegroundMgr.SendBattlegroundList(GetPlayer(), ObjectGuid.Empty, (BattlegroundTypeId)battlefieldList.ListID);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BattlefieldPort)]
|
||||
void HandleBattleFieldPort(BattlefieldPort battlefieldPort)
|
||||
{
|
||||
if (!GetPlayer().InBattlegroundQueue())
|
||||
{
|
||||
Log.outDebug(LogFilter.Battleground, "CMSG_BATTLEFIELD_PORT {0} Slot: {1}, Unk: {2}, Time: {3}, AcceptedInvite: {4}. Player not in queue!",
|
||||
GetPlayerInfo(), battlefieldPort.Ticket.Id, battlefieldPort.Ticket.Type, battlefieldPort.Ticket.Time, battlefieldPort.AcceptedInvite);
|
||||
return;
|
||||
}
|
||||
|
||||
BattlegroundQueueTypeId bgQueueTypeId = GetPlayer().GetBattlegroundQueueTypeId(battlefieldPort.Ticket.Id);
|
||||
if (bgQueueTypeId == BattlegroundQueueTypeId.None)
|
||||
{
|
||||
Log.outDebug(LogFilter.Battleground, "CMSG_BATTLEFIELD_PORT {0} Slot: {1}, Unk: {2}, Time: {3}, AcceptedInvite: {4}. Invalid queueSlot!",
|
||||
GetPlayerInfo(), battlefieldPort.Ticket.Id, battlefieldPort.Ticket.Type, battlefieldPort.Ticket.Time, battlefieldPort.AcceptedInvite);
|
||||
return;
|
||||
}
|
||||
|
||||
BattlegroundQueue bgQueue = Global.BattlegroundMgr.GetBattlegroundQueue(bgQueueTypeId);
|
||||
|
||||
//we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattlegroundQueue.RemovePlayer() function
|
||||
GroupQueueInfo ginfo;
|
||||
if (!bgQueue.GetPlayerGroupInfoData(GetPlayer().GetGUID(), out ginfo))
|
||||
{
|
||||
Log.outDebug(LogFilter.Battleground, "CMSG_BATTLEFIELD_PORT {0} Slot: {1}, Unk: {2}, Time: {3}, AcceptedInvite: {4}. Player not in queue (No player Group Info)!",
|
||||
GetPlayerInfo(), battlefieldPort.Ticket.Id, battlefieldPort.Ticket.Type, battlefieldPort.Ticket.Time, battlefieldPort.AcceptedInvite);
|
||||
return;
|
||||
}
|
||||
// if action == 1, then instanceId is required
|
||||
if (ginfo.IsInvitedToBGInstanceGUID == 0 && battlefieldPort.AcceptedInvite)
|
||||
{
|
||||
Log.outDebug(LogFilter.Battleground, "CMSG_BATTLEFIELD_PORT {0} Slot: {1}, Unk: {2}, Time: {3}, AcceptedInvite: {4}. Player is not invited to any bg!",
|
||||
GetPlayerInfo(), battlefieldPort.Ticket.Id, battlefieldPort.Ticket.Type, battlefieldPort.Ticket.Time, battlefieldPort.AcceptedInvite);
|
||||
return;
|
||||
}
|
||||
|
||||
BattlegroundTypeId bgTypeId = Global.BattlegroundMgr.BGTemplateId(bgQueueTypeId);
|
||||
// BGTemplateId returns Battleground_AA when it is arena queue.
|
||||
// Do instance id search as there is no AA bg instances.
|
||||
Battleground bg = Global.BattlegroundMgr.GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId == BattlegroundTypeId.AA ? BattlegroundTypeId.None : bgTypeId);
|
||||
if (!bg)
|
||||
{
|
||||
if (battlefieldPort.AcceptedInvite)
|
||||
{
|
||||
Log.outDebug(LogFilter.Battleground, "CMSG_BATTLEFIELD_PORT {0} Slot: {1}, Unk: {2}, Time: {3}, AcceptedInvite: {4}. Cant find BG with id {5}!",
|
||||
GetPlayerInfo(), battlefieldPort.Ticket.Id, battlefieldPort.Ticket.Type, battlefieldPort.Ticket.Time, battlefieldPort.AcceptedInvite, ginfo.IsInvitedToBGInstanceGUID);
|
||||
return;
|
||||
}
|
||||
|
||||
bg = Global.BattlegroundMgr.GetBattlegroundTemplate(bgTypeId);
|
||||
if (!bg)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "BattlegroundHandler: bg_template not found for type id {0}.", bgTypeId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// get real bg type
|
||||
bgTypeId = bg.GetTypeID();
|
||||
|
||||
// expected bracket entry
|
||||
PvpDifficultyRecord bracketEntry = Global.DB2Mgr.GetBattlegroundBracketByLevel(bg.GetMapId(), GetPlayer().getLevel());
|
||||
if (bracketEntry == null)
|
||||
return;
|
||||
|
||||
//some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it
|
||||
if (battlefieldPort.AcceptedInvite && ginfo.ArenaType == 0)
|
||||
{
|
||||
//if player is trying to enter Battleground(not arena!) and he has deserter debuff, we must just remove him from queue
|
||||
if (!GetPlayer().CanJoinToBattleground(bg))
|
||||
{
|
||||
// send bg command result to show nice message
|
||||
BattlefieldStatusFailed battlefieldStatus;
|
||||
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatus, bg, GetPlayer(), battlefieldPort.Ticket.Id, 0, GroupJoinBattlegroundResult.Deserters);
|
||||
SendPacket(battlefieldStatus);
|
||||
battlefieldPort.AcceptedInvite = false;
|
||||
Log.outDebug(LogFilter.Battleground, "Player {0} ({1}) has a deserter debuff, do not port him to Battleground!", GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
|
||||
}
|
||||
//if player don't match Battlegroundmax level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue
|
||||
if (GetPlayer().getLevel() > bg.GetMaxLevel())
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "Player {0} ({1}) has level ({2}) higher than maxlevel ({3}) of Battleground({4})! Do not port him to Battleground!",
|
||||
GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), GetPlayer().getLevel(), bg.GetMaxLevel(), bg.GetTypeID());
|
||||
battlefieldPort.AcceptedInvite = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (battlefieldPort.AcceptedInvite)
|
||||
{
|
||||
// check Freeze debuff
|
||||
if (GetPlayer().HasAura(9454))
|
||||
return;
|
||||
|
||||
if (!GetPlayer().IsInvitedForBattlegroundQueueType(bgQueueTypeId))
|
||||
return; // cheating?
|
||||
|
||||
if (!GetPlayer().InBattleground())
|
||||
GetPlayer().SetBattlegroundEntryPoint();
|
||||
|
||||
// resurrect the player
|
||||
if (!GetPlayer().IsAlive())
|
||||
{
|
||||
GetPlayer().ResurrectPlayer(1.0f);
|
||||
GetPlayer().SpawnCorpseBones();
|
||||
}
|
||||
// stop taxi flight at port
|
||||
if (GetPlayer().IsInFlight())
|
||||
{
|
||||
GetPlayer().GetMotionMaster().MovementExpired();
|
||||
GetPlayer().CleanupAfterTaxiFlight();
|
||||
}
|
||||
|
||||
BattlefieldStatusActive battlefieldStatus;
|
||||
Global.BattlegroundMgr.BuildBattlegroundStatusActive(out battlefieldStatus, bg, GetPlayer(), battlefieldPort.Ticket.Id, GetPlayer().GetBattlegroundQueueJoinTime(bgQueueTypeId), bg.GetArenaType());
|
||||
SendPacket(battlefieldStatus);
|
||||
|
||||
// remove BattlegroundQueue status from BGmgr
|
||||
bgQueue.RemovePlayer(GetPlayer().GetGUID(), false);
|
||||
// this is still needed here if Battleground"jumping" shouldn't add deserter debuff
|
||||
// also this is required to prevent stuck at old Battlegroundafter SetBattlegroundId set to new
|
||||
Battleground currentBg = GetPlayer().GetBattleground();
|
||||
if (currentBg)
|
||||
currentBg.RemovePlayerAtLeave(GetPlayer().GetGUID(), false, true);
|
||||
|
||||
// set the destination instance id
|
||||
GetPlayer().SetBattlegroundId(bg.GetInstanceID(), bgTypeId);
|
||||
// set the destination team
|
||||
GetPlayer().SetBGTeam(ginfo.Team);
|
||||
|
||||
Global.BattlegroundMgr.SendToBattleground(GetPlayer(), ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
|
||||
Log.outDebug(LogFilter.Battleground, "Battleground: player {0} ({1}) joined battle for bg {2}, bgtype {3}, queue type {4}.", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), bg.GetInstanceID(), bg.GetTypeID(), bgQueueTypeId);
|
||||
}
|
||||
else // leave queue
|
||||
{
|
||||
// if player leaves rated arena match before match start, it is counted as he played but he lost
|
||||
if (ginfo.IsRated && ginfo.IsInvitedToBGInstanceGUID != 0)
|
||||
{
|
||||
ArenaTeam at = Global.ArenaTeamMgr.GetArenaTeamById((uint)ginfo.Team);
|
||||
if (at != null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Battleground, "UPDATING memberLost's personal arena rating for {0} by opponents rating: {1}, because he has left queue!", GetPlayer().GetGUID().ToString(), ginfo.OpponentsTeamRating);
|
||||
at.MemberLost(GetPlayer(), ginfo.OpponentsMatchmakerRating);
|
||||
at.SaveToDB();
|
||||
}
|
||||
}
|
||||
BattlefieldStatusNone battlefieldStatus = new BattlefieldStatusNone();
|
||||
battlefieldStatus.Ticket = battlefieldPort.Ticket;
|
||||
SendPacket(battlefieldStatus);
|
||||
|
||||
GetPlayer().RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue.removeplayer, it causes bugs
|
||||
bgQueue.RemovePlayer(GetPlayer().GetGUID(), true);
|
||||
// player left queue, we should update it - do not update Arena Queue
|
||||
if (ginfo.ArenaType == 0)
|
||||
Global.BattlegroundMgr.ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry.GetBracketId());
|
||||
|
||||
Log.outDebug(LogFilter.Battleground, "Battleground: player {0} ({1}) left queue for bgtype {2}, queue type {3}.", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), bg.GetTypeID(), bgQueueTypeId);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BattlefieldLeave)]
|
||||
void HandleBattlefieldLeave(BattlefieldLeave packet)
|
||||
{
|
||||
// not allow leave Battlegroundin combat
|
||||
if (GetPlayer().IsInCombat())
|
||||
{
|
||||
Battleground bg = GetPlayer().GetBattleground();
|
||||
if (bg)
|
||||
if (bg.GetStatus() != BattlegroundStatus.WaitLeave)
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().LeaveBattleground();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestBattlefieldStatus)]
|
||||
void HandleRequestBattlefieldStatus(RequestBattlefieldStatus packet)
|
||||
{
|
||||
// we must update all queues here
|
||||
Battleground bg = null;
|
||||
for (byte i = 0; i < SharedConst.MaxPlayerBGQueues; ++i)
|
||||
{
|
||||
BattlegroundQueueTypeId bgQueueTypeId = GetPlayer().GetBattlegroundQueueTypeId(i);
|
||||
if (bgQueueTypeId == 0)
|
||||
continue;
|
||||
|
||||
BattlegroundTypeId bgTypeId = Global.BattlegroundMgr.BGTemplateId(bgQueueTypeId);
|
||||
ArenaTypes arenaType = Global.BattlegroundMgr.BGArenaType(bgQueueTypeId);
|
||||
if (bgTypeId == GetPlayer().GetBattlegroundTypeId())
|
||||
{
|
||||
bg = GetPlayer().GetBattleground();
|
||||
//i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena
|
||||
//so i must use bg pointer to get that information
|
||||
if (bg && bg.GetArenaType() == arenaType)
|
||||
{
|
||||
BattlefieldStatusActive battlefieldStatus;
|
||||
Global.BattlegroundMgr.BuildBattlegroundStatusActive(out battlefieldStatus, bg, GetPlayer(), i, GetPlayer().GetBattlegroundQueueJoinTime(bgQueueTypeId), arenaType);
|
||||
SendPacket(battlefieldStatus);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//we are sending update to player about queue - he can be invited there!
|
||||
//get GroupQueueInfo for queue status
|
||||
BattlegroundQueue bgQueue = Global.BattlegroundMgr.GetBattlegroundQueue(bgQueueTypeId);
|
||||
GroupQueueInfo ginfo;
|
||||
if (!bgQueue.GetPlayerGroupInfoData(GetPlayer().GetGUID(), out ginfo))
|
||||
continue;
|
||||
|
||||
if (ginfo.IsInvitedToBGInstanceGUID != 0)
|
||||
{
|
||||
bg = Global.BattlegroundMgr.GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
|
||||
if (!bg)
|
||||
continue;
|
||||
|
||||
BattlefieldStatusNeedConfirmation battlefieldStatus;
|
||||
Global.BattlegroundMgr.BuildBattlegroundStatusNeedConfirmation(out battlefieldStatus, bg, GetPlayer(), i, GetPlayer().GetBattlegroundQueueJoinTime(bgQueueTypeId), Time.GetMSTimeDiff(Time.GetMSTime(), ginfo.RemoveInviteTime), arenaType);
|
||||
SendPacket(battlefieldStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
bg = Global.BattlegroundMgr.GetBattlegroundTemplate(bgTypeId);
|
||||
if (!bg)
|
||||
continue;
|
||||
|
||||
// expected bracket entry
|
||||
PvpDifficultyRecord bracketEntry = Global.DB2Mgr.GetBattlegroundBracketByLevel(bg.GetMapId(), GetPlayer().getLevel());
|
||||
if (bracketEntry == null)
|
||||
continue;
|
||||
|
||||
uint avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry.GetBracketId());
|
||||
BattlefieldStatusQueued battlefieldStatus;
|
||||
Global.BattlegroundMgr.BuildBattlegroundStatusQueued(out battlefieldStatus, bg, GetPlayer(), i, GetPlayer().GetBattlegroundQueueJoinTime(bgQueueTypeId), avgTime, arenaType, ginfo.Players.Count > 1);
|
||||
SendPacket(battlefieldStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BattlemasterJoinArena)]
|
||||
void HandleBattlemasterJoinArena(BattlemasterJoinArena packet)
|
||||
{
|
||||
// ignore if we already in BG or BG queue
|
||||
if (GetPlayer().InBattleground())
|
||||
return;
|
||||
|
||||
ArenaTypes arenatype = (ArenaTypes)ArenaTeam.GetTypeBySlot(packet.TeamSizeIndex);
|
||||
|
||||
//check existence
|
||||
Battleground bg = Global.BattlegroundMgr.GetBattlegroundTemplate(BattlegroundTypeId.AA);
|
||||
if (!bg)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "Battleground: template bg (all arenas) not found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Global.DisableMgr.IsDisabledFor(DisableType.Battleground, (uint)BattlegroundTypeId.AA, null))
|
||||
{
|
||||
GetPlayer().SendSysMessage(CypherStrings.ArenaDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
BattlegroundTypeId bgTypeId = bg.GetTypeID();
|
||||
BattlegroundQueueTypeId bgQueueTypeId = Global.BattlegroundMgr.BGQueueTypeId(bgTypeId, arenatype);
|
||||
PvpDifficultyRecord bracketEntry = Global.DB2Mgr.GetBattlegroundBracketByLevel(bg.GetMapId(), GetPlayer().getLevel());
|
||||
if (bracketEntry == null)
|
||||
return;
|
||||
|
||||
Group grp = GetPlayer().GetGroup();
|
||||
// no group found, error
|
||||
if (!grp)
|
||||
return;
|
||||
if (grp.GetLeaderGUID() != GetPlayer().GetGUID())
|
||||
return;
|
||||
|
||||
uint ateamId = GetPlayer().GetArenaTeamId(packet.TeamSizeIndex);
|
||||
// check real arenateam existence only here (if it was moved to group.CanJoin .. () then we would ahve to get it twice)
|
||||
ArenaTeam at = Global.ArenaTeamMgr.GetArenaTeamById(ateamId);
|
||||
if (at == null)
|
||||
{
|
||||
GetPlayer().GetSession().SendNotInArenaTeamPacket(arenatype);
|
||||
return;
|
||||
}
|
||||
|
||||
// get the team rating for queuing
|
||||
uint arenaRating = at.GetRating();
|
||||
uint matchmakerRating = at.GetAverageMMR(grp);
|
||||
// the arenateam id must match for everyone in the group
|
||||
|
||||
if (arenaRating <= 0)
|
||||
arenaRating = 1;
|
||||
|
||||
BattlegroundQueue bgQueue = Global.BattlegroundMgr.GetBattlegroundQueue(bgQueueTypeId);
|
||||
|
||||
uint avgTime = 0;
|
||||
GroupQueueInfo ginfo = null;
|
||||
|
||||
ObjectGuid errorGuid;
|
||||
var err = grp.CanJoinBattlegroundQueue(bg, bgQueueTypeId, (uint)arenatype, (uint)arenatype, true, packet.TeamSizeIndex, out errorGuid);
|
||||
if (err == 0)
|
||||
{
|
||||
Log.outDebug(LogFilter.Battleground, "Battleground: arena team id {0}, leader {1} queued with matchmaker rating {2} for type {3}", GetPlayer().GetArenaTeamId(packet.TeamSizeIndex), GetPlayer().GetName(), matchmakerRating, arenatype);
|
||||
|
||||
ginfo = bgQueue.AddGroup(GetPlayer(), grp, bgTypeId, bracketEntry, arenatype, true, false, arenaRating, matchmakerRating, ateamId);
|
||||
avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry.GetBracketId());
|
||||
}
|
||||
|
||||
for (GroupReference refe = grp.GetFirstMember(); refe != null; refe = refe.next())
|
||||
{
|
||||
Player member = refe.GetSource();
|
||||
if (!member)
|
||||
continue;
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
BattlefieldStatusFailed battlefieldStatus;
|
||||
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatus, bg, GetPlayer(), 0, arenatype, err, errorGuid);
|
||||
member.SendPacket(battlefieldStatus);
|
||||
continue;
|
||||
}
|
||||
|
||||
// add to queue
|
||||
uint queueSlot = member.AddBattlegroundQueueId(bgQueueTypeId);
|
||||
|
||||
BattlefieldStatusQueued battlefieldStatusQueued;
|
||||
Global.BattlegroundMgr.BuildBattlegroundStatusQueued(out battlefieldStatusQueued, bg, member, queueSlot, ginfo.JoinTime, avgTime, arenatype, true);
|
||||
member.SendPacket(battlefieldStatusQueued);
|
||||
|
||||
Log.outDebug(LogFilter.Battleground, "Battleground: player joined queue for arena as group bg queue type {0} bg type {1}: GUID {2}, NAME {3}", bgQueueTypeId, bgTypeId, member.GetGUID().ToString(), member.GetName());
|
||||
}
|
||||
|
||||
Global.BattlegroundMgr.ScheduleQueueUpdate(matchmakerRating, arenatype, bgQueueTypeId, bgTypeId, bracketEntry.GetBracketId());
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ReportPvpPlayerAfk)]
|
||||
void HandleReportPvPAFK(ReportPvPPlayerAFK reportPvPPlayerAFK)
|
||||
{
|
||||
Player reportedPlayer = Global.ObjAccessor.FindPlayer(reportPvPPlayerAFK.Offender);
|
||||
if (!reportedPlayer)
|
||||
{
|
||||
Log.outDebug(LogFilter.Battleground, "WorldSession.HandleReportPvPAFK: player not found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.outDebug(LogFilter.BattlegroundReportPvpAfk, "WorldSession.HandleReportPvPAFK: {0} [IP: {1}] reported {2}", _player.GetName(), _player.GetSession().GetRemoteAddress(), reportedPlayer.GetGUID().ToString());
|
||||
|
||||
reportedPlayer.ReportedAfkBy(GetPlayer());
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestRatedBattlefieldInfo)]
|
||||
void HandleRequestRatedBattlefieldInfo(RequestRatedBattlefieldInfo packet)
|
||||
{
|
||||
/// @Todo: perfome research in this case
|
||||
/// The unk fields are related to arenas
|
||||
WorldPacket data = new WorldPacket(ServerOpcodes.RatedBattlefieldInfo);
|
||||
data.WriteInt32(0); // BgWeeklyWins20vs20
|
||||
data.WriteInt32(0); // BgWeeklyPlayed20vs20
|
||||
data.WriteInt32(0); // BgWeeklyPlayed15vs15
|
||||
data.WriteInt32(0);
|
||||
data.WriteInt32(0); // BgWeeklyWins10vs10
|
||||
data.WriteInt32(0);
|
||||
data.WriteInt32(0);
|
||||
data.WriteInt32(0);
|
||||
data.WriteInt32(0); // BgWeeklyWins15vs15
|
||||
data.WriteInt32(0);
|
||||
data.WriteInt32(0);
|
||||
data.WriteInt32(0);
|
||||
data.WriteInt32(0);
|
||||
data.WriteInt32(0);
|
||||
data.WriteInt32(0);
|
||||
data.WriteInt32(0); // BgWeeklyPlayed10vs10
|
||||
data.WriteInt32(0);
|
||||
data.WriteInt32(0);
|
||||
|
||||
//SendPacket(data);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GetPvpOptionsEnabled, Processing = PacketProcessing.Inplace)]
|
||||
void HandleGetPVPOptionsEnabled(GetPVPOptionsEnabled packet)
|
||||
{
|
||||
// This packet is completely irrelevant, it triggers PVP_TYPES_ENABLED lua event but that is not handled in interface code as of 6.1.2
|
||||
PVPOptionsEnabled pvpOptionsEnabled = new PVPOptionsEnabled();
|
||||
pvpOptionsEnabled.PugBattlegrounds = true;
|
||||
SendPacket(new PVPOptionsEnabled());
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestPvpRewards)]
|
||||
void HandleRequestPvpReward(RequestPVPRewards packet)
|
||||
{
|
||||
GetPlayer().SendPvpRewards();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AreaSpiritHealerQuery)]
|
||||
void HandleAreaSpiritHealerQuery(AreaSpiritHealerQuery areaSpiritHealerQuery)
|
||||
{
|
||||
Creature unit = ObjectAccessor.GetCreature(GetPlayer(), areaSpiritHealerQuery.HealerGuid);
|
||||
if (!unit)
|
||||
return;
|
||||
|
||||
if (!unit.IsSpiritService()) // it's not spirit service
|
||||
return;
|
||||
|
||||
Battleground bg = GetPlayer().GetBattleground();
|
||||
if (bg != null)
|
||||
Global.BattlegroundMgr.SendAreaSpiritHealerQuery(GetPlayer(), bg, areaSpiritHealerQuery.HealerGuid);
|
||||
|
||||
BattleField bf = Global.BattleFieldMgr.GetBattlefieldToZoneId(GetPlayer().GetZoneId());
|
||||
if (bf != null)
|
||||
bf.SendAreaSpiritHealerQuery(GetPlayer(), areaSpiritHealerQuery.HealerGuid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AreaSpiritHealerQueue)]
|
||||
void HandleAreaSpiritHealerQueue(AreaSpiritHealerQueue areaSpiritHealerQueue)
|
||||
{
|
||||
Creature unit = ObjectAccessor.GetCreature(GetPlayer(), areaSpiritHealerQueue.HealerGuid);
|
||||
if (!unit)
|
||||
return;
|
||||
|
||||
if (!unit.IsSpiritService()) // it's not spirit service
|
||||
return;
|
||||
|
||||
Battleground bg = GetPlayer().GetBattleground();
|
||||
if (bg)
|
||||
bg.AddPlayerToResurrectQueue(areaSpiritHealerQueue.HealerGuid, GetPlayer().GetGUID());
|
||||
|
||||
BattleField bf = Global.BattleFieldMgr.GetBattlefieldToZoneId(GetPlayer().GetZoneId());
|
||||
if (bf != null)
|
||||
bf.AddPlayerToResurrectQueue(areaSpiritHealerQueue.HealerGuid, GetPlayer().GetGUID());
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.HearthAndResurrect)]
|
||||
void HandleHearthAndResurrect(HearthAndResurrect packet)
|
||||
{
|
||||
if (GetPlayer().IsInFlight())
|
||||
return;
|
||||
|
||||
BattleField bf = Global.BattleFieldMgr.GetBattlefieldToZoneId(GetPlayer().GetZoneId());
|
||||
if (bf != null)
|
||||
{
|
||||
bf.PlayerAskToLeave(_player);
|
||||
return;
|
||||
}
|
||||
|
||||
AreaTableRecord atEntry = CliDB.AreaTableStorage.LookupByKey(GetPlayer().GetAreaId());
|
||||
if (atEntry == null || !atEntry.Flags[0].HasAnyFlag(AreaFlags.CanHearthAndResurrect))
|
||||
return;
|
||||
|
||||
GetPlayer().BuildPlayerRepop();
|
||||
GetPlayer().ResurrectPlayer(1.0f);
|
||||
GetPlayer().TeleportTo(GetPlayer().GetHomebind());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.BattlePets;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.BattlePetRequestJournal)]
|
||||
void HandleBattlePetRequestJournal(BattlePetRequestJournal battlePetRequestJournal)
|
||||
{
|
||||
// TODO: Move this to BattlePetMgr::SendJournal() just to have all packets in one file
|
||||
BattlePetJournal battlePetJournal = new BattlePetJournal();
|
||||
battlePetJournal.Trap = GetBattlePetMgr().GetTrapLevel();
|
||||
|
||||
foreach (var battlePet in GetBattlePetMgr().GetLearnedPets())
|
||||
battlePetJournal.Pets.Add(battlePet.PacketInfo);
|
||||
|
||||
battlePetJournal.Slots = GetBattlePetMgr().GetSlots();
|
||||
SendPacket(battlePetJournal);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BattlePetSetBattleSlot)]
|
||||
void HandleBattlePetSetBattleSlot(BattlePetSetBattleSlot battlePetSetBattleSlot)
|
||||
{
|
||||
BattlePetMgr.BattlePet pet = GetBattlePetMgr().GetPet(battlePetSetBattleSlot.PetGuid);
|
||||
if (pet != null)
|
||||
GetBattlePetMgr().GetSlot(battlePetSetBattleSlot.Slot).Pet = pet.PacketInfo;
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BattlePetModifyName)]
|
||||
void HandleBattlePetModifyName(BattlePetModifyName battlePetModifyName)
|
||||
{
|
||||
BattlePetMgr.BattlePet pet = GetBattlePetMgr().GetPet(battlePetModifyName.PetGuid);
|
||||
if (pet != null)
|
||||
{
|
||||
pet.PacketInfo.Name = battlePetModifyName.Name;
|
||||
|
||||
if (pet.SaveInfo != BattlePetSaveInfo.New)
|
||||
pet.SaveInfo = BattlePetSaveInfo.Changed;
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BattlePetDeletePet)]
|
||||
void HandleBattlePetDeletePet(BattlePetDeletePet battlePetDeletePet)
|
||||
{
|
||||
GetBattlePetMgr().RemovePet(battlePetDeletePet.PetGuid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BattlePetSetFlags)]
|
||||
void HandleBattlePetSetFlags(BattlePetSetFlags battlePetSetFlags)
|
||||
{
|
||||
var pet = GetBattlePetMgr().GetPet(battlePetSetFlags.PetGuid);
|
||||
if (pet != null)
|
||||
{
|
||||
if (battlePetSetFlags.ControlType == FlagsControlType.Apply)
|
||||
pet.PacketInfo.Flags |= (ushort)battlePetSetFlags.Flags;
|
||||
else
|
||||
pet.PacketInfo.Flags &= (ushort)~battlePetSetFlags.Flags;
|
||||
|
||||
if (pet.SaveInfo != BattlePetSaveInfo.New)
|
||||
pet.SaveInfo = BattlePetSaveInfo.Changed;
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CageBattlePet)]
|
||||
void HandleCageBattlePet(CageBattlePet cageBattlePet)
|
||||
{
|
||||
GetBattlePetMgr().CageBattlePet(cageBattlePet.PetGuid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BattlePetSummon, Processing = PacketProcessing.Inplace)]
|
||||
void HandleBattlePetSummon(BattlePetSummon battlePetSummon)
|
||||
{
|
||||
GetBattlePetMgr().SummonPet(battlePetSummon.PetGuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using Google.Protobuf;
|
||||
using System;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.BattlenetRequest, Status = SessionStatus.Authed)]
|
||||
void HandleBattlenetRequest(BattlenetRequest request)
|
||||
{
|
||||
Global.ServiceMgr.Dispatch(this, request.Method.GetServiceHash(), request.Method.Token, request.Method.GetMethodId(), new CodedInputStream(request.Data));
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BattlenetRequestRealmListTicket, Status = SessionStatus.Authed)]
|
||||
void HandleBattlenetRequestRealmListTicket(RequestRealmListTicket requestRealmListTicket)
|
||||
{
|
||||
SetRealmListSecret(requestRealmListTicket.Secret);
|
||||
|
||||
RealmListTicket realmListTicket = new RealmListTicket();
|
||||
realmListTicket.Token = requestRealmListTicket.Token;
|
||||
realmListTicket.Allow = true;
|
||||
realmListTicket.Ticket = new Framework.IO.ByteBuffer();
|
||||
realmListTicket.Ticket.WriteCString("WorldserverRealmListTicket");
|
||||
|
||||
SendPacket(realmListTicket);
|
||||
}
|
||||
|
||||
public void SendBattlenetResponse(uint serviceHash, uint methodId, uint token, IMessage response)
|
||||
{
|
||||
Response bnetResponse = new Response();
|
||||
bnetResponse.BnetStatus = BattlenetRpcErrorCode.Ok;
|
||||
bnetResponse.Method.Type = MathFunctions.MakePair64(methodId, serviceHash);
|
||||
bnetResponse.Method.ObjectId = 1;
|
||||
bnetResponse.Method.Token = token;
|
||||
|
||||
if (response.CalculateSize() != 0)
|
||||
bnetResponse.Data.WriteBytes(response.ToByteArray());
|
||||
|
||||
SendPacket(bnetResponse);
|
||||
}
|
||||
|
||||
public void SendBattlenetResponse(uint serviceHash, uint methodId, uint token, BattlenetRpcErrorCode status)
|
||||
{
|
||||
Response bnetResponse = new Response();
|
||||
bnetResponse.BnetStatus = status;
|
||||
bnetResponse.Method.Type = MathFunctions.MakePair64(methodId, serviceHash);
|
||||
bnetResponse.Method.ObjectId = 1;
|
||||
bnetResponse.Method.Token = token;
|
||||
|
||||
SendPacket(bnetResponse);
|
||||
}
|
||||
|
||||
public void SendBattlenetRequest(uint serviceHash, uint methodId, IMessage request, Action<CodedInputStream> callback)
|
||||
{
|
||||
_battlenetResponseCallbacks[_battlenetRequestToken] = callback;
|
||||
SendBattlenetRequest(serviceHash, methodId, request);
|
||||
}
|
||||
|
||||
public void SendBattlenetRequest(uint serviceHash, uint methodId, IMessage request)
|
||||
{
|
||||
Notification notification = new Notification();
|
||||
notification.Method.Type = MathFunctions.MakePair64(methodId, serviceHash);
|
||||
notification.Method.ObjectId = 1;
|
||||
notification.Method.Token = _battlenetRequestToken++;
|
||||
|
||||
if (request.CalculateSize() != 0)
|
||||
notification.Data.WriteBytes(request.ToByteArray());
|
||||
|
||||
SendPacket(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.BlackMarket;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.BlackMarketOpen)]
|
||||
void HandleBlackMarketOpen(BlackMarketOpen blackMarketOpen)
|
||||
{
|
||||
Creature unit = GetPlayer().GetNPCIfCanInteractWith(blackMarketOpen.Guid, NPCFlags.BlackMarket | NPCFlags.BlackMarketView);
|
||||
if (!unit)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketHello - {0} not found or you can't interact with him.", blackMarketOpen.Guid.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
SendBlackMarketOpenResult(blackMarketOpen.Guid, unit);
|
||||
}
|
||||
|
||||
void SendBlackMarketOpenResult(ObjectGuid guid, Creature auctioneer)
|
||||
{
|
||||
BlackMarketOpenResult packet = new BlackMarketOpenResult();
|
||||
packet.Guid = guid;
|
||||
packet.Enable = Global.BlackMarketMgr.IsEnabled();
|
||||
SendPacket(packet);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BlackMarketRequestItems)]
|
||||
void HandleBlackMarketRequestItems(BlackMarketRequestItems blackMarketRequestItems)
|
||||
{
|
||||
if (!Global.BlackMarketMgr.IsEnabled())
|
||||
return;
|
||||
|
||||
Creature unit = GetPlayer().GetNPCIfCanInteractWith(blackMarketRequestItems.Guid, NPCFlags.BlackMarket | NPCFlags.BlackMarketView);
|
||||
if (!unit)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketRequestItems - {0} not found or you can't interact with him.", blackMarketRequestItems.Guid.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
BlackMarketRequestItemsResult result = new BlackMarketRequestItemsResult();
|
||||
Global.BlackMarketMgr.BuildItemsResponse(result, GetPlayer());
|
||||
SendPacket(result);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BlackMarketBidOnItem)]
|
||||
void HandleBlackMarketBidOnItem(BlackMarketBidOnItem blackMarketBidOnItem)
|
||||
{
|
||||
if (!Global.BlackMarketMgr.IsEnabled())
|
||||
return;
|
||||
|
||||
Player player = GetPlayer();
|
||||
Creature unit = player.GetNPCIfCanInteractWith(blackMarketBidOnItem.Guid, NPCFlags.BlackMarket);
|
||||
if (!unit)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketBidOnItem - {0} not found or you can't interact with him.", blackMarketBidOnItem.Guid.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
BlackMarketEntry entry = Global.BlackMarketMgr.GetAuctionByID(blackMarketBidOnItem.MarketID);
|
||||
if (entry == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketBidOnItem - {0} (name: {1}) tried to bid on a nonexistent auction (MarketId: {2}).", player.GetGUID().ToString(), player.GetName(), blackMarketBidOnItem.MarketID);
|
||||
SendBlackMarketBidOnItemResult(BlackMarketError.ItemNotFound, blackMarketBidOnItem.MarketID, blackMarketBidOnItem.Item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.GetBidder() == player.GetGUID().GetCounter())
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketBidOnItem - {0} (name: {1}) tried to place a bid on an item he already bid on. (MarketId: {2}).", player.GetGUID().ToString(), player.GetName(), blackMarketBidOnItem.MarketID);
|
||||
SendBlackMarketBidOnItemResult(BlackMarketError.AlreadyBid, blackMarketBidOnItem.MarketID, blackMarketBidOnItem.Item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!entry.ValidateBid(blackMarketBidOnItem.BidAmount))
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketBidOnItem - {0} (name: {1}) tried to place an invalid bid. Amount: {2} (MarketId: {3}).", player.GetGUID().ToString(), player.GetName(), blackMarketBidOnItem.BidAmount, blackMarketBidOnItem.MarketID);
|
||||
SendBlackMarketBidOnItemResult(BlackMarketError.HigherBid, blackMarketBidOnItem.MarketID, blackMarketBidOnItem.Item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.HasEnoughMoney(blackMarketBidOnItem.BidAmount))
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketBidOnItem - {0} (name: {1}) does not have enough money to place bid. (MarketId: {2}).", player.GetGUID().ToString(), player.GetName(), blackMarketBidOnItem.MarketID);
|
||||
SendBlackMarketBidOnItemResult(BlackMarketError.NotEnoughMoney, blackMarketBidOnItem.MarketID, blackMarketBidOnItem.Item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.GetSecondsRemaining() <= 0)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketBidOnItem - {0} (name: {1}) tried to bid on a completed auction. (MarketId: {2}).", player.GetGUID().ToString(), player.GetName(), blackMarketBidOnItem.MarketID);
|
||||
SendBlackMarketBidOnItemResult(BlackMarketError.DatabaseError, blackMarketBidOnItem.MarketID, blackMarketBidOnItem.Item);
|
||||
return;
|
||||
}
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
|
||||
Global.BlackMarketMgr.SendAuctionOutbidMail(entry, trans);
|
||||
entry.PlaceBid(blackMarketBidOnItem.BidAmount, player, trans);
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
SendBlackMarketBidOnItemResult(BlackMarketError.Ok, blackMarketBidOnItem.MarketID, blackMarketBidOnItem.Item);
|
||||
}
|
||||
|
||||
void SendBlackMarketBidOnItemResult(BlackMarketError result, uint marketId, ItemInstance item)
|
||||
{
|
||||
BlackMarketBidOnItemResult packet = new BlackMarketBidOnItemResult();
|
||||
|
||||
packet.MarketID = marketId;
|
||||
packet.Item = item;
|
||||
packet.Result = result;
|
||||
|
||||
SendPacket(packet);
|
||||
}
|
||||
|
||||
public void SendBlackMarketWonNotification(BlackMarketEntry entry, Item item)
|
||||
{
|
||||
BlackMarketWon packet = new BlackMarketWon();
|
||||
|
||||
packet.MarketID = entry.GetMarketId();
|
||||
packet.Item = new ItemInstance(item);
|
||||
packet.RandomPropertiesID = item.GetItemRandomPropertyId();
|
||||
|
||||
SendPacket(packet);
|
||||
}
|
||||
|
||||
public void SendBlackMarketOutbidNotification(BlackMarketTemplate templ)
|
||||
{
|
||||
BlackMarketOutbid packet = new BlackMarketOutbid();
|
||||
|
||||
packet.MarketID = templ.MarketID;
|
||||
packet.Item = templ.Item;
|
||||
packet.RandomPropertiesID = templ.Item.RandomPropertiesID;
|
||||
|
||||
SendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,524 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.Entities;
|
||||
using Game.Guilds;
|
||||
using Game.Maps;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.CalendarGet)]
|
||||
void HandleCalendarGetCalendar(CalendarGetCalendar calendarGetCalendar)
|
||||
{
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
|
||||
long currTime = Time.UnixTime;
|
||||
|
||||
CalendarSendCalendar packet = new CalendarSendCalendar();
|
||||
packet.ServerTime = currTime;
|
||||
|
||||
var invites = Global.CalendarMgr.GetPlayerInvites(guid);
|
||||
foreach (var invite in invites)
|
||||
{
|
||||
CalendarSendCalendarInviteInfo inviteInfo = new CalendarSendCalendarInviteInfo();
|
||||
inviteInfo.EventID = invite.EventId;
|
||||
inviteInfo.InviteID = invite.InviteId;
|
||||
inviteInfo.InviterGuid = invite.SenderGuid;
|
||||
inviteInfo.Status = invite.Status;
|
||||
inviteInfo.Moderator = invite.Rank;
|
||||
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(invite.EventId);
|
||||
if (calendarEvent != null)
|
||||
inviteInfo.InviteType = (byte)(calendarEvent.IsGuildEvent() && calendarEvent.GuildId == _player.GetGuildId() ? 1 : 0);
|
||||
|
||||
packet.Invites.Add(inviteInfo);
|
||||
}
|
||||
|
||||
var playerEvents = Global.CalendarMgr.GetPlayerEvents(guid);
|
||||
foreach (var calendarEvent in playerEvents)
|
||||
{
|
||||
CalendarSendCalendarEventInfo eventInfo;
|
||||
eventInfo.EventID = calendarEvent.EventId;
|
||||
eventInfo.Date = calendarEvent.Date;
|
||||
Guild guild = Global.GuildMgr.GetGuildById(calendarEvent.GuildId);
|
||||
eventInfo.EventGuildID = guild ? guild.GetGUID() : ObjectGuid.Empty;
|
||||
eventInfo.EventName = calendarEvent.Title;
|
||||
eventInfo.EventType = calendarEvent.EventType;
|
||||
eventInfo.Flags = calendarEvent.Flags;
|
||||
eventInfo.OwnerGuid = calendarEvent.OwnerGuid;
|
||||
eventInfo.TextureID = calendarEvent.TextureId;
|
||||
|
||||
packet.Events.Add(eventInfo);
|
||||
}
|
||||
|
||||
for (byte i = 0; i < (int)Difficulty.Max; ++i)
|
||||
{
|
||||
var boundInstances = GetPlayer().GetBoundInstances((Difficulty)i);
|
||||
foreach (var pair in boundInstances)
|
||||
{
|
||||
if (pair.Value.perm)
|
||||
{
|
||||
CalendarSendCalendarRaidLockoutInfo lockoutInfo;
|
||||
|
||||
InstanceSave save = pair.Value.save;
|
||||
lockoutInfo.MapID = (int)save.GetMapId();
|
||||
lockoutInfo.DifficultyID = (uint)save.GetDifficultyID();
|
||||
lockoutInfo.ExpireTime = save.GetResetTime() - currTime;
|
||||
lockoutInfo.InstanceID = save.GetInstanceId(); // instance save id as unique instance copy id
|
||||
|
||||
packet.RaidLockouts.Add(lockoutInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SendPacket(packet);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CalendarGetEvent)]
|
||||
void HandleCalendarGetEvent(CalendarGetEvent calendarGetEvent)
|
||||
{
|
||||
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarGetEvent.EventID);
|
||||
if (calendarEvent != null)
|
||||
Global.CalendarMgr.SendCalendarEvent(GetPlayer().GetGUID(), calendarEvent, CalendarSendEventType.Get);
|
||||
else
|
||||
Global.CalendarMgr.SendCalendarCommandResult(GetPlayer().GetGUID(), CalendarError.EventInvalid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CalendarGuildFilter)]
|
||||
void HandleCalendarGuildFilter(CalendarGuildFilter calendarGuildFilter)
|
||||
{
|
||||
Guild guild = Global.GuildMgr.GetGuildById(GetPlayer().GetGuildId());
|
||||
if (guild)
|
||||
guild.MassInviteToEvent(this, calendarGuildFilter.MinLevel, calendarGuildFilter.MaxLevel, calendarGuildFilter.MaxRankOrder);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CalendarAddEvent)]
|
||||
void HandleCalendarAddEvent(CalendarAddEvent calendarAddEvent)
|
||||
{
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
|
||||
// prevent events in the past
|
||||
// To Do: properly handle timezones and remove the "- time_t(86400L)" hack
|
||||
if (calendarAddEvent.EventInfo.Time < (Time.UnixTime - 86400L))
|
||||
return;
|
||||
|
||||
CalendarEvent calendarEvent = new CalendarEvent(Global.CalendarMgr.GetFreeEventId(), guid, 0, (CalendarEventType)calendarAddEvent.EventInfo.EventType, calendarAddEvent.EventInfo.TextureID,
|
||||
calendarAddEvent.EventInfo.Time, (CalendarFlags)calendarAddEvent.EventInfo.Flags, calendarAddEvent.EventInfo.Title, calendarAddEvent.EventInfo.Description, 0);
|
||||
|
||||
if (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement())
|
||||
{
|
||||
Player creator = Global.ObjAccessor.FindPlayer(guid);
|
||||
if (creator)
|
||||
calendarEvent.GuildId = creator.GetGuildId();
|
||||
}
|
||||
|
||||
if (calendarEvent.IsGuildAnnouncement())
|
||||
{
|
||||
CalendarInvite invite = new CalendarInvite(0, calendarEvent.EventId, ObjectGuid.Empty, guid, SharedConst.CalendarDefaultResponseTime, CalendarInviteStatus.NotSignedUp, CalendarModerationRank.Player, "");
|
||||
// WARNING: By passing pointer to a local variable, the underlying method(s) must NOT perform any kind
|
||||
// of storage of the pointer as it will lead to memory corruption
|
||||
Global.CalendarMgr.AddInvite(calendarEvent, invite);
|
||||
}
|
||||
else
|
||||
{
|
||||
SQLTransaction trans = null;
|
||||
if (calendarAddEvent.EventInfo.Invites.Length > 1)
|
||||
trans = new SQLTransaction();
|
||||
|
||||
for (int i = 0; i < calendarAddEvent.EventInfo.Invites.Length; ++i)
|
||||
{
|
||||
CalendarInvite invite = new CalendarInvite(Global.CalendarMgr.GetFreeInviteId(), calendarEvent.EventId,
|
||||
calendarAddEvent.EventInfo.Invites[i].Guid, guid, SharedConst.CalendarDefaultResponseTime, (CalendarInviteStatus)calendarAddEvent.EventInfo.Invites[i].Status,
|
||||
(CalendarModerationRank)calendarAddEvent.EventInfo.Invites[i].Moderator, "");
|
||||
Global.CalendarMgr.AddInvite(calendarEvent, invite, trans);
|
||||
}
|
||||
|
||||
if (calendarAddEvent.EventInfo.Invites.Length > 1)
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
Global.CalendarMgr.AddEvent(calendarEvent, CalendarSendEventType.Add);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CalendarUpdateEvent)]
|
||||
void HandleCalendarUpdateEvent(CalendarUpdateEvent calendarUpdateEvent)
|
||||
{
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
long oldEventTime;
|
||||
|
||||
// prevent events in the past
|
||||
// To Do: properly handle timezones and remove the "- time_t(86400L)" hack
|
||||
if (calendarUpdateEvent.EventInfo.Time < (Time.UnixTime - 86400L))
|
||||
return;
|
||||
|
||||
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarUpdateEvent.EventInfo.EventID);
|
||||
if (calendarEvent != null)
|
||||
{
|
||||
oldEventTime = calendarEvent.Date;
|
||||
|
||||
calendarEvent.EventType = (CalendarEventType)calendarUpdateEvent.EventInfo.EventType;
|
||||
calendarEvent.Flags = (CalendarFlags)calendarUpdateEvent.EventInfo.Flags;
|
||||
calendarEvent.Date = calendarUpdateEvent.EventInfo.Time;
|
||||
calendarEvent.TextureId = (int)calendarUpdateEvent.EventInfo.TextureID;
|
||||
calendarEvent.Title = calendarUpdateEvent.EventInfo.Title;
|
||||
calendarEvent.Description = calendarUpdateEvent.EventInfo.Description;
|
||||
|
||||
Global.CalendarMgr.UpdateEvent(calendarEvent);
|
||||
Global.CalendarMgr.SendCalendarEventUpdateAlert(calendarEvent, oldEventTime);
|
||||
}
|
||||
else
|
||||
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventInvalid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CalendarRemoveEvent)]
|
||||
void HandleCalendarRemoveEvent(CalendarRemoveEvent calendarRemoveEvent)
|
||||
{
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
Global.CalendarMgr.RemoveEvent(calendarRemoveEvent.EventID, guid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CalendarCopyEvent)]
|
||||
void HandleCalendarCopyEvent(CalendarCopyEvent calendarCopyEvent)
|
||||
{
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
|
||||
// prevent events in the past
|
||||
// To Do: properly handle timezones and remove the "- time_t(86400L)" hack
|
||||
if (calendarCopyEvent.Date < (Time.UnixTime - 86400L))
|
||||
return;
|
||||
|
||||
CalendarEvent oldEvent = Global.CalendarMgr.GetEvent(calendarCopyEvent.EventID);
|
||||
if (oldEvent == null)
|
||||
{
|
||||
CalendarEvent newEvent = new CalendarEvent(oldEvent, Global.CalendarMgr.GetFreeEventId());
|
||||
newEvent.Date = calendarCopyEvent.Date;
|
||||
Global.CalendarMgr.AddEvent(newEvent, CalendarSendEventType.Copy);
|
||||
|
||||
var invites = Global.CalendarMgr.GetEventInvites(calendarCopyEvent.EventID);
|
||||
SQLTransaction trans = null;
|
||||
if (invites.Count > 1)
|
||||
trans = new SQLTransaction();
|
||||
|
||||
foreach (var invite in invites)
|
||||
Global.CalendarMgr.AddInvite(newEvent, new CalendarInvite(invite, Global.CalendarMgr.GetFreeInviteId(), newEvent.EventId), trans);
|
||||
|
||||
if (invites.Count > 1)
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
// should we change owner when somebody makes a copy of event owned by another person?
|
||||
}
|
||||
else
|
||||
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventInvalid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CalendarEventInvite)]
|
||||
void HandleCalendarEventInvite(CalendarEventInvite calendarEventInvite)
|
||||
{
|
||||
ObjectGuid playerGuid = GetPlayer().GetGUID();
|
||||
|
||||
ObjectGuid inviteeGuid = ObjectGuid.Empty;
|
||||
Team inviteeTeam = 0;
|
||||
ulong inviteeGuildId = 0;
|
||||
|
||||
Player player = Global.ObjAccessor.FindPlayerByName(calendarEventInvite.Name);
|
||||
if (player)
|
||||
{
|
||||
// Invitee is online
|
||||
inviteeGuid = player.GetGUID();
|
||||
inviteeTeam = player.GetTeam();
|
||||
inviteeGuildId = player.GetGuildId();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invitee offline, get data from database
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUID_RACE_ACC_BY_NAME);
|
||||
stmt.AddValue(0, calendarEventInvite.Name);
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
inviteeGuid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
|
||||
inviteeTeam = Player.TeamForRace((Race)result.Read<byte>(1));
|
||||
inviteeGuildId = Player.GetGuildIdFromDB(inviteeGuid);
|
||||
}
|
||||
}
|
||||
|
||||
if (inviteeGuid.IsEmpty())
|
||||
{
|
||||
Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.PlayerNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer().GetTeam() != inviteeTeam && !WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionCalendar))
|
||||
{
|
||||
Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.NotAllied);
|
||||
return;
|
||||
}
|
||||
|
||||
SQLResult result1 = DB.Characters.Query("SELECT flags FROM character_social WHERE guid = {0} AND friend = {1}", inviteeGuid, playerGuid);
|
||||
if (!result1.IsEmpty())
|
||||
{
|
||||
|
||||
if (Convert.ToBoolean(result1.Read<byte>(0) & (byte)SocialFlag.Ignored))
|
||||
{
|
||||
Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.IgnoringYouS, calendarEventInvite.Name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!calendarEventInvite.Creating)
|
||||
{
|
||||
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarEventInvite.EventID);
|
||||
if (calendarEvent != null)
|
||||
{
|
||||
if (calendarEvent.IsGuildEvent() && calendarEvent.GuildId == inviteeGuildId)
|
||||
{
|
||||
// we can't invite guild members to guild events
|
||||
Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.NoGuildInvites);
|
||||
return;
|
||||
}
|
||||
|
||||
CalendarInvite invite = new CalendarInvite(Global.CalendarMgr.GetFreeInviteId(), calendarEventInvite.EventID, inviteeGuid, playerGuid, SharedConst.CalendarDefaultResponseTime, CalendarInviteStatus.Invited, CalendarModerationRank.Player, "");
|
||||
Global.CalendarMgr.AddInvite(calendarEvent, invite);
|
||||
}
|
||||
else
|
||||
Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.EventInvalid);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (calendarEventInvite.IsSignUp && inviteeGuildId == GetPlayer().GetGuildId())
|
||||
{
|
||||
Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.NoGuildInvites);
|
||||
return;
|
||||
}
|
||||
|
||||
CalendarInvite invite = new CalendarInvite(calendarEventInvite.EventID, 0, inviteeGuid, playerGuid, SharedConst.CalendarDefaultResponseTime, CalendarInviteStatus.Invited, CalendarModerationRank.Player, "");
|
||||
Global.CalendarMgr.SendCalendarEventInvite(invite);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CalendarEventSignUp)]
|
||||
void HandleCalendarEventSignup(CalendarEventSignUp calendarEventSignUp)
|
||||
{
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
|
||||
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarEventSignUp.EventID);
|
||||
if (calendarEvent != null)
|
||||
{
|
||||
if (calendarEvent.IsGuildEvent() && calendarEvent.GuildId != GetPlayer().GetGuildId())
|
||||
{
|
||||
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.GuildPlayerNotInGuild);
|
||||
return;
|
||||
}
|
||||
|
||||
CalendarInviteStatus status = calendarEventSignUp.Tentative ? CalendarInviteStatus.Tentative : CalendarInviteStatus.SignedUp;
|
||||
CalendarInvite invite = new CalendarInvite(Global.CalendarMgr.GetFreeInviteId(), calendarEventSignUp.EventID, guid, guid, Time.UnixTime, status, CalendarModerationRank.Player, "");
|
||||
Global.CalendarMgr.AddInvite(calendarEvent, invite);
|
||||
Global.CalendarMgr.SendCalendarClearPendingAction(guid);
|
||||
}
|
||||
else
|
||||
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventInvalid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CalendarEventRsvp)]
|
||||
void HandleCalendarEventRsvp(CalendarEventRSVP calendarEventRSVP)
|
||||
{
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
|
||||
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarEventRSVP.EventID);
|
||||
if (calendarEvent != null)
|
||||
{
|
||||
// i think we still should be able to remove self from locked events
|
||||
if (calendarEventRSVP.Status != CalendarInviteStatus.Removed && calendarEvent.IsLocked())
|
||||
{
|
||||
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventLocked);
|
||||
return;
|
||||
}
|
||||
|
||||
CalendarInvite invite = Global.CalendarMgr.GetInvite(calendarEventRSVP.InviteID);
|
||||
if (invite != null)
|
||||
{
|
||||
invite.Status = calendarEventRSVP.Status;
|
||||
invite.ResponseTime = Time.UnixTime;
|
||||
|
||||
Global.CalendarMgr.UpdateInvite(invite);
|
||||
Global.CalendarMgr.SendCalendarEventStatus(calendarEvent, invite);
|
||||
Global.CalendarMgr.SendCalendarClearPendingAction(guid);
|
||||
}
|
||||
else
|
||||
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.NoInvite); // correct?
|
||||
}
|
||||
else
|
||||
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventInvalid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CalendarRemoveInvite)]
|
||||
void HandleCalendarEventRemoveInvite(CalendarRemoveInvite calendarRemoveInvite)
|
||||
{
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
|
||||
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarRemoveInvite.EventID);
|
||||
if (calendarEvent != null)
|
||||
{
|
||||
if (calendarEvent.OwnerGuid == calendarRemoveInvite.Guid)
|
||||
{
|
||||
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.DeleteCreatorFailed);
|
||||
return;
|
||||
}
|
||||
|
||||
Global.CalendarMgr.RemoveInvite(calendarRemoveInvite.InviteID, calendarRemoveInvite.EventID, guid);
|
||||
}
|
||||
else
|
||||
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.NoInvite);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CalendarEventStatus)]
|
||||
void HandleCalendarEventStatus(CalendarEventStatus calendarEventStatus)
|
||||
{
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
|
||||
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarEventStatus.EventID);
|
||||
if (calendarEvent != null)
|
||||
{
|
||||
CalendarInvite invite = Global.CalendarMgr.GetInvite(calendarEventStatus.InviteID);
|
||||
if (invite != null)
|
||||
{
|
||||
invite.Status = (CalendarInviteStatus)calendarEventStatus.Status;
|
||||
|
||||
Global.CalendarMgr.UpdateInvite(invite);
|
||||
Global.CalendarMgr.SendCalendarEventStatus(calendarEvent, invite);
|
||||
Global.CalendarMgr.SendCalendarClearPendingAction(calendarEventStatus.Guid);
|
||||
}
|
||||
else
|
||||
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.NoInvite); // correct?
|
||||
}
|
||||
else
|
||||
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventInvalid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CalendarEventModeratorStatus)]
|
||||
void HandleCalendarEventModeratorStatus(CalendarEventModeratorStatus calendarEventModeratorStatus)
|
||||
{
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
|
||||
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarEventModeratorStatus.EventID);
|
||||
if (calendarEvent != null)
|
||||
{
|
||||
CalendarInvite invite = Global.CalendarMgr.GetInvite(calendarEventModeratorStatus.InviteID);
|
||||
if (invite != null)
|
||||
{
|
||||
invite.Rank = (CalendarModerationRank)calendarEventModeratorStatus.Status;
|
||||
Global.CalendarMgr.UpdateInvite(invite);
|
||||
Global.CalendarMgr.SendCalendarEventModeratorStatusAlert(calendarEvent, invite);
|
||||
}
|
||||
else
|
||||
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.NoInvite); // correct?
|
||||
}
|
||||
else
|
||||
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventInvalid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CalendarComplain)]
|
||||
void HandleCalendarComplain(CalendarComplain calendarComplain)
|
||||
{
|
||||
// what to do with complains?
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CalendarGetNumPending)]
|
||||
void HandleCalendarGetNumPending(CalendarGetNumPending calendarGetNumPending)
|
||||
{
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
uint pending = Global.CalendarMgr.GetPlayerNumPending(guid);
|
||||
|
||||
SendPacket(new CalendarSendNumPending(pending));
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetSavedInstanceExtend)]
|
||||
void HandleSetSavedInstanceExtend(SetSavedInstanceExtend setSavedInstanceExtend)
|
||||
{
|
||||
Player player = GetPlayer();
|
||||
if (player)
|
||||
{
|
||||
InstanceBind instanceBind = player.GetBoundInstance((uint)setSavedInstanceExtend.MapID, (Difficulty)setSavedInstanceExtend.DifficultyID, setSavedInstanceExtend.Extend); // include expired instances if we are toggling extend on
|
||||
if (instanceBind == null || instanceBind.save == null || !instanceBind.perm)
|
||||
return;
|
||||
|
||||
BindExtensionState newState;
|
||||
if (!setSavedInstanceExtend.Extend || instanceBind.extendState == BindExtensionState.Expired)
|
||||
newState = BindExtensionState.Normal;
|
||||
else
|
||||
newState = BindExtensionState.Extended;
|
||||
|
||||
player.BindToInstance(instanceBind.save, true, newState, false);
|
||||
}
|
||||
/*
|
||||
InstancePlayerBind* instanceBind = GetPlayer().GetBoundInstance(setSavedInstanceExtend.MapID, Difficulty(setSavedInstanceExtend.DifficultyID);
|
||||
if (!instanceBind || !instanceBind.save)
|
||||
return;
|
||||
|
||||
InstanceSave* save = instanceBind.save;
|
||||
// http://www.wowwiki.com/Instance_Lock_Extension
|
||||
// SendCalendarRaidLockoutUpdated(save);
|
||||
*/
|
||||
}
|
||||
|
||||
public void SendCalendarRaidLockout(InstanceSave save, bool add)
|
||||
{
|
||||
long currTime = Time.UnixTime;
|
||||
|
||||
if (add)
|
||||
{
|
||||
CalendarRaidLockoutAdded calendarRaidLockoutAdded = new CalendarRaidLockoutAdded();
|
||||
calendarRaidLockoutAdded.InstanceID = save.GetInstanceId();
|
||||
calendarRaidLockoutAdded.ServerTime = (uint)currTime;
|
||||
calendarRaidLockoutAdded.MapID = (int)save.GetMapId();
|
||||
calendarRaidLockoutAdded.DifficultyID = save.GetDifficultyID();
|
||||
calendarRaidLockoutAdded.TimeRemaining = (int)(save.GetResetTime() - currTime);
|
||||
SendPacket(calendarRaidLockoutAdded);
|
||||
}
|
||||
else
|
||||
{
|
||||
CalendarRaidLockoutRemoved calendarRaidLockoutRemoved = new CalendarRaidLockoutRemoved();
|
||||
calendarRaidLockoutRemoved.InstanceID = save.GetInstanceId();
|
||||
calendarRaidLockoutRemoved.MapID = (int)save.GetMapId();
|
||||
calendarRaidLockoutRemoved.DifficultyID = save.GetDifficultyID();
|
||||
SendPacket(calendarRaidLockoutRemoved);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendCalendarRaidLockoutUpdated(InstanceSave save)
|
||||
{
|
||||
if (save == null)
|
||||
return;
|
||||
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
long currTime = Time.UnixTime;
|
||||
|
||||
CalendarRaidLockoutUpdated packet = new CalendarRaidLockoutUpdated();
|
||||
packet.DifficultyID = (uint)save.GetDifficultyID();
|
||||
packet.MapID = (int)save.GetMapId();
|
||||
packet.NewTimeRemaining = 0; // FIXME
|
||||
packet.OldTimeRemaining = (int)(save.GetResetTime() - currTime);
|
||||
|
||||
SendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Chat;
|
||||
using Game.DataStorage;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.ChatJoinChannel)]
|
||||
void HandleJoinChannel(JoinChannel packet)
|
||||
{
|
||||
AreaTableRecord zone = CliDB.AreaTableStorage.LookupByKey(GetPlayer().GetZoneId());
|
||||
if (packet.ChatChannelId != 0)
|
||||
{
|
||||
ChatChannelsRecord channel = CliDB.ChatChannelsStorage.LookupByKey(packet.ChatChannelId);
|
||||
if (channel == null)
|
||||
return;
|
||||
|
||||
if (zone == null || !GetPlayer().CanJoinConstantChannelInZone(channel, zone))
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(packet.ChannelName))
|
||||
return;
|
||||
|
||||
if (packet.ChannelName.IsNumber())
|
||||
return;
|
||||
|
||||
ChannelManager cMgr = ChannelManager.ForTeam(GetPlayer().GetTeam());
|
||||
if (cMgr != null)
|
||||
{
|
||||
Channel channel = cMgr.GetJoinChannel((uint)packet.ChatChannelId, packet.ChannelName, zone);
|
||||
if (channel != null)
|
||||
channel.JoinChannel(GetPlayer(), packet.Password);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChatLeaveChannel)]
|
||||
void HandleLeaveChannel(LeaveChannel packet)
|
||||
{
|
||||
if (string.IsNullOrEmpty(packet.ChannelName) && packet.ZoneChannelID == 0)
|
||||
return;
|
||||
|
||||
AreaTableRecord zone = CliDB.AreaTableStorage.LookupByKey(GetPlayer().GetZoneId());
|
||||
if (packet.ZoneChannelID != 0)
|
||||
{
|
||||
ChatChannelsRecord channel = CliDB.ChatChannelsStorage.LookupByKey(packet.ZoneChannelID);
|
||||
if (channel == null)
|
||||
return;
|
||||
|
||||
if (zone == null || !GetPlayer().CanJoinConstantChannelInZone(channel, zone))
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelManager cMgr = ChannelManager.ForTeam(GetPlayer().GetTeam());
|
||||
if (cMgr != null)
|
||||
{
|
||||
Channel channel = cMgr.GetChannel((uint)packet.ZoneChannelID, packet.ChannelName, GetPlayer(), true, zone);
|
||||
if (channel != null)
|
||||
channel.LeaveChannel(GetPlayer(), true);
|
||||
|
||||
if (packet.ZoneChannelID != 0)
|
||||
cMgr.LeftChannel((uint)packet.ZoneChannelID, zone);
|
||||
else
|
||||
cMgr.LeftChannel(packet.ChannelName);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelAnnouncements)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelDeclineInvite)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelDisplayList)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelList)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelOwner)]
|
||||
void HandleChannelCommand(ChannelCommand packet)
|
||||
{
|
||||
Channel channel = ChannelManager.GetChannelForPlayerByNamePart(packet.ChannelName, GetPlayer());
|
||||
if (channel == null)
|
||||
return;
|
||||
|
||||
switch (packet.GetOpcode())
|
||||
{
|
||||
case ClientOpcodes.ChatChannelAnnouncements:
|
||||
channel.Announce(GetPlayer());
|
||||
break;
|
||||
case ClientOpcodes.ChatChannelDeclineInvite:
|
||||
channel.DeclineInvite(GetPlayer());
|
||||
break;
|
||||
case ClientOpcodes.ChatChannelDisplayList:
|
||||
case ClientOpcodes.ChatChannelList:
|
||||
channel.List(GetPlayer());
|
||||
break;
|
||||
case ClientOpcodes.ChatChannelOwner:
|
||||
channel.SendWhoOwner(GetPlayer());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelBan)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelInvite)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelKick)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelModerator)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelMute)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelSetOwner)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelSilenceAll)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelUnban)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelUnmoderator)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelUnmute)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelUnsilenceAll)]
|
||||
void HandleChannelPlayerCommand(ChannelPlayerCommand packet)
|
||||
{
|
||||
if (packet.Name.Length >= 49)
|
||||
{
|
||||
Log.outDebug(LogFilter.ChatSystem, "{0} {1} ChannelName: {2}, Name: {3}, Name too long.", packet.GetOpcode(), GetPlayerInfo(), packet.ChannelName, packet.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ObjectManager.NormalizePlayerName(ref packet.Name))
|
||||
return;
|
||||
|
||||
Channel channel = ChannelManager.GetChannelForPlayerByNamePart(packet.ChannelName, GetPlayer());
|
||||
if (channel == null)
|
||||
return;
|
||||
|
||||
switch (packet.GetOpcode())
|
||||
{
|
||||
case ClientOpcodes.ChatChannelBan:
|
||||
channel.Ban(GetPlayer(), packet.Name);
|
||||
break;
|
||||
case ClientOpcodes.ChatChannelInvite:
|
||||
channel.Invite(GetPlayer(), packet.Name);
|
||||
break;
|
||||
case ClientOpcodes.ChatChannelKick:
|
||||
channel.Kick(GetPlayer(), packet.Name);
|
||||
break;
|
||||
case ClientOpcodes.ChatChannelModerator:
|
||||
channel.SetModerator(GetPlayer(), packet.Name);
|
||||
break;
|
||||
case ClientOpcodes.ChatChannelMute:
|
||||
channel.SetMute(GetPlayer(), packet.Name);
|
||||
break;
|
||||
case ClientOpcodes.ChatChannelSetOwner:
|
||||
channel.SetOwner(GetPlayer(), packet.Name);
|
||||
break;
|
||||
case ClientOpcodes.ChatChannelSilenceAll:
|
||||
channel.SilenceAll(GetPlayer(), packet.Name);
|
||||
break;
|
||||
case ClientOpcodes.ChatChannelUnban:
|
||||
channel.UnBan(GetPlayer(), packet.Name);
|
||||
break;
|
||||
case ClientOpcodes.ChatChannelUnmoderator:
|
||||
channel.UnsetModerator(GetPlayer(), packet.Name);
|
||||
break;
|
||||
case ClientOpcodes.ChatChannelUnmute:
|
||||
channel.UnsetMute(GetPlayer(), packet.Name);
|
||||
break;
|
||||
case ClientOpcodes.ChatChannelUnsilenceAll:
|
||||
channel.UnsilenceAll(GetPlayer(), packet.Name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChatChannelPassword)]
|
||||
void HandleChannelPassword(ChannelPassword packet)
|
||||
{
|
||||
if (packet.Password.Length > 31)
|
||||
{
|
||||
Log.outDebug(LogFilter.ChatSystem, "{0} {1} ChannelName: {2}, Password: {3}, Password too long.",
|
||||
packet.GetOpcode(), GetPlayerInfo(), packet.ChannelName, packet.Password);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.outDebug(LogFilter.ChatSystem, "{0} {1} ChannelName: {2}, Password: {3}", packet.GetOpcode(), GetPlayerInfo(), packet.ChannelName, packet.Password);
|
||||
|
||||
Channel channel = ChannelManager.GetChannelForPlayerByNamePart(packet.ChannelName, GetPlayer());
|
||||
if (channel != null)
|
||||
channel.Password(GetPlayer(), packet.Password);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,668 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Chat;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using Game.Guilds;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.ChatMessageGuild)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatMessageOfficer)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatMessageParty)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatMessageRaid)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatMessageRaidWarning)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatMessageSay)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatMessageYell)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatMessageInstanceChat)]
|
||||
void HandleChatMessage(ChatMessage packet)
|
||||
{
|
||||
ChatMsg type;
|
||||
|
||||
switch (packet.GetOpcode())
|
||||
{
|
||||
case ClientOpcodes.ChatMessageSay:
|
||||
type = ChatMsg.Say;
|
||||
break;
|
||||
case ClientOpcodes.ChatMessageYell:
|
||||
type = ChatMsg.Yell;
|
||||
break;
|
||||
case ClientOpcodes.ChatMessageGuild:
|
||||
type = ChatMsg.Guild;
|
||||
break;
|
||||
case ClientOpcodes.ChatMessageOfficer:
|
||||
type = ChatMsg.Officer;
|
||||
break;
|
||||
case ClientOpcodes.ChatMessageParty:
|
||||
type = ChatMsg.Party;
|
||||
break;
|
||||
case ClientOpcodes.ChatMessageRaid:
|
||||
type = ChatMsg.Raid;
|
||||
break;
|
||||
case ClientOpcodes.ChatMessageRaidWarning:
|
||||
type = ChatMsg.RaidWarning;
|
||||
break;
|
||||
case ClientOpcodes.ChatMessageInstanceChat:
|
||||
type = ChatMsg.InstanceChat;
|
||||
break;
|
||||
default:
|
||||
Log.outError(LogFilter.Network, "HandleMessagechatOpcode : Unknown chat opcode ({0})", packet.GetOpcode());
|
||||
return;
|
||||
}
|
||||
|
||||
HandleChat(type, packet.Language, packet.Text);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChatMessageWhisper)]
|
||||
void HandleChatMessageWhisper(ChatMessageWhisper packet)
|
||||
{
|
||||
HandleChat(ChatMsg.Whisper, packet.Language, packet.Text, packet.Target);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChatMessageChannel)]
|
||||
void HandleChatMessageChannel(ChatMessageChannel packet)
|
||||
{
|
||||
HandleChat(ChatMsg.Channel, packet.Language, packet.Text, packet.Target);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChatMessageEmote)]
|
||||
void HandleChatMessageEmote(ChatMessageEmote packet)
|
||||
{
|
||||
HandleChat(ChatMsg.Emote, Language.Universal, packet.Text);
|
||||
}
|
||||
|
||||
void HandleChat(ChatMsg type, Language lang, string msg, string target = "")
|
||||
{
|
||||
Player sender = GetPlayer();
|
||||
|
||||
if (lang == Language.Universal && type != ChatMsg.Emote)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "CMSG_MESSAGECHAT: Possible hacking-attempt: {0} tried to send a message in universal language", GetPlayerInfo());
|
||||
SendNotification(CypherStrings.UnknownLanguage);
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent talking at unknown language (cheating)
|
||||
LanguageDesc langDesc = ObjectManager.GetLanguageDescByID(lang);
|
||||
if (langDesc == null)
|
||||
{
|
||||
SendNotification(CypherStrings.UnknownLanguage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (langDesc.skill_id != 0 && !sender.HasSkill((SkillType)langDesc.skill_id))
|
||||
{
|
||||
// also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language)
|
||||
var langAuras = sender.GetAuraEffectsByType(AuraType.ComprehendLanguage);
|
||||
bool foundAura = false;
|
||||
foreach (var eff in langAuras)
|
||||
{
|
||||
if (eff.GetMiscValue() == (int)lang)
|
||||
{
|
||||
foundAura = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundAura)
|
||||
{
|
||||
SendNotification(CypherStrings.NotLearnedLanguage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// send in universal language if player in .gm on mode (ignore spell effects)
|
||||
if (sender.IsGameMaster())
|
||||
lang = Language.Universal;
|
||||
else
|
||||
{
|
||||
// send in universal language in two side iteration allowed mode
|
||||
if (HasPermission(RBACPermissions.TwoSideInteractionChat))
|
||||
lang = Language.Universal;
|
||||
else
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ChatMsg.Party:
|
||||
case ChatMsg.Raid:
|
||||
case ChatMsg.RaidWarning:
|
||||
// allow two side chat at group channel if two side group allowed
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionGroup))
|
||||
lang = Language.Universal;
|
||||
break;
|
||||
case ChatMsg.Guild:
|
||||
case ChatMsg.Officer:
|
||||
// allow two side chat at guild channel if two side guild allowed
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionGuild))
|
||||
lang = Language.Universal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used)
|
||||
var ModLangAuras = sender.GetAuraEffectsByType(AuraType.ModLanguage);
|
||||
if (!ModLangAuras.Empty())
|
||||
lang = (Language)ModLangAuras.FirstOrDefault().GetMiscValue();
|
||||
}
|
||||
|
||||
if (!sender.CanSpeak())
|
||||
{
|
||||
string timeStr = Time.secsToTimeString((ulong)(m_muteTime - Time.UnixTime));
|
||||
SendNotification(CypherStrings.WaitBeforeSpeaking, timeStr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender.HasAura(1852) && type != ChatMsg.Whisper)
|
||||
{
|
||||
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.GmSilence), sender.GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(msg))
|
||||
return;
|
||||
|
||||
if (new CommandHandler(this).ParseCommand(msg))
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ChatMsg.Say:
|
||||
// Prevent cheating
|
||||
if (!sender.IsAlive())
|
||||
return;
|
||||
|
||||
if (sender.getLevel() < WorldConfig.GetIntValue(WorldCfg.ChatSayLevelReq))
|
||||
{
|
||||
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.SayReq), WorldConfig.GetIntValue(WorldCfg.ChatSayLevelReq));
|
||||
return;
|
||||
}
|
||||
|
||||
sender.Say(msg, lang);
|
||||
break;
|
||||
case ChatMsg.Emote:
|
||||
// Prevent cheating
|
||||
if (!sender.IsAlive())
|
||||
return;
|
||||
|
||||
if (sender.getLevel() < WorldConfig.GetIntValue(WorldCfg.ChatEmoteLevelReq))
|
||||
{
|
||||
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.SayReq), WorldConfig.GetIntValue(WorldCfg.ChatEmoteLevelReq));
|
||||
return;
|
||||
}
|
||||
|
||||
sender.TextEmote(msg);
|
||||
break;
|
||||
case ChatMsg.Yell:
|
||||
// Prevent cheating
|
||||
if (!sender.IsAlive())
|
||||
return;
|
||||
|
||||
if (sender.getLevel() < WorldConfig.GetIntValue(WorldCfg.ChatYellLevelReq))
|
||||
{
|
||||
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.SayReq), WorldConfig.GetIntValue(WorldCfg.ChatYellLevelReq));
|
||||
return;
|
||||
}
|
||||
|
||||
sender.Yell(msg, lang);
|
||||
break;
|
||||
case ChatMsg.Whisper:
|
||||
// @todo implement cross realm whispers (someday)
|
||||
ExtendedPlayerName extName = ObjectManager.ExtractExtendedPlayerName(target);
|
||||
|
||||
if (!ObjectManager.NormalizePlayerName(ref extName.Name))
|
||||
{
|
||||
SendChatPlayerNotfoundNotice(target);
|
||||
break;
|
||||
}
|
||||
|
||||
Player receiver = Global.ObjAccessor.FindPlayerByName(extName.Name);
|
||||
if (!receiver || (lang != Language.Addon && !receiver.isAcceptWhispers() && receiver.GetSession().HasPermission(RBACPermissions.CanFilterWhispers) && !receiver.IsInWhisperWhiteList(sender.GetGUID())))
|
||||
{
|
||||
SendChatPlayerNotfoundNotice(target);
|
||||
return;
|
||||
}
|
||||
if (!sender.IsGameMaster() && sender.getLevel() < WorldConfig.GetIntValue(WorldCfg.ChatWhisperLevelReq) && !receiver.IsInWhisperWhiteList(sender.GetGUID()))
|
||||
{
|
||||
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.WhisperReq), WorldConfig.GetIntValue(WorldCfg.ChatWhisperLevelReq));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer().GetTeam() != receiver.GetTeam() && !HasPermission(RBACPermissions.TwoSideInteractionChat) && !receiver.IsInWhisperWhiteList(sender.GetGUID()))
|
||||
{
|
||||
SendChatPlayerNotfoundNotice(target);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer().HasAura(1852) && !receiver.IsGameMaster())
|
||||
{
|
||||
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.GmSilence), GetPlayer().GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (receiver.getLevel() < WorldConfig.GetIntValue(WorldCfg.ChatWhisperLevelReq) ||
|
||||
(HasPermission(RBACPermissions.CanFilterWhispers) && !sender.isAcceptWhispers() && !sender.IsInWhisperWhiteList(receiver.GetGUID())))
|
||||
sender.AddWhisperWhiteList(receiver.GetGUID());
|
||||
|
||||
GetPlayer().Whisper(msg, lang, receiver);
|
||||
break;
|
||||
case ChatMsg.Party:
|
||||
{
|
||||
// if player is in Battleground, he cannot say to Battlegroundmembers by /p
|
||||
Group group = GetPlayer().GetOriginalGroup();
|
||||
if (!group)
|
||||
{
|
||||
group = GetPlayer().GetGroup();
|
||||
if (!group || group.isBGGroup())
|
||||
return;
|
||||
}
|
||||
|
||||
if (group.IsLeader(GetPlayer().GetGUID()))
|
||||
type = ChatMsg.PartyLeader;
|
||||
|
||||
Global.ScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, group);
|
||||
|
||||
ChatPkt data = new ChatPkt();
|
||||
data.Initialize(type, lang, sender, null, msg);
|
||||
group.BroadcastPacket(data, false, group.GetMemberGroup(GetPlayer().GetGUID()));
|
||||
}
|
||||
break;
|
||||
case ChatMsg.Guild:
|
||||
if (GetPlayer().GetGuildId() != 0)
|
||||
{
|
||||
Guild guild = Global.GuildMgr.GetGuildById(GetPlayer().GetGuildId());
|
||||
if (guild)
|
||||
{
|
||||
Global.ScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, guild);
|
||||
|
||||
guild.BroadcastToGuild(this, false, msg, lang == Language.Addon ? Language.Addon : Language.Universal);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ChatMsg.Officer:
|
||||
if (GetPlayer().GetGuildId() != 0)
|
||||
{
|
||||
Guild guild = Global.GuildMgr.GetGuildById(GetPlayer().GetGuildId());
|
||||
if (guild)
|
||||
{
|
||||
Global.ScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, guild);
|
||||
|
||||
guild.BroadcastToGuild(this, true, msg, lang == Language.Addon ? Language.Addon : Language.Universal);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ChatMsg.Raid:
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group || !group.isRaidGroup() || group.isBGGroup())
|
||||
return;
|
||||
|
||||
if (group.IsLeader(GetPlayer().GetGUID()))
|
||||
type = ChatMsg.RaidLeader;
|
||||
|
||||
Global.ScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, group);
|
||||
|
||||
ChatPkt data = new ChatPkt();
|
||||
data.Initialize(type, lang, sender, null, msg);
|
||||
group.BroadcastPacket(data, false);
|
||||
}
|
||||
break;
|
||||
case ChatMsg.RaidWarning:
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group || !group.isRaidGroup() || !(group.IsLeader(GetPlayer().GetGUID()) || group.IsAssistant(GetPlayer().GetGUID())) || group.isBGGroup())
|
||||
return;
|
||||
|
||||
Global.ScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, group);
|
||||
|
||||
ChatPkt data = new ChatPkt();
|
||||
//in Battleground, raid warning is sent only to players in Battleground - code is ok
|
||||
data.Initialize(ChatMsg.RaidWarning, lang, sender, null, msg);
|
||||
group.BroadcastPacket(data, false);
|
||||
}
|
||||
break;
|
||||
case ChatMsg.Channel:
|
||||
if (!HasPermission(RBACPermissions.SkipCheckChatChannelReq))
|
||||
{
|
||||
if (GetPlayer().getLevel() < WorldConfig.GetIntValue(WorldCfg.ChatChannelLevelReq))
|
||||
{
|
||||
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.ChannelReq), WorldConfig.GetIntValue(WorldCfg.ChatChannelLevelReq));
|
||||
return;
|
||||
}
|
||||
}
|
||||
Channel chn = ChannelManager.GetChannelForPlayerByNamePart(target, sender);
|
||||
if (chn != null)
|
||||
{
|
||||
Global.ScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, chn);
|
||||
chn.Say(GetPlayer().GetGUID(), msg, lang);
|
||||
}
|
||||
break;
|
||||
case ChatMsg.InstanceChat:
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
if (group.IsLeader(GetPlayer().GetGUID()))
|
||||
type = ChatMsg.InstanceChatLeader;
|
||||
|
||||
Global.ScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, group);
|
||||
|
||||
ChatPkt packet = new ChatPkt();
|
||||
packet.Initialize(type, lang, sender, null, msg);
|
||||
group.BroadcastPacket(packet, false);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Log.outError(LogFilter.ChatSystem, "CHAT: unknown message type {0}, lang: {1}", type, lang);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChatAddonMessageGuild)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatAddonMessageOfficer)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatAddonMessageParty)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatAddonMessageRaid)]
|
||||
[WorldPacketHandler(ClientOpcodes.ChatAddonMessageInstanceChat)]
|
||||
void HandleChatAddonMessage(ChatAddonMessage packet)
|
||||
{
|
||||
ChatMsg type;
|
||||
|
||||
switch (packet.GetOpcode())
|
||||
{
|
||||
case ClientOpcodes.ChatAddonMessageGuild:
|
||||
type = ChatMsg.Guild;
|
||||
break;
|
||||
case ClientOpcodes.ChatAddonMessageOfficer:
|
||||
type = ChatMsg.Officer;
|
||||
break;
|
||||
case ClientOpcodes.ChatAddonMessageParty:
|
||||
type = ChatMsg.Party;
|
||||
break;
|
||||
case ClientOpcodes.ChatAddonMessageRaid:
|
||||
type = ChatMsg.Raid;
|
||||
break;
|
||||
case ClientOpcodes.ChatAddonMessageInstanceChat:
|
||||
type = ChatMsg.InstanceChat;
|
||||
break;
|
||||
default:
|
||||
Log.outError(LogFilter.Network, "HandleChatAddonMessage: Unknown addon chat opcode ({0})", packet.GetOpcode());
|
||||
return;
|
||||
}
|
||||
|
||||
HandleChatAddon(type, packet.Prefix, packet.Text);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChatAddonMessageWhisper)]
|
||||
void HandleChatAddonMessageWhisper(ChatAddonMessageWhisper packet)
|
||||
{
|
||||
HandleChatAddon(ChatMsg.Whisper, packet.Prefix, packet.Text, packet.Target);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChatAddonMessageChannel)]
|
||||
void HandleChatAddonMessageChannel(ChatAddonMessageChannel chatAddonMessageChannel)
|
||||
{
|
||||
HandleChatAddon(ChatMsg.Channel, chatAddonMessageChannel.Prefix, chatAddonMessageChannel.Text, chatAddonMessageChannel.Target);
|
||||
}
|
||||
|
||||
void HandleChatAddon(ChatMsg type, string prefix, string text, string target = "")
|
||||
{
|
||||
Player sender = GetPlayer();
|
||||
|
||||
if (string.IsNullOrEmpty(prefix) || prefix.Length > 16)
|
||||
return;
|
||||
|
||||
// Disabled addon channel?
|
||||
if (!WorldConfig.GetBoolValue(WorldCfg.AddonChannel))
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ChatMsg.Guild:
|
||||
case ChatMsg.Officer:
|
||||
if (sender.GetGuildId() != 0)
|
||||
{
|
||||
Guild guild = Global.GuildMgr.GetGuildById(sender.GetGuildId());
|
||||
if (guild)
|
||||
guild.BroadcastAddonToGuild(this, type == ChatMsg.Officer, text, prefix);
|
||||
}
|
||||
break;
|
||||
case ChatMsg.Whisper:
|
||||
/// @todo implement cross realm whispers (someday)
|
||||
ExtendedPlayerName extName = ObjectManager.ExtractExtendedPlayerName(target);
|
||||
|
||||
if (!ObjectManager.NormalizePlayerName(ref extName.Name))
|
||||
break;
|
||||
|
||||
Player receiver = Global.ObjAccessor.FindPlayerByName(extName.Name);
|
||||
if (!receiver)
|
||||
break;
|
||||
|
||||
sender.WhisperAddon(text, prefix, receiver);
|
||||
break;
|
||||
// Messages sent to "RAID" while in a party will get delivered to "PARTY"
|
||||
case ChatMsg.Party:
|
||||
case ChatMsg.Raid:
|
||||
case ChatMsg.InstanceChat:
|
||||
{
|
||||
Group group = null;
|
||||
int subGroup = -1;
|
||||
if (type != ChatMsg.InstanceChat)
|
||||
group = sender.GetOriginalGroup();
|
||||
|
||||
if (!group)
|
||||
{
|
||||
group = sender.GetGroup();
|
||||
if (!group)
|
||||
break;
|
||||
|
||||
if (type == ChatMsg.Party)
|
||||
subGroup = sender.GetSubGroup();
|
||||
}
|
||||
|
||||
ChatPkt data = new ChatPkt();
|
||||
data.Initialize(type, Language.Addon, sender, null, text, 0, "", LocaleConstant.enUS, prefix);
|
||||
group.BroadcastAddonMessagePacket(data, prefix, true, subGroup, sender.GetGUID());
|
||||
break;
|
||||
}
|
||||
case ChatMsg.Channel:
|
||||
Channel chn = ChannelManager.GetChannelForPlayerByNamePart(target, sender);
|
||||
if (chn != null)
|
||||
chn.AddonSay(sender.GetGUID(), prefix, text);
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.outError(LogFilter.Server, "HandleAddonMessagechat: unknown addon message type {0}", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChatMessageAfk)]
|
||||
void HandleChatMessageAFK(ChatMessageAFK packet)
|
||||
{
|
||||
Player sender = GetPlayer();
|
||||
|
||||
if (sender.IsInCombat())
|
||||
return;
|
||||
|
||||
if (sender.HasAura(1852))
|
||||
{
|
||||
SendNotification(CypherStrings.GmSilence, sender.GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender.isAFK()) // Already AFK
|
||||
{
|
||||
if (string.IsNullOrEmpty(packet.Text))
|
||||
sender.ToggleAFK(); // Remove AFK
|
||||
else
|
||||
sender.autoReplyMsg = packet.Text; // Update message
|
||||
}
|
||||
else // New AFK mode
|
||||
{
|
||||
sender.autoReplyMsg = string.IsNullOrEmpty(packet.Text) ? Global.ObjectMgr.GetCypherString(CypherStrings.PlayerAfkDefault) : packet.Text;
|
||||
|
||||
if (sender.isDND())
|
||||
sender.ToggleDND();
|
||||
|
||||
sender.ToggleAFK();
|
||||
}
|
||||
|
||||
Global.ScriptMgr.OnPlayerChat(sender, ChatMsg.Afk, Language.Universal, packet.Text);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChatMessageDnd)]
|
||||
void HandleChatMessageDND(ChatMessageDND packet)
|
||||
{
|
||||
Player sender = GetPlayer();
|
||||
|
||||
if (sender.IsInCombat())
|
||||
return;
|
||||
|
||||
if (sender.HasAura(1852))
|
||||
{
|
||||
SendNotification(CypherStrings.GmSilence, sender.GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender.isDND()) // Already DND
|
||||
{
|
||||
if (string.IsNullOrEmpty(packet.Text))
|
||||
sender.ToggleDND(); // Remove DND
|
||||
else
|
||||
sender.autoReplyMsg = packet.Text; // Update message
|
||||
}
|
||||
else // New DND mode
|
||||
{
|
||||
sender.autoReplyMsg = string.IsNullOrEmpty(packet.Text) ? Global.ObjectMgr.GetCypherString(CypherStrings.PlayerDndDefault) : packet.Text;
|
||||
|
||||
if (sender.isAFK())
|
||||
sender.ToggleAFK();
|
||||
|
||||
sender.ToggleDND();
|
||||
}
|
||||
|
||||
Global.ScriptMgr.OnPlayerChat(sender, ChatMsg.Dnd, Language.Universal, packet.Text);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.Emote)]
|
||||
void HandleEmote(EmoteClient packet)
|
||||
{
|
||||
if (!GetPlayer().IsAlive() || GetPlayer().HasUnitState(UnitState.Died))
|
||||
return;
|
||||
|
||||
Global.ScriptMgr.OnPlayerClearEmote(GetPlayer());
|
||||
if (GetPlayer().GetUInt32Value(UnitFields.NpcEmotestate) != 0)
|
||||
GetPlayer().SetUInt32Value(UnitFields.NpcEmotestate, 0);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SendTextEmote)]
|
||||
void HandleTextEmote(CTextEmote packet)
|
||||
{
|
||||
if (!GetPlayer().IsAlive())
|
||||
return;
|
||||
|
||||
if (!GetPlayer().CanSpeak())
|
||||
{
|
||||
string timeStr = Time.secsToTimeString((ulong)(m_muteTime - Time.UnixTime));
|
||||
SendNotification(CypherStrings.WaitBeforeSpeaking, timeStr);
|
||||
return;
|
||||
}
|
||||
|
||||
Global.ScriptMgr.OnPlayerTextEmote(GetPlayer(), (uint)packet.SoundIndex, (uint)packet.EmoteID, packet.Target);
|
||||
|
||||
EmotesTextRecord em = CliDB.EmotesTextStorage.LookupByKey(packet.EmoteID);
|
||||
if (em == null)
|
||||
return;
|
||||
|
||||
uint emote_anim = em.EmoteID;
|
||||
|
||||
switch ((Emote)emote_anim)
|
||||
{
|
||||
case Emote.StateSleep:
|
||||
case Emote.StateSit:
|
||||
case Emote.StateKneel:
|
||||
case Emote.OneshotNone:
|
||||
break;
|
||||
case Emote.StateDance:
|
||||
case Emote.StateRead:
|
||||
GetPlayer().SetUInt32Value(UnitFields.NpcEmotestate, emote_anim);
|
||||
break;
|
||||
default:
|
||||
// Only allow text-emotes for "dead" entities (feign death included)
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
break;
|
||||
GetPlayer().HandleEmoteCommand((Emote)emote_anim);
|
||||
break;
|
||||
}
|
||||
|
||||
STextEmote textEmote = new STextEmote();
|
||||
textEmote.SourceGUID = GetPlayer().GetGUID();
|
||||
textEmote.SourceAccountGUID = GetAccountGUID();
|
||||
textEmote.TargetGUID = packet.Target;
|
||||
textEmote.EmoteID = packet.EmoteID;
|
||||
textEmote.SoundIndex = packet.SoundIndex;
|
||||
GetPlayer().SendMessageToSetInRange(textEmote, WorldConfig.GetFloatValue(WorldCfg.ListenRangeTextemote), true);
|
||||
|
||||
Unit unit = Global.ObjAccessor.GetUnit(GetPlayer(), packet.Target);
|
||||
|
||||
GetPlayer().UpdateCriteria(CriteriaTypes.DoEmote, (uint)packet.EmoteID, 0, 0, unit);
|
||||
|
||||
// Send scripted event call
|
||||
if (unit)
|
||||
{
|
||||
Creature creature = unit.ToCreature();
|
||||
if (creature)
|
||||
creature.GetAI().ReceiveEmote(GetPlayer(), (TextEmotes)packet.EmoteID);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChatReportIgnored)]
|
||||
void HandleChatIgnoredOpcode(ChatReportIgnored packet)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(packet.IgnoredGUID);
|
||||
if (!player || player.GetSession() == null)
|
||||
return;
|
||||
|
||||
ChatPkt data = new ChatPkt();
|
||||
data.Initialize(ChatMsg.Ignored, Language.Universal, GetPlayer(), GetPlayer(), GetPlayer().GetName());
|
||||
player.SendPacket(data);
|
||||
}
|
||||
|
||||
void SendChatPlayerNotfoundNotice(string name)
|
||||
{
|
||||
SendPacket(new ChatPlayerNotfound(name));
|
||||
}
|
||||
|
||||
void SendPlayerAmbiguousNotice(string name)
|
||||
{
|
||||
SendPacket(new ChatPlayerAmbiguous(name));
|
||||
}
|
||||
|
||||
void SendChatRestricted(ChatRestrictionType restriction)
|
||||
{
|
||||
SendPacket(new ChatRestricted(restriction));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.CollectionItemSetFavorite)]
|
||||
void HandleCollectionItemSetFavorite(CollectionItemSetFavorite collectionItemSetFavorite)
|
||||
{
|
||||
switch (collectionItemSetFavorite.Type)
|
||||
{
|
||||
case CollectionType.Toybox:
|
||||
GetCollectionMgr().ToySetFavorite(collectionItemSetFavorite.ID, collectionItemSetFavorite.IsFavorite);
|
||||
break;
|
||||
case CollectionType.Appearance:
|
||||
{
|
||||
var pair = GetCollectionMgr().HasItemAppearance(collectionItemSetFavorite.ID);
|
||||
if (!pair.Item1 || pair.Item2)
|
||||
return;
|
||||
|
||||
GetCollectionMgr().SetAppearanceIsFavorite(collectionItemSetFavorite.ID, collectionItemSetFavorite.IsFavorite);
|
||||
break;
|
||||
}
|
||||
case CollectionType.TransmogSet:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.AttackSwing, Processing = PacketProcessing.Inplace)]
|
||||
void HandleAttackSwing(AttackSwing packet)
|
||||
{
|
||||
Unit enemy = Global.ObjAccessor.GetUnit(GetPlayer(), packet.Victim);
|
||||
if (!enemy)
|
||||
{
|
||||
// stop attack state at client
|
||||
SendAttackStop(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetPlayer().IsValidAttackTarget(enemy))
|
||||
{
|
||||
// stop attack state at client
|
||||
SendAttackStop(enemy);
|
||||
return;
|
||||
}
|
||||
|
||||
//! Client explicitly checks the following before sending CMSG_ATTACKSWING packet,
|
||||
//! so we'll place the same check here. Note that it might be possible to reuse this snippet
|
||||
//! in other places as well.
|
||||
Vehicle vehicle = GetPlayer().GetVehicle();
|
||||
if (vehicle)
|
||||
{
|
||||
VehicleSeatRecord seat = vehicle.GetSeatForPassenger(GetPlayer());
|
||||
Contract.Assert(seat != null);
|
||||
if (!seat.Flags[0].HasAnyFlag((uint)VehicleSeatFlags.CanAttack))
|
||||
{
|
||||
SendAttackStop(enemy);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GetPlayer().Attack(enemy, true);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AttackStop, Processing = PacketProcessing.Inplace)]
|
||||
void HandleAttackStop(AttackStop packet)
|
||||
{
|
||||
GetPlayer().AttackStop();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetSheathed, Processing = PacketProcessing.Inplace)]
|
||||
void HandleSetSheathed(SetSheathed packet)
|
||||
{
|
||||
if (packet.CurrentSheathState >= (int)SheathState.Max)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "Unknown sheath state {0} ??", packet.CurrentSheathState);
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().SetSheath((SheathState)packet.CurrentSheathState);
|
||||
}
|
||||
|
||||
void SendAttackStop(Unit enemy)
|
||||
{
|
||||
SendPacket(new SAttackStop(GetPlayer(), enemy));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.CanDuel)]
|
||||
void HandleCanDuel(CanDuel packet)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(packet.TargetGUID);
|
||||
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
CanDuelResult response = new CanDuelResult();
|
||||
response.TargetGUID = packet.TargetGUID;
|
||||
response.Result = player.duel == null;
|
||||
SendPacket(response);
|
||||
|
||||
if (response.Result)
|
||||
{
|
||||
if (GetPlayer().IsMounted())
|
||||
GetPlayer().CastSpell(player, 62875);
|
||||
else
|
||||
GetPlayer().CastSpell(player, 7266);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.DuelResponse)]
|
||||
void HandleDuelResponse(DuelResponse duelResponse)
|
||||
{
|
||||
if (duelResponse.Accepted)
|
||||
HandleDuelAccepted();
|
||||
else
|
||||
HandleDuelCancelled();
|
||||
}
|
||||
|
||||
void HandleDuelAccepted()
|
||||
{
|
||||
if (GetPlayer().duel == null) // ignore accept from duel-sender
|
||||
return;
|
||||
|
||||
Player player = GetPlayer();
|
||||
Player plTarget = player.duel.opponent;
|
||||
|
||||
if (player == player.duel.initiator || !plTarget || player == plTarget || player.duel.startTime != 0 || plTarget.duel.startTime != 0)
|
||||
return;
|
||||
|
||||
Log.outDebug(LogFilter.Network, "Player 1 is: {0} ({1})", player.GetGUID().ToString(), player.GetName());
|
||||
Log.outDebug(LogFilter.Network, "Player 2 is: {0} ({1})", plTarget.GetGUID().ToString(), plTarget.GetName());
|
||||
|
||||
long now = Time.UnixTime;
|
||||
player.duel.startTimer = now;
|
||||
plTarget.duel.startTimer = now;
|
||||
|
||||
DuelCountdown packet = new DuelCountdown(3000);
|
||||
|
||||
player.SendPacket(packet);
|
||||
plTarget.SendPacket(packet);
|
||||
}
|
||||
|
||||
void HandleDuelCancelled()
|
||||
{
|
||||
// no duel requested
|
||||
if (GetPlayer().duel == null)
|
||||
return;
|
||||
|
||||
// player surrendered in a duel using /forfeit
|
||||
if (GetPlayer().duel.startTime != 0)
|
||||
{
|
||||
GetPlayer().CombatStopWithPets(true);
|
||||
if (GetPlayer().duel.opponent)
|
||||
GetPlayer().duel.opponent.CombatStopWithPets(true);
|
||||
|
||||
GetPlayer().CastSpell(GetPlayer(), 7267, true); // beg
|
||||
GetPlayer().DuelComplete(DuelCompleteType.Won);
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().DuelComplete(DuelCompleteType.Interrupted);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Garrisons;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.GetGarrisonInfo)]
|
||||
void HandleGetGarrisonInfo(GetGarrisonInfo getGarrisonInfo)
|
||||
{
|
||||
Garrison garrison = _player.GetGarrison();
|
||||
if (garrison != null)
|
||||
garrison.SendInfo();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GarrisonPurchaseBuilding)]
|
||||
void HandleGarrisonPurchaseBuilding(GarrisonPurchaseBuilding garrisonPurchaseBuilding)
|
||||
{
|
||||
if (!_player.GetNPCIfCanInteractWith(garrisonPurchaseBuilding.NpcGUID, NPCFlags.GarrisonArchitect))
|
||||
return;
|
||||
|
||||
Garrison garrison = _player.GetGarrison();
|
||||
if (garrison != null)
|
||||
garrison.PlaceBuilding(garrisonPurchaseBuilding.PlotInstanceID, garrisonPurchaseBuilding.BuildingID);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GarrisonCancelConstruction)]
|
||||
void HandleGarrisonCancelConstruction(GarrisonCancelConstruction garrisonCancelConstruction)
|
||||
{
|
||||
if (!_player.GetNPCIfCanInteractWith(garrisonCancelConstruction.NpcGUID, NPCFlags.GarrisonArchitect))
|
||||
return;
|
||||
|
||||
Garrison garrison = _player.GetGarrison();
|
||||
if (garrison != null)
|
||||
garrison.CancelBuildingConstruction(garrisonCancelConstruction.PlotInstanceID);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GarrisonRequestBlueprintAndSpecializationData)]
|
||||
void HandleGarrisonRequestBlueprintAndSpecializationData(GarrisonRequestBlueprintAndSpecializationData garrisonRequestBlueprintAndSpecializationData)
|
||||
{
|
||||
Garrison garrison = _player.GetGarrison();
|
||||
if (garrison != null)
|
||||
garrison.SendBlueprintAndSpecializationData();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GarrisonGetBuildingLandmarks)]
|
||||
void HandleGarrisonGetBuildingLandmarks(GarrisonGetBuildingLandmarks garrisonGetBuildingLandmarks)
|
||||
{
|
||||
Garrison garrison = _player.GetGarrison();
|
||||
if (garrison != null)
|
||||
garrison.SendBuildingLandmarks(_player);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,655 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
public void SendPartyResult(PartyOperation operation, string member, PartyResult res, uint val = 0)
|
||||
{
|
||||
PartyCommandResult packet = new PartyCommandResult();
|
||||
|
||||
packet.Name = member;
|
||||
packet.Command = (byte)operation;
|
||||
packet.Result = (byte)res;
|
||||
packet.ResultData = val;
|
||||
packet.ResultGUID = ObjectGuid.Empty;
|
||||
|
||||
SendPacket(packet);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PartyInvite)]
|
||||
void HandlePartyInvite(PartyInviteClient packet)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayerByName(packet.TargetName);
|
||||
|
||||
// no player
|
||||
if (!player)
|
||||
{
|
||||
SendPartyResult(PartyOperation.Invite, packet.TargetName, PartyResult.BadPlayerNameS);
|
||||
return;
|
||||
}
|
||||
|
||||
// player trying to invite himself (most likely cheating)
|
||||
if (player == GetPlayer())
|
||||
{
|
||||
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.BadPlayerNameS);
|
||||
return;
|
||||
}
|
||||
|
||||
// restrict invite to GMs
|
||||
if (!WorldConfig.GetBoolValue(WorldCfg.AllowGmGroup) && !GetPlayer().IsGameMaster() && player.IsGameMaster())
|
||||
{
|
||||
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.BadPlayerNameS);
|
||||
return;
|
||||
}
|
||||
|
||||
// can't group with
|
||||
if (!GetPlayer().IsGameMaster() && !WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionGroup) && GetPlayer().GetTeam() != player.GetTeam())
|
||||
{
|
||||
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.PlayerWrongFaction);
|
||||
return;
|
||||
}
|
||||
if (GetPlayer().GetInstanceId() != 0 && player.GetInstanceId() != 0 && GetPlayer().GetInstanceId() != player.GetInstanceId() && GetPlayer().GetMapId() == player.GetMapId())
|
||||
{
|
||||
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.TargetNotInInstanceS);
|
||||
return;
|
||||
}
|
||||
// just ignore us
|
||||
if (player.GetInstanceId() != 0 && player.GetDungeonDifficultyID() != GetPlayer().GetDungeonDifficultyID())
|
||||
{
|
||||
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.IgnoringYouS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.GetSocial().HasIgnore(GetPlayer().GetGUID()))
|
||||
{
|
||||
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.IgnoringYouS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.GetSocial().HasFriend(GetPlayer().GetGUID()) && GetPlayer().getLevel() < WorldConfig.GetIntValue(WorldCfg.PartyLevelReq))
|
||||
{
|
||||
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.InviteRestricted);
|
||||
return;
|
||||
}
|
||||
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (group && group.isBGGroup())
|
||||
group = GetPlayer().GetOriginalGroup();
|
||||
|
||||
Group group2 = player.GetGroup();
|
||||
if (group2 && group2.isBGGroup())
|
||||
group2 = player.GetOriginalGroup();
|
||||
|
||||
PartyInvite partyInvite;
|
||||
// player already in another group or invited
|
||||
if (group2 || player.GetGroupInvite())
|
||||
{
|
||||
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.AlreadyInGroupS);
|
||||
|
||||
if (group2)
|
||||
{
|
||||
// tell the player that they were invited but it failed as they were already in a group
|
||||
partyInvite = new PartyInvite();
|
||||
partyInvite.Initialize(GetPlayer(), packet.ProposedRoles, false);
|
||||
player.SendPacket(partyInvite);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (group)
|
||||
{
|
||||
// not have permissions for invite
|
||||
if (!group.IsLeader(GetPlayer().GetGUID()) && !group.IsAssistant(GetPlayer().GetGUID()))
|
||||
{
|
||||
SendPartyResult(PartyOperation.Invite, "", PartyResult.NotLeader);
|
||||
return;
|
||||
}
|
||||
// not have place
|
||||
if (group.IsFull())
|
||||
{
|
||||
SendPartyResult(PartyOperation.Invite, "", PartyResult.GroupFull);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ok, but group not exist, start a new group
|
||||
// but don't create and save the group to the DB until
|
||||
// at least one person joins
|
||||
if (!group)
|
||||
{
|
||||
group = new Group();
|
||||
// new group: if can't add then delete
|
||||
if (!group.AddLeaderInvite(GetPlayer()))
|
||||
return;
|
||||
|
||||
if (!group.AddInvite(player))
|
||||
{
|
||||
group.RemoveAllInvites();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// already existed group: if can't add then just leave
|
||||
if (!group.AddInvite(player))
|
||||
return;
|
||||
}
|
||||
|
||||
partyInvite = new PartyInvite();
|
||||
partyInvite.Initialize(GetPlayer(), packet.ProposedRoles, true);
|
||||
player.SendPacket(partyInvite);
|
||||
|
||||
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.Ok);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PartyInviteResponse)]
|
||||
void HandlePartyInviteResponse(PartyInviteResponse packet)
|
||||
{
|
||||
Group group = GetPlayer().GetGroupInvite();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
if (packet.Accept)
|
||||
{
|
||||
// Remove player from invitees in any case
|
||||
group.RemoveInvite(GetPlayer());
|
||||
|
||||
if (group.GetLeaderGUID() == GetPlayer().GetGUID())
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandleGroupAcceptOpcode: player {0} ({1}) tried to accept an invite to his own group", GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// Group is full
|
||||
if (group.IsFull())
|
||||
{
|
||||
SendPartyResult(PartyOperation.Invite, "", PartyResult.GroupFull);
|
||||
return;
|
||||
}
|
||||
|
||||
Player leader = Global.ObjAccessor.FindPlayer(group.GetLeaderGUID());
|
||||
|
||||
// Forming a new group, create it
|
||||
if (!group.IsCreated())
|
||||
{
|
||||
// This can happen if the leader is zoning. To be removed once delayed actions for zoning are implemented
|
||||
if (!leader)
|
||||
{
|
||||
group.RemoveAllInvites();
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're about to create a group there really should be a leader present
|
||||
Contract.Assert(leader);
|
||||
group.RemoveInvite(leader);
|
||||
group.Create(leader);
|
||||
Global.GroupMgr.AddGroup(group);
|
||||
}
|
||||
|
||||
// Everything is fine, do it, PLAYER'S GROUP IS SET IN ADDMEMBER!!!
|
||||
if (!group.AddMember(GetPlayer()))
|
||||
return;
|
||||
|
||||
group.BroadcastGroupUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remember leader if online (group will be invalid if group gets disbanded)
|
||||
Player leader = Global.ObjAccessor.FindPlayer(group.GetLeaderGUID());
|
||||
|
||||
// uninvite, group can be deleted
|
||||
GetPlayer().UninviteFromGroup();
|
||||
|
||||
if (!leader || leader.GetSession() == null)
|
||||
return;
|
||||
|
||||
// report
|
||||
GroupDecline decline = new GroupDecline(GetPlayer().GetName());
|
||||
leader.SendPacket(decline);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PartyUninvite)]
|
||||
void HandlePartyUninvite(PartyUninvite packet)
|
||||
{
|
||||
//can't uninvite yourself
|
||||
if (packet.TargetGUID == GetPlayer().GetGUID())
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandleGroupUninviteGuidOpcode: leader {0}({1}) tried to uninvite himself from the group.",
|
||||
GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
PartyResult res = GetPlayer().CanUninviteFromGroup(packet.TargetGUID);
|
||||
if (res != PartyResult.Ok)
|
||||
{
|
||||
SendPartyResult(PartyOperation.UnInvite, "", res);
|
||||
return;
|
||||
}
|
||||
|
||||
Group grp = GetPlayer().GetGroup();
|
||||
// grp is checked already above in CanUninviteFromGroup()
|
||||
Contract.Assert(grp);
|
||||
|
||||
if (grp.IsMember(packet.TargetGUID))
|
||||
{
|
||||
Player.RemoveFromGroup(grp, packet.TargetGUID, RemoveMethod.Kick, GetPlayer().GetGUID(), packet.Reason);
|
||||
return;
|
||||
}
|
||||
Player player = grp.GetInvited(packet.TargetGUID);
|
||||
if (player)
|
||||
{
|
||||
player.UninviteFromGroup();
|
||||
return;
|
||||
}
|
||||
|
||||
SendPartyResult(PartyOperation.UnInvite, "", PartyResult.TargetNotInGroupS);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetPartyLeader, Processing = PacketProcessing.Inplace)]
|
||||
void HandleSetPartyLeader(SetPartyLeader packet)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindConnectedPlayer(packet.TargetGUID);
|
||||
Group group = GetPlayer().GetGroup();
|
||||
|
||||
if (!group || !player)
|
||||
return;
|
||||
|
||||
if (!group.IsLeader(GetPlayer().GetGUID()) || player.GetGroup() != group)
|
||||
return;
|
||||
|
||||
// Everything's fine, accepted.
|
||||
group.ChangeLeader(packet.TargetGUID, packet.PartyIndex);
|
||||
group.SendUpdate();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetRole, Processing = PacketProcessing.Inplace)]
|
||||
void HandleSetRole(SetRole packet)
|
||||
{
|
||||
RoleChangedInform roleChangedInform = new RoleChangedInform();
|
||||
|
||||
Group group = GetPlayer().GetGroup();
|
||||
byte oldRole = (byte)(group ? group.GetLfgRoles(packet.TargetGUID) : 0);
|
||||
if (oldRole == packet.Role)
|
||||
return;
|
||||
|
||||
roleChangedInform.PartyIndex = packet.PartyIndex;
|
||||
roleChangedInform.From = GetPlayer().GetGUID();
|
||||
roleChangedInform.ChangedUnit = packet.TargetGUID;
|
||||
roleChangedInform.OldRole = oldRole;
|
||||
roleChangedInform.NewRole = packet.Role;
|
||||
|
||||
if (group)
|
||||
{
|
||||
group.BroadcastPacket(roleChangedInform, false);
|
||||
group.SetLfgRoles(packet.TargetGUID, (LfgRoles)packet.Role);
|
||||
}
|
||||
else
|
||||
SendPacket(roleChangedInform);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.LeaveGroup)]
|
||||
void HandleLeaveGroup(LeaveGroup packet)
|
||||
{
|
||||
Group grp = GetPlayer().GetGroup();
|
||||
if (!grp)
|
||||
return;
|
||||
|
||||
if (GetPlayer().InBattleground())
|
||||
{
|
||||
SendPartyResult(PartyOperation.Invite, "", PartyResult.InviteRestricted);
|
||||
return;
|
||||
}
|
||||
|
||||
/** error handling **/
|
||||
/********************/
|
||||
|
||||
// everything's fine, do it
|
||||
SendPartyResult(PartyOperation.Leave, GetPlayer().GetName(), PartyResult.Ok);
|
||||
|
||||
GetPlayer().RemoveFromGroup(RemoveMethod.Leave);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetLootMethod)]
|
||||
void HandleSetLootMethod(SetLootMethod packet)
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
/** error handling **/
|
||||
if (!group.IsLeader(GetPlayer().GetGUID()))
|
||||
return;
|
||||
|
||||
switch (packet.LootMethod)
|
||||
{
|
||||
case LootMethod.FreeForAll:
|
||||
case LootMethod.MasterLoot:
|
||||
case LootMethod.GroupLoot:
|
||||
case LootMethod.PersonalLoot:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.LootThreshold < ItemQuality.Uncommon || packet.LootThreshold > ItemQuality.Artifact)
|
||||
return;
|
||||
|
||||
if (packet.LootMethod == LootMethod.MasterLoot && !group.IsMember(packet.LootMasterGUID))
|
||||
return;
|
||||
|
||||
// everything's fine, do it
|
||||
group.SetLootMethod(packet.LootMethod);
|
||||
group.SetMasterLooterGuid(packet.LootMasterGUID);
|
||||
group.SetLootThreshold(packet.LootThreshold);
|
||||
group.SendUpdate();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.LootRoll)]
|
||||
void HandleLootRoll(LootRoll packet)
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
group.CountRollVote(GetPlayer().GetGUID(), packet.LootObj, (byte)(packet.LootListID - 1), packet.RollType);
|
||||
|
||||
switch (packet.RollType)
|
||||
{
|
||||
case RollType.Need:
|
||||
GetPlayer().UpdateCriteria(CriteriaTypes.RollNeed, 1);
|
||||
break;
|
||||
case RollType.Greed:
|
||||
GetPlayer().UpdateCriteria(CriteriaTypes.RollGreed, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.MinimapPing)]
|
||||
void HandleMinimapPing(MinimapPingClient packet)
|
||||
{
|
||||
if (!GetPlayer().GetGroup())
|
||||
return;
|
||||
|
||||
MinimapPing minimapPing = new MinimapPing();
|
||||
minimapPing.Sender = GetPlayer().GetGUID();
|
||||
minimapPing.PositionX = packet.PositionX;
|
||||
minimapPing.PositionY = packet.PositionY;
|
||||
GetPlayer().GetGroup().BroadcastPacket(minimapPing, true, -1, GetPlayer().GetGUID());
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RandomRoll)]
|
||||
void HandleRandomRoll(RandomRollClient packet)
|
||||
{
|
||||
if (packet.Min > packet.Max || packet.Max > 10000) // < 32768 for urand call
|
||||
return;
|
||||
|
||||
GetPlayer().DoRandomRoll(packet.Min, packet.Max);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.UpdateRaidTarget)]
|
||||
void HandleUpdateRaidTarget(UpdateRaidTarget packet)
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
if (packet.Symbol == -1) // target icon request
|
||||
group.SendTargetIconList(this, packet.PartyIndex);
|
||||
else // target icon update
|
||||
{
|
||||
if (group.isRaidGroup() && !group.IsLeader(GetPlayer().GetGUID()) && !group.IsAssistant(GetPlayer().GetGUID()))
|
||||
return;
|
||||
|
||||
if (packet.Target.IsPlayer())
|
||||
{
|
||||
Player target = Global.ObjAccessor.FindConnectedPlayer(packet.Target);
|
||||
if (!target || target.IsHostileTo(GetPlayer()))
|
||||
return;
|
||||
}
|
||||
|
||||
group.SetTargetIcon((byte)packet.Symbol, packet.Target, GetPlayer().GetGUID(), packet.PartyIndex);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ConvertRaid)]
|
||||
void HandleConvertRaid(ConvertRaid packet)
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
if (GetPlayer().InBattleground())
|
||||
return;
|
||||
|
||||
// error handling
|
||||
if (!group.IsLeader(GetPlayer().GetGUID()) || group.GetMembersCount() < 2)
|
||||
return;
|
||||
|
||||
// everything's fine, do it (is it 0 (PartyOperation.Invite) correct code)
|
||||
SendPartyResult(PartyOperation.Invite, "", PartyResult.Ok);
|
||||
|
||||
// New 4.x: it is now possible to convert a raid to a group if member count is 5 or less
|
||||
if (packet.Raid)
|
||||
group.ConvertToRaid();
|
||||
else
|
||||
group.ConvertToGroup();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestPartyJoinUpdates)]
|
||||
void HandleRequestPartyJoinUpdates(RequestPartyJoinUpdates packet)
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
group.SendTargetIconList(this, packet.PartyIndex);
|
||||
group.SendRaidMarkersChanged(this, packet.PartyIndex);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChangeSubGroup, Processing = PacketProcessing.ThreadUnsafe)]
|
||||
void HandleChangeSubGroup(ChangeSubGroup packet)
|
||||
{
|
||||
// we will get correct for group here, so we don't have to check if group is BG raid
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
if (packet.NewSubGroup >= MapConst.MaxRaidSubGroups)
|
||||
return;
|
||||
|
||||
ObjectGuid senderGuid = GetPlayer().GetGUID();
|
||||
if (!group.IsLeader(senderGuid) && !group.IsAssistant(senderGuid))
|
||||
return;
|
||||
|
||||
if (!group.HasFreeSlotSubGroup(packet.NewSubGroup))
|
||||
return;
|
||||
|
||||
group.ChangeMembersGroup(packet.TargetGUID, packet.NewSubGroup);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SwapSubGroups, Processing = PacketProcessing.ThreadUnsafe)]
|
||||
void HandleSwapSubGroups(SwapSubGroups packet)
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
ObjectGuid senderGuid = GetPlayer().GetGUID();
|
||||
if (!group.IsLeader(senderGuid) && !group.IsAssistant(senderGuid))
|
||||
return;
|
||||
|
||||
group.SwapMembersGroups(packet.FirstTarget, packet.SecondTarget);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetAssistantLeader)]
|
||||
void HandleSetAssistantLeader(SetAssistantLeader packet)
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
if (!group.IsLeader(GetPlayer().GetGUID()))
|
||||
return;
|
||||
|
||||
group.SetGroupMemberFlag(packet.Target, packet.Apply, GroupMemberFlags.Assistant);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetPartyAssignment)]
|
||||
void HandleSetPartyAssignment(SetPartyAssignment packet)
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
ObjectGuid senderGuid = GetPlayer().GetGUID();
|
||||
if (!group.IsLeader(senderGuid) && !group.IsAssistant(senderGuid))
|
||||
return;
|
||||
|
||||
switch ((GroupMemberAssignment)packet.Assignment)
|
||||
{
|
||||
case GroupMemberAssignment.MainAssist:
|
||||
group.RemoveUniqueGroupMemberFlag(GroupMemberFlags.MainAssist);
|
||||
group.SetGroupMemberFlag(packet.Target, packet.Set, GroupMemberFlags.MainAssist);
|
||||
break;
|
||||
case GroupMemberAssignment.MainTank:
|
||||
group.RemoveUniqueGroupMemberFlag(GroupMemberFlags.MainTank); // Remove main assist flag from current if any.
|
||||
group.SetGroupMemberFlag(packet.Target, packet.Set, GroupMemberFlags.MainTank);
|
||||
break;
|
||||
}
|
||||
|
||||
group.SendUpdate();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.DoReadyCheck)]
|
||||
void HandleDoReadyCheckOpcode(DoReadyCheck packet)
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
/** error handling **/
|
||||
if (!group.IsLeader(GetPlayer().GetGUID()) && !group.IsAssistant(GetPlayer().GetGUID()))
|
||||
return;
|
||||
|
||||
// everything's fine, do it
|
||||
group.StartReadyCheck(GetPlayer().GetGUID(), packet.PartyIndex);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ReadyCheckResponse, Processing = PacketProcessing.Inplace)]
|
||||
void HandleReadyCheckResponseOpcode(ReadyCheckResponseClient packet)
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
// everything's fine, do it
|
||||
group.SetMemberReadyCheck(GetPlayer().GetGUID(), packet.IsReady);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestPartyMemberStats)]
|
||||
void HandleRequestPartyMemberStats(RequestPartyMemberStats packet)
|
||||
{
|
||||
PartyMemberState partyMemberStats = new PartyMemberState();
|
||||
|
||||
Player player = Global.ObjAccessor.FindConnectedPlayer(packet.TargetGUID);
|
||||
if (!player)
|
||||
{
|
||||
partyMemberStats.MemberGuid = packet.TargetGUID;
|
||||
partyMemberStats.MemberStats.Status = GroupMemberOnlineStatus.Offline;
|
||||
}
|
||||
else
|
||||
partyMemberStats.Initialize(player);
|
||||
|
||||
SendPacket(partyMemberStats);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestRaidInfo)]
|
||||
void HandleRequestRaidInfo(RequestRaidInfo packet)
|
||||
{
|
||||
// every time the player checks the character screen
|
||||
GetPlayer().SendRaidInfo();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.OptOutOfLoot)]
|
||||
void HandleOptOutOfLoot(OptOutOfLoot packet)
|
||||
{
|
||||
// ignore if player not loaded
|
||||
if (!GetPlayer()) // needed because STATUS_AUTHED
|
||||
{
|
||||
if (packet.PassOnLoot)
|
||||
Log.outError(LogFilter.Network, "CMSG_OPT_OUT_OF_LOOT value<>0 for not-loaded character!");
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().SetPassOnGroupLoot(packet.PassOnLoot);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.InitiateRolePoll)]
|
||||
void HandleInitiateRolePoll(InitiateRolePoll packet)
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
if (!group.IsLeader(guid) && !group.IsAssistant(guid))
|
||||
return;
|
||||
|
||||
RolePollInform rolePollInform = new RolePollInform();
|
||||
rolePollInform.From = guid;
|
||||
rolePollInform.PartyIndex = packet.PartyIndex;
|
||||
group.BroadcastPacket(rolePollInform, true);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetEveryoneIsAssistant)]
|
||||
void HandleSetEveryoneIsAssistant(SetEveryoneIsAssistant packet)
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
if (!group.IsLeader(GetPlayer().GetGUID()))
|
||||
return;
|
||||
|
||||
group.SetEveryoneIsAssistant(packet.EveryoneIsAssistant);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ClearRaidMarker)]
|
||||
void HandleClearRaidMarker(ClearRaidMarker packet)
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
if (group.isRaidGroup() && !group.IsLeader(GetPlayer().GetGUID()) && !group.IsAssistant(GetPlayer().GetGUID()))
|
||||
return;
|
||||
|
||||
group.DeleteRaidMarker(packet.MarkerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Guilds;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.LfGuildAddRecruit)]
|
||||
void HandleGuildFinderAddRecruit(LFGuildAddRecruit lfGuildAddRecruit)
|
||||
{
|
||||
if (Global.GuildFinderMgr.GetAllMembershipRequestsForPlayer(GetPlayer().GetGUID()).Count >= 10)
|
||||
return;
|
||||
|
||||
if (!lfGuildAddRecruit.GuildGUID.IsGuild())
|
||||
return;
|
||||
if (!lfGuildAddRecruit.ClassRoles.HasAnyFlag((uint)GuildFinderOptionsRoles.All) || lfGuildAddRecruit.ClassRoles > (uint)GuildFinderOptionsRoles.All)
|
||||
return;
|
||||
if (!lfGuildAddRecruit.Availability.HasAnyFlag((uint)GuildFinderOptionsAvailability.Always) || lfGuildAddRecruit.Availability > (uint)GuildFinderOptionsAvailability.Always)
|
||||
return;
|
||||
if (!lfGuildAddRecruit.PlayStyle.HasAnyFlag((uint)GuildFinderOptionsInterest.All) || lfGuildAddRecruit.PlayStyle > (uint)GuildFinderOptionsInterest.All)
|
||||
return;
|
||||
|
||||
MembershipRequest request = new MembershipRequest(GetPlayer().GetGUID(), lfGuildAddRecruit.GuildGUID, lfGuildAddRecruit.Availability,
|
||||
lfGuildAddRecruit.ClassRoles, lfGuildAddRecruit.PlayStyle, lfGuildAddRecruit.Comment, Time.UnixTime);
|
||||
Global.GuildFinderMgr.AddMembershipRequest(lfGuildAddRecruit.GuildGUID, request);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.LfGuildBrowse)]
|
||||
void HandleGuildFinderBrowse(LFGuildBrowse lfGuildBrowse)
|
||||
{
|
||||
if (!lfGuildBrowse.ClassRoles.HasAnyFlag((uint)GuildFinderOptionsRoles.All) || lfGuildBrowse.ClassRoles > (uint)GuildFinderOptionsRoles.All)
|
||||
return;
|
||||
if (!lfGuildBrowse.Availability.HasAnyFlag((uint)GuildFinderOptionsAvailability.Always) || lfGuildBrowse.Availability > (uint)GuildFinderOptionsAvailability.Always)
|
||||
return;
|
||||
if (!lfGuildBrowse.PlayStyle.HasAnyFlag((uint)GuildFinderOptionsInterest.All) || lfGuildBrowse.PlayStyle > (uint)GuildFinderOptionsInterest.All)
|
||||
return;
|
||||
if (lfGuildBrowse.CharacterLevel > WorldConfig.GetIntValue(WorldCfg.MaxPlayerLevel) || lfGuildBrowse.CharacterLevel < 1)
|
||||
return;
|
||||
|
||||
Player player = GetPlayer();
|
||||
|
||||
LFGuildPlayer settings = new LFGuildPlayer(player.GetGUID(), lfGuildBrowse.ClassRoles, lfGuildBrowse.Availability, lfGuildBrowse.PlayStyle, (uint)GuildFinderOptionsLevel.Any);
|
||||
var guildList = Global.GuildFinderMgr.GetGuildsMatchingSetting(settings, (uint)player.GetTeam());
|
||||
|
||||
LFGuildBrowseResult lfGuildBrowseResult = new LFGuildBrowseResult();
|
||||
for (var i = 0; i < guildList.Count; ++i)
|
||||
{
|
||||
LFGuildSettings guildSettings = guildList[i];
|
||||
LFGuildBrowseData guildData = new LFGuildBrowseData();
|
||||
Guild guild = Global.GuildMgr.GetGuildByGuid(guildSettings.GetGUID());
|
||||
|
||||
guildData.GuildName = guild.GetName();
|
||||
guildData.GuildGUID = guild.GetGUID();
|
||||
guildData.GuildVirtualRealm = Global.WorldMgr.GetVirtualRealmAddress();
|
||||
guildData.GuildMembers = guild.GetMembersCount();
|
||||
guildData.GuildAchievementPoints = guild.GetAchievementMgr().GetAchievementPoints();
|
||||
guildData.PlayStyle = guildSettings.GetInterests();
|
||||
guildData.Availability = guildSettings.GetAvailability();
|
||||
guildData.ClassRoles = guildSettings.GetClassRoles();
|
||||
guildData.LevelRange = guildSettings.GetLevel();
|
||||
guildData.EmblemStyle = guild.GetEmblemInfo().GetStyle();
|
||||
guildData.EmblemColor = guild.GetEmblemInfo().GetColor();
|
||||
guildData.BorderStyle = guild.GetEmblemInfo().GetBorderStyle();
|
||||
guildData.BorderColor = guild.GetEmblemInfo().GetBorderColor();
|
||||
guildData.Background = guild.GetEmblemInfo().GetBackgroundColor();
|
||||
guildData.Comment = guildSettings.GetComment();
|
||||
guildData.Cached = 0;
|
||||
guildData.MembershipRequested = (sbyte)(Global.GuildFinderMgr.HasRequest(player.GetGUID(), guild.GetGUID()) ? 1 : 0);
|
||||
|
||||
lfGuildBrowseResult.Post.Add(guildData);
|
||||
}
|
||||
|
||||
player.SendPacket(lfGuildBrowseResult);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.LfGuildDeclineRecruit)]
|
||||
void HandleGuildFinderDeclineRecruit(LFGuildDeclineRecruit lfGuildDeclineRecruit)
|
||||
{
|
||||
if (!GetPlayer().GetGuild())
|
||||
return;
|
||||
|
||||
if (!lfGuildDeclineRecruit.RecruitGUID.IsPlayer())
|
||||
return;
|
||||
|
||||
Global.GuildFinderMgr.RemoveMembershipRequest(lfGuildDeclineRecruit.RecruitGUID, GetPlayer().GetGuild().GetGUID());
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.LfGuildGetApplications)]
|
||||
void HandleGuildFinderGetApplications(LFGuildGetApplications lfGuildGetApplications)
|
||||
{
|
||||
List<MembershipRequest> applicatedGuilds = Global.GuildFinderMgr.GetAllMembershipRequestsForPlayer(GetPlayer().GetGUID());
|
||||
LFGuildApplications lfGuildApplications = new LFGuildApplications();
|
||||
lfGuildApplications.NumRemaining = 10 - Global.GuildFinderMgr.CountRequestsFromPlayer(GetPlayer().GetGUID());
|
||||
|
||||
for (var i = 0; i < applicatedGuilds.Count; ++i)
|
||||
{
|
||||
MembershipRequest application = applicatedGuilds[i];
|
||||
LFGuildApplicationData applicationData = new LFGuildApplicationData();
|
||||
|
||||
Guild guild = Global.GuildMgr.GetGuildByGuid(application.GetGuildGuid());
|
||||
LFGuildSettings guildSettings = Global.GuildFinderMgr.GetGuildSettings(application.GetGuildGuid());
|
||||
|
||||
applicationData.GuildGUID = application.GetGuildGuid();
|
||||
applicationData.GuildVirtualRealm = Global.WorldMgr.GetVirtualRealmAddress();
|
||||
applicationData.GuildName = guild.GetName();
|
||||
applicationData.ClassRoles = guildSettings.GetClassRoles();
|
||||
applicationData.PlayStyle = guildSettings.GetInterests();
|
||||
applicationData.Availability = guildSettings.GetAvailability();
|
||||
applicationData.SecondsSinceCreated = (uint)(Time.UnixTime - application.GetSubmitTime());
|
||||
applicationData.SecondsUntilExpiration = (uint)(application.GetExpiryTime() - Time.UnixTime);
|
||||
applicationData.Comment = application.GetComment();
|
||||
|
||||
lfGuildApplications.Application.Add(applicationData);
|
||||
}
|
||||
|
||||
GetPlayer().SendPacket(lfGuildApplications);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.LfGuildGetGuildPost)]
|
||||
void HandleGuildFinderGetGuildPost(LFGuildGetGuildPost lfGuildGetGuildPost)
|
||||
{
|
||||
Player player = GetPlayer();
|
||||
|
||||
Guild guild = player.GetGuild();
|
||||
if (!guild) // Player must be in guild
|
||||
return;
|
||||
|
||||
LFGuildPost lfGuildPost = new LFGuildPost();
|
||||
if (guild.GetLeaderGUID() == player.GetGUID())
|
||||
{
|
||||
LFGuildSettings settings = Global.GuildFinderMgr.GetGuildSettings(guild.GetGUID());
|
||||
if (settings == null)
|
||||
return;
|
||||
|
||||
lfGuildPost.Post.HasValue = true;
|
||||
lfGuildPost.Post.Value.Active = settings.IsListed();
|
||||
lfGuildPost.Post.Value.PlayStyle = settings.GetInterests();
|
||||
lfGuildPost.Post.Value.Availability = settings.GetAvailability();
|
||||
lfGuildPost.Post.Value.ClassRoles = settings.GetClassRoles();
|
||||
lfGuildPost.Post.Value.LevelRange = settings.GetLevel();
|
||||
lfGuildPost.Post.Value.Comment = settings.GetComment();
|
||||
}
|
||||
|
||||
player.SendPacket(lfGuildPost);
|
||||
}
|
||||
|
||||
// Lists all recruits for a guild - Misses times
|
||||
[WorldPacketHandler(ClientOpcodes.LfGuildGetRecruits)]
|
||||
void HandleGuildFinderGetRecruits(LFGuildGetRecruits lfGuildGetRecruits)
|
||||
{
|
||||
Player player = GetPlayer();
|
||||
Guild guild = player.GetGuild();
|
||||
if (!guild)
|
||||
return;
|
||||
|
||||
long now = Time.UnixTime;
|
||||
LFGuildRecruits lfGuildRecruits = new LFGuildRecruits();
|
||||
lfGuildRecruits.UpdateTime = now;
|
||||
var recruitsList = Global.GuildFinderMgr.GetAllMembershipRequestsForGuild(guild.GetGUID());
|
||||
if (recruitsList != null)
|
||||
{
|
||||
foreach (var recruitRequestPair in recruitsList)
|
||||
{
|
||||
LFGuildRecruitData recruitData = new LFGuildRecruitData();
|
||||
recruitData.RecruitGUID = recruitRequestPair.Key;
|
||||
recruitData.RecruitVirtualRealm = Global.WorldMgr.GetVirtualRealmAddress();
|
||||
recruitData.Comment = recruitRequestPair.Value.GetComment();
|
||||
recruitData.ClassRoles = recruitRequestPair.Value.GetClassRoles();
|
||||
recruitData.PlayStyle = recruitRequestPair.Value.GetInterests();
|
||||
recruitData.Availability = recruitRequestPair.Value.GetAvailability();
|
||||
recruitData.SecondsSinceCreated = (uint)(now - recruitRequestPair.Value.GetSubmitTime());
|
||||
recruitData.SecondsUntilExpiration = (uint)(recruitRequestPair.Value.GetExpiryTime() - now);
|
||||
|
||||
CharacterInfo charInfo = Global.WorldMgr.GetCharacterInfo(recruitRequestPair.Key);
|
||||
if (charInfo != null)
|
||||
{
|
||||
recruitData.Name = charInfo.Name;
|
||||
recruitData.CharacterClass = (int)charInfo.ClassID;
|
||||
recruitData.CharacterGender = (int)charInfo.Sex;
|
||||
recruitData.CharacterLevel = charInfo.Level;
|
||||
}
|
||||
|
||||
lfGuildRecruits.Recruits.Add(recruitData);
|
||||
}
|
||||
}
|
||||
|
||||
player.SendPacket(lfGuildRecruits);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.LfGuildRemoveRecruit)]
|
||||
void HandleGuildFinderRemoveRecruit(LFGuildRemoveRecruit lfGuildRemoveRecruit)
|
||||
{
|
||||
if (!lfGuildRemoveRecruit.GuildGUID.IsGuild())
|
||||
return;
|
||||
|
||||
Global.GuildFinderMgr.RemoveMembershipRequest(GetPlayer().GetGUID(), lfGuildRemoveRecruit.GuildGUID);
|
||||
}
|
||||
|
||||
// Sent any time a guild master sets an option in the interface and when listing / unlisting his guild
|
||||
[WorldPacketHandler(ClientOpcodes.LfGuildSetGuildPost)]
|
||||
void HandleGuildFinderSetGuildPost(LFGuildSetGuildPost lfGuildSetGuildPost)
|
||||
{
|
||||
// Level sent is zero if untouched, force to any (from interface). Idk why
|
||||
if (lfGuildSetGuildPost.LevelRange == 0)
|
||||
lfGuildSetGuildPost.LevelRange = (uint)GuildFinderOptionsLevel.Any;
|
||||
|
||||
if (!lfGuildSetGuildPost.ClassRoles.HasAnyFlag((uint)GuildFinderOptionsRoles.All) || lfGuildSetGuildPost.ClassRoles > (uint)GuildFinderOptionsRoles.All)
|
||||
return;
|
||||
if (!lfGuildSetGuildPost.Availability.HasAnyFlag((uint)GuildFinderOptionsAvailability.Always) || lfGuildSetGuildPost.Availability > (uint)GuildFinderOptionsAvailability.Always)
|
||||
return;
|
||||
if (!lfGuildSetGuildPost.PlayStyle.HasAnyFlag((uint)GuildFinderOptionsInterest.All) || lfGuildSetGuildPost.PlayStyle > (uint)GuildFinderOptionsInterest.All)
|
||||
return;
|
||||
if (!lfGuildSetGuildPost.LevelRange.HasAnyFlag((uint)GuildFinderOptionsLevel.All) || lfGuildSetGuildPost.LevelRange > (uint)GuildFinderOptionsLevel.All)
|
||||
return;
|
||||
|
||||
Player player = GetPlayer();
|
||||
|
||||
if (player.GetGuildId() == 0) // Player must be in guild
|
||||
return;
|
||||
|
||||
Guild guild = Global.GuildMgr.GetGuildById(player.GetGuildId());
|
||||
if (guild.GetLeaderGUID() != player.GetGUID())
|
||||
return;
|
||||
|
||||
LFGuildSettings settings = new LFGuildSettings(lfGuildSetGuildPost.Active, (uint)player.GetTeam(), player.GetGuild().GetGUID(), lfGuildSetGuildPost.ClassRoles,
|
||||
lfGuildSetGuildPost.Availability, lfGuildSetGuildPost.PlayStyle, lfGuildSetGuildPost.LevelRange, lfGuildSetGuildPost.Comment);
|
||||
Global.GuildFinderMgr.SetGuildSettings(player.GetGuild().GetGUID(), settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,467 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Guilds;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.QueryGuildInfo, Status = SessionStatus.Authed)]
|
||||
void HandleGuildQuery(QueryGuildInfo query)
|
||||
{
|
||||
Guild guild = Global.GuildMgr.GetGuildByGuid(query.GuildGuid);
|
||||
if (guild)
|
||||
{
|
||||
if (guild.IsMember(query.PlayerGuid))
|
||||
{
|
||||
guild.SendQueryResponse(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QueryGuildInfoResponse response = new QueryGuildInfoResponse();
|
||||
response.GuildGUID = query.GuildGuid;
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildInviteByName)]
|
||||
void HandleGuildInviteByName(GuildInviteByName packet)
|
||||
{
|
||||
if (!ObjectManager.NormalizePlayerName(ref packet.Name))
|
||||
return;
|
||||
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleInviteMember(this, packet.Name);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildOfficerRemoveMember)]
|
||||
void HandleGuildOfficerRemoveMember(GuildOfficerRemoveMember packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleRemoveMember(this, packet.Removee);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AcceptGuildInvite)]
|
||||
void HandleGuildAcceptInvite(AcceptGuildInvite packet)
|
||||
{
|
||||
if (GetPlayer().GetGuildId() == 0)
|
||||
{
|
||||
Guild guild = Global.GuildMgr.GetGuildById(GetPlayer().GetGuildIdInvited());
|
||||
if (guild)
|
||||
guild.HandleAcceptMember(this);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildDeclineInvitation)]
|
||||
void HandleGuildDeclineInvitation(GuildDeclineInvitation packet)
|
||||
{
|
||||
GetPlayer().SetGuildIdInvited(0);
|
||||
GetPlayer().SetInGuild(0);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildGetRoster)]
|
||||
void HandleGuildGetRoster(GuildGetRoster packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleRoster(this);
|
||||
else
|
||||
Guild.SendCommandResult(this, GuildCommandType.GetRoster, GuildCommandError.PlayerNotInGuild);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildPromoteMember)]
|
||||
void HandleGuildPromoteMember(GuildPromoteMember packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleUpdateMemberRank(this, packet.Promotee, false);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildDemoteMember)]
|
||||
void HandleGuildDemoteMember(GuildDemoteMember packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleUpdateMemberRank(this, packet.Demotee, true);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildAssignMemberRank)]
|
||||
void HandleGuildAssignRank(GuildAssignMemberRank packet)
|
||||
{
|
||||
ObjectGuid setterGuid = GetPlayer().GetGUID();
|
||||
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleSetMemberRank(this, packet.Member, setterGuid, (byte)packet.RankOrder);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildLeave)]
|
||||
void HandleGuildLeave(GuildLeave packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleLeaveMember(this);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildDelete)]
|
||||
void HandleGuildDisband(GuildDelete packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleDelete(this);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildUpdateMotdText)]
|
||||
void HandleGuildUpdateMotdText(GuildUpdateMotdText packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleSetMOTD(this, packet.MotdText);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildSetMemberNote)]
|
||||
void HandleGuildSetMemberNote(GuildSetMemberNote packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleSetMemberNote(this, packet.Note, packet.NoteeGUID, packet.IsPublic);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildGetRanks)]
|
||||
void HandleGuildGetRanks(GuildGetRanks packet)
|
||||
{
|
||||
Guild guild = Global.GuildMgr.GetGuildByGuid(packet.GuildGUID);
|
||||
if (guild)
|
||||
if (guild.IsMember(GetPlayer().GetGUID()))
|
||||
guild.SendGuildRankInfo(this);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildAddRank)]
|
||||
void HandleGuildAddRank(GuildAddRank packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleAddNewRank(this, packet.Name);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildDeleteRank)]
|
||||
void HandleGuildDeleteRank(GuildDeleteRank packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleRemoveRank(this, (byte)packet.RankOrder);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildUpdateInfoText)]
|
||||
void HandleGuildUpdateInfoText(GuildUpdateInfoText packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleSetInfo(this, packet.InfoText);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SaveGuildEmblem)]
|
||||
void HandleSaveGuildEmblem(SaveGuildEmblem packet)
|
||||
{
|
||||
Guild.EmblemInfo emblemInfo = new Guild.EmblemInfo();
|
||||
emblemInfo.ReadPacket(packet);
|
||||
|
||||
if (GetPlayer().GetNPCIfCanInteractWith(packet.Vendor, NPCFlags.TabardDesigner))
|
||||
{
|
||||
// Remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
if (!emblemInfo.ValidateEmblemColors())
|
||||
{
|
||||
Guild.SendSaveEmblemResult(this, GuildEmblemError.InvalidTabardColors);
|
||||
return;
|
||||
}
|
||||
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleSetEmblem(this, emblemInfo);
|
||||
else
|
||||
Guild.SendSaveEmblemResult(this, GuildEmblemError.NoGuild); // "You are not part of a guild!";
|
||||
}
|
||||
else
|
||||
Guild.SendSaveEmblemResult(this, GuildEmblemError.InvalidVendor); // "That's not an emblem vendor!"
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildEventLogQuery)]
|
||||
void HandleGuildEventLogQuery(GuildEventLogQuery packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.SendEventLog(this);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildBankRemainingWithdrawMoneyQuery)]
|
||||
void HandleGuildBankMoneyWithdrawn(GuildBankRemainingWithdrawMoneyQuery packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.SendMoneyInfo(this);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildPermissionsQuery)]
|
||||
void HandleGuildPermissionsQuery(GuildPermissionsQuery packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.SendPermissions(this);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildBankActivate)]
|
||||
void HandleGuildBankActivate(GuildBankActivate packet)
|
||||
{
|
||||
GameObject go = GetPlayer().GetGameObjectIfCanInteractWith(packet.Banker, GameObjectTypes.GuildBank);
|
||||
if (go == null)
|
||||
return;
|
||||
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild == null)
|
||||
{
|
||||
Guild.SendCommandResult(this, GuildCommandType.ViewTab, GuildCommandError.PlayerNotInGuild);
|
||||
return;
|
||||
}
|
||||
|
||||
guild.SendBankList(this, 0, packet.FullUpdate);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildBankQueryTab)]
|
||||
void HandleGuildBankQueryTab(GuildBankQueryTab packet)
|
||||
{
|
||||
if (GetPlayer().GetGameObjectIfCanInteractWith(packet.Banker, GameObjectTypes.GuildBank))
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.SendBankList(this, packet.Tab, packet.FullUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildBankDepositMoney)]
|
||||
void HandleGuildBankDepositMoney(GuildBankDepositMoney packet)
|
||||
{
|
||||
if (GetPlayer().GetGameObjectIfCanInteractWith(packet.Banker, GameObjectTypes.GuildBank))
|
||||
{
|
||||
if (packet.Money != 0 && GetPlayer().HasEnoughMoney(packet.Money))
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleMemberDepositMoney(this, packet.Money);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildBankWithdrawMoney)]
|
||||
void HandleGuildBankWithdrawMoney(GuildBankWithdrawMoney packet)
|
||||
{
|
||||
if (packet.Money != 0 && GetPlayer().GetGameObjectIfCanInteractWith(packet.Banker, GameObjectTypes.GuildBank))
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleMemberWithdrawMoney(this, packet.Money);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildBankSwapItems)]
|
||||
void HandleGuildBankSwapItems(GuildBankSwapItems packet)
|
||||
{
|
||||
if (!GetPlayer().GetGameObjectIfCanInteractWith(packet.Banker, GameObjectTypes.GuildBank))
|
||||
return;
|
||||
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (!guild)
|
||||
return;
|
||||
|
||||
if (packet.BankOnly)
|
||||
{
|
||||
guild.SwapItems(GetPlayer(), packet.BankTab1, packet.BankSlot1, packet.BankTab, packet.BankSlot, (uint)packet.StackCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Player <-> Bank
|
||||
// Allow to work with inventory only
|
||||
if (!Player.IsInventoryPos(packet.ContainerSlot, packet.ContainerItemSlot) && !packet.AutoStore)
|
||||
GetPlayer().SendEquipError(InventoryResult.InternalBagError);
|
||||
else
|
||||
guild.SwapItemsWithInventory(GetPlayer(), packet.ToSlot != 0, packet.BankTab, packet.BankSlot, packet.ContainerSlot, packet.ContainerItemSlot, (uint)packet.StackCount);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildBankBuyTab)]
|
||||
void HandleGuildBankBuyTab(GuildBankBuyTab packet)
|
||||
{
|
||||
if (packet.Banker.IsEmpty() || GetPlayer().GetGameObjectIfCanInteractWith(packet.Banker, GameObjectTypes.GuildBank))
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleBuyBankTab(this, packet.BankTab);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildBankUpdateTab)]
|
||||
void HandleGuildBankUpdateTab(GuildBankUpdateTab packet)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(packet.Name) && !string.IsNullOrEmpty(packet.Icon))
|
||||
{
|
||||
if (GetPlayer().GetGameObjectIfCanInteractWith(packet.Banker, GameObjectTypes.GuildBank))
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleSetBankTabInfo(this, packet.BankTab, packet.Name, packet.Icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildBankLogQuery)]
|
||||
void HandleGuildBankLogQuery(GuildBankLogQuery packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.SendBankLog(this, (byte)packet.Tab);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildBankTextQuery)]
|
||||
void HandleGuildBankTextQuery(GuildBankTextQuery packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.SendBankTabText(this, (byte)packet.Tab);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildBankSetTabText)]
|
||||
void HandleGuildBankSetTabText(GuildBankSetTabText packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.SetBankTabText((byte)packet.Tab, packet.TabText);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildSetRankPermissions)]
|
||||
void HandleGuildSetRankPermissions(GuildSetRankPermissions packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (!guild)
|
||||
return;
|
||||
|
||||
List<Guild.GuildBankRightsAndSlots> rightsAndSlots = new List<Guild.GuildBankRightsAndSlots>(GuildConst.MaxBankTabs);
|
||||
for (byte tabId = 0; tabId < GuildConst.MaxBankTabs; ++tabId)
|
||||
rightsAndSlots[tabId] = new Guild.GuildBankRightsAndSlots(tabId, (sbyte)packet.TabFlags[tabId], packet.TabWithdrawItemLimit[tabId]);
|
||||
|
||||
guild.HandleSetRankInfo(this, (byte)packet.RankOrder, packet.RankName, (GuildRankRights)packet.Flags, (uint)packet.WithdrawGoldLimit, rightsAndSlots);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestGuildPartyState)]
|
||||
void HandleGuildRequestPartyState(RequestGuildPartyState packet)
|
||||
{
|
||||
Guild guild = Global.GuildMgr.GetGuildByGuid(packet.GuildGUID);
|
||||
if (guild)
|
||||
guild.HandleGuildPartyRequest(this);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildChangeNameRequest)]
|
||||
void HandleGuildChallengeUpdateRequest(GuildChallengeUpdateRequest packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleGuildRequestChallengeUpdate(this);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.DeclineGuildInvites)]
|
||||
void HandleDeclineGuildInvites(DeclineGuildInvites packet)
|
||||
{
|
||||
GetPlayer().ApplyModFlag(PlayerFields.Flags, PlayerFlags.AutoDeclineGuild, packet.Allow);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestGuildRewardsList, Processing = PacketProcessing.Inplace)]
|
||||
void HandleRequestGuildRewardsList(RequestGuildRewardsList packet)
|
||||
{
|
||||
if (Global.GuildMgr.GetGuildById(GetPlayer().GetGuildId()))
|
||||
{
|
||||
var rewards = Global.GuildMgr.GetGuildRewards();
|
||||
|
||||
GuildRewardList rewardList = new GuildRewardList();
|
||||
rewardList.Version = (uint)Time.UnixTime;
|
||||
|
||||
for (int i = 0; i < rewards.Count; i++)
|
||||
{
|
||||
GuildRewardItem rewardItem = new GuildRewardItem();
|
||||
rewardItem.ItemID = rewards[i].ItemID;
|
||||
rewardItem.RaceMask = (uint)rewards[i].RaceMask;
|
||||
rewardItem.MinGuildLevel = 0;
|
||||
rewardItem.MinGuildRep = rewards[i].MinGuildRep;
|
||||
rewardItem.AchievementsRequired = rewards[i].AchievementsRequired;
|
||||
rewardItem.Cost = rewards[i].Cost;
|
||||
rewardList.RewardItems.Add(rewardItem);
|
||||
}
|
||||
|
||||
SendPacket(rewardList);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildQueryNews, Processing = PacketProcessing.Inplace)]
|
||||
void HandleGuildQueryNews(GuildQueryNews packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
if (guild.GetGUID() == packet.GuildGUID)
|
||||
guild.SendNewsUpdate(this);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildNewsUpdateSticky)]
|
||||
void HandleGuildNewsUpdateSticky(GuildNewsUpdateSticky packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleNewsSetSticky(this, (uint)packet.NewsID, packet.Sticky);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildSetGuildMaster)]
|
||||
void HandleGuildSetGuildMaster(GuildSetGuildMaster packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleSetNewGuildMaster(this, packet.NewMasterName);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildSetAchievementTracking)]
|
||||
void HandleGuildSetAchievementTracking(GuildSetAchievementTracking packet)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleSetAchievementTracking(this, packet.AchievementIDs);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildGetAchievementMembers)]
|
||||
void HandleGuildGetAchievementMembers(GuildGetAchievementMembers getAchievementMembers)
|
||||
{
|
||||
Guild guild = GetPlayer().GetGuild();
|
||||
if (guild)
|
||||
guild.HandleGetAchievementMembers(this, getAchievementMembers.AchievementID);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.DataStorage;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.DbQueryBulk, Processing = PacketProcessing.Inplace, Status = SessionStatus.Authed)]
|
||||
void HandleDBQueryBulk(DBQueryBulk dbQuery)
|
||||
{
|
||||
IDB2Storage store = Global.DB2Mgr.GetStorage(dbQuery.TableHash);
|
||||
if (store == null)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "CMSG_DB_QUERY_BULK: {0} requested unsupported unknown hotfix type: {1}", GetPlayerInfo(), dbQuery.TableHash);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (DBQueryBulk.DBQueryRecord record in dbQuery.Queries)
|
||||
{
|
||||
DBReply dbReply = new DBReply();
|
||||
dbReply.TableHash = dbQuery.TableHash;
|
||||
dbReply.RecordID = record.RecordID;
|
||||
|
||||
if (store.HasRecord(record.RecordID))
|
||||
{
|
||||
dbReply.Allow = true;
|
||||
dbReply.Timestamp = (uint)Global.WorldMgr.GetGameTime();
|
||||
store.WriteRecord(record.RecordID, GetSessionDbcLocale(), dbReply.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outTrace(LogFilter.Network, "CMSG_DB_QUERY_BULK: {0} requested non-existing entry {1} in datastore: {2}", GetPlayerInfo(), record.RecordID, dbQuery.TableHash);
|
||||
dbReply.Timestamp = (uint)Time.UnixTime;
|
||||
}
|
||||
|
||||
SendPacket(dbReply);
|
||||
}
|
||||
}
|
||||
|
||||
void SendHotfixList(int version)
|
||||
{
|
||||
SendPacket(new HotfixList(version, Global.DB2Mgr.GetHotfixData()));
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.HotfixQuery, Status = SessionStatus.Authed)]
|
||||
void HandleHotfixQuery(HotfixQuery hotfixQuery)
|
||||
{
|
||||
Dictionary<ulong, int> hotfixes = Global.DB2Mgr.GetHotfixData();
|
||||
|
||||
HotfixQueryResponse hotfixQueryResponse = new HotfixQueryResponse();
|
||||
foreach (ulong hotfixId in hotfixQuery.Hotfixes)
|
||||
{
|
||||
int hotfix = hotfixes.LookupByKey(hotfixId);
|
||||
if (hotfix != 0)
|
||||
{
|
||||
var storage = Global.DB2Mgr.GetStorage(MathFunctions.Pair64_HiPart(hotfixId));
|
||||
|
||||
HotfixQueryResponse.HotfixData hotfixData = new HotfixQueryResponse.HotfixData();
|
||||
hotfixData.ID = hotfixId;
|
||||
hotfixData.RecordID = hotfix;
|
||||
if (storage.HasRecord((uint)hotfixData.RecordID))
|
||||
{
|
||||
hotfixData.Data.HasValue = true;
|
||||
storage.WriteRecord((uint)hotfixData.RecordID, GetSessionDbcLocale(), hotfixData.Data.Value);
|
||||
}
|
||||
|
||||
hotfixQueryResponse.Hotfixes.Add(hotfixData);
|
||||
}
|
||||
}
|
||||
|
||||
SendPacket(hotfixQueryResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Guilds;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.Inspect)]
|
||||
void HandleInspect(Inspect inspect)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(inspect.Target);
|
||||
if (!player)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession.HandleInspectOpcode: Target {0} not found.", inspect.Target.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetPlayer().IsWithinDistInMap(player, SharedConst.InspectDistance, false))
|
||||
return;
|
||||
|
||||
if (GetPlayer().IsValidAttackTarget(player))
|
||||
return;
|
||||
|
||||
InspectResult inspectResult = new InspectResult();
|
||||
inspectResult.InspecteeGUID = inspect.Target;
|
||||
|
||||
for (byte i = 0; i < EquipmentSlot.End; ++i)
|
||||
{
|
||||
Item item = player.GetItemByPos(InventorySlots.Bag0, i);
|
||||
if (item)
|
||||
inspectResult.Items.Add(new InspectItemData(item, i));
|
||||
}
|
||||
|
||||
inspectResult.ClassID = player.GetClass();
|
||||
inspectResult.GenderID = (Gender)player.GetByteValue(PlayerFields.Bytes3, PlayerFieldOffsets.Bytes3OffsetGender);
|
||||
|
||||
if (GetPlayer().CanBeGameMaster() || WorldConfig.GetIntValue(WorldCfg.TalentsInspecting) + (GetPlayer().GetTeamId() == player.GetTeamId() ? 1 : 0) > 1)
|
||||
{
|
||||
var talents = player.GetTalentMap(player.GetActiveTalentGroup());
|
||||
foreach (var v in talents)
|
||||
{
|
||||
if (v.Value != PlayerSpellState.Removed)
|
||||
inspectResult.Talents.Add((ushort)v.Key);
|
||||
}
|
||||
}
|
||||
|
||||
Guild guild = Global.GuildMgr.GetGuildById(player.GetGuildId());
|
||||
if (guild)
|
||||
{
|
||||
inspectResult.GuildData.HasValue = true;
|
||||
|
||||
InspectGuildData guildData = inspectResult.GuildData.Value;
|
||||
guildData.GuildGUID = guild.GetGUID();
|
||||
guildData.NumGuildMembers = guild.GetMembersCount();
|
||||
guildData.AchievementPoints = (int)guild.GetAchievementMgr().GetAchievementPoints();
|
||||
}
|
||||
|
||||
inspectResult.InspecteeGUID = inspect.Target;
|
||||
inspectResult.SpecializationID = (int)player.GetUInt32Value(PlayerFields.CurrentSpecId);
|
||||
|
||||
SendPacket(inspectResult);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestHonorStats)]
|
||||
void HandleRequestHonorStatsOpcode(RequestHonorStats request)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(request.TargetGUID);
|
||||
if (!player)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession.HandleRequestHonorStatsOpcode: Target {0} not found.", request.TargetGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetPlayer().IsWithinDistInMap(player, SharedConst.InspectDistance, false))
|
||||
return;
|
||||
|
||||
if (GetPlayer().IsValidAttackTarget(player))
|
||||
return;
|
||||
|
||||
InspectHonorStats honorStats = new InspectHonorStats();
|
||||
honorStats.PlayerGUID = request.TargetGUID;
|
||||
honorStats.LifetimeHK = player.GetUInt32Value(PlayerFields.LifetimeHonorableKills);
|
||||
honorStats.YesterdayHK = player.GetUInt16Value(PlayerFields.Kills, 1);
|
||||
honorStats.TodayHK = player.GetUInt16Value(PlayerFields.Kills, 0);
|
||||
honorStats.LifetimeMaxRank = 0; /// @todo
|
||||
|
||||
SendPacket(honorStats);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.InspectPvp)]
|
||||
void HandleInspectPVP(InspectPVPRequest request)
|
||||
{
|
||||
/// @todo: deal with request.InspectRealmAddress
|
||||
|
||||
Player player = Global.ObjAccessor.FindPlayer(request.InspectTarget);
|
||||
if (!player)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession.HandleInspectPVP: Target {0} not found.", request.InspectTarget.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetPlayer().IsWithinDistInMap(player, SharedConst.InspectDistance, false))
|
||||
return;
|
||||
|
||||
if (GetPlayer().IsValidAttackTarget(player))
|
||||
return;
|
||||
|
||||
InspectPVPResponse response = new InspectPVPResponse();
|
||||
response.ClientGUID = request.InspectTarget;
|
||||
/// @todo: fill brackets
|
||||
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QueryInspectAchievements)]
|
||||
void HandleQueryInspectAchievements(QueryInspectAchievements inspect)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(inspect.Guid);
|
||||
if (!player)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession.HandleQueryInspectAchievements: [{0}] inspected unknown Player [{1}]", GetPlayer().GetGUID().ToString(), inspect.Guid.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetPlayer().IsWithinDistInMap(player, SharedConst.InspectDistance, false))
|
||||
return;
|
||||
|
||||
if (GetPlayer().IsValidAttackTarget(player))
|
||||
return;
|
||||
|
||||
player.SendRespondInspectAchievements(GetPlayer());
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,522 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.DungeonFinding;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Game.DataStorage;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.DfJoin)]
|
||||
void HandleLfgJoin(DFJoin dfJoin)
|
||||
{
|
||||
if (!Global.LFGMgr.isOptionEnabled(LfgOptions.EnableDungeonFinder | LfgOptions.EnableRaidBrowser) ||
|
||||
(GetPlayer().GetGroup() && GetPlayer().GetGroup().GetLeaderGUID() != GetPlayer().GetGUID() &&
|
||||
(GetPlayer().GetGroup().GetMembersCount() == MapConst.MaxGroupSize || !GetPlayer().GetGroup().isLFGGroup())))
|
||||
return;
|
||||
|
||||
if (dfJoin.Slots.Empty())
|
||||
{
|
||||
Log.outDebug(LogFilter.Lfg, "CMSG_DF_JOIN {0} no dungeons selected", GetPlayerInfo());
|
||||
return;
|
||||
}
|
||||
|
||||
List<uint> newDungeons = new List<uint>();
|
||||
foreach (uint slot in dfJoin.Slots)
|
||||
{
|
||||
uint dungeon = slot & 0x00FFFFFF;
|
||||
if (CliDB.LfgDungeonsStorage.ContainsKey(dungeon))
|
||||
newDungeons.Add(dungeon);
|
||||
}
|
||||
|
||||
Log.outDebug(LogFilter.Lfg, "CMSG_DF_JOIN {0} roles: {1}, Dungeons: {2}", GetPlayerInfo(), dfJoin.Roles, newDungeons.Count);
|
||||
|
||||
Global.LFGMgr.JoinLfg(GetPlayer(), dfJoin.Roles, newDungeons);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.DfLeave)]
|
||||
void HandleLfgLeave(DFLeave dfLeave)
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
|
||||
Log.outDebug(LogFilter.Lfg, "CMSG_DF_LEAVE {0} in group: {1} sent guid {2}.", GetPlayerInfo(), group ? 1 : 0, dfLeave.Ticket.RequesterGuid.ToString());
|
||||
|
||||
// Check cheating - only leader can leave the queue
|
||||
if (!group || group.GetLeaderGUID() == dfLeave.Ticket.RequesterGuid)
|
||||
Global.LFGMgr.LeaveLfg(dfLeave.Ticket.RequesterGuid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.DfProposalResponse)]
|
||||
void HandleLfgProposalResult(DFProposalResponse dfProposalResponse)
|
||||
{
|
||||
Log.outDebug(LogFilter.Lfg, "CMSG_LFG_PROPOSAL_RESULT {0} proposal: {1} accept: {2}", GetPlayerInfo(), dfProposalResponse.ProposalID, dfProposalResponse.Accepted ? 1 : 0);
|
||||
Global.LFGMgr.UpdateProposal(dfProposalResponse.ProposalID, GetPlayer().GetGUID(), dfProposalResponse.Accepted);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.DfSetRoles)]
|
||||
void HandleLfgSetRoles(DFSetRoles dfSetRoles)
|
||||
{
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
Log.outDebug(LogFilter.Lfg, "CMSG_DF_SET_ROLES {0} Not in group",
|
||||
GetPlayerInfo());
|
||||
return;
|
||||
}
|
||||
ObjectGuid gguid = group.GetGUID();
|
||||
Log.outDebug(LogFilter.Lfg, "CMSG_DF_SET_ROLES: Group {0}, Player {1}, Roles: {2}", gguid.ToString(), GetPlayerInfo(), dfSetRoles.RolesDesired);
|
||||
Global.LFGMgr.UpdateRoleCheck(gguid, guid, dfSetRoles.RolesDesired);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.DfBootPlayerVote)]
|
||||
void HandleLfgSetBootVote(DFBootPlayerVote dfBootPlayerVote)
|
||||
{
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
Log.outDebug(LogFilter.Lfg, "CMSG_LFG_SET_BOOT_VOTE {0} agree: {1}", GetPlayerInfo(), dfBootPlayerVote.Vote ? 1 : 0);
|
||||
Global.LFGMgr.UpdateBoot(guid, dfBootPlayerVote.Vote);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.DfTeleport)]
|
||||
void HandleLfgTeleport(DFTeleport dfTeleport)
|
||||
{
|
||||
Log.outDebug(LogFilter.Lfg, "CMSG_DF_TELEPORT {0} out: {1}", GetPlayerInfo(), dfTeleport.TeleportOut ? 1 : 0);
|
||||
Global.LFGMgr.TeleportPlayer(GetPlayer(), dfTeleport.TeleportOut, true);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.DfGetSystemInfo, Processing = PacketProcessing.ThreadSafe)]
|
||||
void HandleDfGetSystemInfo(DFGetSystemInfo dfGetSystemInfo)
|
||||
{
|
||||
Log.outDebug(LogFilter.Lfg, "CMSG_LFG_Lock_INFO_REQUEST {0} for {1}", GetPlayerInfo(), (dfGetSystemInfo.Player ? "player" : "party"));
|
||||
|
||||
if (dfGetSystemInfo.Player)
|
||||
SendLfgPlayerLockInfo();
|
||||
else
|
||||
SendLfgPartyLockInfo();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.DfGetJoinStatus, Processing = PacketProcessing.ThreadSafe)]
|
||||
void HandleDfGetJoinStatus(DFGetJoinStatus packet)
|
||||
{
|
||||
if (!GetPlayer().isUsingLfg())
|
||||
return;
|
||||
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
LfgUpdateData updateData = Global.LFGMgr.GetLfgStatus(guid);
|
||||
|
||||
if (GetPlayer().GetGroup())
|
||||
{
|
||||
SendLfgUpdateStatus(updateData, true);
|
||||
updateData.dungeons.Clear();
|
||||
SendLfgUpdateStatus(updateData, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendLfgUpdateStatus(updateData, false);
|
||||
updateData.dungeons.Clear();
|
||||
SendLfgUpdateStatus(updateData, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendLfgPlayerLockInfo()
|
||||
{
|
||||
// Get Random dungeons that can be done at a certain level and expansion
|
||||
uint level = GetPlayer().getLevel();
|
||||
List<uint> randomDungeons = Global.LFGMgr.GetRandomAndSeasonalDungeons(level, (uint)GetExpansion());
|
||||
|
||||
LfgPlayerInfo lfgPlayerInfo = new LfgPlayerInfo();
|
||||
|
||||
// Get player locked Dungeons
|
||||
foreach (var locked in Global.LFGMgr.GetLockedDungeons(_player.GetGUID()))
|
||||
lfgPlayerInfo.BlackList.Slot.Add(new LFGBlackListSlot(locked.Key, (uint)locked.Value.lockStatus, locked.Value.requiredItemLevel, (int)locked.Value.currentItemLevel));
|
||||
|
||||
foreach (var slot in randomDungeons)
|
||||
{
|
||||
var playerDungeonInfo = new LfgPlayerDungeonInfo();
|
||||
playerDungeonInfo.Slot = slot;
|
||||
playerDungeonInfo.CompletionQuantity = 1;
|
||||
playerDungeonInfo.CompletionLimit = 1;
|
||||
playerDungeonInfo.CompletionCurrencyID = 0;
|
||||
playerDungeonInfo.SpecificQuantity = 0;
|
||||
playerDungeonInfo.SpecificLimit = 1;
|
||||
playerDungeonInfo.OverallQuantity = 0;
|
||||
playerDungeonInfo.OverallLimit = 1;
|
||||
playerDungeonInfo.PurseWeeklyQuantity = 0;
|
||||
playerDungeonInfo.PurseWeeklyLimit = 0;
|
||||
playerDungeonInfo.PurseQuantity = 0;
|
||||
playerDungeonInfo.PurseLimit = 0;
|
||||
playerDungeonInfo.Quantity = 1;
|
||||
playerDungeonInfo.CompletedMask = 0;
|
||||
playerDungeonInfo.EncounterMask = 0;
|
||||
|
||||
LfgReward reward = Global.LFGMgr.GetRandomDungeonReward(slot, level);
|
||||
if (reward != null)
|
||||
{
|
||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(reward.firstQuest);
|
||||
if (quest != null)
|
||||
{
|
||||
playerDungeonInfo.FirstReward = !GetPlayer().CanRewardQuest(quest, false);
|
||||
if (!playerDungeonInfo.FirstReward)
|
||||
quest = Global.ObjectMgr.GetQuestTemplate(reward.otherQuest);
|
||||
|
||||
if (quest != null)
|
||||
{
|
||||
playerDungeonInfo.Rewards.RewardMoney = _player.GetQuestMoneyReward(quest);
|
||||
playerDungeonInfo.Rewards.RewardXP = _player.GetQuestXPReward(quest);
|
||||
for (byte i = 0; i < SharedConst.QuestRewardItemCount; ++i)
|
||||
{
|
||||
uint itemId = quest.RewardItemId[i];
|
||||
if (itemId != 0)
|
||||
playerDungeonInfo.Rewards.Item.Add(new LfgPlayerQuestRewardItem(itemId, quest.RewardItemCount[i]));
|
||||
}
|
||||
|
||||
for (byte i = 0; i < SharedConst.QuestRewardCurrencyCount; ++i)
|
||||
{
|
||||
uint curencyId = quest.RewardCurrencyId[i];
|
||||
if (curencyId != 0)
|
||||
playerDungeonInfo.Rewards.Currency.Add(new LfgPlayerQuestRewardCurrency(curencyId, quest.RewardCurrencyCount[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lfgPlayerInfo.Dungeons.Add(playerDungeonInfo);
|
||||
}
|
||||
|
||||
SendPacket(lfgPlayerInfo);
|
||||
}
|
||||
|
||||
public void SendLfgPartyLockInfo()
|
||||
{
|
||||
ObjectGuid guid = GetPlayer().GetGUID();
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
LfgPartyInfo lfgPartyInfo = new LfgPartyInfo();
|
||||
|
||||
// Get the Locked dungeons of the other party members
|
||||
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
|
||||
{
|
||||
Player plrg = refe.GetSource();
|
||||
if (!plrg)
|
||||
continue;
|
||||
|
||||
ObjectGuid pguid = plrg.GetGUID();
|
||||
if (pguid == guid)
|
||||
continue;
|
||||
|
||||
LFGBlackList lfgBlackList = new LFGBlackList();
|
||||
lfgBlackList.PlayerGuid.Set(pguid);
|
||||
foreach (var locked in Global.LFGMgr.GetLockedDungeons(pguid))
|
||||
lfgBlackList.Slot.Add(new LFGBlackListSlot(locked.Key, (uint)locked.Value.lockStatus, locked.Value.requiredItemLevel, (int)locked.Value.currentItemLevel));
|
||||
|
||||
lfgPartyInfo.Player.Add(lfgBlackList);
|
||||
}
|
||||
|
||||
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_PARTY_INFO {0}", GetPlayerInfo());
|
||||
SendPacket(lfgPartyInfo);
|
||||
}
|
||||
|
||||
public void SendLfgUpdateStatus(LfgUpdateData updateData, bool party)
|
||||
{
|
||||
bool join = false;
|
||||
bool queued = false;
|
||||
|
||||
switch (updateData.updateType)
|
||||
{
|
||||
case LfgUpdateType.JoinQueueInitial: // Joined queue outside the dungeon
|
||||
join = true;
|
||||
break;
|
||||
case LfgUpdateType.JoinQueue:
|
||||
case LfgUpdateType.AddedToQueue: // Rolecheck Success
|
||||
join = true;
|
||||
queued = true;
|
||||
break;
|
||||
case LfgUpdateType.ProposalBegin:
|
||||
join = true;
|
||||
break;
|
||||
case LfgUpdateType.UpdateStatus:
|
||||
join = updateData.state != LfgState.Rolecheck && updateData.state != LfgState.None;
|
||||
queued = updateData.state == LfgState.Queued;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
LFGUpdateStatus lfgUpdateStatus = new LFGUpdateStatus();
|
||||
|
||||
RideTicket ticket = Global.LFGMgr.GetTicket(_player.GetGUID());
|
||||
if (ticket != null)
|
||||
lfgUpdateStatus.Ticket = ticket;
|
||||
|
||||
lfgUpdateStatus.SubType = (byte)LfgQueueType.Dungeon; // other types not implemented
|
||||
lfgUpdateStatus.Reason = (byte)updateData.updateType;
|
||||
|
||||
foreach (var dungeonId in updateData.dungeons)
|
||||
lfgUpdateStatus.Slots.Add(Global.LFGMgr.GetLFGDungeonEntry(dungeonId));
|
||||
|
||||
lfgUpdateStatus.RequestedRoles = (uint)Global.LFGMgr.GetRoles(_player.GetGUID());
|
||||
//lfgUpdateStatus.SuspendedPlayers;
|
||||
lfgUpdateStatus.IsParty = party;
|
||||
lfgUpdateStatus.NotifyUI = true;
|
||||
lfgUpdateStatus.Joined = join;
|
||||
lfgUpdateStatus.LfgJoined = updateData.updateType != LfgUpdateType.RemovedFromQueue;
|
||||
lfgUpdateStatus.Queued = queued;
|
||||
|
||||
SendPacket(lfgUpdateStatus);
|
||||
}
|
||||
|
||||
public void SendLfgRoleChosen(ObjectGuid guid, LfgRoles roles)
|
||||
{
|
||||
RoleChosen roleChosen = new RoleChosen();
|
||||
roleChosen.Player = guid;
|
||||
roleChosen.RoleMask = roles;
|
||||
roleChosen.Accepted = roles > 0;
|
||||
SendPacket(roleChosen);
|
||||
}
|
||||
|
||||
public void SendLfgRoleCheckUpdate(LfgRoleCheck roleCheck)
|
||||
{
|
||||
List<uint> dungeons = new List<uint>();
|
||||
if (roleCheck.rDungeonId != 0)
|
||||
dungeons.Add(roleCheck.rDungeonId);
|
||||
else
|
||||
dungeons = roleCheck.dungeons;
|
||||
|
||||
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_ROLE_CHECK_UPDATE {0}", GetPlayerInfo());
|
||||
|
||||
LFGRoleCheckUpdate lfgRoleCheckUpdate = new LFGRoleCheckUpdate();
|
||||
lfgRoleCheckUpdate.PartyIndex = 127;
|
||||
lfgRoleCheckUpdate.RoleCheckStatus = (byte)roleCheck.state;
|
||||
lfgRoleCheckUpdate.IsBeginning = roleCheck.state == LfgRoleCheckState.Initialiting;
|
||||
|
||||
foreach (var dungeonId in dungeons)
|
||||
lfgRoleCheckUpdate.JoinSlots.Add(Global.LFGMgr.GetLFGDungeonEntry(dungeonId));
|
||||
|
||||
lfgRoleCheckUpdate.BgQueueID = 0;
|
||||
lfgRoleCheckUpdate.GroupFinderActivityID = 0;
|
||||
if (!roleCheck.roles.Empty())
|
||||
{
|
||||
// Leader info MUST be sent 1st :S
|
||||
byte roles = (byte)roleCheck.roles.Find(roleCheck.leader).Value;
|
||||
lfgRoleCheckUpdate.Members.Add(new LFGRoleCheckUpdateMember(roleCheck.leader, roles, Global.WorldMgr.GetCharacterInfo(roleCheck.leader).Level, roles > 0));
|
||||
|
||||
foreach (var it in roleCheck.roles)
|
||||
{
|
||||
if (it.Key == roleCheck.leader)
|
||||
continue;
|
||||
|
||||
roles = (byte)it.Value;
|
||||
lfgRoleCheckUpdate.Members.Add(new LFGRoleCheckUpdateMember(it.Key, roles, Global.WorldMgr.GetCharacterInfo(it.Key).Level, roles > 0));
|
||||
}
|
||||
}
|
||||
|
||||
SendPacket(lfgRoleCheckUpdate);
|
||||
}
|
||||
|
||||
public void SendLfgJoinResult(LfgJoinResultData joinData)
|
||||
{
|
||||
LFGJoinResult lfgJoinResult = new LFGJoinResult();
|
||||
|
||||
RideTicket ticket = Global.LFGMgr.GetTicket(GetPlayer().GetGUID());
|
||||
if (ticket != null)
|
||||
lfgJoinResult.Ticket = ticket;
|
||||
|
||||
lfgJoinResult.Result = (byte)joinData.result;
|
||||
if (joinData.result == LfgJoinResult.RoleCheckFailed)
|
||||
lfgJoinResult.ResultDetail = (byte)joinData.state;
|
||||
|
||||
foreach (var it in joinData.lockmap)
|
||||
{
|
||||
var blackList = new LFGJoinBlackList();
|
||||
blackList.PlayerGuid = it.Key;
|
||||
|
||||
foreach (var lockInfo in it.Value)
|
||||
{
|
||||
Log.outTrace(LogFilter.Lfg, "SendLfgJoinResult:: {0} DungeonID: {1} Lock status: {2} Required itemLevel: {3} Current itemLevel: {4}",
|
||||
it.Key.ToString(), (lockInfo.Key & 0x00FFFFFF), lockInfo.Value.lockStatus, lockInfo.Value.requiredItemLevel, lockInfo.Value.currentItemLevel);
|
||||
|
||||
blackList.Slots.Add(new LFGJoinBlackListSlot((int)lockInfo.Key, (int)lockInfo.Value.lockStatus, lockInfo.Value.requiredItemLevel, (int)lockInfo.Value.currentItemLevel));
|
||||
}
|
||||
}
|
||||
|
||||
SendPacket(lfgJoinResult);
|
||||
}
|
||||
|
||||
public void SendLfgQueueStatus(LfgQueueStatusData queueData)
|
||||
{
|
||||
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_QUEUE_STATUS {0} state: {1} dungeon: {2}, waitTime: {3}, " +
|
||||
"avgWaitTime: {4}, waitTimeTanks: {5}, waitTimeHealer: {6}, waitTimeDps: {7}, queuedTime: {8}, tanks: {9}, healers: {10}, dps: {11}",
|
||||
GetPlayerInfo(), Global.LFGMgr.GetState(GetPlayer().GetGUID()), queueData.dungeonId, queueData.waitTime, queueData.waitTimeAvg,
|
||||
queueData.waitTimeTank, queueData.waitTimeHealer, queueData.waitTimeDps, queueData.queuedTime, queueData.tanks, queueData.healers, queueData.dps);
|
||||
|
||||
LFGQueueStatus lfgQueueStatus = new LFGQueueStatus();
|
||||
|
||||
RideTicket ticket = Global.LFGMgr.GetTicket(GetPlayer().GetGUID());
|
||||
if (ticket != null)
|
||||
lfgQueueStatus.Ticket = ticket;
|
||||
lfgQueueStatus.Slot = queueData.queueId;
|
||||
lfgQueueStatus.AvgWaitTimeMe = (uint)queueData.waitTime;
|
||||
lfgQueueStatus.AvgWaitTime = (uint)queueData.waitTimeAvg;
|
||||
lfgQueueStatus.AvgWaitTimeByRole[0] = (uint)queueData.waitTimeTank;
|
||||
lfgQueueStatus.AvgWaitTimeByRole[1] = (uint)queueData.waitTimeHealer;
|
||||
lfgQueueStatus.AvgWaitTimeByRole[2] = (uint)queueData.waitTimeDps;
|
||||
lfgQueueStatus.LastNeeded[0] = queueData.tanks;
|
||||
lfgQueueStatus.LastNeeded[1] = queueData.healers;
|
||||
lfgQueueStatus.LastNeeded[2] = queueData.dps;
|
||||
lfgQueueStatus.QueuedTime = queueData.queuedTime;
|
||||
|
||||
SendPacket(lfgQueueStatus);
|
||||
}
|
||||
|
||||
public void SendLfgPlayerReward(LfgPlayerRewardData rewardData)
|
||||
{
|
||||
if (rewardData.rdungeonEntry == 0 || rewardData.sdungeonEntry == 0 || rewardData.quest == null)
|
||||
return;
|
||||
|
||||
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_PLAYER_REWARD {0} rdungeonEntry: {1}, sdungeonEntry: {2}, done: {3}",
|
||||
GetPlayerInfo(), rewardData.rdungeonEntry, rewardData.sdungeonEntry, rewardData.done);
|
||||
|
||||
LFGPlayerReward lfgPlayerReward = new LFGPlayerReward();
|
||||
lfgPlayerReward.QueuedSlot = rewardData.rdungeonEntry;
|
||||
lfgPlayerReward.ActualSlot = rewardData.sdungeonEntry;
|
||||
lfgPlayerReward.RewardMoney = GetPlayer().GetQuestMoneyReward(rewardData.quest);
|
||||
lfgPlayerReward.AddedXP = GetPlayer().GetQuestXPReward(rewardData.quest);
|
||||
|
||||
for (byte i = 0; i < SharedConst.QuestRewardItemCount; ++i)
|
||||
{
|
||||
uint itemId = rewardData.quest.RewardItemId[i];
|
||||
if (itemId != 0)
|
||||
lfgPlayerReward.Rewards.Add(new LFGPlayerRewards(itemId, rewardData.quest.RewardItemCount[i], 0, false));
|
||||
}
|
||||
|
||||
for (byte i = 0; i < SharedConst.QuestRewardCurrencyCount; ++i)
|
||||
{
|
||||
uint currencyId = rewardData.quest.RewardCurrencyId[i];
|
||||
if (currencyId != 0)
|
||||
lfgPlayerReward.Rewards.Add(new LFGPlayerRewards(currencyId, rewardData.quest.RewardCurrencyCount[i], 0, true));
|
||||
}
|
||||
|
||||
SendPacket(lfgPlayerReward);
|
||||
}
|
||||
|
||||
public void SendLfgBootProposalUpdate(LfgPlayerBoot boot)
|
||||
{
|
||||
LfgAnswer playerVote = boot.votes.LookupByKey(GetPlayer().GetGUID());
|
||||
byte votesNum = 0;
|
||||
byte agreeNum = 0;
|
||||
uint secsleft = (uint)((boot.cancelTime - Time.UnixTime) / 1000);
|
||||
foreach (var it in boot.votes)
|
||||
{
|
||||
if (it.Value != LfgAnswer.Pending)
|
||||
{
|
||||
++votesNum;
|
||||
if (it.Value == LfgAnswer.Agree)
|
||||
++agreeNum;
|
||||
}
|
||||
}
|
||||
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_BOOT_PROPOSAL_UPDATE {0} inProgress: {1} - didVote: {2} - agree: {3} - victim: {4} votes: {5} - agrees: {6} - left: {7} - needed: {8} - reason {9}",
|
||||
GetPlayerInfo(), boot.inProgress, playerVote != LfgAnswer.Pending, playerVote == LfgAnswer.Agree, boot.victim.ToString(), votesNum, agreeNum, secsleft, SharedConst.LFGKickVotesNeeded, boot.reason);
|
||||
|
||||
LfgBootPlayer lfgBootPlayer = new LfgBootPlayer();
|
||||
lfgBootPlayer.Info.VoteInProgress = boot.inProgress; // Vote in progress
|
||||
lfgBootPlayer.Info.VotePassed = agreeNum >= SharedConst.LFGKickVotesNeeded; // Did succeed
|
||||
lfgBootPlayer.Info.MyVoteCompleted = playerVote != LfgAnswer.Pending; // Did Vote
|
||||
lfgBootPlayer.Info.MyVote = playerVote == LfgAnswer.Agree; // Agree
|
||||
lfgBootPlayer.Info.Target = boot.victim; // Victim GUID
|
||||
lfgBootPlayer.Info.TotalVotes = votesNum; // Total Votes
|
||||
lfgBootPlayer.Info.BootVotes = agreeNum; // Agree Count
|
||||
lfgBootPlayer.Info.TimeLeft = secsleft; // Time Left
|
||||
lfgBootPlayer.Info.VotesNeeded = SharedConst.LFGKickVotesNeeded; // Needed Votes
|
||||
lfgBootPlayer.Info.Reason = boot.reason; // Kick reason
|
||||
SendPacket(lfgBootPlayer);
|
||||
}
|
||||
|
||||
public void SendLfgProposalUpdate(LfgProposal proposal)
|
||||
{
|
||||
ObjectGuid playerGuid = GetPlayer().GetGUID();
|
||||
ObjectGuid guildGuid = proposal.players.LookupByKey(playerGuid).group;
|
||||
bool silent = !proposal.isNew && guildGuid == proposal.group;
|
||||
uint dungeonEntry = proposal.dungeonId;
|
||||
|
||||
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_PROPOSAL_UPDATE {0} state: {1}", GetPlayerInfo(), proposal.state);
|
||||
|
||||
// show random dungeon if player selected random dungeon and it's not lfg group
|
||||
if (!silent)
|
||||
{
|
||||
List<uint> playerDungeons = Global.LFGMgr.GetSelectedDungeons(playerGuid);
|
||||
if (!playerDungeons.Contains(proposal.dungeonId))
|
||||
dungeonEntry = playerDungeons.First();
|
||||
}
|
||||
|
||||
LFGProposalUpdate lfgProposalUpdate = new LFGProposalUpdate();
|
||||
|
||||
RideTicket ticket = Global.LFGMgr.GetTicket(GetPlayer().GetGUID());
|
||||
if (ticket != null)
|
||||
lfgProposalUpdate.Ticket = ticket;
|
||||
lfgProposalUpdate.InstanceID = 0;
|
||||
lfgProposalUpdate.ProposalID = proposal.id;
|
||||
lfgProposalUpdate.Slot = Global.LFGMgr.GetLFGDungeonEntry(dungeonEntry);
|
||||
lfgProposalUpdate.State = (byte)proposal.state;
|
||||
lfgProposalUpdate.CompletedMask = proposal.encounters;
|
||||
lfgProposalUpdate.ValidCompletedMask = true;
|
||||
lfgProposalUpdate.ProposalSilent = silent;
|
||||
lfgProposalUpdate.IsRequeue = !proposal.isNew;
|
||||
|
||||
foreach (var pair in proposal.players)
|
||||
{
|
||||
var proposalPlayer = new LFGProposalUpdatePlayer();
|
||||
proposalPlayer.Roles = (uint)pair.Value.role;
|
||||
proposalPlayer.Me = (pair.Key == playerGuid);
|
||||
proposalPlayer.MyParty = !pair.Value.group.IsEmpty() && pair.Value.group == proposal.group;
|
||||
proposalPlayer.SameParty = !pair.Value.group.IsEmpty() && pair.Value.group == guildGuid;
|
||||
proposalPlayer.Responded = (pair.Value.accept != LfgAnswer.Pending);
|
||||
proposalPlayer.Accepted = (pair.Value.accept == LfgAnswer.Agree);
|
||||
|
||||
lfgProposalUpdate.Players.Add(proposalPlayer);
|
||||
}
|
||||
|
||||
SendPacket(lfgProposalUpdate);
|
||||
}
|
||||
|
||||
public void SendLfgDisabled()
|
||||
{
|
||||
SendPacket(new LfgDisabled());
|
||||
}
|
||||
|
||||
public void SendLfgOfferContinue(uint dungeonEntry)
|
||||
{
|
||||
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_OFFER_CONTINUE {0} dungeon entry: {1}", GetPlayerInfo(), dungeonEntry);
|
||||
SendPacket(new LfgOfferContinue(Global.LFGMgr.GetLFGDungeonEntry(dungeonEntry)));
|
||||
}
|
||||
|
||||
public void SendLfgTeleportError(LfgTeleportResult err)
|
||||
{
|
||||
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_TELEPORT_DENIED {0} reason: {1}", GetPlayerInfo(), err);
|
||||
SendPacket(new LfgTeleportDenied(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.LogoutRequest)]
|
||||
void HandleLogoutRequest(LogoutRequest packet)
|
||||
{
|
||||
Player pl = GetPlayer();
|
||||
if (!GetPlayer().GetLootGUID().IsEmpty())
|
||||
GetPlayer().SendLootReleaseAll();
|
||||
|
||||
bool instantLogout = (pl.HasFlag(PlayerFields.Flags, PlayerFlags.Resting) && !pl.IsInCombat() ||
|
||||
pl.IsInFlight() || HasPermission(RBACPermissions.InstantLogout));
|
||||
|
||||
bool canLogoutInCombat = pl.HasFlag(PlayerFields.Flags, PlayerFlags.Resting);
|
||||
|
||||
int reason = 0;
|
||||
if (pl.IsInCombat() && !canLogoutInCombat)
|
||||
reason = 1;
|
||||
else if (pl.IsFalling())
|
||||
reason = 3; // is jumping or falling
|
||||
else if (pl.duel != null || pl.HasAura(9454)) // is dueling or frozen by GM via freeze command
|
||||
reason = 2; // FIXME - Need the correct value
|
||||
|
||||
LogoutResponse logoutResponse = new LogoutResponse();
|
||||
logoutResponse.LogoutResult = reason;
|
||||
logoutResponse.Instant = instantLogout;
|
||||
SendPacket(logoutResponse);
|
||||
|
||||
if (reason != 0)
|
||||
{
|
||||
SetLogoutStartTime(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// instant logout in taverns/cities or on taxi or for admins, gm's, mod's if its enabled in worldserver.conf
|
||||
if (instantLogout)
|
||||
{
|
||||
LogoutPlayer(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// not set flags if player can't free move to prevent lost state at logout cancel
|
||||
if (pl.CanFreeMove())
|
||||
{
|
||||
if (pl.GetStandState() == UnitStandStateType.Stand)
|
||||
pl.SetStandState(UnitStandStateType.Sit);
|
||||
pl.SetRooted(true);
|
||||
pl.SetFlag(UnitFields.Flags, UnitFlags.Stunned);
|
||||
}
|
||||
|
||||
SetLogoutStartTime(Time.UnixTime);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.LogoutCancel)]
|
||||
void HandleLogoutCancel(LogoutCancel packet)
|
||||
{
|
||||
// Player have already logged out serverside, too late to cancel
|
||||
if (!GetPlayer())
|
||||
return;
|
||||
|
||||
SetLogoutStartTime(0);
|
||||
|
||||
SendPacket(new LogoutCancelAck());
|
||||
|
||||
// not remove flags if can't free move - its not set in Logout request code.
|
||||
if (GetPlayer().CanFreeMove())
|
||||
{
|
||||
//!we can move again
|
||||
GetPlayer().SetRooted(false);
|
||||
|
||||
//! Stand Up
|
||||
GetPlayer().SetStandState(UnitStandStateType.Stand);
|
||||
|
||||
//! DISABLE_ROTATE
|
||||
GetPlayer().RemoveFlag(UnitFields.Flags, UnitFlags.Stunned);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,585 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using Game.Guilds;
|
||||
using Game.Loots;
|
||||
using Game.Maps;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.LootItem)]
|
||||
void HandleAutostoreLootItem(LootItemPkt packet)
|
||||
{
|
||||
Player player = GetPlayer();
|
||||
AELootResult aeResult = player.GetAELootView().Count > 1 ? new AELootResult() : null;
|
||||
|
||||
/// @todo Implement looting by LootObject guid
|
||||
foreach (LootRequest req in packet.Loot)
|
||||
{
|
||||
Loot loot = null;
|
||||
ObjectGuid lguid = player.GetLootWorldObjectGUID(req.Object);
|
||||
|
||||
if (lguid.IsGameObject())
|
||||
{
|
||||
GameObject go = player.GetMap().GetGameObject(lguid);
|
||||
|
||||
// not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
|
||||
if (!go || ((go.GetOwnerGUID() != player.GetGUID() && go.GetGoType() != GameObjectTypes.FishingHole) && !go.IsWithinDistInMap(player, SharedConst.InteractionDistance)))
|
||||
{
|
||||
player.SendLootRelease(lguid);
|
||||
continue;
|
||||
}
|
||||
|
||||
loot = go.loot;
|
||||
}
|
||||
else if (lguid.IsItem())
|
||||
{
|
||||
Item pItem = player.GetItemByGuid(lguid);
|
||||
|
||||
if (!pItem)
|
||||
{
|
||||
player.SendLootRelease(lguid);
|
||||
continue;
|
||||
}
|
||||
|
||||
loot = pItem.loot;
|
||||
}
|
||||
else if (lguid.IsCorpse())
|
||||
{
|
||||
Corpse bones = ObjectAccessor.GetCorpse(player, lguid);
|
||||
if (!bones)
|
||||
{
|
||||
player.SendLootRelease(lguid);
|
||||
continue;
|
||||
}
|
||||
|
||||
loot = bones.loot;
|
||||
}
|
||||
else
|
||||
{
|
||||
Creature creature = player.GetMap().GetCreature(lguid);
|
||||
|
||||
bool lootAllowed = creature && creature.IsAlive() == (player.GetClass() == Class.Rogue && creature.loot.loot_type == LootType.Pickpocketing);
|
||||
if (!lootAllowed || !creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance))
|
||||
{
|
||||
player.SendLootError(req.Object, lguid, lootAllowed ? LootError.TooFar : LootError.DidntKill);
|
||||
continue;
|
||||
}
|
||||
|
||||
loot = creature.loot;
|
||||
}
|
||||
|
||||
player.StoreLootItem((byte)(req.LootListID - 1), loot, aeResult);
|
||||
|
||||
// If player is removing the last LootItem, delete the empty container.
|
||||
if (loot.isLooted() && lguid.IsItem())
|
||||
player.GetSession().DoLootRelease(lguid);
|
||||
}
|
||||
|
||||
if (aeResult != null)
|
||||
{
|
||||
foreach (var resultValue in aeResult.GetByOrder())
|
||||
{
|
||||
player.SendNewItem(resultValue.item, resultValue.count, false, false, true);
|
||||
player.UpdateCriteria(CriteriaTypes.LootItem, resultValue.item.GetEntry(), resultValue.count);
|
||||
player.UpdateCriteria(CriteriaTypes.LootType, resultValue.item.GetEntry(), resultValue.count, (ulong)resultValue.lootType);
|
||||
player.UpdateCriteria(CriteriaTypes.LootEpicItem, resultValue.item.GetEntry(), resultValue.count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.LootMoney)]
|
||||
void HandleLootMoney(LootMoney lootMoney)
|
||||
{
|
||||
Player player = GetPlayer();
|
||||
|
||||
foreach (var lootView in player.GetAELootView())
|
||||
{
|
||||
ObjectGuid guid = lootView.Value;
|
||||
Loot loot = null;
|
||||
bool shareMoney = true;
|
||||
|
||||
switch (guid.GetHigh())
|
||||
{
|
||||
case HighGuid.GameObject:
|
||||
{
|
||||
GameObject go = player.GetMap().GetGameObject(guid);
|
||||
|
||||
// do not check distance for GO if player is the owner of it (ex. fishing bobber)
|
||||
if (go && ((go.GetOwnerGUID() == player.GetGUID() || go.IsWithinDistInMap(player, SharedConst.InteractionDistance))))
|
||||
loot = go.loot;
|
||||
|
||||
break;
|
||||
}
|
||||
case HighGuid.Corpse: // remove insignia ONLY in BG
|
||||
{
|
||||
Corpse bones = ObjectAccessor.GetCorpse(player, guid);
|
||||
|
||||
if (bones && bones.IsWithinDistInMap(player, SharedConst.InteractionDistance))
|
||||
{
|
||||
loot = bones.loot;
|
||||
shareMoney = false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case HighGuid.Item:
|
||||
{
|
||||
Item item = player.GetItemByGuid(guid);
|
||||
if (item)
|
||||
{
|
||||
loot = item.loot;
|
||||
shareMoney = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HighGuid.Creature:
|
||||
case HighGuid.Vehicle:
|
||||
{
|
||||
Creature creature = player.GetMap().GetCreature(guid);
|
||||
bool lootAllowed = creature && creature.IsAlive() == (player.GetClass() == Class.Rogue && creature.loot.loot_type == LootType.Pickpocketing);
|
||||
if (lootAllowed && creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance))
|
||||
{
|
||||
loot = creature.loot;
|
||||
if (creature.IsAlive())
|
||||
shareMoney = false;
|
||||
}
|
||||
else
|
||||
player.SendLootError(lootView.Key, guid, lootAllowed ? LootError.TooFar : LootError.DidntKill);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue; // unlootable type
|
||||
}
|
||||
|
||||
if (loot == null)
|
||||
continue;
|
||||
|
||||
loot.NotifyMoneyRemoved();
|
||||
if (shareMoney && player.GetGroup() != null) //item, pickpocket and players can be looted only single player
|
||||
{
|
||||
|
||||
Group group = player.GetGroup();
|
||||
|
||||
List<Player> playersNear = new List<Player>();
|
||||
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
|
||||
{
|
||||
Player member = refe.GetSource();
|
||||
if (!member)
|
||||
continue;
|
||||
|
||||
if (player.IsAtGroupRewardDistance(member))
|
||||
playersNear.Add(member);
|
||||
}
|
||||
|
||||
uint goldPerPlayer = (uint)(loot.gold / playersNear.Count);
|
||||
|
||||
foreach (var pl in playersNear)
|
||||
{
|
||||
pl.ModifyMoney(goldPerPlayer);
|
||||
pl.UpdateCriteria(CriteriaTypes.LootMoney, goldPerPlayer);
|
||||
|
||||
Guild guild = Global.GuildMgr.GetGuildById(pl.GetGuildId());
|
||||
if (guild)
|
||||
{
|
||||
uint guildGold = MathFunctions.CalculatePct(goldPerPlayer, pl.GetTotalAuraModifier(AuraType.DepositBonusMoneyInGuildBankOnLoot));
|
||||
if (guildGold != 0)
|
||||
guild.HandleMemberDepositMoney(this, guildGold, true);
|
||||
}
|
||||
|
||||
LootMoneyNotify packet = new LootMoneyNotify();
|
||||
packet.Money = goldPerPlayer;
|
||||
packet.SoleLooter = playersNear.Count <= 1 ? true : false;
|
||||
pl.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
player.ModifyMoney(loot.gold);
|
||||
player.UpdateCriteria(CriteriaTypes.LootMoney, loot.gold);
|
||||
|
||||
Guild guild = Global.GuildMgr.GetGuildById(player.GetGuildId());
|
||||
if (guild)
|
||||
{
|
||||
uint guildGold = MathFunctions.CalculatePct(loot.gold, player.GetTotalAuraModifier(AuraType.DepositBonusMoneyInGuildBankOnLoot));
|
||||
if (guildGold != 0)
|
||||
guild.HandleMemberDepositMoney(this, guildGold, true);
|
||||
}
|
||||
|
||||
LootMoneyNotify packet = new LootMoneyNotify();
|
||||
packet.Money = loot.gold;
|
||||
packet.SoleLooter = true; // "You loot..."
|
||||
SendPacket(packet);
|
||||
}
|
||||
|
||||
loot.gold = 0;
|
||||
|
||||
// Delete the money loot record from the DB
|
||||
if (!loot.containerID.IsEmpty())
|
||||
loot.DeleteLootMoneyFromContainerItemDB();
|
||||
|
||||
// Delete container if empty
|
||||
if (loot.isLooted() && guid.IsItem())
|
||||
player.GetSession().DoLootRelease(guid);
|
||||
}
|
||||
}
|
||||
|
||||
class AELootCreatureCheck : ICheck<Creature>
|
||||
{
|
||||
public static float LootDistance = 30.0f;
|
||||
|
||||
public AELootCreatureCheck(Player looter, ObjectGuid mainLootTarget)
|
||||
{
|
||||
_looter = looter;
|
||||
_mainLootTarget = mainLootTarget;
|
||||
}
|
||||
|
||||
public bool Invoke(Creature creature)
|
||||
{
|
||||
if (creature.IsAlive())
|
||||
return false;
|
||||
|
||||
if (creature.GetGUID() == _mainLootTarget)
|
||||
return false;
|
||||
|
||||
if (!_looter.IsWithinDist(creature, LootDistance))
|
||||
return false;
|
||||
|
||||
return _looter.isAllowedToLoot(creature);
|
||||
}
|
||||
|
||||
Player _looter;
|
||||
ObjectGuid _mainLootTarget;
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.LootUnit)]
|
||||
void HandleLoot(LootUnit packet)
|
||||
{
|
||||
// Check possible cheat
|
||||
if (!GetPlayer().IsAlive() || !packet.Unit.IsCreatureOrVehicle())
|
||||
return;
|
||||
|
||||
List<Creature> corpses = new List<Creature>();
|
||||
AELootCreatureCheck check = new AELootCreatureCheck(_player, packet.Unit);
|
||||
CreatureListSearcher searcher = new CreatureListSearcher(_player, corpses, check);
|
||||
Cell.VisitGridObjects(_player, searcher, AELootCreatureCheck.LootDistance);
|
||||
|
||||
if (!corpses.Empty())
|
||||
SendPacket(new AELootTargets((uint)corpses.Count + 1));
|
||||
|
||||
GetPlayer().SendLoot(packet.Unit, LootType.Corpse);
|
||||
|
||||
if (!corpses.Empty())
|
||||
{
|
||||
// main target
|
||||
SendPacket(new AELootTargetsAck());
|
||||
|
||||
foreach (Creature creature in corpses)
|
||||
{
|
||||
GetPlayer().SendLoot(creature.GetGUID(), LootType.Corpse, true);
|
||||
SendPacket(new AELootTargetsAck());
|
||||
}
|
||||
}
|
||||
|
||||
// interrupt cast
|
||||
if (GetPlayer().IsNonMeleeSpellCast(false))
|
||||
GetPlayer().InterruptNonMeleeSpells(false);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.LootRelease)]
|
||||
void HandleLootRelease(LootRelease packet)
|
||||
{
|
||||
// cheaters can modify lguid to prevent correct apply loot release code and re-loot
|
||||
// use internal stored guid
|
||||
if (GetPlayer().HasLootWorldObjectGUID(packet.Unit))
|
||||
DoLootRelease(packet.Unit);
|
||||
}
|
||||
|
||||
public void DoLootRelease(ObjectGuid lguid)
|
||||
{
|
||||
Player player = GetPlayer();
|
||||
Loot loot;
|
||||
|
||||
if (player.GetLootGUID() == lguid)
|
||||
player.SetLootGUID(ObjectGuid.Empty);
|
||||
player.SendLootRelease(lguid);
|
||||
|
||||
player.RemoveFlag(UnitFields.Flags, UnitFlags.Looting);
|
||||
|
||||
if (!player.IsInWorld)
|
||||
return;
|
||||
|
||||
if (lguid.IsGameObject())
|
||||
{
|
||||
GameObject go = player.GetMap().GetGameObject(lguid);
|
||||
|
||||
// not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
|
||||
if (!go || ((go.GetOwnerGUID() != player.GetGUID() && go.GetGoType() != GameObjectTypes.FishingHole) && !go.IsWithinDistInMap(player, SharedConst.InteractionDistance)))
|
||||
return;
|
||||
|
||||
loot = go.loot;
|
||||
|
||||
if (go.GetGoType() == GameObjectTypes.Door)
|
||||
{
|
||||
// locked doors are opened with spelleffect openlock, prevent remove its as looted
|
||||
go.UseDoorOrButton();
|
||||
}
|
||||
else if (loot.isLooted() || go.GetGoType() == GameObjectTypes.FishingNode)
|
||||
{
|
||||
if (go.GetGoType() == GameObjectTypes.FishingHole)
|
||||
{ // The fishing hole used once more
|
||||
go.AddUse(); // if the max usage is reached, will be despawned in next tick
|
||||
if (go.GetUseCount() >= go.m_goValue.FishingHole.MaxOpens)
|
||||
go.SetLootState(LootState.JustDeactivated);
|
||||
else
|
||||
go.SetLootState(LootState.Ready);
|
||||
}
|
||||
else
|
||||
go.SetLootState(LootState.JustDeactivated);
|
||||
|
||||
loot.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// not fully looted object
|
||||
go.SetLootState(LootState.Activated, player);
|
||||
|
||||
// if the round robin player release, reset it.
|
||||
if (player.GetGUID() == loot.roundRobinPlayer)
|
||||
loot.roundRobinPlayer.Clear();
|
||||
}
|
||||
}
|
||||
else if (lguid.IsCorpse()) // ONLY remove insignia at BG
|
||||
{
|
||||
Corpse corpse = ObjectAccessor.GetCorpse(player, lguid);
|
||||
if (!corpse || !corpse.IsWithinDistInMap(player, SharedConst.InteractionDistance))
|
||||
return;
|
||||
|
||||
loot = corpse.loot;
|
||||
|
||||
if (loot.isLooted())
|
||||
{
|
||||
loot.clear();
|
||||
corpse.RemoveFlag(CorpseFields.DynamicFlags, 0x0001);
|
||||
}
|
||||
}
|
||||
else if (lguid.IsItem())
|
||||
{
|
||||
Item pItem = player.GetItemByGuid(lguid);
|
||||
if (!pItem)
|
||||
return;
|
||||
|
||||
ItemTemplate proto = pItem.GetTemplate();
|
||||
|
||||
// destroy only 5 items from stack in case prospecting and milling
|
||||
if (proto.GetFlags().HasAnyFlag(ItemFlags.IsProspectable | ItemFlags.IsMillable))
|
||||
{
|
||||
pItem.m_lootGenerated = false;
|
||||
pItem.loot.clear();
|
||||
|
||||
uint count = pItem.GetCount();
|
||||
|
||||
// >=5 checked in spell code, but will work for cheating cases also with removing from another stacks.
|
||||
if (count > 5)
|
||||
count = 5;
|
||||
|
||||
player.DestroyItemCount(pItem, ref count, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pItem.loot.isLooted() || !proto.GetFlags().HasAnyFlag(ItemFlags.HasLoot)) // Only delete item if no loot or money (unlooted loot is saved to db)
|
||||
player.DestroyItem(pItem.GetBagSlot(), pItem.GetSlot(), true);
|
||||
}
|
||||
return; // item can be looted only single player
|
||||
}
|
||||
else
|
||||
{
|
||||
Creature creature = player.GetMap().GetCreature(lguid);
|
||||
|
||||
bool lootAllowed = creature && creature.IsAlive() == (player.GetClass() == Class.Rogue && creature.loot.loot_type == LootType.Pickpocketing);
|
||||
if (!lootAllowed || !creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance))
|
||||
return;
|
||||
|
||||
loot = creature.loot;
|
||||
if (loot.isLooted())
|
||||
{
|
||||
creature.RemoveFlag(ObjectFields.DynamicFlags, UnitDynFlags.Lootable);
|
||||
|
||||
// skip pickpocketing loot for speed, skinning timer reduction is no-op in fact
|
||||
if (!creature.IsAlive())
|
||||
creature.AllLootRemovedFromCorpse();
|
||||
|
||||
loot.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the round robin player release, reset it.
|
||||
if (player.GetGUID() == loot.roundRobinPlayer)
|
||||
{
|
||||
loot.roundRobinPlayer.Clear();
|
||||
|
||||
Group group = player.GetGroup();
|
||||
if (group)
|
||||
{
|
||||
if (group.GetLootMethod() != LootMethod.MasterLoot)
|
||||
group.SendLooter(creature, null);
|
||||
|
||||
|
||||
}
|
||||
// force dynflag update to update looter and lootable info
|
||||
creature.ForceValuesUpdateAtIndex(ObjectFields.DynamicFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Player is not looking at loot list, he doesn't need to see updates on the loot list
|
||||
loot.RemoveLooter(player.GetGUID());
|
||||
player.RemoveAELootedObject(loot.GetGUID());
|
||||
}
|
||||
|
||||
void DoLootReleaseAll()
|
||||
{
|
||||
Dictionary<ObjectGuid, ObjectGuid> lootView = _player.GetAELootView();
|
||||
foreach (var lootPair in lootView)
|
||||
DoLootRelease(lootPair.Value);
|
||||
}
|
||||
|
||||
//[WorldPacketHandler(ClientOpcodes.MasterLootItem)]
|
||||
void HandleLootMasterGive(WorldPacket packet)
|
||||
{
|
||||
ObjectGuid lootguid = packet.ReadPackedGuid();
|
||||
byte slotid = packet.ReadUInt8();
|
||||
ObjectGuid target_playerguid = packet.ReadPackedGuid();
|
||||
|
||||
if (GetPlayer().GetGroup() == null || GetPlayer().GetGroup().GetLooterGuid() != GetPlayer().GetGUID() || GetPlayer().GetGroup().GetLootMethod() != LootMethod.MasterLoot)
|
||||
{
|
||||
GetPlayer().SendLootError(lootguid, ObjectGuid.Empty, LootError.DidntKill);
|
||||
return;
|
||||
}
|
||||
|
||||
Player target = Global.ObjAccessor.FindPlayer(target_playerguid);
|
||||
if (!target)
|
||||
{
|
||||
GetPlayer().SendLootError(lootguid, ObjectGuid.Empty, LootError.PlayerNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.outDebug(LogFilter.Network, "HandleLootMasterGive (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [{0}].", target.GetName());
|
||||
|
||||
if (GetPlayer().GetLootGUID() != lootguid)
|
||||
{
|
||||
GetPlayer().SendLootError(lootguid, ObjectGuid.Empty, LootError.DidntKill);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetPlayer().IsInRaidWith(target) || !GetPlayer().IsInMap(target))
|
||||
{
|
||||
GetPlayer().SendLootError(lootguid, ObjectGuid.Empty, LootError.MasterOther);
|
||||
Log.outInfo(LogFilter.Loot, "MasterLootItem: Player {0} tried to give an item to ineligible player {1}!", GetPlayer().GetName(), target.GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
Loot loot = null;
|
||||
|
||||
if (GetPlayer().GetLootGUID().IsCreatureOrVehicle())
|
||||
{
|
||||
Creature creature = GetPlayer().GetMap().GetCreature(lootguid);
|
||||
if (creature == null)
|
||||
return;
|
||||
|
||||
loot = creature.loot;
|
||||
}
|
||||
else if (GetPlayer().GetLootGUID().IsGameObject())
|
||||
{
|
||||
GameObject pGO = GetPlayer().GetMap().GetGameObject(lootguid);
|
||||
if (pGO == null)
|
||||
return;
|
||||
|
||||
loot = pGO.loot;
|
||||
}
|
||||
|
||||
if (loot == null)
|
||||
return;
|
||||
|
||||
if (slotid >= loot.items.Count + loot.quest_items.Count)
|
||||
{
|
||||
Log.outDebug(LogFilter.Loot, "MasterLootItem: Player {0} might be using a hack! (slot {1}, size {2})",
|
||||
GetPlayer().GetName(), slotid, loot.items.Count);
|
||||
return;
|
||||
}
|
||||
|
||||
LootItem item = slotid >= loot.items.Count ? loot.quest_items[slotid - loot.items.Count] : loot.items[slotid];
|
||||
|
||||
List<ItemPosCount> dest = new List<ItemPosCount>(); ;
|
||||
InventoryResult msg = target.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, item.itemid, item.count);
|
||||
if (item.follow_loot_rules && !item.AllowedForPlayer(target))
|
||||
msg = InventoryResult.CantEquipEver;
|
||||
if (msg != InventoryResult.Ok)
|
||||
{
|
||||
if (msg == InventoryResult.ItemMaxCount)
|
||||
GetPlayer().SendLootError(lootguid, ObjectGuid.Empty, LootError.MasterUniqueItem);
|
||||
else if (msg == InventoryResult.InvFull)
|
||||
GetPlayer().SendLootError(lootguid, ObjectGuid.Empty, LootError.MasterInvFull);
|
||||
else
|
||||
GetPlayer().SendLootError(lootguid, ObjectGuid.Empty, LootError.MasterOther);
|
||||
|
||||
target.SendEquipError(msg, null, null, item.itemid);
|
||||
return;
|
||||
}
|
||||
|
||||
// not move item from loot to target inventory
|
||||
Item newitem = target.StoreNewItem(dest, item.itemid, true, item.randomPropertyId, item.GetAllowedLooters(), item.context, item.BonusListIDs);
|
||||
target.SendNewItem(newitem, item.count, false, false, true);
|
||||
target.UpdateCriteria(CriteriaTypes.LootItem, item.itemid, item.count);
|
||||
target.UpdateCriteria(CriteriaTypes.LootType, item.itemid, item.count, (ulong)loot.loot_type);
|
||||
target.UpdateCriteria(CriteriaTypes.LootEpicItem, item.itemid, item.count);
|
||||
|
||||
// mark as looted
|
||||
item.count = 0;
|
||||
item.is_looted = true;
|
||||
|
||||
loot.NotifyItemRemoved(slotid);
|
||||
--loot.unlootedCount;
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetLootSpecialization)]
|
||||
void HandleSetLootSpecialization(SetLootSpecialization packet)
|
||||
{
|
||||
if (packet.SpecID != 0)
|
||||
{
|
||||
ChrSpecializationRecord chrSpec = CliDB.ChrSpecializationStorage.LookupByKey(packet.SpecID);
|
||||
if (chrSpec != null)
|
||||
{
|
||||
if (chrSpec.ClassID == (uint)GetPlayer().GetClass())
|
||||
GetPlayer().SetLootSpecId(packet.SpecID);
|
||||
}
|
||||
}
|
||||
else
|
||||
GetPlayer().SetLootSpecId(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,698 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Guilds;
|
||||
using Game.Mails;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
bool CanOpenMailBox(ObjectGuid guid)
|
||||
{
|
||||
if (guid == GetPlayer().GetGUID())
|
||||
{
|
||||
if (!HasPermission(RBACPermissions.CommandMailbox))
|
||||
{
|
||||
Log.outWarn(LogFilter.ChatSystem, "{0} attempt open mailbox in cheating way.", GetPlayer().GetName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (guid.IsGameObject())
|
||||
{
|
||||
if (!GetPlayer().GetGameObjectIfCanInteractWith(guid, GameObjectTypes.Mailbox))
|
||||
return false;
|
||||
}
|
||||
else if (guid.IsAnyTypeCreature())
|
||||
{
|
||||
if (!GetPlayer().GetNPCIfCanInteractWith(guid, NPCFlags.Mailbox))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SendMail)]
|
||||
void HandleSendMail(SendMail packet)
|
||||
{
|
||||
if (packet.Info.Attachments.Count > SharedConst.MaxMailItems) // client limit
|
||||
{
|
||||
GetPlayer().SendMailResult(0, MailResponseType.Send, MailResponseResult.TooManyAttachments);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CanOpenMailBox(packet.Info.Mailbox))
|
||||
return;
|
||||
|
||||
if (string.IsNullOrEmpty(packet.Info.Target))
|
||||
return;
|
||||
|
||||
Player player = GetPlayer();
|
||||
if (player.getLevel() < WorldConfig.GetIntValue(WorldCfg.MailLevelReq))
|
||||
{
|
||||
SendNotification(CypherStrings.MailSenderReq, WorldConfig.GetIntValue(WorldCfg.MailLevelReq));
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectGuid receiverGuid = ObjectGuid.Empty;
|
||||
if (ObjectManager.NormalizePlayerName(ref packet.Info.Target))
|
||||
receiverGuid = ObjectManager.GetPlayerGUIDByName(packet.Info.Target);
|
||||
|
||||
if (receiverGuid.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.Network, "Player {0} is sending mail to {1} (GUID: not existed!) with subject {2}" +
|
||||
"and body {3} includes {4} items, {5} copper and {6} COD copper with StationeryID = {7}",
|
||||
GetPlayerInfo(), packet.Info.Target, packet.Info.Subject, packet.Info.Body,
|
||||
packet.Info.Attachments.Count, packet.Info.SendMoney, packet.Info.Cod, packet.Info.StationeryID);
|
||||
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.RecipientNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.Info.SendMoney < 0)
|
||||
{
|
||||
GetPlayer().SendMailResult(0, MailResponseType.Send, MailResponseResult.InternalError);
|
||||
Log.outWarn(LogFilter.Server, "Player {0} attempted to send mail to {1} ({2}) with negative money value (SendMoney: {3})",
|
||||
GetPlayerInfo(), packet.Info.Target, receiverGuid.ToString(), packet.Info.SendMoney);
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.Info.Cod < 0)
|
||||
{
|
||||
GetPlayer().SendMailResult(0, MailResponseType.Send, MailResponseResult.InternalError);
|
||||
Log.outWarn(LogFilter.Server, "Player {0} attempted to send mail to {1} ({2}) with negative COD value (Cod: {3})",
|
||||
GetPlayerInfo(), packet.Info.Target, receiverGuid.ToString(), packet.Info.Cod);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.outInfo(LogFilter.Network, "Player {0} is sending mail to {1} ({2}) with subject {3} and body {4}" +
|
||||
"includes {5} items, {6} copper and {7} COD copper with StationeryID = {8}",
|
||||
GetPlayerInfo(), packet.Info.Target, receiverGuid.ToString(), packet.Info.Subject,
|
||||
packet.Info.Body, packet.Info.Attachments.Count, packet.Info.SendMoney, packet.Info.Cod, packet.Info.StationeryID);
|
||||
|
||||
if (player.GetGUID() == receiverGuid)
|
||||
{
|
||||
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.CannotSendToSelf);
|
||||
return;
|
||||
}
|
||||
|
||||
uint cost = (uint)(!packet.Info.Attachments.Empty() ? 30 * packet.Info.Attachments.Count : 30); // price hardcoded in client
|
||||
|
||||
long reqmoney = cost + packet.Info.SendMoney;
|
||||
|
||||
// Check for overflow
|
||||
if (reqmoney < packet.Info.SendMoney)
|
||||
{
|
||||
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.NotEnoughMoney);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.HasEnoughMoney(reqmoney) && !player.IsGameMaster())
|
||||
{
|
||||
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.NotEnoughMoney);
|
||||
return;
|
||||
}
|
||||
|
||||
Player receiver = Global.ObjAccessor.FindPlayer(receiverGuid);
|
||||
|
||||
Team receiverTeam = 0;
|
||||
byte mailsCount = 0; //do not allow to send to one player more than 100 mails
|
||||
byte receiverLevel = 0;
|
||||
uint receiverAccountId = 0;
|
||||
|
||||
if (receiver)
|
||||
{
|
||||
receiverTeam = receiver.GetTeam();
|
||||
mailsCount = (byte)receiver.GetMails().Count;
|
||||
receiverLevel = (byte)receiver.getLevel();
|
||||
receiverAccountId = receiver.GetSession().GetAccountId();
|
||||
}
|
||||
else
|
||||
{
|
||||
receiverTeam = ObjectManager.GetPlayerTeamByGUID(receiverGuid);
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAIL_COUNT);
|
||||
stmt.AddValue(0, receiverGuid.GetCounter());
|
||||
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
mailsCount = (byte)result.Read<ulong>(0);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_LEVEL);
|
||||
stmt.AddValue(0, receiverGuid.GetCounter());
|
||||
|
||||
result = DB.Characters.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
receiverLevel = result.Read<byte>(0);
|
||||
|
||||
receiverAccountId = ObjectManager.GetPlayerAccountIdByGUID(receiverGuid);
|
||||
}
|
||||
|
||||
// do not allow to have more than 100 mails in mailbox.. mails count is in opcode byte!!! - so max can be 255..
|
||||
if (mailsCount > 100)
|
||||
{
|
||||
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.RecipientCapReached);
|
||||
return;
|
||||
}
|
||||
|
||||
// test the receiver's Faction... or all items are account bound
|
||||
bool accountBound = !packet.Info.Attachments.Empty();
|
||||
foreach (var att in packet.Info.Attachments)
|
||||
{
|
||||
Item item = player.GetItemByGuid(att.ItemGUID);
|
||||
if (item)
|
||||
{
|
||||
ItemTemplate itemProto = item.GetTemplate();
|
||||
if (itemProto == null || !itemProto.GetFlags().HasAnyFlag(ItemFlags.IsBoundToAccount))
|
||||
{
|
||||
accountBound = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!accountBound && player.GetTeam() != receiverTeam && !HasPermission(RBACPermissions.TwoSideInteractionMail))
|
||||
{
|
||||
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.NotYourTeam);
|
||||
return;
|
||||
}
|
||||
|
||||
if (receiverLevel < WorldConfig.GetIntValue(WorldCfg.MailLevelReq))
|
||||
{
|
||||
SendNotification(CypherStrings.MailReceiverReq, WorldConfig.GetIntValue(WorldCfg.MailLevelReq));
|
||||
return;
|
||||
}
|
||||
|
||||
List<Item> items = new List<Item>();
|
||||
foreach (var att in packet.Info.Attachments)
|
||||
{
|
||||
if (att.ItemGUID.IsEmpty())
|
||||
{
|
||||
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.MailAttachmentInvalid);
|
||||
return;
|
||||
}
|
||||
|
||||
Item item = player.GetItemByGuid(att.ItemGUID);
|
||||
|
||||
// prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail)
|
||||
if (!item)
|
||||
{
|
||||
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.MailAttachmentInvalid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!item.CanBeTraded(true))
|
||||
{
|
||||
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.MailBoundItem);
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.IsBoundAccountWide() && item.IsSoulBound() && player.GetSession().GetAccountId() != receiverAccountId)
|
||||
{
|
||||
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.NotSameAccount);
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.GetTemplate().GetFlags().HasAnyFlag(ItemFlags.Conjured) || item.GetUInt32Value(ItemFields.Duration) != 0)
|
||||
{
|
||||
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.MailBoundItem);
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.Info.Cod != 0 && item.HasFlag(ItemFields.Flags, ItemFieldFlags.Wrapped))
|
||||
{
|
||||
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.CantSendWrappedCod);
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.IsNotEmptyBag())
|
||||
{
|
||||
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.DestroyNonemptyBag);
|
||||
return;
|
||||
}
|
||||
|
||||
items.Add(item);
|
||||
}
|
||||
|
||||
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.Ok);
|
||||
|
||||
player.ModifyMoney(-reqmoney);
|
||||
player.UpdateCriteria(CriteriaTypes.GoldSpentForMail, cost);
|
||||
|
||||
bool needItemDelay = false;
|
||||
|
||||
MailDraft draft = new MailDraft(packet.Info.Subject, packet.Info.Body);
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
|
||||
if (!packet.Info.Attachments.Empty() || packet.Info.SendMoney > 0)
|
||||
{
|
||||
bool log = HasPermission(RBACPermissions.LogGmTrade);
|
||||
if (!packet.Info.Attachments.Empty())
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (log)
|
||||
{
|
||||
Log.outCommand(GetAccountId(), "GM {0} ({1}) (Account: {2}) mail item: {3} (Entry: {4} Count: {5}) to player: {6} ({7}) (Account: {8})",
|
||||
GetPlayerName(), GetPlayer().GetGUID().ToString(), GetAccountId(), item.GetTemplate().GetName(), item.GetEntry(), item.GetCount(),
|
||||
packet.Info.Target, receiverGuid.ToString(), receiverAccountId);
|
||||
}
|
||||
|
||||
item.SetNotRefundable(GetPlayer()); // makes the item no longer refundable
|
||||
player.MoveItemFromInventory(item.GetBagSlot(), item.GetSlot(), true);
|
||||
|
||||
item.DeleteFromInventoryDB(trans); // deletes item from character's inventory
|
||||
item.SetOwnerGUID(receiverGuid);
|
||||
item.SetState(ItemUpdateState.Changed);
|
||||
item.SaveToDB(trans); // recursive and not have transaction guard into self, item not in inventory and can be save standalone
|
||||
|
||||
draft.AddItem(item);
|
||||
}
|
||||
|
||||
// if item send to character at another account, then apply item delivery delay
|
||||
needItemDelay = player.GetSession().GetAccountId() != receiverAccountId;
|
||||
}
|
||||
|
||||
if (log && packet.Info.SendMoney > 0)
|
||||
{
|
||||
Log.outCommand(GetAccountId(), "GM {0} ({1}) (Account: {{2}) mail money: {3} to player: {4} ({5}) (Account: {6})",
|
||||
GetPlayerName(), GetPlayer().GetGUID().ToString(), GetAccountId(), packet.Info.SendMoney, packet.Info.Target, receiverGuid.ToString(), receiverAccountId);
|
||||
}
|
||||
}
|
||||
|
||||
// If theres is an item, there is a one hour delivery delay if sent to another account's character.
|
||||
uint deliver_delay = needItemDelay ? WorldConfig.GetUIntValue(WorldCfg.MailDeliveryDelay) : 0;
|
||||
|
||||
// Mail sent between guild members arrives instantly
|
||||
Guild guild = Global.GuildMgr.GetGuildById(player.GetGuildId());
|
||||
if (guild)
|
||||
if (guild.IsMember(receiverGuid))
|
||||
deliver_delay = 0;
|
||||
|
||||
// don't ask for COD if there are no items
|
||||
if (packet.Info.Attachments.Empty())
|
||||
packet.Info.Cod = 0;
|
||||
|
||||
// will delete item or place to receiver mail list
|
||||
draft.AddMoney((ulong)packet.Info.SendMoney).AddCOD((uint)packet.Info.Cod).SendMailTo(trans, new MailReceiver(receiver, receiverGuid.GetCounter()), new MailSender(player), string.IsNullOrEmpty(packet.Info.Body) ? MailCheckMask.Copied : MailCheckMask.HasBody, deliver_delay);
|
||||
|
||||
player.SaveInventoryAndGoldToDB(trans);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
//called when mail is read
|
||||
[WorldPacketHandler(ClientOpcodes.MailMarkAsRead)]
|
||||
void HandleMailMarkAsRead(MailMarkAsRead packet)
|
||||
{
|
||||
if (!CanOpenMailBox(packet.Mailbox))
|
||||
return;
|
||||
|
||||
Player player = GetPlayer();
|
||||
Mail m = player.GetMail(packet.MailID);
|
||||
if (m != null && m.state != MailState.Deleted)
|
||||
{
|
||||
if (player.unReadMails != 0)
|
||||
--player.unReadMails;
|
||||
m.checkMask = m.checkMask | MailCheckMask.Read;
|
||||
player.m_mailsUpdated = true;
|
||||
m.state = MailState.Changed;
|
||||
}
|
||||
}
|
||||
|
||||
//called when client deletes mail
|
||||
[WorldPacketHandler(ClientOpcodes.MailDelete)]
|
||||
void HandleMailDelete(MailDelete packet)
|
||||
{
|
||||
Mail m = GetPlayer().GetMail(packet.MailID);
|
||||
Player player = GetPlayer();
|
||||
player.m_mailsUpdated = true;
|
||||
if (m != null)
|
||||
{
|
||||
// delete shouldn't show up for COD mails
|
||||
if (m.COD != 0)
|
||||
{
|
||||
player.SendMailResult(packet.MailID, MailResponseType.Deleted, MailResponseResult.InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
m.state = MailState.Deleted;
|
||||
}
|
||||
player.SendMailResult(packet.MailID, MailResponseType.Deleted, MailResponseResult.Ok);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.MailReturnToSender)]
|
||||
void HandleMailReturnToSender(MailReturnToSender packet)
|
||||
{
|
||||
if (!CanOpenMailBox(_player.PlayerTalkClass.GetInteractionData().SourceGuid))
|
||||
return;
|
||||
|
||||
Player player = GetPlayer();
|
||||
Mail m = player.GetMail(packet.MailID);
|
||||
if (m == null || m.state == MailState.Deleted || m.deliver_time > Time.UnixTime || m.sender != packet.SenderGUID.GetCounter())
|
||||
{
|
||||
player.SendMailResult(packet.MailID, MailResponseType.ReturnedToSender, MailResponseResult.InternalError);
|
||||
return;
|
||||
}
|
||||
//we can return mail now, so firstly delete the old one
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_MAIL_BY_ID);
|
||||
stmt.AddValue(0, packet.MailID);
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_MAIL_ITEM_BY_ID);
|
||||
stmt.AddValue(0, packet.MailID);
|
||||
trans.Append(stmt);
|
||||
|
||||
player.RemoveMail(packet.MailID);
|
||||
|
||||
// only return mail if the player exists (and delete if not existing)
|
||||
if (m.messageType == MailMessageType.Normal && m.sender != 0)
|
||||
{
|
||||
MailDraft draft = new MailDraft(m.subject, m.body);
|
||||
if (m.mailTemplateId != 0)
|
||||
draft = new MailDraft(m.mailTemplateId, false); // items already included
|
||||
|
||||
if (m.HasItems())
|
||||
{
|
||||
foreach (var itemInfo in m.items)
|
||||
{
|
||||
Item item = player.GetMItem(itemInfo.item_guid);
|
||||
if (item)
|
||||
draft.AddItem(item);
|
||||
player.RemoveMItem(itemInfo.item_guid);
|
||||
}
|
||||
}
|
||||
draft.AddMoney(m.money).SendReturnToSender(GetAccountId(), m.receiver, m.sender, trans);
|
||||
}
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
player.SendMailResult(packet.MailID, MailResponseType.ReturnedToSender, MailResponseResult.Ok);
|
||||
}
|
||||
|
||||
//called when player takes item attached in mail
|
||||
[WorldPacketHandler(ClientOpcodes.MailTakeItem)]
|
||||
void HandleMailTakeItem(MailTakeItem packet)
|
||||
{
|
||||
uint AttachID = packet.AttachID;
|
||||
|
||||
if (!CanOpenMailBox(packet.Mailbox))
|
||||
return;
|
||||
|
||||
Player player = GetPlayer();
|
||||
|
||||
Mail m = player.GetMail(packet.MailID);
|
||||
if (m == null || m.state == MailState.Deleted || m.deliver_time > Time.UnixTime)
|
||||
{
|
||||
player.SendMailResult(packet.MailID, MailResponseType.ItemTaken, MailResponseResult.InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
// verify that the mail has the item to avoid cheaters taking COD items without paying
|
||||
if (!m.items.Any(p => p.item_guid == AttachID))
|
||||
{
|
||||
player.SendMailResult(packet.MailID, MailResponseType.ItemTaken, MailResponseResult.InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent cheating with skip client money check
|
||||
if (!player.HasEnoughMoney(m.COD))
|
||||
{
|
||||
player.SendMailResult(packet.MailID, MailResponseType.ItemTaken, MailResponseResult.NotEnoughMoney);
|
||||
return;
|
||||
}
|
||||
|
||||
Item it = player.GetMItem(packet.AttachID);
|
||||
|
||||
List<ItemPosCount> dest = new List<ItemPosCount>();
|
||||
InventoryResult msg = GetPlayer().CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, dest, it, false);
|
||||
if (msg == InventoryResult.Ok)
|
||||
{
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
m.RemoveItem(packet.AttachID);
|
||||
m.removedItems.Add(packet.AttachID);
|
||||
|
||||
if (m.COD > 0) //if there is COD, take COD money from player and send them to sender by mail
|
||||
{
|
||||
ObjectGuid sender_guid = ObjectGuid.Create(HighGuid.Player, m.sender);
|
||||
Player receiver = Global.ObjAccessor.FindPlayer(sender_guid);
|
||||
|
||||
uint sender_accId = 0;
|
||||
|
||||
if (HasPermission(RBACPermissions.LogGmTrade))
|
||||
{
|
||||
string sender_name;
|
||||
if (receiver)
|
||||
{
|
||||
sender_accId = receiver.GetSession().GetAccountId();
|
||||
sender_name = receiver.GetName();
|
||||
}
|
||||
else
|
||||
{
|
||||
// can be calculated early
|
||||
sender_accId = ObjectManager.GetPlayerAccountIdByGUID(sender_guid);
|
||||
|
||||
if (!ObjectManager.GetPlayerNameByGUID(sender_guid, out sender_name))
|
||||
sender_name = Global.ObjectMgr.GetCypherString(CypherStrings.Unknown);
|
||||
}
|
||||
Log.outCommand(GetAccountId(), "GM {0} (Account: {1}) receiver mail item: {2} (Entry: {3} Count: {4}) and send COD money: {5} to player: {6} (Account: {7})",
|
||||
GetPlayerName(), GetAccountId(), it.GetTemplate().GetName(), it.GetEntry(), it.GetCount(), m.COD, sender_name, sender_accId);
|
||||
}
|
||||
else if (!receiver)
|
||||
sender_accId = ObjectManager.GetPlayerAccountIdByGUID(sender_guid);
|
||||
|
||||
// check player existence
|
||||
if (receiver || sender_accId != 0)
|
||||
{
|
||||
new MailDraft(m.subject, "")
|
||||
.AddMoney(m.COD)
|
||||
.SendMailTo(trans, new MailReceiver(receiver, m.sender), new MailSender( MailMessageType.Normal, m.receiver), MailCheckMask.CodPayment);
|
||||
}
|
||||
|
||||
player.ModifyMoney(-(long)m.COD);
|
||||
}
|
||||
m.COD = 0;
|
||||
m.state = MailState.Changed;
|
||||
player.m_mailsUpdated = true;
|
||||
player.RemoveMItem(it.GetGUID().GetCounter());
|
||||
|
||||
uint count = it.GetCount(); // save counts before store and possible merge with deleting
|
||||
it.SetState(ItemUpdateState.Unchanged); // need to set this state, otherwise item cannot be removed later, if neccessary
|
||||
player.MoveItemToInventory(dest, it, true);
|
||||
|
||||
player.SaveInventoryAndGoldToDB(trans);
|
||||
player._SaveMail(trans);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
player.SendMailResult(packet.MailID, MailResponseType.ItemTaken, MailResponseResult.Ok, 0, packet.AttachID, count);
|
||||
}
|
||||
else
|
||||
player.SendMailResult(packet.MailID, MailResponseType.ItemTaken, MailResponseResult.EquipError, msg);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.MailTakeMoney)]
|
||||
void HandleMailTakeMoney(MailTakeMoney packet)
|
||||
{
|
||||
if (!CanOpenMailBox(packet.Mailbox))
|
||||
return;
|
||||
|
||||
Player player = GetPlayer();
|
||||
|
||||
Mail m = player.GetMail(packet.MailID);
|
||||
if ((m == null || m.state == MailState.Deleted || m.deliver_time > Time.UnixTime) ||
|
||||
(packet.Money > 0 && m.money != (ulong)packet.Money))
|
||||
{
|
||||
player.SendMailResult(packet.MailID, MailResponseType.MoneyTaken, MailResponseResult.InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.ModifyMoney((long)m.money, false))
|
||||
{
|
||||
player.SendMailResult(packet.MailID, MailResponseType.MoneyTaken, MailResponseResult.EquipError, InventoryResult.TooMuchGold);
|
||||
return;
|
||||
}
|
||||
|
||||
m.money = 0;
|
||||
m.state = MailState.Changed;
|
||||
player.m_mailsUpdated = true;
|
||||
|
||||
player.SendMailResult(packet.MailID, MailResponseType.MoneyTaken, MailResponseResult.Ok);
|
||||
|
||||
// save money and mail to prevent cheating
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
player.SaveGoldToDB(trans);
|
||||
player._SaveMail(trans);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
//called when player lists his received mails
|
||||
[WorldPacketHandler(ClientOpcodes.MailGetList)]
|
||||
void HandleGetMailList(MailGetList packet)
|
||||
{
|
||||
if (!CanOpenMailBox(packet.Mailbox))
|
||||
return;
|
||||
|
||||
Player player = GetPlayer();
|
||||
|
||||
//load players mails, and mailed items
|
||||
if (!player.m_mailsLoaded)
|
||||
player._LoadMail();
|
||||
|
||||
var mails = player.GetMails();
|
||||
|
||||
MailListResult response = new MailListResult();
|
||||
long curTime = Time.UnixTime;
|
||||
|
||||
foreach (Mail m in mails)
|
||||
{
|
||||
// skip deleted or not delivered (deliver delay not expired) mails
|
||||
if (m.state == MailState.Deleted || curTime < m.deliver_time)
|
||||
continue;
|
||||
|
||||
// max. 50 mails can be sent
|
||||
if (response.Mails.Count < 50)
|
||||
response.Mails.Add(new MailListEntry(m, player));
|
||||
}
|
||||
|
||||
player.PlayerTalkClass.GetInteractionData().Reset();
|
||||
player.PlayerTalkClass.GetInteractionData().SourceGuid = packet.Mailbox;
|
||||
SendPacket(response);
|
||||
|
||||
// recalculate m_nextMailDelivereTime and unReadMails
|
||||
GetPlayer().UpdateNextMailTimeAndUnreads();
|
||||
}
|
||||
|
||||
//used when player copies mail body to his inventory
|
||||
[WorldPacketHandler(ClientOpcodes.MailCreateTextItem)]
|
||||
void HandleMailCreateTextItem(MailCreateTextItem packet)
|
||||
{
|
||||
if (!CanOpenMailBox(packet.Mailbox))
|
||||
return;
|
||||
|
||||
Player player = GetPlayer();
|
||||
|
||||
Mail m = player.GetMail(packet.MailID);
|
||||
if (m == null || (string.IsNullOrEmpty(m.body) && m.mailTemplateId == 0) || m.state == MailState.Deleted || m.deliver_time > Time.UnixTime)
|
||||
{
|
||||
player.SendMailResult(packet.MailID, MailResponseType.MadePermanent, MailResponseResult.InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
Item bodyItem = new Item(); // This is not bag and then can be used new Item.
|
||||
if (!bodyItem.Create(Global.ObjectMgr.GetGenerator(HighGuid.Item).Generate(), 8383, player))
|
||||
return;
|
||||
|
||||
// in mail template case we need create new item text
|
||||
if (m.mailTemplateId != 0)
|
||||
{
|
||||
MailTemplateRecord mailTemplateEntry = CliDB.MailTemplateStorage.LookupByKey(m.mailTemplateId);
|
||||
if (mailTemplateEntry == null)
|
||||
{
|
||||
player.SendMailResult(packet.MailID, MailResponseType.MadePermanent, MailResponseResult.InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
bodyItem.SetText(mailTemplateEntry.Body[GetSessionDbcLocale()]);
|
||||
}
|
||||
else
|
||||
bodyItem.SetText(m.body);
|
||||
|
||||
if (m.messageType == MailMessageType.Normal)
|
||||
bodyItem.SetGuidValue(ItemFields.Creator, ObjectGuid.Create(HighGuid.Player, m.sender));
|
||||
|
||||
bodyItem.SetFlag(ItemFields.Flags, ItemFieldFlags.Readable);
|
||||
|
||||
Log.outInfo(LogFilter.Network, "HandleMailCreateTextItem mailid={0}", packet.MailID);
|
||||
|
||||
List<ItemPosCount> dest = new List<ItemPosCount>();
|
||||
InventoryResult msg = GetPlayer().CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, dest, bodyItem, false);
|
||||
if (msg == InventoryResult.Ok)
|
||||
{
|
||||
m.checkMask = m.checkMask | MailCheckMask.Copied;
|
||||
m.state = MailState.Changed;
|
||||
player.m_mailsUpdated = true;
|
||||
|
||||
player.StoreItem(dest, bodyItem, true);
|
||||
player.SendMailResult(packet.MailID, MailResponseType.MadePermanent, MailResponseResult.Ok);
|
||||
}
|
||||
else
|
||||
player.SendMailResult(packet.MailID, MailResponseType.MadePermanent, MailResponseResult.EquipError, msg);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QueryNextMailTime)]
|
||||
void HandleQueryNextMailTime(MailQueryNextMailTime packet)
|
||||
{
|
||||
MailQueryNextTimeResult result = new MailQueryNextTimeResult();
|
||||
|
||||
if (!GetPlayer().m_mailsLoaded)
|
||||
GetPlayer()._LoadMail();
|
||||
|
||||
if (GetPlayer().unReadMails > 0)
|
||||
{
|
||||
result.NextMailTime = 0.0f;
|
||||
|
||||
long now = Time.UnixTime;
|
||||
List<ulong> sentSenders = new List<ulong>();
|
||||
|
||||
foreach (Mail mail in GetPlayer().GetMails())
|
||||
{
|
||||
if (mail.checkMask.HasAnyFlag(MailCheckMask.Read))
|
||||
continue;
|
||||
|
||||
// and already delivered
|
||||
if (now < mail.deliver_time)
|
||||
continue;
|
||||
|
||||
// only send each mail sender once
|
||||
if (sentSenders.Any(p => p == mail.sender))
|
||||
continue;
|
||||
|
||||
result.Next.Add(new MailQueryNextTimeResult.MailNextTimeEntry(mail));
|
||||
|
||||
sentSenders.Add(mail.sender);
|
||||
|
||||
// do not send more than 2 mails
|
||||
if (sentSenders.Count > 2)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
result.NextMailTime = -Time.Day;
|
||||
|
||||
SendPacket(result);
|
||||
}
|
||||
|
||||
public void SendShowMailBox(ObjectGuid guid)
|
||||
{
|
||||
ShowMailbox packet = new ShowMailbox();
|
||||
packet.PostmasterGUID = guid;
|
||||
SendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,789 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.BattleGrounds;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using Game.Guilds;
|
||||
using Game.Maps;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using Game.PvP;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.RequestAccountData, Status = SessionStatus.Authed)]
|
||||
void HandleRequestAccountData(RequestAccountData request)
|
||||
{
|
||||
if (request.DataType > AccountDataTypes.Max)
|
||||
return;
|
||||
|
||||
AccountData adata = GetAccountData(request.DataType);
|
||||
if (adata.Data == null)
|
||||
return;
|
||||
|
||||
UpdateAccountData data = new UpdateAccountData();
|
||||
data.Player = GetPlayer() ? GetPlayer().GetGUID() : ObjectGuid.Empty;
|
||||
data.Time = (uint)adata.Time;
|
||||
data.Size = (uint)adata.Data.Length;
|
||||
data.DataType = request.DataType;
|
||||
data.CompressedData = new ByteBuffer(ZLib.Compress(Encoding.UTF8.GetBytes(adata.Data)));
|
||||
|
||||
SendPacket(data);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.UpdateAccountData, Status = SessionStatus.Authed)]
|
||||
void HandleUpdateAccountData(UserClientUpdateAccountData packet)
|
||||
{
|
||||
if (packet.DataType > AccountDataTypes.Max)
|
||||
return;
|
||||
|
||||
if (packet.Size == 0)
|
||||
{
|
||||
SetAccountData(packet.DataType, 0, "");
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.Size > 0xFFFF)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "UpdateAccountData: Account data packet too big, size {0}", packet.Size);
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] data = ZLib.Decompress(packet.CompressedData.GetData(), packet.Size);
|
||||
SetAccountData(packet.DataType, packet.Time, Encoding.Default.GetString(data));
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetSelection)]
|
||||
void HandleSetSelection(SetSelection packet)
|
||||
{
|
||||
GetPlayer().SetSelection(packet.Selection);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ObjectUpdateFailed)]
|
||||
void HandleObjectUpdateFailed(ObjectUpdateFailed objectUpdateFailed)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "Object update failed for {0} for player {1} ({2})", objectUpdateFailed.ObjectGUID.ToString(), GetPlayerName(), GetPlayer().GetGUID().ToString());
|
||||
|
||||
// If create object failed for current player then client will be stuck on loading screen
|
||||
if (GetPlayer().GetGUID() == objectUpdateFailed.ObjectGUID)
|
||||
{
|
||||
LogoutPlayer(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Pretend we've never seen this object
|
||||
GetPlayer().m_clientGUIDs.Remove(objectUpdateFailed.ObjectGUID);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ObjectUpdateRescued, Processing = PacketProcessing.Inplace)]
|
||||
void HandleObjectUpdateRescued(ObjectUpdateRescued objectUpdateRescued)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "Object update rescued for {0} for player {1} ({2})", objectUpdateRescued.ObjectGUID.ToString(), GetPlayerName(), GetPlayer().GetGUID().ToString());
|
||||
|
||||
// Client received values update after destroying object
|
||||
// re-register object in m_clientGUIDs to send DestroyObject on next visibility update
|
||||
GetPlayer().m_clientGUIDs.Add(objectUpdateRescued.ObjectGUID);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetActionButton)]
|
||||
void HandleSetActionButton(SetActionButton packet)
|
||||
{
|
||||
uint action = packet.GetButtonAction();
|
||||
uint type = packet.GetButtonType();
|
||||
|
||||
if (packet.Action == 0)
|
||||
GetPlayer().RemoveActionButton(packet.Index);
|
||||
else
|
||||
GetPlayer().AddActionButton(packet.Index, action, type);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetActionBarToggles)]
|
||||
void HandleSetActionBarToggles(SetActionBarToggles packet)
|
||||
{
|
||||
if (!GetPlayer()) // ignore until not logged (check needed because STATUS_AUTHED)
|
||||
{
|
||||
if (packet.Mask != 0)
|
||||
Log.outError(LogFilter.Network, "WorldSession.HandleSetActionBarToggles in not logged state with value: {0}, ignored", packet.Mask);
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().SetByteValue(PlayerFields.FieldBytes, PlayerFieldOffsets.FieldBytesOffsetActionBarToggles, packet.Mask);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CompleteCinematic)]
|
||||
void HandleCompleteCinematic(CompleteCinematic packet)
|
||||
{
|
||||
// If player has sight bound to visual waypoint NPC we should remove it
|
||||
GetPlayer().GetCinematicMgr().EndCinematic();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.NextCinematicCamera)]
|
||||
void HandleNextCinematicCamera(NextCinematicCamera packet)
|
||||
{
|
||||
// Sent by client when cinematic actually begun. So we begin the server side process
|
||||
GetPlayer().GetCinematicMgr().BeginCinematic();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CompleteMovie)]
|
||||
void HandleCompleteMovie(CompleteMovie packet)
|
||||
{
|
||||
uint movie = _player.GetMovie();
|
||||
if (movie == 0)
|
||||
return;
|
||||
|
||||
_player.SetMovie(0);
|
||||
Global.ScriptMgr.OnMovieComplete(_player, movie);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ViolenceLevel, Processing = PacketProcessing.Inplace, Status = SessionStatus.Authed)]
|
||||
void HandleViolenceLevel(ViolenceLevel violenceLevel)
|
||||
{
|
||||
// do something?
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AreaTrigger)]
|
||||
void HandleAreaTrigger(AreaTriggerPkt packet)
|
||||
{
|
||||
Player player = GetPlayer();
|
||||
if (player.IsInFlight())
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "HandleAreaTriggerOpcode: Player '{0}' (GUID: {1}) in flight, ignore Area Trigger ID:{2}",
|
||||
player.GetName(), player.GetGUID().ToString(), packet.AreaTriggerID);
|
||||
return;
|
||||
}
|
||||
|
||||
AreaTriggerRecord atEntry = CliDB.AreaTriggerStorage.LookupByKey(packet.AreaTriggerID);
|
||||
if (atEntry == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "HandleAreaTriggerOpcode: Player '{0}' (GUID: {1}) send unknown (by DBC) Area Trigger ID:{2}",
|
||||
player.GetName(), player.GetGUID().ToString(), packet.AreaTriggerID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.Entered && !player.IsInAreaTriggerRadius(atEntry))
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "HandleAreaTriggerOpcode: Player '{0}' ({1}) too far, ignore Area Trigger ID: {2}",
|
||||
player.GetName(), player.GetGUID().ToString(), packet.AreaTriggerID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.isDebugAreaTriggers)
|
||||
player.SendSysMessage(packet.Entered ? CypherStrings.DebugAreatriggerEntered : CypherStrings.DebugAreatriggerLeft, packet.AreaTriggerID);
|
||||
|
||||
if (Global.ScriptMgr.OnAreaTrigger(player, atEntry, packet.Entered))
|
||||
return;
|
||||
|
||||
if (player.IsAlive())
|
||||
{
|
||||
List<uint> quests = Global.ObjectMgr.GetQuestsForAreaTrigger(packet.AreaTriggerID);
|
||||
if (quests != null)
|
||||
{
|
||||
foreach (uint questId in quests)
|
||||
{
|
||||
Quest qInfo = Global.ObjectMgr.GetQuestTemplate(questId);
|
||||
if (qInfo != null && player.GetQuestStatus(questId) == QuestStatus.Incomplete)
|
||||
{
|
||||
foreach (QuestObjective obj in qInfo.Objectives)
|
||||
{
|
||||
if (obj.Type == QuestObjectiveType.AreaTrigger && !player.IsQuestObjectiveComplete(obj))
|
||||
{
|
||||
player.SetQuestObjectiveData(obj, 1);
|
||||
player.SendQuestUpdateAddCreditSimple(obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (player.CanCompleteQuest(questId))
|
||||
player.CompleteQuest(questId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Global.ObjectMgr.IsTavernAreaTrigger(packet.AreaTriggerID))
|
||||
{
|
||||
// set resting flag we are in the inn
|
||||
player.GetRestMgr().SetRestFlag(RestFlag.Tavern, atEntry.Id);
|
||||
|
||||
if (Global.WorldMgr.IsFFAPvPRealm())
|
||||
player.RemoveByteFlag(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag, UnitBytes2Flags.FFAPvp);
|
||||
|
||||
return;
|
||||
}
|
||||
Battleground bg = player.GetBattleground();
|
||||
if (bg)
|
||||
bg.HandleAreaTrigger(player, packet.AreaTriggerID, packet.Entered);
|
||||
|
||||
OutdoorPvP pvp = player.GetOutdoorPvP();
|
||||
if (pvp != null)
|
||||
{
|
||||
if (pvp.HandleAreaTrigger(player, packet.AreaTriggerID, packet.Entered))
|
||||
return;
|
||||
}
|
||||
|
||||
AreaTriggerStruct at = Global.ObjectMgr.GetAreaTrigger(packet.AreaTriggerID);
|
||||
if (at == null)
|
||||
return;
|
||||
|
||||
bool teleported = false;
|
||||
if (player.GetMapId() != at.target_mapId)
|
||||
{
|
||||
EnterState denyReason = Global.MapMgr.PlayerCannotEnter(at.target_mapId, player, false);
|
||||
if (denyReason != 0)
|
||||
{
|
||||
bool reviveAtTrigger = false; // should we revive the player if he is trying to enter the correct instance?
|
||||
switch (denyReason)
|
||||
{
|
||||
case EnterState.CannotEnterNoEntry:
|
||||
Log.outDebug(LogFilter.Maps, "MAP: Player '{0}' attempted to enter map with id {1} which has no entry", player.GetName(), at.target_mapId);
|
||||
break;
|
||||
case EnterState.CannotEnterUninstancedDungeon:
|
||||
Log.outDebug(LogFilter.Maps, "MAP: Player '{0}' attempted to enter dungeon map {1} but no instance template was found", player.GetName(), at.target_mapId);
|
||||
break;
|
||||
case EnterState.CannotEnterDifficultyUnavailable:
|
||||
{
|
||||
Log.outDebug(LogFilter.Maps, "MAP: Player '{0}' attempted to enter instance map {1} but the requested difficulty was not found", player.GetName(), at.target_mapId);
|
||||
MapRecord entry = CliDB.MapStorage.LookupByKey(at.target_mapId);
|
||||
if (entry != null)
|
||||
player.SendTransferAborted(entry.Id, TransferAbortReason.Difficulty, (byte)player.GetDifficultyID(entry));
|
||||
}
|
||||
break;
|
||||
case EnterState.CannotEnterNotInRaid:
|
||||
Log.outDebug(LogFilter.Maps, "MAP: Player '{0}' must be in a raid group to enter map {1}", player.GetName(), at.target_mapId);
|
||||
player.SendRaidGroupOnlyMessage(RaidGroupReason.Only, 0);
|
||||
reviveAtTrigger = true;
|
||||
break;
|
||||
case EnterState.CannotEnterCorpseInDifferentInstance:
|
||||
player.SendPacket(new AreaTriggerNoCorpse());
|
||||
Log.outDebug(LogFilter.Maps, "MAP: Player '{0}' does not have a corpse in instance map {1} and cannot enter", player.GetName(), at.target_mapId);
|
||||
break;
|
||||
case EnterState.CannotEnterInstanceBindMismatch:
|
||||
{
|
||||
MapRecord entry = CliDB.MapStorage.LookupByKey(at.target_mapId);
|
||||
if (entry != null)
|
||||
{
|
||||
string mapName = entry.MapName[player.GetSession().GetSessionDbcLocale()];
|
||||
Log.outDebug(LogFilter.Maps, "MAP: Player '{0}' cannot enter instance map '{1}' because their permanent bind is incompatible with their group's", player.GetName(), mapName);
|
||||
// is there a special opcode for this?
|
||||
// @todo figure out how to get player localized difficulty string (e.g. "10 player", "Heroic" etc)
|
||||
player.SendSysMessage(CypherStrings.InstanceBindMismatch, mapName);
|
||||
}
|
||||
reviveAtTrigger = true;
|
||||
}
|
||||
break;
|
||||
case EnterState.CannotEnterTooManyInstances:
|
||||
player.SendTransferAborted(at.target_mapId, TransferAbortReason.TooManyInstances);
|
||||
Log.outDebug(LogFilter.Maps, "MAP: Player '{0}' cannot enter instance map {1} because he has exceeded the maximum number of instances per hour.", player.GetName(), at.target_mapId);
|
||||
reviveAtTrigger = true;
|
||||
break;
|
||||
case EnterState.CannotEnterMaxPlayers:
|
||||
player.SendTransferAborted(at.target_mapId, TransferAbortReason.MaxPlayers);
|
||||
reviveAtTrigger = true;
|
||||
break;
|
||||
case EnterState.CannotEnterZoneInCombat:
|
||||
player.SendTransferAborted(at.target_mapId, TransferAbortReason.ZoneInCombat);
|
||||
reviveAtTrigger = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (reviveAtTrigger) // check if the player is touching the areatrigger leading to the map his corpse is on
|
||||
{
|
||||
if (!player.IsAlive() && player.HasCorpse())
|
||||
{
|
||||
if (player.GetCorpseLocation().GetMapId() == at.target_mapId)
|
||||
{
|
||||
player.ResurrectPlayer(0.5f);
|
||||
player.SpawnCorpseBones();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Group group = player.GetGroup();
|
||||
if (group)
|
||||
if (group.isLFGGroup() && player.GetMap().IsDungeon())
|
||||
teleported = player.TeleportToBGEntryPoint();
|
||||
}
|
||||
|
||||
if (!teleported)
|
||||
{
|
||||
WorldSafeLocsRecord entranceLocation = null;
|
||||
InstanceSave instanceSave = player.GetInstanceSave(at.target_mapId);
|
||||
if (instanceSave != null)
|
||||
{
|
||||
// Check if we can contact the instancescript of the instance for an updated entrance location
|
||||
Map map = Global.MapMgr.FindMap(at.target_mapId, player.GetInstanceSave(at.target_mapId).GetInstanceId());
|
||||
if (map)
|
||||
{
|
||||
InstanceMap instanceMap = map.ToInstanceMap();
|
||||
if (instanceMap != null)
|
||||
{
|
||||
InstanceScript instanceScript = instanceMap.GetInstanceScript();
|
||||
if (instanceScript != null)
|
||||
entranceLocation = CliDB.WorldSafeLocsStorage.LookupByKey(instanceScript.GetEntranceLocation());
|
||||
}
|
||||
}
|
||||
|
||||
// Finally check with the instancesave for an entrance location if we did not get a valid one from the instancescript
|
||||
if (entranceLocation == null)
|
||||
entranceLocation = CliDB.WorldSafeLocsStorage.LookupByKey(instanceSave.GetEntranceLocation());
|
||||
}
|
||||
|
||||
if (entranceLocation != null)
|
||||
player.TeleportTo(entranceLocation.MapID, entranceLocation.Loc.X, entranceLocation.Loc.Y, entranceLocation.Loc.Z, (float)(entranceLocation.Facing * Math.PI / 180), TeleportToOptions.NotLeaveTransport);
|
||||
else
|
||||
player.TeleportTo(at.target_mapId, at.target_X, at.target_Y, at.target_Z, at.target_Orientation, TeleportToOptions.NotLeaveTransport);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestPlayedTime)]
|
||||
void HandlePlayedTime(RequestPlayedTime packet)
|
||||
{
|
||||
PlayedTime playedTime = new PlayedTime();
|
||||
playedTime.TotalTime = GetPlayer().GetTotalPlayedTime();
|
||||
playedTime.LevelTime = GetPlayer().GetLevelPlayedTime();
|
||||
playedTime.TriggerEvent = packet.TriggerScriptEvent; // 0-1 - will not show in chat frame
|
||||
SendPacket(playedTime);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SaveCufProfiles, Processing = PacketProcessing.Inplace)]
|
||||
void HandleSaveCUFProfiles(SaveCUFProfiles packet)
|
||||
{
|
||||
if (packet.CUFProfiles.Count > PlayerConst.MaxCUFProfiles)
|
||||
{
|
||||
Log.outError(LogFilter.Player, "HandleSaveCUFProfiles - {0} tried to save more than {1} CUF profiles. Hacking attempt?", GetPlayerName(), PlayerConst.MaxCUFProfiles);
|
||||
return;
|
||||
}
|
||||
|
||||
for (byte i = 0; i < packet.CUFProfiles.Count; ++i)
|
||||
GetPlayer().SaveCUFProfile(i, packet.CUFProfiles[i]);
|
||||
|
||||
for (byte i = (byte)packet.CUFProfiles.Count; i < PlayerConst.MaxCUFProfiles; ++i)
|
||||
GetPlayer().SaveCUFProfile(i, null);
|
||||
}
|
||||
|
||||
public void SendLoadCUFProfiles()
|
||||
{
|
||||
Player player = GetPlayer();
|
||||
|
||||
LoadCUFProfiles loadCUFProfiles = new LoadCUFProfiles();
|
||||
|
||||
for (byte i = 0; i < PlayerConst.MaxCUFProfiles; ++i)
|
||||
{
|
||||
CUFProfile cufProfile = player.GetCUFProfile(i);
|
||||
if (cufProfile != null)
|
||||
loadCUFProfiles.CUFProfiles.Add(cufProfile);
|
||||
}
|
||||
|
||||
SendPacket(loadCUFProfiles);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetAdvancedCombatLogging, Processing = PacketProcessing.Inplace)]
|
||||
void HandleSetAdvancedCombatLogging(SetAdvancedCombatLogging setAdvancedCombatLogging)
|
||||
{
|
||||
GetPlayer().SetAdvancedCombatLogging(setAdvancedCombatLogging.Enable);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.MountSpecialAnim)]
|
||||
void HandleMountSpecialAnim(MountSpecial mountSpecial)
|
||||
{
|
||||
SpecialMountAnim specialMountAnim = new SpecialMountAnim();
|
||||
specialMountAnim.UnitGUID = _player.GetGUID();
|
||||
GetPlayer().SendMessageToSet(specialMountAnim, false);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.MountSetFavorite)]
|
||||
void HandleMountSetFavorite(MountSetFavorite mountSetFavorite)
|
||||
{
|
||||
_collectionMgr.MountSetFavorite(mountSetFavorite.MountSpellID, mountSetFavorite.IsFavorite);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PvpPrestigeRankUp)]
|
||||
void HandlePvpPrestigeRankUp(PvpPrestigeRankUp pvpPrestigeRankUp)
|
||||
{
|
||||
if (_player.CanPrestige())
|
||||
_player.Prestige();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CloseInteraction)]
|
||||
void HandleCloseInteraction(CloseInteraction closeInteraction)
|
||||
{
|
||||
if (_player.PlayerTalkClass.GetInteractionData().SourceGuid == closeInteraction.SourceGuid)
|
||||
_player.PlayerTalkClass.GetInteractionData().Reset();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChatUnregisterAllAddonPrefixes)]
|
||||
void HandleUnregisterAllAddonPrefixes(ChatUnregisterAllAddonPrefixes packet)
|
||||
{
|
||||
_registeredAddonPrefixes.Clear();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ChatRegisterAddonPrefixes)]
|
||||
void HandleAddonRegisteredPrefixes(ChatRegisterAddonPrefixes packet)
|
||||
{
|
||||
_registeredAddonPrefixes.AddRange(packet.Prefixes);
|
||||
|
||||
if (_registeredAddonPrefixes.Count > 64) // shouldn't happen
|
||||
{
|
||||
_filterAddonMessages = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_filterAddonMessages = true;
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.TogglePvp)]
|
||||
void HandleTogglePvP(TogglePvP packet)
|
||||
{
|
||||
Player player = GetPlayer();
|
||||
|
||||
bool inPvP = player.HasFlag(PlayerFields.Flags, PlayerFlags.InPVP);
|
||||
player.ApplyModFlag(PlayerFields.Flags, PlayerFlags.InPVP, !inPvP);
|
||||
player.ApplyModFlag(PlayerFields.Flags, PlayerFlags.PVPTimer, inPvP);
|
||||
|
||||
if (player.HasFlag(PlayerFields.Flags, PlayerFlags.InPVP))
|
||||
{
|
||||
if (!player.IsPvP() || player.pvpInfo.EndTimer != 0)
|
||||
player.UpdatePvP(true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!player.pvpInfo.IsHostile && player.IsPvP())
|
||||
player.pvpInfo.EndTimer = Time.UnixTime; // start toggle-off
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetPvp)]
|
||||
void HandleSetPvP(SetPvP packet)
|
||||
{
|
||||
Player player = GetPlayer();
|
||||
|
||||
player.ApplyModFlag(PlayerFields.Flags, PlayerFlags.InPVP, packet.EnablePVP);
|
||||
player.ApplyModFlag(PlayerFields.Flags, PlayerFlags.PVPTimer, !packet.EnablePVP);
|
||||
|
||||
if (player.HasFlag(PlayerFields.Flags, PlayerFlags.InPVP))
|
||||
{
|
||||
if (!player.IsPvP() || player.pvpInfo.EndTimer != 0)
|
||||
player.UpdatePvP(true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!player.pvpInfo.IsHostile && player.IsPvP())
|
||||
player.pvpInfo.EndTimer = Time.UnixTime; // start set-off
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.FarSight)]
|
||||
void HandleFarSight(FarSight farSight)
|
||||
{
|
||||
if (farSight.Enable)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "Added FarSight {0} to player {1}", GetPlayer().GetUInt64Value(PlayerFields.Farsight), GetPlayer().GetGUID().ToString());
|
||||
WorldObject target = GetPlayer().GetViewpoint();
|
||||
if (target)
|
||||
GetPlayer().SetSeer(target);
|
||||
else
|
||||
Log.outDebug(LogFilter.Network, "Player {0} (GUID: {1}) requests non-existing seer {2}", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), GetPlayer().GetUInt64Value(PlayerFields.Farsight));
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "Player {0} set vision to self", GetPlayer().GetGUID().ToString());
|
||||
GetPlayer().SetSeer(GetPlayer());
|
||||
}
|
||||
|
||||
GetPlayer().UpdateVisibilityForPlayer();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetTitle)]
|
||||
void HandleSetTitle(SetTitle packet)
|
||||
{
|
||||
// -1 at none
|
||||
if (packet.TitleID > 0 && packet.TitleID < PlayerConst.MaxTitleIndex)
|
||||
{
|
||||
if (!GetPlayer().HasTitle((uint)packet.TitleID))
|
||||
return;
|
||||
}
|
||||
else
|
||||
packet.TitleID = 0;
|
||||
|
||||
GetPlayer().SetUInt32Value(PlayerFields.ChosenTitle, (uint)packet.TitleID);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ResetInstances)]
|
||||
void HandleResetInstances(ResetInstances packet)
|
||||
{
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (group)
|
||||
{
|
||||
if (group.IsLeader(GetPlayer().GetGUID()))
|
||||
group.ResetInstances(InstanceResetMethod.All, false, false, GetPlayer());
|
||||
}
|
||||
else
|
||||
GetPlayer().ResetInstances(InstanceResetMethod.All, false, false);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetDungeonDifficulty)]
|
||||
void HandleSetDungeonDifficulty(SetDungeonDifficulty setDungeonDifficulty)
|
||||
{
|
||||
DifficultyRecord difficultyEntry = CliDB.DifficultyStorage.LookupByKey(setDungeonDifficulty.DifficultyID);
|
||||
if (difficultyEntry == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetDungeonDifficulty: {0} sent an invalid instance mode {1}!",
|
||||
GetPlayer().GetGUID().ToString(), setDungeonDifficulty.DifficultyID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (difficultyEntry.InstanceType != MapTypes.Instance)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetDungeonDifficulty: {0} sent an non-dungeon instance mode {1}!",
|
||||
GetPlayer().GetGUID().ToString(), difficultyEntry.Id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!difficultyEntry.Flags.HasAnyFlag(DifficultyFlags.CanSelect))
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetDungeonDifficulty: {0} sent unselectable instance mode {1}!",
|
||||
GetPlayer().GetGUID().ToString(), difficultyEntry.Id);
|
||||
return;
|
||||
}
|
||||
|
||||
Difficulty difficultyID = (Difficulty)difficultyEntry.Id;
|
||||
if (difficultyID == GetPlayer().GetDungeonDifficultyID())
|
||||
return;
|
||||
|
||||
// cannot reset while in an instance
|
||||
Map map = GetPlayer().GetMap();
|
||||
if (map && map.IsDungeon())
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession:HandleSetDungeonDifficulty: player (Name: {0}, {1}) tried to reset the instance while player is inside!",
|
||||
GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (group)
|
||||
{
|
||||
if (group.IsLeader(GetPlayer().GetGUID()))
|
||||
{
|
||||
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
|
||||
{
|
||||
Player groupGuy = refe.GetSource();
|
||||
if (!groupGuy)
|
||||
continue;
|
||||
|
||||
if (!groupGuy.IsInMap(groupGuy))
|
||||
return;
|
||||
|
||||
if (groupGuy.GetMap().IsNonRaidDungeon())
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession:HandleSetDungeonDifficulty: {0} tried to reset the instance while group member (Name: {1}, {2}) is inside!",
|
||||
GetPlayer().GetGUID().ToString(), groupGuy.GetName(), groupGuy.GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
// the difficulty is set even if the instances can't be reset
|
||||
//_player->SendDungeonDifficulty(true);
|
||||
group.ResetInstances(InstanceResetMethod.ChangeDifficulty, false, false, GetPlayer());
|
||||
group.SetDungeonDifficultyID(difficultyID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GetPlayer().ResetInstances(InstanceResetMethod.ChangeDifficulty, false, false);
|
||||
GetPlayer().SetDungeonDifficultyID(difficultyID);
|
||||
GetPlayer().SendDungeonDifficulty();
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetRaidDifficulty)]
|
||||
void HandleSetRaidDifficulty(SetRaidDifficulty setRaidDifficulty)
|
||||
{
|
||||
DifficultyRecord difficultyEntry = CliDB.DifficultyStorage.LookupByKey(setRaidDifficulty.DifficultyID);
|
||||
if (difficultyEntry == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetDungeonDifficulty: {0} sent an invalid instance mode {1}!",
|
||||
GetPlayer().GetGUID().ToString(), setRaidDifficulty.DifficultyID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (difficultyEntry.InstanceType != MapTypes.Raid)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetDungeonDifficulty: {0} sent an non-dungeon instance mode {1}!",
|
||||
GetPlayer().GetGUID().ToString(), difficultyEntry.Id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!difficultyEntry.Flags.HasAnyFlag(DifficultyFlags.CanSelect))
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetDungeonDifficulty: {0} sent unselectable instance mode {1}!",
|
||||
GetPlayer().GetGUID().ToString(), difficultyEntry.Id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (((int)(difficultyEntry.Flags & DifficultyFlags.Legacy) >> 5) != setRaidDifficulty.Legacy)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetDungeonDifficulty: {0} sent not matching legacy difficulty {1}!",
|
||||
GetPlayer().GetGUID().ToString(), difficultyEntry.Id);
|
||||
return;
|
||||
}
|
||||
|
||||
Difficulty difficultyID = (Difficulty)difficultyEntry.Id;
|
||||
if (difficultyID == (setRaidDifficulty.Legacy != 0 ? GetPlayer().GetLegacyRaidDifficultyID() : GetPlayer().GetRaidDifficultyID()))
|
||||
return;
|
||||
|
||||
// cannot reset while in an instance
|
||||
Map map = GetPlayer().GetMap();
|
||||
if (map && map.IsDungeon())
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession:HandleSetRaidDifficulty: player (Name: {0}, {1} tried to reset the instance while inside!",
|
||||
GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
Group group = GetPlayer().GetGroup();
|
||||
if (group)
|
||||
{
|
||||
if (group.IsLeader(GetPlayer().GetGUID()))
|
||||
{
|
||||
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
|
||||
{
|
||||
Player groupGuy = refe.GetSource();
|
||||
if (!groupGuy)
|
||||
continue;
|
||||
|
||||
if (!groupGuy.IsInMap(groupGuy))
|
||||
return;
|
||||
|
||||
if (groupGuy.GetMap().IsRaid())
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession:HandleSetRaidDifficulty: player {0} tried to reset the instance while inside!", GetPlayer().GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
// the difficulty is set even if the instances can't be reset
|
||||
group.ResetInstances(InstanceResetMethod.ChangeDifficulty, true, setRaidDifficulty.Legacy != 0, GetPlayer());
|
||||
if (setRaidDifficulty.Legacy != 0)
|
||||
group.SetLegacyRaidDifficultyID(difficultyID);
|
||||
else
|
||||
group.SetRaidDifficultyID(difficultyID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GetPlayer().ResetInstances(InstanceResetMethod.ChangeDifficulty, true, setRaidDifficulty.Legacy != 0);
|
||||
if (setRaidDifficulty.Legacy != 0)
|
||||
GetPlayer().SetLegacyRaidDifficultyID(difficultyID);
|
||||
else
|
||||
GetPlayer().SetRaidDifficultyID(difficultyID);
|
||||
|
||||
GetPlayer().SendRaidDifficulty(setRaidDifficulty.Legacy != 0);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetTaxiBenchmarkMode, Processing = PacketProcessing.Inplace)]
|
||||
void HandleSetTaxiBenchmark(SetTaxiBenchmarkMode packet)
|
||||
{
|
||||
_player.ApplyModFlag(PlayerFields.Flags, PlayerFlags.TaxiBenchmark, packet.Enable);
|
||||
}
|
||||
|
||||
public void SendSetPhaseShift(List<uint> phaseIds, List<uint> terrainswaps, List<uint> worldMapAreaSwaps)
|
||||
{
|
||||
PhaseShift phaseShift = new PhaseShift();
|
||||
phaseShift.ClientGUID = GetPlayer().GetGUID();
|
||||
phaseShift.PersonalGUID = GetPlayer().GetGUID();
|
||||
phaseShift.PhaseShifts = phaseIds;
|
||||
phaseShift.VisibleMapIDs = terrainswaps;
|
||||
phaseShift.UiWorldMapAreaIDSwaps = worldMapAreaSwaps;
|
||||
SendPacket(phaseShift);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GuildSetFocusedAchievement)]
|
||||
void HandleGuildSetFocusedAchievement(GuildSetFocusedAchievement setFocusedAchievement)
|
||||
{
|
||||
Guild guild = Global.GuildMgr.GetGuildById(GetPlayer().GetGuildId());
|
||||
if (guild)
|
||||
guild.GetAchievementMgr().SendAchievementInfo(GetPlayer(), setFocusedAchievement.AchievementID);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.InstanceLockResponse)]
|
||||
void HandleInstanceLockResponse(InstanceLockResponse packet)
|
||||
{
|
||||
if (!GetPlayer().HasPendingBind())
|
||||
{
|
||||
Log.outInfo(LogFilter.Network, "InstanceLockResponse: Player {0} (guid {1}) tried to bind himself/teleport to graveyard without a pending bind!",
|
||||
GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.AcceptLock)
|
||||
GetPlayer().BindToInstance();
|
||||
else
|
||||
GetPlayer().RepopAtGraveyard();
|
||||
|
||||
GetPlayer().SetPendingBind(0, 0);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.WardenData)]
|
||||
void HandleWardenDataOpcode(WardenData packet)
|
||||
{
|
||||
if (_warden == null || packet.Data.GetSize() == 0)
|
||||
return;
|
||||
|
||||
var unpacked = new ByteBuffer(_warden.DecryptData(packet.Data.GetData()));
|
||||
WardenOpcodes opcode = (WardenOpcodes)packet.Data.ReadUInt8();
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case WardenOpcodes.CMSG_ModuleMissing:
|
||||
_warden.SendModuleToClient();
|
||||
break;
|
||||
case WardenOpcodes.Cmsg_ModuleOk:
|
||||
_warden.RequestHash();
|
||||
break;
|
||||
case WardenOpcodes.Smsg_CheatChecksRequest:
|
||||
_warden.HandleData(packet.Data);
|
||||
break;
|
||||
case WardenOpcodes.Cmsg_MemChecksResult:
|
||||
Log.outDebug(LogFilter.Warden, "NYI WARDEN_CMSG_MEM_CHECKS_RESULT received!");
|
||||
break;
|
||||
case WardenOpcodes.Cmsg_HashResult:
|
||||
_warden.HandleHashResult(packet.Data);
|
||||
_warden.InitializeModule();
|
||||
break;
|
||||
case WardenOpcodes.Cmsg_ModuleFailed:
|
||||
Log.outDebug(LogFilter.Warden, "NYI WARDEN_CMSG_MODULE_FAILED received!");
|
||||
break;
|
||||
default:
|
||||
Log.outDebug(LogFilter.Warden, "Got unknown warden opcode {0} of size {1}.", opcode, packet.Data.GetSize() - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,651 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.BattleGrounds;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Garrisons;
|
||||
using Game.Maps;
|
||||
using Game.Movement;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.MoveChangeTransport, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveFallReset, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveFallLand, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveHeartbeat, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveJump, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveSetFacing, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveSetPitch, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStartAscend, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStartBackward, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStartDescend, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStartForward, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStartPitchDown, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStartPitchUp, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStartStrafeLeft, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStartStrafeRight, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStartSwim, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStartTurnLeft, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStartTurnRight, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStop, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStopAscend, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStopPitch, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStopStrafe, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStopSwim, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveStopTurn, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveDoubleJump, Processing = PacketProcessing.ThreadSafe)]
|
||||
void HandleMovement(ClientPlayerMovement packet)
|
||||
{
|
||||
HandleMovementOpcode(packet.GetOpcode(), packet.Status);
|
||||
}
|
||||
|
||||
void HandleMovementOpcode(ClientOpcodes opcode, MovementInfo movementInfo)
|
||||
{
|
||||
Unit mover = GetPlayer().m_unitMovedByMe;
|
||||
Player plrMover = mover.ToPlayer();
|
||||
|
||||
if (plrMover && plrMover.IsBeingTeleported())
|
||||
return;
|
||||
|
||||
GetPlayer().ValidateMovementInfo(movementInfo);
|
||||
|
||||
if (movementInfo.Guid != mover.GetGUID())
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandleMovementOpcodes: guid error");
|
||||
return;
|
||||
}
|
||||
if (!movementInfo.Pos.IsPositionValid())
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandleMovementOpcodes: Invalid Position");
|
||||
return;
|
||||
}
|
||||
|
||||
// stop some emotes at player move
|
||||
if (plrMover && (plrMover.GetUInt32Value(UnitFields.NpcEmotestate) != 0))
|
||||
plrMover.SetUInt32Value(UnitFields.NpcEmotestate, (uint)Emote.OneshotNone);
|
||||
|
||||
//handle special cases
|
||||
if (!movementInfo.transport.guid.IsEmpty())
|
||||
{
|
||||
if (movementInfo.transport.pos.GetPositionX() > 50 || movementInfo.transport.pos.GetPositionY() > 50 || movementInfo.transport.pos.GetPositionZ() > 50)
|
||||
return;
|
||||
|
||||
if (!GridDefines.IsValidMapCoord(movementInfo.Pos.posX + movementInfo.transport.pos.posX, movementInfo.Pos.posY + movementInfo.transport.pos.posY,
|
||||
movementInfo.Pos.posZ + movementInfo.transport.pos.posZ, movementInfo.Pos.Orientation + movementInfo.transport.pos.Orientation))
|
||||
return;
|
||||
|
||||
if (plrMover)
|
||||
{
|
||||
if (!plrMover.GetTransport())
|
||||
{
|
||||
Transport transport = plrMover.GetMap().GetTransport(movementInfo.transport.guid);
|
||||
if (transport)
|
||||
transport.AddPassenger(plrMover);
|
||||
}
|
||||
else if (plrMover.GetTransport().GetGUID() != movementInfo.transport.guid)
|
||||
{
|
||||
plrMover.GetTransport().RemovePassenger(plrMover);
|
||||
Transport transport = plrMover.GetMap().GetTransport(movementInfo.transport.guid);
|
||||
if (transport)
|
||||
transport.AddPassenger(plrMover);
|
||||
else
|
||||
movementInfo.ResetTransport();
|
||||
}
|
||||
}
|
||||
|
||||
if (!mover.GetTransport() && !mover.GetVehicle())
|
||||
{
|
||||
GameObject go = mover.GetMap().GetGameObject(movementInfo.transport.guid);
|
||||
if (!go || go.GetGoType() != GameObjectTypes.Transport)
|
||||
movementInfo.transport.Reset();
|
||||
}
|
||||
}
|
||||
else if (plrMover && plrMover.GetTransport()) // if we were on a transport, leave
|
||||
plrMover.GetTransport().RemovePassenger(plrMover);
|
||||
|
||||
// fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map).
|
||||
if (opcode == ClientOpcodes.MoveFallLand && plrMover && !plrMover.IsInFlight())
|
||||
plrMover.HandleFall(movementInfo);
|
||||
|
||||
if (plrMover && movementInfo.HasMovementFlag(MovementFlag.Swimming) != plrMover.IsInWater())
|
||||
{
|
||||
// now client not include swimming flag in case jumping under water
|
||||
plrMover.SetInWater(!plrMover.IsInWater() || plrMover.GetMap().IsUnderWater(movementInfo.Pos.posX, movementInfo.Pos.posY, movementInfo.Pos.posZ));
|
||||
}
|
||||
|
||||
uint mstime = Time.GetMSTime();
|
||||
|
||||
if (m_clientTimeDelay == 0)
|
||||
m_clientTimeDelay = mstime - movementInfo.Time;
|
||||
|
||||
movementInfo.Time = movementInfo.Time + m_clientTimeDelay;
|
||||
|
||||
movementInfo.Guid = mover.GetGUID();
|
||||
mover.m_movementInfo = movementInfo;
|
||||
|
||||
// Some vehicles allow the passenger to turn by himself
|
||||
Vehicle vehicle = mover.GetVehicle();
|
||||
if (vehicle)
|
||||
{
|
||||
VehicleSeatRecord seat = vehicle.GetSeatForPassenger(mover);
|
||||
if (seat != null)
|
||||
{
|
||||
if (seat.Flags[0].HasAnyFlag((uint)VehicleSeatFlags.AllowTurning))
|
||||
{
|
||||
if (movementInfo.Pos.GetOrientation() != mover.GetOrientation())
|
||||
{
|
||||
mover.SetOrientation(movementInfo.Pos.GetOrientation());
|
||||
mover.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Turning);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mover.UpdatePosition(movementInfo.Pos);
|
||||
|
||||
MoveUpdate moveUpdate = new MoveUpdate();
|
||||
moveUpdate.Status = mover.m_movementInfo;
|
||||
mover.SendMessageToSet(moveUpdate, GetPlayer());
|
||||
|
||||
if (plrMover) // nothing is charmed, or player charmed
|
||||
{
|
||||
if (plrMover.IsSitState() && movementInfo.HasMovementFlag(MovementFlag.MaskMoving | MovementFlag.MaskTurning))
|
||||
plrMover.SetStandState(UnitStandStateType.Stand);
|
||||
|
||||
plrMover.UpdateFallInformationIfNeed(movementInfo, opcode);
|
||||
|
||||
if (movementInfo.Pos.posZ < plrMover.GetMap().GetMinHeight(movementInfo.Pos.GetPositionX(), movementInfo.Pos.GetPositionY()))
|
||||
{
|
||||
if (!(plrMover.GetBattleground() && plrMover.GetBattleground().HandlePlayerUnderMap(GetPlayer())))
|
||||
{
|
||||
// NOTE: this is actually called many times while falling
|
||||
// even after the player has been teleported away
|
||||
/// @todo discard movement packets after the player is rooted
|
||||
if (plrMover.IsAlive())
|
||||
{
|
||||
plrMover.SetFlag(PlayerFields.Flags, PlayerFlags.IsOutOfBounds);
|
||||
plrMover.EnvironmentalDamage(EnviromentalDamage.FallToVoid, (uint)GetPlayer().GetMaxHealth());
|
||||
// player can be alive if GM/etc
|
||||
// change the death state to CORPSE to prevent the death timer from
|
||||
// starting in the next player update
|
||||
if (!plrMover.IsAlive())
|
||||
plrMover.KillPlayer();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
plrMover.RemoveFlag(PlayerFields.Flags, PlayerFlags.IsOutOfBounds);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.WorldPortResponse, Status = SessionStatus.Transfer)]
|
||||
void HandleMoveWorldportAck(WorldPortResponse packet)
|
||||
{
|
||||
HandleMoveWorldportAck();
|
||||
}
|
||||
|
||||
void HandleMoveWorldportAck()
|
||||
{
|
||||
// ignore unexpected far teleports
|
||||
if (!GetPlayer().IsBeingTeleportedFar())
|
||||
return;
|
||||
|
||||
bool seamlessTeleport = GetPlayer().IsBeingTeleportedSeamlessly();
|
||||
GetPlayer().SetSemaphoreTeleportFar(false);
|
||||
|
||||
// get the teleport destination
|
||||
WorldLocation loc = GetPlayer().GetTeleportDest();
|
||||
|
||||
// possible errors in the coordinate validity check
|
||||
if (!GridDefines.IsValidMapCoord(loc))
|
||||
{
|
||||
LogoutPlayer(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// get the destination map entry, not the current one, this will fix homebind and reset greeting
|
||||
MapRecord mapEntry = CliDB.MapStorage.LookupByKey(loc.GetMapId());
|
||||
InstanceTemplate mInstance = Global.ObjectMgr.GetInstanceTemplate(loc.GetMapId());
|
||||
|
||||
// reset instance validity, except if going to an instance inside an instance
|
||||
if (!GetPlayer().m_InstanceValid && mInstance == null)
|
||||
GetPlayer().m_InstanceValid = true;
|
||||
|
||||
Map oldMap = GetPlayer().GetMap();
|
||||
Map newMap = Global.MapMgr.CreateMap(loc.GetMapId(), GetPlayer());
|
||||
|
||||
if (GetPlayer().IsInWorld)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "Player (Name {0}) is still in world when teleported from map {1} to new map {2}", GetPlayer().GetName(), oldMap.GetId(), loc.GetMapId());
|
||||
oldMap.RemovePlayerFromMap(GetPlayer(), false);
|
||||
}
|
||||
|
||||
// relocate the player to the teleport destination
|
||||
// the CannotEnter checks are done in TeleporTo but conditions may change
|
||||
// while the player is in transit, for example the map may get full
|
||||
if (newMap == null || newMap.CannotEnter(GetPlayer()) != 0)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "Map {0} could not be created for {1} ({2}), porting player to homebind", loc.GetMapId(), newMap ? newMap.GetMapName() : "Unknown", GetPlayer().GetGUID().ToString());
|
||||
GetPlayer().TeleportTo(GetPlayer().GetHomebind());
|
||||
return;
|
||||
}
|
||||
|
||||
float z = loc.GetPositionZ();
|
||||
if (GetPlayer().HasUnitMovementFlag(MovementFlag.Hover))
|
||||
z += GetPlayer().GetFloatValue(UnitFields.HoverHeight);
|
||||
|
||||
GetPlayer().Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation());
|
||||
|
||||
GetPlayer().ResetMap();
|
||||
GetPlayer().SetMap(newMap);
|
||||
|
||||
ResumeToken resumeToken = new ResumeToken();
|
||||
resumeToken.SequenceIndex = _player.m_movementCounter;
|
||||
resumeToken.Reason = seamlessTeleport ? 2 : 1u;
|
||||
SendPacket(resumeToken);
|
||||
|
||||
if (!seamlessTeleport)
|
||||
GetPlayer().SendInitialPacketsBeforeAddToMap();
|
||||
|
||||
if (!GetPlayer().GetMap().AddPlayerToMap(GetPlayer(), !seamlessTeleport))
|
||||
{
|
||||
Log.outError(LogFilter.Network, "WORLD: failed to teleport player {0} ({1}) to map {2} ({3}) because of unknown reason!",
|
||||
GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), loc.GetMapId(), newMap ? newMap.GetMapName() : "Unknown");
|
||||
GetPlayer().ResetMap();
|
||||
GetPlayer().SetMap(oldMap);
|
||||
GetPlayer().TeleportTo(GetPlayer().GetHomebind());
|
||||
return;
|
||||
}
|
||||
|
||||
// Battleground state prepare (in case join to BG), at relogin/tele player not invited
|
||||
// only add to bg group and object, if the player was invited (else he entered through command)
|
||||
if (GetPlayer().InBattleground())
|
||||
{
|
||||
Battleground bg;
|
||||
// cleanup setting if outdated
|
||||
if (!mapEntry.IsBattlegroundOrArena())
|
||||
{
|
||||
// We're not in BG
|
||||
GetPlayer().SetBattlegroundId(0, BattlegroundTypeId.None);
|
||||
// reset destination bg team
|
||||
GetPlayer().SetBGTeam(0);
|
||||
}
|
||||
// join to bg case
|
||||
else if (bg = GetPlayer().GetBattleground())
|
||||
{
|
||||
if (GetPlayer().IsInvitedForBattlegroundInstance(GetPlayer().GetBattlegroundId()))
|
||||
bg.AddPlayer(GetPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
if (!seamlessTeleport)
|
||||
GetPlayer().SendInitialPacketsAfterAddToMap();
|
||||
else
|
||||
{
|
||||
GetPlayer().UpdateVisibilityForPlayer();
|
||||
Garrison garrison = GetPlayer().GetGarrison();
|
||||
if (garrison != null)
|
||||
garrison.SendRemoteInfo();
|
||||
}
|
||||
|
||||
// flight fast teleport case
|
||||
if (GetPlayer().GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Flight)
|
||||
{
|
||||
if (!GetPlayer().InBattleground())
|
||||
{
|
||||
if (!seamlessTeleport)
|
||||
{
|
||||
// short preparations to continue flight
|
||||
FlightPathMovementGenerator flight = (FlightPathMovementGenerator)GetPlayer().GetMotionMaster().top();
|
||||
flight.Initialize(GetPlayer());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Battlegroundstate prepare, stop flight
|
||||
GetPlayer().GetMotionMaster().MovementExpired();
|
||||
GetPlayer().CleanupAfterTaxiFlight();
|
||||
}
|
||||
|
||||
// resurrect character at enter into instance where his corpse exist after add to map
|
||||
if (mapEntry.IsDungeon() && !GetPlayer().IsAlive())
|
||||
{
|
||||
if (GetPlayer().GetCorpseLocation().GetMapId() == mapEntry.Id)
|
||||
{
|
||||
GetPlayer().ResurrectPlayer(0.5f, false);
|
||||
GetPlayer().SpawnCorpseBones();
|
||||
}
|
||||
}
|
||||
|
||||
bool allowMount = !mapEntry.IsDungeon() || mapEntry.IsBattlegroundOrArena();
|
||||
if (mInstance != null)
|
||||
{
|
||||
// check if this instance has a reset time and send it to player if so
|
||||
Difficulty diff = GetPlayer().GetDifficultyID(mapEntry);
|
||||
MapDifficultyRecord mapDiff = Global.DB2Mgr.GetMapDifficultyData(mapEntry.Id, diff);
|
||||
if (mapDiff != null)
|
||||
{
|
||||
if (mapDiff.GetRaidDuration() != 0)
|
||||
{
|
||||
long timeReset = Global.InstanceSaveMgr.GetResetTimeFor(mapEntry.Id, diff);
|
||||
if (timeReset != 0)
|
||||
{
|
||||
uint timeleft = (uint)(timeReset - Time.UnixTime);
|
||||
GetPlayer().SendInstanceResetWarning(mapEntry.Id, diff, timeleft, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if instance is valid
|
||||
if (!GetPlayer().CheckInstanceValidity(false))
|
||||
GetPlayer().m_InstanceValid = false;
|
||||
|
||||
// instance mounting is handled in InstanceTemplate
|
||||
allowMount = mInstance.AllowMount;
|
||||
}
|
||||
|
||||
// mount allow check
|
||||
if (!allowMount)
|
||||
GetPlayer().RemoveAurasByType(AuraType.Mounted);
|
||||
|
||||
// update zone immediately, otherwise leave channel will cause crash in mtmap
|
||||
uint newzone, newarea;
|
||||
GetPlayer().GetZoneAndAreaId(out newzone, out newarea);
|
||||
GetPlayer().UpdateZone(newzone, newarea);
|
||||
|
||||
// honorless target
|
||||
if (GetPlayer().pvpInfo.IsHostile)
|
||||
GetPlayer().CastSpell(GetPlayer(), 2479, true);
|
||||
|
||||
// in friendly area
|
||||
else if (GetPlayer().IsPvP() && !GetPlayer().HasFlag(PlayerFields.Flags, PlayerFlags.InPVP))
|
||||
GetPlayer().UpdatePvP(false, false);
|
||||
|
||||
// resummon pet
|
||||
GetPlayer().ResummonPetTemporaryUnSummonedIfAny();
|
||||
|
||||
//lets process all delayed operations on successful teleport
|
||||
GetPlayer().ProcessDelayedOperations();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SuspendTokenResponse, Status = SessionStatus.Transfer)]
|
||||
void HandleSuspendTokenResponse(SuspendTokenResponse suspendTokenResponse)
|
||||
{
|
||||
if (!_player.IsBeingTeleportedFar())
|
||||
return;
|
||||
|
||||
WorldLocation loc = GetPlayer().GetTeleportDest();
|
||||
|
||||
if (CliDB.MapStorage.LookupByKey(loc.GetMapId()).IsDungeon())
|
||||
{
|
||||
UpdateLastInstance updateLastInstance = new UpdateLastInstance();
|
||||
updateLastInstance.MapID = loc.GetMapId();
|
||||
SendPacket(updateLastInstance);
|
||||
}
|
||||
|
||||
NewWorld packet = new NewWorld();
|
||||
packet.MapID = loc.GetMapId();
|
||||
packet.Pos = loc;
|
||||
packet.Reason = (uint)(!_player.IsBeingTeleportedSeamlessly() ? NewWorldReason.Normal : NewWorldReason.Seamless);
|
||||
SendPacket(packet);
|
||||
|
||||
if (_player.IsBeingTeleportedSeamlessly())
|
||||
HandleMoveWorldportAck();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.MoveTeleportAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
void HandleMoveTeleportAck(MoveTeleportAck packet)
|
||||
{
|
||||
Player plMover = GetPlayer().m_unitMovedByMe.ToPlayer();
|
||||
|
||||
if (!plMover || !plMover.IsBeingTeleportedNear())
|
||||
return;
|
||||
|
||||
if (packet.MoverGUID != plMover.GetGUID())
|
||||
return;
|
||||
|
||||
plMover.SetSemaphoreTeleportNear(false);
|
||||
|
||||
uint old_zone = plMover.GetZoneId();
|
||||
|
||||
WorldLocation dest = plMover.GetTeleportDest();
|
||||
|
||||
plMover.UpdatePosition(dest, true);
|
||||
|
||||
uint newzone, newarea;
|
||||
plMover.GetZoneAndAreaId(out newzone, out newarea);
|
||||
plMover.UpdateZone(newzone, newarea);
|
||||
|
||||
// new zone
|
||||
if (old_zone != newzone)
|
||||
{
|
||||
// honorless target
|
||||
if (plMover.pvpInfo.IsHostile)
|
||||
plMover.CastSpell(plMover, 2479, true);
|
||||
|
||||
// in friendly area
|
||||
else if (plMover.IsPvP() && !plMover.HasFlag(PlayerFields.Flags, PlayerFlags.InPVP))
|
||||
plMover.UpdatePvP(false, false);
|
||||
}
|
||||
|
||||
// resummon pet
|
||||
GetPlayer().ResummonPetTemporaryUnSummonedIfAny();
|
||||
|
||||
//lets process all delayed operations on successful teleport
|
||||
GetPlayer().ProcessDelayedOperations();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.MoveForceFlightBackSpeedChangeAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveForceFlightSpeedChangeAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveForcePitchRateChangeAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveForceRunBackSpeedChangeAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveForceRunSpeedChangeAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveForceSwimBackSpeedChangeAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveForceSwimSpeedChangeAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveForceTurnRateChangeAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveForceWalkSpeedChangeAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
void HandleForceSpeedChangeAck(MovementSpeedAck packet)
|
||||
{
|
||||
GetPlayer().ValidateMovementInfo(packet.Ack.Status);
|
||||
|
||||
// now can skip not our packet
|
||||
if (GetPlayer().GetGUID() != packet.Ack.Status.Guid)
|
||||
return;
|
||||
|
||||
/*----------------*/
|
||||
// client ACK send one packet for mounted/run case and need skip all except last from its
|
||||
// in other cases anti-cheat check can be fail in false case
|
||||
UnitMoveType move_type;
|
||||
|
||||
ClientOpcodes opcode = packet.GetOpcode();
|
||||
switch (opcode)
|
||||
{
|
||||
case ClientOpcodes.MoveForceWalkSpeedChangeAck:
|
||||
move_type = UnitMoveType.Walk;
|
||||
break;
|
||||
case ClientOpcodes.MoveForceRunSpeedChangeAck:
|
||||
move_type = UnitMoveType.Run;
|
||||
break;
|
||||
case ClientOpcodes.MoveForceRunBackSpeedChangeAck:
|
||||
move_type = UnitMoveType.RunBack;
|
||||
break;
|
||||
case ClientOpcodes.MoveForceSwimSpeedChangeAck:
|
||||
move_type = UnitMoveType.Swim;
|
||||
break;
|
||||
case ClientOpcodes.MoveForceSwimBackSpeedChangeAck:
|
||||
move_type = UnitMoveType.SwimBack;
|
||||
break;
|
||||
case ClientOpcodes.MoveForceTurnRateChangeAck:
|
||||
move_type = UnitMoveType.TurnRate;
|
||||
break;
|
||||
case ClientOpcodes.MoveForceFlightSpeedChangeAck:
|
||||
move_type = UnitMoveType.Flight;
|
||||
break;
|
||||
case ClientOpcodes.MoveForceFlightBackSpeedChangeAck:
|
||||
move_type = UnitMoveType.FlightBack;
|
||||
break;
|
||||
case ClientOpcodes.MoveForcePitchRateChangeAck:
|
||||
move_type = UnitMoveType.PitchRate;
|
||||
break;
|
||||
default:
|
||||
Log.outError(LogFilter.Network, "WorldSession.HandleForceSpeedChangeAck: Unknown move type opcode: {0}", opcode);
|
||||
return;
|
||||
}
|
||||
|
||||
// skip all forced speed changes except last and unexpected
|
||||
// in run/mounted case used one ACK and it must be skipped. m_forced_speed_changes[MOVE_RUN] store both.
|
||||
if (GetPlayer().m_forced_speed_changes[(int)move_type] > 0)
|
||||
{
|
||||
--GetPlayer().m_forced_speed_changes[(int)move_type];
|
||||
if (GetPlayer().m_forced_speed_changes[(int)move_type] > 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetPlayer().GetTransport() && Math.Abs(GetPlayer().GetSpeed(move_type) - packet.Speed) > 0.01f)
|
||||
{
|
||||
if (GetPlayer().GetSpeed(move_type) > packet.Speed) // must be greater - just correct
|
||||
{
|
||||
Log.outError(LogFilter.Network, "{0}SpeedChange player {1} is NOT correct (must be {2} instead {3}), force set to correct value",
|
||||
move_type, GetPlayer().GetName(), GetPlayer().GetSpeed(move_type), packet.Speed);
|
||||
GetPlayer().SetSpeedRate(move_type, GetPlayer().GetSpeedRate(move_type));
|
||||
}
|
||||
else // must be lesser - cheating
|
||||
{
|
||||
Log.outDebug(LogFilter.Server, "Player {0} from account id {1} kicked for incorrect speed (must be {2} instead {3})",
|
||||
GetPlayer().GetName(), GetPlayer().GetSession().GetAccountId(), GetPlayer().GetSpeed(move_type), packet.Speed);
|
||||
GetPlayer().GetSession().KickPlayer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetActiveMover)]
|
||||
void HandleSetActiveMover(SetActiveMover packet)
|
||||
{
|
||||
if (GetPlayer().IsInWorld)
|
||||
{
|
||||
if (_player.m_unitMovedByMe.GetGUID() != packet.ActiveMover)
|
||||
Log.outError(LogFilter.Network, "HandleSetActiveMover: incorrect mover guid: mover is {0} and should be {1},", packet.ActiveMover.ToString(), _player.m_unitMovedByMe.GetGUID().ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.MoveKnockBackAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
void HandleMoveKnockBackAck(MoveKnockBackAck movementAck)
|
||||
{
|
||||
GetPlayer().ValidateMovementInfo(movementAck.Ack.Status);
|
||||
|
||||
if (GetPlayer().m_unitMovedByMe.GetGUID() != movementAck.Ack.Status.Guid)
|
||||
return;
|
||||
|
||||
GetPlayer().m_movementInfo = movementAck.Ack.Status;
|
||||
|
||||
MoveUpdateKnockBack updateKnockBack = new MoveUpdateKnockBack();
|
||||
updateKnockBack.Status = GetPlayer().m_movementInfo;
|
||||
GetPlayer().SendMessageToSet(updateKnockBack, false);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.MoveEnableSwimToFlyTransAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveFeatherFallAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveForceRootAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveForceUnrootAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveGravityDisableAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveGravityEnableAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveHoverAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveSetCanFlyAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveSetCanTurnWhileFallingAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveSetIgnoreMovementForcesAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveWaterWalkAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
[WorldPacketHandler(ClientOpcodes.MoveEnableDoubleJumpAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
void HandleMovementAckMessage(MovementAckMessage movementAck)
|
||||
{
|
||||
GetPlayer().ValidateMovementInfo(movementAck.Ack.Status);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SummonResponse)]
|
||||
void HandleSummonResponseOpcode(SummonResponse packet)
|
||||
{
|
||||
if (!GetPlayer().IsAlive() || GetPlayer().IsInCombat())
|
||||
return;
|
||||
|
||||
GetPlayer().SummonIfPossible(packet.Accept);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.MoveSetCollisionHeightAck, Processing = PacketProcessing.ThreadSafe)]
|
||||
void HandleSetCollisionHeightAck(MoveSetCollisionHeightAck packet)
|
||||
{
|
||||
GetPlayer().ValidateMovementInfo(packet.Data.Status);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.MoveTimeSkipped, Processing = PacketProcessing.Inplace)]
|
||||
void HandleMoveTimeSkipped(MoveTimeSkipped moveTimeSkipped)
|
||||
{
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.MoveSplineDone, Processing = PacketProcessing.ThreadSafe)]
|
||||
void HandleMoveSplineDoneOpcode(MoveSplineDone moveSplineDone)
|
||||
{
|
||||
MovementInfo movementInfo = moveSplineDone.Status;
|
||||
_player.ValidateMovementInfo(movementInfo);
|
||||
|
||||
// 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)
|
||||
|
||||
uint curDest = GetPlayer().m_taxi.GetTaxiDestination();
|
||||
if (curDest != 0)
|
||||
{
|
||||
TaxiNodesRecord curDestNode = CliDB.TaxiNodesStorage.LookupByKey(curDest);
|
||||
|
||||
// far teleport case
|
||||
if (curDestNode != null && curDestNode.MapID != GetPlayer().GetMapId())
|
||||
{
|
||||
if (GetPlayer().GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Flight)
|
||||
{
|
||||
// short preparations to continue flight
|
||||
FlightPathMovementGenerator flight = (FlightPathMovementGenerator)GetPlayer().GetMotionMaster().top();
|
||||
|
||||
flight.SetCurrentNodeAfterTeleport();
|
||||
TaxiPathNodeRecord node = flight.GetPath()[(int)flight.GetCurrentNode()];
|
||||
flight.SkipCurrentNode();
|
||||
|
||||
GetPlayer().TeleportTo(curDestNode.MapID, node.Loc.X, node.Loc.Y, node.Loc.Z, GetPlayer().GetOrientation());
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// at this point only 1 node is expected (final destination)
|
||||
if (GetPlayer().m_taxi.GetPath().Count != 1)
|
||||
return;
|
||||
|
||||
GetPlayer().CleanupAfterTaxiFlight();
|
||||
GetPlayer().SetFallInformation(0, GetPlayer().GetPositionZ());
|
||||
if (GetPlayer().pvpInfo.IsHostile)
|
||||
GetPlayer().CastSpell(GetPlayer(), 2479, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,577 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.BattleGrounds;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.TabardVendorActivate)]
|
||||
void HandleTabardVendorActivate(Hello packet)
|
||||
{
|
||||
Creature unit = GetPlayer().GetNPCIfCanInteractWith(packet.Unit, NPCFlags.TabardDesigner);
|
||||
if (!unit)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleTabardVendorActivateOpcode - {0} not found or you can not interact with him.", packet.Unit.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
SendTabardVendorActivate(packet.Unit);
|
||||
}
|
||||
|
||||
public void SendTabardVendorActivate(ObjectGuid guid)
|
||||
{
|
||||
PlayerTabardVendorActivate packet = new PlayerTabardVendorActivate();
|
||||
packet.Vendor = guid;
|
||||
SendPacket(packet);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.TrainerList)]
|
||||
void HandleTrainerList(Hello packet)
|
||||
{
|
||||
Creature npc = GetPlayer().GetNPCIfCanInteractWith(packet.Unit, NPCFlags.Trainer);
|
||||
if (!npc)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, $"WorldSession.SendTrainerList - {packet.Unit.ToString()} not found or you can not interact with him.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint trainerId = Global.ObjectMgr.GetCreatureDefaultTrainer(npc.GetEntry());
|
||||
if (trainerId != 0)
|
||||
SendTrainerList(npc, trainerId);
|
||||
else
|
||||
Log.outDebug(LogFilter.Network, $"WorldSession.SendTrainerList - Creature id {npc.GetEntry()} has no trainer data.");
|
||||
}
|
||||
|
||||
public void SendTrainerList(Creature npc, uint trainerId)
|
||||
{
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
Trainer trainer = Global.ObjectMgr.GetTrainer(trainerId);
|
||||
if (trainer == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, $"WORLD: SendTrainerList - trainer spells not found for trainer {npc.GetGUID().ToString()} id {trainerId}");
|
||||
return;
|
||||
}
|
||||
|
||||
_player.PlayerTalkClass.GetInteractionData().Reset();
|
||||
_player.PlayerTalkClass.GetInteractionData().SourceGuid = npc.GetGUID();
|
||||
_player.PlayerTalkClass.GetInteractionData().TrainerId = trainerId;
|
||||
trainer.SendSpells(npc, _player, GetSessionDbLocaleIndex());
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.TrainerBuySpell)]
|
||||
void HandleTrainerBuySpell(TrainerBuySpell packet)
|
||||
{
|
||||
Creature npc = _player.GetNPCIfCanInteractWith(packet.TrainerGUID, NPCFlags.Trainer);
|
||||
if (npc == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, $"WORLD: HandleTrainerBuySpell - {packet.TrainerGUID.ToString()} not found or you can not interact with him.");
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (_player.HasUnitState(UnitState.Died))
|
||||
_player.RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
if (_player.PlayerTalkClass.GetInteractionData().SourceGuid != packet.TrainerGUID)
|
||||
return;
|
||||
|
||||
if (_player.PlayerTalkClass.GetInteractionData().TrainerId != packet.TrainerID)
|
||||
return;
|
||||
|
||||
// check present spell in trainer spell list
|
||||
Trainer trainer = Global.ObjectMgr.GetTrainer(packet.TrainerID);
|
||||
if (trainer == null)
|
||||
return;
|
||||
|
||||
trainer.TeachSpell(npc, _player, packet.SpellID);
|
||||
}
|
||||
|
||||
void SendTrainerBuyFailed(ObjectGuid trainerGUID, uint spellID, TrainerFailReason trainerFailedReason)
|
||||
{
|
||||
TrainerBuyFailed trainerBuyFailed = new TrainerBuyFailed();
|
||||
trainerBuyFailed.TrainerGUID = trainerGUID;
|
||||
trainerBuyFailed.SpellID = spellID; // should be same as in packet from client
|
||||
trainerBuyFailed.TrainerFailedReason = trainerFailedReason; // 1 == "Not enough money for trainer service." 0 == "Trainer service %d unavailable."
|
||||
SendPacket(trainerBuyFailed);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.TalkToGossip)]
|
||||
void HandleGossipHello(Hello packet)
|
||||
{
|
||||
Creature unit = GetPlayer().GetNPCIfCanInteractWith(packet.Unit, NPCFlags.Gossip);
|
||||
if (unit == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleGossipHello - {0} not found or you can not interact with him.", packet.Unit.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// set faction visible if needed
|
||||
var factionTemplateEntry = CliDB.FactionTemplateStorage.LookupByKey(unit.getFaction());
|
||||
if (factionTemplateEntry != null)
|
||||
GetPlayer().GetReputationMgr().SetVisible(factionTemplateEntry);
|
||||
|
||||
GetPlayer().RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Talk);
|
||||
|
||||
if (unit.IsArmorer() || unit.IsCivilian() || unit.IsQuestGiver() || unit.IsServiceProvider() || unit.IsGuard())
|
||||
unit.StopMoving();
|
||||
|
||||
// If spiritguide, no need for gossip menu, just put player into resurrect queue
|
||||
if (unit.IsSpiritGuide())
|
||||
{
|
||||
Battleground bg = GetPlayer().GetBattleground();
|
||||
if (bg)
|
||||
{
|
||||
bg.AddPlayerToResurrectQueue(unit.GetGUID(), GetPlayer().GetGUID());
|
||||
Global.BattlegroundMgr.SendAreaSpiritHealerQuery(GetPlayer(), bg, unit.GetGUID());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Global.ScriptMgr.OnGossipHello(GetPlayer(), unit))
|
||||
{
|
||||
GetPlayer().PrepareGossipMenu(unit, unit.GetCreatureTemplate().GossipMenuId, true);
|
||||
GetPlayer().SendPreparedGossip(unit);
|
||||
}
|
||||
unit.GetAI().sGossipHello(GetPlayer());
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GossipSelectOption)]
|
||||
void HandleGossipSelectOption(GossipSelectOption packet)
|
||||
{
|
||||
if (GetPlayer().PlayerTalkClass.GetGossipMenu().GetItem(packet.GossipIndex) == null)
|
||||
return;
|
||||
|
||||
// Prevent cheating on C# scripted menus
|
||||
if (GetPlayer().PlayerTalkClass.GetInteractionData().SourceGuid != packet.GossipUnit)
|
||||
return;
|
||||
|
||||
Creature unit = null;
|
||||
GameObject go = null;
|
||||
if (packet.GossipUnit.IsCreatureOrVehicle())
|
||||
{
|
||||
unit = GetPlayer().GetNPCIfCanInteractWith(packet.GossipUnit, NPCFlags.Gossip);
|
||||
if (unit == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleGossipSelectOption - {0} not found or you can't interact with him.", packet.GossipUnit.ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (packet.GossipUnit.IsGameObject())
|
||||
{
|
||||
go = GetPlayer().GetGameObjectIfCanInteractWith(packet.GossipUnit);
|
||||
if (go == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleGossipSelectOption - {0} not found or you can't interact with it.", packet.GossipUnit.ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleGossipSelectOption - unsupported {0}.", packet.GossipUnit.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
if ((unit && unit.GetScriptId() != unit.LastUsedScriptID) || (go != null && go.GetScriptId() != go.LastUsedScriptID))
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleGossipSelectOption - Script reloaded while in use, ignoring and set new scipt id");
|
||||
if (unit != null)
|
||||
unit.LastUsedScriptID = unit.GetScriptId();
|
||||
|
||||
if (go != null)
|
||||
go.LastUsedScriptID = go.GetScriptId();
|
||||
GetPlayer().PlayerTalkClass.SendCloseGossip();
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(packet.PromotionCode))
|
||||
{
|
||||
if (unit)
|
||||
{
|
||||
unit.GetAI().sGossipSelectCode(GetPlayer(), packet.GossipID, packet.GossipIndex, packet.PromotionCode);
|
||||
if (!Global.ScriptMgr.OnGossipSelectCode(GetPlayer(), unit, GetPlayer().PlayerTalkClass.GetGossipOptionSender(packet.GossipIndex), GetPlayer().PlayerTalkClass.GetGossipOptionAction(packet.GossipIndex), packet.PromotionCode))
|
||||
GetPlayer().OnGossipSelect(unit, packet.GossipIndex, packet.GossipID);
|
||||
}
|
||||
else
|
||||
{
|
||||
go.GetAI().GossipSelectCode(GetPlayer(), packet.GossipID, packet.GossipIndex, packet.PromotionCode);
|
||||
Global.ScriptMgr.OnGossipSelectCode(GetPlayer(), go, GetPlayer().PlayerTalkClass.GetGossipOptionSender(packet.GossipIndex), GetPlayer().PlayerTalkClass.GetGossipOptionAction(packet.GossipIndex), packet.PromotionCode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unit != null)
|
||||
{
|
||||
unit.GetAI().sGossipSelect(GetPlayer(), packet.GossipID, packet.GossipIndex);
|
||||
if (!Global.ScriptMgr.OnGossipSelect(GetPlayer(), unit, GetPlayer().PlayerTalkClass.GetGossipOptionSender(packet.GossipIndex), GetPlayer().PlayerTalkClass.GetGossipOptionAction(packet.GossipIndex)))
|
||||
GetPlayer().OnGossipSelect(unit, packet.GossipIndex, packet.GossipID);
|
||||
}
|
||||
else
|
||||
{
|
||||
go.GetAI().GossipSelect(GetPlayer(), packet.GossipID, packet.GossipIndex);
|
||||
if (!Global.ScriptMgr.OnGossipSelect(GetPlayer(), go, GetPlayer().PlayerTalkClass.GetGossipOptionSender(packet.GossipIndex), GetPlayer().PlayerTalkClass.GetGossipOptionAction(packet.GossipIndex)))
|
||||
GetPlayer().OnGossipSelect(go, packet.GossipIndex, packet.GossipID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SpiritHealerActivate)]
|
||||
void HandleSpiritHealerActivate(SpiritHealerActivate packet)
|
||||
{
|
||||
Creature unit = GetPlayer().GetNPCIfCanInteractWith(packet.Healer, NPCFlags.SpiritHealer);
|
||||
if (!unit)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleSpiritHealerActivateOpcode - {0} not found or you can not interact with him.", packet.Healer.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
SendSpiritResurrect();
|
||||
}
|
||||
|
||||
void SendSpiritResurrect()
|
||||
{
|
||||
GetPlayer().ResurrectPlayer(0.5f, true);
|
||||
|
||||
GetPlayer().DurabilityLossAll(0.25f, true);
|
||||
|
||||
// get corpse nearest graveyard
|
||||
WorldSafeLocsRecord corpseGrave = null;
|
||||
WorldLocation corpseLocation = GetPlayer().GetCorpseLocation();
|
||||
if (GetPlayer().HasCorpse())
|
||||
{
|
||||
corpseGrave = Global.ObjectMgr.GetClosestGraveYard(corpseLocation.GetPositionX(), corpseLocation.GetPositionY(),
|
||||
corpseLocation.GetPositionZ(), corpseLocation.GetMapId(), GetPlayer().GetTeam());
|
||||
}
|
||||
|
||||
// now can spawn bones
|
||||
GetPlayer().SpawnCorpseBones();
|
||||
|
||||
// teleport to nearest from corpse graveyard, if different from nearest to player ghost
|
||||
if (corpseGrave != null)
|
||||
{
|
||||
WorldSafeLocsRecord ghostGrave = Global.ObjectMgr.GetClosestGraveYard(
|
||||
GetPlayer().GetPositionX(), GetPlayer().GetPositionY(), GetPlayer().GetPositionZ(), GetPlayer().GetMapId(), GetPlayer().GetTeam());
|
||||
|
||||
if (corpseGrave != ghostGrave)
|
||||
GetPlayer().TeleportTo(corpseGrave.MapID, corpseGrave.Loc.X, corpseGrave.Loc.Y, corpseGrave.Loc.Z, GetPlayer().GetOrientation());
|
||||
// or update at original position
|
||||
else
|
||||
GetPlayer().UpdateObjectVisibility();
|
||||
}
|
||||
// or update at original position
|
||||
else
|
||||
GetPlayer().UpdateObjectVisibility();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BinderActivate)]
|
||||
void HandleBinderActivate(Hello packet)
|
||||
{
|
||||
if (!GetPlayer().IsInWorld || !GetPlayer().IsAlive())
|
||||
return;
|
||||
|
||||
Creature unit = GetPlayer().GetNPCIfCanInteractWith(packet.Unit, NPCFlags.Innkeeper);
|
||||
if (!unit)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleBinderActivate - {0} not found or you can not interact with him.", packet.Unit.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
SendBindPoint(unit);
|
||||
}
|
||||
|
||||
void SendBindPoint(Creature npc)
|
||||
{
|
||||
// prevent set homebind to instances in any case
|
||||
if (GetPlayer().GetMap().Instanceable())
|
||||
return;
|
||||
|
||||
uint bindspell = 3286;
|
||||
|
||||
// send spell for homebinding (3286)
|
||||
npc.CastSpell(GetPlayer(), bindspell, true);
|
||||
|
||||
GetPlayer().PlayerTalkClass.SendCloseGossip();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestStabledPets)]
|
||||
void HandleRequestStabledPets(RequestStabledPets packet)
|
||||
{
|
||||
if (!CheckStableMaster(packet.StableMaster))
|
||||
return;
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
// remove mounts this fix bug where getting pet from stable while mounted deletes pet.
|
||||
if (GetPlayer().IsMounted())
|
||||
GetPlayer().RemoveAurasByType(AuraType.Mounted);
|
||||
|
||||
SendStablePet(packet.StableMaster);
|
||||
}
|
||||
|
||||
public void SendStablePet(ObjectGuid guid)
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PET_SLOTS_DETAIL);
|
||||
stmt.AddValue(0, guid.GetCounter());
|
||||
stmt.AddValue(1, PetSaveMode.FirstStableSlot);
|
||||
stmt.AddValue(2, PetSaveMode.LastStableSlot);
|
||||
|
||||
_queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(SendStablePetCallback, guid));
|
||||
}
|
||||
|
||||
void SendStablePetCallback(ObjectGuid guid, SQLResult result)
|
||||
{
|
||||
if (!GetPlayer())
|
||||
return;
|
||||
|
||||
PetStableList packet = new PetStableList();
|
||||
packet.StableMaster = guid;
|
||||
|
||||
Pet pet = GetPlayer().GetPet();
|
||||
|
||||
uint petSlot = 0;
|
||||
// not let move dead pet in slot
|
||||
if (pet && pet.IsAlive() && pet.getPetType() == PetType.Hunter)
|
||||
{
|
||||
PetStableInfo stableEntry;// = new PetStableInfo();
|
||||
stableEntry.PetSlot = petSlot;
|
||||
stableEntry.PetNumber = pet.GetCharmInfo().GetPetNumber();
|
||||
stableEntry.CreatureID = pet.GetEntry();
|
||||
stableEntry.DisplayID = pet.GetDisplayId();
|
||||
stableEntry.ExperienceLevel = pet.getLevel();
|
||||
stableEntry.PetFlags = PetStableinfo.Active;
|
||||
stableEntry.PetName = pet.GetName();
|
||||
++petSlot;
|
||||
|
||||
packet.Pets.Add(stableEntry);
|
||||
}
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
PetStableInfo stableEntry;// = new PetStableInfo();
|
||||
|
||||
stableEntry.PetSlot = petSlot;
|
||||
stableEntry.PetNumber = result.Read<uint>(1); // petnumber
|
||||
stableEntry.CreatureID = result.Read<uint>(2); // creature entry
|
||||
stableEntry.DisplayID = result.Read<uint>(5); // creature displayid
|
||||
stableEntry.ExperienceLevel = result.Read<ushort>(3); // level
|
||||
stableEntry.PetFlags = PetStableinfo.Inactive;
|
||||
stableEntry.PetName = result.Read<string>(4); // Name
|
||||
|
||||
++petSlot;
|
||||
packet.Pets.Add(stableEntry);
|
||||
}
|
||||
while (result.NextRow());
|
||||
}
|
||||
|
||||
SendPacket(packet);
|
||||
}
|
||||
|
||||
void SendPetStableResult(byte res)
|
||||
{
|
||||
SendPacket(new PetStableResult(res));
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RepairItem)]
|
||||
void HandleRepairItem(RepairItem packet)
|
||||
{
|
||||
Creature unit = GetPlayer().GetNPCIfCanInteractWith(packet.NpcGUID, NPCFlags.Repair);
|
||||
if (!unit)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleRepairItemOpcode - {0} not found or you can not interact with him.", packet.NpcGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
// reputation discount
|
||||
float discountMod = GetPlayer().GetReputationPriceDiscount(unit);
|
||||
|
||||
if (!packet.ItemGUID.IsEmpty())
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "ITEM: Repair {0}, at {1}", packet.ItemGUID.ToString(), packet.NpcGUID.ToString());
|
||||
|
||||
Item item = GetPlayer().GetItemByGuid(packet.ItemGUID);
|
||||
if (item)
|
||||
GetPlayer().DurabilityRepair(item.GetPos(), true, discountMod, packet.UseGuildBank);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "ITEM: Repair all items at {0}", packet.NpcGUID.ToString());
|
||||
GetPlayer().DurabilityRepairAll(true, discountMod, packet.UseGuildBank);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ListInventory)]
|
||||
void HandleListInventory(Hello packet)
|
||||
{
|
||||
if (!GetPlayer().IsAlive())
|
||||
return;
|
||||
|
||||
SendListInventory(packet.Unit);
|
||||
}
|
||||
|
||||
public void SendListInventory(ObjectGuid vendorGuid)
|
||||
{
|
||||
Creature vendor = GetPlayer().GetNPCIfCanInteractWith(vendorGuid, NPCFlags.Vendor);
|
||||
if (vendor == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: SendListInventory - {0} not found or you can not interact with him.", vendorGuid.ToString());
|
||||
GetPlayer().SendSellError(SellResult.CantFindVendor, null, ObjectGuid.Empty);
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
// Stop the npc if moving
|
||||
if (vendor.HasUnitState(UnitState.Moving))
|
||||
vendor.StopMoving();
|
||||
|
||||
VendorItemData vendorItems = vendor.GetVendorItems();
|
||||
int rawItemCount = vendorItems != null ? vendorItems.GetItemCount() : 0;
|
||||
|
||||
VendorInventory packet = new VendorInventory();
|
||||
packet.Vendor = vendor.GetGUID();
|
||||
|
||||
float discountMod = GetPlayer().GetReputationPriceDiscount(vendor);
|
||||
byte count = 0;
|
||||
for (uint slot = 0; slot < rawItemCount; ++slot)
|
||||
{
|
||||
VendorItem vendorItem = vendorItems.GetItem(slot);
|
||||
if (vendorItem == null)
|
||||
continue;
|
||||
|
||||
VendorItemPkt item = new VendorItemPkt();
|
||||
|
||||
PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(vendorItem.PlayerConditionId);
|
||||
if (playerCondition != null)
|
||||
if (!ConditionManager.IsPlayerMeetingCondition(_player, playerCondition))
|
||||
item.PlayerConditionFailed = (int)playerCondition.Id;
|
||||
|
||||
if (vendorItem.Type == ItemVendorType.Item)
|
||||
{
|
||||
ItemTemplate itemTemplate = Global.ObjectMgr.GetItemTemplate(vendorItem.item);
|
||||
if (itemTemplate == null)
|
||||
continue;
|
||||
|
||||
int leftInStock = vendorItem.maxcount == 0 ? -1 : (int)vendor.GetVendorItemCurrentCount(vendorItem);
|
||||
if (!GetPlayer().IsGameMaster())
|
||||
{
|
||||
if (!Convert.ToBoolean(itemTemplate.GetAllowableClass() & GetPlayer().getClassMask()) && itemTemplate.GetBonding() == ItemBondingType.OnAcquire)
|
||||
continue;
|
||||
|
||||
if ((itemTemplate.GetFlags2().HasAnyFlag(ItemFlags2.FactionHorde) && GetPlayer().GetTeam() == Team.Alliance) ||
|
||||
(itemTemplate.GetFlags2().HasAnyFlag(ItemFlags2.FactionAlliance) && GetPlayer().GetTeam() == Team.Horde))
|
||||
continue;
|
||||
|
||||
if (leftInStock == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Global.ConditionMgr.IsObjectMeetingVendorItemConditions(vendor.GetEntry(), vendorItem.item, _player, vendor))
|
||||
{
|
||||
Log.outDebug(LogFilter.Condition, "SendListInventory: conditions not met for creature entry {0} item {1}", vendor.GetEntry(), vendorItem.item);
|
||||
continue;
|
||||
}
|
||||
|
||||
int price = (int)(vendorItem.IsGoldRequired(itemTemplate) ? Math.Floor(itemTemplate.GetBuyPrice() * discountMod) : 0);
|
||||
|
||||
int priceMod = GetPlayer().GetTotalAuraModifier(AuraType.ModVendorItemsPrices);
|
||||
if (priceMod != 0)
|
||||
price -= MathFunctions.CalculatePct(price, priceMod);
|
||||
|
||||
item.MuID = (int)slot + 1;
|
||||
item.Durability = (int)itemTemplate.MaxDurability;
|
||||
item.ExtendedCostID = (int)vendorItem.ExtendedCost;
|
||||
item.Type = (int)vendorItem.Type;
|
||||
item.Quantity = leftInStock;
|
||||
item.StackCount = (int)itemTemplate.GetBuyCount();
|
||||
item.Price = (ulong)price;
|
||||
item.DoNotFilterOnVendor = vendorItem.IgnoreFiltering;
|
||||
|
||||
item.Item.ItemID = vendorItem.item;
|
||||
if (!vendorItem.BonusListIDs.Empty())
|
||||
{
|
||||
item.Item.ItemBonus.HasValue = true;
|
||||
item.Item.ItemBonus.Value.BonusListIDs = vendorItem.BonusListIDs;
|
||||
}
|
||||
|
||||
packet.Items.Add(item);
|
||||
}
|
||||
else if (vendorItem.Type == ItemVendorType.Currency)
|
||||
{
|
||||
CurrencyTypesRecord currencyTemplate = CliDB.CurrencyTypesStorage.LookupByKey(vendorItem.item);
|
||||
if (currencyTemplate == null)
|
||||
continue;
|
||||
|
||||
if (vendorItem.ExtendedCost == 0)
|
||||
continue; // there's no price defined for currencies, only extendedcost is used
|
||||
|
||||
item.MuID = (int)slot + 1; // client expects counting to start at 1
|
||||
item.ExtendedCostID = (int)vendorItem.ExtendedCost;
|
||||
item.Item.ItemID = vendorItem.item;
|
||||
item.Type = (int)vendorItem.Type;
|
||||
item.StackCount = (int)vendorItem.maxcount;
|
||||
item.DoNotFilterOnVendor = vendorItem.IgnoreFiltering;
|
||||
|
||||
packet.Items.Add(item);
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
if (++count >= SharedConst.MaxVendorItems)
|
||||
break;
|
||||
}
|
||||
|
||||
SendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,726 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using Game.Spells;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.DismissCritter)]
|
||||
void HandleDismissCritter(DismissCritter packet)
|
||||
{
|
||||
Unit pet = ObjectAccessor.GetCreatureOrPetOrVehicle(GetPlayer(), packet.CritterGUID);
|
||||
if (!pet)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "Vanitypet {0} does not exist - player '{1}' ({2} / account: {3}) attempted to dismiss it (possibly lagged out)",
|
||||
packet.CritterGUID.ToString(), GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), GetAccountId());
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer().GetCritterGUID() == pet.GetGUID())
|
||||
{
|
||||
if (pet.IsTypeId(TypeId.Unit) && pet.ToCreature().IsSummon())
|
||||
pet.ToTempSummon().UnSummon();
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestPetInfo)]
|
||||
void HandleRequestPetInfo(RequestPetInfo packet)
|
||||
{
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PetAction)]
|
||||
void HandlePetAction(PetAction packet)
|
||||
{
|
||||
ObjectGuid guid1 = packet.PetGUID; //pet guid
|
||||
ObjectGuid guid2 = packet.TargetGUID; //tag guid
|
||||
|
||||
uint spellid = UnitActionBarEntry.UNIT_ACTION_BUTTON_ACTION(packet.Action);
|
||||
ActiveStates flag = (ActiveStates)UnitActionBarEntry.UNIT_ACTION_BUTTON_TYPE(packet.Action); //delete = 0x07 CastSpell = C1
|
||||
|
||||
// used also for charmed creature
|
||||
Unit pet = Global.ObjAccessor.GetUnit(GetPlayer(), guid1);
|
||||
if (!pet)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandlePetAction: {0} doesn't exist for {1}", guid1.ToString(), GetPlayer().GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (pet != GetPlayer().GetFirstControlled())
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandlePetAction: {0} does not belong to {1}", guid1.ToString(), GetPlayer().GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pet.IsAlive())
|
||||
{
|
||||
SpellInfo spell = (flag == ActiveStates.Enabled || flag == ActiveStates.Passive) ? Global.SpellMgr.GetSpellInfo(spellid) : null;
|
||||
if (spell == null)
|
||||
return;
|
||||
if (!spell.HasAttribute(SpellAttr0.CastableWhileDead))
|
||||
return;
|
||||
}
|
||||
|
||||
/// @todo allow control charmed player?
|
||||
if (pet.IsTypeId(TypeId.Player) && !(flag == ActiveStates.Command && spellid == (uint)CommandStates.Attack))
|
||||
return;
|
||||
|
||||
if (GetPlayer().m_Controlled.Count == 1)
|
||||
HandlePetActionHelper(pet, guid1, spellid, flag, guid2, packet.ActionPosition.X, packet.ActionPosition.Y, packet.ActionPosition.Z);
|
||||
else
|
||||
{
|
||||
//If a pet is dismissed, m_Controlled will change
|
||||
List<Unit> controlled = new List<Unit>();
|
||||
foreach (var unit in GetPlayer().m_Controlled)
|
||||
if (unit.GetEntry() == pet.GetEntry() && unit.IsAlive())
|
||||
controlled.Add(unit);
|
||||
|
||||
foreach (var unit in controlled)
|
||||
HandlePetActionHelper(unit, guid1, spellid, flag, guid2, packet.ActionPosition.X, packet.ActionPosition.Y, packet.ActionPosition.Z);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PetStopAttack)]
|
||||
void HandlePetStopAttack(PetStopAttack packet)
|
||||
{
|
||||
Unit pet = ObjectAccessor.GetCreatureOrPetOrVehicle(GetPlayer(), packet.PetGUID);
|
||||
if (!pet)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandlePetStopAttack: {0} does not exist", packet.PetGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (pet != GetPlayer().GetPet() && pet != GetPlayer().GetCharm())
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandlePetStopAttack: {0} isn't a pet or charmed creature of player {1}", packet.PetGUID.ToString(), GetPlayer().GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pet.IsAlive())
|
||||
return;
|
||||
|
||||
pet.AttackStop();
|
||||
}
|
||||
|
||||
void HandlePetActionHelper(Unit pet, ObjectGuid guid1, uint spellid, ActiveStates flag, ObjectGuid guid2, float x, float y, float z)
|
||||
{
|
||||
CharmInfo charmInfo = pet.GetCharmInfo();
|
||||
if (charmInfo == null)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "WorldSession.HandlePetAction(petGuid: {0}, tagGuid: {1}, spellId: {2}, flag: {3}): object (GUID: {4} Entry: {5} TypeId: {6}) is considered pet-like but doesn't have a charminfo!",
|
||||
guid1, guid2, spellid, flag, pet.GetGUID().ToString(), pet.GetEntry(), pet.GetTypeId());
|
||||
return;
|
||||
}
|
||||
|
||||
switch (flag)
|
||||
{
|
||||
case ActiveStates.Command: //0x07
|
||||
switch ((CommandStates)spellid)
|
||||
{
|
||||
case CommandStates.Stay: //flat=1792 //STAY
|
||||
pet.StopMoving();
|
||||
pet.GetMotionMaster().Clear(false);
|
||||
pet.GetMotionMaster().MoveIdle();
|
||||
charmInfo.SetCommandState(CommandStates.Stay);
|
||||
|
||||
charmInfo.SetIsCommandAttack(false);
|
||||
charmInfo.SetIsAtStay(true);
|
||||
charmInfo.SetIsCommandFollow(false);
|
||||
charmInfo.SetIsFollowing(false);
|
||||
charmInfo.SetIsReturning(false);
|
||||
charmInfo.SaveStayPosition();
|
||||
break;
|
||||
case CommandStates.Follow: //spellid=1792 //FOLLOW
|
||||
pet.AttackStop();
|
||||
pet.InterruptNonMeleeSpells(false);
|
||||
pet.GetMotionMaster().MoveFollow(GetPlayer(), SharedConst.PetFollowDist, pet.GetFollowAngle());
|
||||
charmInfo.SetCommandState(CommandStates.Follow);
|
||||
|
||||
charmInfo.SetIsCommandAttack(false);
|
||||
charmInfo.SetIsAtStay(false);
|
||||
charmInfo.SetIsReturning(true);
|
||||
charmInfo.SetIsCommandFollow(true);
|
||||
charmInfo.SetIsFollowing(false);
|
||||
break;
|
||||
case CommandStates.Attack: //spellid=1792 //ATTACK
|
||||
{
|
||||
// Can't attack if owner is pacified
|
||||
if (GetPlayer().HasAuraType(AuraType.ModPacify))
|
||||
{
|
||||
/// @todo Send proper error message to client
|
||||
return;
|
||||
}
|
||||
|
||||
// only place where pet can be player
|
||||
Unit TargetUnit = Global.ObjAccessor.GetUnit(GetPlayer(), guid2);
|
||||
if (!TargetUnit)
|
||||
return;
|
||||
|
||||
Unit owner = pet.GetOwner();
|
||||
if (owner)
|
||||
if (!owner.IsValidAttackTarget(TargetUnit))
|
||||
return;
|
||||
|
||||
pet.ClearUnitState(UnitState.Follow);
|
||||
// This is true if pet has no target or has target but targets differs.
|
||||
if (pet.GetVictim() != TargetUnit || (pet.GetVictim() == TargetUnit && !pet.GetCharmInfo().IsCommandAttack()))
|
||||
{
|
||||
if (pet.GetVictim())
|
||||
pet.AttackStop();
|
||||
|
||||
if (!pet.IsTypeId(TypeId.Player) && pet.ToCreature().IsAIEnabled)
|
||||
{
|
||||
charmInfo.SetIsCommandAttack(true);
|
||||
charmInfo.SetIsAtStay(false);
|
||||
charmInfo.SetIsFollowing(false);
|
||||
charmInfo.SetIsCommandFollow(false);
|
||||
charmInfo.SetIsReturning(false);
|
||||
|
||||
pet.ToCreature().GetAI().AttackStart(TargetUnit);
|
||||
|
||||
//10% chance to play special pet attack talk, else growl
|
||||
if (pet.IsPet() && pet.ToPet().getPetType() == PetType.Summon && pet != TargetUnit && RandomHelper.IRand(0, 100) < 10)
|
||||
pet.SendPetTalk(PetTalk.Attack);
|
||||
else
|
||||
{
|
||||
// 90% chance for pet and 100% chance for charmed creature
|
||||
pet.SendPetAIReaction(guid1);
|
||||
}
|
||||
}
|
||||
else // charmed player
|
||||
{
|
||||
if (pet.GetVictim() && pet.GetVictim() != TargetUnit)
|
||||
pet.AttackStop();
|
||||
|
||||
charmInfo.SetIsCommandAttack(true);
|
||||
charmInfo.SetIsAtStay(false);
|
||||
charmInfo.SetIsFollowing(false);
|
||||
charmInfo.SetIsCommandFollow(false);
|
||||
charmInfo.SetIsReturning(false);
|
||||
|
||||
pet.Attack(TargetUnit, true);
|
||||
pet.SendPetAIReaction(guid1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CommandStates.Abandon: // abandon (hunter pet) or dismiss (summoned pet)
|
||||
if (pet.GetCharmerGUID() == GetPlayer().GetGUID())
|
||||
GetPlayer().StopCastingCharm();
|
||||
else if (pet.GetOwnerGUID() == GetPlayer().GetGUID())
|
||||
{
|
||||
Contract.Assert(pet.IsTypeId(TypeId.Unit));
|
||||
if (pet.IsPet())
|
||||
{
|
||||
if (pet.ToPet().getPetType() == PetType.Hunter)
|
||||
GetPlayer().RemovePet(pet.ToPet(), PetSaveMode.AsDeleted);
|
||||
else
|
||||
//dismissing a summoned pet is like killing them (this prevents returning a soulshard...)
|
||||
pet.setDeathState(DeathState.Corpse);
|
||||
}
|
||||
else if (pet.HasUnitTypeMask(UnitTypeMask.Minion))
|
||||
{
|
||||
((Minion)pet).UnSummon();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CommandStates.MoveTo:
|
||||
pet.StopMoving();
|
||||
pet.GetMotionMaster().Clear(false);
|
||||
pet.GetMotionMaster().MovePoint(0, x, y, z);
|
||||
charmInfo.SetCommandState(CommandStates.MoveTo);
|
||||
|
||||
charmInfo.SetIsCommandAttack(false);
|
||||
charmInfo.SetIsAtStay(true);
|
||||
charmInfo.SetIsFollowing(false);
|
||||
charmInfo.SetIsReturning(false);
|
||||
charmInfo.SaveStayPosition();
|
||||
break;
|
||||
default:
|
||||
Log.outError(LogFilter.Network, "WORLD: unknown PET flag Action {0} and spellid {1}.", flag, spellid);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ActiveStates.Reaction: // 0x6
|
||||
switch ((ReactStates)spellid)
|
||||
{
|
||||
case ReactStates.Passive: //passive
|
||||
pet.AttackStop();
|
||||
goto case ReactStates.Defensive;
|
||||
case ReactStates.Defensive: //recovery
|
||||
case ReactStates.Aggressive: //activete
|
||||
if (pet.IsTypeId(TypeId.Unit))
|
||||
pet.ToCreature().SetReactState((ReactStates)spellid);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ActiveStates.Disabled: // 0x81 spell (disabled), ignore
|
||||
case ActiveStates.Passive: // 0x01
|
||||
case ActiveStates.Enabled: // 0xC1 spell
|
||||
{
|
||||
Unit unit_target = null;
|
||||
|
||||
if (!guid2.IsEmpty())
|
||||
unit_target = Global.ObjAccessor.GetUnit(GetPlayer(), guid2);
|
||||
|
||||
// do not cast unknown spells
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellid);
|
||||
if (spellInfo == null)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "WORLD: unknown PET spell id {0}", spellid);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None))
|
||||
{
|
||||
if (effect != null && (effect.TargetA.GetTarget() == Targets.UnitSrcAreaEnemy || effect.TargetA.GetTarget() == Targets.UnitDestAreaEnemy || effect.TargetA.GetTarget() == Targets.DestDynobjEnemy))
|
||||
return;
|
||||
}
|
||||
|
||||
// do not cast not learned spells
|
||||
if (!pet.HasSpell(spellid) || spellInfo.IsPassive())
|
||||
return;
|
||||
|
||||
// Clear the flags as if owner clicked 'attack'. AI will reset them
|
||||
// after AttackStart, even if spell failed
|
||||
if (pet.GetCharmInfo() != null)
|
||||
{
|
||||
pet.GetCharmInfo().SetIsAtStay(false);
|
||||
pet.GetCharmInfo().SetIsCommandAttack(true);
|
||||
pet.GetCharmInfo().SetIsReturning(false);
|
||||
pet.GetCharmInfo().SetIsFollowing(false);
|
||||
}
|
||||
|
||||
Spell spell = new Spell(pet, spellInfo, TriggerCastFlags.None);
|
||||
|
||||
SpellCastResult result = spell.CheckPetCast(unit_target);
|
||||
|
||||
//auto turn to target unless possessed
|
||||
if (result == SpellCastResult.UnitNotInfront && !pet.isPossessed() && !pet.IsVehicle())
|
||||
{
|
||||
Unit unit_target2 = spell.m_targets.GetUnitTarget();
|
||||
if (unit_target)
|
||||
{
|
||||
pet.SetInFront(unit_target);
|
||||
Player player = unit_target.ToPlayer();
|
||||
if (player)
|
||||
pet.SendUpdateToPlayer(player);
|
||||
}
|
||||
else if (unit_target2)
|
||||
{
|
||||
pet.SetInFront(unit_target2);
|
||||
Player player = unit_target2.ToPlayer();
|
||||
if (player)
|
||||
pet.SendUpdateToPlayer(player);
|
||||
}
|
||||
Unit powner = pet.GetCharmerOrOwner();
|
||||
if (powner)
|
||||
{
|
||||
Player player = powner.ToPlayer();
|
||||
if (player)
|
||||
pet.SendUpdateToPlayer(player);
|
||||
}
|
||||
|
||||
result = SpellCastResult.SpellCastOk;
|
||||
}
|
||||
|
||||
if (result == SpellCastResult.SpellCastOk)
|
||||
{
|
||||
unit_target = spell.m_targets.GetUnitTarget();
|
||||
|
||||
//10% chance to play special pet attack talk, else growl
|
||||
//actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
|
||||
if (pet.IsPet() && (pet.ToPet().getPetType() == PetType.Summon) && (pet != unit_target) && (RandomHelper.IRand(0, 100) < 10))
|
||||
pet.SendPetTalk(PetTalk.SpecialSpell);
|
||||
else
|
||||
{
|
||||
pet.SendPetAIReaction(guid1);
|
||||
}
|
||||
|
||||
if (unit_target && !GetPlayer().IsFriendlyTo(unit_target) && !pet.isPossessed() && !pet.IsVehicle())
|
||||
{
|
||||
// This is true if pet has no target or has target but targets differs.
|
||||
if (pet.GetVictim() != unit_target)
|
||||
{
|
||||
if (pet.GetVictim())
|
||||
pet.AttackStop();
|
||||
pet.GetMotionMaster().Clear();
|
||||
if (pet.ToCreature().IsAIEnabled)
|
||||
pet.ToCreature().GetAI().AttackStart(unit_target);
|
||||
}
|
||||
}
|
||||
|
||||
spell.prepare(spell.m_targets);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pet.isPossessed() || pet.IsVehicle()) /// @todo: confirm this check
|
||||
Spell.SendCastResult(GetPlayer(), spellInfo, spell.m_SpellVisual, spell.m_castId, result);
|
||||
else
|
||||
spell.SendPetCastResult(result);
|
||||
|
||||
if (!pet.GetSpellHistory().HasCooldown(spellid))
|
||||
pet.GetSpellHistory().ResetCooldown(spellid, true);
|
||||
|
||||
spell.finish(false);
|
||||
spell.Dispose();
|
||||
|
||||
// reset specific flags in case of spell fail. AI will reset other flags
|
||||
if (pet.GetCharmInfo() != null)
|
||||
pet.GetCharmInfo().SetIsCommandAttack(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Log.outError(LogFilter.Network, "WORLD: unknown PET flag Action {0} and spellid {1}.", flag, spellid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QueryPetName)]
|
||||
void HandleQueryPetName(QueryPetName packet)
|
||||
{
|
||||
SendQueryPetNameResponse(packet.UnitGUID);
|
||||
}
|
||||
|
||||
void SendQueryPetNameResponse(ObjectGuid guid)
|
||||
{
|
||||
QueryPetNameResponse response = new QueryPetNameResponse();
|
||||
response.UnitGUID = guid;
|
||||
|
||||
Creature unit = ObjectAccessor.GetCreatureOrPetOrVehicle(GetPlayer(), guid);
|
||||
if (unit)
|
||||
{
|
||||
response.Allow = true;
|
||||
response.Timestamp = unit.GetUInt32Value(UnitFields.PetNameTimestamp);
|
||||
response.Name = unit.GetName();
|
||||
|
||||
Pet pet = unit.ToPet();
|
||||
if (pet)
|
||||
{
|
||||
DeclinedName names = pet.GetDeclinedNames();
|
||||
if (names != null)
|
||||
{
|
||||
response.HasDeclined = true;
|
||||
response.DeclinedNames = names;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().SendPacket(response);
|
||||
}
|
||||
|
||||
bool CheckStableMaster(ObjectGuid guid)
|
||||
{
|
||||
// spell case or GM
|
||||
if (guid == GetPlayer().GetGUID())
|
||||
{
|
||||
if (!GetPlayer().IsGameMaster() && !GetPlayer().HasAuraType(AuraType.OpenStable))
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "{0} attempt open stable in cheating way.", guid.ToString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// stable master case
|
||||
else
|
||||
{
|
||||
if (!GetPlayer().GetNPCIfCanInteractWith(guid, NPCFlags.StableMaster))
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "Stablemaster {0} not found or you can't interact with him.", guid.ToString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PetSetAction)]
|
||||
void HandlePetSetAction(PetSetAction packet)
|
||||
{
|
||||
ObjectGuid petguid = packet.PetGUID;
|
||||
Unit pet = Global.ObjAccessor.GetUnit(GetPlayer(), petguid);
|
||||
if (!pet || pet != GetPlayer().GetFirstControlled())
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandlePetSetAction: Unknown {0} or pet owner {1}", petguid.ToString(), GetPlayer().GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
CharmInfo charmInfo = pet.GetCharmInfo();
|
||||
if (charmInfo == null)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "WorldSession.HandlePetSetAction: {0} is considered pet-like but doesn't have a charminfo!", pet.GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
uint position = packet.Index;
|
||||
uint actionData = packet.Action;
|
||||
|
||||
uint spell_id = UnitActionBarEntry.UNIT_ACTION_BUTTON_ACTION(actionData);
|
||||
ActiveStates act_state = (ActiveStates)UnitActionBarEntry.UNIT_ACTION_BUTTON_TYPE(actionData);
|
||||
|
||||
Log.outDebug(LogFilter.Network, "Player {0} has changed pet spell action. Position: {1}, Spell: {2}, State: {3}", GetPlayer().GetName(), position, spell_id, act_state);
|
||||
|
||||
|
||||
//if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add
|
||||
if (!((act_state == ActiveStates.Enabled || act_state == ActiveStates.Disabled || act_state == ActiveStates.Passive) && spell_id != 0 && !pet.HasSpell(spell_id)))
|
||||
{
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id);
|
||||
if (spellInfo != null)
|
||||
{
|
||||
//sign for autocast
|
||||
if (act_state == ActiveStates.Enabled)
|
||||
{
|
||||
if (pet.GetTypeId() == TypeId.Unit && pet.IsPet())
|
||||
((Pet)pet).ToggleAutocast(spellInfo, true);
|
||||
else
|
||||
{
|
||||
foreach (var unit in GetPlayer().m_Controlled)
|
||||
if (unit.GetEntry() == pet.GetEntry())
|
||||
unit.GetCharmInfo().ToggleCreatureAutocast(spellInfo, true);
|
||||
}
|
||||
}
|
||||
//sign for no/turn off autocast
|
||||
else if (act_state == ActiveStates.Disabled)
|
||||
{
|
||||
if (pet.GetTypeId() == TypeId.Unit && pet.IsPet())
|
||||
pet.ToPet().ToggleAutocast(spellInfo, false);
|
||||
else
|
||||
{
|
||||
foreach (var unit in GetPlayer().m_Controlled)
|
||||
if (unit.GetEntry() == pet.GetEntry())
|
||||
unit.GetCharmInfo().ToggleCreatureAutocast(spellInfo, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
charmInfo.SetActionBar((byte)position, spell_id, act_state);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PetRename)]
|
||||
void HandlePetRename(PetRename packet)
|
||||
{
|
||||
ObjectGuid petguid = packet.RenameData.PetGUID;
|
||||
bool isdeclined = packet.RenameData.HasDeclinedNames;
|
||||
string name = packet.RenameData.NewName;
|
||||
|
||||
Pet pet = ObjectAccessor.GetPet(GetPlayer(), petguid);
|
||||
// check it!
|
||||
if (!pet || !pet.IsPet() || pet.ToPet().getPetType() != PetType.Hunter || !pet.HasByteFlag(UnitFields.Bytes2, UnitBytes2Offsets.PetFlags, UnitPetFlags.CanBeRenamed) ||
|
||||
pet.GetOwnerGUID() != GetPlayer().GetGUID() || pet.GetCharmInfo() == null)
|
||||
return;
|
||||
|
||||
PetNameInvalidReason res = ObjectManager.CheckPetName(name);
|
||||
if (res != PetNameInvalidReason.Success)
|
||||
{
|
||||
SendPetNameInvalid(res, name, null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Global.ObjectMgr.IsReservedName(name))
|
||||
{
|
||||
SendPetNameInvalid(PetNameInvalidReason.Reserved, name, null);
|
||||
return;
|
||||
}
|
||||
|
||||
pet.SetName(name);
|
||||
pet.SetGroupUpdateFlag(GroupUpdatePetFlags.Name);
|
||||
pet.RemoveByteFlag(UnitFields.Bytes2, UnitBytes2Offsets.PetFlags, UnitPetFlags.CanBeRenamed);
|
||||
|
||||
PreparedStatement stmt;
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
if (isdeclined)
|
||||
{
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_PET_DECLINEDNAME);
|
||||
stmt.AddValue(0, pet.GetCharmInfo().GetPetNumber());
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_CHAR_PET_DECLINEDNAME);
|
||||
stmt.AddValue(0, pet.GetCharmInfo().GetPetNumber());
|
||||
stmt.AddValue(1, GetPlayer().GetGUID().ToString());
|
||||
|
||||
for (byte i = 0; i < SharedConst.MaxDeclinedNameCases; i++)
|
||||
stmt.AddValue(i + 1, packet.RenameData.DeclinedNames.name[i]);
|
||||
|
||||
trans.Append(stmt);
|
||||
}
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_CHAR_PET_NAME);
|
||||
stmt.AddValue(0, name);
|
||||
stmt.AddValue(1, GetPlayer().GetGUID().ToString());
|
||||
stmt.AddValue(2, pet.GetCharmInfo().GetPetNumber());
|
||||
trans.Append(stmt);
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
pet.SetUInt32Value(UnitFields.PetNameTimestamp, (uint)Time.UnixTime); // cast can't be helped
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PetAbandon)]
|
||||
void HandlePetAbandon(PetAbandon packet)
|
||||
{
|
||||
if (!GetPlayer().IsInWorld)
|
||||
return;
|
||||
|
||||
Creature pet = ObjectAccessor.GetCreatureOrPetOrVehicle(GetPlayer(), packet.Pet);
|
||||
if (pet)
|
||||
{
|
||||
if (pet.IsPet())
|
||||
GetPlayer().RemovePet(pet.ToPet(), PetSaveMode.AsDeleted);
|
||||
else if (pet.GetGUID() == GetPlayer().GetCharmGUID())
|
||||
GetPlayer().StopCastingCharm();
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PetSpellAutocast)]
|
||||
void HandlePetSpellAutocast(PetSpellAutocast packet)
|
||||
{
|
||||
Creature pet = ObjectAccessor.GetCreatureOrPetOrVehicle(GetPlayer(), packet.PetGUID);
|
||||
if (!pet)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "WorldSession.HandlePetSpellAutocast: {0} not found.", packet.PetGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (pet != GetPlayer().GetGuardianPet() && pet != GetPlayer().GetCharm())
|
||||
{
|
||||
Log.outError(LogFilter.Network, "WorldSession.HandlePetSpellAutocast: {0} isn't pet of player {1} ({2}).",
|
||||
packet.PetGUID.ToString(), GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(packet.SpellID);
|
||||
if (spellInfo == null)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "WorldSession.HandlePetSpellAutocast: Unknown spell id {0} used by {1}.", packet.SpellID, packet.PetGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// do not add not learned spells/ passive spells
|
||||
if (!pet.HasSpell(packet.SpellID) || !spellInfo.IsAutocastable())
|
||||
return;
|
||||
|
||||
CharmInfo charmInfo = pet.GetCharmInfo();
|
||||
if (charmInfo == null)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "WorldSession.HandlePetSpellAutocastOpcod: object {0} is considered pet-like but doesn't have a charminfo!", pet.GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (pet.IsPet())
|
||||
pet.ToPet().ToggleAutocast(spellInfo, packet.AutocastEnabled);
|
||||
else
|
||||
charmInfo.ToggleCreatureAutocast(spellInfo, packet.AutocastEnabled);
|
||||
|
||||
charmInfo.SetSpellAutocast(spellInfo, packet.AutocastEnabled);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PetCastSpell)]
|
||||
void HandlePetCastSpell(PetCastSpell petCastSpell)
|
||||
{
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(petCastSpell.Cast.SpellID);
|
||||
if (spellInfo == null)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "WorldSession.HandlePetCastSpell: unknown spell id {0} tried to cast by {1}", petCastSpell.Cast.SpellID, petCastSpell.PetGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
Unit caster = Global.ObjAccessor.GetUnit(GetPlayer(), petCastSpell.PetGUID);
|
||||
if (!caster)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "WorldSession.HandlePetCastSpell: Caster {0} not found.", petCastSpell.PetGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// This opcode is also sent from charmed and possessed units (players and creatures)
|
||||
if (caster != GetPlayer().GetGuardianPet() && caster != GetPlayer().GetCharm())
|
||||
{
|
||||
Log.outError(LogFilter.Network, "WorldSession.HandlePetCastSpell: {0} isn't pet of player {1} ({2}).", petCastSpell.PetGUID.ToString(), GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// do not cast not learned spells
|
||||
if (!caster.HasSpell(spellInfo.Id) || spellInfo.IsPassive())
|
||||
return;
|
||||
|
||||
SpellCastTargets targets = new SpellCastTargets(caster, petCastSpell.Cast);
|
||||
caster.ClearUnitState(UnitState.Follow);
|
||||
|
||||
Spell spell = new Spell(caster, spellInfo, TriggerCastFlags.None);
|
||||
spell.m_fromClient = true;
|
||||
spell.m_misc.Data0 = petCastSpell.Cast.Misc[0];
|
||||
spell.m_misc.Data1 = petCastSpell.Cast.Misc[1];
|
||||
spell.m_targets = targets;
|
||||
|
||||
SpellCastResult result = spell.CheckPetCast(null);
|
||||
|
||||
if (result == SpellCastResult.SpellCastOk)
|
||||
{
|
||||
Creature creature = caster.ToCreature();
|
||||
if (creature)
|
||||
{
|
||||
Pet pet = creature.ToPet();
|
||||
if (pet)
|
||||
{
|
||||
// 10% chance to play special pet attack talk, else growl
|
||||
// actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
|
||||
if (pet.getPetType() == PetType.Summon && (RandomHelper.IRand(0, 100) < 10))
|
||||
pet.SendPetTalk(PetTalk.SpecialSpell);
|
||||
else
|
||||
pet.SendPetAIReaction(petCastSpell.PetGUID);
|
||||
}
|
||||
}
|
||||
|
||||
SpellPrepare spellPrepare = new SpellPrepare();
|
||||
spellPrepare.ClientCastID = petCastSpell.Cast.CastID;
|
||||
spellPrepare.ServerCastID = spell.m_castId;
|
||||
SendPacket(spellPrepare);
|
||||
|
||||
spell.prepare(targets);
|
||||
}
|
||||
else
|
||||
{
|
||||
spell.SendPetCastResult(result);
|
||||
|
||||
if (!caster.GetSpellHistory().HasCooldown(spellInfo.Id))
|
||||
caster.GetSpellHistory().ResetCooldown(spellInfo.Id, true);
|
||||
|
||||
spell.finish(false);
|
||||
spell.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
void SendPetNameInvalid(PetNameInvalidReason error, string name, DeclinedName declinedName)
|
||||
{
|
||||
PetNameInvalid petNameInvalid = new PetNameInvalid();
|
||||
petNameInvalid.Result = error;
|
||||
petNameInvalid.RenameData.NewName = name;
|
||||
for (int i = 0; i < SharedConst.MaxDeclinedNameCases; i++)
|
||||
petNameInvalid.RenameData.DeclinedNames.name[i] = declinedName.name[i];
|
||||
|
||||
SendPacket(petNameInvalid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,535 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.Entities;
|
||||
using Game.Guilds;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.PetitionBuy)]
|
||||
void HandlePetitionBuy(PetitionBuy packet)
|
||||
{
|
||||
// prevent cheating
|
||||
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.Unit, NPCFlags.Petitioner);
|
||||
if (!creature)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandlePetitionBuyOpcode - {0} not found or you can't interact with him.", packet.Unit.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
uint charterItemID = GuildConst.CharterItemId;
|
||||
int cost = WorldConfig.GetIntValue(WorldCfg.CharterCostGuild);
|
||||
|
||||
// do not let if already in guild.
|
||||
if (GetPlayer().GetGuildId() != 0)
|
||||
return;
|
||||
|
||||
if (Global.GuildMgr.GetGuildByName(packet.Title))
|
||||
{
|
||||
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.NameExists_S, packet.Title);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Global.ObjectMgr.IsReservedName(packet.Title) || !ObjectManager.IsValidCharterName(packet.Title))
|
||||
{
|
||||
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.NameInvalid, packet.Title);
|
||||
return;
|
||||
}
|
||||
|
||||
ItemTemplate pProto = Global.ObjectMgr.GetItemTemplate(charterItemID);
|
||||
if (pProto == null)
|
||||
{
|
||||
GetPlayer().SendBuyError(BuyResult.CantFindItem, null, charterItemID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetPlayer().HasEnoughMoney(cost))
|
||||
{ //player hasn't got enough money
|
||||
GetPlayer().SendBuyError(BuyResult.NotEnoughtMoney, creature, charterItemID);
|
||||
return;
|
||||
}
|
||||
|
||||
List<ItemPosCount> dest = new List<ItemPosCount>();
|
||||
InventoryResult msg = GetPlayer().CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, charterItemID, pProto.GetBuyCount());
|
||||
if (msg != InventoryResult.Ok)
|
||||
{
|
||||
GetPlayer().SendEquipError(msg, null, null, charterItemID);
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().ModifyMoney(-cost);
|
||||
Item charter = GetPlayer().StoreNewItem(dest, charterItemID, true);
|
||||
if (!charter)
|
||||
return;
|
||||
|
||||
charter.SetUInt32Value(ItemFields.Enchantment, (uint)charter.GetGUID().GetCounter());
|
||||
// ITEM_FIELD_ENCHANTMENT_1_1 is guild/arenateam id
|
||||
// ITEM_FIELD_ENCHANTMENT_1_1+1 is current signatures count (showed on item)
|
||||
charter.SetState(ItemUpdateState.Changed, GetPlayer());
|
||||
GetPlayer().SendNewItem(charter, 1, true, false);
|
||||
|
||||
// a petition is invalid, if both the owner and the type matches
|
||||
// we checked above, if this player is in an arenateam, so this must be
|
||||
// datacorruption
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_BY_OWNER);
|
||||
stmt.AddValue(0, GetPlayer().GetGUID().GetCounter());
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
StringBuilder ssInvalidPetitionGUIDs = new StringBuilder();
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
ssInvalidPetitionGUIDs.AppendFormat("'{0}', ", result.Read<uint>(0));
|
||||
} while (result.NextRow());
|
||||
}
|
||||
|
||||
// delete petitions with the same guid as this one
|
||||
ssInvalidPetitionGUIDs.AppendFormat("'{0}'", charter.GetGUID().GetCounter());
|
||||
|
||||
Log.outDebug(LogFilter.Network, "Invalid petition GUIDs: {0}", ssInvalidPetitionGUIDs.ToString());
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
trans.Append("DELETE FROM petition WHERE petitionguid IN ({0})", ssInvalidPetitionGUIDs.ToString());
|
||||
trans.Append("DELETE FROM petition_sign WHERE petitionguid IN ({0})", ssInvalidPetitionGUIDs.ToString());
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_PETITION);
|
||||
stmt.AddValue(0, GetPlayer().GetGUID().GetCounter());
|
||||
stmt.AddValue(1, charter.GetGUID().GetCounter());
|
||||
stmt.AddValue(2, packet.Title);
|
||||
trans.Append(stmt);
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PetitionShowSignatures)]
|
||||
void HandlePetitionShowSignatures(PetitionShowSignatures packet)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "Received opcode CMSG_PETITION_SHOW_SIGNATURES");
|
||||
|
||||
byte signs = 0;
|
||||
|
||||
// if has guild => error, return;
|
||||
if (GetPlayer().GetGuildId() != 0)
|
||||
return;
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_SIGNATURE);
|
||||
stmt.AddValue(0, packet.Item.GetCounter());
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
// result == NULL also correct in case no sign yet
|
||||
if (!result.IsEmpty())
|
||||
signs = (byte)result.GetRowCount();
|
||||
|
||||
ServerPetitionShowSignatures signaturesPacket = new ServerPetitionShowSignatures();
|
||||
signaturesPacket.Item = packet.Item;
|
||||
signaturesPacket.Owner = GetPlayer().GetGUID();
|
||||
signaturesPacket.OwnerAccountID = ObjectGuid.Create(HighGuid.WowAccount, ObjectManager.GetPlayerAccountIdByGUID(GetPlayer().GetGUID()));
|
||||
signaturesPacket.PetitionID = (int)packet.Item.GetCounter(); // @todo verify that...
|
||||
|
||||
for (byte i = 1; i <= signs; ++i)
|
||||
{
|
||||
ObjectGuid signerGUID = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
|
||||
|
||||
ServerPetitionShowSignatures.PetitionSignature signature = new ServerPetitionShowSignatures.PetitionSignature();
|
||||
signature.Signer = signerGUID;
|
||||
signature.Choice = 0;
|
||||
signaturesPacket.Signatures.Add(signature);
|
||||
|
||||
result.NextRow();
|
||||
}
|
||||
SendPacket(signaturesPacket);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QueryPetition)]
|
||||
void HandleQueryPetition(QueryPetition packet)
|
||||
{
|
||||
SendPetitionQuery(packet.ItemGUID);
|
||||
}
|
||||
|
||||
public void SendPetitionQuery(ObjectGuid petitionGUID)
|
||||
{
|
||||
ObjectGuid ownerGUID = ObjectGuid.Empty;
|
||||
string title = "NO_NAME_FOR_GUID";
|
||||
|
||||
QueryPetitionResponse responsePacket = new QueryPetitionResponse();
|
||||
responsePacket.PetitionID = (uint)petitionGUID.GetCounter(); // PetitionID (in Trinity always same as GUID_LOPART(petition guid))
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION);
|
||||
stmt.AddValue(0, petitionGUID.GetCounter());
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
ownerGUID = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
|
||||
title = result.Read<string>(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "CMSG_PETITION_Select failed for petition ({0})", petitionGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
int reqSignatures = WorldConfig.GetIntValue(WorldCfg.MinPetitionSigns);
|
||||
|
||||
PetitionInfo petitionInfo = new PetitionInfo();
|
||||
petitionInfo.PetitionID = (int)petitionGUID.GetCounter();
|
||||
petitionInfo.Petitioner = ownerGUID;
|
||||
petitionInfo.MinSignatures = reqSignatures;
|
||||
petitionInfo.MaxSignatures = reqSignatures;
|
||||
petitionInfo.Title = title;
|
||||
|
||||
responsePacket.Allow = true;
|
||||
responsePacket.Info = petitionInfo;
|
||||
|
||||
SendPacket(responsePacket);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PetitionRenameGuild)]
|
||||
void HandlePetitionRenameGuild(PetitionRenameGuild packet)
|
||||
{
|
||||
Item item = GetPlayer().GetItemByGuid(packet.PetitionGuid);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
if (Global.GuildMgr.GetGuildByName(packet.NewGuildName))
|
||||
{
|
||||
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.NameExists_S, packet.NewGuildName);
|
||||
return;
|
||||
}
|
||||
if (Global.ObjectMgr.IsReservedName(packet.NewGuildName) || !ObjectManager.IsValidCharterName(packet.NewGuildName))
|
||||
{
|
||||
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.NameInvalid, packet.NewGuildName);
|
||||
return;
|
||||
}
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_PETITION_NAME);
|
||||
stmt.AddValue(0, packet.NewGuildName);
|
||||
stmt.AddValue(1, packet.PetitionGuid.GetCounter());
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
PetitionRenameGuildResponse renameResponse = new PetitionRenameGuildResponse();
|
||||
renameResponse.PetitionGuid = packet.PetitionGuid;
|
||||
renameResponse.NewGuildName = packet.NewGuildName;
|
||||
SendPacket(renameResponse);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SignPetition)]
|
||||
void HandleSignPetition(SignPetition packet)
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_SIGNATURES);
|
||||
stmt.AddValue(0, packet.PetitionGUID.GetCounter());
|
||||
stmt.AddValue(1, packet.PetitionGUID.GetCounter());
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outError(LogFilter.Network, "Petition {0} is not found for player {1} {2}", packet.PetitionGUID.ToString(), GetPlayer().GetGUID().ToString(), GetPlayer().GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectGuid ownerGuid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
|
||||
ulong signs = result.Read<ulong>(1);
|
||||
|
||||
if (ownerGuid == GetPlayer().GetGUID())
|
||||
return;
|
||||
|
||||
// not let enemies sign guild charter
|
||||
if (!WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionGuild) && GetPlayer().GetTeam() != ObjectManager.GetPlayerTeamByGUID(ownerGuid))
|
||||
{
|
||||
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.NotAllied);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (GetPlayer().GetGuildId() != 0)
|
||||
{
|
||||
Guild.SendCommandResult(this, GuildCommandType.InvitePlayer, GuildCommandError.AlreadyInGuild_S, GetPlayer().GetName());
|
||||
return;
|
||||
}
|
||||
if (GetPlayer().GetGuildIdInvited() != 0)
|
||||
{
|
||||
Guild.SendCommandResult(this, GuildCommandType.InvitePlayer, GuildCommandError.AlreadyInvitedToGuild_S, GetPlayer().GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
// Client doesn't allow to sign petition two times by one character, but not check sign by another character from same account
|
||||
// not allow sign another player from already sign player account
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_SIG_BY_ACCOUNT);
|
||||
stmt.AddValue(0, GetAccountId());
|
||||
stmt.AddValue(1, packet.PetitionGUID.GetCounter());
|
||||
result = DB.Characters.Query(stmt);
|
||||
|
||||
PetitionSignResults signResult = new PetitionSignResults();
|
||||
signResult.Player = GetPlayer().GetGUID();
|
||||
signResult.Item = packet.PetitionGUID;
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
signResult.Error = PetitionSigns.AlreadySigned;
|
||||
|
||||
// close at signer side
|
||||
SendPacket(signResult);
|
||||
return;
|
||||
}
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_PETITION_SIGNATURE);
|
||||
stmt.AddValue(0, ownerGuid.GetCounter());
|
||||
stmt.AddValue(1, packet.PetitionGUID.GetCounter());
|
||||
stmt.AddValue(2, GetPlayer().GetGUID().GetCounter());
|
||||
stmt.AddValue(3, GetAccountId());
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
Log.outDebug(LogFilter.Network, "PETITION SIGN: {0} by player: {1} ({2} Account: {3})", packet.PetitionGUID.ToString(), GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), GetAccountId());
|
||||
|
||||
signResult.Error = PetitionSigns.Ok;
|
||||
|
||||
// close at signer side
|
||||
SendPacket(signResult);
|
||||
|
||||
// update for owner if online
|
||||
Player owner = Global.ObjAccessor.FindPlayer(ownerGuid);
|
||||
if (owner)
|
||||
owner.SendPacket(signResult);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.DeclinePetition)]
|
||||
void HandleDeclinePetition(DeclinePetition packet)
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_OWNER_BY_GUID);
|
||||
stmt.AddValue(0, packet.PetitionGUID.GetCounter());
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
if (result.IsEmpty())
|
||||
return;
|
||||
|
||||
ObjectGuid ownerguid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
|
||||
|
||||
Player owner = Global.ObjAccessor.FindPlayer(ownerguid);
|
||||
if (owner) // petition owner online
|
||||
{
|
||||
// Disabled because packet isn't handled by the client in any way
|
||||
/*
|
||||
WorldPacket data = new WorldPacket(ServerOpcodes.PetitionDecline);
|
||||
data.WritePackedGuid(GetPlayer().GetGUID());
|
||||
owner.SendPacket(data);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.OfferPetition)]
|
||||
void HandleOfferPetition(OfferPetition packet)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindConnectedPlayer(packet.TargetPlayer);
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
if (!WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionGuild) && GetPlayer().GetTeam() != player.GetTeam())
|
||||
{
|
||||
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.NotAllied);
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.GetGuildId() != 0)
|
||||
{
|
||||
Guild.SendCommandResult(this, GuildCommandType.InvitePlayer, GuildCommandError.AlreadyInGuild_S, GetPlayer().GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.GetGuildIdInvited() != 0)
|
||||
{
|
||||
Guild.SendCommandResult(this, GuildCommandType.InvitePlayer, GuildCommandError.AlreadyInvitedToGuild_S, GetPlayer().GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_SIGNATURE);
|
||||
stmt.AddValue(0, packet.ItemGUID.GetCounter());
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
byte signs = 0;
|
||||
// result == NULL also correct charter without signs
|
||||
if (!result.IsEmpty())
|
||||
signs = (byte)result.GetRowCount();
|
||||
|
||||
ServerPetitionShowSignatures signaturesPacket = new ServerPetitionShowSignatures();
|
||||
signaturesPacket.Item = packet.ItemGUID;
|
||||
signaturesPacket.Owner = GetPlayer().GetGUID();
|
||||
signaturesPacket.OwnerAccountID = ObjectGuid.Create(HighGuid.WowAccount, player.GetSession().GetAccountId());
|
||||
signaturesPacket.PetitionID = (int)packet.ItemGUID.GetCounter(); // @todo verify that...
|
||||
|
||||
for (byte i = 1; i <= signs; ++i)
|
||||
{
|
||||
ObjectGuid signerGUID = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
|
||||
|
||||
ServerPetitionShowSignatures.PetitionSignature signature = new ServerPetitionShowSignatures.PetitionSignature();
|
||||
signature.Signer = signerGUID;
|
||||
signature.Choice = 0;
|
||||
signaturesPacket.Signatures.Add(signature);
|
||||
|
||||
result.NextRow();
|
||||
}
|
||||
|
||||
player.SendPacket(signaturesPacket);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.TurnInPetition)]
|
||||
void HandleTurnInPetition(TurnInPetition packet)
|
||||
{
|
||||
// Check if player really has the required petition charter
|
||||
Item item = GetPlayer().GetItemByGuid(packet.Item);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
// Get petition data from db
|
||||
ObjectGuid ownerguid;
|
||||
string name;
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION);
|
||||
stmt.AddValue(0, packet.Item.GetCounter());
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
ownerguid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
|
||||
name = result.Read<string>(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outError(LogFilter.Network, "Player {0} ({1}) tried to turn in petition ({2}) that is not present in the database", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), packet.Item.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// Only the petition owner can turn in the petition
|
||||
if (GetPlayer().GetGUID() != ownerguid)
|
||||
return;
|
||||
|
||||
TurnInPetitionResult resultPacket = new TurnInPetitionResult();
|
||||
|
||||
// Check if player is already in a guild
|
||||
if (GetPlayer().GetGuildId() != 0)
|
||||
{
|
||||
resultPacket.Result = PetitionTurns.AlreadyInGuild;
|
||||
GetPlayer().SendPacket(resultPacket);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if guild name is already taken
|
||||
if (Global.GuildMgr.GetGuildByName(name))
|
||||
{
|
||||
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.NameExists_S, name);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get petition signatures from db
|
||||
byte signatures;
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_SIGNATURE);
|
||||
stmt.AddValue(0, packet.Item.GetCounter());
|
||||
result = DB.Characters.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
signatures = (byte)result.GetRowCount();
|
||||
else
|
||||
signatures = 0;
|
||||
|
||||
uint requiredSignatures = WorldConfig.GetUIntValue(WorldCfg.MinPetitionSigns);
|
||||
|
||||
// Notify player if signatures are missing
|
||||
if (signatures < requiredSignatures)
|
||||
{
|
||||
resultPacket.Result = PetitionTurns.NeedMoreSignatures;
|
||||
SendPacket(resultPacket);
|
||||
return;
|
||||
}
|
||||
// Proceed with guild/arena team creation
|
||||
|
||||
// Delete charter item
|
||||
GetPlayer().DestroyItem(item.GetBagSlot(), item.GetSlot(), true);
|
||||
|
||||
// Create guild
|
||||
Guild guild = new Guild();
|
||||
if (!guild.Create(GetPlayer(), name))
|
||||
return;
|
||||
|
||||
// Register guild and add guild master
|
||||
Global.GuildMgr.AddGuild(guild);
|
||||
|
||||
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.Success, name);
|
||||
|
||||
// Add members from signatures
|
||||
for (byte i = 0; i < signatures; ++i)
|
||||
{
|
||||
guild.AddMember(ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0)));
|
||||
result.NextRow();
|
||||
}
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_PETITION_BY_GUID);
|
||||
stmt.AddValue(0, packet.Item.GetCounter());
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_PETITION_SIGNATURE_BY_GUID);
|
||||
stmt.AddValue(0, packet.Item.GetCounter());
|
||||
trans.Append(stmt);
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
// created
|
||||
Log.outDebug(LogFilter.Network, "Player {0} ({1}) turning in petition {2}", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), packet.Item.ToString());
|
||||
|
||||
resultPacket.Result = PetitionTurns.Ok;
|
||||
SendPacket(resultPacket);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PetitionShowList)]
|
||||
void HandlePetitionShowList(PetitionShowList packet)
|
||||
{
|
||||
SendPetitionShowList(packet.PetitionUnit);
|
||||
}
|
||||
|
||||
public void SendPetitionShowList(ObjectGuid guid)
|
||||
{
|
||||
Creature creature = GetPlayer().GetNPCIfCanInteractWith(guid, NPCFlags.Petitioner);
|
||||
if (!creature)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandlePetitionShowListOpcode - {0} not found or you can't interact with him.", guid.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
WorldPacket data = new WorldPacket(ServerOpcodes.PetitionShowList);
|
||||
data.WritePackedGuid(guid); // npc guid
|
||||
|
||||
ServerPetitionShowList packet = new ServerPetitionShowList();
|
||||
packet.Unit = guid;
|
||||
packet.Price = WorldConfig.GetUIntValue(WorldCfg.CharterCostGuild);
|
||||
SendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.GameMath;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Maps;
|
||||
using Game.Misc;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.QueryPlayerName)]
|
||||
void HandleNameQueryRequest(QueryPlayerName queryPlayerName)
|
||||
{
|
||||
SendNameQuery(queryPlayerName.Player);
|
||||
}
|
||||
|
||||
public void SendNameQuery(ObjectGuid guid)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(guid);
|
||||
|
||||
QueryPlayerNameResponse response = new QueryPlayerNameResponse();
|
||||
response.Player = guid;
|
||||
|
||||
if (response.Data.Initialize(guid, player))
|
||||
response.Result = ResponseCodes.Success;
|
||||
else
|
||||
response.Result = ResponseCodes.Failure; // name unknown
|
||||
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QueryTime)]
|
||||
void HandleQueryTime(QueryTime packet)
|
||||
{
|
||||
SendQueryTimeResponse();
|
||||
}
|
||||
|
||||
void SendQueryTimeResponse()
|
||||
{
|
||||
QueryTimeResponse queryTimeResponse = new QueryTimeResponse();
|
||||
queryTimeResponse.CurrentTime = Time.UnixTime;
|
||||
SendPacket(queryTimeResponse);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QueryGameObject, Processing = PacketProcessing.Inplace)]
|
||||
void HandleGameObjectQuery(QueryGameObject packet)
|
||||
{
|
||||
QueryGameObjectResponse response = new QueryGameObjectResponse();
|
||||
response.GameObjectID = packet.GameObjectID;
|
||||
|
||||
GameObjectTemplate gameObjectInfo = Global.ObjectMgr.GetGameObjectTemplate(packet.GameObjectID);
|
||||
if (gameObjectInfo != null)
|
||||
{
|
||||
response.Allow = true;
|
||||
GameObjectStats stats = new GameObjectStats();
|
||||
|
||||
stats.Type = (uint)gameObjectInfo.type;
|
||||
stats.DisplayID = gameObjectInfo.displayId;
|
||||
|
||||
stats.Name[0] = gameObjectInfo.name;
|
||||
stats.IconName = gameObjectInfo.IconName;
|
||||
stats.CastBarCaption = gameObjectInfo.castBarCaption;
|
||||
stats.UnkString = gameObjectInfo.unk1;
|
||||
|
||||
LocaleConstant localeConstant = GetSessionDbLocaleIndex();
|
||||
if (localeConstant != LocaleConstant.enUS)
|
||||
{
|
||||
GameObjectLocale gameObjectLocale = Global.ObjectMgr.GetGameObjectLocale(packet.GameObjectID);
|
||||
if (gameObjectLocale != null)
|
||||
{
|
||||
ObjectManager.GetLocaleString(gameObjectLocale.Name, localeConstant, ref stats.Name[0]);
|
||||
ObjectManager.GetLocaleString(gameObjectLocale.CastBarCaption, localeConstant, ref stats.CastBarCaption);
|
||||
ObjectManager.GetLocaleString(gameObjectLocale.Unk1, localeConstant, ref stats.UnkString);
|
||||
}
|
||||
}
|
||||
|
||||
var items = Global.ObjectMgr.GetGameObjectQuestItemList(packet.GameObjectID);
|
||||
foreach (int item in items)
|
||||
stats.QuestItems.Add(item);
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (int* ptr = gameObjectInfo.Raw.data)
|
||||
{
|
||||
for (int i = 0; i < SharedConst.MaxGOData; i++)
|
||||
stats.Data[i] = ptr[i];
|
||||
}
|
||||
}
|
||||
stats.RequiredLevel = (uint)gameObjectInfo.RequiredLevel;
|
||||
response.Stats = stats;
|
||||
}
|
||||
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QueryCreature, Processing = PacketProcessing.Inplace)]
|
||||
void HandleCreatureQuery(QueryCreature packet)
|
||||
{
|
||||
QueryCreatureResponse response = new QueryCreatureResponse();
|
||||
|
||||
response.CreatureID = packet.CreatureID;
|
||||
|
||||
CreatureTemplate creatureInfo = Global.ObjectMgr.GetCreatureTemplate(packet.CreatureID);
|
||||
if (creatureInfo != null)
|
||||
{
|
||||
response.Allow = true;
|
||||
|
||||
CreatureStats stats = new CreatureStats();
|
||||
|
||||
stats.Leader = creatureInfo.RacialLeader;
|
||||
|
||||
string name = creatureInfo.Name;
|
||||
string nameAlt = creatureInfo.FemaleName;
|
||||
|
||||
stats.Flags[0] = (uint)creatureInfo.TypeFlags;
|
||||
stats.Flags[1] = creatureInfo.TypeFlags2;
|
||||
|
||||
stats.CreatureType = (int)creatureInfo.CreatureType;
|
||||
stats.CreatureFamily = (int)creatureInfo.Family;
|
||||
stats.Classification = (int)creatureInfo.Rank;
|
||||
|
||||
for (uint i = 0; i < SharedConst.MaxCreatureKillCredit; ++i)
|
||||
stats.ProxyCreatureID[i] = creatureInfo.KillCredit[i];
|
||||
|
||||
stats.CreatureDisplayID[0] = creatureInfo.ModelId1;
|
||||
stats.CreatureDisplayID[1] = creatureInfo.ModelId2;
|
||||
stats.CreatureDisplayID[2] = creatureInfo.ModelId3;
|
||||
stats.CreatureDisplayID[3] = creatureInfo.ModelId4;
|
||||
|
||||
stats.HpMulti = creatureInfo.ModHealth;
|
||||
stats.EnergyMulti = creatureInfo.ModMana;
|
||||
|
||||
stats.CreatureMovementInfoID = creatureInfo.MovementId;
|
||||
stats.RequiredExpansion = creatureInfo.RequiredExpansion;
|
||||
stats.HealthScalingExpansion = creatureInfo.HealthScalingExpansion;
|
||||
stats.VignetteID = creatureInfo.VignetteID;
|
||||
|
||||
stats.Title = creatureInfo.SubName;
|
||||
//stats.TitleAlt = ;
|
||||
stats.CursorName = creatureInfo.IconName;
|
||||
|
||||
var items = Global.ObjectMgr.GetCreatureQuestItemList(packet.CreatureID);
|
||||
foreach (uint item in items)
|
||||
stats.QuestItems.Add(item);
|
||||
|
||||
LocaleConstant localeConstant = GetSessionDbLocaleIndex();
|
||||
if (localeConstant != LocaleConstant.enUS)
|
||||
{
|
||||
CreatureLocale creatureLocale = Global.ObjectMgr.GetCreatureLocale(packet.CreatureID);
|
||||
if (creatureLocale != null)
|
||||
{
|
||||
ObjectManager.GetLocaleString(creatureLocale.Name, localeConstant, ref name);
|
||||
ObjectManager.GetLocaleString(creatureLocale.NameAlt, localeConstant, ref nameAlt);
|
||||
ObjectManager.GetLocaleString(creatureLocale.Title, localeConstant, ref stats.Title);
|
||||
ObjectManager.GetLocaleString(creatureLocale.TitleAlt, localeConstant, ref stats.TitleAlt);
|
||||
}
|
||||
}
|
||||
stats.Name[0] = name;
|
||||
stats.NameAlt[0] = nameAlt;
|
||||
|
||||
response.Stats = stats;
|
||||
}
|
||||
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QueryNpcText)]
|
||||
void HandleNpcTextQuery(QueryNPCText packet)
|
||||
{
|
||||
NpcText npcText = Global.ObjectMgr.GetNpcText(packet.TextID);
|
||||
|
||||
QueryNPCTextResponse response = new QueryNPCTextResponse();
|
||||
response.TextID = packet.TextID;
|
||||
|
||||
if (npcText != null)
|
||||
{
|
||||
for (byte i = 0; i < SharedConst.MaxNpcTextOptions; ++i)
|
||||
{
|
||||
response.Probabilities[i] = npcText.Data[i].Probability;
|
||||
response.BroadcastTextID[i] = npcText.Data[i].BroadcastTextID;
|
||||
if (!response.Allow && npcText.Data[i].BroadcastTextID != 0)
|
||||
response.Allow = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!response.Allow)
|
||||
Log.outError(LogFilter.Sql, "HandleNpcTextQuery: no BroadcastTextID found for text {0} in `npc_text table`", packet.TextID);
|
||||
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QueryPageText)]
|
||||
void HandleQueryPageText(QueryPageText packet)
|
||||
{
|
||||
QueryPageTextResponse response = new QueryPageTextResponse();
|
||||
response.PageTextID = packet.PageTextID;
|
||||
|
||||
uint pageID = packet.PageTextID;
|
||||
while (pageID != 0)
|
||||
{
|
||||
PageText pageText = Global.ObjectMgr.GetPageText(pageID);
|
||||
|
||||
if (pageText == null)
|
||||
break;
|
||||
|
||||
QueryPageTextResponse.PageTextInfo page;
|
||||
page.ID = pageID;
|
||||
page.NextPageID = pageText.NextPageID;
|
||||
page.Text = pageText.Text;
|
||||
page.PlayerConditionID = pageText.PlayerConditionID;
|
||||
page.Flags = pageText.Flags;
|
||||
|
||||
LocaleConstant locale = GetSessionDbLocaleIndex();
|
||||
if (locale != LocaleConstant.enUS)
|
||||
{
|
||||
PageTextLocale pageLocale = Global.ObjectMgr.GetPageTextLocale(pageID);
|
||||
if (pageLocale != null)
|
||||
ObjectManager.GetLocaleString(pageLocale.Text, locale, ref page.Text);
|
||||
}
|
||||
|
||||
response.Pages.Add(page);
|
||||
pageID = pageText.NextPageID;
|
||||
}
|
||||
|
||||
response.Allow = !response.Pages.Empty();
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QueryCorpseLocationFromClient)]
|
||||
void HandleQueryCorpseLocation(QueryCorpseLocationFromClient queryCorpseLocation)
|
||||
{
|
||||
CorpseLocation packet = new CorpseLocation();
|
||||
Player player = Global.ObjAccessor.FindConnectedPlayer(queryCorpseLocation.Player);
|
||||
if (!player || !player.HasCorpse() || !_player.IsInSameRaidWith(player))
|
||||
{
|
||||
packet.Valid = false; // corpse not found
|
||||
packet.Player = queryCorpseLocation.Player;
|
||||
SendPacket(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
WorldLocation corpseLocation = player.GetCorpseLocation();
|
||||
uint corpseMapID = corpseLocation.GetMapId();
|
||||
uint mapID = corpseLocation.GetMapId();
|
||||
float x = corpseLocation.GetPositionX();
|
||||
float y = corpseLocation.GetPositionY();
|
||||
float z = corpseLocation.GetPositionZ();
|
||||
|
||||
// if corpse at different map
|
||||
if (mapID != player.GetMapId())
|
||||
{
|
||||
// search entrance map for proper show entrance
|
||||
MapRecord corpseMapEntry = CliDB.MapStorage.LookupByKey(mapID);
|
||||
if (corpseMapEntry != null)
|
||||
{
|
||||
if (corpseMapEntry.IsDungeon() && corpseMapEntry.CorpseMapID >= 0)
|
||||
{
|
||||
// if corpse map have entrance
|
||||
Map entranceMap = Global.MapMgr.CreateBaseMap((uint)corpseMapEntry.CorpseMapID);
|
||||
if (entranceMap != null)
|
||||
{
|
||||
mapID = (uint)corpseMapEntry.CorpseMapID;
|
||||
x = corpseMapEntry.CorpsePos.X;
|
||||
y = corpseMapEntry.CorpsePos.Y;
|
||||
z = entranceMap.GetHeight(player.GetPhases(), x, y, MapConst.MaxHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
packet.Valid = true;
|
||||
packet.Player = queryCorpseLocation.Player;
|
||||
packet.MapID = (int)corpseMapID;
|
||||
packet.ActualMapID = (int)mapID;
|
||||
packet.Position = new Vector3(x, y, z);
|
||||
packet.Transport = ObjectGuid.Empty;
|
||||
SendPacket(packet);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QueryCorpseTransport)]
|
||||
void HandleQueryCorpseTransport(QueryCorpseTransport queryCorpseTransport)
|
||||
{
|
||||
CorpseTransportQuery response = new CorpseTransportQuery();
|
||||
response.Player = queryCorpseTransport.Player;
|
||||
|
||||
Player player = Global.ObjAccessor.FindConnectedPlayer(queryCorpseTransport.Player);
|
||||
if (player)
|
||||
{
|
||||
Corpse corpse = player.GetCorpse();
|
||||
if (_player.IsInSameRaidWith(player) && corpse && !corpse.GetTransGUID().IsEmpty() && corpse.GetTransGUID() == queryCorpseTransport.Transport)
|
||||
{
|
||||
response.Position = new Vector3(corpse.GetTransOffsetX(), corpse.GetTransOffsetY(), corpse.GetTransOffsetZ());
|
||||
response.Facing = corpse.GetTransOffsetO();
|
||||
}
|
||||
}
|
||||
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QueryQuestCompletionNpcs)]
|
||||
void HandleQueryQuestCompletionNPCs(QueryQuestCompletionNPCs queryQuestCompletionNPCs)
|
||||
{
|
||||
QuestCompletionNPCResponse response = new QuestCompletionNPCResponse();
|
||||
|
||||
foreach (var questID in queryQuestCompletionNPCs.QuestCompletionNPCs)
|
||||
{
|
||||
QuestCompletionNPC questCompletionNPC = new QuestCompletionNPC();
|
||||
|
||||
if (Global.ObjectMgr.GetQuestTemplate(questID) == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: Unknown quest {0} in CMSG_QUEST_NPC_QUERY by {1}", questID, GetPlayer().GetGUID());
|
||||
continue;
|
||||
}
|
||||
|
||||
questCompletionNPC.QuestID = questID;
|
||||
|
||||
var creatures = Global.ObjectMgr.GetCreatureQuestInvolvedRelationReverseBounds(questID);
|
||||
foreach (var id in creatures)
|
||||
questCompletionNPC.NPCs.Add(id);
|
||||
|
||||
var gos = Global.ObjectMgr.GetGOQuestInvolvedRelationReverseBounds(questID);
|
||||
foreach (var id in gos)
|
||||
questCompletionNPC.NPCs.Add(id | 0x80000000); // GO mask
|
||||
|
||||
response.QuestCompletionNPCs.Add(questCompletionNPC);
|
||||
}
|
||||
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QuestPoiQuery)]
|
||||
void HandleQuestPOIQuery(QuestPOIQuery packet)
|
||||
{
|
||||
if (packet.MissingQuestCount >= SharedConst.MaxQuestLogSize)
|
||||
return;
|
||||
|
||||
// Read quest ids and add the in a unordered_set so we don't send POIs for the same quest multiple times
|
||||
HashSet<uint> questIds = new HashSet<uint>();
|
||||
for (int i = 0; i < packet.MissingQuestCount; ++i)
|
||||
questIds.Add(packet.MissingQuestPOIs[i]); // QuestID
|
||||
|
||||
QuestPOIQueryResponse response = new QuestPOIQueryResponse();
|
||||
|
||||
foreach (var QuestID in questIds)
|
||||
{
|
||||
bool questOk = false;
|
||||
|
||||
ushort questSlot = GetPlayer().FindQuestSlot(QuestID);
|
||||
|
||||
if (questSlot != SharedConst.MaxQuestLogSize)
|
||||
questOk = GetPlayer().GetQuestSlotQuestId(questSlot) == QuestID;
|
||||
|
||||
if (questOk)
|
||||
{
|
||||
var poiData = Global.ObjectMgr.GetQuestPOIList(QuestID);
|
||||
if (poiData != null)
|
||||
{
|
||||
QuestPOIData questPOIData = new QuestPOIData();
|
||||
|
||||
questPOIData.QuestID = QuestID;
|
||||
|
||||
foreach (var data in poiData)
|
||||
{
|
||||
QuestPOIBlobData questPOIBlobData = new QuestPOIBlobData();
|
||||
|
||||
questPOIBlobData.BlobIndex = data.BlobIndex;
|
||||
questPOIBlobData.ObjectiveIndex = data.ObjectiveIndex;
|
||||
questPOIBlobData.QuestObjectiveID = data.QuestObjectiveID;
|
||||
questPOIBlobData.QuestObjectID = data.QuestObjectID;
|
||||
questPOIBlobData.MapID = data.MapID;
|
||||
questPOIBlobData.WorldMapAreaID = data.WorldMapAreaID;
|
||||
questPOIBlobData.Floor = data.Floor;
|
||||
questPOIBlobData.Priority = data.Priority;
|
||||
questPOIBlobData.Flags = data.Flags;
|
||||
questPOIBlobData.WorldEffectID = data.WorldEffectID;
|
||||
questPOIBlobData.PlayerConditionID = data.PlayerConditionID;
|
||||
questPOIBlobData.UnkWoD1 = data.UnkWoD1;
|
||||
|
||||
foreach (var point in data.points)
|
||||
questPOIBlobData.QuestPOIBlobPointStats.Add(new QuestPOIBlobPoint(point.X, point.Y));
|
||||
|
||||
questPOIData.QuestPOIBlobDataStats.Add(questPOIBlobData);
|
||||
}
|
||||
|
||||
response.QuestPOIDataStats.Add(questPOIData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ItemTextQuery)]
|
||||
void HandleItemTextQuery(ItemTextQuery packet)
|
||||
{
|
||||
QueryItemTextResponse queryItemTextResponse = new QueryItemTextResponse();
|
||||
queryItemTextResponse.Id = packet.Id;
|
||||
|
||||
Item item = GetPlayer().GetItemByGuid(packet.Id);
|
||||
if (item)
|
||||
{
|
||||
queryItemTextResponse.Valid = true;
|
||||
queryItemTextResponse.Text = item.GetText();
|
||||
}
|
||||
|
||||
SendPacket(queryItemTextResponse);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QueryRealmName)]
|
||||
void HandleQueryRealmName(QueryRealmName queryRealmName)
|
||||
{
|
||||
RealmQueryResponse realmQueryResponse = new RealmQueryResponse();
|
||||
realmQueryResponse.VirtualRealmAddress = queryRealmName.VirtualRealmAddress;
|
||||
|
||||
RealmHandle realmHandle = new RealmHandle(queryRealmName.VirtualRealmAddress);
|
||||
if (Global.ObjectMgr.GetRealmName(realmHandle.Realm, ref realmQueryResponse.NameInfo.RealmNameActual, ref realmQueryResponse.NameInfo.RealmNameNormalized))
|
||||
{
|
||||
realmQueryResponse.LookupState = (byte)ResponseCodes.Success;
|
||||
realmQueryResponse.NameInfo.IsInternalRealm = false;
|
||||
realmQueryResponse.NameInfo.IsLocal = queryRealmName.VirtualRealmAddress == Global.WorldMgr.GetRealm().Id.GetAddress();
|
||||
}
|
||||
else
|
||||
realmQueryResponse.LookupState = (byte)ResponseCodes.Failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,647 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.BattleGrounds;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.QuestGiverStatusQuery, Processing = PacketProcessing.Inplace)]
|
||||
void HandleQuestgiverStatusQuery(QuestGiverStatusQuery packet)
|
||||
{
|
||||
QuestGiverStatus questStatus = QuestGiverStatus.None;
|
||||
|
||||
var questgiver = Global.ObjAccessor.GetObjectByTypeMask(GetPlayer(), packet.QuestGiverGUID, TypeMask.Unit | TypeMask.GameObject);
|
||||
if (!questgiver)
|
||||
{
|
||||
Log.outInfo(LogFilter.Network, "Error in CMSG_QUESTGIVER_STATUS_QUERY, called for non-existing questgiver {0}", packet.QuestGiverGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
switch (questgiver.GetTypeId())
|
||||
{
|
||||
case TypeId.Unit:
|
||||
if (!questgiver.ToCreature().IsHostileTo(GetPlayer()))// do not show quest status to enemies
|
||||
questStatus = GetPlayer().GetQuestDialogStatus(questgiver);
|
||||
break;
|
||||
case TypeId.GameObject:
|
||||
questStatus = GetPlayer().GetQuestDialogStatus(questgiver);
|
||||
break;
|
||||
default:
|
||||
Log.outError(LogFilter.Network, "QuestGiver called for unexpected type {0}", questgiver.GetTypeId());
|
||||
break;
|
||||
}
|
||||
|
||||
//inform client about status of quest
|
||||
GetPlayer().PlayerTalkClass.SendQuestGiverStatus(questStatus, packet.QuestGiverGUID);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QuestGiverHello)]
|
||||
void HandleQuestgiverHello(QuestGiverHello packet)
|
||||
{
|
||||
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.QuestGiverGUID, NPCFlags.QuestGiver);
|
||||
if (creature == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleQuestgiverHello - {0} not found or you can't interact with him.", packet.QuestGiverGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
// Stop the npc if moving
|
||||
creature.StopMoving();
|
||||
|
||||
if (Global.ScriptMgr.OnGossipHello(GetPlayer(), creature))
|
||||
return;
|
||||
|
||||
GetPlayer().PrepareGossipMenu(creature, creature.GetCreatureTemplate().GossipMenuId, true);
|
||||
GetPlayer().SendPreparedGossip(creature);
|
||||
|
||||
creature.GetAI().sGossipHello(GetPlayer());
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QuestGiverAcceptQuest)]
|
||||
void HandleQuestgiverAcceptQuest(QuestGiverAcceptQuest packet)
|
||||
{
|
||||
WorldObject obj;
|
||||
if (!packet.QuestGiverGUID.IsPlayer())
|
||||
obj = Global.ObjAccessor.GetObjectByTypeMask(_player, packet.QuestGiverGUID, TypeMask.Unit | TypeMask.GameObject | TypeMask.Item);
|
||||
else
|
||||
obj = Global.ObjAccessor.FindPlayer(packet.QuestGiverGUID);
|
||||
|
||||
var CLOSE_GOSSIP_CLEAR_DIVIDER = new System.Action(() =>
|
||||
{
|
||||
GetPlayer().PlayerTalkClass.SendCloseGossip();
|
||||
GetPlayer().SetDivider(ObjectGuid.Empty);
|
||||
});
|
||||
|
||||
// no or incorrect quest giver
|
||||
if (obj == null)
|
||||
{
|
||||
CLOSE_GOSSIP_CLEAR_DIVIDER();
|
||||
return;
|
||||
}
|
||||
|
||||
Player playerQuestObject = obj.ToPlayer();
|
||||
if (playerQuestObject)
|
||||
{
|
||||
if ((_player.GetDivider().IsEmpty() && _player.GetDivider() != packet.QuestGiverGUID) || !playerQuestObject.CanShareQuest(packet.QuestID))
|
||||
{
|
||||
CLOSE_GOSSIP_CLEAR_DIVIDER();
|
||||
return;
|
||||
}
|
||||
if (!_player.IsInSameRaidWith(playerQuestObject))
|
||||
{
|
||||
CLOSE_GOSSIP_CLEAR_DIVIDER();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!obj.hasQuest(packet.QuestID))
|
||||
{
|
||||
CLOSE_GOSSIP_CLEAR_DIVIDER();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// some kind of WPE protection
|
||||
if (!_player.CanInteractWithQuestGiver(obj))
|
||||
{
|
||||
CLOSE_GOSSIP_CLEAR_DIVIDER();
|
||||
return;
|
||||
}
|
||||
|
||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
|
||||
if (quest != null)
|
||||
{
|
||||
// prevent cheating
|
||||
if (!GetPlayer().CanTakeQuest(quest, true))
|
||||
{
|
||||
CLOSE_GOSSIP_CLEAR_DIVIDER();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_player.GetDivider().IsEmpty())
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(_player.GetDivider());
|
||||
if (player != null)
|
||||
{
|
||||
player.SendPushToPartyResponse(_player, QuestPushReason.Accepted);
|
||||
_player.SetDivider(ObjectGuid.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
if (_player.CanAddQuest(quest, true))
|
||||
{
|
||||
_player.AddQuestAndCheckCompletion(quest, obj);
|
||||
|
||||
if (quest.HasFlag(QuestFlags.PartyAccept))
|
||||
{
|
||||
var group = _player.GetGroup();
|
||||
if (group)
|
||||
{
|
||||
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
|
||||
{
|
||||
Player player = refe.GetSource();
|
||||
|
||||
if (!player || player == _player) // not self
|
||||
continue;
|
||||
|
||||
if (player.CanTakeQuest(quest, true))
|
||||
{
|
||||
player.SetDivider(_player.GetGUID());
|
||||
|
||||
//need confirmation that any gossip window will close
|
||||
player.PlayerTalkClass.SendCloseGossip();
|
||||
|
||||
_player.SendQuestConfirmAccept(quest, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_player.PlayerTalkClass.SendCloseGossip();
|
||||
|
||||
if (quest.SourceSpellID > 0)
|
||||
_player.CastSpell(_player, quest.SourceSpellID, true);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CLOSE_GOSSIP_CLEAR_DIVIDER();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QuestGiverQueryQuest)]
|
||||
void HandleQuestgiverQueryQuest(QuestGiverQueryQuest packet)
|
||||
{
|
||||
// Verify that the guid is valid and is a questgiver or involved in the requested quest
|
||||
var obj = Global.ObjAccessor.GetObjectByTypeMask(GetPlayer(), packet.QuestGiverGUID, (TypeMask.Unit | TypeMask.GameObject | TypeMask.Item));
|
||||
if (!obj || (!obj.hasQuest(packet.QuestID) && !obj.hasInvolvedQuest(packet.QuestID)))
|
||||
{
|
||||
GetPlayer().PlayerTalkClass.SendCloseGossip();
|
||||
return;
|
||||
}
|
||||
|
||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
|
||||
if (quest != null)
|
||||
{
|
||||
if (!GetPlayer().CanTakeQuest(quest, true))
|
||||
return;
|
||||
|
||||
if (quest.IsAutoAccept() && GetPlayer().CanAddQuest(quest, true))
|
||||
GetPlayer().AddQuestAndCheckCompletion(quest, obj);
|
||||
|
||||
if (quest.IsAutoComplete())
|
||||
GetPlayer().PlayerTalkClass.SendQuestGiverRequestItems(quest, obj.GetGUID(), GetPlayer().CanCompleteQuest(quest.Id), true);
|
||||
else
|
||||
GetPlayer().PlayerTalkClass.SendQuestGiverQuestDetails(quest, obj.GetGUID(), true);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QueryQuestInfo)]
|
||||
void HandleQuestQuery(QueryQuestInfo packet)
|
||||
{
|
||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
|
||||
if (quest != null)
|
||||
_player.PlayerTalkClass.SendQuestQueryResponse(quest);
|
||||
else
|
||||
{
|
||||
QueryQuestInfoResponse response = new QueryQuestInfoResponse();
|
||||
response.QuestID = packet.QuestID;
|
||||
SendPacket(response);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QuestGiverChooseReward)]
|
||||
void HandleQuestgiverChooseReward(QuestGiverChooseReward packet)
|
||||
{
|
||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
|
||||
if (quest == null)
|
||||
return;
|
||||
|
||||
// This is Real Item Entry, not slot id as pre 5.x
|
||||
if (packet.ItemChoiceID != 0)
|
||||
{
|
||||
ItemTemplate rewardProto = Global.ObjectMgr.GetItemTemplate(packet.ItemChoiceID);
|
||||
if (rewardProto == null)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player {0} ({1}) tried to get invalid reward item (Item Entry: {2}) for quest {3} (possible packet-hacking detected)", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), packet.ItemChoiceID, packet.QuestID);
|
||||
return;
|
||||
}
|
||||
|
||||
bool itemValid = false;
|
||||
for (uint i = 0; i < quest.GetRewChoiceItemsCount(); ++i)
|
||||
{
|
||||
if (quest.RewardChoiceItemId[i] != 0 && quest.RewardChoiceItemId[i] == packet.ItemChoiceID)
|
||||
{
|
||||
itemValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!itemValid && quest.PackageID != 0)
|
||||
{
|
||||
var questPackageItems = Global.DB2Mgr.GetQuestPackageItems(quest.PackageID);
|
||||
if (questPackageItems != null)
|
||||
{
|
||||
foreach (var questPackageItem in questPackageItems)
|
||||
{
|
||||
if (questPackageItem.ItemID != packet.ItemChoiceID)
|
||||
continue;
|
||||
|
||||
if (_player.CanSelectQuestPackageItem(questPackageItem))
|
||||
{
|
||||
itemValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!itemValid)
|
||||
{
|
||||
var questPackageItems1 = Global.DB2Mgr.GetQuestPackageItemsFallback(quest.PackageID);
|
||||
if (questPackageItems1 != null)
|
||||
{
|
||||
foreach (var questPackageItem in questPackageItems1)
|
||||
{
|
||||
if (questPackageItem.ItemID != packet.ItemChoiceID)
|
||||
continue;
|
||||
|
||||
itemValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!itemValid)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player {0} ({1}) tried to get reward item (Item Entry: {2}) wich is not a reward for quest {3} (possible packet-hacking detected)", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), packet.ItemChoiceID, packet.QuestID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WorldObject obj = GetPlayer();
|
||||
if (!quest.HasFlag(QuestFlags.AutoComplete))
|
||||
{
|
||||
obj = Global.ObjAccessor.GetObjectByTypeMask(GetPlayer(), packet.QuestGiverGUID, TypeMask.Unit | TypeMask.GameObject);
|
||||
if (!obj || !obj.hasInvolvedQuest(packet.QuestID))
|
||||
return;
|
||||
|
||||
// some kind of WPE protection
|
||||
if (!GetPlayer().CanInteractWithQuestGiver(obj))
|
||||
return;
|
||||
}
|
||||
|
||||
if ((!GetPlayer().CanSeeStartQuest(quest) && GetPlayer().GetQuestStatus(packet.QuestID) == QuestStatus.None) ||
|
||||
(GetPlayer().GetQuestStatus(packet.QuestID) != QuestStatus.Complete && !quest.IsAutoComplete()))
|
||||
{
|
||||
Log.outError(LogFilter.Network, "Error in QuestStatus.Complete: player {0} ({1}) tried to complete quest {2}, but is not allowed to do so (possible packet-hacking or high latency)",
|
||||
GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), packet.QuestID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer().CanRewardQuest(quest, packet.ItemChoiceID, true))
|
||||
{
|
||||
GetPlayer().RewardQuest(quest, packet.ItemChoiceID, obj);
|
||||
|
||||
switch (obj.GetTypeId())
|
||||
{
|
||||
case TypeId.Unit:
|
||||
case TypeId.Player:
|
||||
{
|
||||
//For AutoSubmition was added plr case there as it almost same exclute AI script cases.
|
||||
Creature creatureQGiver = obj.ToCreature();
|
||||
if (!creatureQGiver || !Global.ScriptMgr.OnQuestReward(GetPlayer(), creatureQGiver, quest, packet.ItemChoiceID))
|
||||
{
|
||||
// Send next quest
|
||||
Quest nextQuest = GetPlayer().GetNextQuest(packet.QuestGiverGUID, quest);
|
||||
if (nextQuest != null)
|
||||
{
|
||||
// Only send the quest to the player if the conditions are met
|
||||
if (GetPlayer().CanTakeQuest(nextQuest, false))
|
||||
{
|
||||
if (nextQuest.IsAutoAccept() && GetPlayer().CanAddQuest(nextQuest, true))
|
||||
GetPlayer().AddQuestAndCheckCompletion(nextQuest, obj);
|
||||
|
||||
GetPlayer().PlayerTalkClass.SendQuestGiverQuestDetails(nextQuest, packet.QuestGiverGUID, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (creatureQGiver)
|
||||
creatureQGiver.GetAI().sQuestReward(GetPlayer(), quest, packet.ItemChoiceID);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TypeId.GameObject:
|
||||
GameObject questGiver = obj.ToGameObject();
|
||||
if (!Global.ScriptMgr.OnQuestReward(GetPlayer(), questGiver, quest, packet.ItemChoiceID))
|
||||
{
|
||||
// Send next quest
|
||||
Quest nextQuest = GetPlayer().GetNextQuest(packet.QuestGiverGUID, quest);
|
||||
if (nextQuest != null)
|
||||
{
|
||||
// Only send the quest to the player if the conditions are met
|
||||
if (GetPlayer().CanTakeQuest(nextQuest, false))
|
||||
{
|
||||
if (nextQuest.IsAutoAccept() && GetPlayer().CanAddQuest(nextQuest, true))
|
||||
GetPlayer().AddQuestAndCheckCompletion(nextQuest, obj);
|
||||
|
||||
GetPlayer().PlayerTalkClass.SendQuestGiverQuestDetails(nextQuest, packet.QuestGiverGUID, true);
|
||||
}
|
||||
}
|
||||
|
||||
questGiver.GetAI().QuestReward(GetPlayer(), quest, packet.ItemChoiceID);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
GetPlayer().PlayerTalkClass.SendQuestGiverOfferReward(quest, packet.QuestGiverGUID, true);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QuestGiverRequestReward)]
|
||||
void HandleQuestgiverRequestReward(QuestGiverRequestReward packet)
|
||||
{
|
||||
WorldObject obj = Global.ObjAccessor.GetObjectByTypeMask(GetPlayer(), packet.QuestGiverGUID, TypeMask.Unit | TypeMask.GameObject);
|
||||
if (obj == null || !obj.hasInvolvedQuest(packet.QuestID))
|
||||
return;
|
||||
|
||||
// some kind of WPE protection
|
||||
if (!GetPlayer().CanInteractWithQuestGiver(obj))
|
||||
return;
|
||||
|
||||
if (GetPlayer().CanCompleteQuest(packet.QuestID))
|
||||
GetPlayer().CompleteQuest(packet.QuestID);
|
||||
|
||||
if (GetPlayer().GetQuestStatus(packet.QuestID) != QuestStatus.Complete)
|
||||
return;
|
||||
|
||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
|
||||
if (quest != null)
|
||||
GetPlayer().PlayerTalkClass.SendQuestGiverOfferReward(quest, packet.QuestGiverGUID, true);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QuestLogRemoveQuest)]
|
||||
void HandleQuestLogRemoveQuest(QuestLogRemoveQuest packet)
|
||||
{
|
||||
if (packet.Entry < SharedConst.MaxQuestLogSize)
|
||||
{
|
||||
uint questId = GetPlayer().GetQuestSlotQuestId(packet.Entry);
|
||||
if (questId != 0)
|
||||
{
|
||||
if (!GetPlayer().TakeQuestSourceItem(questId, true))
|
||||
return; // can't un-equip some items, reject quest cancel
|
||||
|
||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(questId);
|
||||
if (quest != null)
|
||||
{
|
||||
if (quest.HasSpecialFlag(QuestSpecialFlags.Timed))
|
||||
GetPlayer().RemoveTimedQuest(questId);
|
||||
|
||||
if (quest.HasFlag(QuestFlags.Pvp))
|
||||
{
|
||||
GetPlayer().pvpInfo.IsHostile = GetPlayer().pvpInfo.IsInHostileArea || GetPlayer().HasPvPForcingQuest();
|
||||
GetPlayer().UpdatePvPState();
|
||||
}
|
||||
}
|
||||
|
||||
GetPlayer().TakeQuestSourceItem(questId, true); // remove quest src item from player
|
||||
GetPlayer().AbandonQuest(questId); // remove all quest items player received before abandoning quest. Note, this does not remove normal drop items that happen to be quest requirements.
|
||||
GetPlayer().RemoveActiveQuest(questId);
|
||||
GetPlayer().RemoveCriteriaTimer(CriteriaTimedTypes.Quest, questId);
|
||||
|
||||
Log.outInfo(LogFilter.Network, "Player {0} abandoned quest {1}", GetPlayer().GetGUID().ToString(), questId);
|
||||
|
||||
Global.ScriptMgr.OnQuestStatusChange(_player, questId);
|
||||
}
|
||||
|
||||
GetPlayer().SetQuestSlot(packet.Entry, 0);
|
||||
|
||||
GetPlayer().UpdateCriteria(CriteriaTypes.QuestAbandoned, 1);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QuestConfirmAccept)]
|
||||
void HandleQuestConfirmAccept(QuestConfirmAccept packet)
|
||||
{
|
||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
|
||||
if (quest != null)
|
||||
{
|
||||
if (!quest.HasFlag(QuestFlags.PartyAccept))
|
||||
return;
|
||||
|
||||
Player originalPlayer = Global.ObjAccessor.FindPlayer(GetPlayer().GetDivider());
|
||||
if (originalPlayer == null)
|
||||
return;
|
||||
|
||||
if (!GetPlayer().IsInSameRaidWith(originalPlayer))
|
||||
return;
|
||||
|
||||
if (!!originalPlayer.IsActiveQuest(packet.QuestID))
|
||||
return;
|
||||
|
||||
if (!GetPlayer().CanTakeQuest(quest, true))
|
||||
return;
|
||||
|
||||
if (GetPlayer().CanAddQuest(quest, true))
|
||||
{
|
||||
GetPlayer().AddQuestAndCheckCompletion(quest, null); // NULL, this prevent DB script from duplicate running
|
||||
|
||||
if (quest.SourceSpellID > 0)
|
||||
_player.CastSpell(_player, quest.SourceSpellID, true);
|
||||
}
|
||||
}
|
||||
|
||||
GetPlayer().SetDivider(ObjectGuid.Empty);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QuestGiverCompleteQuest)]
|
||||
void HandleQuestgiverCompleteQuest(QuestGiverCompleteQuest packet)
|
||||
{
|
||||
bool autoCompleteMode = packet.FromScript; // 0 - standart complete quest mode with npc, 1 - auto-complete mode
|
||||
|
||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
|
||||
if (quest == null)
|
||||
return;
|
||||
|
||||
if (autoCompleteMode && !quest.HasFlag(QuestFlags.AutoComplete))
|
||||
return;
|
||||
|
||||
WorldObject obj;
|
||||
if (autoCompleteMode)
|
||||
obj = GetPlayer();
|
||||
else
|
||||
obj = Global.ObjAccessor.GetObjectByTypeMask(GetPlayer(), packet.QuestGiverGUID, TypeMask.Unit | TypeMask.GameObject);
|
||||
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
if (!autoCompleteMode)
|
||||
{
|
||||
if (!obj.hasInvolvedQuest(packet.QuestID))
|
||||
return;
|
||||
|
||||
// some kind of WPE protection
|
||||
if (!GetPlayer().CanInteractWithQuestGiver(obj))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do not allow completing quests on other players.
|
||||
if (packet.QuestGiverGUID != GetPlayer().GetGUID())
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetPlayer().CanSeeStartQuest(quest) && GetPlayer().GetQuestStatus(packet.QuestID) == QuestStatus.None)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "Possible hacking attempt: Player {0} ({1}) tried to complete quest [entry: {2}] without being in possession of the quest!",
|
||||
GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), packet.QuestID);
|
||||
return;
|
||||
}
|
||||
Battleground bg = GetPlayer().GetBattleground();
|
||||
if (bg)
|
||||
bg.HandleQuestComplete(packet.QuestID, GetPlayer());
|
||||
|
||||
if (GetPlayer().GetQuestStatus(packet.QuestID) != QuestStatus.Complete)
|
||||
{
|
||||
if (quest.IsRepeatable())
|
||||
GetPlayer().PlayerTalkClass.SendQuestGiverRequestItems(quest, packet.QuestGiverGUID, GetPlayer().CanCompleteRepeatableQuest(quest), false);
|
||||
else
|
||||
GetPlayer().PlayerTalkClass.SendQuestGiverRequestItems(quest, packet.QuestGiverGUID, GetPlayer().CanRewardQuest(quest, false), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (quest.HasSpecialFlag(QuestSpecialFlags.Deliver)) // some items required
|
||||
GetPlayer().PlayerTalkClass.SendQuestGiverRequestItems(quest, packet.QuestGiverGUID, GetPlayer().CanRewardQuest(quest, false), false);
|
||||
else // no items required
|
||||
GetPlayer().PlayerTalkClass.SendQuestGiverOfferReward(quest, packet.QuestGiverGUID, true);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PushQuestToParty)]
|
||||
void HandlePushQuestToParty(PushQuestToParty packet)
|
||||
{
|
||||
if (!GetPlayer().CanShareQuest(packet.QuestID))
|
||||
return;
|
||||
|
||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
|
||||
if (quest == null)
|
||||
return;
|
||||
|
||||
Player sender = GetPlayer();
|
||||
|
||||
Group group = sender.GetGroup();
|
||||
if (!group)
|
||||
return;
|
||||
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
|
||||
{
|
||||
Player receiver = refe.GetSource();
|
||||
|
||||
if (!receiver || receiver == sender)
|
||||
continue;
|
||||
|
||||
if (!receiver.SatisfyQuestStatus(quest, false))
|
||||
{
|
||||
sender.SendPushToPartyResponse(receiver, QuestPushReason.OnQuest);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (receiver.GetQuestStatus(packet.QuestID) == QuestStatus.Complete)
|
||||
{
|
||||
sender.SendPushToPartyResponse(receiver, QuestPushReason.AlreadyDone);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!receiver.CanTakeQuest(quest, false))
|
||||
{
|
||||
sender.SendPushToPartyResponse(receiver, QuestPushReason.Invalid);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!receiver.SatisfyQuestLog(false))
|
||||
{
|
||||
sender.SendPushToPartyResponse(receiver, QuestPushReason.LogFull);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!receiver.GetDivider().IsEmpty())
|
||||
{
|
||||
sender.SendPushToPartyResponse(receiver, QuestPushReason.Busy);
|
||||
continue;
|
||||
}
|
||||
|
||||
sender.SendPushToPartyResponse(receiver, QuestPushReason.Success);
|
||||
|
||||
if (quest.IsAutoAccept() && receiver.CanAddQuest(quest, true) && receiver.CanTakeQuest(quest, true))
|
||||
receiver.AddQuestAndCheckCompletion(quest, sender);
|
||||
|
||||
if ((quest.IsAutoComplete() && quest.IsRepeatable() && !quest.IsDailyOrWeekly()) || quest.HasFlag(QuestFlags.AutoComplete))
|
||||
receiver.PlayerTalkClass.SendQuestGiverRequestItems(quest, sender.GetGUID(), receiver.CanCompleteRepeatableQuest(quest), true);
|
||||
else
|
||||
{
|
||||
receiver.SetDivider(sender.GetGUID());
|
||||
receiver.PlayerTalkClass.SendQuestGiverQuestDetails(quest, receiver.GetGUID(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QuestPushResult)]
|
||||
void HandleQuestPushResult(QuestPushResult packet)
|
||||
{
|
||||
if (!GetPlayer().GetDivider().IsEmpty())
|
||||
{
|
||||
if (_player.GetDivider() == packet.SenderGUID)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(_player.GetDivider());
|
||||
if (player)
|
||||
player.SendPushToPartyResponse(_player, packet.Result);
|
||||
}
|
||||
|
||||
_player.SetDivider(ObjectGuid.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QuestGiverStatusMultipleQuery)]
|
||||
void HandleQuestgiverStatusMultipleQuery(QuestGiverStatusMultipleQuery packet)
|
||||
{
|
||||
_player.SendQuestGiverStatusMultiple();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestWorldQuestUpdate)]
|
||||
void HandleRequestWorldQuestUpdate(RequestWorldQuestUpdate packet)
|
||||
{
|
||||
WorldQuestUpdate response = new WorldQuestUpdate();
|
||||
|
||||
/// @todo: 7.x Has to be implemented
|
||||
//response.WorldQuestUpdates.push_back(WorldPackets::Quest::WorldQuestUpdateInfo(lastUpdate, questID, timer, variableID, value));
|
||||
|
||||
SendPacket(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.GrantLevel)]
|
||||
void HandleGrantLevel(GrantLevel grantLevel)
|
||||
{
|
||||
Player target = Global.ObjAccessor.GetPlayer(GetPlayer(), grantLevel.Target);
|
||||
|
||||
// check cheating
|
||||
byte levels = GetPlayer().GetGrantableLevels();
|
||||
ReferAFriendError error = 0;
|
||||
if (!target)
|
||||
error = ReferAFriendError.NoTarget;
|
||||
if (levels == 0)
|
||||
error = ReferAFriendError.InsufficientGrantableLevels;
|
||||
else if (GetRecruiterId() != target.GetSession().GetAccountId())
|
||||
error = ReferAFriendError.NotReferredBy;
|
||||
else if (target.GetTeamId() != GetPlayer().GetTeamId())
|
||||
error = ReferAFriendError.DifferentFaction;
|
||||
else if (target.getLevel() >= GetPlayer().getLevel())
|
||||
error = ReferAFriendError.TargetTooHigh;
|
||||
else if (target.getLevel() >= WorldConfig.GetIntValue(WorldCfg.MaxRecruitAFriendBonusPlayerLevel))
|
||||
error = ReferAFriendError.GrantLevelMaxI;
|
||||
else if (target.GetGroup() != GetPlayer().GetGroup())
|
||||
error = ReferAFriendError.NotInGroup;
|
||||
else if (target.getLevel() >= Global.ObjectMgr.GetMaxLevelForExpansion(target.GetSession().GetExpansion()))
|
||||
error = ReferAFriendError.InsufExpanLvl;
|
||||
|
||||
if (error != 0)
|
||||
{
|
||||
ReferAFriendFailure failure = new ReferAFriendFailure();
|
||||
failure.Reason = error;
|
||||
if (error == ReferAFriendError.NotInGroup)
|
||||
failure.Str = target.GetName();
|
||||
|
||||
SendPacket(failure);
|
||||
return;
|
||||
}
|
||||
|
||||
ProposeLevelGrant proposeLevelGrant = new ProposeLevelGrant();
|
||||
proposeLevelGrant.Sender = GetPlayer().GetGUID();
|
||||
target.SendPacket(proposeLevelGrant);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AcceptLevelGrant)]
|
||||
void HandleAcceptGrantLevel(AcceptLevelGrant acceptLevelGrant)
|
||||
{
|
||||
Player other = Global.ObjAccessor.GetPlayer(GetPlayer(), acceptLevelGrant.Granter);
|
||||
if (!(other && other.GetSession() != null))
|
||||
return;
|
||||
|
||||
if (GetAccountId() != other.GetSession().GetRecruiterId())
|
||||
return;
|
||||
|
||||
if (other.GetGrantableLevels() != 0)
|
||||
other.SetGrantableLevels(other.GetGrantableLevels() - 1);
|
||||
else
|
||||
return;
|
||||
|
||||
GetPlayer().GiveLevel(GetPlayer().getLevel() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.QueryScenarioPoi)]
|
||||
void HandleQueryScenarioPOI(QueryScenarioPOI queryScenarioPOI)
|
||||
{
|
||||
ScenarioPOIs response = new ScenarioPOIs();
|
||||
|
||||
// Read criteria tree ids and add the in a unordered_set so we don't send POIs for the same criteria tree multiple times
|
||||
List<int> criteriaTreeIds = new List<int>();
|
||||
for (int i = 0; i < queryScenarioPOI.MissingScenarioPOIs.Count; ++i)
|
||||
criteriaTreeIds.Add(queryScenarioPOI.MissingScenarioPOIs[i]); // CriteriaTreeID
|
||||
|
||||
foreach (int criteriaTreeId in criteriaTreeIds)
|
||||
{
|
||||
var poiVector = Global.ScenarioMgr.GetScenarioPOIs((uint)criteriaTreeId);
|
||||
if (poiVector != null)
|
||||
{
|
||||
ScenarioPOIData scenarioPOIData = new ScenarioPOIData();
|
||||
scenarioPOIData.CriteriaTreeID = criteriaTreeId;
|
||||
scenarioPOIData.ScenarioPOIs = poiVector;
|
||||
response.ScenarioPOIDataStats.Add(scenarioPOIData);
|
||||
}
|
||||
}
|
||||
|
||||
SendPacket(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.SceneTriggerEvent)]
|
||||
void HandleSceneTriggerEvent(SceneTriggerEvent sceneTriggerEvent)
|
||||
{
|
||||
Log.outDebug(LogFilter.Scenes, "HandleSceneTriggerEvent: SceneInstanceID: {0} Event: {1}", sceneTriggerEvent.SceneInstanceID, sceneTriggerEvent._Event);
|
||||
|
||||
GetPlayer().GetSceneMgr().OnSceneTrigger(sceneTriggerEvent.SceneInstanceID, sceneTriggerEvent._Event);
|
||||
}
|
||||
|
||||
void HandleScenePlaybackComplete(ScenePlaybackComplete scenePlaybackComplete)
|
||||
{
|
||||
Log.outDebug(LogFilter.Scenes, "HandleScenePlaybackComplete: SceneInstanceID: {0}", scenePlaybackComplete.SceneInstanceID);
|
||||
|
||||
GetPlayer().GetSceneMgr().OnSceneComplete(scenePlaybackComplete.SceneInstanceID);
|
||||
}
|
||||
|
||||
void HandleScenePlaybackCanceled(ScenePlaybackCanceled scenePlaybackCanceled)
|
||||
{
|
||||
Log.outDebug(LogFilter.Scenes, "HandleScenePlaybackCanceled: SceneInstanceID: {0}", scenePlaybackCanceled.SceneInstanceID);
|
||||
|
||||
GetPlayer().GetSceneMgr().OnSceneCancel(scenePlaybackCanceled.SceneInstanceID);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.LearnTalents)]
|
||||
void HandleLearnTalents(LearnTalents packet)
|
||||
{
|
||||
LearnTalentsFailed learnTalentsFailed = new LearnTalentsFailed();
|
||||
bool anythingLearned = false;
|
||||
foreach (uint talentId in packet.Talents)
|
||||
{
|
||||
TalentLearnResult result = _player.LearnTalent(talentId, ref learnTalentsFailed.SpellID);
|
||||
if (result != 0)
|
||||
{
|
||||
if (learnTalentsFailed.Reason == 0)
|
||||
learnTalentsFailed.Reason = (uint)result;
|
||||
|
||||
learnTalentsFailed.Talents.Add((ushort)talentId);
|
||||
}
|
||||
else
|
||||
anythingLearned = true;
|
||||
}
|
||||
|
||||
if (learnTalentsFailed.Reason != 0)
|
||||
SendPacket(learnTalentsFailed);
|
||||
|
||||
if (anythingLearned)
|
||||
GetPlayer().SendTalentsInfoData();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ConfirmRespecWipe)]
|
||||
void HandleConfirmRespecWipe(ConfirmRespecWipe confirmRespecWipe)
|
||||
{
|
||||
Creature unit = GetPlayer().GetNPCIfCanInteractWith(confirmRespecWipe.RespecMaster, NPCFlags.Trainer);
|
||||
if (unit == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleTalentWipeConfirm - {0} not found or you can't interact with him.", confirmRespecWipe.RespecMaster.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (confirmRespecWipe.RespecType != SpecResetType.Talents)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleConfirmRespecWipe - reset type {0} is not implemented.", confirmRespecWipe.RespecType);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!unit.CanResetTalents(_player))
|
||||
return;
|
||||
|
||||
if (!_player.PlayerTalkClass.GetGossipMenu().HasMenuItemType((uint)GossipOption.Unlearntalents))
|
||||
return;
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
if (!GetPlayer().ResetTalents())
|
||||
{
|
||||
GetPlayer().SendRespecWipeConfirm(ObjectGuid.Empty, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().SendTalentsInfoData();
|
||||
unit.CastSpell(GetPlayer(), 14867, true); //spell: "Untalent Visual Effect"
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.UnlearnSkill)]
|
||||
void HandleUnlearnSkill(UnlearnSkill packet)
|
||||
{
|
||||
SkillRaceClassInfoRecord rcEntry = Global.DB2Mgr.GetSkillRaceClassInfo(packet.SkillLine, GetPlayer().GetRace(), GetPlayer().GetClass());
|
||||
if (rcEntry == null || !rcEntry.Flags.HasAnyFlag(SkillRaceClassInfoFlags.Unlearnable))
|
||||
return;
|
||||
|
||||
GetPlayer().SetSkill(packet.SkillLine, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Guilds;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.Who)]
|
||||
void HandleWho(WhoRequestPkt whoRequest)
|
||||
{
|
||||
WhoRequest request = whoRequest.Request;
|
||||
|
||||
// zones count, client limit = 10 (2.0.10)
|
||||
// can't be received from real client or broken packet
|
||||
if (whoRequest.Areas.Count > 10)
|
||||
return;
|
||||
|
||||
// user entered strings count, client limit=4 (checked on 2.0.10)
|
||||
// can't be received from real client or broken packet
|
||||
if (request.Words.Count > 4)
|
||||
return;
|
||||
|
||||
/// @todo: handle following packet values
|
||||
/// VirtualRealmNames
|
||||
/// ShowEnemies
|
||||
/// ShowArenaPlayers
|
||||
/// ExactName
|
||||
/// ServerInfo
|
||||
|
||||
request.Words.ForEach(p => p = p.ToLower());
|
||||
|
||||
request.Name.ToLower();
|
||||
request.Guild.ToLower();
|
||||
|
||||
// client send in case not set max level value 100 but we support 255 max level,
|
||||
// update it to show GMs with characters after 100 level
|
||||
if (whoRequest.Request.MaxLevel >= 100)
|
||||
whoRequest.Request.MaxLevel = 255;
|
||||
|
||||
var team = GetPlayer().GetTeam();
|
||||
|
||||
uint gmLevelInWhoList = WorldConfig.GetUIntValue(WorldCfg.GmLevelInWhoList);
|
||||
|
||||
WhoResponsePkt response = new WhoResponsePkt();
|
||||
foreach (var target in Global.ObjAccessor.GetPlayers())
|
||||
{
|
||||
// player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST
|
||||
if (target.GetTeam() != team && !HasPermission(RBACPermissions.TwoSideWhoList))
|
||||
continue;
|
||||
|
||||
// player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST
|
||||
if (target.GetSession().GetSecurity() > (AccountTypes)gmLevelInWhoList && !HasPermission(RBACPermissions.WhoSeeAllSecLevels))
|
||||
continue;
|
||||
|
||||
// do not process players which are not in world
|
||||
if (!target.IsInWorld)
|
||||
continue;
|
||||
|
||||
// check if target is globally visible for player
|
||||
if (!target.IsVisibleGloballyFor(GetPlayer()))
|
||||
continue;
|
||||
|
||||
// check if target's level is in level range
|
||||
uint lvl = target.getLevel();
|
||||
if (lvl < request.MinLevel || lvl > request.MaxLevel)
|
||||
continue;
|
||||
|
||||
// check if class matches classmask
|
||||
int class_ = (byte)target.GetClass();
|
||||
if (!Convert.ToBoolean(request.ClassFilter & (1 << class_)))
|
||||
continue;
|
||||
|
||||
// check if race matches racemask
|
||||
int race = (int)target.GetRace();
|
||||
if (!Convert.ToBoolean(request.RaceFilter & (1 << race)))
|
||||
continue;
|
||||
|
||||
if (!whoRequest.Areas.Empty())
|
||||
{
|
||||
if (whoRequest.Areas.Contains((int)target.GetZoneId()))
|
||||
continue;
|
||||
}
|
||||
|
||||
string wTargetName = target.GetName().ToLower();
|
||||
if (!string.IsNullOrEmpty(request.Name) && !wTargetName.Equals(request.Name))
|
||||
continue;
|
||||
|
||||
string wTargetGuildName = "";
|
||||
Guild targetGuild = target.GetGuild();
|
||||
if (targetGuild)
|
||||
wTargetGuildName = targetGuild.GetName().ToLower();
|
||||
|
||||
if (!string.IsNullOrEmpty(request.Guild) && !wTargetGuildName.Equals(request.Guild))
|
||||
continue;
|
||||
|
||||
if (!request.Words.Empty())
|
||||
{
|
||||
string aname = "";
|
||||
AreaTableRecord areaEntry = CliDB.AreaTableStorage.LookupByKey(target.GetZoneId());
|
||||
if (areaEntry != null)
|
||||
aname = areaEntry.AreaName[GetSessionDbcLocale()].ToLower();
|
||||
|
||||
bool show = false;
|
||||
for (int i = 0; i < request.Words.Count; ++i)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(request.Words[i]))
|
||||
{
|
||||
if (wTargetName.Equals(request.Words[i]) ||
|
||||
wTargetGuildName.Equals(request.Words[i]) ||
|
||||
aname.Equals(request.Words[i]))
|
||||
{
|
||||
show = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!show)
|
||||
continue;
|
||||
}
|
||||
|
||||
WhoEntry whoEntry = new WhoEntry();
|
||||
if (!whoEntry.PlayerData.Initialize(target.GetGUID(), target))
|
||||
continue;
|
||||
|
||||
if (targetGuild)
|
||||
{
|
||||
whoEntry.GuildGUID = targetGuild.GetGUID();
|
||||
whoEntry.GuildVirtualRealmAddress = Global.WorldMgr.GetVirtualRealmAddress();
|
||||
whoEntry.GuildName = targetGuild.GetName();
|
||||
}
|
||||
|
||||
whoEntry.AreaID = (int)target.GetZoneId();
|
||||
whoEntry.IsGM = target.IsGameMaster();
|
||||
|
||||
response.Response.Add(whoEntry);
|
||||
|
||||
// 50 is maximum player count sent to client
|
||||
if (response.Response.Count >= 50)
|
||||
break;
|
||||
}
|
||||
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.WhoIs)]
|
||||
void HandleWhoIs(WhoIsRequest packet)
|
||||
{
|
||||
if (!HasPermission(RBACPermissions.OpcodeWhois))
|
||||
{
|
||||
SendNotification(CypherStrings.YouNotHavePermission);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ObjectManager.NormalizePlayerName(ref packet.CharName))
|
||||
{
|
||||
SendNotification(CypherStrings.NeedCharacterName);
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = Global.ObjAccessor.FindPlayerByName(packet.CharName);
|
||||
if (!player)
|
||||
{
|
||||
SendNotification(CypherStrings.PlayerNotExistOrOffline, packet.CharName);
|
||||
return;
|
||||
}
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_WHOIS);
|
||||
stmt.AddValue(0, player.GetSession().GetAccountId());
|
||||
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
SendNotification(CypherStrings.AccountForPlayerNotFound, packet.CharName);
|
||||
return;
|
||||
}
|
||||
|
||||
string acc = result.Read<string>(0);
|
||||
if (string.IsNullOrEmpty(acc))
|
||||
acc = "Unknown";
|
||||
|
||||
string email = result.Read<string>(1);
|
||||
if (string.IsNullOrEmpty(email))
|
||||
email = "Unknown";
|
||||
|
||||
string lastip = result.Read<string>(2);
|
||||
if (string.IsNullOrEmpty(lastip))
|
||||
lastip = "Unknown";
|
||||
|
||||
WhoIsResponse response = new WhoIsResponse();
|
||||
response.AccountName = packet.CharName + "'s " + "account is " + acc + ", e-mail: " + email + ", last ip: " + lastip;
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SendContactList)]
|
||||
void HandleContactList(SendContactList packet)
|
||||
{
|
||||
GetPlayer().GetSocial().SendSocialList(GetPlayer(), packet.Flags);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AddFriend)]
|
||||
void HandleAddFriend(AddFriend packet)
|
||||
{
|
||||
if (!ObjectManager.NormalizePlayerName(ref packet.Name))
|
||||
return;
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUID_RACE_ACC_BY_NAME);
|
||||
stmt.AddValue(0, packet.Name);
|
||||
|
||||
_queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleAddFriendCallBack, packet.Notes));
|
||||
}
|
||||
|
||||
void HandleAddFriendCallBack(string friendNote, SQLResult result)
|
||||
{
|
||||
if (!GetPlayer())
|
||||
return;
|
||||
|
||||
ObjectGuid friendGuid = ObjectGuid.Empty;
|
||||
FriendsResult friendResult = FriendsResult.NotFound;
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
ulong lowGuid = result.Read<ulong>(0);
|
||||
if (lowGuid != 0)
|
||||
{
|
||||
friendGuid = ObjectGuid.Create(HighGuid.Player, lowGuid);
|
||||
Team team = Player.TeamForRace((Race)result.Read<byte>(1));
|
||||
uint friendAccountId = result.Read<uint>(2);
|
||||
|
||||
if (HasPermission(RBACPermissions.AllowGmFriend) || Global.AccountMgr.IsPlayerAccount(Global.AccountMgr.GetSecurity(friendAccountId, (int)Global.WorldMgr.GetRealm().Id.Realm)))
|
||||
{
|
||||
if (friendGuid == GetPlayer().GetGUID())
|
||||
friendResult = FriendsResult.Self;
|
||||
else if (GetPlayer().GetTeam() != team && !HasPermission(RBACPermissions.TwoSideAddFriend))
|
||||
friendResult = FriendsResult.Enemy;
|
||||
else if (GetPlayer().GetSocial().HasFriend(friendGuid))
|
||||
friendResult = FriendsResult.Already;
|
||||
else
|
||||
{
|
||||
Player playerFriend = Global.ObjAccessor.FindPlayer(friendGuid);
|
||||
if (playerFriend && playerFriend.IsVisibleGloballyFor(GetPlayer()))
|
||||
friendResult = FriendsResult.AddedOnline;
|
||||
else
|
||||
friendResult = FriendsResult.AddedOffline;
|
||||
|
||||
if (GetPlayer().GetSocial().AddToSocialList(friendGuid, SocialFlag.Friend))
|
||||
GetPlayer().GetSocial().SetFriendNote(friendGuid, friendNote);
|
||||
else
|
||||
friendResult = FriendsResult.ListFull;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Global.SocialMgr.SendFriendStatus(GetPlayer(), friendResult, friendGuid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.DelFriend)]
|
||||
void HandleDelFriend(DelFriend packet)
|
||||
{
|
||||
/// @todo: handle VirtualRealmAddress
|
||||
GetPlayer().GetSocial().RemoveFromSocialList(packet.Player.Guid, SocialFlag.Friend);
|
||||
|
||||
Global.SocialMgr.SendFriendStatus(GetPlayer(), FriendsResult.Removed, packet.Player.Guid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AddIgnore)]
|
||||
void HandleAddIgnore(AddIgnore packet)
|
||||
{
|
||||
if (!ObjectManager.NormalizePlayerName(ref packet.Name))
|
||||
return;
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUID_BY_NAME);
|
||||
stmt.AddValue(0, packet.Name);
|
||||
|
||||
_queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleAddIgnoreCallBack));
|
||||
}
|
||||
|
||||
void HandleAddIgnoreCallBack(SQLResult result)
|
||||
{
|
||||
if (!GetPlayer())
|
||||
return;
|
||||
|
||||
ObjectGuid IgnoreGuid = ObjectGuid.Empty;
|
||||
FriendsResult ignoreResult = FriendsResult.IgnoreNotFound;
|
||||
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
ulong lowGuid = result.Read<ulong>(0);
|
||||
if (lowGuid != 0)
|
||||
{
|
||||
IgnoreGuid = ObjectGuid.Create(HighGuid.Player, lowGuid);
|
||||
|
||||
if (IgnoreGuid == GetPlayer().GetGUID()) //not add yourself
|
||||
ignoreResult = FriendsResult.IgnoreSelf;
|
||||
else if (GetPlayer().GetSocial().HasIgnore(IgnoreGuid))
|
||||
ignoreResult = FriendsResult.IgnoreAlready;
|
||||
else
|
||||
{
|
||||
ignoreResult = FriendsResult.IgnoreAdded;
|
||||
|
||||
// ignore list full
|
||||
if (!GetPlayer().GetSocial().AddToSocialList(IgnoreGuid, SocialFlag.Ignored))
|
||||
ignoreResult = FriendsResult.IgnoreFull;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Global.SocialMgr.SendFriendStatus(GetPlayer(), ignoreResult, IgnoreGuid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.DelIgnore)]
|
||||
void HandleDelIgnore(DelIgnore packet)
|
||||
{
|
||||
/// @todo: handle VirtualRealmAddress
|
||||
Log.outDebug(LogFilter.Network, "WorldSession.HandleDelIgnoreOpcode: {0}", packet.Player.Guid.ToString());
|
||||
|
||||
GetPlayer().GetSocial().RemoveFromSocialList(packet.Player.Guid, SocialFlag.Ignored);
|
||||
|
||||
Global.SocialMgr.SendFriendStatus(GetPlayer(), FriendsResult.IgnoreRemoved, packet.Player.Guid);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetContactNotes)]
|
||||
void HandleSetContactNotes(SetContactNotes packet)
|
||||
{
|
||||
/// @todo: handle VirtualRealmAddress
|
||||
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetContactNotesOpcode: Contact: {0}, Notes: {1}", packet.Player.Guid.ToString(), packet.Notes);
|
||||
GetPlayer().GetSocial().SetFriendNote(packet.Player.Guid, packet.Notes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,616 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Guilds;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using Game.Spells;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.UseItem)]
|
||||
void HandleUseItem(UseItem packet)
|
||||
{
|
||||
Player user = GetPlayer();
|
||||
|
||||
// ignore for remote control state
|
||||
if (user.m_unitMovedByMe != user)
|
||||
return;
|
||||
|
||||
Item item = user.GetUseableItemByPos(packet.PackSlot, packet.Slot);
|
||||
if (item == null)
|
||||
{
|
||||
user.SendEquipError(InventoryResult.ItemNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.GetGUID() != packet.CastItem)
|
||||
{
|
||||
user.SendEquipError(InventoryResult.ItemNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
ItemTemplate proto = item.GetTemplate();
|
||||
if (proto == null)
|
||||
{
|
||||
user.SendEquipError(InventoryResult.ItemNotFound, item);
|
||||
return;
|
||||
}
|
||||
|
||||
// some item classes can be used only in equipped state
|
||||
if (proto.GetInventoryType() != InventoryType.NonEquip && !item.IsEquipped())
|
||||
{
|
||||
user.SendEquipError(InventoryResult.ItemNotFound, item);
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryResult msg = user.CanUseItem(item);
|
||||
if (msg != InventoryResult.Ok)
|
||||
{
|
||||
user.SendEquipError(msg, item);
|
||||
return;
|
||||
}
|
||||
|
||||
// only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB)
|
||||
if (proto.GetClass() == ItemClass.Consumable && !proto.GetFlags().HasAnyFlag(ItemFlags.IgnoreDefaultArenaRestrictions) && user.InArena())
|
||||
{
|
||||
user.SendEquipError(InventoryResult.NotDuringArenaMatch, item);
|
||||
return;
|
||||
}
|
||||
|
||||
// don't allow items banned in arena
|
||||
if (proto.GetFlags().HasAnyFlag(ItemFlags.NotUseableInArena) && user.InArena())
|
||||
{
|
||||
user.SendEquipError(InventoryResult.NotDuringArenaMatch, item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.IsInCombat())
|
||||
{
|
||||
for (int i = 0; i < proto.Effects.Count; ++i)
|
||||
{
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(proto.Effects[i].SpellID);
|
||||
if (spellInfo != null)
|
||||
{
|
||||
if (!spellInfo.CanBeUsedInCombat())
|
||||
{
|
||||
user.SendEquipError(InventoryResult.NotInCombat, item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory)
|
||||
if (item.GetBonding() == ItemBondingType.OnUse || item.GetBonding() == ItemBondingType.OnAcquire || item.GetBonding() == ItemBondingType.Quest)
|
||||
{
|
||||
if (!item.IsSoulBound())
|
||||
{
|
||||
item.SetState(ItemUpdateState.Changed, user);
|
||||
item.SetBinding(true);
|
||||
GetCollectionMgr().AddItemAppearance(item);
|
||||
}
|
||||
}
|
||||
|
||||
SpellCastTargets targets = new SpellCastTargets(user, packet.Cast);
|
||||
|
||||
// Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state.
|
||||
if (!Global.ScriptMgr.OnItemUse(user, item, targets, packet.Cast.CastID))
|
||||
{
|
||||
// no script or script not process request by self
|
||||
user.CastItemUseSpell(item, targets, packet.Cast.CastID, packet.Cast.Misc);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.OpenItem)]
|
||||
void HandleOpenItem(OpenItem packet)
|
||||
{
|
||||
Player player = GetPlayer();
|
||||
|
||||
// ignore for remote control state
|
||||
if (player.m_unitMovedByMe != player)
|
||||
return;
|
||||
|
||||
Item item = player.GetItemByPos(packet.Slot, packet.PackSlot);
|
||||
if (!item)
|
||||
{
|
||||
player.SendEquipError(InventoryResult.ItemNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
ItemTemplate proto = item.GetTemplate();
|
||||
if (proto == null)
|
||||
{
|
||||
player.SendEquipError(InventoryResult.ItemNotFound, item);
|
||||
return;
|
||||
}
|
||||
|
||||
// Verify that the bag is an actual bag or wrapped item that can be used "normally"
|
||||
if (!proto.GetFlags().HasAnyFlag(ItemFlags.HasLoot) && !item.HasFlag(ItemFields.Flags, ItemFieldFlags.Wrapped))
|
||||
{
|
||||
player.SendEquipError(InventoryResult.ClientLockedOut, item);
|
||||
Log.outError(LogFilter.Network, "Possible hacking attempt: Player {0} [guid: {1}] tried to open item [guid: {2}, entry: {3}] which is not openable!",
|
||||
player.GetName(), player.GetGUID().ToString(), item.GetGUID().ToString(), proto.GetId());
|
||||
return;
|
||||
}
|
||||
|
||||
// locked item
|
||||
uint lockId = proto.GetLockID();
|
||||
if (lockId != 0)
|
||||
{
|
||||
LockRecord lockInfo = CliDB.LockStorage.LookupByKey(lockId);
|
||||
if (lockInfo == null)
|
||||
{
|
||||
player.SendEquipError(InventoryResult.ItemLocked, item);
|
||||
Log.outError(LogFilter.Network, "WORLD:OpenItem: item [guid = {0}] has an unknown lockId: {1}!", item.GetGUID().ToString(), lockId);
|
||||
return;
|
||||
}
|
||||
|
||||
// was not unlocked yet
|
||||
if (item.IsLocked())
|
||||
{
|
||||
player.SendEquipError(InventoryResult.ItemLocked, item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.HasFlag(ItemFields.Flags, ItemFieldFlags.Wrapped))// wrapped?
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_GIFT_BY_ITEM);
|
||||
stmt.AddValue(0, item.GetGUID().GetCounter());
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
uint entry = result.Read<uint>(0);
|
||||
uint flags = result.Read<uint>(1);
|
||||
|
||||
item.SetUInt64Value(ItemFields.GiftCreator, 0);
|
||||
item.SetEntry(entry);
|
||||
item.SetUInt32Value(ItemFields.Flags, flags);
|
||||
item.SetState(ItemUpdateState.Changed, player);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outError(LogFilter.Network, "Wrapped item {0} don't have record in character_gifts table and will deleted", item.GetGUID().ToString());
|
||||
player.DestroyItem(item.GetBagSlot(), item.GetSlot(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_GIFT);
|
||||
stmt.AddValue(0, item.GetGUID().GetCounter());
|
||||
DB.Characters.Execute(stmt);
|
||||
}
|
||||
else
|
||||
player.SendLoot(item.GetGUID(), LootType.Corpse);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GameObjUse)]
|
||||
void HandleGameObjectUse(GameObjUse packet)
|
||||
{
|
||||
GameObject obj = GetPlayer().GetGameObjectIfCanInteractWith(packet.Guid);
|
||||
if (obj)
|
||||
{
|
||||
// ignore for remote control state
|
||||
if (GetPlayer().m_unitMovedByMe != GetPlayer())
|
||||
if (!(GetPlayer().IsOnVehicle(GetPlayer().m_unitMovedByMe) || GetPlayer().IsMounted()) && !obj.GetGoInfo().IsUsableMounted())
|
||||
return;
|
||||
|
||||
obj.Use(GetPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GameObjReportUse)]
|
||||
void HandleGameobjectReportUse(GameObjReportUse packet)
|
||||
{
|
||||
// ignore for remote control state
|
||||
if (GetPlayer().m_unitMovedByMe != GetPlayer())
|
||||
return;
|
||||
|
||||
GameObject go = GetPlayer().GetGameObjectIfCanInteractWith(packet.Guid);
|
||||
if (go)
|
||||
{
|
||||
if (go.GetAI().GossipHello(GetPlayer(), false))
|
||||
return;
|
||||
|
||||
GetPlayer().UpdateCriteria(CriteriaTypes.UseGameobject, go.GetEntry());
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CastSpell, Processing = PacketProcessing.ThreadSafe)]
|
||||
void HandleCastSpell(CastSpell cast)
|
||||
{
|
||||
// ignore for remote control state (for player case)
|
||||
Unit mover = GetPlayer().m_unitMovedByMe;
|
||||
if (mover != GetPlayer() && mover.IsTypeId(TypeId.Player))
|
||||
return;
|
||||
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(cast.Cast.SpellID);
|
||||
if (spellInfo == null)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "WORLD: unknown spell id {0}", cast.Cast.SpellID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (spellInfo.IsPassive())
|
||||
return;
|
||||
|
||||
Unit caster = mover;
|
||||
if (caster.IsTypeId(TypeId.Unit) && !caster.ToCreature().HasSpell(spellInfo.Id))
|
||||
{
|
||||
// If the vehicle creature does not have the spell but it allows the passenger to cast own spells
|
||||
// change caster to player and let him cast
|
||||
if (!GetPlayer().IsOnVehicle(caster) || spellInfo.CheckVehicle(GetPlayer()) != SpellCastResult.SpellCastOk)
|
||||
return;
|
||||
|
||||
caster = GetPlayer();
|
||||
}
|
||||
|
||||
// check known spell or raid marker spell (which not requires player to know it)
|
||||
if (caster.IsTypeId(TypeId.Player) && !caster.ToPlayer().HasActiveSpell(spellInfo.Id) && !spellInfo.HasEffect(SpellEffectName.ChangeRaidMarker) && !spellInfo.HasAttribute(SpellAttr8.RaidMarker))
|
||||
return;
|
||||
|
||||
// Check possible spell cast overrides
|
||||
spellInfo = caster.GetCastSpellInfo(spellInfo);
|
||||
|
||||
// Client is resending autoshot cast opcode when other spell is casted during shoot rotation
|
||||
// Skip it to prevent "interrupt" message
|
||||
if (spellInfo.IsAutoRepeatRangedSpell() && GetPlayer().GetCurrentSpell(CurrentSpellTypes.AutoRepeat) != null
|
||||
&& GetPlayer().GetCurrentSpell(CurrentSpellTypes.AutoRepeat).m_spellInfo == spellInfo)
|
||||
return;
|
||||
|
||||
// can't use our own spells when we're in possession of another unit,
|
||||
if (GetPlayer().isPossessing())
|
||||
return;
|
||||
|
||||
// client provided targets
|
||||
SpellCastTargets targets = new SpellCastTargets(caster, cast.Cast);
|
||||
|
||||
// auto-selection buff level base at target level (in spellInfo)
|
||||
if (targets.GetUnitTarget() != null)
|
||||
{
|
||||
SpellInfo actualSpellInfo = spellInfo.GetAuraRankForLevel(targets.GetUnitTarget().GetLevelForTarget(caster));
|
||||
|
||||
// if rank not found then function return NULL but in explicit cast case original spell can be casted and later failed with appropriate error message
|
||||
if (actualSpellInfo != null)
|
||||
spellInfo = actualSpellInfo;
|
||||
}
|
||||
|
||||
if (cast.Cast.MoveUpdate.HasValue)
|
||||
HandleMovementOpcode(ClientOpcodes.MoveStop, cast.Cast.MoveUpdate.Value);
|
||||
|
||||
Spell spell = new Spell(caster, spellInfo, TriggerCastFlags.None, ObjectGuid.Empty, false);
|
||||
|
||||
SpellPrepare spellPrepare = new SpellPrepare();
|
||||
spellPrepare.ClientCastID = cast.Cast.CastID;
|
||||
spellPrepare.ServerCastID = spell.m_castId;
|
||||
SendPacket(spellPrepare);
|
||||
|
||||
spell.m_fromClient = true;
|
||||
spell.m_misc.Data0 = cast.Cast.Misc[0];
|
||||
spell.m_misc.Data1 = cast.Cast.Misc[1];
|
||||
spell.prepare(targets);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CancelCast, Processing = PacketProcessing.ThreadSafe)]
|
||||
void HandleCancelCast(CancelCast packet)
|
||||
{
|
||||
if (GetPlayer().IsNonMeleeSpellCast(false))
|
||||
GetPlayer().InterruptNonMeleeSpells(false, packet.SpellID, false);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CancelAura)]
|
||||
void HandleCancelAura(CancelAura cancelAura)
|
||||
{
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(cancelAura.SpellID);
|
||||
if (spellInfo == null)
|
||||
return;
|
||||
|
||||
// not allow remove spells with attr SPELL_ATTR0_CANT_CANCEL
|
||||
if (spellInfo.HasAttribute(SpellAttr0.CantCancel))
|
||||
return;
|
||||
|
||||
// channeled spell case (it currently casted then)
|
||||
if (spellInfo.IsChanneled())
|
||||
{
|
||||
Spell curSpell = GetPlayer().GetCurrentSpell(CurrentSpellTypes.Channeled);
|
||||
if (curSpell != null)
|
||||
if (curSpell.GetSpellInfo().Id == cancelAura.SpellID)
|
||||
GetPlayer().InterruptSpell(CurrentSpellTypes.Channeled);
|
||||
return;
|
||||
}
|
||||
|
||||
// non channeled case:
|
||||
// don't allow remove non positive spells
|
||||
// don't allow cancelling passive auras (some of them are visible)
|
||||
if (!spellInfo.IsPositive() || spellInfo.IsPassive())
|
||||
return;
|
||||
|
||||
GetPlayer().RemoveOwnedAura(cancelAura.SpellID, cancelAura.CasterGUID, 0, AuraRemoveMode.Cancel);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CancelGrowthAura)]
|
||||
void HandleCancelGrowthAura(CancelGrowthAura cancelGrowthAura)
|
||||
{
|
||||
GetPlayer().RemoveAurasByType(AuraType.ModScale, aurApp =>
|
||||
{
|
||||
SpellInfo spellInfo = aurApp.GetBase().GetSpellInfo();
|
||||
return !spellInfo.HasAttribute(SpellAttr0.CantCancel) && spellInfo.IsPositive() && !spellInfo.IsPassive();
|
||||
});
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CancelMountAura)]
|
||||
void HandleCancelMountAura(CancelMountAura packet)
|
||||
{
|
||||
GetPlayer().RemoveAurasByType(AuraType.Mounted, aurApp =>
|
||||
{
|
||||
SpellInfo spellInfo = aurApp.GetBase().GetSpellInfo();
|
||||
return !spellInfo.HasAttribute(SpellAttr0.CantCancel) && spellInfo.IsPositive() && !spellInfo.IsPassive();
|
||||
});
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.PetCancelAura)]
|
||||
void HandlePetCancelAura(PetCancelAura packet)
|
||||
{
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(packet.SpellID);
|
||||
if (spellInfo == null)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "WORLD: unknown PET spell id {0}", packet.SpellID);
|
||||
return;
|
||||
}
|
||||
|
||||
Creature pet= ObjectAccessor.GetCreatureOrPetOrVehicle(_player, packet.PetGUID);
|
||||
if (pet == null)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandlePetCancelAura: Attempt to cancel an aura for non-existant {0} by player '{1}'", packet.PetGUID.ToString(), GetPlayer().GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (pet != GetPlayer().GetGuardianPet() && pet != GetPlayer().GetCharm())
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandlePetCancelAura: {0} is not a pet of player '{1}'", packet.PetGUID.ToString(), GetPlayer().GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pet.IsAlive())
|
||||
{
|
||||
pet.SendPetActionFeedback(packet.SpellID, ActionFeedback.PetDead);
|
||||
return;
|
||||
}
|
||||
|
||||
pet.RemoveOwnedAura(packet.SpellID, ObjectGuid.Empty, 0, AuraRemoveMode.Cancel);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CancelAutoRepeatSpell)]
|
||||
void HandleCancelAutoRepeatSpell(CancelAutoRepeatSpell packet)
|
||||
{
|
||||
//may be better send SMSG_CANCEL_AUTO_REPEAT?
|
||||
//cancel and prepare for deleting
|
||||
_player.InterruptSpell(CurrentSpellTypes.AutoRepeat);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CancelChannelling)]
|
||||
void HandleCancelChanneling(CancelChannelling cancelChanneling)
|
||||
{
|
||||
// ignore for remote control state (for player case)
|
||||
Unit mover = _player.m_unitMovedByMe;
|
||||
if (mover != _player && mover.IsTypeId(TypeId.Player))
|
||||
return;
|
||||
|
||||
mover.InterruptSpell(CurrentSpellTypes.Channeled);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.TotemDestroyed)]
|
||||
void HandleTotemDestroyed(TotemDestroyed totemDestroyed)
|
||||
{
|
||||
// ignore for remote control state
|
||||
if (GetPlayer().m_unitMovedByMe != GetPlayer())
|
||||
return;
|
||||
|
||||
byte slotId = totemDestroyed.Slot;
|
||||
slotId += (int)SummonSlot.Totem;
|
||||
|
||||
if (slotId >= SharedConst.MaxTotemSlot)
|
||||
return;
|
||||
|
||||
if (GetPlayer().m_SummonSlot[slotId].IsEmpty())
|
||||
return;
|
||||
|
||||
Creature totem = ObjectAccessor.GetCreature(GetPlayer(), _player.m_SummonSlot[slotId]);
|
||||
if (totem != null && totem.IsTotem())// && totem.GetGUID() == packet.TotemGUID) Unknown why blizz doesnt send the guid when you right click it.
|
||||
totem.ToTotem().UnSummon();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SelfRes)]
|
||||
void HandleSelfRes(SelfRes packet)
|
||||
{
|
||||
if (_player.HasAuraType(AuraType.PreventResurrection))
|
||||
return; // silent return, client should display error by itself and not send this opcode
|
||||
|
||||
if (_player.GetUInt32Value(PlayerFields.SelfResSpell) != 0)
|
||||
{
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(_player.GetUInt32Value(PlayerFields.SelfResSpell));
|
||||
if (spellInfo != null)
|
||||
_player.CastSpell(_player, spellInfo, false, null);
|
||||
|
||||
_player.SetUInt32Value(PlayerFields.SelfResSpell, 0);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SpellClick)]
|
||||
void HandleSpellClick(SpellClick packet)
|
||||
{
|
||||
// this will get something not in world. crash
|
||||
Creature unit = ObjectAccessor.GetCreatureOrPetOrVehicle(GetPlayer(), packet.SpellClickUnitGuid);
|
||||
if (unit == null)
|
||||
return;
|
||||
|
||||
/// @todo Unit.SetCharmedBy: 28782 is not in world but 0 is trying to charm it! . crash
|
||||
if (!unit.IsInWorld)
|
||||
return;
|
||||
|
||||
unit.HandleSpellClick(GetPlayer());
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GetMirrorImageData)]
|
||||
void HandleMirrorImageDataRequest(GetMirrorImageData packet)
|
||||
{
|
||||
ObjectGuid guid = packet.UnitGUID;
|
||||
|
||||
// Get unit for which data is needed by client
|
||||
Unit unit = Global.ObjAccessor.GetUnit(GetPlayer(), guid);
|
||||
if (!unit)
|
||||
return;
|
||||
|
||||
if (!unit.HasAuraType(AuraType.CloneCaster))
|
||||
return;
|
||||
|
||||
// Get creator of the unit (SPELL_AURA_CLONE_CASTER does not stack)
|
||||
Unit creator = unit.GetAuraEffectsByType(AuraType.CloneCaster).FirstOrDefault().GetCaster();
|
||||
if (!creator)
|
||||
return;
|
||||
|
||||
Player player = creator.ToPlayer();
|
||||
if (player)
|
||||
{
|
||||
MirrorImageComponentedData data = new MirrorImageComponentedData();
|
||||
data.UnitGUID = guid;
|
||||
data.DisplayID = (int)creator.GetDisplayId();
|
||||
data.RaceID = (byte)creator.GetRace();
|
||||
data.Gender = (byte)creator.GetGender();
|
||||
data.ClassID = (byte)creator.GetClass();
|
||||
|
||||
Guild guild = player.GetGuild();
|
||||
|
||||
data.SkinColor = player.GetByteValue(PlayerFields.Bytes, PlayerFieldOffsets.BytesOffsetSkinId);
|
||||
data.FaceVariation = player.GetByteValue(PlayerFields.Bytes, PlayerFieldOffsets.BytesOffsetFaceId);
|
||||
data.HairVariation = player.GetByteValue(PlayerFields.Bytes, PlayerFieldOffsets.BytesOffsetHairStyleId);
|
||||
data.HairColor = player.GetByteValue(PlayerFields.Bytes, PlayerFieldOffsets.BytesOffsetHairColorId);
|
||||
data.BeardVariation = player.GetByteValue(PlayerFields.Bytes2, PlayerFieldOffsets.Bytes2OffsetFacialStyle);
|
||||
for (int i = 0; i < PlayerConst.CustomDisplaySize; ++i)
|
||||
data.CustomDisplay[i] = player.GetByteValue(PlayerFields.Bytes2, (byte)(PlayerFieldOffsets.Bytes2OffsetCustomDisplayOption + i));
|
||||
data.GuildGUID = (guild ? guild.GetGUID() : ObjectGuid.Empty);
|
||||
|
||||
byte[] itemSlots =
|
||||
{
|
||||
EquipmentSlot.Head,
|
||||
EquipmentSlot.Shoulders,
|
||||
EquipmentSlot.Shirt,
|
||||
EquipmentSlot.Chest,
|
||||
EquipmentSlot.Waist ,
|
||||
EquipmentSlot.Legs ,
|
||||
EquipmentSlot.Feet,
|
||||
EquipmentSlot.Wrist,
|
||||
EquipmentSlot.Hands,
|
||||
EquipmentSlot.Tabard,
|
||||
EquipmentSlot.Cloak
|
||||
};
|
||||
|
||||
// Display items in visible slots
|
||||
foreach (var slot in itemSlots)
|
||||
{
|
||||
uint itemDisplayId;
|
||||
Item item = player.GetItemByPos(InventorySlots.Bag0, slot);
|
||||
if ((slot == EquipmentSlot.Head && player.HasFlag(PlayerFields.Flags, PlayerFlags.HideHelm)) ||
|
||||
(slot == EquipmentSlot.Cloak && player.HasFlag(PlayerFields.Flags, PlayerFlags.HideCloak)))
|
||||
itemDisplayId = 0;
|
||||
else if (item)
|
||||
itemDisplayId = item.GetDisplayId(player);
|
||||
else
|
||||
itemDisplayId = 0;
|
||||
|
||||
data.ItemDisplayID.Add((int)itemDisplayId);
|
||||
}
|
||||
|
||||
SendPacket(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
MirrorImageCreatureData data = new MirrorImageCreatureData();
|
||||
data.UnitGUID = guid;
|
||||
data.DisplayID = (int)creator.GetDisplayId();
|
||||
SendPacket(data);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.MissileTrajectoryCollision)]
|
||||
void HandleMissileTrajectoryCollision(MissileTrajectoryCollision packet)
|
||||
{
|
||||
Unit caster = Global.ObjAccessor.GetUnit(_player, packet.Target);
|
||||
if (caster == null)
|
||||
return;
|
||||
|
||||
Spell spell = caster.FindCurrentSpellBySpellId(packet.SpellID);
|
||||
if (spell == null || !spell.m_targets.HasDst())
|
||||
return;
|
||||
|
||||
Position pos = spell.m_targets.GetDstPos();
|
||||
pos.Relocate(packet.CollisionPos);
|
||||
spell.m_targets.ModDst(pos);
|
||||
|
||||
NotifyMissileTrajectoryCollision data = new NotifyMissileTrajectoryCollision();
|
||||
data.Caster = packet.Target;
|
||||
data.CastID = packet.CastID;
|
||||
data.CollisionPos = packet.CollisionPos;
|
||||
caster.SendMessageToSet(data, true);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.UpdateMissileTrajectory)]
|
||||
void HandleUpdateMissileTrajectory(UpdateMissileTrajectory packet)
|
||||
{
|
||||
Unit caster = Global.ObjAccessor.GetUnit(GetPlayer(), packet.Guid);
|
||||
Spell spell = caster ? caster.GetCurrentSpell(CurrentSpellTypes.Generic) : null;
|
||||
if (!spell || spell.m_spellInfo.Id != packet.SpellID || !spell.m_targets.HasDst() || !spell.m_targets.HasSrc())
|
||||
return;
|
||||
|
||||
Position pos = spell.m_targets.GetSrcPos();
|
||||
pos.Relocate(packet.FirePos);
|
||||
spell.m_targets.ModSrc(pos);
|
||||
|
||||
pos = spell.m_targets.GetDstPos();
|
||||
pos.Relocate(packet.ImpactPos);
|
||||
spell.m_targets.ModDst(pos);
|
||||
|
||||
spell.m_targets.SetPitch(packet.Pitch);
|
||||
spell.m_targets.SetSpeed(packet.Speed);
|
||||
|
||||
if (packet.Status.HasValue)
|
||||
{
|
||||
GetPlayer().ValidateMovementInfo(packet.Status.Value);
|
||||
/*public uint opcode;
|
||||
recvPacket >> opcode;
|
||||
recvPacket.SetOpcode(CMSG_MOVE_STOP); // always set to CMSG_MOVE_STOP in client SetOpcode
|
||||
//HandleMovementOpcodes(recvPacket);*/
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestCategoryCooldowns, Processing = PacketProcessing.Inplace)]
|
||||
void HandleRequestCategoryCooldowns(RequestCategoryCooldowns requestCategoryCooldowns)
|
||||
{
|
||||
GetPlayer().SendSpellCategoryCooldowns();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Movement;
|
||||
using Game.Network;
|
||||
using Game.Network.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);
|
||||
if (unit)
|
||||
SendLearnNewTaxiNode(unit);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.TaxiNodeStatusQuery, Processing = PacketProcessing.ThreadSafe)]
|
||||
void HandleTaxiNodeStatusQuery(TaxiNodeStatusQuery taxiNodeStatusQuery)
|
||||
{
|
||||
SendTaxiStatus(taxiNodeStatusQuery.UnitGUID);
|
||||
}
|
||||
|
||||
public void SendTaxiStatus(ObjectGuid guid)
|
||||
{
|
||||
// cheating checks
|
||||
Creature unit = ObjectAccessor.GetCreature(GetPlayer(), guid);
|
||||
if (unit == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WorldSession.SendTaxiStatus - {0} not found.", guid.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
uint curloc = Global.ObjectMgr.GetNearestTaxiNode(unit.GetPositionX(), unit.GetPositionY(), unit.GetPositionZ(), unit.GetMapId(), GetPlayer().GetTeam());
|
||||
|
||||
TaxiNodeStatusPkt data = new TaxiNodeStatusPkt();
|
||||
data.Unit = guid;
|
||||
|
||||
if (curloc == 0)
|
||||
data.Status = TaxiNodeStatus.None;
|
||||
else if (unit.GetReactionTo(GetPlayer()) >= ReputationRank.Neutral)
|
||||
data.Status = GetPlayer().m_taxi.IsTaximaskNodeKnown(curloc) ? 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);
|
||||
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 ShowTaxiNodes();
|
||||
data.WindowInfo.HasValue = true;
|
||||
data.WindowInfo.Value.UnitGUID = unit.GetGUID();
|
||||
data.WindowInfo.Value.CurrentNode = (int)curloc;
|
||||
|
||||
GetPlayer().m_taxi.AppendTaximaskTo(data, lastTaxiCheaterState);
|
||||
|
||||
SendPacket(data);
|
||||
|
||||
GetPlayer().SetTaxiCheater(lastTaxiCheaterState);
|
||||
}
|
||||
|
||||
public void SendDoFlight(uint mountDisplayId, uint path, uint pathNode = 0)
|
||||
{
|
||||
// remove fake death
|
||||
if (GetPlayer().HasUnitState(UnitState.Died))
|
||||
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
|
||||
|
||||
while (GetPlayer().GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Flight)
|
||||
GetPlayer().GetMotionMaster().MovementExpired(false);
|
||||
|
||||
if (mountDisplayId != 0)
|
||||
GetPlayer().Mount(mountDisplayId);
|
||||
|
||||
GetPlayer().GetMotionMaster().MoveTaxiFlight(path, pathNode);
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
TaxiNodeStatusPkt data = new TaxiNodeStatusPkt();
|
||||
data.Unit = unit.GetGUID();
|
||||
data.Status = TaxiNodeStatus.Learned;
|
||||
SendPacket(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SendDiscoverNewTaxiNode(uint nodeid)
|
||||
{
|
||||
if (GetPlayer().m_taxi.SetTaximaskNode(nodeid))
|
||||
SendPacket(new NewTaxiPath());
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ActivateTaxi, Processing = PacketProcessing.ThreadSafe)]
|
||||
void HandleActivateTaxi(ActivateTaxi activateTaxi)
|
||||
{
|
||||
Creature unit = GetPlayer().GetNPCIfCanInteractWith(activateTaxi.Vendor, NPCFlags.FlightMaster);
|
||||
if (unit == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleActivateTaxiOpcode - {0} not found or you can't interact with it.", activateTaxi.Vendor.ToString());
|
||||
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.SpellId))
|
||||
{
|
||||
var mountDisplays = Global.DB2Mgr.GetMountDisplays(mount.Id);
|
||||
if (mountDisplays != null)
|
||||
{
|
||||
List<MountXDisplayRecord> usableDisplays = mountDisplays.Where(mountDisplay =>
|
||||
{
|
||||
PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(mountDisplay.PlayerConditionID);
|
||||
if (playerCondition != null)
|
||||
return ConditionManager.IsPlayerMeetingCondition(GetPlayer(), playerCondition);
|
||||
|
||||
return true;
|
||||
}).ToList();
|
||||
|
||||
if (!usableDisplays.Empty())
|
||||
preferredMountDisplay = usableDisplays.SelectRandom().DisplayID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<uint> nodes = new List<uint>();
|
||||
Global.TaxiPathGraph.GetCompleteNodeRoute(from, to, GetPlayer(), nodes);
|
||||
GetPlayer().ActivateTaxiPathTo(nodes, unit, 0, preferredMountDisplay);
|
||||
}
|
||||
|
||||
public void SendActivateTaxiReply(ActivateTaxiReply reply = ActivateTaxiReply.Ok)
|
||||
{
|
||||
ActivateTaxiReplyPkt data = new ActivateTaxiReplyPkt();
|
||||
data.Reply = reply;
|
||||
SendPacket(data);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.TaxiRequestEarlyLanding, Processing = PacketProcessing.ThreadSafe)]
|
||||
void HandleTaxiRequestEarlyLanding(TaxiRequestEarlyLanding taxiRequestEarlyLanding)
|
||||
{
|
||||
if (GetPlayer().GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Flight)
|
||||
{
|
||||
if (GetPlayer().m_taxi.RequestEarlyLanding())
|
||||
{
|
||||
FlightPathMovementGenerator flight = (FlightPathMovementGenerator)GetPlayer().GetMotionMaster().top();
|
||||
flight.LoadPath(GetPlayer(), flight.GetPath()[(int)flight.GetCurrentNode()].NodeIndex);
|
||||
flight.Reset(GetPlayer());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using Game.SupportSystem;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.GmTicketGetCaseStatus, Processing = PacketProcessing.Inplace)]
|
||||
void HandleGMTicketGetCaseStatus(GMTicketGetCaseStatus packet)
|
||||
{
|
||||
//TODO: Implement GmCase and handle this packet correctly
|
||||
GMTicketCaseStatus status = new GMTicketCaseStatus();
|
||||
SendPacket(status);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.GmTicketGetSystemStatus, Processing = PacketProcessing.Inplace)]
|
||||
void HandleGMTicketSystemStatusOpcode(GMTicketGetSystemStatus packet)
|
||||
{
|
||||
// Note: This only disables the ticket UI at client side and is not fully reliable
|
||||
// Note: This disables the whole customer support UI after trying to send a ticket in disabled state (MessageBox: "GM Help Tickets are currently unavaiable."). UI remains disabled until the character relogs.
|
||||
GMTicketSystemStatusPkt response = new GMTicketSystemStatusPkt();
|
||||
response.Status = Global.SupportMgr.GetSupportSystemStatus() ? 1 : 0;
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SupportTicketSubmitBug)]
|
||||
void HandleSupportTicketSubmitBug(SupportTicketSubmitBug packet)
|
||||
{
|
||||
if (!Global.SupportMgr.GetBugSystemStatus())
|
||||
return;
|
||||
|
||||
BugTicket ticket = new BugTicket(GetPlayer());
|
||||
ticket.SetPosition(packet.Header.MapID, packet.Header.Position);
|
||||
ticket.SetFacing(packet.Header.Facing);
|
||||
ticket.SetNote(packet.Note);
|
||||
|
||||
Global.SupportMgr.AddTicket(ticket);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SupportTicketSubmitSuggestion)]
|
||||
void HandleSupportTicketSubmitSuggestion(SupportTicketSubmitSuggestion packet)
|
||||
{
|
||||
if (!Global.SupportMgr.GetSuggestionSystemStatus())
|
||||
return;
|
||||
|
||||
SuggestionTicket ticket = new SuggestionTicket(GetPlayer());
|
||||
ticket.SetPosition(packet.Header.MapID, packet.Header.Position);
|
||||
ticket.SetFacing(packet.Header.Facing);
|
||||
ticket.SetNote(packet.Note);
|
||||
|
||||
Global.SupportMgr.AddTicket(ticket);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SupportTicketSubmitComplaint)]
|
||||
void HandleSupportTicketSubmitComplaint(SupportTicketSubmitComplaint packet)
|
||||
{
|
||||
if (!Global.SupportMgr.GetComplaintSystemStatus())
|
||||
return;
|
||||
|
||||
ComplaintTicket comp = new ComplaintTicket(GetPlayer());
|
||||
comp.SetPosition(packet.Header.MapID, packet.Header.Position);
|
||||
comp.SetFacing(packet.Header.Facing);
|
||||
comp.SetChatLog(packet.ChatLog);
|
||||
comp.SetTargetCharacterGuid(packet.TargetCharacterGUID);
|
||||
comp.SetComplaintType((GMSupportComplaintType)packet.ComplaintType);
|
||||
comp.SetNote(packet.Note);
|
||||
|
||||
Global.SupportMgr.AddTicket(comp);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BugReport)]
|
||||
void HandleBugReport(BugReport bugReport)
|
||||
{
|
||||
// Note: There is no way to trigger this with standard UI except /script ReportBug("text")
|
||||
if (!Global.SupportMgr.GetBugSystemStatus())
|
||||
return;
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_BUG_REPORT);
|
||||
stmt.AddValue(0, bugReport.Text);
|
||||
stmt.AddValue(1, bugReport.DiagInfo);
|
||||
DB.Characters.Execute(stmt);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.Complaint)]
|
||||
void HandleComplaint(Complaint packet)
|
||||
{ // NOTE: all chat messages from this spammer are automatically ignored by the spam reporter until logout in case of chat spam.
|
||||
// if it's mail spam - ALL mails from this spammer are automatically removed by client
|
||||
|
||||
ComplaintResult result = new ComplaintResult();
|
||||
result.ComplaintType = packet.ComplaintType;
|
||||
result.Result = 0;
|
||||
SendPacket(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.UiTimeRequest, Status = SessionStatus.Authed, Processing = PacketProcessing.Inplace)]
|
||||
void HandleUITimeRequest(UITimeRequest packet)
|
||||
{
|
||||
UITime response = new UITime();
|
||||
response.Time = (uint)Time.UnixTime;
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.TimeSyncResponse, Processing = PacketProcessing.Inplace)]
|
||||
void HandleTimeSyncResponse(TimeSyncResponse packet)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "CMSG_TIME_SYNC_RESP");
|
||||
|
||||
if (packet.SequenceIndex != _player.m_timeSyncQueue.FirstOrDefault())
|
||||
Log.outError(LogFilter.Network, "Wrong time sync counter from player {0} (cheater?)", _player.GetName());
|
||||
|
||||
Log.outDebug(LogFilter.Network, "Time sync received: counter {0}, client ticks {1}, time since last sync {2}", packet.SequenceIndex, packet.ClientTime, packet.ClientTime - _player.m_timeSyncClient);
|
||||
|
||||
uint ourTicks = packet.ClientTime + (Time.GetMSTime() - _player.m_timeSyncServer);
|
||||
|
||||
// diff should be small
|
||||
Log.outDebug(LogFilter.Network, "Our ticks: {0}, diff {1}, latency {2}", ourTicks, ourTicks - packet.ClientTime, GetLatency());
|
||||
|
||||
_player.m_timeSyncClient = packet.ClientTime;
|
||||
_player.m_timeSyncQueue.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.UpdateWowTokenAuctionableList)]
|
||||
void HandleUpdateListedAuctionableTokens(UpdateListedAuctionableTokens updateListedAuctionableTokens)
|
||||
{
|
||||
UpdateListedAuctionableTokensResponse response = new UpdateListedAuctionableTokensResponse();
|
||||
|
||||
/// @todo: fix 6.x implementation
|
||||
response.UnkInt = updateListedAuctionableTokens.UnkInt;
|
||||
response.Result = TokenResult.Success;
|
||||
|
||||
SendPacket(response);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestWowTokenMarketPrice)]
|
||||
void HandleRequestWowTokenMarketPrice(RequestWowTokenMarketPrice requestWowTokenMarketPrice)
|
||||
{
|
||||
WowTokenMarketPriceResponse response = new WowTokenMarketPriceResponse();
|
||||
|
||||
/// @todo: 6.x fix implementation
|
||||
response.CurrentMarketPrice = 300000000;
|
||||
response.UnkInt = requestWowTokenMarketPrice.UnkInt;
|
||||
response.Result = TokenResult.Success;
|
||||
//packet.ReadUInt32("UnkInt32");
|
||||
|
||||
SendPacket(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using Game.Spells;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.AddToy)]
|
||||
void HandleAddToy(AddToy packet)
|
||||
{
|
||||
if (packet.Guid.IsEmpty())
|
||||
return;
|
||||
|
||||
Item item = _player.GetItemByGuid(packet.Guid);
|
||||
if (!item)
|
||||
{
|
||||
_player.SendEquipError(InventoryResult.ItemNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Global.DB2Mgr.IsToyItem(item.GetEntry()))
|
||||
return;
|
||||
|
||||
InventoryResult msg = _player.CanUseItem(item);
|
||||
if (msg != InventoryResult.Ok)
|
||||
{
|
||||
_player.SendEquipError(msg, item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_collectionMgr.AddToy(item.GetEntry(), false))
|
||||
_player.DestroyItem(item.GetBagSlot(), item.GetSlot(), true);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.UseToy)]
|
||||
void HandleUseToy(UseToy packet)
|
||||
{
|
||||
ItemTemplate item = Global.ObjectMgr.GetItemTemplate(packet.ItemID);
|
||||
if (item == null)
|
||||
return;
|
||||
|
||||
if (!_collectionMgr.HasToy(packet.ItemID))
|
||||
return;
|
||||
|
||||
var effect = item.Effects.Find(eff => { return packet.Cast.SpellID == eff.SpellID; });
|
||||
if (effect == null)
|
||||
return;
|
||||
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(packet.Cast.SpellID);
|
||||
if (spellInfo == null)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandleUseToy: unknown spell id: {0} used by Toy Item entry {1}", packet.Cast.SpellID, packet.ItemID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player.isPossessing())
|
||||
return;
|
||||
|
||||
SpellCastTargets targets = new SpellCastTargets(_player, packet.Cast);
|
||||
|
||||
Spell spell = new Spell(_player, spellInfo, TriggerCastFlags.None, ObjectGuid.Empty, false);
|
||||
|
||||
SpellPrepare spellPrepare = new SpellPrepare();
|
||||
spellPrepare.ClientCastID = packet.Cast.CastID;
|
||||
spellPrepare.ServerCastID = spell.m_castId;
|
||||
SendPacket(spellPrepare);
|
||||
|
||||
spell.m_fromClient = true;
|
||||
spell.m_castItemEntry = packet.ItemID;
|
||||
spell.m_misc.Data0 = packet.Cast.Misc[0];
|
||||
spell.m_misc.Data1 = packet.Cast.Misc[1];
|
||||
spell.m_castFlagsEx |= SpellCastFlagsEx.UseToySpell;
|
||||
spell.prepare(targets);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,765 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using Game.Spells;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
public void SendTradeStatus(TradeStatusPkt info)
|
||||
{
|
||||
info.Clear(); // reuse packet
|
||||
Player trader = GetPlayer().GetTrader();
|
||||
info.PartnerIsSameBnetAccount = trader && trader.GetSession().GetBattlenetAccountId() == GetBattlenetAccountId();
|
||||
SendPacket(info);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.IgnoreTrade)]
|
||||
void HandleIgnoreTradeOpcode(IgnoreTrade packet) { }
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BusyTrade)]
|
||||
void HandleBusyTradeOpcode(BusyTrade packet) { }
|
||||
|
||||
public void SendUpdateTrade(bool trader_data = true)
|
||||
{
|
||||
TradeData view_trade = trader_data ? GetPlayer().GetTradeData().GetTraderData() : GetPlayer().GetTradeData();
|
||||
|
||||
TradeUpdated tradeUpdated = new TradeUpdated();
|
||||
tradeUpdated.WhichPlayer = (byte)(trader_data ? 1 : 0);
|
||||
tradeUpdated.ClientStateIndex = view_trade.GetClientStateIndex();
|
||||
tradeUpdated.CurrentStateIndex = view_trade.GetServerStateIndex();
|
||||
tradeUpdated.Gold = view_trade.GetMoney();
|
||||
tradeUpdated.ProposedEnchantment = (int)view_trade.GetSpell();
|
||||
|
||||
for (byte i = 0; i < (byte)TradeSlots.Count; ++i)
|
||||
{
|
||||
Item item = view_trade.GetItem((TradeSlots)i);
|
||||
if (item)
|
||||
{
|
||||
TradeUpdated.TradeItem tradeItem = new TradeUpdated.TradeItem();
|
||||
tradeItem.Slot = i;
|
||||
tradeItem.Item = new ItemInstance(item);
|
||||
tradeItem.StackCount = (int)item.GetCount();
|
||||
tradeItem.GiftCreator = item.GetGuidValue(ItemFields.GiftCreator);
|
||||
if (!item.HasFlag(ItemFields.Flags, ItemFieldFlags.Wrapped))
|
||||
{
|
||||
tradeItem.Unwrapped.HasValue = true;
|
||||
TradeUpdated.UnwrappedTradeItem unwrappedItem = tradeItem.Unwrapped.Value;
|
||||
unwrappedItem.EnchantID = (int)item.GetEnchantmentId(EnchantmentSlot.Perm);
|
||||
unwrappedItem.OnUseEnchantmentID = (int)item.GetEnchantmentId(EnchantmentSlot.Use);
|
||||
unwrappedItem.Creator = item.GetGuidValue(ItemFields.Creator);
|
||||
unwrappedItem.Charges = item.GetSpellCharges();
|
||||
unwrappedItem.Lock = item.GetTemplate().GetLockID() != 0 && !item.HasFlag(ItemFields.Flags, ItemFieldFlags.Unlocked);
|
||||
unwrappedItem.MaxDurability = item.GetUInt32Value(ItemFields.MaxDurability);
|
||||
unwrappedItem.Durability = item.GetUInt32Value(ItemFields.Durability);
|
||||
|
||||
byte g = 0;
|
||||
foreach (ItemDynamicFieldGems gemData in item.GetGems())
|
||||
{
|
||||
if (gemData.ItemId != 0)
|
||||
{
|
||||
ItemGemData gem = new ItemGemData();
|
||||
gem.Slot = g;
|
||||
gem.Item = new ItemInstance(gemData);
|
||||
tradeItem.Unwrapped.Value.Gems.Add(gem);
|
||||
}
|
||||
++g;
|
||||
}
|
||||
}
|
||||
tradeUpdated.Items.Add(tradeItem);
|
||||
}
|
||||
}
|
||||
|
||||
SendPacket(tradeUpdated);
|
||||
}
|
||||
|
||||
void moveItems(Item[] myItems, Item[] hisItems)
|
||||
{
|
||||
Player trader = GetPlayer().GetTrader();
|
||||
if (!trader)
|
||||
return;
|
||||
|
||||
for (byte i = 0; i < (int)TradeSlots.TradedCount; ++i)
|
||||
{
|
||||
List<ItemPosCount> traderDst = new List<ItemPosCount>();
|
||||
List<ItemPosCount> playerDst = new List<ItemPosCount>();
|
||||
bool traderCanTrade = (myItems[i] == null || trader.CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, traderDst, myItems[i], false) == InventoryResult.Ok);
|
||||
bool playerCanTrade = (hisItems[i] == null || GetPlayer().CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, playerDst, hisItems[i], false) == InventoryResult.Ok);
|
||||
if (traderCanTrade && playerCanTrade)
|
||||
{
|
||||
// Ok, if trade item exists and can be stored
|
||||
// If we trade in both directions we had to check, if the trade will work before we actually do it
|
||||
// A roll back is not possible after we stored it
|
||||
if (myItems[i])
|
||||
{
|
||||
// logging
|
||||
Log.outDebug(LogFilter.Network, "partner storing: {0}", myItems[i].GetGUID().ToString());
|
||||
|
||||
if (HasPermission(RBACPermissions.LogGmTrade))
|
||||
{
|
||||
Log.outCommand(_player.GetSession().GetAccountId(), "GM {0} (Account: {1}) trade: {2} (Entry: {3} Count: {4}) to player: {5} (Account: {6})",
|
||||
GetPlayer().GetName(), GetPlayer().GetSession().GetAccountId(), myItems[i].GetTemplate().GetName(), myItems[i].GetEntry(), myItems[i].GetCount(),
|
||||
trader.GetName(), trader.GetSession().GetAccountId());
|
||||
}
|
||||
|
||||
// adjust time (depends on /played)
|
||||
if (myItems[i].HasFlag(ItemFields.Flags, ItemFieldFlags.BopTradeable))
|
||||
myItems[i].SetUInt32Value(ItemFields.CreatePlayedTime, trader.GetTotalPlayedTime() - (GetPlayer().GetTotalPlayedTime() - myItems[i].GetUInt32Value(ItemFields.CreatePlayedTime)));
|
||||
// store
|
||||
trader.MoveItemToInventory(traderDst, myItems[i], true, true);
|
||||
}
|
||||
if (hisItems[i])
|
||||
{
|
||||
// logging
|
||||
Log.outDebug(LogFilter.Network, "player storing: {0}", hisItems[i].GetGUID().ToString());
|
||||
|
||||
if (HasPermission(RBACPermissions.LogGmTrade))
|
||||
{
|
||||
Log.outCommand(trader.GetSession().GetAccountId(), "GM {0} (Account: {1}) trade: {2} (Entry: {3} Count: {4}) to player: {5} (Account: {6})",
|
||||
trader.GetName(), trader.GetSession().GetAccountId(), hisItems[i].GetTemplate().GetName(), hisItems[i].GetEntry(), hisItems[i].GetCount(),
|
||||
GetPlayer().GetName(), GetPlayer().GetSession().GetAccountId());
|
||||
}
|
||||
|
||||
|
||||
// adjust time (depends on /played)
|
||||
if (hisItems[i].HasFlag(ItemFields.Flags, ItemFieldFlags.BopTradeable))
|
||||
hisItems[i].SetUInt32Value(ItemFields.CreatePlayedTime, GetPlayer().GetTotalPlayedTime() - (trader.GetTotalPlayedTime() - hisItems[i].GetUInt32Value(ItemFields.CreatePlayedTime)));
|
||||
// store
|
||||
GetPlayer().MoveItemToInventory(playerDst, hisItems[i], true, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// in case of fatal error log error message
|
||||
// return the already removed items to the original owner
|
||||
if (myItems[i])
|
||||
{
|
||||
if (!traderCanTrade)
|
||||
Log.outError(LogFilter.Network, "trader can't store item: {0}", myItems[i].GetGUID().ToString());
|
||||
if (GetPlayer().CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, playerDst, myItems[i], false) == InventoryResult.Ok)
|
||||
GetPlayer().MoveItemToInventory(playerDst, myItems[i], true, true);
|
||||
else
|
||||
Log.outError(LogFilter.Network, "player can't take item back: {0}", myItems[i].GetGUID().ToString());
|
||||
}
|
||||
// return the already removed items to the original owner
|
||||
if (hisItems[i])
|
||||
{
|
||||
if (!playerCanTrade)
|
||||
Log.outError(LogFilter.Network, "player can't store item: {0}", hisItems[i].GetGUID().ToString());
|
||||
if (trader.CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, traderDst, hisItems[i], false) == InventoryResult.Ok)
|
||||
trader.MoveItemToInventory(traderDst, hisItems[i], true, true);
|
||||
else
|
||||
Log.outError(LogFilter.Network, "trader can't take item back: {0}", hisItems[i].GetGUID().ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void setAcceptTradeMode(TradeData myTrade, TradeData hisTrade, Item[] myItems, Item[] hisItems)
|
||||
{
|
||||
myTrade.SetInAcceptProcess(true);
|
||||
hisTrade.SetInAcceptProcess(true);
|
||||
|
||||
// store items in local list and set 'in-trade' flag
|
||||
for (byte i = 0; i < (int)TradeSlots.Count; ++i)
|
||||
{
|
||||
Item item = myTrade.GetItem((TradeSlots)i);
|
||||
if (item)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "player trade item {0} bag: {1} slot: {2}", item.GetGUID().ToString(), item.GetBagSlot(), item.GetSlot());
|
||||
//Can return null
|
||||
myItems[i] = item;
|
||||
myItems[i].SetInTrade();
|
||||
}
|
||||
item = hisTrade.GetItem((TradeSlots)i);
|
||||
if (item)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "partner trade item {0} bag: {1} slot: {2}", item.GetGUID().ToString(), item.GetBagSlot(), item.GetSlot());
|
||||
hisItems[i] = item;
|
||||
hisItems[i].SetInTrade();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void clearAcceptTradeMode(TradeData myTrade, TradeData hisTrade)
|
||||
{
|
||||
myTrade.SetInAcceptProcess(false);
|
||||
hisTrade.SetInAcceptProcess(false);
|
||||
}
|
||||
|
||||
static void clearAcceptTradeMode(Item[] myItems, Item[] hisItems)
|
||||
{
|
||||
// clear 'in-trade' flag
|
||||
for (byte i = 0; i < (int)TradeSlots.Count; ++i)
|
||||
{
|
||||
if (myItems[i])
|
||||
myItems[i].SetInTrade(false);
|
||||
if (hisItems[i])
|
||||
hisItems[i].SetInTrade(false);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.AcceptTrade)]
|
||||
void HandleAcceptTrade(AcceptTrade acceptTrade)
|
||||
{
|
||||
TradeData my_trade = GetPlayer().GetTradeData();
|
||||
if (my_trade == null)
|
||||
return;
|
||||
|
||||
Player trader = my_trade.GetTrader();
|
||||
|
||||
TradeData his_trade = trader.GetTradeData();
|
||||
if (his_trade == null)
|
||||
return;
|
||||
|
||||
Item[] myItems = new Item[(int)TradeSlots.Count];
|
||||
Item[] hisItems = new Item[(int)TradeSlots.Count];
|
||||
|
||||
// set before checks for propertly undo at problems (it already set in to client)
|
||||
my_trade.SetAccepted(true);
|
||||
|
||||
TradeStatusPkt info = new TradeStatusPkt();
|
||||
if (his_trade.GetServerStateIndex() != acceptTrade.StateIndex)
|
||||
{
|
||||
info.Status = TradeStatus.StateChanged;
|
||||
SendTradeStatus(info);
|
||||
my_trade.SetAccepted(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetPlayer().IsWithinDistInMap(trader, 11.11f, false))
|
||||
{
|
||||
info.Status = TradeStatus.TooFarAway;
|
||||
SendTradeStatus(info);
|
||||
my_trade.SetAccepted(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// not accept case incorrect money amount
|
||||
if (!GetPlayer().HasEnoughMoney(my_trade.GetMoney()))
|
||||
{
|
||||
info.Status = TradeStatus.Failed;
|
||||
info.BagResult = InventoryResult.NotEnoughMoney;
|
||||
SendTradeStatus(info);
|
||||
my_trade.SetAccepted(false, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// not accept case incorrect money amount
|
||||
if (!trader.HasEnoughMoney(his_trade.GetMoney()))
|
||||
{
|
||||
info.Status = TradeStatus.Failed;
|
||||
info.BagResult = InventoryResult.NotEnoughMoney;
|
||||
trader.GetSession().SendTradeStatus(info);
|
||||
his_trade.SetAccepted(false, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer().GetMoney() >= PlayerConst.MaxMoneyAmount - his_trade.GetMoney())
|
||||
{
|
||||
info.Status = TradeStatus.Failed;
|
||||
info.BagResult = InventoryResult.TooMuchGold;
|
||||
SendTradeStatus(info);
|
||||
my_trade.SetAccepted(false, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (trader.GetMoney() >= PlayerConst.MaxMoneyAmount - my_trade.GetMoney())
|
||||
{
|
||||
info.Status = TradeStatus.Failed;
|
||||
info.BagResult = InventoryResult.TooMuchGold;
|
||||
trader.GetSession().SendTradeStatus(info);
|
||||
his_trade.SetAccepted(false, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// not accept if some items now can't be trade (cheating)
|
||||
for (byte i = 0; i < (byte)TradeSlots.Count; ++i)
|
||||
{
|
||||
Item item = my_trade.GetItem((TradeSlots)i);
|
||||
if (item)
|
||||
{
|
||||
if (!item.CanBeTraded(false, true))
|
||||
{
|
||||
info.Status = TradeStatus.Cancelled;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.IsBindedNotWith(trader))
|
||||
{
|
||||
info.Status = TradeStatus.Failed;
|
||||
info.BagResult = InventoryResult.TradeBoundItem;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
item = his_trade.GetItem((TradeSlots)i);
|
||||
if (item)
|
||||
{
|
||||
if (!item.CanBeTraded(false, true))
|
||||
{
|
||||
info.Status = TradeStatus.Cancelled;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (his_trade.IsAccepted())
|
||||
{
|
||||
setAcceptTradeMode(my_trade, his_trade, myItems, hisItems);
|
||||
|
||||
Spell my_spell = null;
|
||||
SpellCastTargets my_targets = new SpellCastTargets();
|
||||
|
||||
Spell his_spell = null;
|
||||
SpellCastTargets his_targets = new SpellCastTargets();
|
||||
|
||||
// not accept if spell can't be casted now (cheating)
|
||||
uint my_spell_id = my_trade.GetSpell();
|
||||
if (my_spell_id != 0)
|
||||
{
|
||||
SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(my_spell_id);
|
||||
Item castItem = my_trade.GetSpellCastItem();
|
||||
|
||||
if (spellEntry == null || !his_trade.GetItem(TradeSlots.NonTraded) ||
|
||||
(my_trade.HasSpellCastItem() && !castItem))
|
||||
{
|
||||
clearAcceptTradeMode(my_trade, his_trade);
|
||||
clearAcceptTradeMode(myItems, hisItems);
|
||||
|
||||
my_trade.SetSpell(0);
|
||||
return;
|
||||
}
|
||||
|
||||
my_spell = new Spell(GetPlayer(), spellEntry, TriggerCastFlags.FullMask);
|
||||
my_spell.m_CastItem = castItem;
|
||||
my_targets.SetTradeItemTarget(GetPlayer());
|
||||
my_spell.m_targets = my_targets;
|
||||
|
||||
SpellCastResult res = my_spell.CheckCast(true);
|
||||
if (res != SpellCastResult.SpellCastOk)
|
||||
{
|
||||
my_spell.SendCastResult(res);
|
||||
|
||||
clearAcceptTradeMode(my_trade, his_trade);
|
||||
clearAcceptTradeMode(myItems, hisItems);
|
||||
|
||||
my_spell.Dispose();
|
||||
my_trade.SetSpell(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// not accept if spell can't be casted now (cheating)
|
||||
uint his_spell_id = his_trade.GetSpell();
|
||||
if (his_spell_id != 0)
|
||||
{
|
||||
SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(his_spell_id);
|
||||
Item castItem = his_trade.GetSpellCastItem();
|
||||
|
||||
if (spellEntry == null || !my_trade.GetItem(TradeSlots.NonTraded) || (his_trade.HasSpellCastItem() && !castItem))
|
||||
{
|
||||
his_trade.SetSpell(0);
|
||||
|
||||
clearAcceptTradeMode(my_trade, his_trade);
|
||||
clearAcceptTradeMode(myItems, hisItems);
|
||||
return;
|
||||
}
|
||||
|
||||
his_spell = new Spell(trader, spellEntry, TriggerCastFlags.FullMask);
|
||||
his_spell.m_CastItem = castItem;
|
||||
his_targets.SetTradeItemTarget(trader);
|
||||
his_spell.m_targets = his_targets;
|
||||
|
||||
SpellCastResult res = his_spell.CheckCast(true);
|
||||
if (res != SpellCastResult.SpellCastOk)
|
||||
{
|
||||
his_spell.SendCastResult(res);
|
||||
|
||||
clearAcceptTradeMode(my_trade, his_trade);
|
||||
clearAcceptTradeMode(myItems, hisItems);
|
||||
|
||||
my_spell.Dispose();
|
||||
his_spell.Dispose();
|
||||
|
||||
his_trade.SetSpell(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// inform partner client
|
||||
info.Status = TradeStatus.Accepted;
|
||||
trader.GetSession().SendTradeStatus(info);
|
||||
|
||||
// test if item will fit in each inventory
|
||||
TradeStatusPkt myCanCompleteInfo = new TradeStatusPkt();
|
||||
TradeStatusPkt hisCanCompleteInfo = new TradeStatusPkt();
|
||||
hisCanCompleteInfo.BagResult = trader.CanStoreItems(myItems, (int)TradeSlots.TradedCount, ref hisCanCompleteInfo.ItemID);
|
||||
myCanCompleteInfo.BagResult = GetPlayer().CanStoreItems(hisItems, (int)TradeSlots.TradedCount, ref myCanCompleteInfo.ItemID);
|
||||
|
||||
clearAcceptTradeMode(myItems, hisItems);
|
||||
|
||||
// in case of missing space report error
|
||||
if (myCanCompleteInfo.BagResult != InventoryResult.Ok)
|
||||
{
|
||||
clearAcceptTradeMode(my_trade, his_trade);
|
||||
|
||||
myCanCompleteInfo.Status = TradeStatus.Failed;
|
||||
trader.GetSession().SendTradeStatus(myCanCompleteInfo);
|
||||
myCanCompleteInfo.FailureForYou = true;
|
||||
SendTradeStatus(myCanCompleteInfo);
|
||||
my_trade.SetAccepted(false);
|
||||
his_trade.SetAccepted(false);
|
||||
return;
|
||||
}
|
||||
else if (hisCanCompleteInfo.BagResult != InventoryResult.Ok)
|
||||
{
|
||||
clearAcceptTradeMode(my_trade, his_trade);
|
||||
|
||||
hisCanCompleteInfo.Status = TradeStatus.Failed;
|
||||
SendTradeStatus(hisCanCompleteInfo);
|
||||
hisCanCompleteInfo.FailureForYou = true;
|
||||
trader.GetSession().SendTradeStatus(hisCanCompleteInfo);
|
||||
my_trade.SetAccepted(false);
|
||||
his_trade.SetAccepted(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// execute trade: 1. remove
|
||||
for (byte i = 0; i < (int)TradeSlots.TradedCount; ++i)
|
||||
{
|
||||
if (myItems[i])
|
||||
{
|
||||
myItems[i].SetGuidValue(ItemFields.GiftCreator, GetPlayer().GetGUID());
|
||||
GetPlayer().MoveItemFromInventory(myItems[i].GetBagSlot(), myItems[i].GetSlot(), true);
|
||||
}
|
||||
if (hisItems[i])
|
||||
{
|
||||
hisItems[i].SetGuidValue(ItemFields.GiftCreator, trader.GetGUID());
|
||||
trader.MoveItemFromInventory(hisItems[i].GetBagSlot(), hisItems[i].GetSlot(), true);
|
||||
}
|
||||
}
|
||||
|
||||
// execute trade: 2. store
|
||||
moveItems(myItems, hisItems);
|
||||
|
||||
// logging money
|
||||
if (HasPermission(RBACPermissions.LogGmTrade))
|
||||
{
|
||||
if (my_trade.GetMoney() > 0)
|
||||
{
|
||||
Log.outCommand(GetPlayer().GetSession().GetAccountId(), "GM {0} (Account: {1}) give money (Amount: {2}) to player: {3} (Account: {4})",
|
||||
GetPlayer().GetName(), GetPlayer().GetSession().GetAccountId(), my_trade.GetMoney(), trader.GetName(), trader.GetSession().GetAccountId());
|
||||
}
|
||||
|
||||
if (his_trade.GetMoney() > 0)
|
||||
{
|
||||
Log.outCommand(GetPlayer().GetSession().GetAccountId(), "GM {0} (Account: {1}) give money (Amount: {2}) to player: {3} (Account: {4})",
|
||||
trader.GetName(), trader.GetSession().GetAccountId(), his_trade.GetMoney(), GetPlayer().GetName(), GetPlayer().GetSession().GetAccountId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// update money
|
||||
GetPlayer().ModifyMoney(-(long)my_trade.GetMoney());
|
||||
GetPlayer().ModifyMoney((long)his_trade.GetMoney());
|
||||
trader.ModifyMoney(-(long)his_trade.GetMoney());
|
||||
trader.ModifyMoney((long)my_trade.GetMoney());
|
||||
|
||||
if (my_spell)
|
||||
my_spell.prepare(my_targets);
|
||||
|
||||
if (his_spell)
|
||||
his_spell.prepare(his_targets);
|
||||
|
||||
// cleanup
|
||||
clearAcceptTradeMode(my_trade, his_trade);
|
||||
GetPlayer().SetTradeData(null);
|
||||
trader.SetTradeData(null);
|
||||
|
||||
// desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards)
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
GetPlayer().SaveInventoryAndGoldToDB(trans);
|
||||
trader.SaveInventoryAndGoldToDB(trans);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
info.Status = TradeStatus.Complete;
|
||||
trader.GetSession().SendTradeStatus(info);
|
||||
SendTradeStatus(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
info.Status = TradeStatus.Accepted;
|
||||
trader.GetSession().SendTradeStatus(info);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.UnacceptTrade)]
|
||||
void HandleUnacceptTrade(UnacceptTrade packet)
|
||||
{
|
||||
TradeData my_trade = GetPlayer().GetTradeData();
|
||||
if (my_trade == null)
|
||||
return;
|
||||
|
||||
my_trade.SetAccepted(false, true);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BeginTrade)]
|
||||
void HandleBeginTrade(BeginTrade packet)
|
||||
{
|
||||
TradeData my_trade = GetPlayer().GetTradeData();
|
||||
if (my_trade == null)
|
||||
return;
|
||||
|
||||
TradeStatusPkt info = new TradeStatusPkt();
|
||||
my_trade.GetTrader().GetSession().SendTradeStatus(info);
|
||||
SendTradeStatus(info);
|
||||
}
|
||||
|
||||
public void SendCancelTrade()
|
||||
{
|
||||
if (PlayerRecentlyLoggedOut() || PlayerLogout())
|
||||
return;
|
||||
|
||||
TradeStatusPkt info = new TradeStatusPkt();
|
||||
info.Status = TradeStatus.Cancelled;
|
||||
SendTradeStatus(info);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.CancelTrade, Status = SessionStatus.LoggedinOrRecentlyLogout)]
|
||||
void HandleCancelTrade(CancelTrade cancelTrade)
|
||||
{
|
||||
// sent also after LOGOUT COMPLETE
|
||||
if (GetPlayer()) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT
|
||||
GetPlayer().TradeCancel(true);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.InitiateTrade)]
|
||||
void HandleInitiateTrade(InitiateTrade initiateTrade)
|
||||
{
|
||||
if (GetPlayer().GetTradeData() != null)
|
||||
return;
|
||||
|
||||
TradeStatusPkt info = new TradeStatusPkt();
|
||||
if (!GetPlayer().IsAlive())
|
||||
{
|
||||
info.Status = TradeStatus.Dead;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer().HasUnitState(UnitState.Stunned))
|
||||
{
|
||||
info.Status = TradeStatus.Stunned;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isLogingOut())
|
||||
{
|
||||
info.Status = TradeStatus.LoggingOut;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer().IsInFlight())
|
||||
{
|
||||
info.Status = TradeStatus.TooFarAway;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer().getLevel() < WorldConfig.GetIntValue(WorldCfg.TradeLevelReq))
|
||||
{
|
||||
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.TradeReq), WorldConfig.GetIntValue(WorldCfg.TradeLevelReq));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Player pOther = Global.ObjAccessor.FindPlayer(initiateTrade.Guid);
|
||||
if (!pOther)
|
||||
{
|
||||
info.Status = TradeStatus.NoTarget;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther == GetPlayer() || pOther.GetTradeData() != null)
|
||||
{
|
||||
info.Status = TradeStatus.PlayerBusy;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pOther.IsAlive())
|
||||
{
|
||||
info.Status = TradeStatus.TargetDead;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther.IsInFlight())
|
||||
{
|
||||
info.Status = TradeStatus.TooFarAway;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther.HasUnitState(UnitState.Stunned))
|
||||
{
|
||||
info.Status = TradeStatus.TargetStunned;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther.GetSession().isLogingOut())
|
||||
{
|
||||
info.Status = TradeStatus.TargetLoggingOut;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther.GetSocial().HasIgnore(GetPlayer().GetGUID()))
|
||||
{
|
||||
info.Status = TradeStatus.PlayerIgnored;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((pOther.GetTeam() != GetPlayer().GetTeam() ||
|
||||
pOther.HasFlag(PlayerFields.FlagsEx, PlayerFlagsEx.MercenaryMode) ||
|
||||
GetPlayer().HasFlag(PlayerFields.FlagsEx, PlayerFlagsEx.MercenaryMode)) &&
|
||||
(!WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideTrade) &&
|
||||
!HasPermission(RBACPermissions.AllowTwoSideTrade)))
|
||||
{
|
||||
info.Status = TradeStatus.WrongFaction;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pOther.IsWithinDistInMap(GetPlayer(), 11.11f, false))
|
||||
{
|
||||
info.Status = TradeStatus.TooFarAway;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pOther.getLevel() < WorldConfig.GetIntValue(WorldCfg.TradeLevelReq))
|
||||
{
|
||||
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.TradeOtherReq), WorldConfig.GetIntValue(WorldCfg.TradeLevelReq));
|
||||
return;
|
||||
}
|
||||
|
||||
// OK start trade
|
||||
GetPlayer().SetTradeData(new TradeData(GetPlayer(), pOther));
|
||||
pOther.SetTradeData(new TradeData(pOther, GetPlayer()));
|
||||
|
||||
info.Status = TradeStatus.Proposed;
|
||||
info.Partner = GetPlayer().GetGUID();
|
||||
pOther.GetSession().SendTradeStatus(info);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetTradeGold)]
|
||||
void HandleSetTradeGold(SetTradeGold setTradeGold)
|
||||
{
|
||||
TradeData my_trade = GetPlayer().GetTradeData();
|
||||
if (my_trade == null)
|
||||
return;
|
||||
|
||||
my_trade.UpdateClientStateIndex();
|
||||
my_trade.SetMoney(setTradeGold.Coinage);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetTradeItem)]
|
||||
void HandleSetTradeItem(SetTradeItem setTradeItem)
|
||||
{
|
||||
TradeData my_trade = GetPlayer().GetTradeData();
|
||||
if (my_trade == null)
|
||||
return;
|
||||
|
||||
TradeStatusPkt info = new TradeStatusPkt();
|
||||
// invalid slot number
|
||||
if (setTradeItem.TradeSlot >= (byte)TradeSlots.Count)
|
||||
{
|
||||
info.Status = TradeStatus.Cancelled;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
// check cheating, can't fail with correct client operations
|
||||
Item item = GetPlayer().GetItemByPos(setTradeItem.PackSlot, setTradeItem.ItemSlotInPack);
|
||||
if (!item || (setTradeItem.TradeSlot != (byte)TradeSlots.NonTraded && !item.CanBeTraded(false, true)))
|
||||
{
|
||||
info.Status = TradeStatus.Cancelled;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectGuid iGUID = item.GetGUID();
|
||||
|
||||
// prevent place single item into many trade slots using cheating and client bugs
|
||||
if (my_trade.HasItem(iGUID))
|
||||
{
|
||||
// cheating attempt
|
||||
info.Status = TradeStatus.Cancelled;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
my_trade.UpdateClientStateIndex();
|
||||
if (setTradeItem.TradeSlot != (byte)TradeSlots.NonTraded && item.IsBindedNotWith(my_trade.GetTrader()))
|
||||
{
|
||||
info.Status = TradeStatus.NotOnTaplist;
|
||||
info.TradeSlot = setTradeItem.TradeSlot;
|
||||
SendTradeStatus(info);
|
||||
return;
|
||||
}
|
||||
|
||||
my_trade.SetItem((TradeSlots)setTradeItem.TradeSlot, item);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.ClearTradeItem)]
|
||||
void HandleClearTradeItem(ClearTradeItem clearTradeItem)
|
||||
{
|
||||
TradeData my_trade = GetPlayer().GetTradeData();
|
||||
if (my_trade == null)
|
||||
return;
|
||||
|
||||
my_trade.UpdateClientStateIndex();
|
||||
|
||||
// invalid slot number
|
||||
if (clearTradeItem.TradeSlot >= (byte)TradeSlots.Count)
|
||||
return;
|
||||
|
||||
my_trade.SetItem((TradeSlots)clearTradeItem.TradeSlot, null);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetTradeCurrency)]
|
||||
void HandleSetTradeCurrency(SetTradeCurrency setTradeCurrency)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.TransmogrifyItems)]
|
||||
void HandleTransmogrifyItems(TransmogrifyItems transmogrifyItems)
|
||||
{
|
||||
Player player = GetPlayer();
|
||||
|
||||
// Validate
|
||||
if (!player.GetNPCIfCanInteractWith(transmogrifyItems.Npc, NPCFlags.Transmogrifier))
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - Unit (GUID: {0}) not found or player can't interact with it.", transmogrifyItems.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
long cost = 0;
|
||||
Dictionary<Item, uint> transmogItems = new Dictionary<Item, uint>();
|
||||
Dictionary<Item, uint> illusionItems = new Dictionary<Item, uint>();
|
||||
|
||||
List<Item> resetAppearanceItems = new List<Item>();
|
||||
List<Item> resetIllusionItems = new List<Item>();
|
||||
List<uint> bindAppearances = new List<uint>();
|
||||
|
||||
foreach (TransmogrifyItem transmogItem in transmogrifyItems.Items)
|
||||
{
|
||||
// slot of the transmogrified item
|
||||
if (transmogItem.Slot >= EquipmentSlot.End)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - Player ({0}, name: {1}) tried to transmogrify wrong slot {2} when transmogrifying items.", player.GetGUID().ToString(), player.GetName(), transmogItem.Slot);
|
||||
return;
|
||||
}
|
||||
|
||||
// transmogrified item
|
||||
Item itemTransmogrified = player.GetItemByPos(InventorySlots.Bag0, (byte)transmogItem.Slot);
|
||||
if (!itemTransmogrified)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - Player (GUID: {0}, name: {1}) tried to transmogrify an invalid item in a valid slot (slot: {2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.Slot);
|
||||
return;
|
||||
}
|
||||
|
||||
if (transmogItem.ItemModifiedAppearanceID != 0)
|
||||
{
|
||||
ItemModifiedAppearanceRecord itemModifiedAppearance = CliDB.ItemModifiedAppearanceStorage.LookupByKey(transmogItem.ItemModifiedAppearanceID);
|
||||
if (itemModifiedAppearance == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify using invalid appearance ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.ItemModifiedAppearanceID);
|
||||
return;
|
||||
}
|
||||
|
||||
var pairValue = GetCollectionMgr().HasItemAppearance((uint)transmogItem.ItemModifiedAppearanceID);
|
||||
if (!pairValue.Item1)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify using appearance he has not collected ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.ItemModifiedAppearanceID);
|
||||
return;
|
||||
}
|
||||
ItemTemplate itemTemplate = Global.ObjectMgr.GetItemTemplate(itemModifiedAppearance.ItemID);
|
||||
if (player.CanUseItem(itemTemplate) != InventoryResult.Ok)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify using appearance he can never use ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.ItemModifiedAppearanceID);
|
||||
return;
|
||||
}
|
||||
|
||||
// validity of the transmogrification items
|
||||
if (!Item.CanTransmogrifyItemWithItem(itemTransmogrified, itemModifiedAppearance))
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} failed CanTransmogrifyItemWithItem ({2} with appearance {3}).", player.GetGUID().ToString(), player.GetName(), itemTransmogrified.GetEntry(), transmogItem.ItemModifiedAppearanceID);
|
||||
return;
|
||||
}
|
||||
|
||||
transmogItems[itemTransmogrified] = (uint)transmogItem.ItemModifiedAppearanceID;
|
||||
if (pairValue.Item2)
|
||||
bindAppearances.Add((uint)transmogItem.ItemModifiedAppearanceID);
|
||||
|
||||
// add cost
|
||||
cost += itemTransmogrified.GetSpecialPrice();
|
||||
}
|
||||
else
|
||||
resetAppearanceItems.Add(itemTransmogrified);
|
||||
|
||||
if (transmogItem.SpellItemEnchantmentID != 0)
|
||||
{
|
||||
if (transmogItem.Slot != EquipmentSlot.MainHand && transmogItem.Slot != EquipmentSlot.OffHand)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify illusion into non-weapon slot ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.Slot);
|
||||
return;
|
||||
}
|
||||
|
||||
SpellItemEnchantmentRecord illusion = CliDB.SpellItemEnchantmentStorage.LookupByKey(transmogItem.SpellItemEnchantmentID);
|
||||
if (illusion == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify illusion using invalid enchant ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.SpellItemEnchantmentID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (illusion.ItemVisual == 0 || !illusion.Flags.HasAnyFlag(EnchantmentSlotMask.Collectable))
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify illusion using not allowed enchant ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.SpellItemEnchantmentID);
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerConditionRecord condition = CliDB.PlayerConditionStorage.LookupByKey(illusion.PlayerConditionID);
|
||||
if (condition != null)
|
||||
{
|
||||
if (!ConditionManager.IsPlayerMeetingCondition(player, condition))
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify illusion using not collected enchant ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.SpellItemEnchantmentID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (illusion.ScalingClassRestricted > 0 && illusion.ScalingClassRestricted != (byte)player.GetClass())
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify illusion using not allowed class enchant ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.SpellItemEnchantmentID);
|
||||
return;
|
||||
}
|
||||
|
||||
illusionItems[itemTransmogrified] = (uint)transmogItem.SpellItemEnchantmentID;
|
||||
cost += illusion.TransmogCost;
|
||||
}
|
||||
else
|
||||
resetIllusionItems.Add(itemTransmogrified);
|
||||
}
|
||||
|
||||
if (cost != 0) // 0 cost if reverting look
|
||||
{
|
||||
if (!player.HasEnoughMoney(cost))
|
||||
return;
|
||||
|
||||
player.ModifyMoney(-cost);
|
||||
}
|
||||
|
||||
// Everything is fine, proceed
|
||||
foreach (var transmogPair in transmogItems)
|
||||
{
|
||||
Item transmogrified = transmogPair.Key;
|
||||
|
||||
if (!transmogrifyItems.CurrentSpecOnly)
|
||||
{
|
||||
transmogrified.SetModifier(ItemModifier.TransmogAppearanceAllSpecs, transmogPair.Value);
|
||||
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec1, 0);
|
||||
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec2, 0);
|
||||
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec3, 0);
|
||||
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec4, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (transmogrified.GetModifier(ItemModifier.TransmogAppearanceSpec1) == 0)
|
||||
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec1, transmogrified.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
|
||||
if (transmogrified.GetModifier(ItemModifier.TransmogAppearanceSpec2) == 0)
|
||||
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec2, transmogrified.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
|
||||
if (transmogrified.GetModifier(ItemModifier.TransmogAppearanceSpec3) == 0)
|
||||
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec3, transmogrified.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
|
||||
if (transmogrified.GetModifier(ItemModifier.TransmogAppearanceSpec4) == 0)
|
||||
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec4, transmogrified.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
|
||||
transmogrified.SetModifier(ItemConst.AppearanceModifierSlotBySpec[player.GetActiveTalentGroup()], transmogPair.Value);
|
||||
}
|
||||
|
||||
player.SetVisibleItemSlot(transmogrified.GetSlot(), transmogrified);
|
||||
|
||||
transmogrified.SetNotRefundable(player);
|
||||
transmogrified.ClearSoulboundTradeable(player);
|
||||
transmogrified.SetState(ItemUpdateState.Changed, player);
|
||||
}
|
||||
|
||||
foreach (var illusionPair in illusionItems)
|
||||
{
|
||||
Item transmogrified = illusionPair.Key;
|
||||
|
||||
if (!transmogrifyItems.CurrentSpecOnly)
|
||||
{
|
||||
transmogrified.SetModifier(ItemModifier.EnchantIllusionAllSpecs, illusionPair.Value);
|
||||
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec1, 0);
|
||||
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec2, 0);
|
||||
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec3, 0);
|
||||
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec4, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (transmogrified.GetModifier(ItemModifier.EnchantIllusionSpec1) == 0)
|
||||
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec1, transmogrified.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
|
||||
if (transmogrified.GetModifier(ItemModifier.EnchantIllusionSpec2) == 0)
|
||||
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec2, transmogrified.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
|
||||
if (transmogrified.GetModifier(ItemModifier.EnchantIllusionSpec3) == 0)
|
||||
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec3, transmogrified.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
|
||||
if (transmogrified.GetModifier(ItemModifier.EnchantIllusionSpec4) == 0)
|
||||
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec4, transmogrified.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
|
||||
transmogrified.SetModifier(ItemConst.IllusionModifierSlotBySpec[player.GetActiveTalentGroup()], illusionPair.Value);
|
||||
}
|
||||
|
||||
player.SetVisibleItemSlot(transmogrified.GetSlot(), transmogrified);
|
||||
|
||||
transmogrified.SetNotRefundable(player);
|
||||
transmogrified.ClearSoulboundTradeable(player);
|
||||
transmogrified.SetState(ItemUpdateState.Changed, player);
|
||||
}
|
||||
|
||||
foreach (Item item in resetAppearanceItems)
|
||||
{
|
||||
if (!transmogrifyItems.CurrentSpecOnly)
|
||||
{
|
||||
item.SetModifier(ItemModifier.TransmogAppearanceAllSpecs, 0);
|
||||
item.SetModifier(ItemModifier.TransmogAppearanceSpec1, 0);
|
||||
item.SetModifier(ItemModifier.TransmogAppearanceSpec2, 0);
|
||||
item.SetModifier(ItemModifier.TransmogAppearanceSpec3, 0);
|
||||
item.SetModifier(ItemModifier.TransmogAppearanceSpec4, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.GetModifier(ItemModifier.TransmogAppearanceSpec1) == 0)
|
||||
item.SetModifier(ItemModifier.TransmogAppearanceSpec1, item.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
|
||||
if (item.GetModifier(ItemModifier.TransmogAppearanceSpec2) == 0)
|
||||
item.SetModifier(ItemModifier.TransmogAppearanceSpec2, item.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
|
||||
if (item.GetModifier(ItemModifier.TransmogAppearanceSpec2) == 0)
|
||||
item.SetModifier(ItemModifier.TransmogAppearanceSpec3, item.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
|
||||
if (item.GetModifier(ItemModifier.TransmogAppearanceSpec4) == 0)
|
||||
item.SetModifier(ItemModifier.TransmogAppearanceSpec4, item.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
|
||||
item.SetModifier(ItemConst.AppearanceModifierSlotBySpec[player.GetActiveTalentGroup()], 0);
|
||||
item.SetModifier(ItemModifier.EnchantIllusionAllSpecs, 0);
|
||||
}
|
||||
|
||||
item.SetState(ItemUpdateState.Changed, player);
|
||||
player.SetVisibleItemSlot(item.GetSlot(), item);
|
||||
}
|
||||
|
||||
foreach (Item item in resetIllusionItems)
|
||||
{
|
||||
if (!transmogrifyItems.CurrentSpecOnly)
|
||||
{
|
||||
item.SetModifier(ItemModifier.EnchantIllusionAllSpecs, 0);
|
||||
item.SetModifier(ItemModifier.EnchantIllusionSpec1, 0);
|
||||
item.SetModifier(ItemModifier.EnchantIllusionSpec2, 0);
|
||||
item.SetModifier(ItemModifier.EnchantIllusionSpec3, 0);
|
||||
item.SetModifier(ItemModifier.EnchantIllusionSpec4, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.GetModifier(ItemModifier.EnchantIllusionSpec1) == 0)
|
||||
item.SetModifier(ItemModifier.EnchantIllusionSpec1, item.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
|
||||
if (item.GetModifier(ItemModifier.EnchantIllusionSpec2) == 0)
|
||||
item.SetModifier(ItemModifier.EnchantIllusionSpec2, item.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
|
||||
if (item.GetModifier(ItemModifier.EnchantIllusionSpec3) == 0)
|
||||
item.SetModifier(ItemModifier.EnchantIllusionSpec3, item.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
|
||||
if (item.GetModifier(ItemModifier.EnchantIllusionSpec4) == 0)
|
||||
item.SetModifier(ItemModifier.EnchantIllusionSpec4, item.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
|
||||
item.SetModifier(ItemConst.IllusionModifierSlotBySpec[player.GetActiveTalentGroup()], 0);
|
||||
item.SetModifier(ItemModifier.TransmogAppearanceAllSpecs, 0);
|
||||
}
|
||||
|
||||
item.SetState(ItemUpdateState.Changed, player);
|
||||
player.SetVisibleItemSlot(item.GetSlot(), item);
|
||||
}
|
||||
|
||||
foreach (uint itemModifedAppearanceId in bindAppearances)
|
||||
{
|
||||
var itemsProvidingAppearance = GetCollectionMgr().GetItemsProvidingTemporaryAppearance(itemModifedAppearanceId);
|
||||
foreach (ObjectGuid itemGuid in itemsProvidingAppearance)
|
||||
{
|
||||
Item item = player.GetItemByGuid(itemGuid);
|
||||
if (item)
|
||||
{
|
||||
item.SetNotRefundable(player);
|
||||
item.ClearSoulboundTradeable(player);
|
||||
GetCollectionMgr().AddItemAppearance(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
[WorldPacketHandler(ClientOpcodes.MoveDismissVehicle)]
|
||||
void HandleMoveDismissVehicle(MoveDismissVehicle packet)
|
||||
{
|
||||
ObjectGuid vehicleGUID = GetPlayer().GetCharmGUID();
|
||||
if (vehicleGUID.IsEmpty()) // something wrong here...
|
||||
return;
|
||||
|
||||
GetPlayer().ValidateMovementInfo(packet.Status);
|
||||
GetPlayer().m_movementInfo = packet.Status;
|
||||
|
||||
GetPlayer().ExitVehicle();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestVehiclePrevSeat)]
|
||||
void HandleRequestVehiclePrevSeat(RequestVehiclePrevSeat packet)
|
||||
{
|
||||
Unit vehicle_base = GetPlayer().GetVehicleBase();
|
||||
if (!vehicle_base)
|
||||
return;
|
||||
|
||||
VehicleSeatRecord seat = GetPlayer().GetVehicle().GetSeatForPassenger(GetPlayer());
|
||||
if (!seat.CanSwitchFromSeat())
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandleRequestVehiclePrevSeat: {0} tried to switch seats but current seatflags {1} don't permit that.",
|
||||
GetPlayer().GetGUID().ToString(), seat.Flags[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().ChangeSeat(-1, false);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestVehicleNextSeat)]
|
||||
void HandleRequestVehicleNextSeat(RequestVehicleNextSeat packet)
|
||||
{
|
||||
Unit vehicle_base = GetPlayer().GetVehicleBase();
|
||||
if (!vehicle_base)
|
||||
return;
|
||||
|
||||
VehicleSeatRecord seat = GetPlayer().GetVehicle().GetSeatForPassenger(GetPlayer());
|
||||
if (!seat.CanSwitchFromSeat())
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandleRequestVehicleNextSeat: {0} tried to switch seats but current seatflags {1} don't permit that.",
|
||||
GetPlayer().GetGUID().ToString(), seat.Flags[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().ChangeSeat(-1, true);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.MoveChangeVehicleSeats)]
|
||||
void HandleMoveChangeVehicleSeats(MoveChangeVehicleSeats packet)
|
||||
{
|
||||
Unit vehicle_base = GetPlayer().GetVehicleBase();
|
||||
if (!vehicle_base)
|
||||
return;
|
||||
|
||||
VehicleSeatRecord seat = GetPlayer().GetVehicle().GetSeatForPassenger(GetPlayer());
|
||||
if (!seat.CanSwitchFromSeat())
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandleMoveChangeVehicleSeats, {0} tried to switch seats but current seatflags {1} don't permit that.",
|
||||
GetPlayer().GetGUID().ToString(), seat.Flags[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().ValidateMovementInfo(packet.Status);
|
||||
|
||||
if (vehicle_base.GetGUID() != packet.Status.Guid)
|
||||
return;
|
||||
|
||||
vehicle_base.m_movementInfo = packet.Status;
|
||||
|
||||
Unit vehUnit;
|
||||
if (packet.DstVehicle.IsEmpty())
|
||||
GetPlayer().ChangeSeat(-1, packet.DstSeatIndex != 255);
|
||||
else if (vehUnit = Global.ObjAccessor.GetUnit(GetPlayer(), packet.DstVehicle))
|
||||
{
|
||||
Vehicle vehicle = vehUnit.GetVehicleKit();
|
||||
if (vehicle)
|
||||
if (vehicle.HasEmptySeat((sbyte)packet.DstSeatIndex))
|
||||
vehUnit.HandleSpellClick(GetPlayer(), (sbyte)packet.DstSeatIndex);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestVehicleSwitchSeat)]
|
||||
void HandleRequestVehicleSwitchSeat(RequestVehicleSwitchSeat packet)
|
||||
{
|
||||
Unit vehicle_base = GetPlayer().GetVehicleBase();
|
||||
if (!vehicle_base)
|
||||
return;
|
||||
|
||||
VehicleSeatRecord seat = GetPlayer().GetVehicle().GetSeatForPassenger(GetPlayer());
|
||||
if (!seat.CanSwitchFromSeat())
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandleRequestVehicleSwitchSeat: {0} tried to switch seats but current seatflags {1} don't permit that.",
|
||||
GetPlayer().GetGUID().ToString(), seat.Flags[0]);
|
||||
return;
|
||||
}
|
||||
Unit vehUnit;
|
||||
if (vehicle_base.GetGUID() == packet.Vehicle)
|
||||
GetPlayer().ChangeSeat((sbyte)packet.SeatIndex);
|
||||
else if (vehUnit = Global.ObjAccessor.GetUnit(GetPlayer(), packet.Vehicle))
|
||||
{
|
||||
Vehicle vehicle = vehUnit.GetVehicleKit();
|
||||
if (vehicle)
|
||||
if (vehicle.HasEmptySeat((sbyte)packet.SeatIndex))
|
||||
vehUnit.HandleSpellClick(GetPlayer(), (sbyte)packet.SeatIndex);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RideVehicleInteract)]
|
||||
void HandleRideVehicleInteract(RideVehicleInteract packet)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(packet.Vehicle);
|
||||
if (player)
|
||||
{
|
||||
if (!player.GetVehicleKit())
|
||||
return;
|
||||
if (!player.IsInRaidWith(GetPlayer()))
|
||||
return;
|
||||
if (!player.IsWithinDistInMap(GetPlayer(), SharedConst.InteractionDistance))
|
||||
return;
|
||||
|
||||
GetPlayer().EnterVehicle(player);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.EjectPassenger)]
|
||||
void HandleEjectPassenger(EjectPassenger packet)
|
||||
{
|
||||
Vehicle vehicle = GetPlayer().GetVehicleKit();
|
||||
if (!vehicle)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "HandleEjectPassenger: {0} is not in a vehicle!", GetPlayer().GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.Passenger.IsUnit())
|
||||
{
|
||||
Unit unit = Global.ObjAccessor.GetUnit(GetPlayer(), packet.Passenger);
|
||||
if (!unit)
|
||||
{
|
||||
Log.outError(LogFilter.Network, "{0} tried to eject {1} from vehicle, but the latter was not found in world!", GetPlayer().GetGUID().ToString(), packet.Passenger.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!unit.IsOnVehicle(vehicle.GetBase()))
|
||||
{
|
||||
Log.outError(LogFilter.Network, "{0} tried to eject {1}, but they are not in the same vehicle", GetPlayer().GetGUID().ToString(), packet.Passenger.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
VehicleSeatRecord seat = vehicle.GetSeatForPassenger(unit);
|
||||
Contract.Assert(seat != null);
|
||||
if (seat.IsEjectable())
|
||||
unit.ExitVehicle();
|
||||
else
|
||||
Log.outError(LogFilter.Network, "{0} attempted to eject {1} from non-ejectable seat.", GetPlayer().GetGUID().ToString(), packet.Passenger.ToString());
|
||||
}
|
||||
|
||||
else
|
||||
Log.outError(LogFilter.Network, "HandleEjectPassenger: {0} tried to eject invalid {1}", GetPlayer().GetGUID().ToString(), packet.Passenger.ToString());
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestVehicleExit)]
|
||||
void HandleRequestVehicleExit(RequestVehicleExit packet)
|
||||
{
|
||||
Vehicle vehicle = GetPlayer().GetVehicle();
|
||||
if (vehicle)
|
||||
{
|
||||
VehicleSeatRecord seat = vehicle.GetSeatForPassenger(GetPlayer());
|
||||
if (seat != null)
|
||||
{
|
||||
if (seat.CanEnterOrExit())
|
||||
GetPlayer().ExitVehicle();
|
||||
else
|
||||
Log.outError(LogFilter.Network, "{0} tried to exit vehicle, but seatflags {1} (ID: {2}) don't permit that.",
|
||||
GetPlayer().GetGUID().ToString(), seat.Id, seat.Flags[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.MoveSetVehicleRecIdAck)]
|
||||
void HandleMoveSetVehicleRecAck(MoveSetVehicleRecIdAck setVehicleRecIdAck)
|
||||
{
|
||||
GetPlayer().ValidateMovementInfo(setVehicleRecIdAck.Data.Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 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/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public partial class WorldSession
|
||||
{
|
||||
public void SendVoidStorageTransferResult(VoidTransferError result)
|
||||
{
|
||||
SendPacket(new VoidTransferResult(result));
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.UnlockVoidStorage)]
|
||||
void HandleVoidStorageUnlock(UnlockVoidStorage unlockVoidStorage)
|
||||
{
|
||||
Creature unit = GetPlayer().GetNPCIfCanInteractWith(unlockVoidStorage.Npc, NPCFlags.VaultKeeper);
|
||||
if (!unit)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageUnlock - {0} not found or player can't interact with it.", unlockVoidStorage.Npc.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPlayer().IsVoidStorageUnlocked())
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageUnlock - Player({0}, name: {1}) tried to unlock void storage a 2nd time.", GetPlayer().GetGUID().ToString(), GetPlayer().GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().ModifyMoney(-SharedConst.VoidStorageUnlockCost);
|
||||
GetPlayer().UnlockVoidStorage();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.QueryVoidStorage)]
|
||||
void HandleVoidStorageQuery(QueryVoidStorage queryVoidStorage)
|
||||
{
|
||||
Player player = GetPlayer();
|
||||
|
||||
Creature unit = player.GetNPCIfCanInteractWith(queryVoidStorage.Npc, NPCFlags.Transmogrifier | NPCFlags.VaultKeeper);
|
||||
if (!unit)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageQuery - {0} not found or player can't interact with it.", queryVoidStorage.Npc.ToString());
|
||||
SendPacket(new VoidStorageFailed());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetPlayer().IsVoidStorageUnlocked())
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageQuery - {0} name: {1} queried void storage without unlocking it.", player.GetGUID().ToString(), player.GetName());
|
||||
SendPacket(new VoidStorageFailed());
|
||||
return;
|
||||
}
|
||||
|
||||
byte count = 0;
|
||||
for (byte i = 0; i < SharedConst.VoidStorageMaxSlot; ++i)
|
||||
if (player.GetVoidStorageItem(i) != null)
|
||||
++count;
|
||||
|
||||
VoidStorageContents voidStorageContents = new VoidStorageContents();
|
||||
for (byte i = 0; i < SharedConst.VoidStorageMaxSlot; ++i)
|
||||
{
|
||||
VoidStorageItem item = player.GetVoidStorageItem(i);
|
||||
if (item == null)
|
||||
continue;
|
||||
|
||||
VoidItem voidItem = new VoidItem();
|
||||
voidItem.Guid = ObjectGuid.Create(HighGuid.Item, item.ItemId);
|
||||
voidItem.Creator = item.CreatorGuid;
|
||||
voidItem.Slot = i;
|
||||
voidItem.Item = new ItemInstance(item);
|
||||
|
||||
voidStorageContents.Items.Add(voidItem);
|
||||
}
|
||||
|
||||
SendPacket(voidStorageContents);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.VoidStorageTransfer)]
|
||||
void HandleVoidStorageTransfer(VoidStorageTransfer voidStorageTransfer)
|
||||
{
|
||||
Player player = GetPlayer();
|
||||
|
||||
Creature unit = player.GetNPCIfCanInteractWith(voidStorageTransfer.Npc, NPCFlags.VaultKeeper);
|
||||
if (!unit)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageTransfer - {0} not found or player can't interact with it.", voidStorageTransfer.Npc.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.IsVoidStorageUnlocked())
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageTransfer - Player ({0}, name: {1}) queried void storage without unlocking it.", player.GetGUID().ToString(), player.GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (voidStorageTransfer.Deposits.Length > player.GetNumOfVoidStorageFreeSlots())
|
||||
{
|
||||
SendVoidStorageTransferResult(VoidTransferError.Full);
|
||||
return;
|
||||
}
|
||||
|
||||
uint freeBagSlots = 0;
|
||||
if (!voidStorageTransfer.Withdrawals.Empty())
|
||||
{
|
||||
// make this a Player function
|
||||
for (byte i = InventorySlots.BagStart; i < InventorySlots.BagEnd; i++)
|
||||
{
|
||||
Bag bag = player.GetBagByPos(i);
|
||||
if (bag)
|
||||
freeBagSlots += bag.GetFreeSlots();
|
||||
}
|
||||
for (byte i = InventorySlots.ItemStart; i < InventorySlots.ItemEnd; i++)
|
||||
{
|
||||
if (!player.GetItemByPos(InventorySlots.Bag0, i))
|
||||
++freeBagSlots;
|
||||
}
|
||||
}
|
||||
|
||||
if (voidStorageTransfer.Withdrawals.Length > freeBagSlots)
|
||||
{
|
||||
SendVoidStorageTransferResult(VoidTransferError.InventoryFull);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.HasEnoughMoney((voidStorageTransfer.Deposits.Length * SharedConst.VoidStorageStoreItemCost)))
|
||||
{
|
||||
SendVoidStorageTransferResult(VoidTransferError.NotEnoughMoney);
|
||||
return;
|
||||
}
|
||||
|
||||
VoidStorageTransferChanges voidStorageTransferChanges = new VoidStorageTransferChanges();
|
||||
|
||||
byte depositCount = 0;
|
||||
for (int i = 0; i < voidStorageTransfer.Deposits.Length; ++i)
|
||||
{
|
||||
Item item = player.GetItemByGuid(voidStorageTransfer.Deposits[i]);
|
||||
if (!item)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageTransfer - {0} {1} wants to deposit an invalid item ({2}).", player.GetGUID().ToString(), player.GetName(), voidStorageTransfer.Deposits[i].ToString());
|
||||
continue;
|
||||
}
|
||||
|
||||
VoidStorageItem itemVS = new VoidStorageItem(Global.ObjectMgr.GenerateVoidStorageItemId(), item.GetEntry(), item.GetGuidValue(ItemFields.Creator),
|
||||
item.GetItemRandomEnchantmentId(), item.GetItemSuffixFactor(), item.GetModifier(ItemModifier.UpgradeId),
|
||||
item.GetModifier(ItemModifier.ScalingStatDistributionFixedLevel), item.GetModifier(ItemModifier.ArtifactKnowledgeLevel),
|
||||
(byte)item.GetUInt32Value(ItemFields.Context), item.GetDynamicValues(ItemDynamicFields.BonusListIds));
|
||||
|
||||
VoidItem voidItem;
|
||||
voidItem.Guid = ObjectGuid.Create(HighGuid.Item, itemVS.ItemId);
|
||||
voidItem.Creator = item.GetGuidValue(ItemFields.Creator);
|
||||
voidItem.Item = new ItemInstance(itemVS);
|
||||
voidItem.Slot = _player.AddVoidStorageItem(itemVS);
|
||||
|
||||
voidStorageTransferChanges.AddedItems.Add(voidItem);
|
||||
|
||||
player.DestroyItem(item.GetBagSlot(), item.GetSlot(), true);
|
||||
++depositCount;
|
||||
}
|
||||
|
||||
long cost = depositCount * SharedConst.VoidStorageStoreItemCost;
|
||||
|
||||
player.ModifyMoney(-cost);
|
||||
|
||||
for (int i = 0; i < voidStorageTransfer.Withdrawals.Length; ++i)
|
||||
{
|
||||
byte slot;
|
||||
VoidStorageItem itemVS = player.GetVoidStorageItem(voidStorageTransfer.Withdrawals[i].GetCounter(), out slot);
|
||||
if (itemVS == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageTransfer - {0} {1} tried to withdraw an invalid item ({2})", player.GetGUID().ToString(), player.GetName(), voidStorageTransfer.Withdrawals[i].ToString());
|
||||
continue;
|
||||
}
|
||||
|
||||
List<ItemPosCount> dest = new List<ItemPosCount>();
|
||||
InventoryResult msg = player.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, itemVS.ItemEntry, 1);
|
||||
if (msg != InventoryResult.Ok)
|
||||
{
|
||||
SendVoidStorageTransferResult(VoidTransferError.InventoryFull);
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageTransfer - {0} {1} couldn't withdraw {2} because inventory was full.", player.GetGUID().ToString(), player.GetName(), voidStorageTransfer.Withdrawals[i].ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
Item item = player.StoreNewItem(dest, itemVS.ItemEntry, true, itemVS.ItemRandomPropertyId, null, itemVS.Context, itemVS.BonusListIDs);
|
||||
item.SetUInt32Value(ItemFields.PropertySeed, itemVS.ItemSuffixFactor);
|
||||
item.SetGuidValue(ItemFields.Creator, itemVS.CreatorGuid);
|
||||
item.SetModifier(ItemModifier.UpgradeId, itemVS.ItemUpgradeId);
|
||||
item.SetBinding(true);
|
||||
GetCollectionMgr().AddItemAppearance(item);
|
||||
|
||||
voidStorageTransferChanges.RemovedItems.Add(ObjectGuid.Create(HighGuid.Item, itemVS.ItemId));
|
||||
|
||||
player.DeleteVoidStorageItem(slot);
|
||||
}
|
||||
|
||||
SendPacket(voidStorageTransferChanges);
|
||||
SendVoidStorageTransferResult(VoidTransferError.Ok);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SwapVoidItem)]
|
||||
void HandleVoidSwapItem(SwapVoidItem swapVoidItem)
|
||||
{
|
||||
Player player = GetPlayer();
|
||||
|
||||
Creature unit = player.GetNPCIfCanInteractWith(swapVoidItem.Npc, NPCFlags.VaultKeeper);
|
||||
if (!unit)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidSwapItem - {0} not found or player can't interact with it.", swapVoidItem.Npc.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.IsVoidStorageUnlocked())
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidSwapItem - Player ({0}, name: {1}) queried void storage without unlocking it.", player.GetGUID().ToString(), player.GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
byte oldSlot;
|
||||
if (player.GetVoidStorageItem(swapVoidItem.VoidItemGuid.GetCounter(), out oldSlot) == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidSwapItem - Player (GUID: {0}, name: {1}) requested swapping an invalid item (slot: {2}, itemid: {3}).", player.GetGUID().ToString(), player.GetName(), swapVoidItem.DstSlot, swapVoidItem.VoidItemGuid.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
bool usedDestSlot = player.GetVoidStorageItem((byte)swapVoidItem.DstSlot) != null;
|
||||
ObjectGuid itemIdDest = ObjectGuid.Empty;
|
||||
if (usedDestSlot)
|
||||
itemIdDest = ObjectGuid.Create(HighGuid.Item, player.GetVoidStorageItem((byte)swapVoidItem.DstSlot).ItemId);
|
||||
|
||||
if (!player.SwapVoidStorageItem(oldSlot, (byte)swapVoidItem.DstSlot))
|
||||
{
|
||||
SendVoidStorageTransferResult(VoidTransferError.InternalError1);
|
||||
return;
|
||||
}
|
||||
|
||||
VoidItemSwapResponse voidItemSwapResponse = new VoidItemSwapResponse();
|
||||
voidItemSwapResponse.VoidItemA = swapVoidItem.VoidItemGuid;
|
||||
voidItemSwapResponse.VoidItemSlotA = swapVoidItem.DstSlot;
|
||||
if (usedDestSlot)
|
||||
{
|
||||
voidItemSwapResponse.VoidItemB = itemIdDest;
|
||||
voidItemSwapResponse.VoidItemSlotB = oldSlot;
|
||||
}
|
||||
|
||||
SendPacket(voidItemSwapResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user