Beispiel #1
0
        public static bool HasSpace(Character pChar, int nItemID, short nAmount)
        {
            var nTI = ItemConstants.GetInventoryType(nItemID);

            if (nTI == InventoryType.Equip)
            {
                if (pChar.InventoryEquip.GetFreeSlot() > 0)
                {
                    return(true);
                }
            }
            else
            {
                var inv = GetInventory(pChar, nTI);

                if (inv.GetFreeSlot() > 0)
                {
                    return(true);
                }

                // determine if item can be merged in with existing slot
                {
                    var item = inv.Get(inv.FindItemSlot(nItemID));

                    if (item?.nNumber < nAmount + item?.SlotMax)
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
        public static MapleItem CreateItem(int itemId, string source, short quantity = 1, bool randomStats = false)
        {
            MapleInventoryType type = ItemConstants.GetInventoryType(itemId);

            if (type == MapleInventoryType.Equip)
            {
                WzEquip wzInfo = DataBuffer.GetEquipById(itemId);
                if (wzInfo != null)
                {
                    MapleEquip equip = new MapleEquip(itemId, source);
                    equip.SetDefaultStats(wzInfo, randomStats);
                    return(equip);
                }
            }
            else if (type != MapleInventoryType.Undefined)
            {
                WzItem wzInfo = DataBuffer.GetItemById(itemId);
                if (wzInfo != null)
                {
                    if (wzInfo.SlotMax > 0 && quantity > wzInfo.SlotMax)
                    {
                        quantity = (short)wzInfo.SlotMax;
                    }
                    MapleItem item = new MapleItem(itemId, source, quantity);
                    return(item);
                }
            }
            return(null);
        }
Beispiel #3
0
        public static GW_ItemSlotEquip CreateNormalStatEquip(int nItemID, long liCashItemSN = 0)
        {
            if (ItemConstants.GetInventoryType(nItemID) != InventoryType.Equip)
            {
                return(null);
            }

            var pItem = new GW_ItemSlotEquip(nItemID);

            pItem.niSTR   = (short)pItem.EquipTemplate.incSTR;
            pItem.niDEX   = (short)pItem.EquipTemplate.incDEX;
            pItem.niINT   = (short)pItem.EquipTemplate.incINT;
            pItem.niLUK   = (short)pItem.EquipTemplate.incLUK;
            pItem.niMaxHP = (short)pItem.EquipTemplate.incMHP;
            pItem.niMaxMP = (short)pItem.EquipTemplate.incMMP;
            pItem.niPAD   = (short)pItem.EquipTemplate.incPAD;
            pItem.niMAD   = (short)pItem.EquipTemplate.incMAD;
            pItem.niPDD   = (short)pItem.EquipTemplate.incPDD;
            pItem.niMDD   = (short)pItem.EquipTemplate.incMDD;
            pItem.niACC   = (short)pItem.EquipTemplate.incACC;
            pItem.niEVA   = (short)pItem.EquipTemplate.incEVA;
            pItem.niSpeed = (short)pItem.EquipTemplate.incSpeed;
            pItem.niJump  = (short)pItem.EquipTemplate.incJump;

            FinishEquip(pItem, liCashItemSN);

            return(pItem);
        }
Beispiel #4
0
        public static void UnEquip(Character pChar, short slotFrom, short slotTo)
        {
            //20:40:35[INFO] Recv[CP_UserChangeSlotPositionRequest] [4D 00] [1D A8 02 01] [01] [B3 FB] [01 00] [FF FF]
            //20:40:38[INFO] Recv[CP_UserChangeSlotPositionRequest] [4D 00] [7B B3 02 01] [01] [B3 FB] [01 00] [FF FF]

            var srcEquipInv = GetInventory(pChar, slotFrom);

            var source = srcEquipInv.GetKvp(slotFrom);

            if (slotTo != 0)             //Not dropping
            {
                if (!pChar.InventoryEquip.IsFreeSlot(slotTo))
                {
                    return;                                                           // PE
                }
            }

            if (!srcEquipInv.Remove(slotFrom))
            {
                return;                                            // false means they passed an empty slot
            }
            var pItem = source.Value;

            if (-slotFrom == (int)BodyPart.BP_SADDLE || -slotFrom == (int)BodyPart.BP_TAMINGMOB)
            {
                pChar.Buffs.Remove(pChar.Stats.SecondaryStats.rRideVehicle);
            }
            else
            {
                // taming stuff cant have option skills
                pChar.Skills.ModifyOptionSkills(pItem, false);
            }

            if (slotTo == 0)             //Dropping Item
            {
                pChar.Modify.Inventory(ctx =>
                {
                    ctx.Remove(InventoryType.Equip, slotFrom);
                });

                if (ItemConstants.GetInventoryType(pItem.nItemID) == InventoryType.Equip)
                {
                    CDropFactory.CreateDropItem(pChar.Field, pChar.Position.CurrentXY, pChar.dwId, pItem);
                }
                else
                {
                    //Should never happen????
                    pChar.SendMessage($"You unequipped and dropped a non-equip item. Please report to staff: {pItem.nItemID}");
                }
            }
            else             //Unequip to inventory
            {
                pChar.InventoryEquip.Add(slotTo, source.Value);

                pChar.Modify.Inventory(ctx =>
                {
                    ctx.Move(InventoryType.Equip, slotFrom, slotTo);
                });
            }
        }
Beispiel #5
0
        public void UseLotteryItem(short nPOS, int nItemID)
        {
            if (Parent.Stats.nHP <= 0)
            {
                return;
            }

            var pItemRaw = InventoryManipulator.GetItem(Parent, ItemConstants.GetInventoryType(nItemID), nPOS);             // TODO determine if we can hardcode the inventory type

            var itemResult = MasterManager.CreateItem(RandomBoxes.GetRandom(nItemID));

            if (itemResult != null && pItemRaw is GW_ItemSlotBundle pItem)
            {
                if (InventoryManipulator.CountFreeSlots(Parent, InventoryType.Equip) > 0 && InventoryManipulator.CountFreeSlots(Parent, InventoryType.Consume) > 0)
                {
                    InventoryManipulator.RemoveFrom(Parent, pItemRaw.InvType, nPOS);
                    InventoryManipulator.InsertInto(Parent, itemResult);
                }
                else
                {
                    Parent.SendMessage("Please make some room in your inventory.");
                }
            }
            else
            {
                Parent.SendMessage("This item has not been implemented yet. If you believe this to be an error, please report it on the discord server.");
            }
        }
Beispiel #6
0
 protected GW_ItemSlotBase(int nItemID)
 {
     this.nItemID   = nItemID;
     InvType        = ItemConstants.GetInventoryType(nItemID);
     IsRechargeable = ItemConstants.IsRechargeableItem(nItemID);
     IsArrow        = ItemConstants.IsArrow(nItemID);
 }
Beispiel #7
0
        private static void SellItem(Character pChar, short nSlot, int nItemId, short nCount)
        {
            var pItem = InventoryManipulator.GetItem(pChar, ItemConstants.GetInventoryType(nItemId), nSlot);

            if (pItem is null)
            {
                pChar.SendMessage("Trying to sell null item.");
                pChar.SendPacket(CPacket.CShopDlg.ShopResult(ShopRes.SellIncorrectRequest));
                return;
            }

            if (pItem.CashItem || pItem.NotSale)
            {
                pChar.SendMessage("Cannot trade cash items.");
                return;
            }

            var nCostPerItem = pItem.Template.Price;

            nCount = ItemConstants.is_treat_singly(nItemId) ? (short)1 : nCount;

            var nFinalCost = nCostPerItem * nCount;

            if (pItem.IsRechargeable)
            {
                var dUnitPrice = ((ConsumeItemTemplate)pItem.Template).UnitPrice;

                nFinalCost += (int)Math.Floor(dUnitPrice * pItem.nNumber);
            }

            if (pItem is GW_ItemSlotBundle && !pItem.IsRechargeable)
            {
                if (pItem.nNumber < nCount)
                {
                    pChar.SendMessage("Trying to sell more than you possess.");
                    pChar.SendPacket(CPacket.CShopDlg.ShopResult(ShopRes.SellIncorrectRequest));
                    return;
                }

                if (nCount <= 0)
                {
                    pChar.SendMessage("Trying to sell negative amount.");
                    pChar.SendPacket(CPacket.CShopDlg.ShopResult(ShopRes.SellIncorrectRequest));
                    return;
                }
            }
            else
            {
                nCount = -1;
            }

            pChar.SendPacket(CPacket.CShopDlg.ShopResult(ShopRes.SellSuccess));

            //pChar.SendMessage("final price: " + nFinalCost);

            InventoryManipulator.RemoveFrom(pChar, pItem.InvType, nSlot, nCount);
            pChar.Modify.GainMeso(nFinalCost, false);
        }
        public void OnLostQuestItem(CInPacket p, short nQuestID)
        {
            var nLostCount = p.Decode4();

            var pAct = MasterManager.QuestTemplates[nQuestID].StartAct;

            if (pAct is null)
            {
                return;                           // invalid quest ID
            }
            if (nLostCount <= 0 || pAct.Items.Length <= 0)
            {
                return;                                                        // TODO trigger AB, close socket
            }
            var aLostItem = p.DecodeIntArray(nLostCount);

            foreach (var item in pAct.Items)
            {
                if (!aLostItem.Contains(item.Item.ItemID))
                {
                    continue;                                                        // TODO trigger AB?
                }
                if (ItemConstants.GetInventoryType(item.Item.ItemID) == InventoryType.Equip)
                {
                    Parent.SendMessage("Not currently supported. Check again later.");
                    return;                     // TODO
                }

                if (!MasterManager.ItemTemplates[item.Item.ItemID]?.Quest ?? true)
                {
                    continue;
                }

                if (InventoryManipulator.HasSpace(Parent, item.Item.ItemID, (short)item.Item.Count))
                {
                    var itemToAdd = MasterManager.CreateItem(item.Item.ItemID);
                    itemToAdd.nNumber = (short)item.Item.Count;
                    InventoryManipulator.InsertInto(Parent, itemToAdd);
                }
                else
                {
                    // TODO proper response packet
                    Parent.SendMessage("Please make space in your inventory.");
                    return;
                }
            }

            // TODO
            // if ( aChangedItem.a && *(aChangedItem.a - 1) > 0u )
            //		CUser::PostQuestEffect(&v16->vfptr, 1, &aChangedItem, 0, 0);
        }
Beispiel #9
0
        public static GW_ItemSlotBase CreateItem(int nItemID, bool bRandStats = true)
        {
            if (nItemID <= 0)
            {
                return(null);
            }

            // TODO test the below
            if (ItemConstants.GetInventoryType(nItemID) != InventoryType.Equip)
            {
                GW_ItemSlotBase item;
                if (ItemConstants.IsPet(nItemID))
                {
                    item = new GW_ItemSlotPet(nItemID);
                    ((GW_ItemSlotPet)item).nRemainLife = 7776000;
                }
                else
                {
                    item = new GW_ItemSlotBundle(nItemID);
                }

                if (item.Template is null)
                {
                    throw new ArgumentOutOfRangeException(nameof(nItemID), "Doesn't exist in data files.");
                }

                if (ItemConstants.IsRechargeableItem(item.nItemID))
                {
                    item.nNumber = (short)item.Template.SlotMax;
                }
                else
                {
                    item.nNumber = 1;
                }

                item.tDateExpire = DateTime.MaxValue;

                return(item);
            }

            if (bRandStats)
            {
                return(CreateVariableStatEquip(nItemID));
            }

            return(CreateNormalStatEquip(nItemID));
        }
Beispiel #10
0
        // TODO figure out somewhere else for the below functions to live

        public static AbstractItemTemplate ItemTemplate(int nItemID)
        {
            switch (ItemConstants.GetInventoryType(nItemID))
            {
            case InventoryType.Equip:
                return(EquipTemplates[nItemID]);

            case InventoryType.Cash:
            case InventoryType.Consume:
            case InventoryType.Etc:
            case InventoryType.Install:
            case InventoryType.Special:
                return(ItemTemplates[nItemID]);

            default:
                throw new NullReferenceException("Unable to find a template for item with item ID: " + nItemID);
            }
        }
Beispiel #11
0
        public static bool HasSpace(Character pChar, int[] items)
        {
            var map = new Dictionary <InventoryType, int>();

            foreach (var item in items)
            {
                var nTI = ItemConstants.GetInventoryType(item);
                if (map.ContainsKey(nTI))
                {
                    map[nTI]++;
                }
                else
                {
                    map.Add(nTI, 1);
                }
            }

            return(HasSpace(pChar, map));
        }
Beispiel #12
0
        /// <summary>
        /// Removes items that aren't in the cached data.
        /// Note: Must be called after all game data has been cached.
        /// </summary>
        public void PurgeInvalidItems()
        {
            var entriesToRemove = new List <int>();

            foreach (var mob in this)
            {
                if (MasterManager.MobTemplates[mob.MobID] is null)
                {
                    entriesToRemove.Add(mob.MobID);
                }
                else
                {
                    var dropsToKeep = new List <DropStruct>();
                    foreach (var drop in mob.Drops)
                    {
                        if (ItemConstants.GetInventoryType(drop.ItemID) == Common.Types.InventoryType.Equip)
                        {
                            if (MasterManager.EquipTemplates[drop.ItemID] is null)
                            {
                                continue;
                            }
                        }
                        else
                        {
                            if (MasterManager.ItemTemplates[drop.ItemID] is null)
                            {
                                continue;
                            }
                        }

                        dropsToKeep.Add(drop);
                    }
                    mob.Drops = dropsToKeep;
                }
            }

            foreach (var entry in entriesToRemove)
            {
                Remove(entry);
            }

            Log.Info("Drops: " + Count);
        }
Beispiel #13
0
        public override void Execute(CommandCtx ctx)
        {
            var itemId = ctx.NextInt();

            var sCount = !ctx.Empty ? ctx.NextString() : null;
            var nCount = 1;

            if (sCount is object)
            {
                if (!int.TryParse(sCount, out nCount))
                {
                    ctx.Character.SendMessage("Unable to parse count.");
                    return;
                }
            }

            var character = ctx.Character;

            var nInvType = ItemConstants.GetInventoryType(itemId);

            if (InventoryManipulator.CountFreeSlots(character, nInvType) > 0)
            {
                var item = MasterManager.CreateItem(itemId);

                if (item is null)
                {
                    return;
                }

                if (item is GW_ItemSlotBundle isb)
                {
                    isb.nNumber = (short)Math.Min(nCount, item.SlotMax);
                }

                InventoryManipulator.InsertInto(character, item);
                character.SendPacket(CPacket.DropPickUpMessage_Item(itemId, nCount, true));
            }
        }
Beispiel #14
0
        public void PickUp(Character pChar, int dwDropId, short pX, short pY, bool bByPet = false)
        {
            var pDrop = this[dwDropId];

            if (pDrop is null)
            {
                return;
            }

            switch (pDrop.DropOwnType)
            {
            case DropOwnType.PartyOwn when pChar.Party?.PartyID != pDrop.DropOwnerID:
            case DropOwnType.UserOwn when pChar.dwId != pDrop.DropOwnerID:
                pChar.SendMessage("Trying to pick up a drop that doesn't belong to you.");
                return;
            }

            if (pDrop.Item != null)
            {
                if (InventoryManipulator.CountFreeSlots(pChar, ItemConstants.GetInventoryType(pDrop.Item.nItemID)) <= 0)
                {
                    return;
                }
            }

            if (bByPet)
            {
                if (Constants.MULTIPET_ACTIVATED)
                {
                    throw new NotImplementedException();                     // since we arent checking multiple pet equip slots
                }

                if (pDrop.bIsMoney == 1)
                {
                    if (InventoryManipulator.GetItem(pChar, BodyPart.BP_PETABIL_MESO, true) is null)
                    {
                        return;
                    }
                }
                else
                {
                    if (InventoryManipulator.GetItem(pChar, BodyPart.BP_PETABIL_ITEM, true) is null)
                    {
                        return;
                    }
                }

                pDrop.nLeaveType = DropLeaveType.PetPickup;
            }
            else
            {
                pDrop.nLeaveType = DropLeaveType.UserPickup;
            }

            pDrop.OwnerCharId = pChar.dwId;

            if (pDrop.bIsMoney > 0)
            {
                pChar.Modify.GainMeso(pDrop.nMesoVal);
            }
            else
            {
                if (pDrop.Item.Template is CashItemTemplate itemDataTemplate)
                {
                    if (itemDataTemplate.Max > 0 &&
                        InventoryManipulator.ContainsItem(pChar, pDrop.ItemId, (short)itemDataTemplate.Max))
                    {
                        pChar.SendMessage("Can't hold anymore of this item..");
                        return;
                    }
                }

                if (!Field.TryDropPickup(pChar, pDrop))
                {
                    return;
                }

                pChar.SendPacket(CPacket.DropPickUpMessage_Item(pDrop.ItemId, pDrop.Item.nNumber, false));

                if (pDrop.Item.Template.PickupMessage.Length > 0)
                {
                    pChar.SendMessage(pDrop.Item.Template.PickupMessage);
                }
            }

            Remove(dwDropId);
        }
 public void RemoveFrom(int itemId, short slot, short amount = 1) => InventoryManipulator.RemoveFrom(Character, ItemConstants.GetInventoryType(itemId), slot, amount);
        public bool CheckDemand(short nQuestID, int dwNpcTemplateID, int nAct)
        {
            // TODO proper response codes

            var pQuest = MasterManager.QuestTemplates[nQuestID];

            var pDemand = nAct == 0 ? pQuest.StartDemand : pQuest.EndDemand;

            if (pDemand is null)
            {
                return(true);                             // no requirements
            }
            var correctNpc = nAct == 0 ? pQuest.StartNPC : pQuest.EndNPC;

            if (correctNpc != 0 && correctNpc != dwNpcTemplateID)
            {
                return(false);
            }

            switch (nAct)
            {
            case 0 when this[nQuestID] is null:
                return(true);

            case 1 when this[nQuestID] is null:
            case 1 when this[nQuestID].nState == QuestActType.NotStarted:
            case 0 when this[nQuestID].nState == QuestActType.QuestAccept:
                return(false);

            default:
                if (this[nQuestID].IsComplete)
                {
                    return(false);
                }
                break;
            }

            if (Parent.Stats.nLevel < pDemand.LevelMin)
            {
                return(false);
            }
            if (Parent.Stats.nPOP < pDemand.Pop)
            {
                return(false);
            }
            if (pQuest.Start > DateTime.MinValue && pQuest.Start.SecondsSinceStart() < 0)
            {
                return(false);
            }

            // hmm the client is still allowing some quests that have an end date and max level to be triggered...
            //if (pQuest.End > DateTime.MinValue && pQuest.End.SecondsSinceStart() > 0) return false;
            //if (pDemand.LevelMax != 0 && Parent.Stats.nLevel > pDemand.LevelMax) return false;

            if (pDemand.SubJobFlags != 0 && Parent.Stats.nSubJob != pDemand.SubJobFlags)
            {
                return(false);
            }

            if (pDemand.Job.Length > 0 &&
                pDemand.Job.All(job => job != Parent.Stats.nJob))
            {
                return(false);
            }

            foreach (var item in pDemand.DemandItem)
            {
                if (ItemConstants.GetInventoryType(item.ItemID) == InventoryType.Equip)
                {
                    if (InventoryManipulator.ItemEquipped(Parent, item.ItemID))
                    {
                        continue;
                    }
                }

                if (!InventoryManipulator.ContainsItem(Parent, item.ItemID, (short)item.Count))
                {
                    return(false);
                }
            }

            if (pDemand.EquipAllNeed.Any(
                    item => !InventoryManipulator.ItemEquipped(Parent, item)))
            {
                return(false);
            }

            if (pDemand.EquipSelectNeed.Length > 0 && pDemand.EquipSelectNeed.All(             // TODO verify
                    item => !InventoryManipulator.ItemEquipped(Parent, item)))
            {
                return(false);
            }

            foreach (var quest in pDemand.DemandQuest)
            {
                if (quest.State == 0 && !Contains(quest.QuestID))
                {
                    return(false);
                }
                if ((QuestActType)quest.State != this[quest.QuestID].nState)
                {
                    return(false);
                }
            }

            foreach (var skill in pDemand.DemandSkill)
            {
                if (skill.Acquire == 0 && Parent.Skills[skill.SkillID]?.nSLV != 0)
                {
                    return(false);
                }
                if (Parent.Skills[skill.SkillID].nSLV == 0)
                {
                    return(false);
                }
            }

            foreach (var mob in pDemand.DemandMob)
            {
                var quest = this[nQuestID];
                if (!quest.DemandRecords.ContainsKey(mob.MobID))
                {
                    return(false);
                }
                if (quest.DemandRecords[mob.MobID].nValue != mob.Count)
                {
                    return(false);
                }
            }

            foreach (var map in pDemand.DemandMap)
            {
                var quest = this[nQuestID];
                if (!quest.DemandRecords.ContainsKey(map.MapID))
                {
                    return(false);
                }
                if (quest.DemandRecords[map.MapID].nValue <= 0)
                {
                    return(false);
                }
            }

            if (pDemand.FieldEnter.Length > 0 &&
                pDemand.FieldEnter.All(map => map == Parent.Stats.dwPosMap))
            {
                return(false);
            }

            // TODO taming mob
            // TODO pet closeness

            return(true);
        }
        public static void Handle(MapleClient c, PacketReader pr)
        {
            try
            {
                if (c.NpcEngine != null && c.NpcEngine.IsShop)
                {
                    byte mode  = pr.ReadByte();
                    int  NpcId = c.NpcEngine.NpcId;
                    switch (mode)
                    {
                    case 0:
                    {
                        short shopIndex = pr.ReadShort();
                        int   itemId    = pr.ReadInt();
                        short amount    = pr.ReadShort();
                        c.NpcEngine.BuyItem(itemId, shopIndex, amount);
                        break;
                    }

                    case 1:     //sell
                    {
                        short inventoryIndex = pr.ReadShort();
                        int   itemId         = pr.ReadInt();
                        short qty            = pr.ReadShort();

                        MapleInventoryType invType = ItemConstants.GetInventoryType(itemId);
                        switch (invType)
                        {
                        case MapleInventoryType.Equip:
                        case MapleInventoryType.Etc:
                        case MapleInventoryType.Setup:
                        case MapleInventoryType.Use:
                            break;

                        default:
                            return;         // Not a valid item
                        }
                        WzItem wzitem = DataBuffer.GetItemById(itemId);
                        if (wzitem == null)
                        {
                            wzitem = DataBuffer.GetEquipById(itemId);
                        }
                        if (wzitem == null)     // Item doesnt exist (anymore?)
                        {
                            return;
                        }
                        if (wzitem.NotSale || wzitem.IsCashItem || wzitem.IsQuestItem)
                        {
                            return;
                        }
                        byte response = 0;
                        if (!wzitem.IsQuestItem)
                        {
                            MapleInventory inventory = c.Account.Character.Inventory;
                            MapleItem      item      = inventory.GetItemSlotFromInventory(invType, inventoryIndex);
                            if (item?.ItemId == itemId && item.Quantity >= qty)
                            {
                                if (inventory.Mesos + wzitem.Price > GameConstants.MAX_MESOS)
                                {
                                    response = 2;     // You do not have enough mesos
                                }
                                else
                                {
                                    inventory.RemoveItemsFromSlot(item.InventoryType, item.Position, qty, true);
                                    inventory.GainMesos(wzitem.Price * qty, false, false);
                                }
                                // TODO: buyback
                            }
                        }
                        PacketWriter pw = new PacketWriter();
                        pw.WriteHeader(SendHeader.NpcTransaction);
                        pw.WriteByte(response);
                        pw.WriteByte(0);
                        pw.WriteByte(0);
                        c.SendPacket(pw);
                        break;
                    }

                    case 3:
                    {
                        c.NpcEngine.Dispose();
                        break;
                    }

                    default:
                    {
                        c.NpcEngine.ScriptInstance = null;
                        ServerConsole.Warning("Unkown NpcShopActionHandler mode:" + mode);
                        ServerConsole.Info(Functions.ByteArrayToStr(pr.ToArray()));
                        break;
                    }
                    }
                }
            }
            catch (Exception ex)
            {
                ServerConsole.Error("NpcShopActionHandler Failure");
                ServerConsole.Error(ex.Message);
                if (c.NpcEngine != null)
                {
                    c.NpcEngine.Dispose();
                }
            }
        }
Beispiel #18
0
 public static CharacterInventoryItems GetInventory(Character pChar, int nItemID)
 => GetInventory(pChar, ItemConstants.GetInventoryType(nItemID));
Beispiel #19
0
        /// <summary>
        /// Handles skill casting. Will return false if skill is unable to cast for any reason, such as not enough resources or invalid skill.
        /// </summary>
        /// <param name="nSkillID"></param>
        /// <param name="bLeft">If the skill is happening to the left of the character</param>
        /// <param name="bOutsideHandling">When this is true, the function will only process the resource/cooldown portion.</param>
        /// <returns></returns>
        public bool Cast(int nSkillID, bool bLeft, bool bOutsideHandling = false, int nSpiritJavelinItemID = 0)
        {
            if (Parent.Stats.nHP <= 0)
            {
                return(false);                                   // REEEEEEEEE
            }
#if DEBUG
            Parent.SendMessage("Casting spell " + nSkillID);
#endif

            var skill = Get(nSkillID, true);

            if (skill == null)
            {
                Parent.SendMessage("Unable to find skill.");
                return(false);
            }

            var template = skill.Template;
            var nSLV     = skill.nSLV;

            if (Parent.Cooldowns.OnCooldown(nSkillID))
            {
                Parent.SendMessage("Trying to cast skill while skill on cooldown.");
                return(false);
            }

            double costMp        = skill.MPCost;                    // done
            var    costMeso      = template.MesoR(nSLV);            // may not be done..
            var    itemConsumeId = template.ItemConsume;            // done
            if (Parent.Buffs.Contains((int)Skills.BISHOP_INFINITY)) // party buff
            {
                costMp = 0;
            }
            else
            {
                switch (Parent.Stats.nJob / 10)
                {
                case 21:
                    if (Parent.Buffs.Contains((int)Skills.ARCHMAGE1_INFINITY))
                    {
                        costMp = 0;
                        break;
                    }
                    costMp *= (Parent.Skills.Get((int)Skills.MAGE1_ELEMENT_AMPLIFICATION)?.X_Effect ?? 100.0) * 0.01;
                    goto default;

                case 22:
                    if (Parent.Buffs.Contains((int)Skills.ARCHMAGE2_INFINITY))
                    {
                        costMp = 0;
                        break;
                    }
                    costMp *= (Parent.Skills.Get((int)Skills.MAGE2_ELEMENT_AMPLIFICATION)?.X_Effect ?? 100.0) * 0.01;
                    goto default;

                case 121:                         // koc mage
                    costMp *= (Parent.Skills.Get((int)Skills.FLAMEWIZARD_ELEMENT_AMPLIFICATION)?.X_Effect ?? 100.0) * 0.01;
                    goto default;

                case 221:                         // evan
                case 222:                         // evan rounded up (2215-2218)
                    costMp *= (Parent.Skills.Get((int)Skills.EVAN_ELEMENT_AMPLIFICATION)?.X_Effect ?? 100.0) * 0.01;
                    goto default;

                case 31:
                    if (Parent.Buffs[(int)Skills.BOWMASTER_CONCENTRATION] is BuffSkill pBuff)
                    {
                        costMp *= 1 - (pBuff.Template.X(pBuff.nSLV) * 0.01);
                    }
                    goto default;

                default:
                    if (Parent.Stats.nMP < Math.Floor(costMp))
                    {
                        Log.Debug($"Not enough mp to perform skill. Current MP: {Parent.Stats.nMP}. MP required: {costMp}. SkillID: {nSkillID}. CharID: {Parent.dwId}. CharName: {Parent.Stats.sCharacterName}.");
                        return(false);
                    }
                    break;
                }
            }
            // calculate HP cost
            int costHp;
            switch ((Skills)nSkillID)
            {
            case Skills.DUAL5_FINAL_CUT:
            case Skills.DRAGONKNIGHT_DRAGON_ROAR:
            case Skills.DRAGONKNIGHT_SACRIFICE:
            case Skills.INFIGHTER_MP_RECOVERY:
                costHp = (int)(Parent.BasicStats.nMHP * template.X(skill.nSLV) * 0.01);
                break;

            default:
                costHp = 0;
                break;
            }

            if (Parent.Stats.nHP <= costHp)
            {
                Log.Debug($"Not enough hp to perform skill. Hp required: {costHp}");
                return(false);
            }

            if (Parent.Stats.nMoney < costMeso)
            {
                Log.Debug($"Not enough meso to perform skill. Meso required: {costMeso}");
                return(false);
            }

            var itemConsumeAmount = template.ItemConsumeAmount;

            if (nSkillID == (int)Skills.NIGHTLORD_SPIRIT_JAVELIN)
            {
                if (!ItemConstants.IsThrowingStar(nSpiritJavelinItemID))
                {
                    return(false);
                }

                itemConsumeId     = nSpiritJavelinItemID;
                itemConsumeAmount = 200;                 // we hardcodin' bois
            }

            if (itemConsumeId > 0 && itemConsumeAmount > 0)
            {
                var valid    = false;
                var itemType = ItemConstants.GetInventoryType(itemConsumeId);
                foreach (var item in itemType == InventoryType.Etc ? Parent.InventoryEtc : Parent.InventoryConsume)                 // lol ternary operator in a loop
                {
                    if (item.Value.nItemID == itemConsumeId && item.Value.nNumber >= itemConsumeAmount)
                    {
                        valid = true;
                        InventoryManipulator.RemoveFrom(Parent, itemType, item.Key, (short)itemConsumeAmount);
                        break;
                    }
                }

                if (!valid)
                {
                    return(false);
                }
            }

            // energy skills
            switch ((Skills)nSkillID)
            {
            case Skills.BUCCANEER_ENERGY_BURSTER:
            case Skills.STRIKER_ENERGY_BURSTER:
            case Skills.BUCCANEER_ENERGY_DRAIN:
            case Skills.STRIKER_ENERGY_DRAIN:
            case Skills.VIPER_ENERGY_ORB:
                if (Parent.Combat.nEnergy != SkillLogic.EnergyMax)
                {
                    Parent.SendMessage($"Insufficient energy. ({Parent.Combat.nEnergy} != {SkillLogic.EnergyMax}).");
                    return(false);
                }
                break;
            }

            Parent.Modify.Stats(ctx =>
            {
                if (costHp > 0)
                {
                    ctx.HP -= costHp;
                }

                if (costMp > 0)
                {
                    ctx.MP -= (int)Math.Floor(costMp);
                }

                if (costMeso > 0)
                {
                    ctx.Money -= costMeso;
                }
            });

            if (Parent.nPreparedSkill == 0)
            {
                var nCdSkillId = nSkillID;
                var nCdTime    = template.Cooltime(skill.nSLV);

                switch ((Skills)nSkillID)
                {
                case Skills.MECHANIC_SAFETY:
                {
                    if (!Parent.Field.Summons.Any(s => s.dwParentID == dwParentID &&
                                                  (s.nSkillID == (int)Skills.MECHANIC_SATELITE || s.nSkillID == (int)Skills.MECHANIC_SATELITE2 || s.nSkillID == (int)Skills.MECHANIC_SATELITE3)))
                    {
                        return(false);                                        // satellites must be active to cast this skill
                    }
                }
                break;

                case Skills.WILDHUNTER_SWALLOW:
                case Skills.MECHANIC_TESLA_COIL:
                    nCdTime = 0;
                    break;

                case Skills.WILDHUNTER_SWALLOW_DUMMY_ATTACK:
                case Skills.WILDHUNTER_SWALLOW_DUMMY_BUFF:
                    var pTempTemplate = Parent.Skills.Get((int)Skills.WILDHUNTER_SWALLOW);
                    nCdSkillId = pTempTemplate.nSkillID;
                    nCdTime    = (short)pTempTemplate.CoolTimeSeconds;
                    break;
                }

                if (nCdTime > 0)
                {
                    Parent.Cooldowns.UpdateOrInsert(nCdSkillId, (short)nCdTime);
                }
            }

            if (template.is_heros_will_skill)
            {
                Parent.Buffs.CancelAllDebuffs();
                return(true);
            }

            if (bOutsideHandling || template.IsNotBuff)
            {
                return(true);
            }

            if (SkillLogic.is_teleport_mastery_skill(nSkillID))
            {
                HandleTeleportMastery(nSkillID, nSLV);
                return(true);
            }

            switch ((Skills)nSkillID)
            {
            case Skills.HERO_ENRAGE:
            {
                Parent.Buffs.Remove((int)Skills.CRUSADER_COMBO_ATTACK);
                Parent.Combat.ComboCounter = 0;
            }
            break;

            case Skills.CRUSADER_MAGIC_CRASH:
            case Skills.DRAGONKNIGHT_MAGIC_CRASH:
            case Skills.KNIGHT_MAGIC_CRASH:
                CastAOEMobStat(nSkillID);
                return(true);

            case Skills.NIGHTLORD_SPIRIT_JAVELIN:
            {
                Parent.Buffs.Remove(nSkillID);
                var buff = new BuffSkill(nSkillID, nSLV);
                buff.GenerateSpiritJavelin(nSpiritJavelinItemID);
                Parent.Buffs.Add(buff);
            }
                return(true);

            case Skills.BMAGE_SUPER_BODY:
                DoSuperBody(nSLV);
                return(true);

            case Skills.BMAGE_AURA_BLUE:
                DoAuraSkill(SecondaryStatFlag.BlueAura, (int)Skills.BMAGE_AURA_BLUE_ADVANCED, nSkillID, nSLV);
                return(true);

            case Skills.BMAGE_AURA_YELLOW:
                DoAuraSkill(SecondaryStatFlag.YellowAura, (int)Skills.BMAGE_AURA_YELLOW_ADVANCED, nSkillID, nSLV);
                return(true);

            case Skills.BMAGE_AURA_DARK:
                DoAuraSkill(SecondaryStatFlag.DarkAura, (int)Skills.BMAGE_AURA_DARK_ADVANCED, nSkillID, nSLV);
                return(true);

            case Skills.SHADOWER_SMOKE_SHELL:
            case Skills.EVAN_RECOVERY_AURA:
            case Skills.MAGE1_POISON_MIST:
            case Skills.FLAMEWIZARD_FLAME_GEAR:
            case Skills.BMAGE_SHELTER:
                CastAffectedAreaSkill
                    (nSkillID, skill.nSLV, (short)skill.BuffTime, Parent.Position.CurrentXY, template.LT, template.RB);
                return(true);

            case Skills.THIEFMASTER_CHAKRA:
                if (Parent.Stats.nHP < Parent.BasicStats.nMHP * 0.5)
                {
                    // BMS
                    // dwFlaga = sd->nY + 100;
                    // tCur = CRand32::Random(&g_rand) % 100 + 100;
                    // CQWUser::IncHP(v5, ((tCur * v5->m_basicStat.nLUK * 0.033 + v5->m_basicStat.nDEX) * dwFlaga * 0.002), 0);
                    var nMultiplier = skill.Y_Effect + 100;
                    var nRand       = Constants.Rand.Next() % 100 + 100;
                    Parent.Modify.Heal((int)((nRand * Parent.BasicStats.nLUK * 0.033 + Parent.BasicStats.nDEX) * nMultiplier * 0.002));
                    return(true);
                }
                return(false);

            case Skills.KNIGHT_RESTORATION:
                Parent.Modify.Heal((int)(Parent.BasicStats.nMHP * skill.X_Effect));
                return(true);

            case Skills.FLAMEWIZARD_SLOW:
            case Skills.WIZARD1_SLOW:
            case Skills.WIZARD2_SLOW:
            case Skills.NIGHTLORD_NINJA_AMBUSH:
            case Skills.SHADOWER_NINJA_AMBUSH:
            case Skills.HERMIT_SHADOW_WEB:
            case Skills.NIGHTWALKER_SHADOW_WEB:
            case Skills.DUAL3_FLASH_BANG:
            case Skills.DUAL4_UPPER_STAB:
            case Skills.HUNTER_ARROW_BOMB:
            case Skills.BOWMASTER_VENGEANCE:
            case Skills.PAGE_THREATEN:
                CastAOEMobStat(nSkillID);
                return(true);

            case Skills.DUAL4_OWL_DEATH:
                if (skill.DoProp())
                {
                    Parent.Buffs.AddSkillBuff(nSkillID, nSLV, Parent.Buffs.BuffTimeModifier());
                    Parent.Combat.OwlSpiritCount = 10;
                }
                return(true);

            case Skills.ADMIN_HOLY_SYMBOL:
                foreach (var pChar in Parent.Field.Users)
                {
                    pChar.Buffs.AddSkillBuff(nSkillID, nSLV, Parent.Buffs.BuffTimeModifier());
                }
                return(true);

            case Skills.WILDHUNTER_SWALLOW:
                SwallowMob(Parent.m_dwSwallowMobID, nSLV);
                return(true);

            case Skills.VALKYRIE_DICE:
            case Skills.MECHANIC_DICE:
            case Skills.BUCCANEER_DICE:
                DoDice(nSkillID, nSLV);
                return(true);

            case Skills.INFIGHTER_MP_RECOVERY:
                Parent.Modify.Heal(0, (int)(Parent.BasicStats.nMHP * (0.5 + (0.1 * nSLV))));                         // hard coding ftw
                return(true);

            case Skills.CLERIC_HEAL:
                DoPartyHeal(nSkillID, template.HP(nSLV));
                return(true);

            case Skills.BISHOP_RESURRECTION:
                if (Parent.Party?.Count > 1)
                {
                    Parent.Party.ApplyBuffToParty(Parent, Parent.Field.dwUniqueId, nSkillID, nSLV);
                }
                return(true);

            case Skills.PRIEST_DISPEL:
                if (Parent.Party?.Count > 1)
                {
                    Parent.Party.ApplyBuffToParty(Parent, Parent.Field.dwUniqueId, nSkillID, nSLV);
                }
                else
                {
                    Parent.Buffs.CancelAllDebuffs();
                }
                CastAOEMobStat(nSkillID);                         // lazy impl
                return(true);

            case Skills.KNIGHT_COMBAT_ORDERS:
                DoCombatOrders(nSkillID, nSLV);
                return(true);

            case Skills.BISHOP_INFINITY:                     // only a party buff for clerics (custom)
                if (Parent.Party?.Count > 1)
                {
                    Parent.Party.ApplyBuffToParty(Parent, Parent.Field.dwUniqueId, nSkillID, nSLV, 2);
                    return(true);
                }
                break;

            case Skills.VIPER_TIME_LEAP:
                DoTimeleap(nSkillID);
                return(true);

            case Skills.MECHANIC_HN07:
            {
                if (Parent.Skills.Get((int)Skills.MECHANIC_HN07_UPGRADE, false) is SkillEntry se)
                {
                    Parent.Buffs.AddSkillBuff(se.nSkillID, se.nSLV);
                    return(true);
                }
            }
            break;
            }

            if (template.Time(nSLV) != 0)
            {
                var buffTimeModifier = Parent.Buffs.BuffTimeModifier();

                if (Parent.Party?.Count > 1 && template.IsPartyBuff)
                {
                    Parent.Party.ApplyBuffToParty
                        (Parent, Parent.Field.dwUniqueId, nSkillID, nSLV, buffTimeModifier);
                }
                else
                {
                    Parent.Buffs.AddSkillBuff(nSkillID, nSLV, buffTimeModifier);
                }
            }

            return(true);
        }
Beispiel #20
0
        public static void Handle_UserSkillLearnItemUseRequest(WvsGameClient c, CInPacket p)
        {
            int   dwTickCount = p.Decode4();
            short nPOS        = p.Decode2();
            int   nItemID     = p.Decode4();

            c.Character.Action.Enable();

            if (c.Character.Stats.nHP <= 0)
            {
                return;
            }

            if (InventoryManipulator.GetItem(c.Character, ItemConstants.GetInventoryType(nItemID), nPOS) is GW_ItemSlotBundle item &&
                item.Template is ConsumeItemTemplate template)
            {
                var jobroot = Math.Floor(c.Character.Stats.nJob * 0.01);                 // 3500 -> 35

                var bUsed         = false;
                var bSuccess      = false;
                var bIsMasterBook = item.nItemID / 10000 == 229;

                foreach (var skillId in template.SkillData)
                {
                    var skillJob  = (int)Math.Floor(skillId / 10000f); // 35111010 -> 3511
                    var skillRoot = (int)Math.Floor(skillJob / 100f);  // 3511 -> 35

                    if (skillRoot == jobroot)                          // this can only be true once
                    {
                        if (skillJob > c.Character.Stats.nJob)
                        {
                            break;
                        }

                        var skill = c.Character.Skills.FirstOrDefault(s => s.nSkillID == skillId);

                        if (bIsMasterBook)
                        {
                            if (skill is null || skill.nSLV < template.ReqSkillLevel || skill.CurMastery >= template.MasterLevel)
                            {
                                return;
                            }
                        }
                        else
                        {
                            if (skill != null && skill.CurMastery > 0)
                            {
                                break;
                            }
                        }

                        bUsed = true;

                        if (template.SuccessRate != 100)
                        {
                            if (Constants.Rand.Next() % 100 > template.SuccessRate)
                            {
                                break;
                            }
                        }

                        c.Character.Modify.Skills(mod => mod.AddEntry(skillId, s => s.CurMastery = (byte)template.MasterLevel));
                        bSuccess = true;
                        break;
                    }
                }

                if (bUsed)
                {
                    InventoryManipulator.RemoveFrom(c.Character, item.InvType, nPOS);                     // always remove
                }

                c.Character.Field.Broadcast(CPacket.SkillLearnItemResult(c.dwCharId, bIsMasterBook, bUsed, bSuccess));
            }
        }
Beispiel #21
0
        private static void BuyItem(Character pChar, short nPos, int nItemId, short nCount)
        {
            var cShop = pChar.Socket.ActiveShop;

            // price is 0 for invis items
            if (!cShop.ContainsItem(nItemId) ||
                cShop.GetItemPrice(nItemId) <= 0 ||
                cShop.GetItemLevelLimited(nItemId) > pChar.Stats.nLevel)
            {
                pChar.SendMessage("Trying to buy an item that doesn't exist in the shop.");
                pChar.SendPacket(CPacket.CShopDlg.ShopResult(ShopRes.BuyUnknown));
                return;
            }

            nCount = ItemConstants.is_treat_singly(nItemId) ? (short)1 : nCount;

            var nPricePerCount = cShop.GetItemPrice(nItemId);
            var nFinalPrice    = nPricePerCount * nCount;

            if (nFinalPrice > pChar.Stats.nMoney)
            {
                pChar.SendMessage("Trying to buy an item without enough money.");
                pChar.SendPacket(CPacket.CShopDlg.ShopResult(ShopRes.BuyNoMoney));
                return;
            }

            var nInvType = ItemConstants.GetInventoryType(nItemId);

            if (InventoryManipulator.CountFreeSlots(pChar, nInvType) < 1)
            {
                pChar.SendMessage("Please make some space in your inventory.");
                pChar.SendPacket(CPacket.CShopDlg.ShopResult(ShopRes.BuyUnknown));
                return;
            }

            var pItem = MasterManager.CreateItem(nItemId, false);

            var slotmax = pItem.SlotMax;

            if (pChar.Skills.Get(false,
                                 (int)Skills.NIGHTWALKER_JAVELIN_MASTERY,
                                 (int)Skills.ASSASSIN_JAVELIN_MASTERY) is SkillEntry se)
            {
                slotmax += (short)se.Y_Effect;
            }

            if (slotmax < nCount * cShop.GetItemQuantity(nItemId))
            {
                pChar.SendMessage("Unable to purchase more than one slot of items at a time.");
                pChar.SendPacket(CPacket.CShopDlg.ShopResult(ShopRes.BuyUnknown));
                return;
            }

            pChar.SendPacket(CPacket.CShopDlg.ShopResult(ShopRes.BuySuccess));

            pItem.nNumber = (short)(pItem.IsRechargeable ? slotmax : nCount * cShop.GetItemQuantity(nItemId));

            pChar.SendMessage("final price: " + nFinalPrice);

            InventoryManipulator.InsertInto(pChar, pItem);
            pChar.Modify.GainMeso(-nFinalPrice, false);
        }
        public static void Handle(MapleClient c, PacketReader pr)
        {
            MapleCharacter chr = c.Account.Character;

            if (!chr.DisableActions())
            {
                return;
            }
            int       tickCount  = pr.ReadInt();
            short     slot       = pr.ReadShort();
            int       itemId     = pr.ReadInt();
            MapleItem item       = chr.Inventory.GetItemSlotFromInventory(ItemConstants.GetInventoryType(itemId), slot);
            bool      removeItem = true;

            if (item == null || item.ItemId != itemId)
            {
                return;
            }


            switch (itemId)
            {
            case 5062006:     //Platinum Miracle Cube
            {
                int equipSlot = pr.ReadInt();
                if (equipSlot < 0)
                {
                    return;
                }
                MapleEquip equip = chr.Inventory.GetItemSlotFromInventory(MapleInventoryType.Equip, (short)equipSlot) as MapleEquip;
                if (equip == null)
                {
                    return;
                }
                if (!MapleEquipEnhancer.CubeItem(equip, CubeType.PlatinumMiracle, chr))
                {
                    removeItem = false;
                }
                break;
            }

            case 5072000:     //Super Megaphone
            case 5072001:     //Super Megaphone
            {
                if (!CanMegaPhone(c.Account.Character))
                {
                    chr.EnableActions();
                    break;
                }
                string message = pr.ReadMapleString();
                if (message.Length > 60)
                {
                    return;
                }
                bool whisperIcon = pr.ReadBool();
                message = string.Format("{0} : {1}", c.Account.Character.Name, message);
                Program.BroadCastWorldPacket(MapleCharacter.ServerNotice(message, 3, c.Channel, whisperIcon));
                break;
            }

            case 5570000:           //Vicious hammer
            {
                removeItem = false; //Handled in UseGoldenHammerHandler
                pr.Skip(4);
                short      equipSlot = (short)pr.ReadInt();
                MapleEquip equip     = chr.Inventory.GetItemSlotFromInventory(MapleInventoryType.Equip, equipSlot) as MapleEquip;
                if (equip != null)
                {
                    UseGoldenHammerHandler.DoHammer(item, equip, chr);
                }
                break;
            }

            default:
            {
                ServerConsole.Warning("Unhandled UseSpecialItem: {0}", itemId);
                removeItem = false;
                chr.SendPopUpMessage("You cannot use this item");
                chr.EnableActions();
                break;
            }
            }
            if (removeItem)
            {
                chr.Inventory.RemoveItemsFromSlot(item.InventoryType, item.Position, 1);
            }
            chr.EnableActions(false);
        }