Пример #1
0
        void HandleUseCritterItem(UseCritterItem useCritterItem)
        {
            Item item = GetPlayer().GetItemByGuid(useCritterItem.ItemGuid);

            if (!item)
            {
                return;
            }

            foreach (var itemEffect in item.GetEffects())
            {
                if (itemEffect.TriggerType != ItemSpelltriggerType.LearnSpellId)
                {
                    continue;
                }

                var speciesEntry = Global.SpellMgr.GetBattlePetSpecies((uint)itemEffect.SpellID);
                if (speciesEntry != null)
                {
                    GetBattlePetMgr().AddPet(speciesEntry.Id, BattlePetMgr.SelectPetDisplay(speciesEntry), BattlePetMgr.RollPetBreed(speciesEntry.Id), BattlePetMgr.GetDefaultPetQuality(speciesEntry.Id));
                }
            }

            GetPlayer().DestroyItem(item.GetBagSlot(), item.GetSlot(), true);
        }
Пример #2
0
        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);
            }
        }
Пример #3
0
        void HandleUseCritterItem(UseCritterItem useCritterItem)
        {
            Item item = GetPlayer().GetItemByGuid(useCritterItem.ItemGuid);

            if (!item)
            {
                return;
            }

            if (item.GetTemplate().Effects.Count < 2)
            {
                return;
            }

            uint spellToLearn = (uint)item.GetTemplate().Effects[1].SpellID;

            foreach (BattlePetSpeciesRecord entry in CliDB.BattlePetSpeciesStorage.Values)
            {
                if (entry.SummonSpellID == spellToLearn)
                {
                    GetBattlePetMgr().AddPet(entry.Id, entry.CreatureID, BattlePetMgr.RollPetBreed(entry.Id), BattlePetMgr.GetDefaultPetQuality(entry.Id));
                    _player.UpdateCriteria(CriteriaTypes.OwnBattlePetCount);
                    break;
                }
            }

            GetPlayer().DestroyItem(item.GetBagSlot(), item.GetSlot(), true);
        }
Пример #4
0
        void HandleUseCritterItem(UseCritterItem useCritterItem)
        {
            Item item = GetPlayer().GetItemByGuid(useCritterItem.ItemGuid);

            if (!item)
            {
                return;
            }

            if (item.GetBonus().EffectCount < 2)
            {
                return;
            }

            uint spellToLearn = (uint)item.GetEffect(1).SpellID;

            var entry = Global.SpellMgr.GetBattlePetSpecies(spellToLearn);

            if (entry != null)
            {
                GetBattlePetMgr().AddPet(entry.Id, entry.CreatureID, BattlePetMgr.RollPetBreed(entry.Id), BattlePetMgr.GetDefaultPetQuality(entry.Id));
                _player.UpdateCriteria(CriteriaTypes.OwnBattlePetCount);
            }

            GetPlayer().DestroyItem(item.GetBagSlot(), item.GetSlot(), true);
        }
Пример #5
0
        void HandleOpenWrappedItemCallback(ushort pos, ObjectGuid itemGuid, SQLResult result)
        {
            if (!GetPlayer())
            {
                return;
            }

            Item item = GetPlayer().GetItemByPos(pos);

            if (!item)
            {
                return;
            }

            if (item.GetGUID() != itemGuid || !item.IsWrapped()) // during getting result, gift was swapped with another item
            {
                return;
            }

            if (result.IsEmpty())
            {
                Log.outError(LogFilter.Network, $"Wrapped item {item.GetGUID()} don't have record in character_gifts table and will deleted");
                GetPlayer().DestroyItem(item.GetBagSlot(), item.GetSlot(), true);
                return;
            }

            SQLTransaction trans = new();

            uint entry = result.Read <uint>(0);
            uint flags = result.Read <uint>(1);

            item.SetGiftCreator(ObjectGuid.Empty);
            item.SetEntry(entry);
            item.SetItemFlags((ItemFieldFlags)flags);
            item.SetMaxDurability(item.GetTemplate().MaxDurability);
            item.SetState(ItemUpdateState.Changed, GetPlayer());

            GetPlayer().SaveInventoryAndGoldToDB(trans);

            PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_GIFT);

            stmt.AddValue(0, itemGuid.GetCounter());
            trans.Append(stmt);

            DB.Characters.CommitTransaction(trans);
        }
