Advertisement
Guest User

BaseVendor.cs

a guest
Apr 16th, 2017
49
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 42.31 KB | None | 0 0
  1. #region Header
  2. // **********
  3. // ServUO - BaseVendor.cs
  4. // **********
  5. #endregion
  6.  
  7. #region References
  8. using System;
  9. using System.Collections;
  10. using System.Collections.Generic;
  11. using System.Linq;
  12.  
  13. using Server.Accounting;
  14. using Server.ContextMenus;
  15. using Server.Engines.BulkOrders;
  16. using Server.Factions;
  17. using Server.Items;
  18. using Server.Misc;
  19. using Server.Mobiles;
  20. using Server.Network;
  21. using Server.Regions;
  22. using daat99;
  23. #endregion
  24.  
  25. namespace Server.Mobiles
  26. {
  27.     public enum VendorShoeType
  28.     {
  29.         None,
  30.         Shoes,
  31.         Boots,
  32.         Sandals,
  33.         ThighBoots
  34.     }
  35.  
  36.     public abstract class BaseVendor : BaseCreature, IVendor
  37.     {
  38.         public static List<BaseVendor> AllVendors { get; private set; }
  39.  
  40.         static BaseVendor()
  41.         {
  42.             AllVendors = new List<BaseVendor>(0x4000);
  43.         }
  44.  
  45.         private const int MaxSell = 500;
  46.  
  47.         protected abstract List<SBInfo> SBInfos { get; }
  48.  
  49.         private readonly ArrayList m_ArmorBuyInfo = new ArrayList();
  50.         private readonly ArrayList m_ArmorSellInfo = new ArrayList();
  51.  
  52.         private DateTime m_LastRestock;
  53.  
  54.         public override bool CanTeach { get { return true; } }
  55.  
  56.         public override bool BardImmune { get { return true; } }
  57.  
  58.         public override bool PlayerRangeSensitive { get { return true; } }
  59.  
  60.         public override bool UseSmartAI { get { return true; } }
  61.  
  62.         public virtual bool IsActiveVendor { get { return true; } }
  63.         public virtual bool IsActiveBuyer { get { return IsActiveVendor; } } // response to vendor SELL
  64.         public virtual bool IsActiveSeller { get { return IsActiveVendor; } } // repsonse to vendor BUY
  65.         public virtual bool HasHonestyDiscount { get { return true; } }
  66.  
  67.         public virtual NpcGuild NpcGuild { get { return NpcGuild.None; } }
  68.  
  69.         public virtual bool ChangeRace { get { return true; } }
  70.  
  71.         public override bool IsInvulnerable { get { return true; } }
  72.  
  73.         public virtual DateTime NextTrickOrTreat { get; set; }
  74.  
  75.         public override bool ShowFameTitle { get { return false; } }
  76.  
  77.         public virtual bool IsValidBulkOrder(Item item)
  78.         {
  79.             return false;
  80.         }
  81.  
  82.         public virtual Item CreateBulkOrder(Mobile from, bool fromContextMenu)
  83.         {
  84.             return null;
  85.         }
  86.  
  87.         public virtual bool SupportsBulkOrders(Mobile from)
  88.         {
  89.             return false;
  90.         }
  91.  
  92.         public virtual TimeSpan GetNextBulkOrder(Mobile from)
  93.         {
  94.             return TimeSpan.Zero;
  95.         }
  96.  
  97.         public virtual void OnSuccessfulBulkOrderReceive(Mobile from)
  98.         { }
  99.  
  100.         #region Faction
  101.         public virtual int GetPriceScalar()
  102.         {
  103.             Town town = Town.FromRegion(Region);
  104.  
  105.             if (town != null)
  106.             {
  107.                 return (100 + town.Tax);
  108.             }
  109.  
  110.             return 100;
  111.         }
  112.  
  113.         public void UpdateBuyInfo()
  114.         {
  115.             int priceScalar = GetPriceScalar();
  116.  
  117.             var buyinfo = (IBuyItemInfo[])m_ArmorBuyInfo.ToArray(typeof(IBuyItemInfo));
  118.  
  119.             if (buyinfo != null)
  120.             {
  121.                 foreach (IBuyItemInfo info in buyinfo)
  122.                 {
  123.                     info.PriceScalar = priceScalar;
  124.                 }
  125.             }
  126.         }
  127.         #endregion
  128.  
  129.         private class BulkOrderInfoEntry : ContextMenuEntry
  130.         {
  131.             private readonly Mobile m_From;
  132.             private readonly BaseVendor m_Vendor;
  133.  
  134.             public BulkOrderInfoEntry(Mobile from, BaseVendor vendor)
  135.                 : base(6152, 3)
  136.             {
  137.                 m_From = from;
  138.                 m_Vendor = vendor;
  139.             }
  140.  
  141.             public override void OnClick()
  142.             {
  143.                 if (!m_From.InRange(m_Vendor.Location, 3))
  144.                     return;
  145.  
  146.                 EventSink.InvokeBODOffered(new BODOfferEventArgs(m_From, m_Vendor));
  147.                 if (m_Vendor.SupportsBulkOrders(m_From))
  148.                 {
  149.                     TimeSpan ts = m_Vendor.GetNextBulkOrder(m_From);
  150.  
  151.                     int totalSeconds = (int)ts.TotalSeconds;
  152.                     int totalHours = (totalSeconds + 3599) / 3600;
  153.                     int totalMinutes = (totalSeconds + 59) / 60;
  154.  
  155.                     if (((Core.SE) ? totalMinutes == 0 : totalHours == 0))
  156.                     {
  157.                         m_From.SendLocalizedMessage(1049038); // You can get an order now.
  158.  
  159.                         if (Core.AOS)
  160.                         {
  161.                             Item bulkOrder = m_Vendor.CreateBulkOrder(m_From, true);
  162.  
  163.                             if (bulkOrder is LargeBOD)
  164.                             {
  165.                                 m_From.SendGump(new LargeBODAcceptGump(m_From, (LargeBOD)bulkOrder));
  166.                             }
  167.                             else if (bulkOrder is SmallBOD)
  168.                             {
  169.                                 m_From.SendGump(new SmallBODAcceptGump(m_From, (SmallBOD)bulkOrder));
  170.                             }
  171.                             /*#region FS Edits
  172.                             else if (bulkOrder is LargeMobileBOD)
  173.                             {
  174.                                 m_From.SendGump(new LargeMobileBODAcceptGump(m_From, (LargeMobileBOD)bulkOrder));
  175.                             }
  176.                             else if (bulkOrder is SmallMobileBOD)
  177.                             {
  178.                                 m_From.SendGump(new SmallMobileBODAcceptGump(m_From, (SmallMobileBOD)bulkOrder));
  179.                             }
  180.                             #endregion*/
  181.                         }
  182.                     }
  183.                     else
  184.                     {
  185.                         int oldSpeechHue = m_Vendor.SpeechHue;
  186.                         m_Vendor.SpeechHue = 0x3B2;
  187.  
  188.                         if (Core.SE)
  189.                         {
  190.                             m_Vendor.SayTo(m_From, 1072058, totalMinutes.ToString());
  191.                             // An offer may be available in about ~1_minutes~ minutes.
  192.                         }
  193.                         else
  194.                         {
  195.                             m_Vendor.SayTo(m_From, 1049039, totalHours.ToString()); // An offer may be available in about ~1_hours~ hours.
  196.                         }
  197.  
  198.                         m_Vendor.SpeechHue = oldSpeechHue;
  199.                     }
  200.                 }
  201.             }
  202.         }
  203.  
  204.         public BaseVendor(string title)
  205.             : base(AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 5)
  206.         {
  207.             AllVendors.Add(this);
  208.  
  209.             LoadSBInfo();
  210.  
  211.             Title = title;
  212.  
  213.             InitBody();
  214.             InitOutfit();
  215.  
  216.             Container pack;
  217.             //these packs MUST exist, or the client will crash when the packets are sent
  218.             pack = new Backpack();
  219.             pack.Layer = Layer.ShopBuy;
  220.             pack.Movable = false;
  221.             pack.Visible = false;
  222.             AddItem(pack);
  223.  
  224.             pack = new Backpack();
  225.             pack.Layer = Layer.ShopResale;
  226.             pack.Movable = false;
  227.             pack.Visible = false;
  228.             AddItem(pack);
  229.  
  230.             m_LastRestock = DateTime.UtcNow;
  231.         }
  232.  
  233.         public BaseVendor(Serial serial)
  234.             : base(serial)
  235.         {
  236.             AllVendors.Add(this);
  237.         }
  238.  
  239.         public override void OnDelete()
  240.         {
  241.             base.OnDelete();
  242.  
  243.             AllVendors.Remove(this);
  244.         }
  245.  
  246.         public override void OnAfterDelete()
  247.         {
  248.             base.OnAfterDelete();
  249.            
  250.             AllVendors.Remove(this);
  251.         }
  252.  
  253.         public DateTime LastRestock { get { return m_LastRestock; } set { m_LastRestock = value; } }
  254.  
  255.         public virtual TimeSpan RestockDelay { get { return TimeSpan.FromHours(1); } }
  256.  
  257.         public Container BuyPack
  258.         {
  259.             get
  260.             {
  261.                 Container pack = FindItemOnLayer(Layer.ShopBuy) as Container;
  262.  
  263.                 if (pack == null)
  264.                 {
  265.                     pack = new Backpack();
  266.                     pack.Layer = Layer.ShopBuy;
  267.                     pack.Visible = false;
  268.                     AddItem(pack);
  269.                 }
  270.  
  271.                 return pack;
  272.             }
  273.         }
  274.  
  275.         public abstract void InitSBInfo();
  276.  
  277.         public virtual bool IsTokunoVendor { get { return (Map == Map.Tokuno); } }
  278.         public virtual bool IsStygianVendor { get { return (Map == Map.TerMur); } }
  279.  
  280.         protected void LoadSBInfo()
  281.         {
  282.             m_LastRestock = DateTime.UtcNow;
  283.  
  284.             for (int i = 0; i < m_ArmorBuyInfo.Count; ++i)
  285.             {
  286.                 GenericBuyInfo buy = m_ArmorBuyInfo[i] as GenericBuyInfo;
  287.  
  288.                 if (buy != null)
  289.                 {
  290.                     buy.DeleteDisplayEntity();
  291.                 }
  292.             }
  293.  
  294.             SBInfos.Clear();
  295.  
  296.             InitSBInfo();
  297.  
  298.             m_ArmorBuyInfo.Clear();
  299.             m_ArmorSellInfo.Clear();
  300.  
  301.             for (int i = 0; i < SBInfos.Count; i++)
  302.             {
  303.                 SBInfo sbInfo = SBInfos[i];
  304.                 m_ArmorBuyInfo.AddRange(sbInfo.BuyInfo);
  305.                 m_ArmorSellInfo.Add(sbInfo.SellInfo);
  306.             }
  307.         }
  308.  
  309.         public virtual bool GetGender()
  310.         {
  311.             return Utility.RandomBool();
  312.         }
  313.  
  314.         public virtual void InitBody()
  315.         {
  316.             InitStats(100, 100, 25);
  317.  
  318.             SpeechHue = Utility.RandomDyedHue();
  319.             Hue = Utility.RandomSkinHue();
  320.  
  321.             if (Female = GetGender())
  322.             {
  323.                 Body = 0x191;
  324.                 Name = NameList.RandomName("female");
  325.             }
  326.             else
  327.             {
  328.                 Body = 0x190;
  329.                 Name = NameList.RandomName("male");
  330.             }
  331.         }
  332.  
  333.         public virtual int GetRandomHue()
  334.         {
  335.             switch (Utility.Random(5))
  336.             {
  337.                 default:
  338.                 case 0:
  339.                     return Utility.RandomBlueHue();
  340.                 case 1:
  341.                     return Utility.RandomGreenHue();
  342.                 case 2:
  343.                     return Utility.RandomRedHue();
  344.                 case 3:
  345.                     return Utility.RandomYellowHue();
  346.                 case 4:
  347.                     return Utility.RandomNeutralHue();
  348.             }
  349.         }
  350.  
  351.         public virtual int GetShoeHue()
  352.         {
  353.             if (0.1 > Utility.RandomDouble())
  354.             {
  355.                 return 0;
  356.             }
  357.  
  358.             return Utility.RandomNeutralHue();
  359.         }
  360.  
  361.         public virtual VendorShoeType ShoeType { get { return VendorShoeType.Shoes; } }
  362.  
  363.         public virtual void CheckMorph()
  364.         {
  365.             if (!ChangeRace)
  366.                 return;
  367.  
  368.             if (CheckGargoyle())
  369.             {
  370.                 return;
  371.             }
  372.             #region SA
  373.             else if (CheckTerMur())
  374.             {
  375.                 return;
  376.             }
  377.             #endregion
  378.  
  379.             else if (CheckNecromancer())
  380.             {
  381.                 return;
  382.             }
  383.             else if (CheckTokuno())
  384.             {
  385.                 return;
  386.             }
  387.         }
  388.  
  389.         public virtual bool CheckTokuno()
  390.         {
  391.             if (Map != Map.Tokuno)
  392.             {
  393.                 return false;
  394.             }
  395.  
  396.             NameList n;
  397.  
  398.             if (Female)
  399.             {
  400.                 n = NameList.GetNameList("tokuno female");
  401.             }
  402.             else
  403.             {
  404.                 n = NameList.GetNameList("tokuno male");
  405.             }
  406.  
  407.             if (!n.ContainsName(Name))
  408.             {
  409.                 TurnToTokuno();
  410.             }
  411.  
  412.             return true;
  413.         }
  414.  
  415.         public virtual void TurnToTokuno()
  416.         {
  417.             if (Female)
  418.             {
  419.                 Name = NameList.RandomName("tokuno female");
  420.             }
  421.             else
  422.             {
  423.                 Name = NameList.RandomName("tokuno male");
  424.             }
  425.         }
  426.  
  427.         public virtual bool CheckGargoyle()
  428.         {
  429.             Map map = Map;
  430.  
  431.             if (map != Map.Ilshenar)
  432.             {
  433.                 return false;
  434.             }
  435.  
  436.             if (!Region.IsPartOf("Gargoyle City"))
  437.             {
  438.                 return false;
  439.             }
  440.  
  441.             if (Body != 0x2F6 || (Hue & 0x8000) == 0)
  442.             {
  443.                 TurnToGargoyle();
  444.             }
  445.  
  446.             return true;
  447.         }
  448.  
  449.         #region SA Change
  450.         public virtual bool CheckTerMur()
  451.         {
  452.             Map map = Map;
  453.  
  454.             if (map != Map.TerMur)
  455.             {
  456.                 return false;
  457.             }
  458.  
  459.             if (!Region.IsPartOf("Royal City") && !Region.IsPartOf("Holy City"))
  460.             {
  461.                 return false;
  462.             }
  463.  
  464.             if (Body != 0x29A || Body != 0x29B)
  465.             {
  466.                 TurnToGargRace();
  467.             }
  468.  
  469.             return true;
  470.         }
  471.         #endregion
  472.  
  473.         public virtual bool CheckNecromancer()
  474.         {
  475.             Map map = Map;
  476.  
  477.             if (map != Map.Malas)
  478.             {
  479.                 return false;
  480.             }
  481.  
  482.             if (!Region.IsPartOf("Umbra"))
  483.             {
  484.                 return false;
  485.             }
  486.  
  487.             if (Hue != 0x83E8)
  488.             {
  489.                 TurnToNecromancer();
  490.             }
  491.  
  492.             return true;
  493.         }
  494.  
  495.         public override void OnAfterSpawn()
  496.         {
  497.             CheckMorph();
  498.         }
  499.  
  500.         protected override void OnMapChange(Map oldMap)
  501.         {
  502.             base.OnMapChange(oldMap);
  503.  
  504.             CheckMorph();
  505.  
  506.             LoadSBInfo();
  507.         }
  508.  
  509.         public virtual int GetRandomNecromancerHue()
  510.         {
  511.             switch (Utility.Random(20))
  512.             {
  513.                 case 0:
  514.                     return 0;
  515.                 case 1:
  516.                     return 0x4E9;
  517.                 default:
  518.                     return Utility.RandomList(0x485, 0x497);
  519.             }
  520.         }
  521.  
  522.         public virtual void TurnToNecromancer()
  523.         {
  524.             for (int i = 0; i < Items.Count; ++i)
  525.             {
  526.                 Item item = Items[i];
  527.  
  528.                 if (item is Hair || item is Beard)
  529.                 {
  530.                     item.Hue = 0;
  531.                 }
  532.                 else if (item is BaseClothing || item is BaseWeapon || item is BaseArmor || item is BaseTool)
  533.                 {
  534.                     item.Hue = GetRandomNecromancerHue();
  535.                 }
  536.             }
  537.  
  538.             HairHue = 0;
  539.             FacialHairHue = 0;
  540.  
  541.             Hue = 0x83E8;
  542.         }
  543.  
  544.         public virtual void TurnToGargoyle()
  545.         {
  546.             for (int i = 0; i < Items.Count; ++i)
  547.             {
  548.                 Item item = Items[i];
  549.  
  550.                 if (item is BaseClothing || item is Hair || item is Beard)
  551.                 {
  552.                     item.Delete();
  553.                 }
  554.             }
  555.  
  556.             HairItemID = 0;
  557.             FacialHairItemID = 0;
  558.  
  559.             Body = 0x2F6;
  560.             Hue = Utility.RandomBrightHue() | 0x8000;
  561.             Name = NameList.RandomName("gargoyle vendor");
  562.  
  563.             CapitalizeTitle();
  564.         }
  565.  
  566.         #region SA
  567.         public virtual void TurnToGargRace()
  568.         {
  569.             for (int i = 0; i < Items.Count; ++i)
  570.             {
  571.                 Item item = Items[i];
  572.  
  573.                 if (item is BaseClothing)
  574.                 {
  575.                     item.Delete();
  576.                 }
  577.             }
  578.  
  579.             Race = Race.Gargoyle;
  580.  
  581.             Hue = Race.RandomSkinHue();
  582.  
  583.             HairItemID = Race.RandomHair(Female);
  584.             HairHue = Race.RandomHairHue();
  585.  
  586.             FacialHairItemID = Race.RandomFacialHair(Female);
  587.             if (FacialHairItemID != 0)
  588.             {
  589.                 FacialHairHue = Race.RandomHairHue();
  590.             }
  591.             else
  592.             {
  593.                 FacialHairHue = 0;
  594.             }
  595.  
  596.             InitGargOutfit();
  597.  
  598.             if (Female = GetGender())
  599.             {
  600.                 Body = 0x29B;
  601.                 Name = NameList.RandomName("gargoyle female");
  602.             }
  603.             else
  604.             {
  605.                 Body = 0x29A;
  606.                 Name = NameList.RandomName("gargoyle male");
  607.             }
  608.  
  609.             CapitalizeTitle();
  610.         }
  611.         #endregion
  612.  
  613.         public virtual void CapitalizeTitle()
  614.         {
  615.             string title = Title;
  616.  
  617.             if (title == null)
  618.             {
  619.                 return;
  620.             }
  621.  
  622.             var split = title.Split(' ');
  623.  
  624.             for (int i = 0; i < split.Length; ++i)
  625.             {
  626.                 if (Insensitive.Equals(split[i], "the"))
  627.                 {
  628.                     continue;
  629.                 }
  630.  
  631.                 if (split[i].Length > 1)
  632.                 {
  633.                     split[i] = Char.ToUpper(split[i][0]) + split[i].Substring(1);
  634.                 }
  635.                 else if (split[i].Length > 0)
  636.                 {
  637.                     split[i] = Char.ToUpper(split[i][0]).ToString();
  638.                 }
  639.             }
  640.  
  641.             Title = String.Join(" ", split);
  642.         }
  643.  
  644.         public virtual int GetHairHue()
  645.         {
  646.             return Utility.RandomHairHue();
  647.         }
  648.  
  649.         public virtual void InitOutfit()
  650.         {
  651.             switch (Utility.Random(3))
  652.             {
  653.                 case 0:
  654.                     AddItem(new FancyShirt(GetRandomHue()));
  655.                     break;
  656.                 case 1:
  657.                     AddItem(new Doublet(GetRandomHue()));
  658.                     break;
  659.                 case 2:
  660.                     AddItem(new Shirt(GetRandomHue()));
  661.                     break;
  662.             }
  663.  
  664.             switch (ShoeType)
  665.             {
  666.                 case VendorShoeType.Shoes:
  667.                     AddItem(new Shoes(GetShoeHue()));
  668.                     break;
  669.                 case VendorShoeType.Boots:
  670.                     AddItem(new Boots(GetShoeHue()));
  671.                     break;
  672.                 case VendorShoeType.Sandals:
  673.                     AddItem(new Sandals(GetShoeHue()));
  674.                     break;
  675.                 case VendorShoeType.ThighBoots:
  676.                     AddItem(new ThighBoots(GetShoeHue()));
  677.                     break;
  678.             }
  679.  
  680.             int hairHue = GetHairHue();
  681.  
  682.             Utility.AssignRandomHair(this, hairHue);
  683.             Utility.AssignRandomFacialHair(this, hairHue);
  684.            
  685.             if (Body == 0x191)
  686.             {
  687.                 FacialHairItemID = 0;
  688.             }
  689.                        
  690.             if (Body == 0x191)
  691.             {
  692.                 switch (Utility.Random(6))
  693.                 {
  694.                     case 0:
  695.                         AddItem(new ShortPants(GetRandomHue()));
  696.                         break;
  697.                     case 1:
  698.                     case 2:
  699.                         AddItem(new Kilt(GetRandomHue()));
  700.                         break;
  701.                     case 3:
  702.                     case 4:
  703.                     case 5:
  704.                         AddItem(new Skirt(GetRandomHue()));
  705.                         break;
  706.                 }
  707.             }
  708.             else
  709.             {
  710.                 switch (Utility.Random(2))
  711.                 {
  712.                     case 0:
  713.                         AddItem(new LongPants(GetRandomHue()));
  714.                         break;
  715.                     case 1:
  716.                         AddItem(new ShortPants(GetRandomHue()));
  717.                         break;
  718.                 }
  719.             }
  720.  
  721.             PackGold(100, 200);
  722.         }
  723.  
  724.         #region SA
  725.         public virtual void InitGargOutfit()
  726.         {
  727.             for (int i = 0; i < Items.Count; ++i)
  728.             {
  729.                 Item item = Items[i];
  730.  
  731.                 if (item is BaseClothing)
  732.                 {
  733.                     item.Delete();
  734.                 }
  735.             }
  736.  
  737.             if (Female)
  738.             {
  739.                 switch (Utility.Random(2))
  740.                 {
  741.                     case 0:
  742.                         AddItem(new FemaleGargishClothLegs(GetRandomHue()));
  743.                         AddItem(new FemaleGargishClothKilt(GetRandomHue()));
  744.                         AddItem(new FemaleGargishClothChest(GetRandomHue()));
  745.                         break;
  746.                     case 1:
  747.                         AddItem(new FemaleGargishClothKilt(GetRandomHue()));
  748.                         AddItem(new FemaleGargishClothChest(GetRandomHue()));
  749.                         break;
  750.                 }
  751.             }
  752.             else
  753.             {
  754.                 switch (Utility.Random(2))
  755.                 {
  756.                     case 0:
  757.                         AddItem(new MaleGargishClothLegs(GetRandomHue()));
  758.                         AddItem(new MaleGargishClothKilt(GetRandomHue()));
  759.                         AddItem(new MaleGargishClothChest(GetRandomHue()));
  760.                         break;
  761.                     case 1:
  762.                         AddItem(new MaleGargishClothKilt(GetRandomHue()));
  763.                         AddItem(new MaleGargishClothChest(GetRandomHue()));
  764.                         break;
  765.                 }
  766.             }
  767.             PackGold(100, 200);
  768.         }
  769.         #endregion
  770.  
  771.         public virtual void Restock()
  772.         {
  773.             m_LastRestock = DateTime.UtcNow;
  774.  
  775.             var buyInfo = GetBuyInfo();
  776.  
  777.             foreach (IBuyItemInfo bii in buyInfo)
  778.             {
  779.                 bii.OnRestock();
  780.             }
  781.         }
  782.  
  783.         private static readonly TimeSpan InventoryDecayTime = TimeSpan.FromHours(1.0);
  784.  
  785.         public virtual void VendorBuy(Mobile from)
  786.         {
  787.             if (!IsActiveSeller)
  788.             {
  789.                 return;
  790.             }
  791.  
  792.             if (!from.CheckAlive())
  793.             {
  794.                 return;
  795.             }
  796.  
  797.             if (!CheckVendorAccess(from))
  798.             {
  799.                 Say(501522); // I shall not treat with scum like thee!
  800.                 return;
  801.             }
  802.  
  803.             if (DateTime.UtcNow - m_LastRestock > RestockDelay)
  804.             {
  805.                 Restock();
  806.             }
  807.  
  808.             UpdateBuyInfo();
  809.  
  810.             int count = 0;
  811.             List<BuyItemState> list;
  812.             var buyInfo = GetBuyInfo();
  813.             var sellInfo = GetSellInfo();
  814.  
  815.             list = new List<BuyItemState>(buyInfo.Length);
  816.             Container cont = BuyPack;
  817.  
  818.             List<ObjectPropertyList> opls = null;
  819.  
  820.             for (int idx = 0; idx < buyInfo.Length; idx++)
  821.             {
  822.                 IBuyItemInfo buyItem = buyInfo[idx];
  823.  
  824.                 if (buyItem.Amount <= 0 || list.Count >= 250)
  825.                 {
  826.                     continue;
  827.                 }
  828.  
  829.                 // NOTE: Only GBI supported; if you use another implementation of IBuyItemInfo, this will crash
  830.                 GenericBuyInfo gbi = (GenericBuyInfo)buyItem;
  831.                 IEntity disp = gbi.GetDisplayEntity();
  832.  
  833.                 list.Add(
  834.                     new BuyItemState(
  835.                         buyItem.Name,
  836.                         cont.Serial,
  837.                         disp == null ? (Serial)0x7FC0FFEE : disp.Serial,
  838.                         buyItem.Price,
  839.                         buyItem.Amount,
  840.                         buyItem.ItemID,
  841.                         buyItem.Hue));
  842.                 count++;
  843.  
  844.                 if (opls == null)
  845.                 {
  846.                     opls = new List<ObjectPropertyList>();
  847.                 }
  848.  
  849.                 if (disp is Item)
  850.                 {
  851.                     opls.Add(((Item)disp).PropertyList);
  852.                 }
  853.                 else if (disp is Mobile)
  854.                 {
  855.                     opls.Add(((Mobile)disp).PropertyList);
  856.                 }
  857.             }
  858.  
  859.             var playerItems = cont.Items;
  860.  
  861.             for (int i = playerItems.Count - 1; i >= 0; --i)
  862.             {
  863.                 if (i >= playerItems.Count)
  864.                 {
  865.                     continue;
  866.                 }
  867.  
  868.                 Item item = playerItems[i];
  869.  
  870.                 if ((item.LastMoved + InventoryDecayTime) <= DateTime.UtcNow)
  871.                 {
  872.                     item.Delete();
  873.                 }
  874.             }
  875.  
  876.             for (int i = 0; i < playerItems.Count; ++i)
  877.             {
  878.                 Item item = playerItems[i];
  879.  
  880.                 int price = 0;
  881.                 string name = null;
  882.  
  883.                 foreach (IShopSellInfo ssi in sellInfo)
  884.                 {
  885.                     if (ssi.IsSellable(item))
  886.                     {
  887.                         price = ssi.GetBuyPriceFor(item);
  888.                         name = ssi.GetNameFor(item);
  889.                         break;
  890.                     }
  891.                 }
  892.  
  893.                 if (name != null && list.Count < 250)
  894.                 {
  895.                     list.Add(new BuyItemState(name, cont.Serial, item.Serial, price, item.Amount, item.ItemID, item.Hue));
  896.                     count++;
  897.  
  898.                     if (opls == null)
  899.                     {
  900.                         opls = new List<ObjectPropertyList>();
  901.                     }
  902.  
  903.                     opls.Add(item.PropertyList);
  904.                 }
  905.             }
  906.  
  907.             //one (not all) of the packets uses a byte to describe number of items in the list.  Osi = dumb.
  908.             //if ( list.Count > 255 )
  909.             //  Console.WriteLine( "Vendor Warning: Vendor {0} has more than 255 buy items, may cause client errors!", this );
  910.  
  911.             if (list.Count > 0)
  912.             {
  913.                 list.Sort(new BuyItemStateComparer());
  914.  
  915.                 SendPacksTo(from);
  916.  
  917.                 NetState ns = from.NetState;
  918.  
  919.                 if (ns == null)
  920.                 {
  921.                     return;
  922.                 }
  923.  
  924.                 if (ns.ContainerGridLines)
  925.                 {
  926.                     from.Send(new VendorBuyContent6017(list));
  927.                 }
  928.                 else
  929.                 {
  930.                     from.Send(new VendorBuyContent(list));
  931.                 }
  932.  
  933.                 from.Send(new VendorBuyList(this, list));
  934.  
  935.                 if (ns.HighSeas)
  936.                 {
  937.                     from.Send(new DisplayBuyListHS(this));
  938.                 }
  939.                 else
  940.                 {
  941.                     from.Send(new DisplayBuyList(this));
  942.                 }
  943.  
  944.                 from.Send(new MobileStatusExtended(from)); //make sure their gold amount is sent
  945.  
  946.                 if (opls != null)
  947.                 {
  948.                     for (int i = 0; i < opls.Count; ++i)
  949.                     {
  950.                         from.Send(opls[i]);
  951.                     }
  952.                 }
  953.  
  954.                 SayTo(from, 500186); // Greetings.  Have a look around.
  955.             }
  956.         }
  957.  
  958.         public virtual void SendPacksTo(Mobile from)
  959.         {
  960.             Item pack = FindItemOnLayer(Layer.ShopBuy);
  961.  
  962.             if (pack == null)
  963.             {
  964.                 pack = new Backpack();
  965.                 pack.Layer = Layer.ShopBuy;
  966.                 pack.Movable = false;
  967.                 pack.Visible = false;
  968.                 AddItem(pack);
  969.             }
  970.  
  971.             from.Send(new EquipUpdate(pack));
  972.  
  973.             pack = FindItemOnLayer(Layer.ShopSell);
  974.  
  975.             if (pack != null)
  976.             {
  977.                 from.Send(new EquipUpdate(pack));
  978.             }
  979.  
  980.             pack = FindItemOnLayer(Layer.ShopResale);
  981.  
  982.             if (pack == null)
  983.             {
  984.                 pack = new Backpack();
  985.                 pack.Layer = Layer.ShopResale;
  986.                 pack.Movable = false;
  987.                 pack.Visible = false;
  988.                 AddItem(pack);
  989.             }
  990.  
  991.             from.Send(new EquipUpdate(pack));
  992.         }
  993.  
  994.         public virtual void VendorSell(Mobile from)
  995.         {
  996.             if (!IsActiveBuyer)
  997.             {
  998.                 return;
  999.             }
  1000.  
  1001.             if (!from.CheckAlive())
  1002.             {
  1003.                 return;
  1004.             }
  1005.  
  1006.             if (!CheckVendorAccess(from))
  1007.             {
  1008.                 Say(501522); // I shall not treat with scum like thee!
  1009.                 return;
  1010.             }
  1011.  
  1012.             Container pack = from.Backpack;
  1013.  
  1014.             if (pack != null)
  1015.             {
  1016.                 var info = GetSellInfo();
  1017.  
  1018.                 Dictionary<Item, SellItemState> table = new Dictionary<Item, SellItemState>();
  1019.  
  1020.                 foreach (IShopSellInfo ssi in info)
  1021.                 {
  1022.                     var items = pack.FindItemsByType(ssi.Types);
  1023.  
  1024.                     foreach (Item item in items)
  1025.                     {
  1026.                         if (item is Container && (item).Items.Count != 0)
  1027.                         {
  1028.                             continue;
  1029.                         }
  1030.  
  1031.                         if (item.IsStandardLoot() && item.Movable && ssi.IsSellable(item))
  1032.                         {
  1033.                             table[item] = new SellItemState(item, ssi.GetSellPriceFor(item), ssi.GetNameFor(item));
  1034.                         }
  1035.                     }
  1036.                 }
  1037.  
  1038.                 if (table.Count > 0)
  1039.                 {
  1040.                     SendPacksTo(from);
  1041.  
  1042.                     from.Send(new VendorSellList(this, table.Values));
  1043.                 }
  1044.                 else
  1045.                 {
  1046.                     Say(true, "You have nothing I would be interested in.");
  1047.                 }
  1048.             }
  1049.         }
  1050.  
  1051.         public override bool OnDragDrop(Mobile from, Item dropped)
  1052.         {
  1053.             /* TODO: Thou art giving me? and fame/karma for gold gifts */
  1054.             if (dropped is SmallBOD || dropped is LargeBOD)
  1055.             {
  1056.                 PlayerMobile pm = from as PlayerMobile;
  1057.  
  1058.                 if (Core.ML && pm != null && pm.NextBODTurnInTime > DateTime.UtcNow)
  1059.                 {
  1060.                     SayTo(from, 1079976); // You'll have to wait a few seconds while I inspect the last order.
  1061.                     return false;
  1062.                 }
  1063.                 else if (!IsValidBulkOrder(dropped) || !SupportsBulkOrders(from))
  1064.                 {
  1065.                     SayTo(from, 1045130); // That order is for some other shopkeeper.
  1066.                     return false;
  1067.                 }
  1068.                 else if ((dropped is SmallBOD && !((SmallBOD)dropped).Complete) ||
  1069.                          (dropped is LargeBOD && !((LargeBOD)dropped).Complete))
  1070.                 {
  1071.                     SayTo(from, 1045131); // You have not completed the order yet.
  1072.                     return false;
  1073.                 }
  1074.  
  1075.                 Item reward;
  1076.                 int gold, fame;
  1077.  
  1078.                 if (dropped is SmallBOD)
  1079.                 {
  1080.                     ((SmallBOD)dropped).GetRewards(out reward, out gold, out fame);
  1081.                 }
  1082.                 else
  1083.                 {
  1084.                     ((LargeBOD)dropped).GetRewards(out reward, out gold, out fame);
  1085.                 }
  1086.  
  1087.                 from.SendSound(0x3D);
  1088.  
  1089.                 SayTo(from, 1045132); // Thank you so much!  Here is a reward for your effort.
  1090.  
  1091.                 if (reward != null)
  1092.                 {
  1093.                     from.AddToBackpack(reward);
  1094.                 }
  1095.  
  1096.                 if (gold > 1000)
  1097.                 {
  1098.                     from.AddToBackpack(new BankCheck(gold));
  1099.                 }
  1100.                 else if (gold > 0)
  1101.                 {
  1102.                     from.AddToBackpack(new Gold(gold));
  1103.                 }
  1104.  
  1105.                 Titles.AwardFame(from, fame, true);
  1106.  
  1107.                 OnSuccessfulBulkOrderReceive(from);
  1108.                 Server.Engines.CityLoyalty.CityLoyaltySystem.OnBODTurnIn(from, gold);
  1109.  
  1110.                 if (Core.ML && pm != null)
  1111.                 {
  1112.                     pm.NextBODTurnInTime = DateTime.UtcNow + TimeSpan.FromSeconds(10.0);
  1113.                 }
  1114.  
  1115.                 dropped.Delete();
  1116.                 return true;
  1117.             }
  1118.  
  1119.             return base.OnDragDrop(from, dropped);
  1120.         }
  1121.  
  1122.         private GenericBuyInfo LookupDisplayObject(object obj)
  1123.         {
  1124.             var buyInfo = GetBuyInfo();
  1125.  
  1126.             for (int i = 0; i < buyInfo.Length; ++i)
  1127.             {
  1128.                 GenericBuyInfo gbi = (GenericBuyInfo)buyInfo[i];
  1129.  
  1130.                 if (gbi.GetDisplayEntity() == obj)
  1131.                 {
  1132.                     return gbi;
  1133.                 }
  1134.             }
  1135.  
  1136.             return null;
  1137.         }
  1138.  
  1139.         private void ProcessSinglePurchase(
  1140.             BuyItemResponse buy,
  1141.             IBuyItemInfo bii,
  1142.             List<BuyItemResponse> validBuy,
  1143.             ref int controlSlots,
  1144.             ref bool fullPurchase,
  1145.             ref double totalCost)
  1146.         {
  1147.             int amount = buy.Amount;
  1148.  
  1149.             if (amount > bii.Amount)
  1150.             {
  1151.                 amount = bii.Amount;
  1152.             }
  1153.  
  1154.             if (amount <= 0)
  1155.             {
  1156.                 return;
  1157.             }
  1158.  
  1159.             int slots = bii.ControlSlots * amount;
  1160.  
  1161.             if (controlSlots >= slots)
  1162.             {
  1163.                 controlSlots -= slots;
  1164.             }
  1165.             else
  1166.             {
  1167.                 fullPurchase = false;
  1168.                 return;
  1169.             }
  1170.  
  1171.             totalCost += (double)bii.Price * amount;
  1172.             validBuy.Add(buy);
  1173.         }
  1174.  
  1175.         private void ProcessValidPurchase(int amount, IBuyItemInfo bii, Mobile buyer, Container cont)
  1176.         {
  1177.             if (amount > bii.Amount)
  1178.             {
  1179.                 amount = bii.Amount;
  1180.             }
  1181.  
  1182.             if (amount < 1)
  1183.             {
  1184.                 return;
  1185.             }
  1186.  
  1187.             bii.Amount -= amount;
  1188.  
  1189.             IEntity o = bii.GetEntity();
  1190.  
  1191.             if (o is Item)
  1192.             {
  1193.                 Item item = (Item)o;
  1194.  
  1195.                 if (item.Stackable)
  1196.                 {
  1197.                     item.Amount = amount;
  1198.  
  1199.                     if (cont == null || !cont.TryDropItem(buyer, item, false))
  1200.                     {
  1201.                         item.MoveToWorld(buyer.Location, buyer.Map);
  1202.                     }
  1203.                 }
  1204.                 else
  1205.                 {
  1206.                     item.Amount = 1;
  1207.  
  1208.                     if (cont == null || !cont.TryDropItem(buyer, item, false))
  1209.                     {
  1210.                         item.MoveToWorld(buyer.Location, buyer.Map);
  1211.                     }
  1212.  
  1213.                     for (int i = 1; i < amount; i++)
  1214.                     {
  1215.                         item = bii.GetEntity() as Item;
  1216.  
  1217.                         if (item != null)
  1218.                         {
  1219.                             item.Amount = 1;
  1220.  
  1221.                             if (cont == null || !cont.TryDropItem(buyer, item, false))
  1222.                             {
  1223.                                 item.MoveToWorld(buyer.Location, buyer.Map);
  1224.                             }
  1225.                         }
  1226.                     }
  1227.                 }
  1228.             }
  1229.             else if (o is Mobile)
  1230.             {
  1231.                 Mobile m = (Mobile)o;
  1232.  
  1233.                 m.Direction = (Direction)Utility.Random(8);
  1234.                 m.MoveToWorld(buyer.Location, buyer.Map);
  1235.                 m.PlaySound(m.GetIdleSound());
  1236.  
  1237.                 if (m is BaseCreature)
  1238.                 {
  1239.                     ((BaseCreature)m).SetControlMaster(buyer);
  1240.                 }
  1241.  
  1242.                 for (int i = 1; i < amount; ++i)
  1243.                 {
  1244.                     m = bii.GetEntity() as Mobile;
  1245.  
  1246.                     if (m != null)
  1247.                     {
  1248.                         m.Direction = (Direction)Utility.Random(8);
  1249.                         m.MoveToWorld(buyer.Location, buyer.Map);
  1250.  
  1251.                         if (m is BaseCreature)
  1252.                         {
  1253.                             ((BaseCreature)m).SetControlMaster(buyer);
  1254.                         }
  1255.                     }
  1256.                 }
  1257.             }
  1258.         }
  1259.  
  1260.         public virtual bool OnBuyItems(Mobile buyer, List<BuyItemResponse> list)
  1261.         {
  1262.             if (!IsActiveSeller)
  1263.             {
  1264.                 return false;
  1265.             }
  1266.  
  1267.             if (!buyer.CheckAlive())
  1268.             {
  1269.                 return false;
  1270.             }
  1271.  
  1272.             if (!CheckVendorAccess(buyer))
  1273.             {
  1274.                 Say(501522); // I shall not treat with scum like thee!
  1275.                 return false;
  1276.             }
  1277.  
  1278.             UpdateBuyInfo();
  1279.  
  1280.             //var buyInfo = GetBuyInfo();
  1281.             var info = GetSellInfo();
  1282.             var totalCost = 0.0;
  1283.             var validBuy = new List<BuyItemResponse>(list.Count);
  1284.             Container cont;
  1285.             bool bought = false;
  1286.             bool fromBank = false;
  1287.             bool fullPurchase = true;
  1288.             int controlSlots = buyer.FollowersMax - buyer.Followers;
  1289.  
  1290.             foreach (BuyItemResponse buy in list)
  1291.             {
  1292.                 Serial ser = buy.Serial;
  1293.                 int amount = buy.Amount;
  1294.  
  1295.                 if (ser.IsItem)
  1296.                 {
  1297.                     Item item = World.FindItem(ser);
  1298.  
  1299.                     if (item == null)
  1300.                     {
  1301.                         continue;
  1302.                     }
  1303.  
  1304.                     GenericBuyInfo gbi = LookupDisplayObject(item);
  1305.  
  1306.                     if (gbi != null)
  1307.                     {
  1308.                         ProcessSinglePurchase(buy, gbi, validBuy, ref controlSlots, ref fullPurchase, ref totalCost);
  1309.                     }
  1310.                     else if (item != BuyPack && item.IsChildOf(BuyPack))
  1311.                     {
  1312.                         if (amount > item.Amount)
  1313.                         {
  1314.                             amount = item.Amount;
  1315.                         }
  1316.  
  1317.                         if (amount <= 0)
  1318.                         {
  1319.                             continue;
  1320.                         }
  1321.  
  1322.                         foreach (IShopSellInfo ssi in info)
  1323.                         {
  1324.                             if (ssi.IsSellable(item))
  1325.                             {
  1326.                                 if (ssi.IsResellable(item))
  1327.                                 {
  1328.                                     totalCost += (double)ssi.GetBuyPriceFor(item) * amount;
  1329.                                     validBuy.Add(buy);
  1330.                                     break;
  1331.                                 }
  1332.                             }
  1333.                         }
  1334.                     }
  1335.                 }
  1336.                 else if (ser.IsMobile)
  1337.                 {
  1338.                     Mobile mob = World.FindMobile(ser);
  1339.  
  1340.                     if (mob == null)
  1341.                     {
  1342.                         continue;
  1343.                     }
  1344.  
  1345.                     GenericBuyInfo gbi = LookupDisplayObject(mob);
  1346.  
  1347.                     if (gbi != null)
  1348.                     {
  1349.                         ProcessSinglePurchase(buy, gbi, validBuy, ref controlSlots, ref fullPurchase, ref totalCost);
  1350.                     }
  1351.                 }
  1352.             } //foreach
  1353.  
  1354.             if (fullPurchase && validBuy.Count == 0)
  1355.             {
  1356.                 SayTo(buyer, 500190); // Thou hast bought nothing!
  1357.             }
  1358.             else if (validBuy.Count == 0)
  1359.             {
  1360.                 SayTo(buyer, 500187); // Your order cannot be fulfilled, please try again.
  1361.             }
  1362.  
  1363.             if (validBuy.Count == 0)
  1364.             {
  1365.                 return false;
  1366.             }
  1367.  
  1368.             bought = buyer.AccessLevel >= AccessLevel.GameMaster;
  1369.             var discount = 0.0;
  1370.             cont = buyer.Backpack;
  1371.  
  1372.             if (Core.SA && HasHonestyDiscount)
  1373.             {
  1374.                 double discountPc = 0;
  1375.                 switch (VirtueHelper.GetLevel(buyer, VirtueName.Honesty))
  1376.                 {
  1377.                     case VirtueLevel.Seeker:
  1378.                         discountPc = .1;
  1379.                         break;
  1380.                     case VirtueLevel.Follower:
  1381.                         discountPc = .2;
  1382.                         break;
  1383.                     case VirtueLevel.Knight:
  1384.                         discountPc = .3; break;
  1385.                     default:
  1386.                         discountPc = 0;
  1387.                         break;
  1388.                 }
  1389.                 discount = totalCost - (totalCost * (1.0 - discountPc));
  1390.                 totalCost -= discount;
  1391.             }
  1392.  
  1393.             if (!bought && cont != null)
  1394.             {
  1395.                 if (totalCost <= Int32.MaxValue)
  1396.                 {
  1397.                     if (cont.ConsumeTotal(typeof(Gold), (int)totalCost))
  1398.                     {
  1399.                         bought = true;
  1400.                     }
  1401.                 }
  1402.                 else
  1403.                 {
  1404.                     var items = cont.FindItemsByType<Gold>();
  1405.                     var total = items.Aggregate(0.0, (c, o) => c + o.Amount);
  1406.  
  1407.                     if (total >= totalCost)
  1408.                     {
  1409.                         total = totalCost;
  1410.  
  1411.                         foreach (var o in items)
  1412.                         {
  1413.                             if (o.Amount >= total)
  1414.                             {
  1415.                                 o.Consume((int)total);
  1416.                                 total = 0;
  1417.                             }
  1418.                             else
  1419.                             {
  1420.                                 total -= o.Amount;
  1421.                                 o.Delete();
  1422.                             }
  1423.  
  1424.                             if (total <= 0)
  1425.                             {
  1426.                                 break;
  1427.                             }
  1428.                         }
  1429.  
  1430.                         bought = true;
  1431.                     }
  1432.                 }
  1433.             }
  1434.  
  1435.             //if (totalCost >= 2000)
  1436.             //{
  1437.                 if (!bought)
  1438.                 {
  1439.                     if (totalCost <= Int32.MaxValue)
  1440.                     {
  1441.                         if (Banker.Withdraw(buyer, (int)totalCost))
  1442.                         {
  1443.                             bought = true;
  1444.                             fromBank = false;
  1445.                         }
  1446.                     }
  1447.                     else if (buyer.Account != null && AccountGold.Enabled)
  1448.                     {
  1449.                         if (buyer.Account.WithdrawCurrency(totalCost / AccountGold.CurrencyThreshold))
  1450.                         {
  1451.                             bought = true;
  1452.                             fromBank = false;
  1453.                         }
  1454.                     }
  1455.                 }
  1456.  
  1457.                 if (!bought)
  1458.                 {
  1459.                     cont = buyer.FindBankNoCreate();
  1460.  
  1461.                     if (cont != null)
  1462.                     {
  1463.                         if (totalCost <= Int32.MaxValue)
  1464.                         {
  1465.                             if (cont.ConsumeTotal(typeof(Gold), (int)totalCost))
  1466.                             {
  1467.                                 bought = true;
  1468.                                 fromBank = false;
  1469.                             }
  1470.                         }
  1471.                         else
  1472.                         {
  1473.                             var items = cont.FindItemsByType<Gold>();
  1474.                             var total = items.Aggregate(0.0, (c, o) => c + o.Amount);
  1475.  
  1476.                             if (total >= totalCost)
  1477.                             {
  1478.                                 total = totalCost;
  1479.  
  1480.                                 foreach (var o in items)
  1481.                                 {
  1482.                                     if (o.Amount >= total)
  1483.                                     {
  1484.                                         o.Consume((int)total);
  1485.                                         total = 0;
  1486.                                     }
  1487.                                     else
  1488.                                     {
  1489.                                         total -= o.Amount;
  1490.                                         o.Delete();
  1491.                                     }
  1492.  
  1493.                                     if (total <= 0)
  1494.                                     {
  1495.                                         break;
  1496.                                     }
  1497.                                 }
  1498.  
  1499.                                 bought = true;
  1500.                                 fromBank = false;
  1501.                             }
  1502.                         }
  1503.                     }
  1504.                 }
  1505.             //}
  1506.  
  1507.             if (!bought)
  1508.             {
  1509.                 // ? Begging thy pardon, but thy bank account lacks these funds.
  1510.                 // : Begging thy pardon, but thou casnt afford that.
  1511.                 SayTo(buyer, totalCost >= 2000 ? 500191 : 500192);
  1512.  
  1513.                 return false;
  1514.             }
  1515.  
  1516.             if (discount > 0)
  1517.             {
  1518.                 SayTo(buyer, 1151517, discount.ToString());
  1519.             }
  1520.  
  1521.             buyer.PlaySound(0x32);
  1522.            
  1523.             cont = buyer.Backpack ?? buyer.BankBox;
  1524.  
  1525.             foreach (BuyItemResponse buy in validBuy)
  1526.             {
  1527.                 Serial ser = buy.Serial;
  1528.                 int amount = buy.Amount;
  1529.  
  1530.                 if (amount < 1)
  1531.                 {
  1532.                     continue;
  1533.                 }
  1534.  
  1535.                 if (ser.IsItem)
  1536.                 {
  1537.                     Item item = World.FindItem(ser);
  1538.  
  1539.                     if (item == null)
  1540.                     {
  1541.                         continue;
  1542.                     }
  1543.  
  1544.                     GenericBuyInfo gbi = LookupDisplayObject(item);
  1545.  
  1546.                     if (gbi != null)
  1547.                     {
  1548.                         ProcessValidPurchase(amount, gbi, buyer, cont);
  1549.                     }
  1550.                     else
  1551.                     {
  1552.                         if (amount > item.Amount)
  1553.                         {
  1554.                             amount = item.Amount;
  1555.                         }
  1556.  
  1557.                         foreach (IShopSellInfo ssi in info)
  1558.                         {
  1559.                             if (ssi.IsSellable(item))
  1560.                             {
  1561.                                 if (ssi.IsResellable(item))
  1562.                                 {
  1563.                                     Item buyItem;
  1564.  
  1565.                                     if (amount >= item.Amount)
  1566.                                     {
  1567.                                         buyItem = item;
  1568.                                     }
  1569.                                     else
  1570.                                     {
  1571.                                         buyItem = LiftItemDupe(item, item.Amount - amount);
  1572.  
  1573.                                         if (buyItem == null)
  1574.                                         {
  1575.                                             buyItem = item;
  1576.                                         }
  1577.                                     }
  1578.  
  1579.                                     if (cont == null || !cont.TryDropItem(buyer, buyItem, false))
  1580.                                     {
  1581.                                         buyItem.MoveToWorld(buyer.Location, buyer.Map);
  1582.                                     }
  1583.  
  1584.                                     break;
  1585.                                 }
  1586.                             }
  1587.                         }
  1588.                     }
  1589.                 }
  1590.                 else if (ser.IsMobile)
  1591.                 {
  1592.                     Mobile mob = World.FindMobile(ser);
  1593.  
  1594.                     if (mob == null)
  1595.                     {
  1596.                         continue;
  1597.                     }
  1598.  
  1599.                     GenericBuyInfo gbi = LookupDisplayObject(mob);
  1600.  
  1601.                     if (gbi != null)
  1602.                     {
  1603.                         ProcessValidPurchase(amount, gbi, buyer, cont);
  1604.                     }
  1605.                 }
  1606.             } //foreach
  1607.  
  1608.             if (discount > 0)
  1609.             {
  1610.                 SayTo(buyer, 1151517, discount.ToString());
  1611.             }
  1612.  
  1613.             if (fullPurchase)
  1614.             {
  1615.                 if (buyer.AccessLevel >= AccessLevel.GameMaster)
  1616.                 {
  1617.                     SayTo(buyer, true, "I would not presume to charge thee anything.  Here are the goods you requested.");
  1618.                 }
  1619.                 else if (fromBank)
  1620.                 {
  1621.                     SayTo(
  1622.                         buyer,
  1623.                         true,
  1624.                         "The total of thy purchase is {0} gold, which has been withdrawn from your bank account.  My thanks for the patronage.",
  1625.                         totalCost);
  1626.                 }
  1627.                 else
  1628.                 {
  1629.                     SayTo(buyer, true, "The total of thy purchase is {0} gold.  My thanks for the patronage.", totalCost);
  1630.                 }
  1631.             }
  1632.             else
  1633.             {
  1634.                 if (buyer.AccessLevel >= AccessLevel.GameMaster)
  1635.                 {
  1636.                     SayTo(
  1637.                         buyer,
  1638.                         true,
  1639.                         "I would not presume to charge thee anything.  Unfortunately, I could not sell you all the goods you requested.");
  1640.                 }
  1641.                 else if (fromBank)
  1642.                 {
  1643.                     SayTo(
  1644.                         buyer,
  1645.                         true,
  1646.                         "The total of thy purchase is {0} gold, which has been withdrawn from your bank account.  My thanks for the patronage.  Unfortunately, I could not sell you all the goods you requested.",
  1647.                         totalCost);
  1648.                 }
  1649.                 else
  1650.                 {
  1651.                     SayTo(
  1652.                         buyer,
  1653.                         true,
  1654.                         "The total of thy purchase is {0} gold.  My thanks for the patronage.  Unfortunately, I could not sell you all the goods you requested.",
  1655.                         totalCost);
  1656.                 }
  1657.             }
  1658.  
  1659.             return true;
  1660.         }
  1661.  
  1662.         public virtual bool CheckVendorAccess(Mobile from)
  1663.         {
  1664.             GuardedRegion reg = (GuardedRegion)Region.GetRegion(typeof(GuardedRegion));
  1665.  
  1666.             if (reg != null && !reg.CheckVendorAccess(this, from))
  1667.             {
  1668.                 return false;
  1669.             }
  1670.  
  1671.             if (Region != from.Region)
  1672.             {
  1673.                 reg = (GuardedRegion)from.Region.GetRegion(typeof(GuardedRegion));
  1674.  
  1675.                 if (reg != null && !reg.CheckVendorAccess(this, from))
  1676.                 {
  1677.                     return false;
  1678.                 }
  1679.             }
  1680.  
  1681.             return true;
  1682.         }
  1683.  
  1684.         public virtual bool OnSellItems(Mobile seller, List<SellItemResponse> list)
  1685.         {
  1686.             if (!IsActiveBuyer)
  1687.             {
  1688.                 return false;
  1689.             }
  1690.  
  1691.             if (!seller.CheckAlive())
  1692.             {
  1693.                 return false;
  1694.             }
  1695.  
  1696.             if (!CheckVendorAccess(seller))
  1697.             {
  1698.                 Say(501522); // I shall not treat with scum like thee!
  1699.                 return false;
  1700.             }
  1701.  
  1702.             seller.PlaySound(0x32);
  1703.  
  1704.             var info = GetSellInfo();
  1705.             var buyInfo = GetBuyInfo();
  1706.             int GiveGold = 0;
  1707.             int Sold = 0;
  1708.             Container cont;
  1709.  
  1710.             foreach (SellItemResponse resp in list)
  1711.             {
  1712.                 if (resp.Item.RootParent != seller || resp.Amount <= 0 || !resp.Item.IsStandardLoot() || !resp.Item.Movable ||
  1713.                     (resp.Item is Container && (resp.Item).Items.Count != 0))
  1714.                 {
  1715.                     continue;
  1716.                 }
  1717.  
  1718.                 foreach (IShopSellInfo ssi in info)
  1719.                 {
  1720.                     if (ssi.IsSellable(resp.Item))
  1721.                     {
  1722.                         Sold++;
  1723.                         break;
  1724.                     }
  1725.                 }
  1726.             }
  1727.  
  1728.             if (Sold > MaxSell)
  1729.             {
  1730.                 SayTo(seller, true, "You may only sell {0} items at a time!", MaxSell);
  1731.                 return false;
  1732.             }
  1733.             else if (Sold == 0)
  1734.             {
  1735.                 return true;
  1736.             }
  1737.  
  1738.             foreach (SellItemResponse resp in list)
  1739.             {
  1740.                 if (resp.Item.RootParent != seller || resp.Amount <= 0 || !resp.Item.IsStandardLoot() || !resp.Item.Movable ||
  1741.                     (resp.Item is Container && (resp.Item).Items.Count != 0))
  1742.                 {
  1743.                     continue;
  1744.                 }
  1745.  
  1746.                 foreach (IShopSellInfo ssi in info)
  1747.                 {
  1748.                     if (ssi.IsSellable(resp.Item))
  1749.                     {
  1750.                         int amount = resp.Amount;
  1751.  
  1752.                         if (amount > resp.Item.Amount)
  1753.                         {
  1754.                             amount = resp.Item.Amount;
  1755.                         }
  1756.  
  1757.                         if (ssi.IsResellable(resp.Item))
  1758.                         {
  1759.                             bool found = false;
  1760.  
  1761.                             foreach (IBuyItemInfo bii in buyInfo)
  1762.                             {
  1763.                                 if (bii.Restock(resp.Item, amount))
  1764.                                 {
  1765.                                     resp.Item.Consume(amount);
  1766.                                     found = true;
  1767.  
  1768.                                     break;
  1769.                                 }
  1770.                             }
  1771.  
  1772.                             if (!found)
  1773.                             {
  1774.                                 cont = BuyPack;
  1775.  
  1776.                                 if (amount < resp.Item.Amount)
  1777.                                 {
  1778.                                     Item item = LiftItemDupe(resp.Item, resp.Item.Amount - amount);
  1779.  
  1780.                                     if (item != null)
  1781.                                     {
  1782.                                         item.SetLastMoved();
  1783.                                         cont.DropItem(item);
  1784.                                     }
  1785.                                     else
  1786.                                     {
  1787.                                         resp.Item.SetLastMoved();
  1788.                                         cont.DropItem(resp.Item);
  1789.                                     }
  1790.                                 }
  1791.                                 else
  1792.                                 {
  1793.                                     resp.Item.SetLastMoved();
  1794.                                     cont.DropItem(resp.Item);
  1795.                                 }
  1796.                             }
  1797.                         }
  1798.                         else
  1799.                         {
  1800.                             if (amount < resp.Item.Amount)
  1801.                             {
  1802.                                 resp.Item.Amount -= amount;
  1803.                             }
  1804.                             else
  1805.                             {
  1806.                                 resp.Item.Delete();
  1807.                             }
  1808.                         }
  1809.  
  1810.                         GiveGold += ssi.GetSellPriceFor(resp.Item) * amount;
  1811.                         break;
  1812.                     }
  1813.                 }
  1814.             }
  1815.  
  1816.             if (GiveGold > 0)
  1817.             {
  1818.                 while (GiveGold > 60000)
  1819.                 {
  1820.                     seller.AddToBackpack(new Gold(60000));
  1821.                     GiveGold -= 60000;
  1822.                 }
  1823.  
  1824.                 seller.AddToBackpack(new Gold(GiveGold));
  1825.  
  1826.                 seller.PlaySound(0x0037); //Gold dropping sound
  1827.  
  1828.                 if (SupportsBulkOrders(seller))
  1829.                 {
  1830.                     Item bulkOrder = CreateBulkOrder(seller, false);
  1831.  
  1832.                     if (bulkOrder is LargeBOD)
  1833.                     {
  1834.                         seller.SendGump(new LargeBODAcceptGump(seller, (LargeBOD)bulkOrder));
  1835.                     }
  1836.                     else if (bulkOrder is SmallBOD)
  1837.                     {
  1838.                         seller.SendGump(new SmallBODAcceptGump(seller, (SmallBOD)bulkOrder));
  1839.                     }
  1840.                 }
  1841.             }
  1842.             //no cliloc for this?
  1843.             //SayTo( seller, true, "Thank you! I bought {0} item{1}. Here is your {2}gp.", Sold, (Sold > 1 ? "s" : ""), GiveGold );
  1844.  
  1845.             return true;
  1846.         }
  1847.  
  1848.         public override void Serialize(GenericWriter writer)
  1849.         {
  1850.             base.Serialize(writer);
  1851.  
  1852.             writer.Write(1); // version
  1853.  
  1854.             var sbInfos = SBInfos;
  1855.  
  1856.             for (int i = 0; sbInfos != null && i < sbInfos.Count; ++i)
  1857.             {
  1858.                 SBInfo sbInfo = sbInfos[i];
  1859.                 var buyInfo = sbInfo.BuyInfo;
  1860.  
  1861.                 for (int j = 0; buyInfo != null && j < buyInfo.Count; ++j)
  1862.                 {
  1863.                     GenericBuyInfo gbi = buyInfo[j];
  1864.  
  1865.                     int maxAmount = gbi.MaxAmount;
  1866.                     int doubled = 0;
  1867.  
  1868.                     switch (maxAmount)
  1869.                     {
  1870.                         case 40:
  1871.                             doubled = 1;
  1872.                             break;
  1873.                         case 80:
  1874.                             doubled = 2;
  1875.                             break;
  1876.                         case 160:
  1877.                             doubled = 3;
  1878.                             break;
  1879.                         case 320:
  1880.                             doubled = 4;
  1881.                             break;
  1882.                         case 640:
  1883.                             doubled = 5;
  1884.                             break;
  1885.                         case 999:
  1886.                             doubled = 6;
  1887.                             break;
  1888.                     }
  1889.  
  1890.                     if (doubled > 0)
  1891.                     {
  1892.                         writer.WriteEncodedInt(1 + ((j * sbInfos.Count) + i));
  1893.                         writer.WriteEncodedInt(doubled);
  1894.                     }
  1895.                 }
  1896.             }
  1897.  
  1898.             writer.WriteEncodedInt(0);
  1899.         }
  1900.  
  1901.         public override void Deserialize(GenericReader reader)
  1902.         {
  1903.             base.Deserialize(reader);
  1904.  
  1905.             int version = reader.ReadInt();
  1906.  
  1907.             LoadSBInfo();
  1908.  
  1909.             var sbInfos = SBInfos;
  1910.  
  1911.             switch (version)
  1912.             {
  1913.                 case 1:
  1914.                     {
  1915.                         int index;
  1916.  
  1917.                         while ((index = reader.ReadEncodedInt()) > 0)
  1918.                         {
  1919.                             int doubled = reader.ReadEncodedInt();
  1920.  
  1921.                             if (sbInfos != null)
  1922.                             {
  1923.                                 index -= 1;
  1924.                                 int sbInfoIndex = index % sbInfos.Count;
  1925.                                 int buyInfoIndex = index / sbInfos.Count;
  1926.  
  1927.                                 if (sbInfoIndex >= 0 && sbInfoIndex < sbInfos.Count)
  1928.                                 {
  1929.                                     SBInfo sbInfo = sbInfos[sbInfoIndex];
  1930.                                     var buyInfo = sbInfo.BuyInfo;
  1931.  
  1932.                                     if (buyInfo != null && buyInfoIndex >= 0 && buyInfoIndex < buyInfo.Count)
  1933.                                     {
  1934.                                         GenericBuyInfo gbi = buyInfo[buyInfoIndex];
  1935.  
  1936.                                         int amount = 20;
  1937.  
  1938.                                         switch (doubled)
  1939.                                         {
  1940.                                             case 1:
  1941.                                                 amount = 40;
  1942.                                                 break;
  1943.                                             case 2:
  1944.                                                 amount = 80;
  1945.                                                 break;
  1946.                                             case 3:
  1947.                                                 amount = 160;
  1948.                                                 break;
  1949.                                             case 4:
  1950.                                                 amount = 320;
  1951.                                                 break;
  1952.                                             case 5:
  1953.                                                 amount = 640;
  1954.                                                 break;
  1955.                                             case 6:
  1956.                                                 amount = 999;
  1957.                                                 break;
  1958.                                         }
  1959.  
  1960.                                         gbi.Amount = gbi.MaxAmount = amount;
  1961.                                     }
  1962.                                 }
  1963.                             }
  1964.                         }
  1965.  
  1966.                         break;
  1967.                     }
  1968.             }
  1969.  
  1970.             if (IsParagon)
  1971.             {
  1972.                 IsParagon = false;
  1973.             }
  1974.  
  1975.             Timer.DelayCall(TimeSpan.Zero, CheckMorph);
  1976.         }
  1977.  
  1978.         public override void AddCustomContextEntries(Mobile from, List<ContextMenuEntry> list)
  1979.         {
  1980.             if (from.Alive && IsActiveVendor)
  1981.             {
  1982.                 if (SupportsBulkOrders(from))
  1983.                 {
  1984.                     list.Add(new BulkOrderInfoEntry(from, this));
  1985.                 }
  1986.  
  1987.                 if (IsActiveSeller)
  1988.                 {
  1989.                     list.Add(new VendorBuyEntry(from, this));
  1990.                 }
  1991.  
  1992.                 if (IsActiveBuyer)
  1993.                 {
  1994.                     list.Add(new VendorSellEntry(from, this));
  1995.                 }
  1996.             }
  1997.  
  1998.             base.AddCustomContextEntries(from, list);
  1999.         }
  2000.  
  2001.         public virtual IShopSellInfo[] GetSellInfo()
  2002.         {
  2003.             return (IShopSellInfo[])m_ArmorSellInfo.ToArray(typeof(IShopSellInfo));
  2004.         }
  2005.  
  2006.         public virtual IBuyItemInfo[] GetBuyInfo()
  2007.         {
  2008.             return (IBuyItemInfo[])m_ArmorBuyInfo.ToArray(typeof(IBuyItemInfo));
  2009.         }
  2010.     }
  2011. }
  2012.  
  2013. namespace Server.ContextMenus
  2014. {
  2015.     public class VendorBuyEntry : ContextMenuEntry
  2016.     {
  2017.         private readonly BaseVendor m_Vendor;
  2018.  
  2019.         public VendorBuyEntry(Mobile from, BaseVendor vendor)
  2020.             : base(6103, 8)
  2021.         {
  2022.             m_Vendor = vendor;
  2023.             Enabled = vendor.CheckVendorAccess(from);
  2024.         }
  2025.  
  2026.         public override void OnClick()
  2027.         {
  2028.             m_Vendor.VendorBuy(Owner.From);
  2029.         }
  2030.     }
  2031.  
  2032.     public class VendorSellEntry : ContextMenuEntry
  2033.     {
  2034.         private readonly BaseVendor m_Vendor;
  2035.  
  2036.         public VendorSellEntry(Mobile from, BaseVendor vendor)
  2037.             : base(6104, 8)
  2038.         {
  2039.             m_Vendor = vendor;
  2040.             Enabled = vendor.CheckVendorAccess(from);
  2041.         }
  2042.  
  2043.         public override void OnClick()
  2044.         {
  2045.             m_Vendor.VendorSell(Owner.From);
  2046.         }
  2047.     }
  2048. }
  2049.  
  2050. namespace Server
  2051. {
  2052.     public interface IShopSellInfo
  2053.     {
  2054.         //get display name for an item
  2055.         string GetNameFor(Item item);
  2056.  
  2057.         //get price for an item which the player is selling
  2058.         int GetSellPriceFor(Item item);
  2059.  
  2060.         //get price for an item which the player is buying
  2061.         int GetBuyPriceFor(Item item);
  2062.  
  2063.         //can we sell this item to this vendor?
  2064.         bool IsSellable(Item item);
  2065.  
  2066.         //What do we sell?
  2067.         Type[] Types { get; }
  2068.  
  2069.         //does the vendor resell this item?
  2070.         bool IsResellable(Item item);
  2071.     }
  2072.  
  2073.     public interface IBuyItemInfo
  2074.     {
  2075.         //get a new instance of an object (we just bought it)
  2076.         IEntity GetEntity();
  2077.  
  2078.         int ControlSlots { get; }
  2079.  
  2080.         int PriceScalar { get; set; }
  2081.  
  2082.         //display price of the item
  2083.         int Price { get; }
  2084.  
  2085.         //display name of the item
  2086.         string Name { get; }
  2087.  
  2088.         //display hue
  2089.         int Hue { get; }
  2090.  
  2091.         //display id
  2092.         int ItemID { get; }
  2093.  
  2094.         //amount in stock
  2095.         int Amount { get; set; }
  2096.  
  2097.         //max amount in stock
  2098.         int MaxAmount { get; }
  2099.  
  2100.         //Attempt to restock with item, (return true if restock sucessful)
  2101.         bool Restock(Item item, int amount);
  2102.  
  2103.         //called when its time for the whole shop to restock
  2104.         void OnRestock();
  2105.     }
  2106. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement