public void CreateMiniRoom(Character c, MR_Type nType, CInPacket p) { switch (nType) { case MR_Type.Omok: // todo break; case MR_Type.MemoryGame: // todo break; case MR_Type.TradingRoom: if (c.CurMiniRoom != null) { c.SendPacket(CPacket.SystemMessage("You are already in a trade.")); } else { Log.Debug($"Adding trade mini room to field minirooms."); Add(new CTradingRoom(c)); } break; // Recv [CP_MiniRoom] 90 00 00 05 07 00 70 65 65 66 61 63 65 00 01 00 76 C0 4C 00 case MR_Type.PersonalShop: c.SendMessage("no"); break; case MR_Type.EntrustedShop: { // TODO check closeness to other shops var sTitle = p.DecodeString(); p.Skip(3); // TODO what is this var nShopTemplateId = p.Decode4(); var(nItemSlot, pItem) = InventoryManipulator.GetAnyItem(c, InventoryType.Cash, nShopTemplateId); Log.Info($"Player [{c.Stats.sCharacterName}] attempting to create a shop with ItemID [{nShopTemplateId}] and Title [{sTitle}]"); if (pItem == null || nItemSlot == 0) { c.SendPacket(CPacket.SystemMessage("Invalid item or item slot.")); // packet editing? } else if (!c.Field.MapId.InRange(910000000, 910000023)) { c.SendPacket(CPacket.SystemMessage("Item does not work in this map.")); } else if (!ItemConstants.is_entrusted_shop_item(pItem.nItemID)) { c.SendPacket(CPacket.SystemMessage("Invalid shop item.")); // packet editing?? } else { var pMiniRoom = new CEntrustedShop(c, nShopTemplateId, sTitle); if (pMiniRoom.HasItems()) { c.SendMessage("Please retrieve items from fredrick before opening a shop."); } else { //Add(pMiniRoom); // packet is sent in here } } break; } case MR_Type.CashTradingRoom: // todo break; default: break; } }
// // -------------- Inventory Manipulators // public int GetItemCount(int nItemID) => InventoryManipulator.GetAnyItem(Character, nItemID).Item2?.nNumber ?? 0; // TODO count all items instead of just one
public void UseUpgradeScroll(short nScrollPOS, short nEquipPOS, bool bWhiteScroll) { if (Parent.Stats.nHP <= 0) { return; } var pScrollTemplate = InventoryManipulator.GetItem(Parent, InventoryType.Consume, nScrollPOS).Template as ConsumeItemTemplate; var pEquip = InventoryManipulator.GetItem(Parent, InventoryType.Equip, nEquipPOS) as GW_ItemSlotEquip; var nWhiteScrollPOS = InventoryManipulator.GetAnyItem(Parent, InventoryType.Consume, ItemConstants.WhiteScroll).Item1; if (pEquip == null || pScrollTemplate == null) { return; } if (pEquip.CashItem) { return; } if (pEquip.RemainingUpgradeCount <= 0 && pScrollTemplate.Recover <= 0) { return; } var bSuccess = pScrollTemplate.ScrollSuccess(Constants.Rand); var bDestroy = !bSuccess && pScrollTemplate.ScrollDestroy(Constants.Rand); bWhiteScroll = bWhiteScroll && nWhiteScrollPOS > 0; if (!ItemConstants.is_correct_upgrade_equip(pScrollTemplate.TemplateId, pEquip.nItemID)) // PE, validated client-side { return; } if (bSuccess) { if (pScrollTemplate.Recover > 0) { pEquip.RemainingUpgradeCount += (byte)pScrollTemplate.Recover; } else { if (pScrollTemplate.PreventSlip) { pEquip.nAttribute |= ItemAttributeFlags.Spikes; } else if (pScrollTemplate.WarmSupport) { pEquip.nAttribute |= ItemAttributeFlags.Cold; } else if (pScrollTemplate.RandStat) { var randRange = 2 + (2 * pScrollTemplate.IncRandVol); var gX = new GaussianRandom(); if (pEquip.niSTR > 0) { pEquip.niSTR = (short)Math.Max(0, gX.GaussianDistributionVariation(pEquip.niSTR, randRange, false)); } if (pEquip.niLUK > 0) { pEquip.niLUK = (short)Math.Max(0, gX.GaussianDistributionVariation(pEquip.niLUK, randRange, false)); } if (pEquip.niINT > 0) { pEquip.niINT = (short)Math.Max(0, gX.GaussianDistributionVariation(pEquip.niINT, randRange, false)); } if (pEquip.niDEX > 0) { pEquip.niDEX = (short)Math.Max(0, gX.GaussianDistributionVariation(pEquip.niDEX, randRange, false)); } if (pEquip.niACC > 0) { pEquip.niACC = (short)Math.Max(0, gX.GaussianDistributionVariation(pEquip.niACC, randRange, false)); } if (pEquip.niEVA > 0) { pEquip.niEVA = (short)Math.Max(0, gX.GaussianDistributionVariation(pEquip.niEVA, randRange, false)); } if (pEquip.niMaxHP > 0) { pEquip.niMaxHP = (short)Math.Max(0, gX.GaussianDistributionVariation(pEquip.niMaxHP, randRange, false)); } if (pEquip.niMaxMP > 0) { pEquip.niMaxMP = (short)Math.Max(0, gX.GaussianDistributionVariation(pEquip.niMaxMP, randRange, false)); } if (pEquip.niPAD > 0) { pEquip.niPAD = (short)Math.Max(0, gX.GaussianDistributionVariation(pEquip.niPAD, randRange, false)); } if (pEquip.niMAD > 0) { pEquip.niMAD = (short)Math.Max(0, gX.GaussianDistributionVariation(pEquip.niMAD, randRange, false)); } if (pEquip.niPDD > 0) { pEquip.niPDD = (short)Math.Max(0, gX.GaussianDistributionVariation(pEquip.niPDD, randRange, false)); } if (pEquip.niMDD > 0) { pEquip.niMDD = (short)Math.Max(0, gX.GaussianDistributionVariation(pEquip.niMDD, randRange, false)); } if (pEquip.niSpeed > 0) { pEquip.niSpeed = (short)Math.Max(0, gX.GaussianDistributionVariation(pEquip.niSpeed, randRange, false)); } if (pEquip.niJump > 0) { pEquip.niJump = (short)Math.Max(0, gX.GaussianDistributionVariation(pEquip.niJump, randRange, false)); } } else { pEquip.niSTR += (short)pScrollTemplate.IncSTR; pEquip.niLUK += (short)pScrollTemplate.IncLUK; pEquip.niINT += (short)pScrollTemplate.IncINT; pEquip.niDEX += (short)pScrollTemplate.IncDEX; pEquip.niMaxHP += (short)pScrollTemplate.IncMHP; pEquip.niMaxMP += (short)pScrollTemplate.IncMMP; pEquip.niPAD += (short)pScrollTemplate.IncPAD; // watk pEquip.niMAD += (short)pScrollTemplate.IncMAD; // matk pEquip.niPDD += (short)pScrollTemplate.IncPDD; // wdef pEquip.niMDD += (short)pScrollTemplate.IncMDD; // mdef pEquip.niACC += (short)pScrollTemplate.IncACC; // accuracy pEquip.niEVA += (short)pScrollTemplate.IncEVA; // avoid pEquip.niCraft += (short)pScrollTemplate.IncCraft; // still not sure wtf this is pEquip.niSpeed += (short)pScrollTemplate.IncSpeed; pEquip.niJump += (short)pScrollTemplate.IncJump; } } } if (bDestroy) { InventoryManipulator.RemoveFrom(Parent, InventoryType.Equip, nEquipPOS); } else // success or fail { if (pScrollTemplate.Recover <= 0) // not an upgrade count recovery scroll { pEquip.RemainingUpgradeCount -= 1; // reduce remaining upgrade count if no white scroll if (bSuccess) { pEquip.CurrentUpgradeCount += 1; // increase upgrade count } else if (bWhiteScroll) { pEquip.RemainingUpgradeCount += 1; } if (bWhiteScroll) { InventoryManipulator.RemoveFrom(Parent, InventoryType.Consume, nWhiteScrollPOS); } } Parent.Modify.Inventory(ctx => { ctx.UpdateEquipInformation(pEquip, nEquipPOS); }); } InventoryManipulator.RemoveFrom(Parent, InventoryType.Consume, nScrollPOS); Parent.StatisticsTracker.IncrementScrollUse(pScrollTemplate.TemplateId, bSuccess, bDestroy); Parent.Field.Broadcast(pEquip.ShowItemUpgradeEffect(Parent, bSuccess, bDestroy, bWhiteScroll)); }
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)); }