private static void ReadNPCs() { ushort Count = Reader.ReadUInt16(); for (ushort i = 0; i < Count; i++) { NPCData npc = new NPCData(); npc.ID = Reader.ReadInt32(); npc.Quest = ReadString(); npc.Trunk = Reader.ReadInt16(); npc.Shop = new List <ShopItemData>(); byte ItemCount = Reader.ReadByte(); for (byte iw = 0; iw < ItemCount; iw++) { ShopItemData item = new ShopItemData(); item.ID = Reader.ReadInt32(); item.Price = Reader.ReadInt32(); item.Stock = Reader.ReadInt32(); npc.Shop.Add(item); } NPCs.Add(npc.ID, npc); } }
public static void HandleNPCShop(Character chr, Packet packet) { if (chr.ShopNPCID == 0) { return; } var shopInfo = DataProvider.NPCs[chr.ShopNPCID].Shop; var transferId = "" + chr.ID + "-" + chr.ShopNPCID + "-" + RNG.Range.generate(0, long.MaxValue).ToString(); byte type = packet.ReadByte(); switch ((ShopReq)type) { case ShopReq.Buy: { short slot = packet.ReadShort(); int itemid = packet.ReadInt(); short amount = packet.ReadShort(); if (amount < 1 || (Constants.isEquip(itemid) && amount != 1)) { Program.MainForm.LogAppend("Disconnecting player: trying to buy a negative amount of items OR multiple equips. " + packet); chr.Player.Socket.Disconnect(); return; } if (slot < 0 || slot >= shopInfo.Count) { SendShopResult(chr, ShopRes.BuyUnknown); return; } ShopItemData sid = shopInfo[slot]; int costs = amount * sid.Price; if (false && sid.Stock == 0) { SendShopResult(chr, ShopRes.BuyNoStock); return; } if (sid.ID != itemid) { SendShopResult(chr, ShopRes.BuyUnknown); return; } if (costs > chr.Inventory.Mesos) { SendShopResult(chr, ShopRes.BuyNoMoney); return; } if (Constants.isRechargeable(itemid)) { costs = amount * sid.Price; if (amount > DataProvider.Items[itemid].MaxSlot) // You can't but multiple sets at once { SendShopResult(chr, ShopRes.BuyUnknown); return; } } if (!chr.Inventory.HasSlotsFreeForItem(itemid, amount, true)) { SendShopResult(chr, ShopRes.BuyUnknown); return; } Common.Tracking.MesosTransfer.PlayerBuysFromShop(chr.ID, chr.ShopNPCID, costs, transferId); Common.Tracking.ItemTransfer.PlayerBuysFromShop(chr.ID, chr.ShopNPCID, itemid, amount, transferId, null); chr.Inventory.AddNewItem(itemid, amount); SendShopResult(chr, ShopRes.BuySuccess); sid.Stock -= amount; chr.AddMesos(-costs); break; } case ShopReq.Sell: { short itemslot = packet.ReadShort(); int itemid = packet.ReadInt(); short amount = packet.ReadShort(); byte inv = Constants.getInventory(itemid); BaseItem item = chr.Inventory.GetItem(inv, itemslot); if (item == null || item.ItemID != itemid || amount < 1 || // Do not trigger this when selling stars and such. (!Constants.isRechargeable(itemid) && amount > item.Amount) || (Constants.isEquip(itemid) ? DataProvider.Equips.ContainsKey(itemid) == false : DataProvider.Items.ContainsKey(itemid) == false) || item.CashId != 0) { Program.MainForm.LogAppend("Disconnecting player: invalid trade packet: " + packet); chr.Player.Socket.Disconnect(); return; } int sellPrice = 0; if (Constants.isEquip(itemid)) { var ed = DataProvider.Equips[itemid]; sellPrice = ed.Price; } else { var id = DataProvider.Items[itemid]; sellPrice = id.Price * amount; } if (sellPrice < 0) { SendShopResult(chr, ShopRes.SellIncorrectRequest); return; } // Change amount here (rechargeables are sold as 1) if (Constants.isRechargeable(item.ItemID)) { amount = item.Amount; } Common.Tracking.MesosTransfer.PlayerSellsToShop(chr.ID, chr.ShopNPCID, sellPrice, transferId); Common.Tracking.ItemTransfer.PlayerSellsToShop(chr.ID, chr.ShopNPCID, item.ItemID, amount, transferId, item); if (amount == item.Amount) { chr.Inventory.SetItem(inv, itemslot, null); chr.Inventory.TryRemoveCashItem(item); InventoryPacket.SwitchSlots(chr, itemslot, 0, inv); } else { item.Amount -= amount; InventoryPacket.AddItem(chr, inv, item, false); } chr.AddMesos(sellPrice); SendShopResult(chr, ShopRes.SellSuccess); break; } case ShopReq.Recharge: { short itemslot = packet.ReadShort(); byte inv = 2; BaseItem item = chr.Inventory.GetItem(inv, itemslot); if (item == null || !Constants.isRechargeable(item.ItemID)) { Program.MainForm.LogAppend("Disconnecting player: invalid trade packet: " + packet); chr.Player.Socket.Disconnect(); return; } ShopItemData sid = shopInfo.FirstOrDefault((a) => a.ID == item.ItemID); if (sid == null) { Program.MainForm.LogAppend("Disconnecting player: Item not found in shop; not rechargeable?"); chr.Player.Socket.Disconnect(); return; } if (sid.UnitRechargeRate <= 0.0) { SendShopResult(chr, ShopRes.RechargeIncorrectRequest); return; } ItemData data = DataProvider.Items[item.ItemID]; short maxslot = (short)(data.MaxSlot + chr.Skills.GetRechargeableBonus()); short toFill = (short)(maxslot - item.Amount); int sellPrice = (int)Math.Ceiling(-1.0 * sid.UnitRechargeRate * toFill); sellPrice = Math.Max(sellPrice, 1); if (chr.Inventory.Mesos > -sellPrice) { Common.Tracking.MesosTransfer.PlayerBuysFromShop(chr.ID, chr.ShopNPCID, -sellPrice, transferId); Common.Tracking.ItemTransfer.PlayerBuysFromShop(chr.ID, chr.ShopNPCID, item.ItemID, (short)(maxslot - item.Amount), transferId, item); item.Amount = maxslot; chr.AddMesos(sellPrice); InventoryPacket.AddItem(chr, inv, item, false); SendShopResult(chr, ShopRes.RechargeSuccess); } else { SendShopResult(chr, ShopRes.RechargeNoMoney); // no muney? hier! suk a kok! } break; } case ShopReq.Close: chr.ShopNPCID = 0; chr.NpcSession = null; break; default: { Program.MainForm.LogAppend("Unknown NPC shop action: " + packet); break; } } }