Пример #6
0
        void HandleTurnInPetition(TurnInPetition packet)
        {
            // Check if player really has the required petition charter
            Item item = GetPlayer().GetItemByGuid(packet.Item);

            if (!item)
            {
                return;
            }

            Petition petition = Global.PetitionMgr.GetPetition(packet.Item);

            if (petition == null)
            {
                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;
            }

            string name = petition.petitionName; // we need a copy, Guild::AddMember invalidates petition

            // Only the petition owner can turn in the petition
            if (GetPlayer().GetGUID() != petition.ownerGuid)
            {
                return;
            }

            TurnInPetitionResult resultPacket = new TurnInPetitionResult();

            // Check if player is already in a guild
            if (GetPlayer().GetGuildId() != 0)
            {
                resultPacket.Result = PetitionTurns.AlreadyInGuild;
                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;
            }

            var  signatures         = petition.signatures; // we need a copy, Guild::AddMember invalidates petition
            uint requiredSignatures = WorldConfig.GetUIntValue(WorldCfg.MinPetitionSigns);

            // Notify player if signatures are missing
            if (signatures.Count < 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);

            SQLTransaction trans = new SQLTransaction();

            // Add members from signatures
            foreach (var signature in signatures)
            {
                guild.AddMember(trans, signature.PlayerGuid);
            }

            DB.Characters.CommitTransaction(trans);

            Global.PetitionMgr.RemovePetition(packet.Item);

            // created
            Log.outDebug(LogFilter.Network, $"Player {GetPlayer().GetName()} ({GetPlayer().GetGUID()}) turning in petition {packet.Item}");

            resultPacket.Result = PetitionTurns.Ok;
            SendPacket(resultPacket);
        }
Пример #7
0
        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;
        }
Пример #8
0
        void HandleAutoEquipItem(AutoEquipItem autoEquipItem)
        {
            if (autoEquipItem.Inv.Items.Count != 1)
            {
                Log.outError(LogFilter.Network, "WORLD: HandleAutoEquipItem - Invalid itemCount ({0})", autoEquipItem.Inv.Items.Count);
                return;
            }

            var  pl      = GetPlayer();
            Item srcItem = pl.GetItemByPos(autoEquipItem.PackSlot, autoEquipItem.Slot);

            if (srcItem == null)
            {
                return;                                             // only at cheat
            }
            ushort          dest;
            InventoryResult msg = pl.CanEquipItem(ItemConst.NullSlot, out dest, srcItem, !srcItem.IsBag());

            if (msg != InventoryResult.Ok)
            {
                pl.SendEquipError(msg, srcItem);
                return;
            }

            ushort src = srcItem.GetPos();

            if (dest == src)                                           // prevent equip in same slot, only at cheat
            {
                return;
            }

            Item dstItem = pl.GetItemByPos(dest);

            if (dstItem == null)                                         // empty slot, simple case
            {
                if (!srcItem.GetChildItem().IsEmpty())
                {
                    InventoryResult childEquipResult = _player.CanEquipChildItem(srcItem);
                    if (childEquipResult != InventoryResult.Ok)
                    {
                        _player.SendEquipError(msg, srcItem);
                        return;
                    }
                }

                pl.RemoveItem(autoEquipItem.PackSlot, autoEquipItem.Slot, true);
                pl.EquipItem(dest, srcItem, true);
                if (!srcItem.GetChildItem().IsEmpty())
                {
                    _player.EquipChildItem(autoEquipItem.PackSlot, autoEquipItem.Slot, srcItem);
                }

                pl.AutoUnequipOffhandIfNeed();
            }
            else                                                    // have currently equipped item, not simple case
            {
                byte dstbag  = dstItem.GetBagSlot();
                byte dstslot = dstItem.GetSlot();

                msg = pl.CanUnequipItem(dest, !srcItem.IsBag());
                if (msg != InventoryResult.Ok)
                {
                    pl.SendEquipError(msg, dstItem);
                    return;
                }

                if (!dstItem.HasItemFlag(ItemFieldFlags.Child))
                {
                    // check dest.src move possibility
                    List <ItemPosCount> sSrc = new();
                    ushort eSrc = 0;
                    if (pl.IsInventoryPos(src))
                    {
                        msg = pl.CanStoreItem(autoEquipItem.PackSlot, autoEquipItem.Slot, sSrc, dstItem, true);
                        if (msg != InventoryResult.Ok)
                        {
                            msg = pl.CanStoreItem(autoEquipItem.PackSlot, ItemConst.NullSlot, sSrc, dstItem, true);
                        }
                        if (msg != InventoryResult.Ok)
                        {
                            msg = pl.CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, sSrc, dstItem, true);
                        }
                    }
                    else if (Player.IsBankPos(src))
                    {
                        msg = pl.CanBankItem(autoEquipItem.PackSlot, autoEquipItem.Slot, sSrc, dstItem, true);
                        if (msg != InventoryResult.Ok)
                        {
                            msg = pl.CanBankItem(autoEquipItem.PackSlot, ItemConst.NullSlot, sSrc, dstItem, true);
                        }
                        if (msg != InventoryResult.Ok)
                        {
                            msg = pl.CanBankItem(ItemConst.NullBag, ItemConst.NullSlot, sSrc, dstItem, true);
                        }
                    }
                    else if (Player.IsEquipmentPos(src))
                    {
                        msg = pl.CanEquipItem(autoEquipItem.Slot, out eSrc, dstItem, true);
                        if (msg == InventoryResult.Ok)
                        {
                            msg = pl.CanUnequipItem(eSrc, true);
                        }
                    }

                    if (msg == InventoryResult.Ok && Player.IsEquipmentPos(dest) && !srcItem.GetChildItem().IsEmpty())
                    {
                        msg = _player.CanEquipChildItem(srcItem);
                    }

                    if (msg != InventoryResult.Ok)
                    {
                        pl.SendEquipError(msg, dstItem, srcItem);
                        return;
                    }

                    // now do moves, remove...
                    pl.RemoveItem(dstbag, dstslot, false);
                    pl.RemoveItem(autoEquipItem.PackSlot, autoEquipItem.Slot, false);

                    // add to dest
                    pl.EquipItem(dest, srcItem, true);

                    // add to src
                    if (pl.IsInventoryPos(src))
                    {
                        pl.StoreItem(sSrc, dstItem, true);
                    }
                    else if (Player.IsBankPos(src))
                    {
                        pl.BankItem(sSrc, dstItem, true);
                    }
                    else if (Player.IsEquipmentPos(src))
                    {
                        pl.EquipItem(eSrc, dstItem, true);
                    }

                    if (Player.IsEquipmentPos(dest) && !srcItem.GetChildItem().IsEmpty())
                    {
                        _player.EquipChildItem(autoEquipItem.PackSlot, autoEquipItem.Slot, srcItem);
                    }
                }
                else
                {
                    Item parentItem = _player.GetItemByGuid(dstItem.GetCreator());
                    if (parentItem)
                    {
                        if (Player.IsEquipmentPos(dest))
                        {
                            _player.AutoUnequipChildItem(parentItem);
                            // dest is now empty
                            _player.SwapItem(src, dest);
                            // src is now empty
                            _player.SwapItem(parentItem.GetPos(), src);
                        }
                    }
                }

                pl.AutoUnequipOffhandIfNeed();

                // if inventory item was moved, check if we can remove dependent auras, because they were not removed in Player::RemoveItem (update was set to false)
                // do this after swaps are done, we pass nullptr because both weapons could be swapped and none of them should be ignored
                if ((autoEquipItem.PackSlot == InventorySlots.Bag0 && autoEquipItem.Slot < InventorySlots.BagEnd) || (dstbag == InventorySlots.Bag0 && dstslot < InventorySlots.BagEnd))
                {
                    pl.ApplyItemDependentAuras(null, false);
                }
            }
        }
