예제 #1
0
        void HandleSocketGems(SocketGems socketGems)
        {
            if (socketGems.ItemGuid.IsEmpty())
            {
                return;
            }

            //cheat . tried to socket same gem multiple times
            if ((!socketGems.GemItem[0].IsEmpty() && (socketGems.GemItem[0] == socketGems.GemItem[1] || socketGems.GemItem[0] == socketGems.GemItem[2])) ||
                (!socketGems.GemItem[1].IsEmpty() && (socketGems.GemItem[1] == socketGems.GemItem[2])))
            {
                return;
            }

            Item itemTarget = GetPlayer().GetItemByGuid(socketGems.ItemGuid);

            if (!itemTarget)                                         //missing item to socket
            {
                return;
            }

            ItemTemplate itemProto = itemTarget.GetTemplate();

            if (itemProto == null)
            {
                return;
            }

            //this slot is excepted when applying / removing meta gem bonus
            byte slot = itemTarget.IsEquipped() ? itemTarget.GetSlot() : ItemConst.NullSlot;

            Item[] gems = new Item[ItemConst.MaxGemSockets];
            ItemDynamicFieldGems[] gemData       = new ItemDynamicFieldGems[ItemConst.MaxGemSockets];
            GemPropertiesRecord[]  gemProperties = new GemPropertiesRecord[ItemConst.MaxGemSockets];
            SocketedGem[]          oldGemData    = new SocketedGem[ItemConst.MaxGemSockets];


            for (int i = 0; i < ItemConst.MaxGemSockets; ++i)
            {
                Item gem = _player.GetItemByGuid(socketGems.GemItem[i]);
                if (gem)
                {
                    gems[i]            = gem;
                    gemData[i].ItemId  = gem.GetEntry();
                    gemData[i].Context = (byte)gem.m_itemData.Context;
                    for (int b = 0; b < ((List <uint>)gem.m_itemData.BonusListIDs).Count && b < 16; ++b)
                    {
                        gemData[i].BonusListIDs[b] = (ushort)((List <uint>)gem.m_itemData.BonusListIDs)[b];
                    }

                    gemProperties[i] = CliDB.GemPropertiesStorage.LookupByKey(gem.GetTemplate().GetGemProperties());
                }

                oldGemData[i] = itemTarget.GetGem((ushort)i);
            }

            // Find first prismatic socket
            uint firstPrismatic = 0;

            while (firstPrismatic < ItemConst.MaxGemSockets && itemTarget.GetSocketColor(firstPrismatic) != 0)
            {
                ++firstPrismatic;
            }

            for (uint i = 0; i < ItemConst.MaxGemSockets; ++i)                //check for hack maybe
            {
                if (gemProperties[i] == null)
                {
                    continue;
                }

                // tried to put gem in socket where no socket exists (take care about prismatic sockets)
                if (itemTarget.GetSocketColor(i) == 0)
                {
                    // no prismatic socket
                    if (itemTarget.GetEnchantmentId(EnchantmentSlot.Prismatic) == 0)
                    {
                        return;
                    }

                    if (i != firstPrismatic)
                    {
                        return;
                    }
                }

                // Gem must match socket color
                if (ItemConst.SocketColorToGemTypeMask[(int)itemTarget.GetSocketColor(i)] != gemProperties[i].Type)
                {
                    // unless its red, blue, yellow or prismatic
                    if (!ItemConst.SocketColorToGemTypeMask[(int)itemTarget.GetSocketColor(i)].HasAnyFlag(SocketColor.Prismatic) || !gemProperties[i].Type.HasAnyFlag(SocketColor.Prismatic))
                    {
                        return;
                    }
                }
            }

            // check unique-equipped conditions
            for (int i = 0; i < ItemConst.MaxGemSockets; ++i)
            {
                if (!gems[i])
                {
                    continue;
                }

                // continue check for case when attempt add 2 similar unique equipped gems in one item.
                ItemTemplate iGemProto = gems[i].GetTemplate();

                // unique item (for new and already placed bit removed enchantments
                if (iGemProto.HasFlag(ItemFlags.UniqueEquippable))
                {
                    for (int j = 0; j < ItemConst.MaxGemSockets; ++j)
                    {
                        if (i == j)                                    // skip self
                        {
                            continue;
                        }

                        if (gems[j])
                        {
                            if (iGemProto.GetId() == gems[j].GetEntry())
                            {
                                GetPlayer().SendEquipError(InventoryResult.ItemUniqueEquippableSocketed, itemTarget);
                                return;
                            }
                        }
                        else if (oldGemData[j] != null)
                        {
                            if (iGemProto.GetId() == oldGemData[j].ItemId)
                            {
                                GetPlayer().SendEquipError(InventoryResult.ItemUniqueEquippableSocketed, itemTarget);
                                return;
                            }
                        }
                    }
                }

                // unique limit type item
                int limit_newcount = 0;
                if (iGemProto.GetItemLimitCategory() != 0)
                {
                    ItemLimitCategoryRecord limitEntry = CliDB.ItemLimitCategoryStorage.LookupByKey(iGemProto.GetItemLimitCategory());
                    if (limitEntry != null)
                    {
                        // NOTE: limitEntry.mode is not checked because if item has limit then it is applied in equip case
                        for (int j = 0; j < ItemConst.MaxGemSockets; ++j)
                        {
                            if (gems[j])
                            {
                                // new gem
                                if (iGemProto.GetItemLimitCategory() == gems[j].GetTemplate().GetItemLimitCategory())
                                {
                                    ++limit_newcount;
                                }
                            }
                            else if (oldGemData[j] != null)
                            {
                                // existing gem
                                ItemTemplate jProto = Global.ObjectMgr.GetItemTemplate(oldGemData[j].ItemId);
                                if (jProto != null)
                                {
                                    if (iGemProto.GetItemLimitCategory() == jProto.GetItemLimitCategory())
                                    {
                                        ++limit_newcount;
                                    }
                                }
                            }
                        }

                        if (limit_newcount > 0 && limit_newcount > _player.GetItemLimitCategoryQuantity(limitEntry))
                        {
                            GetPlayer().SendEquipError(InventoryResult.ItemUniqueEquippableSocketed, itemTarget);
                            return;
                        }
                    }
                }

                // for equipped item check all equipment for duplicate equipped gems
                if (itemTarget.IsEquipped())
                {
                    InventoryResult res = GetPlayer().CanEquipUniqueItem(gems[i], slot, (uint)Math.Max(limit_newcount, 0));
                    if (res != 0)
                    {
                        GetPlayer().SendEquipError(res, itemTarget);
                        return;
                    }
                }
            }

            bool SocketBonusActivated = itemTarget.GemsFitSockets();   //save state of socketbonus

            GetPlayer().ToggleMetaGemsActive(slot, false);             //turn off all metagems (except for the target item)

            //if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met

            //remove ALL mods - gem can change item level
            if (itemTarget.IsEquipped())
            {
                _player._ApplyItemMods(itemTarget, itemTarget.GetSlot(), false);
            }

            for (ushort i = 0; i < ItemConst.MaxGemSockets; ++i)
            {
                if (gems[i])
                {
                    uint gemScalingLevel = _player.GetLevel();
                    uint fixedLevel      = gems[i].GetModifier(ItemModifier.TimewalkerLevel);
                    if (fixedLevel != 0)
                    {
                        gemScalingLevel = fixedLevel;
                    }

                    itemTarget.SetGem(i, gemData[i], gemScalingLevel);

                    if (gemProperties[i] != null && gemProperties[i].EnchantId != 0)
                    {
                        itemTarget.SetEnchantment(EnchantmentSlot.Sock1 + i, gemProperties[i].EnchantId, 0, 0, GetPlayer().GetGUID());
                    }

                    uint gemCount = 1;
                    GetPlayer().DestroyItemCount(gems[i], ref gemCount, true);
                }
            }

            if (itemTarget.IsEquipped())
            {
                _player._ApplyItemMods(itemTarget, itemTarget.GetSlot(), true);
            }

            Item childItem = _player.GetChildItemByGuid(itemTarget.GetChildItem());

            if (childItem)
            {
                if (childItem.IsEquipped())
                {
                    _player._ApplyItemMods(childItem, childItem.GetSlot(), false);
                }
                childItem.CopyArtifactDataFromParent(itemTarget);
                if (childItem.IsEquipped())
                {
                    _player._ApplyItemMods(childItem, childItem.GetSlot(), true);
                }
            }

            bool SocketBonusToBeActivated = itemTarget.GemsFitSockets(); //current socketbonus state

            if (SocketBonusActivated ^ SocketBonusToBeActivated)         //if there was a change...
            {
                GetPlayer().ApplyEnchantment(itemTarget, EnchantmentSlot.Bonus, false);
                itemTarget.SetEnchantment(EnchantmentSlot.Bonus, SocketBonusToBeActivated ? itemTarget.GetTemplate().GetSocketBonus() : 0, 0, 0, GetPlayer().GetGUID());
                GetPlayer().ApplyEnchantment(itemTarget, EnchantmentSlot.Bonus, true);
                //it is not displayed, client has an inbuilt system to determine if the bonus is activated
            }

            GetPlayer().ToggleMetaGemsActive(slot, true);              //turn on all metagems (except for target item)

            GetPlayer().RemoveTradeableItem(itemTarget);
            itemTarget.ClearSoulboundTradeable(GetPlayer());           // clear tradeable flag

            itemTarget.SendUpdateSockets();
        }
