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(); 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); }
public void BuildAuctionInfo(List <AuctionItem> items, bool listAuctionItems) { Item item = Global.AuctionMgr.GetAItem(itemGUIDLow); if (!item) { Log.outError(LogFilter.Server, "AuctionEntry:BuildAuctionInfo: Auction {0} has a non-existent item: {1}", Id, itemGUIDLow); return; } AuctionItem auctionItem = new AuctionItem(); auctionItem.AuctionItemID = (int)Id; auctionItem.Item = new ItemInstance(item); auctionItem.BuyoutPrice = buyout; auctionItem.CensorBidInfo = false; auctionItem.CensorServerSideInfo = listAuctionItems; auctionItem.Charges = item.GetSpellCharges(); auctionItem.Count = (int)item.GetCount(); auctionItem.DeleteReason = 0; // Always 0 ? auctionItem.DurationLeft = (int)((expire_time - Time.UnixTime) * Time.InMilliseconds); auctionItem.EndTime = (uint)expire_time; auctionItem.Flags = 0; // todo auctionItem.ItemGuid = item.GetGUID(); auctionItem.MinBid = startbid; auctionItem.Owner = ObjectGuid.Create(HighGuid.Player, owner); auctionItem.OwnerAccountID = ObjectGuid.Create(HighGuid.WowAccount, Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(auctionItem.Owner)); auctionItem.MinIncrement = bidder != 0 ? GetAuctionOutBid() : 0; auctionItem.Bidder = bidder != 0 ? ObjectGuid.Create(HighGuid.Player, bidder) : ObjectGuid.Empty; auctionItem.BidAmount = bidder != 0 ? bid : 0; for (EnchantmentSlot c = 0; c < EnchantmentSlot.MaxInspected; c++) { if (item.GetEnchantmentId(c) == 0) { continue; } auctionItem.Enchantments.Add(new ItemEnchantData((int)item.GetEnchantmentId(c), item.GetEnchantmentDuration(c), (int)item.GetEnchantmentCharges(c), (byte)c)); } byte i = 0; foreach (SocketedGem gemData in item.m_itemData.Gems) { if (gemData.ItemId != 0) { ItemGemData gem = new ItemGemData(); gem.Slot = i; gem.Item = new ItemInstance(gemData); auctionItem.Gems.Add(gem); } ++i; } items.Add(auctionItem); }
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.GetGiftCreator(); if (!item.HasItemFlag(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.GetCreator(); unwrappedItem.Charges = item.GetSpellCharges(); unwrappedItem.Lock = item.GetTemplate().GetLockID() != 0 && !item.HasItemFlag(ItemFieldFlags.Unlocked); unwrappedItem.MaxDurability = item.m_itemData.MaxDurability; unwrappedItem.Durability = item.m_itemData.Durability; byte g = 0; foreach (SocketedGem gemData in item.m_itemData.Gems) { 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 HandleBuybackItem(BuyBackItem packet) { Creature creature = _player.GetNPCIfCanInteractWith(packet.VendorGUID, NPCFlags.Vendor, NPCFlags2.None); if (creature == null) { Log.outDebug(LogFilter.Network, "WORLD: HandleBuybackItem - {0} not found or you can not interact with him.", packet.VendorGUID.ToString()); _player.SendSellError(SellResult.CantFindVendor, null, ObjectGuid.Empty); return; } // remove fake death if (_player.HasUnitState(UnitState.Died)) { _player.RemoveAurasByType(AuraType.FeignDeath); } Item pItem = _player.GetItemFromBuyBackSlot(packet.Slot); if (pItem != null) { uint price = _player.m_activePlayerData.BuybackPrice[(int)(packet.Slot - InventorySlots.BuyBackStart)]; if (!_player.HasEnoughMoney(price)) { _player.SendBuyError(BuyResult.NotEnoughtMoney, creature, pItem.GetEntry()); return; } List <ItemPosCount> dest = new(); InventoryResult msg = _player.CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, dest, pItem, false); if (msg == InventoryResult.Ok) { _player.ModifyMoney(-price); _player.RemoveItemFromBuyBackSlot(packet.Slot, false); _player.ItemAddedQuestCheck(pItem.GetEntry(), pItem.GetCount()); _player.StoreItem(dest, pItem, true); } else { _player.SendEquipError(msg, pItem); } return; } else { _player.SendBuyError(BuyResult.CantFindItem, creature, 0); } }
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(); 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(); 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); } }
void HandleSellItem(SellItem packet) { if (packet.ItemGUID.IsEmpty()) { return; } var pl = GetPlayer(); Creature creature = pl.GetNPCIfCanInteractWith(packet.VendorGUID, NPCFlags.Vendor, NPCFlags2.None); if (creature == null) { Log.outDebug(LogFilter.Network, "WORLD: HandleSellItemOpcode - {0} not found or you can not interact with him.", packet.VendorGUID.ToString()); pl.SendSellError(SellResult.CantFindVendor, null, packet.ItemGUID); return; } if (creature.GetCreatureTemplate().FlagsExtra.HasFlag(CreatureFlagsExtra.NoSellVendor)) { _player.SendSellError(SellResult.CantSellToThisMerchant, creature, packet.ItemGUID); return; } // remove fake death if (pl.HasUnitState(UnitState.Died)) { pl.RemoveAurasByType(AuraType.FeignDeath); } Item pItem = pl.GetItemByGuid(packet.ItemGUID); if (pItem != null) { // prevent sell not owner item if (pl.GetGUID() != pItem.GetOwnerGUID()) { pl.SendSellError(SellResult.CantSellItem, creature, packet.ItemGUID); return; } // prevent sell non empty bag by drag-and-drop at vendor's item list if (pItem.IsNotEmptyBag()) { pl.SendSellError(SellResult.CantSellItem, creature, packet.ItemGUID); return; } // prevent sell currently looted item if (pl.GetLootGUID() == pItem.GetGUID()) { pl.SendSellError(SellResult.CantSellItem, creature, packet.ItemGUID); return; } // prevent selling item for sellprice when the item is still refundable // this probably happens when right clicking a refundable item, the client sends both // CMSG_SELL_ITEM and CMSG_REFUND_ITEM (unverified) if (pItem.IsRefundable()) { return; // Therefore, no feedback to client } // special case at auto sell (sell all) if (packet.Amount == 0) { packet.Amount = pItem.GetCount(); } else { // prevent sell more items that exist in stack (possible only not from client) if (packet.Amount > pItem.GetCount()) { pl.SendSellError(SellResult.CantSellItem, creature, packet.ItemGUID); return; } } ItemTemplate pProto = pItem.GetTemplate(); if (pProto != null) { if (pProto.GetSellPrice() > 0) { ulong money = pProto.GetSellPrice() * packet.Amount; if (!_player.ModifyMoney((long)money)) // ensure player doesn't exceed gold limit { _player.SendSellError(SellResult.CantSellItem, creature, packet.ItemGUID); return; } _player.UpdateCriteria(CriteriaType.MoneyEarnedFromSales, money); _player.UpdateCriteria(CriteriaType.SellItemsToVendors, 1); if (packet.Amount < pItem.GetCount()) // need split items { Item pNewItem = pItem.CloneItem(packet.Amount, pl); if (pNewItem == null) { Log.outError(LogFilter.Network, "WORLD: HandleSellItemOpcode - could not create clone of item {0}; count = {1}", pItem.GetEntry(), packet.Amount); pl.SendSellError(SellResult.CantSellItem, creature, packet.ItemGUID); return; } pItem.SetCount(pItem.GetCount() - packet.Amount); pl.ItemRemovedQuestCheck(pItem.GetEntry(), packet.Amount); if (pl.IsInWorld) { pItem.SendUpdateToPlayer(pl); } pItem.SetState(ItemUpdateState.Changed, pl); pl.AddItemToBuyBackSlot(pNewItem); if (pl.IsInWorld) { pNewItem.SendUpdateToPlayer(pl); } } else { pl.RemoveItem(pItem.GetBagSlot(), pItem.GetSlot(), true); pl.ItemRemovedQuestCheck(pItem.GetEntry(), pItem.GetCount()); Item.RemoveItemFromUpdateQueueOf(pItem, pl); pl.AddItemToBuyBackSlot(pItem); } } else { pl.SendSellError(SellResult.CantSellItem, creature, packet.ItemGUID); } return; } } pl.SendSellError(SellResult.CantSellItem, creature, packet.ItemGUID); return; }
public void DoLootRelease(ObjectGuid lguid) { Player player = GetPlayer(); Loot loot; if (player.GetLootGUID() == lguid) { player.SetLootGUID(ObjectGuid.Empty); } player.SendLootRelease(lguid); player.RemoveUnitFlag(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.GetGoValue().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.RemoveCorpseDynamicFlag(CorpseDynFlags.Lootable); } } 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.RemoveDynamicFlag(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.m_values.ModifyValue(creature.m_objectData).ModifyValue(creature.m_objectData.DynamicFlags); creature.ForceUpdateFieldChange(); } } } //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 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, NPCFlags2.None); 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; Item[] items = new Item[packet.Items.Count]; for (var i = 0; i < packet.Items.Count; ++i) { items[i] = GetPlayer().GetItemByGuid(packet.Items[i].Guid); if (!items[i]) { SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.ItemNotFound); return; } if (Global.AuctionMgr.GetAItem(items[i].GetGUID().GetCounter()) || !items[i].CanBeTraded() || items[i].IsNotEmptyBag() || items[i].GetTemplate().GetFlags().HasAnyFlag(ItemFlags.Conjured) || items[i].m_itemData.Expiration != 0 || items[i].GetCount() < packet.Items[i].UseCount) { SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError); return; } finalCount += packet.Items[i].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; } if (items[i].GetEntry() != items[j].GetEntry()) { SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.ItemNotFound); return; } } } for (var i = 0; i < packet.Items.Count; ++i) { if (items[i].GetMaxStackCount() < finalCount) { SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError); return; } } Item item = items[0]; 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); for (var i = 0; i < packet.Items.Count; ++i) { Item item2 = items[i]; // Item stack count equals required count, ready to delete item - cloned item will be used for auction if (item2.GetCount() == packet.Items[i].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() - packet.Items[i].UseCount); item2.SetState(ItemUpdateState.Changed, GetPlayer()); GetPlayer().ItemRemovedQuestCheck(item2.GetEntry(), packet.Items[i].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); }
public void SendAuctionWonMail(AuctionEntry auction, SQLTransaction trans) { Item item = GetAItem(auction.itemGUIDLow); if (!item) { return; } uint bidderAccId = 0; ObjectGuid bidderGuid = ObjectGuid.Create(HighGuid.Player, auction.bidder); Player bidder = Global.ObjAccessor.FindPlayer(bidderGuid); // data for gm.log string bidderName = ""; bool logGmTrade = false; if (bidder) { bidderAccId = bidder.GetSession().GetAccountId(); bidderName = bidder.GetName(); logGmTrade = bidder.GetSession().HasPermission(RBACPermissions.LogGmTrade); } else { bidderAccId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(bidderGuid); logGmTrade = Global.AccountMgr.HasPermission(bidderAccId, RBACPermissions.LogGmTrade, Global.WorldMgr.GetRealm().Id.Realm); if (logGmTrade && !Global.CharacterCacheStorage.GetCharacterNameByGuid(bidderGuid, out bidderName)) { bidderName = Global.ObjectMgr.GetCypherString(CypherStrings.Unknown); } } if (logGmTrade) { ObjectGuid ownerGuid = ObjectGuid.Create(HighGuid.Player, auction.owner); string ownerName; if (!Global.CharacterCacheStorage.GetCharacterNameByGuid(ownerGuid, out ownerName)) { ownerName = Global.ObjectMgr.GetCypherString(CypherStrings.Unknown); } uint ownerAccId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(ownerGuid); Log.outCommand(bidderAccId, $"GM {bidderName} (Account: {bidderAccId}) won item in auction: {item.GetTemplate().GetName()} (Entry: {item.GetEntry()} Count: {item.GetCount()}) and pay money: {auction.bid}. Original owner {ownerName} (Account: {ownerAccId})"); } // receiver exist if (bidder || bidderAccId != 0) { // set owner to bidder (to prevent delete item with sender char deleting) // owner in `data` will set at mail receive and item extracting PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ITEM_OWNER); stmt.AddValue(0, auction.bidder); stmt.AddValue(1, item.GetGUID().GetCounter()); trans.Append(stmt); if (bidder) { bidder.GetSession().SendAuctionWonNotification(auction, item); // FIXME: for offline player need also bidder.UpdateCriteria(CriteriaTypes.WonAuctions, 1); } new MailDraft(auction.BuildAuctionMailSubject(MailAuctionAnswers.Won), AuctionEntry.BuildAuctionMailBody(auction.owner, auction.bid, auction.buyout, 0, 0)) .AddItem(item) .SendMailTo(trans, new MailReceiver(bidder, auction.bidder), new MailSender(auction), MailCheckMask.Copied); } else { // bidder doesn't exist, delete the item Global.AuctionMgr.RemoveAItem(auction.itemGUIDLow, true); } }
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 = Global.CharacterCacheStorage.GetCharacterGuidByName(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; uint receiverBnetAccountId = 0; if (receiver) { receiverTeam = receiver.GetTeam(); mailsCount = (byte)receiver.GetMails().Count; receiverLevel = (byte)receiver.getLevel(); receiverAccountId = receiver.GetSession().GetAccountId(); receiverBnetAccountId = receiver.GetSession().GetBattlenetAccountId(); } else { CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(receiverGuid); if (characterInfo != null) { receiverTeam = Player.TeamForRace(characterInfo.RaceId); receiverLevel = characterInfo.Level; receiverAccountId = characterInfo.AccountId; } 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); } receiverBnetAccountId = Global.BNetAccountMgr.GetIdByGameAccount(receiverAccountId); } // 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) { if (!item.IsBattlenetAccountBound() || player.GetSession().GetBattlenetAccountId() == 0 || player.GetSession().GetBattlenetAccountId() != receiverBnetAccountId) { player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.NotSameAccount); return; } } if (item.GetTemplate().GetFlags().HasAnyFlag(ItemFlags.Conjured) || item.m_itemData.Expiration != 0) { player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.MailBoundItem); return; } if (packet.Info.Cod != 0 && item.HasItemFlag(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); }
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 = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(sender_guid); if (!Global.CharacterCacheStorage.GetCharacterNameByGuid(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 = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(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); } }