Пример #9
0
        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());
        }
Пример #10
0
        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);
            }
        }
Пример #11
0
        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);
        }
Пример #12
0
        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();
                }
            }
        }
Пример #13
0
        void HandleVoidStorageTransfer(VoidStorageTransfer voidStorageTransfer)
        {
            Player player = GetPlayer();

            Creature unit = player.GetNPCIfCanInteractWith(voidStorageTransfer.Npc, NPCFlags.VaultKeeper, NPCFlags2.None);

            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();
                    }
                }
                int inventoryEnd = InventorySlots.ItemStart + _player.GetInventorySlotCount();
                for (byte i = InventorySlots.ItemStart; i < inventoryEnd; 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.GetCreator(),
                                                             item.GetItemRandomBonusListId(), item.GetModifier(ItemModifier.TimewalkerLevel), item.GetModifier(ItemModifier.ArtifactKnowledgeLevel),
                                                             item.GetContext(), item.m_itemData.BonusListIDs);

                VoidItem voidItem;
                voidItem.Guid    = ObjectGuid.Create(HighGuid.Item, itemVS.ItemId);
                voidItem.Creator = item.GetCreator();
                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.RandomBonusListId, null, itemVS.Context, itemVS.BonusListIDs);
                item.SetCreator(itemVS.CreatorGuid);
                item.SetBinding(true);
                GetCollectionMgr().AddItemAppearance(item);

                voidStorageTransferChanges.RemovedItems.Add(ObjectGuid.Create(HighGuid.Item, itemVS.ItemId));

                player.DeleteVoidStorageItem(slot);
            }

            SendPacket(voidStorageTransferChanges);
            SendVoidStorageTransferResult(VoidTransferError.Ok);
        }
Пример #14
0
        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
            stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_SIGNATURE);
            stmt.AddValue(0, packet.Item.GetCounter());
            result = DB.Characters.Query(stmt);

            List <ObjectGuid> guids = new List <ObjectGuid>();

            if (!result.IsEmpty())
            {
                do
                {
                    guids.Add(ObjectGuid.Create(HighGuid.Player, result.Read <ulong>(0)));
                }while (result.NextRow());
            }

            uint requiredSignatures = WorldConfig.GetUIntValue(WorldCfg.MinPetitionSigns);

            // Notify player if signatures are missing
            if (guids.Count < 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);

            SQLTransaction trans = new SQLTransaction();

            // Add members from signatures
            foreach (var guid in guids)
            {
                guild.AddMember(trans, guid);
            }

            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);
        }
Пример #15
0
        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);
        }