Exemple #1
0
        /// <summary>
        /// Handles HP/MP/EXP reduction on death.
        /// Cancels all buffs.
        /// Warps player to return map.
        /// </summary>
        /// <param name="user"></param>
        public virtual void OnUserWarpDie(Character user, bool bLoseExp = true)
        {
            user.StatisticsTracker.nDeaths += 1;
            if (nFieldDeathCount > 0)
            {
                UpdateDeathCount(--nFieldDeathCount);
            }

            if (Template.HasNoExpDecrease() || !bLoseExp)
            {
                user.Modify.Stats(ctx =>
                {
                    ctx.HP = user.BasicStats.nMHP;
                    ctx.MP = user.BasicStats.nMMP;
                });
            }
            else
            {
                const int nCharmId = 5130000;

                if (InventoryManipulator.RemoveQuantity(user, nCharmId, 1))
                {
                    // TODO use real notification packet for this
                    user.SendMessage($"A safety charm has been used to avoid losing exp!");
                    user.Modify.Heal((int)(user.BasicStats.nMHP * 0.33), (int)(user.BasicStats.nMMP * 0.33));
                }
                else
                {
                    user.Modify.Stats(ctx =>
                    {
                        ctx.decrease_exp(user.Field.Template.Town || user.Field.Mobs.aMobGen.Count == 0);
                        ctx.HP = 1;
                        ctx.MP = 1;
                    });
                }
            }

            user.Buffs.CancelAllBuffs();

            user.Action.SetField(user.Field.ReturnMapId);
        }
        public QuestResultType TryExchange(int nIncMoney, QuestAct.ActItem[] aActItem)
        {
            if (nIncMoney == 0 && aActItem.Length <= 0)
            {
                return(QuestResultType.Success);
            }

            if (nIncMoney < 0 &&
                Parent.Stats.nMoney < nIncMoney)
            {
                return(QuestResultType.Failed_Meso);
            }

            foreach (var item in aActItem)
            {
                if (item.Item.Count > 0)
                {
                    if (!InventoryManipulator.HasSpace(Parent, item.Item.ItemID, (short)item.Item.Count))
                    {
                        return(QuestResultType.Failed_Inventory);                        // -> Etc inventory is full
                    }
                }
                else
                {
                    if (!InventoryManipulator.ContainsItem(Parent, item.Item.ItemID, (short)item.Item.Count))
                    {
                        return(QuestResultType.Failed_Unknown);                        // idk what code to give them
                    }
                }
            }

            Parent.Modify.GainMeso(nIncMoney);

            var weight = 0;

            foreach (var item in aActItem)
            {
                if (item.ProbRate != 0)
                {
                    weight += item.ProbRate;
                }
            }

            var itemGiven = false;

            foreach (var item in aActItem.Shuffle())
            {
                if (item.Item.Count < 0)
                {
                    InventoryManipulator.RemoveQuantity(Parent, item.Item.ItemID, (short)item.Item.Count);
                }
                else
                {
                    if (item.ProbRate == 0)
                    {
                        var newItem = MasterManager.CreateItem(item.Item.ItemID, false);
                        if (!newItem.IsEquip)
                        {
                            newItem.nNumber = (short)item.Item.Count;
                        }

                        InventoryManipulator.InsertInto(Parent, newItem);
                    }
                    else if (!itemGiven)
                    {
                        var rand = Constants.Rand.Next(0, weight);

                        if (rand < item.ProbRate)
                        {
                            var newItem = MasterManager.CreateItem(item.Item.ItemID, false);
                            if (!newItem.IsEquip)
                            {
                                newItem.nNumber = (short)item.Item.Count;
                            }

                            InventoryManipulator.InsertInto(Parent, newItem);
                            itemGiven = true;
                        }
                        else
                        {
                            weight -= item.ProbRate;
                        }
                    }
                }
            }

            return(QuestResultType.Success);
        }
 public bool RemoveItem(int itemId, short amount             = 1) => InventoryManipulator.RemoveQuantity(Character, itemId, amount);
        private static void HandleCreateItemOp(Character pChar, int nItemID, bool bStimulantUsed, List <int> aGems)
        {
            // BEGIN VERIFICATION

            //var pMakerItem = MasterManager.EtcTemplates.MakerData(nItemID);
            var makerItem = MasterManager.ItemMakeTemplates[nItemID];

            // verify maker item exists
            if (makerItem is null)
            {
                pChar.SendMessage("Null item maker template.");
                return;
            }

            // verify player is high enough level to use recipe
            if (makerItem.ReqLevel > pChar.Stats.nLevel + 6)
            {
                pChar.SendMessage("Verify the item level you're trying to craft is no more than 6 above your own.");
                return;
            }

            // verify player has enough meso
            if (makerItem.Meso > pChar.Stats.nMoney)
            {
                pChar.SendMessage("Verify you have the correct amount of mesos.");
                return;
            }

            var pCharMakerSkill = pChar.Skills.Get(Common.GameLogic.SkillLogic.get_novice_skill_as_race(Common.GameLogic.SkillLogic.NoviceSkillID.MakerSkill, pChar.Stats.nJob));

            // verify player maker skill level is high enough
            if (makerItem.ReqSkillLevel > (pCharMakerSkill?.nSLV ?? 0))
            {
                pChar.SendMessage($"Verify maker skill level. {makerItem.ReqSkillLevel} < {(pCharMakerSkill?.nSLV ?? 0)}");
                return;
            }

            var(nStimulantItemSlot, pStimulantItem) = InventoryManipulator.GetAnyItem(pChar, InventoryType.Etc, makerItem.CatalystID);

            // verify stimulant (catalyst) exists in player inventory
            if (bStimulantUsed && pStimulantItem is null)
            {
                pChar.SendMessage("Verify you possess the correct stimulant item.");
                return;
            }

            // verify equip slot availability
            if (InventoryManipulator.CountFreeSlots(pChar, InventoryType.Equip) < 1)
            {
                pChar.SendMessage("Please make more room in your equip inventory.");
                return;
            }

            if (InventoryManipulator.CountFreeSlots(pChar, InventoryType.Etc) < makerItem.RandomReward.Length)
            {
                pChar.SendMessage("Please make more room in your etc inventory.");
                return;
            }

            // verify required items exist in player inventory
            if (makerItem.Recipe.Any(item => !InventoryManipulator.ContainsItem(pChar, item.ItemID, (short)item.Count)))
            {
                pChar.SendMessage("Verify you possess all the required components.");
                return;
            }

            var aGemItemIds   = new List <int>();
            var aGemItemTypes = new List <int>();

            // remove duplicate items/types and get item slots for gems
            foreach (var entry in aGems)
            {
                var(nGemSlot, pGemItem) = InventoryManipulator.GetAnyItem(pChar, InventoryType.Etc, entry);

                if (pGemItem is null || nGemSlot == 0 || !(pGemItem.Template is GemEffectTemplate))
                {
                    continue;
                }

                // idk how it would be 0 but we check anyway
                if (!aGemItemTypes.Contains(entry / 100) &&
                    !aGemItemIds.Contains(pGemItem.nItemID) &&
                    pGemItem.nNumber > 0)
                {
                    aGemItemIds.Add(pGemItem.nItemID);
                    aGemItemTypes.Add(entry / 100);
                }
            }

            // END VERIFICATION

            // BEGIN RECIPE PROCESSING

            // remove meso cost from inventory
            if (makerItem.Meso > 0)
            {
                pChar.Modify.GainMeso(-makerItem.Meso);
            }

            // remove stimulant from inventory
            if (bStimulantUsed)
            {
                InventoryManipulator.RemoveQuantity(pChar, pStimulantItem.nItemID, 1);
            }

            // remove recipe items from inventory
            foreach (var item in makerItem.Recipe)
            {
                InventoryManipulator.RemoveQuantity(pChar, item.ItemID, (short)item.Count);
            }

            var bSuccess = true;

            if (bStimulantUsed && Constants.Rand.Next(100) >= 90)
            {
                bSuccess = false;
            }
            else
            {
                // BEGIN MAKER ITEM CREATION

                var pNewItemRaw = MasterManager.CreateItem(makerItem.TemplateId);

                if (pNewItemRaw is GW_ItemSlotEquip pNewItemEquip)
                {
                    pNewItemEquip.RemainingUpgradeCount = (byte)makerItem.TUC;

                    // remove gems from inventory
                    foreach (var nGemItemId in aGemItemIds)
                    {
                        var pGemItemRaw = InventoryManipulator.GetAnyItem(pChar, InventoryType.Etc, nGemItemId).Item2;

                        if (pGemItemRaw.Template is GemEffectTemplate pGemItem)
                        {
                            // gems only have one modifier each
                            if (pGemItem.incPAD > 0)
                            {
                                pNewItemEquip.niPAD += (short)(pGemItem.incPAD * (bStimulantUsed ? 2 : 1));
                            }
                            else if (pGemItem.incPDD > 0)
                            {
                                pNewItemEquip.niPDD += (short)(pGemItem.incPDD * (bStimulantUsed ? 2 : 1));
                            }
                            else if (pGemItem.incMAD > 0)
                            {
                                pNewItemEquip.niMAD += (short)(pGemItem.incMAD * (bStimulantUsed ? 2 : 1));
                            }
                            else if (pGemItem.incMDD > 0)
                            {
                                pNewItemEquip.niMDD += (short)(pGemItem.incMDD * (bStimulantUsed ? 2 : 1));
                            }

                            else if (pGemItem.incSTR > 0)
                            {
                                pNewItemEquip.niSTR += (short)(pGemItem.incSTR * (bStimulantUsed ? 2 : 1));
                            }
                            else if (pGemItem.incINT > 0)
                            {
                                pNewItemEquip.niINT += (short)(pGemItem.incINT * (bStimulantUsed ? 2 : 1));
                            }
                            else if (pGemItem.incDEX > 0)
                            {
                                pNewItemEquip.niDEX += (short)(pGemItem.incDEX * (bStimulantUsed ? 2 : 1));
                            }
                            else if (pGemItem.incLUK > 0)
                            {
                                pNewItemEquip.niLUK += (short)(pGemItem.incLUK * (bStimulantUsed ? 2 : 1));
                            }

                            else if (pGemItem.incACC > 0)
                            {
                                pNewItemEquip.niACC += (short)(pGemItem.incACC * (bStimulantUsed ? 2 : 1));
                            }
                            else if (pGemItem.incEVA > 0)
                            {
                                pNewItemEquip.niEVA += (short)(pGemItem.incEVA * (bStimulantUsed ? 2 : 1));
                            }
                            else if (pGemItem.incMaxHP > 0)
                            {
                                pNewItemEquip.niMaxHP += (short)(pGemItem.incMaxHP * (bStimulantUsed ? 2 : 1));
                            }
                            else if (pGemItem.incMaxMP > 0)
                            {
                                pNewItemEquip.niMaxMP += (short)(pGemItem.incMaxMP * (bStimulantUsed ? 2 : 1));
                            }

                            else if (pGemItem.incJump > 0)
                            {
                                pNewItemEquip.niJump += (short)(pGemItem.incJump * (bStimulantUsed ? 2 : 1));
                            }
                            else if (pGemItem.incSpeed > 0)
                            {
                                pNewItemEquip.niSpeed += (short)(pGemItem.incSpeed * (bStimulantUsed ? 2 : 1));
                            }

                            else if (pGemItem.incReqLevel < 0)
                            {
                                pNewItemEquip.nLevel = (byte)(pNewItemEquip.nLevel + (pGemItem.incReqLevel * (bStimulantUsed ? 2 : 1)));
                            }

                            else if (pGemItem.RandOption > 0)
                            {
                                var gX = new GaussianRandom();

                                var nRange = pGemItem.RandOption * (bStimulantUsed ? 2 : 1);

                                if (pNewItemEquip.niMaxHP > 0)
                                {
                                    pNewItemEquip.niMaxHP = (short)Math.Max(0, gX.GaussianDistributionVariation(pNewItemEquip.niMaxHP, nRange, false));
                                }
                                if (pNewItemEquip.niMaxMP > 0)
                                {
                                    pNewItemEquip.niMaxMP = (short)Math.Max(0, gX.GaussianDistributionVariation(pNewItemEquip.niMaxMP, nRange, false));
                                }

                                if (pNewItemEquip.niPAD > 0)
                                {
                                    pNewItemEquip.niPAD = (short)Math.Max(0, gX.GaussianDistributionVariation(pNewItemEquip.niPAD, nRange, false));
                                }
                                if (pNewItemEquip.niMAD > 0)
                                {
                                    pNewItemEquip.niMAD = (short)Math.Max(0, gX.GaussianDistributionVariation(pNewItemEquip.niMAD, nRange, false));
                                }
                                if (pNewItemEquip.niPDD > 0)
                                {
                                    pNewItemEquip.niPDD = (short)Math.Max(0, gX.GaussianDistributionVariation(pNewItemEquip.niPDD, nRange, false));
                                }
                                if (pNewItemEquip.niMDD > 0)
                                {
                                    pNewItemEquip.niMDD = (short)Math.Max(0, gX.GaussianDistributionVariation(pNewItemEquip.niMDD, nRange, false));
                                }

                                if (pNewItemEquip.niSpeed > 0)
                                {
                                    pNewItemEquip.niSpeed = (short)Math.Max(0, gX.GaussianDistributionVariation(pNewItemEquip.niSpeed, nRange, false));
                                }
                                if (pNewItemEquip.niJump > 0)
                                {
                                    pNewItemEquip.niJump = (short)Math.Max(0, gX.GaussianDistributionVariation(pNewItemEquip.niJump, nRange, false));
                                }
                            }
                            // pNewItemEquip.ApplyRandStatOption(pGemItem.RandOption * (bStimulantUsed ? 2 : 1), false);
                            else if (pGemItem.RandStat > 0)
                            {
                                var gX = new GaussianRandom();

                                var nRange = pGemItem.RandStat * (bStimulantUsed ? 2 : 1);

                                if (pNewItemEquip.niSTR > 0)
                                {
                                    pNewItemEquip.niSTR = (short)Math.Max(0, gX.GaussianDistributionVariation(pNewItemEquip.niSTR, nRange, false));
                                }
                                if (pNewItemEquip.niLUK > 0)
                                {
                                    pNewItemEquip.niLUK = (short)Math.Max(0, gX.GaussianDistributionVariation(pNewItemEquip.niLUK, nRange, false));
                                }
                                if (pNewItemEquip.niINT > 0)
                                {
                                    pNewItemEquip.niINT = (short)Math.Max(0, gX.GaussianDistributionVariation(pNewItemEquip.niINT, nRange, false));
                                }
                                if (pNewItemEquip.niDEX > 0)
                                {
                                    pNewItemEquip.niDEX = (short)Math.Max(0, gX.GaussianDistributionVariation(pNewItemEquip.niDEX, nRange, false));
                                }

                                if (pNewItemEquip.niACC > 0)
                                {
                                    pNewItemEquip.niACC = (short)Math.Max(0, gX.GaussianDistributionVariation(pNewItemEquip.niACC, nRange, false));
                                }
                                if (pNewItemEquip.niEVA > 0)
                                {
                                    pNewItemEquip.niEVA = (short)Math.Max(0, gX.GaussianDistributionVariation(pNewItemEquip.niEVA, nRange, false));
                                }
                            }
                        }
                    }

                    InventoryManipulator.InsertInto(pChar, pNewItemEquip);
                }
                else
                {
                    pNewItemRaw.nNumber = (short)makerItem.ItemNum;
                    InventoryManipulator.InsertInto(pChar, pNewItemRaw);
                }

                // remove gems if any
                foreach (var nGemItemId in aGemItemIds)
                {
                    InventoryManipulator.RemoveQuantity(pChar, nGemItemId, 1);                     //InventoryManipulator.RemoveFrom(pChar, (byte)InventoryType.Etc, itemSlot, 1);
                }

                foreach (var entry in makerItem.RandomReward)
                {
                    if (Constants.Rand.Next(100) >= entry.Prob)
                    {
                        continue;
                    }

                    var pRandRewardItem = MasterManager.CreateItem(entry.ItemID);

                    pRandRewardItem.nNumber = (short)entry.ItemNum;

                    InventoryManipulator.InsertInto(pChar, pRandRewardItem);
                }

                // END MAKER ITEM CREATION
            }

            // END RECIPE PROCESSING

            // SEND RESPONSE PACKETS

            pChar.SendPacket(CreateItemResponse(bSuccess, bStimulantUsed, makerItem, aGemItemIds));

            pChar.SendPacket(MakerItemEffectLocal(bSuccess));
            pChar.Field.Broadcast(MakerItemEffectRemote(pChar.dwId, bSuccess));
        }