예제 #2
0
        void HandleUseItem(UseItem packet)
        {
            Player user = GetPlayer();

            // ignore for remote control state
            if (user.GetUnitBeingMoved() != user)
            {
                return;
            }

            Item item = user.GetUseableItemByPos(packet.PackSlot, packet.Slot);

            if (item == null)
            {
                user.SendEquipError(InventoryResult.ItemNotFound);
                return;
            }

            if (item.GetGUID() != packet.CastItem)
            {
                user.SendEquipError(InventoryResult.ItemNotFound);
                return;
            }

            ItemTemplate proto = item.GetTemplate();

            if (proto == null)
            {
                user.SendEquipError(InventoryResult.ItemNotFound, item);
                return;
            }

            // some item classes can be used only in equipped state
            if (proto.GetInventoryType() != InventoryType.NonEquip && !item.IsEquipped())
            {
                user.SendEquipError(InventoryResult.ItemNotFound, item);
                return;
            }

            InventoryResult msg = user.CanUseItem(item);

            if (msg != InventoryResult.Ok)
            {
                user.SendEquipError(msg, item);
                return;
            }

            // only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB)
            if (proto.GetClass() == ItemClass.Consumable && !proto.HasFlag(ItemFlags.IgnoreDefaultArenaRestrictions) && user.InArena())
            {
                user.SendEquipError(InventoryResult.NotDuringArenaMatch, item);
                return;
            }

            // don't allow items banned in arena
            if (proto.HasFlag(ItemFlags.NotUseableInArena) && user.InArena())
            {
                user.SendEquipError(InventoryResult.NotDuringArenaMatch, item);
                return;
            }

            if (user.IsInCombat())
            {
                foreach (ItemEffectRecord effect in item.GetEffects())
                {
                    SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)effect.SpellID, user.GetMap().GetDifficultyID());
                    if (spellInfo != null)
                    {
                        if (!spellInfo.CanBeUsedInCombat())
                        {
                            user.SendEquipError(InventoryResult.NotInCombat, item);
                            return;
                        }
                    }
                }
            }

            // check also  BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory)
            if (item.GetBonding() == ItemBondingType.OnUse || item.GetBonding() == ItemBondingType.OnAcquire || item.GetBonding() == ItemBondingType.Quest)
            {
                if (!item.IsSoulBound())
                {
                    item.SetState(ItemUpdateState.Changed, user);
                    item.SetBinding(true);
                    GetCollectionMgr().AddItemAppearance(item);
                }
            }

            user.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ItemUse);

            SpellCastTargets targets = new(user, packet.Cast);

            // Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state.
            if (!Global.ScriptMgr.OnItemUse(user, item, targets, packet.Cast.CastID))
            {
                // no script or script not process request by self
                user.CastItemUseSpell(item, targets, packet.Cast.CastID, packet.Cast.Misc);
            }
        }
