diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/VendorBuyPackets.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/VendorBuyPackets.cs index 7f1a3520f..0573d3263 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/VendorBuyPackets.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/VendorBuyPackets.cs @@ -62,8 +62,8 @@ namespace Server.Network var desc = bis.Description ?? ""; - Stream.Write((byte)desc.Length); - Stream.WriteAsciiFixed(desc, desc.Length); + Stream.Write((byte)(desc.Length + 1)); + Stream.WriteAsciiNull(desc); } } } diff --git a/Projects/Server/Network/Packets/OutgoingVendorBuyPackets.cs b/Projects/Server/Network/Packets/OutgoingVendorBuyPackets.cs index 6abcdc3b0..f70dfa49d 100644 --- a/Projects/Server/Network/Packets/OutgoingVendorBuyPackets.cs +++ b/Projects/Server/Network/Packets/OutgoingVendorBuyPackets.cs @@ -84,7 +84,7 @@ namespace Server.Network var length = 8; for (int i = 0; i < list.Count; i++) { - length += 5 + list[i].Description?.Length ?? 0; + length += 6 + list[i].Description?.Length ?? 0; } var writer = new SpanWriter(stackalloc byte[length]); @@ -101,8 +101,8 @@ namespace Server.Network var desc = bis.Description ?? ""; - writer.Write((byte)desc.Length); - writer.WriteAscii(desc); // Doesn't look like it is used anymore + writer.Write((byte)(desc.Length + 1)); + writer.WriteAsciiNull(desc); } ns.Send(writer.Span); diff --git a/Projects/UOContent/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs b/Projects/UOContent/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs index 9b86a4ff9..4343d359b 100644 --- a/Projects/UOContent/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs +++ b/Projects/UOContent/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs @@ -109,7 +109,7 @@ namespace Server.Commands.Generic public void Acquire(TypeBuilder typeBuilder, ILGenerator il, string fieldName) { - if (!(Value is string toParse)) + if (Value is not string toParse) { return; } diff --git a/Projects/UOContent/Mobiles/Vendors/BaseVendor.cs b/Projects/UOContent/Mobiles/Vendors/BaseVendor.cs index 8c7e98cf6..669722ad7 100644 --- a/Projects/UOContent/Mobiles/Vendors/BaseVendor.cs +++ b/Projects/UOContent/Mobiles/Vendors/BaseVendor.cs @@ -8,6 +8,7 @@ using Server.Misc; using Server.Mobiles; using Server.Network; using Server.Regions; +using Server.Text; namespace Server.Mobiles { @@ -26,8 +27,8 @@ namespace Server.Mobiles private static readonly TimeSpan InventoryDecayTime = TimeSpan.FromHours(1.0); - private readonly List m_ArmorBuyInfo = new(); - private readonly List m_ArmorSellInfo = new(); + private readonly List _buyInfo = new(); + private readonly List _sellInfo = new(); public BaseVendor(string title = null) : base(AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2) @@ -77,7 +78,7 @@ namespace Server.Mobiles { get { - if (!(FindItemOnLayer(Layer.ShopBuy) is Container pack)) + if (FindItemOnLayer(Layer.ShopBuy) is not Container pack) { pack = new Backpack { Layer = Layer.ShopBuy, Visible = false }; AddItem(pack); @@ -130,7 +131,6 @@ namespace Server.Mobiles var info = GetSellInfo(); var totalCost = 0; var validBuy = new List(list.Count); - bool bought; var fromBank = false; var fullPurchase = true; var controlSlots = buyer.FollowersMax - buyer.Followers; @@ -213,7 +213,7 @@ namespace Server.Mobiles return false; } - bought = buyer.AccessLevel >= AccessLevel.GameMaster; + var bought = buyer.AccessLevel >= AccessLevel.GameMaster; var cont = buyer.Backpack; if (!bought && cont != null) @@ -337,18 +337,17 @@ namespace Server.Mobiles { SayTo( buyer, - 1151638, - totalCost - .ToString() - ); // The total of your purchase is ~1_val~ gold, which has been drawn from your bank account. My thanks for the patronage. + 1151638, // The total of your purchase is ~1_val~ gold, which has been drawn from your bank account. My thanks for the patronage. + totalCost.ToString() + ); } else { SayTo( buyer, - 1151639, + 1151639, // The total of your purchase is ~1_val~ gold. My thanks for the patronage. totalCost.ToString() - ); // The total of your purchase is ~1_val~ gold. My thanks for the patronage. + ); } } else @@ -448,48 +447,45 @@ namespace Server.Mobiles foreach (var ssi in info) { - if (ssi.IsSellable(resp.Item)) + if (!ssi.IsSellable(resp.Item)) { - var amount = resp.Amount; + continue; + } - if (amount > resp.Item.Amount) + var amount = resp.Amount; + + if (amount > resp.Item.Amount) + { + amount = resp.Item.Amount; + } + + if (ssi.IsResellable(resp.Item)) + { + var found = false; + + foreach (var bii in buyInfo) { - amount = resp.Item.Amount; + if (bii.Restock(resp.Item, amount)) + { + resp.Item.Consume(amount); + found = true; + + break; + } } - if (ssi.IsResellable(resp.Item)) + if (!found) { - var found = false; + var cont = BuyPack; - foreach (var bii in buyInfo) + if (amount < resp.Item.Amount) { - if (bii.Restock(resp.Item, amount)) + var item = LiftItemDupe(resp.Item, resp.Item.Amount - amount); + + if (item != null) { - resp.Item.Consume(amount); - found = true; - - break; - } - } - - if (!found) - { - var cont = BuyPack; - - if (amount < resp.Item.Amount) - { - var item = LiftItemDupe(resp.Item, resp.Item.Amount - amount); - - if (item != null) - { - item.SetLastMoved(); - cont.DropItem(item); - } - else - { - resp.Item.SetLastMoved(); - cont.DropItem(resp.Item); - } + item.SetLastMoved(); + cont.DropItem(item); } else { @@ -497,22 +493,27 @@ namespace Server.Mobiles cont.DropItem(resp.Item); } } + else + { + resp.Item.SetLastMoved(); + cont.DropItem(resp.Item); + } + } + } + else + { + if (amount < resp.Item.Amount) + { + resp.Item.Amount -= amount; } else { - if (amount < resp.Item.Amount) - { - resp.Item.Amount -= amount; - } - else - { - resp.Item.Delete(); - } + resp.Item.Delete(); } - - GiveGold += ssi.GetSellPriceFor(resp.Item) * amount; - break; } + + GiveGold += ssi.GetSellPriceFor(resp.Item) * amount; + break; } } @@ -566,9 +567,9 @@ namespace Server.Mobiles { LastRestock = Core.Now; - for (var i = 0; i < m_ArmorBuyInfo.Count; ++i) + for (var i = 0; i < _buyInfo.Count; ++i) { - if (m_ArmorBuyInfo[i] is GenericBuyInfo buy) + if (_buyInfo[i] is GenericBuyInfo buy) { buy.DeleteDisplayEntity(); } @@ -578,14 +579,14 @@ namespace Server.Mobiles InitSBInfo(); - m_ArmorBuyInfo.Clear(); - m_ArmorSellInfo.Clear(); + _buyInfo.Clear(); + _sellInfo.Clear(); for (var i = 0; i < SBInfos.Count; i++) { var sbInfo = SBInfos[i]; - m_ArmorBuyInfo.AddRange(sbInfo.BuyInfo); - m_ArmorSellInfo.Add(sbInfo.SellInfo); + _buyInfo.AddRange(sbInfo.BuyInfo); + _sellInfo.Add(sbInfo.SellInfo); } } @@ -852,7 +853,7 @@ namespace Server.Mobiles var list = new List(buyInfo.Length); var cont = BuyPack; - var opls = new List(); + var opls = ObjectPropertyList.Enabled ? new List(buyInfo.Length) : null; for (var idx = 0; idx < buyInfo.Length; idx++) { @@ -863,7 +864,7 @@ namespace Server.Mobiles continue; } - if (!(buyItem is GenericBuyInfo gbi)) + if (buyItem is not GenericBuyInfo gbi) { return; } @@ -884,7 +885,7 @@ namespace Server.Mobiles if (disp is IPropertyListObject obj) { - opls.Add(obj.PropertyList); + opls?.Add(obj.PropertyList); } } @@ -925,7 +926,7 @@ namespace Server.Mobiles if (name != null && list.Count < 250) { list.Add(new BuyItemState(name, cont.Serial, item.Serial, price, item.Amount, item.ItemID, item.Hue)); - opls.Add(item.PropertyList); + opls?.Add(item.PropertyList); } } @@ -954,9 +955,12 @@ namespace Server.Mobiles from.NetState.SendDisplayBuyList(Serial); from.NetState.SendMobileStatus(from); // make sure their gold amount is sent - for (var i = 0; i < opls.Count; ++i) + if (opls != null) { - from.NetState?.Send(opls[i].Buffer); + for (var i = 0; i < opls.Count; ++i) + { + from.NetState?.Send(opls[i].Buffer); + } } SayTo(from, 500186); // Greetings. Have a look around. @@ -1383,9 +1387,9 @@ namespace Server.Mobiles base.AddCustomContextEntries(from, list); } - public virtual IShopSellInfo[] GetSellInfo() => m_ArmorSellInfo.ToArray(); + public virtual IShopSellInfo[] GetSellInfo() => _sellInfo.ToArray(); - public virtual IBuyItemInfo[] GetBuyInfo() => m_ArmorBuyInfo.ToArray(); + public virtual IBuyItemInfo[] GetBuyInfo() => _buyInfo.ToArray(); public virtual int GetPriceScalar() => 100 + Town.FromRegion(Region)?.Tax ?? 0; @@ -1393,7 +1397,7 @@ namespace Server.Mobiles { var priceScalar = GetPriceScalar(); - foreach (var info in m_ArmorBuyInfo.ToArray()) + foreach (var info in _buyInfo.ToArray()) { info.PriceScalar = priceScalar; } diff --git a/Projects/UOContent/Mobiles/Vendors/GenericBuy.cs b/Projects/UOContent/Mobiles/Vendors/GenericBuy.cs index 6e698eebb..eb39fc5dd 100644 --- a/Projects/UOContent/Mobiles/Vendors/GenericBuy.cs +++ b/Projects/UOContent/Mobiles/Vendors/GenericBuy.cs @@ -106,23 +106,7 @@ namespace Server.Mobiles { if (m_Amount <= 0) { - /* - Core.ML using this vendor system is undefined behavior, so being - as it lends itself to an abusable exploit to cause ingame havok - and the stackable items are not found to be over 20 items, this is - changed until there is a better solution. - */ - - object Obj_Disp = GetDisplayEntity(); - - if (Core.ML && Obj_Disp is Item item && !item.Stackable) - { - MaxAmount = Math.Min(20, MaxAmount); - } - else - { - MaxAmount = Math.Min(999, MaxAmount * 2); - } + MaxAmount = Math.Min(999, MaxAmount * 2); } else { @@ -152,22 +136,15 @@ namespace Server.Mobiles m_Amount = MaxAmount; } - private bool IsDeleted(IEntity obj) => obj.Deleted; - public void DeleteDisplayEntity() { - if (m_DisplayEntity == null) - { - return; - } - - m_DisplayEntity.Delete(); + m_DisplayEntity?.Delete(); m_DisplayEntity = null; } public IEntity GetDisplayEntity() { - if (m_DisplayEntity != null && !IsDeleted(m_DisplayEntity)) + if (m_DisplayEntity?.Deleted == false) { return m_DisplayEntity; } @@ -179,13 +156,12 @@ namespace Server.Mobiles m_DisplayEntity = DisplayCache.Cache.Lookup(Type); } - if (m_DisplayEntity == null || IsDeleted(m_DisplayEntity)) + if (m_DisplayEntity?.Deleted != false) { m_DisplayEntity = GetEntity(); + DisplayCache.Cache.Store(Type, m_DisplayEntity, canCache); } - DisplayCache.Cache.Store(Type, m_DisplayEntity, canCache); - return m_DisplayEntity; } @@ -196,7 +172,7 @@ namespace Server.Mobiles private Dictionary m_Table; - public DisplayCache() : base(0) + private DisplayCache() : base(0) { m_Table = new Dictionary(); m_Mobiles = new List(); @@ -301,7 +277,7 @@ namespace Server.Mobiles } } - private void DeleteEntities(List entities) + private static void DeleteEntities(List entities) { foreach (var entity in entities) { diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBJewel.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBJewel.cs index 69de493bb..b4b4c354c 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBJewel.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBJewel.cs @@ -29,20 +29,19 @@ namespace Server.Mobiles 20, 0x1ED0, 0, - new object[] { 500 } + new object[] { 500 } // 500 charges ) - ); // 500 charges - Add( - new GenericBuyInfo( + ); + Add(new GenericBuyInfo( "1060740", typeof(BroadcastCrystal), 131, 20, 0x1ED0, 0, - new object[] { 1000 } + new object[] { 1000 } // 1000 charges ) - ); // 1000 charges + ); Add( new GenericBuyInfo( "1060740", @@ -51,9 +50,9 @@ namespace Server.Mobiles 20, 0x1ED0, 0, - new object[] { 2000 } + new object[] { 2000 } // 2000 charges ) - ); // 2000 charges + ); Add(new GenericBuyInfo("1060740", typeof(ReceiverCrystal), 6, 20, 0x1ED0, 0));