예제 #3
0
        void HandleOpenItem(OpenItem packet)
        {
            Player player = GetPlayer();

            // ignore for remote control state
            if (player.GetUnitBeingMoved() != player)
            {
                return;
            }

            // additional check, client outputs message on its own
            if (!player.IsAlive())
            {
                player.SendEquipError(InventoryResult.PlayerDead);
                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.HasFlag(ItemFlags.HasLoot) && !item.IsWrapped())
            {
                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.IsWrapped())// wrapped?
            {
                PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_GIFT_BY_ITEM);
                stmt.AddValue(0, item.GetGUID().GetCounter());
                _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt)
                                            .WithCallback(result => HandleOpenWrappedItemCallback(item.GetPos(), item.GetGUID(), result)));
            }
            else
            {
                player.SendLoot(item.GetGUID(), LootType.Corpse);
            }
        }
예제 #4
0
        public void SendListInventory(ObjectGuid vendorGuid)
        {
            Creature vendor = GetPlayer().GetNPCIfCanInteractWith(vendorGuid, NPCFlags.Vendor, NPCFlags2.None);

            if (vendor == null)
            {
                Log.outDebug(LogFilter.Network, "WORLD: SendListInventory - {0} not found or you can not interact with him.", vendorGuid.ToString());
                GetPlayer().SendSellError(SellResult.CantFindVendor, null, ObjectGuid.Empty);
                return;
            }

            // remove fake death
            if (GetPlayer().HasUnitState(UnitState.Died))
            {
                GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
            }

            // Stop the npc if moving
            vendor.PauseMovement(WorldConfig.GetUIntValue(WorldCfg.CreatureStopForPlayer));
            vendor.SetHomePosition(vendor.GetPosition());

            VendorItemData vendorItems  = vendor.GetVendorItems();
            int            rawItemCount = vendorItems != null?vendorItems.GetItemCount() : 0;

            VendorInventory packet = new();

            packet.Vendor = vendor.GetGUID();

            float discountMod = GetPlayer().GetReputationPriceDiscount(vendor);
            byte  count       = 0;

            for (uint slot = 0; slot < rawItemCount; ++slot)
            {
                VendorItem vendorItem = vendorItems.GetItem(slot);
                if (vendorItem == null)
                {
                    continue;
                }

                VendorItemPkt item = new();

                PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(vendorItem.PlayerConditionId);
                if (playerCondition != null)
                {
                    if (!ConditionManager.IsPlayerMeetingCondition(_player, playerCondition))
                    {
                        item.PlayerConditionFailed = (int)playerCondition.Id;
                    }
                }

                if (vendorItem.Type == ItemVendorType.Item)
                {
                    ItemTemplate itemTemplate = Global.ObjectMgr.GetItemTemplate(vendorItem.item);
                    if (itemTemplate == null)
                    {
                        continue;
                    }

                    int leftInStock = vendorItem.maxcount == 0 ? -1 : (int)vendor.GetVendorItemCurrentCount(vendorItem);
                    if (!GetPlayer().IsGameMaster())
                    {
                        if (!Convert.ToBoolean(itemTemplate.GetAllowableClass() & GetPlayer().GetClassMask()) && itemTemplate.GetBonding() == ItemBondingType.OnAcquire)
                        {
                            continue;
                        }

                        if ((itemTemplate.HasFlag(ItemFlags2.FactionHorde) && GetPlayer().GetTeam() == Team.Alliance) ||
                            (itemTemplate.HasFlag(ItemFlags2.FactionAlliance) && GetPlayer().GetTeam() == Team.Horde))
                        {
                            continue;
                        }

                        if (leftInStock == 0)
                        {
                            continue;
                        }
                    }

                    if (!Global.ConditionMgr.IsObjectMeetingVendorItemConditions(vendor.GetEntry(), vendorItem.item, _player, vendor))
                    {
                        Log.outDebug(LogFilter.Condition, "SendListInventory: conditions not met for creature entry {0} item {1}", vendor.GetEntry(), vendorItem.item);
                        continue;
                    }

                    int price = (int)(vendorItem.IsGoldRequired(itemTemplate) ? Math.Floor(itemTemplate.GetBuyPrice() * discountMod) : 0);

                    int priceMod = GetPlayer().GetTotalAuraModifier(AuraType.ModVendorItemsPrices);
                    if (priceMod != 0)
                    {
                        price -= MathFunctions.CalculatePct(price, priceMod);
                    }

                    item.MuID                = (int)slot + 1;
                    item.Durability          = (int)itemTemplate.MaxDurability;
                    item.ExtendedCostID      = (int)vendorItem.ExtendedCost;
                    item.Type                = (int)vendorItem.Type;
                    item.Quantity            = leftInStock;
                    item.StackCount          = (int)itemTemplate.GetBuyCount();
                    item.Price               = (ulong)price;
                    item.DoNotFilterOnVendor = vendorItem.IgnoreFiltering;
                    item.Refundable          = itemTemplate.HasFlag(ItemFlags.ItemPurchaseRecord) && vendorItem.ExtendedCost != 0 && itemTemplate.GetMaxStackSize() == 1;

                    item.Item.ItemID = vendorItem.item;
                    if (!vendorItem.BonusListIDs.Empty())
                    {
                        item.Item.ItemBonus.Value = new();
                        item.Item.ItemBonus.Value.BonusListIDs = vendorItem.BonusListIDs;
                    }

                    packet.Items.Add(item);
                }
                else if (vendorItem.Type == ItemVendorType.Currency)
                {
                    CurrencyTypesRecord currencyTemplate = CliDB.CurrencyTypesStorage.LookupByKey(vendorItem.item);
                    if (currencyTemplate == null)
                    {
                        continue;
                    }

                    if (vendorItem.ExtendedCost == 0)
                    {
                        continue;                             // there's no price defined for currencies, only extendedcost is used
                    }
                    item.MuID                = (int)slot + 1; // client expects counting to start at 1
                    item.ExtendedCostID      = (int)vendorItem.ExtendedCost;
                    item.Item.ItemID         = vendorItem.item;
                    item.Type                = (int)vendorItem.Type;
                    item.StackCount          = (int)vendorItem.maxcount;
                    item.DoNotFilterOnVendor = vendorItem.IgnoreFiltering;

                    packet.Items.Add(item);
                }
                else
                {
                    continue;
                }

                if (++count >= SharedConst.MaxVendorItems)
                {
                    break;
                }
            }

            packet.Reason = (byte)(count != 0 ? VendorInventoryReason.None : VendorInventoryReason.Empty);

            SendPacket(packet);
        }
예제 #5
0
        public void DoLootRelease(ObjectGuid lguid)
        {
            Player player = GetPlayer();
            Loot   loot;

            if (player.GetLootGUID() == lguid)
            {
                player.SetLootGUID(ObjectGuid.Empty);
            }

            player.SendLootRelease(lguid);
            player.RemoveAELootedWorldObject(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)))
                {
                    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 (pItem.loot.loot_type == LootType.Prospecting || pItem.loot.loot_type == LootType.Milling)
                {
                    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.HasFlag(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());
        }
예제 #6
0
        void HandleSendMail(SendMail packet)
        {
            if (packet.Info.Attachments.Count > SharedConst.MaxClientMailItems)                      // client limit
            {
                GetPlayer().SendMailResult(0, MailResponseType.Send, MailResponseResult.TooManyAttachments);
                return;
            }

            if (!CanOpenMailBox(packet.Info.Mailbox))
            {
                return;
            }

            if (string.IsNullOrEmpty(packet.Info.Target))
            {
                return;
            }

            if (!ValidateHyperlinksAndMaybeKick(packet.Info.Subject) || !ValidateHyperlinksAndMaybeKick(packet.Info.Body))
            {
                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;

            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.HasFlag(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();

            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().HasFlag(ItemFlags.Conjured) || item.m_itemData.Expiration != 0)
                {
                    player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.MailBoundItem);
                    return;
                }

                if (packet.Info.Cod != 0 && item.IsWrapped())
                {
                    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(CriteriaType.MoneySpentOnPostage, cost);

            bool needItemDelay = false;

            MailDraft draft = new(packet.Info.Subject, packet.Info.Body);

            SQLTransaction trans = new();

            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);
        }