I've been through several upgrade processes along the way in my UO gaming so im by no means unexpired at the updates (three different versions of runUO to OrbUO to now ServUO), but there are a few of the updates that i look at and wonder hua??? and im not quite sure how they work or what's the difference or how to update it properly being as crash free as possible. I didn't want to have to create a new tread for every little question that pops up ;) If I have a better understanding of how or why things have been changed, it will help me ask fewer questions later and even help others and make things I release or update more stable. I do want to learn. So the first set of questions.

I don't understand how the new time date system works. a ton of my scripts rely on time date stamps (i think they are called) in order to function. I get a little paranoid of crashes sometimes.

Is 1000 Core.TickCount the same as one second (or roughly the same?) Like for examples:

replace:
AIObject.NextMove = DateTime.Now + TimeSpan.FromSeconds( 1.0 );
with:
AIObject.NextMove = Core.TickCount + 1000;

I did a search and that's only thing I can come up with.

I did this one on my own and it seems to compile and work but want to be sure its right:

replace:
NextActionTime = DateTime.Now;
with:
NextActionTime = Core.TickCount;

Ive noticed in that same script it has something dealing with seconds that still compiles, so I'm guessing parts of the time system still haven't changed? Or is this one likely to crash?

public static TimeSpan PotionDelay = TimeSpan.FromSeconds( 10.0 );

Next question:
Im not a programer and don't really understand all the technical terms used like int and stuff so this is mostly curiosity as I don't care too much long as it works, but whats the difference between the read only int and int like:

private static int[] m_WaterTiles = new int[]
private static readonly int[] m_WaterTiles = new int[]

Last question for now another curiosity: I've noticed that almost all the scripts now, include this. before everything like this.Hue = 1175; I also noticed in some of the scripts in ServUO Distro files, where this. prob could have been added wasn't. Is this some vital change that's starting to be applied that will have to be absolutely necessary later on down the line? or just insurance to help prevent crashes?

Sorry if I annoy anyone.

Last thing before I go. I saw this in fishing and thought i someone might want to know:
Code:
switch (Utility.Random(3))
               {
                 case 0 : chest.DropItem(new BronzedArmorValkyrie()); break;
                 case 1 : chest.DropItem(new EnchantedKelpWovenLeggings()); break;
                 case 2 : chest.DropItem(new RunedDriftwoodBow()); break;   
                 case 3 : chest.DropItem(new AntiqueWeddingDress()); break;
               }
Shouldn't that be switch (Utility.Random(4)) since there's 4 cases? if that's been fixed already or im wrong disregard ;)

Thanks! and PLEASE keep up the good work you don't know what it means to us to have this for our enjoyment.
 
#2: readonly versus not readonly: with the readonly modifier you can only assign a value via the declaration or constructor within the same class, so essentially...once you assign it, thats what it stays at until you change it within the code where its located (if anyone with better knowledge than me can explain better please do)

#3: the "this." isn't necessary in most cases, in fact Visual Studio is highly annoyed by its constant presence and emphatically reminds you that's its completely unnecessary everytime it sees it applied in that manner...
 
m309 hit some of these on the head but here's a recap.

Is 1000 Core.TickCount the same as one second (or roughly the same?)
Core.TickCount is in milliseconds so yes 1000 = one second.

but whats the difference between the read only int and int like
As m309 said, readonly variables can only be assigned via declaration or inside the class constructor. Think of it like a safety net. If you want a variable to be constant and never change this will make sure of that. There are many situation where this is useful and mostly when others would be using your code and might not know the changing the variable might break the code.

I've noticed that almost all the scripts now, include this. before everything like this.Hue = 1175; I also noticed in some of the scripts in ServUO Distro files, where this. prob could have been added wasn't. Is this some vital change that's starting to be applied that will have to be absolutely necessary later on down the line?
As m309 said, 'this' isn't required at all. It's mostly a preference thing because the compiler already implies 'this' where needed. I've never had Visual Studio complain about it though. I think resharper does but I disabled it because I prefer to use them. Mostly useful for knowing what something belongs to, especially when dealing with derived classes as the 'this' works for things it still has access to.

Shouldn't that be switch (Utility.Random(4)) since there's 4 cases?
You are right about this one. Utility.Random(3) is misleading and will only return numbers between 0-2. Utiltiy.Random(4) or for even more clarity Utility.RandomMinMax(0, 3) would both be correct.
 
#2: readonly versus not readonly: with the readonly modifier you can only assign a value via the declaration or constructor within the same class, so essentially...once you assign it, thats what it stays at until you change it within the code where its located (if anyone with better knowledge than me can explain better please do)

#3: the "this." isn't necessary in most cases, in fact Visual Studio is highly annoyed by its constant presence and emphatically reminds you that's its completely unnecessary everytime it sees it applied in that manner...

#1: Ok so the time date update thing is actually a RunUO2.3 update then i take it. I'll search there for more examples to help me figure out what I gota do if i run into more issues. thanks!

#2 Ok i think I understand. Basically other scripts wouldn't be able to override this later? Like a read only file on a hard drive thats what I thought it ment but I wasn't sure if worked the same or not. Stupid question but if you do try to unknowingly override something later that's been set as readonly will the error messages tell you it's a readonly property your trying to override? lol

#3 Guess that answers that lol. I always use Notepad++ and winmerge to tinker with the scripts bacause its so simple to use and not a long load time to open a simple cs to edit it. I have used VS but i figure for what Im doing it works fine.

Utility.RandomMinMax(0, 3)

I didn't know about that one being the same. I've seen it before but wasn't sure what the 0 represented. I figured it was default back to 0 or something.

Thanks Helps out a lot. haven't run across any new questions yet.
 
Yes you will get errors if you try to change a readonly value outside a constructor or it's declaration. In fact you won't even be able to compile if you tried to do this. You'll get an error similar to this: 'A readonly field cannot be assigned to (except in a constructor or a variable initializer)'

Utility.RandomMinMax will give you a random number between 2 values. RandomMinMax(0, 3) can be anything from 0 to 3. RandomMixMax(10, 20) will be anything from 10-20, ect. The reason I suggest it over Utility.Random(4) is for clarity. Utility.Random(4) looks misleading as one might expect it to be a random number between 0-4 but it's really only a random number between 0-3.
 
Well I though I understood lol if you use RandomMixMax(10, 20) and you have 20 cases would the first 10 never be used, and would that throw an unreachable code warning? Reason I ask on that is i do have unreachable code warnings I just havent gave them much though for trying to fix bigger issues.
 
Correct if you use RandomMinMax(10, 20) on a switch statement and you have cases 0-10 then those would never get used.

You aren't going to see unreachable code for switch statements because the value you are checking could be anything and that could change during runtime. e.g. If you are getting a text input from the user and performing a switch statement on it, then it could literally be anything. It doesn't know that RandomMinMax(10, 20) will only produce a number from 10 to 20 it only checks the cases to see if they match. While we are on the subject there is also a 'default:' case that can be used if none of the other cases match and you still want something to happen. Another useful for unknowns.
 
Ok that helps :D

Another question. This ones a big pain in the rear... Is anyone else having issues with belkin routers being able to let people connect via the public IP address (virtual servers) or is it just me and probably my ISP (Charter)? I've even used noip.org's DUC host and I still can't get it to connect. I had this problem before, and I got it working through noip.com's host/redirects back before I had to quit for a while but now i cant seem to get it to do anything. i've even switched routers, but the other is an older belkin so not much of a test. I'll run through the steps of what I did.

It connects fine using UOSteam and the private address the 192.168.2.3.
When I use the public address: 97.95.xxx.xxx it locks up on the connecting screen. or throws a cant connect error.
In the router I got the inbound port set to (theres two boxes)2593-2593 for IP address 192.168.2.3 as well as the outbound port. and ive tried it both TCP and UDP and BOTH. and made sure enabled box was checked.

Only thing i've edited in datapath is line 15 private static readonly string CustomPath = @"C:\Program Files\Electronic Arts\Ultima Online Classic\Freeze Files"; (and im using classic client) If I remember right that's the line for freezefiles. I do get a red "OpenUO Error: Client files not found." Is there something else im missing? it's been so long since I set this up with the original RunUO i cant remember.

Also tried uninstalling and reinstalling/updateing Ultima but I didnt think that would help.
 
Gonna assume you are using Windows so I would also check your Windows Firewall and make sure the server is allowed.

You can also set the IP manually in ServerList.cs in case the auto detect is having problems detecting your public IP.
Change:
Code:
public static readonly string Address = null;
To something like this (use your full IP):
Code:
public static readonly string Address = "97.95.xxx.xxx";

The OpenUO errors is because you haven't setup your server files for OpenUO yet. In OpenUOSDK.cs change the following line to point to your server files the same way you do Datapath.cs.
Code:
public static string ClientDataPath = @"C:\Server";

Note that both Datapath.cs and OpenUOSDK.cs should be pointing to a copy of your client's files and not the client files themselves. If both the server and client share the same files you can end up with IO errors.
 
Ya I completely disabled Windows firewall and AGV disabled just to be sure that wasn't an issue even though I made sure I added exceptions.

Might be missing something but Im not seeing "public static readonly string Address = null;" in my datapath. I missing something somewhere? closesest thing to it was the CustomPath and its set private not public.

On OpenUO and custompath, just being lazy but could I just copy the whole UO folder somewhere and point them to it? lol
 
You can also set the IP manually in ServerList.cs in case the auto detect is having problems detecting your public IP.
Note it's ServerList.cs not Datapath.cs :)

Have you had anyone outside your network try to connect? Could be your router is doing some kind of funky loop back with you trying. If you want you can PM your IP and I'll double check it for you.
 
DOH ya *smacks forehead*

Ya I had my brother try and connect from his house, thats how I knew something was off.
I'll check that ServerList script fix and see if that helps. I been using my Public IP address to try and test it.

PM is start a conversation right? Im a little behind the times with the forums updates apparently lol
 
Last edited:
Well thanks to Kalamus I got the connection firewall issue figured out. The internet was wired from the modem through a Cell Phone signal booster, and then into the router. By bypassing the booster and going directly to the router first then to the phone booster off the router, Were able to connect.

I got another new problem. I have hundreds of custom items that I sell on distro vendors, and I seem to be having a crash with the first one i've tested in game already. The crash occurs when you say use the buy option off the healers context menu. I think it has something to do with the added items but im not sure. seems like this would be an easy fix but I cant seem to figure it out. I even went as far as return my BaseVendor file to stock and still have the crash. Normal vendors with out my custom items for sale dont seem to crash. I also tried removing the readonly parts, and just straight up copying my old RunUO/OrbUO SBinfo file for him over. with same effect.
Code:
Exception:
System.MissingMethodException: No parameterless constructor defined for this object.
  at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
  at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
  at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
  at System.Activator.CreateInstance(Type type, Boolean nonPublic)
  at System.Activator.CreateInstance(Type type)
  at Server.Mobiles.GenericBuyInfo.GetEntity()
  at Server.Mobiles.GenericBuyInfo.GetDisplayEntity()
  at Server.Mobiles.BaseVendor.VendorBuy(Mobile from)
  at Server.ContextMenus.VendorBuyEntry.OnClick()
  at Server.Network.PacketHandlers.ContextMenuResponse(NetState state, PacketReader pvSrc)
  at Server.Network.PacketHandlers.ExtendedCommand(NetState state, PacketReader pvSrc)
  at Server.Network.MessagePump.HandleReceive(NetState ns)
  at Server.Network.MessagePump.Slice()
  at Server.Core.Main(String[] args)
Code:
using System;
using System.Collections.Generic;
using Server.Items;

namespace Server.Mobiles
{
  public class SBHealer : SBInfo
  {
  private readonly List<GenericBuyInfo> m_BuyInfo = new InternalBuyInfo();
  private readonly IShopSellInfo m_SellInfo = new InternalSellInfo();
  public SBHealer()
  {
  }

  public override IShopSellInfo SellInfo
  {
  get
  {
  return this.m_SellInfo;
  }
  }
  public override List<GenericBuyInfo> BuyInfo
  {
  get
  {
  return this.m_BuyInfo;
  }
  }

  public class InternalBuyInfo : List<GenericBuyInfo>
  {
  public InternalBuyInfo()
  {
  this.Add(new GenericBuyInfo(typeof(Bandage), 5, 20, 0xE21, 0));
  this.Add(new GenericBuyInfo(typeof(LesserHealPotion), 15, 20, 0xF0C, 0));
  this.Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0));
  this.Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0));
  this.Add(new GenericBuyInfo(typeof(RefreshPotion), 15, 20, 0xF0B, 0));
         this.Add(new GenericBuyInfo(typeof(IllnessesBook ), 125, 10, 0xFF2, 900 ) );
         this.Add(new GenericBuyInfo(typeof( ColdCurePotion ), 150, 10, 0xF07, 170 ) );
         this.Add(new GenericBuyInfo(typeof( FluCurePotion ), 175, 10, 0xF07, 180 ) );
         this.Add(new GenericBuyInfo(typeof( HeadacheCurePotion ), 125, 10, 0xF07, 140 ) );
         this.Add(new GenericBuyInfo(typeof( VirusCurePotion ), 200, 10, 0xF07, 150 ) );
         this.Add(new GenericBuyInfo(typeof( VampTurnCurePotion ), 300, 10, 0xF07, 160 ) );
         this.Add(new GenericBuyInfo(typeof( LycanInfectionCurePotion ), 300, 10, 0xF07, 1153 ) );
  }
  }

  public class InternalSellInfo : GenericSellInfo
  {
  public InternalSellInfo()
  {
  this.Add(typeof(Bandage), 1);
  this.Add(typeof(LesserHealPotion), 7);
  this.Add(typeof(RefreshPotion), 7);
  this.Add(typeof(Garlic), 2);
  this.Add(typeof(Ginseng), 2);
  }
  }
  }
}

**EDIT** guess it would help to post the crash report lol
 
Last edited:
Sounds like one of your custom items is missing a constructor. Can you run the server with -debug args to get a better crash report or post your item scripts?
 
How do I set up debug I forgot lol
To run your server in debug mode with windows, Create a new shortcut,
or create a shortcut from the servuo.exe,
Insure the path for the shortcut is set to your servuo.exe file.
At the end of the path add "-debug". you can then use that shortcut for debugging.
for example: C:\Servuo\ServUO.exe -debug
 
Last edited:
We got it fixed something was changed in how defined books work. Thanks! (thought I hit reply the other day sorry)

I got a new little issue with the unidentified system I installed eairler on my server. I think the bug that I fixed to make all items work properly and show it as being unidentified also made all the items vendors sell unidentified (or they where always that way) I made a little snipit of code to go somewhere, to try to fix that but after trying several times trying to figure out where it goes im more confused then when I started.
the code I made is something like this:
Code:
 if (buyItem is BaseWeapon || buyItem is BaseArmor || buyItem is BaseClothing || buyItem is BaseJewel || buyItem is BaseTalisman || buyItem is BaseWand }
{
	buyItem.Identified = true;
}
If I better knew where the code would ideally go to work properly It wouldn't be so hard to figure out, but Im not even sure BaseVendor is where the code should go. Anyone got any advise on this? I plan on making a vendor for people to talk to that will ID stuff for them Like Decard Canine from Diablo, but Id hate to have to have people ID stuff they just bought lol. I thought the code would work around line 796 (I know im mising a proper identifier there too) but Im not sure what its talking about with the comment about GBI support.
Heres the BaseVendor for quick refrence, not much of a change to it really thus far:
Code:
#region Header
// **********
// ServUO - BaseVendor.cs
// **********
#endregion

#region References
using System;
using System.Collections;
using System.Collections.Generic;

using Server.ContextMenus;
using Server.Engines.BulkOrders;
using Server.Factions;
using Server.Items;
using Server.Misc;
using Server.Mobiles;
using Server.Network;
using Server.Regions;
#endregion

namespace Server.Mobiles
{
   public enum VendorShoeType
   {
     None,
     Shoes,
     Boots,
     Sandals,
     ThighBoots
   }

   public abstract class BaseVendor : BaseCreature, IVendor
   {
     private const int MaxSell = 500;

     protected abstract List<SBInfo> SBInfos { get; }

     private readonly ArrayList m_ArmorBuyInfo = new ArrayList();
     private readonly ArrayList m_ArmorSellInfo = new ArrayList();

     private DateTime m_LastRestock;

     public override bool CanTeach { get { return true; } }

     public override bool BardImmune { get { return true; } }

     public override bool PlayerRangeSensitive { get { return true; } }

     public virtual bool IsActiveVendor { get { return true; } }
     public virtual bool IsActiveBuyer { get { return IsActiveVendor; } } // response to vendor SELL
     public virtual bool IsActiveSeller { get { return IsActiveVendor; } } // repsonse to vendor BUY

     public virtual NpcGuild NpcGuild { get { return NpcGuild.None; } }

     public override bool IsInvulnerable { get { return true; } }

     public virtual DateTime NextTrickOrTreat { get; set; }

     public override bool ShowFameTitle { get { return false; } }

     public virtual bool IsValidBulkOrder(Item item)
     {
       return false;
     }

     public virtual Item CreateBulkOrder(Mobile from, bool fromContextMenu)
     {
       return null;
     }

     public virtual bool SupportsBulkOrders(Mobile from)
     {
       return false;
     }

     public virtual TimeSpan GetNextBulkOrder(Mobile from)
     {
       return TimeSpan.Zero;
     }

     public virtual void OnSuccessfulBulkOrderReceive(Mobile from)
     { }

     #region Faction
     public virtual int GetPriceScalar()
     {
       Town town = Town.FromRegion(Region);

       if (town != null)
       {
         return (100 + town.Tax);
       }

       return 100;
     }

     public void UpdateBuyInfo()
     {
       int priceScalar = GetPriceScalar();

       var buyinfo = (IBuyItemInfo[])m_ArmorBuyInfo.ToArray(typeof(IBuyItemInfo));

       if (buyinfo != null)
       {
         foreach (IBuyItemInfo info in buyinfo)
         {
           info.PriceScalar = priceScalar;
         }
       }
     }
     #endregion

     private class BulkOrderInfoEntry : ContextMenuEntry
     {
       private readonly Mobile m_From;
       private readonly BaseVendor m_Vendor;

       public BulkOrderInfoEntry(Mobile from, BaseVendor vendor)
         : base(6152)
       {
         m_From = from;
         m_Vendor = vendor;
       }

       public override void OnClick()
       {
         if (m_Vendor.SupportsBulkOrders(m_From))
         {
           TimeSpan ts = m_Vendor.GetNextBulkOrder(m_From);

           int totalSeconds = (int)ts.TotalSeconds;
           int totalHours = (totalSeconds + 3599) / 3600;
           int totalMinutes = (totalSeconds + 59) / 60;

           if (((Core.SE) ? totalMinutes == 0 : totalHours == 0))
           {
             m_From.SendLocalizedMessage(1049038); // You can get an order now.

             if (Core.AOS)
             {
               Item bulkOrder = m_Vendor.CreateBulkOrder(m_From, true);

               if (bulkOrder is LargeBOD)
               {
                 m_From.SendGump(new LargeBODAcceptGump(m_From, (LargeBOD)bulkOrder));
               }
               else if (bulkOrder is SmallBOD)
               {
                 m_From.SendGump(new SmallBODAcceptGump(m_From, (SmallBOD)bulkOrder));
               }
             }
           }
           else
           {
             int oldSpeechHue = m_Vendor.SpeechHue;
             m_Vendor.SpeechHue = 0x3B2;

             if (Core.SE)
             {
               m_Vendor.SayTo(m_From, 1072058, totalMinutes.ToString());
               // An offer may be available in about ~1_minutes~ minutes.
             }
             else
             {
               m_Vendor.SayTo(m_From, 1049039, totalHours.ToString()); // An offer may be available in about ~1_hours~ hours.
             }

             m_Vendor.SpeechHue = oldSpeechHue;
           }
         }
       }
     }

     public BaseVendor(string title)
       : base(AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2)
     {
       LoadSBInfo();

       Title = title;

       InitBody();
       InitOutfit();

       Container pack;
       //these packs MUST exist, or the client will crash when the packets are sent
       pack = new Backpack();
       pack.Layer = Layer.ShopBuy;
       pack.Movable = false;
       pack.Visible = false;
       AddItem(pack);

       pack = new Backpack();
       pack.Layer = Layer.ShopResale;
       pack.Movable = false;
       pack.Visible = false;
       AddItem(pack);

       m_LastRestock = DateTime.UtcNow;
     }

     public BaseVendor(Serial serial)
       : base(serial)
     { }

     public DateTime LastRestock { get { return m_LastRestock; } set { m_LastRestock = value; } }

     public virtual TimeSpan RestockDelay { get { return TimeSpan.FromHours(1); } }

     public Container BuyPack
     {
       get
       {
         Container pack = FindItemOnLayer(Layer.ShopBuy) as Container;

         if (pack == null)
         {
           pack = new Backpack();
           pack.Layer = Layer.ShopBuy;
           pack.Visible = false;
           AddItem(pack);
         }

         return pack;
       }
     }

     public abstract void InitSBInfo();

     public virtual bool IsTokunoVendor { get { return (Map == Map.Tokuno); } }

     protected void LoadSBInfo()
     {
       m_LastRestock = DateTime.UtcNow;

       for (int i = 0; i < m_ArmorBuyInfo.Count; ++i)
       {
         GenericBuyInfo buy = m_ArmorBuyInfo[i] as GenericBuyInfo;

         if (buy != null)
         {
           buy.DeleteDisplayEntity();
         }
       }

       SBInfos.Clear();

       InitSBInfo();

       m_ArmorBuyInfo.Clear();
       m_ArmorSellInfo.Clear();

       for (int i = 0; i < SBInfos.Count; i++)
       {
         SBInfo sbInfo = SBInfos[i];
         m_ArmorBuyInfo.AddRange(sbInfo.BuyInfo);
         m_ArmorSellInfo.Add(sbInfo.SellInfo);
       }
     }

     public virtual bool GetGender()
     {
       return Utility.RandomBool();
     }

     public virtual void InitBody()
     {
       InitStats(100, 100, 25);

       SpeechHue = Utility.RandomDyedHue();
       Hue = Utility.RandomSkinHue();

       if (Female = GetGender())
       {
         Body = 0x191;
         Name = NameList.RandomName("female");
       }
       else
       {
         Body = 0x190;
         Name = NameList.RandomName("male");
       }
     }

     public virtual int GetRandomHue()
     {
       switch (Utility.Random(5))
       {
         default:
         case 0:
           return Utility.RandomBlueHue();
         case 1:
           return Utility.RandomGreenHue();
         case 2:
           return Utility.RandomRedHue();
         case 3:
           return Utility.RandomYellowHue();
         case 4:
           return Utility.RandomNeutralHue();
       }
     }

     public virtual int GetShoeHue()
     {
       if (0.1 > Utility.RandomDouble())
       {
         return 0;
       }

       return Utility.RandomNeutralHue();
     }

     public virtual VendorShoeType ShoeType { get { return VendorShoeType.Shoes; } }

     public virtual void CheckMorph()
     {
       if (CheckGargoyle())
       {
         return;
       }
         #region SA
       else if (CheckTerMur())
       {
         return;
       }
         #endregion

       else if (CheckNecromancer())
       {
         return;
       }
       else if (CheckTokuno())
       {
         return;
       }

       if (Female = GetGender())
       {
         Body = 0x191;
         Name = NameList.RandomName("female");
       }
       else
       {
         Body = 0x190;
         Name = NameList.RandomName("male");
       }
     }

     public virtual bool CheckTokuno()
     {
       if (Map != Map.Tokuno)
       {
         return false;
       }

       NameList n;

       if (Female)
       {
         n = NameList.GetNameList("tokuno female");
       }
       else
       {
         n = NameList.GetNameList("tokuno male");
       }

       if (!n.ContainsName(Name))
       {
         TurnToTokuno();
       }

       return true;
     }

     public virtual void TurnToTokuno()
     {
       if (Female)
       {
         Name = NameList.RandomName("tokuno female");
       }
       else
       {
         Name = NameList.RandomName("tokuno male");
       }
     }

     public virtual bool CheckGargoyle()
     {
       Map map = Map;

       if (map != Map.Ilshenar)
       {
         return false;
       }

       if (!Region.IsPartOf("Gargoyle City"))
       {
         return false;
       }

       if (Body != 0x2F6 || (Hue & 0x8000) == 0)
       {
         TurnToGargoyle();
       }

       return true;
     }

     #region SA Change
     public virtual bool CheckTerMur()
     {
       Map map = Map;

       if (map != Map.TerMur)
       {
         return false;
       }

       if (!Region.IsPartOf("Royal City") && !Region.IsPartOf("Holy City"))
       {
         return false;
       }

       if (Body != 0x29A || Body != 0x29B)
       {
         TurnToGargRace();
       }

       return true;
     }
     #endregion

     public virtual bool CheckNecromancer()
     {
       Map map = Map;

       if (map != Map.Malas)
       {
         return false;
       }

       if (!Region.IsPartOf("Umbra"))
       {
         return false;
       }

       if (Hue != 0x83E8)
       {
         TurnToNecromancer();
       }

       return true;
     }

     public override void OnAfterSpawn()
     {
       CheckMorph();
     }

     protected override void OnMapChange(Map oldMap)
     {
       base.OnMapChange(oldMap);

       CheckMorph();

       LoadSBInfo();
     }

     public virtual int GetRandomNecromancerHue()
     {
       switch (Utility.Random(20))
       {
         case 0:
           return 0;
         case 1:
           return 0x4E9;
         default:
           return Utility.RandomList(0x485, 0x497);
       }
     }

     public virtual void TurnToNecromancer()
     {
       for (int i = 0; i < Items.Count; ++i)
       {
         Item item = Items[i];

         if (item is Hair || item is Beard)
         {
           item.Hue = 0;
         }
         else if (item is BaseClothing || item is BaseWeapon || item is BaseArmor || item is BaseTool)
         {
           item.Hue = GetRandomNecromancerHue();
         }
       }

       HairHue = 0;
       FacialHairHue = 0;

       Hue = 0x83E8;
     }

     public virtual void TurnToGargoyle()
     {
       for (int i = 0; i < Items.Count; ++i)
       {
         Item item = Items[i];

         if (item is BaseClothing || item is Hair || item is Beard)
         {
           item.Delete();
         }
       }

       HairItemID = 0;
       FacialHairItemID = 0;

       Body = 0x2F6;
       Hue = Utility.RandomBrightHue() | 0x8000;
       Name = NameList.RandomName("gargoyle vendor");

       CapitalizeTitle();
     }

     #region SA
     public virtual void TurnToGargRace()
     {
       for (int i = 0; i < Items.Count; ++i)
       {
         Item item = Items[i];

         if (item is BaseClothing)
         {
           item.Delete();
         }
       }

       Race = Race.Gargoyle;

       Hue = Race.RandomSkinHue();

       HairItemID = Race.RandomHair(Female);
       HairHue = Race.RandomHairHue();

       FacialHairItemID = Race.RandomFacialHair(Female);
       if (FacialHairItemID != 0)
       {
         FacialHairHue = Race.RandomHairHue();
       }
       else
       {
         FacialHairHue = 0;
       }

       InitGargOutfit();

       if (Female = GetGender())
       {
         Body = 0x29B;
         Name = NameList.RandomName("gargoyle female");
       }
       else
       {
         Body = 0x29A;
         Name = NameList.RandomName("gargoyle male");
       }

       CapitalizeTitle();
     }
     #endregion

     public virtual void CapitalizeTitle()
     {
       string title = Title;

       if (title == null)
       {
         return;
       }

       var split = title.Split(' ');

       for (int i = 0; i < split.Length; ++i)
       {
         if (Insensitive.Equals(split[i], "the"))
         {
           continue;
         }

         if (split[i].Length > 1)
         {
           split[i] = Char.ToUpper(split[i][0]) + split[i].Substring(1);
         }
         else if (split[i].Length > 0)
         {
           split[i] = Char.ToUpper(split[i][0]).ToString();
         }
       }

       Title = String.Join(" ", split);
     }

     public virtual int GetHairHue()
     {
       return Utility.RandomHairHue();
     }

     public virtual void InitOutfit()
     {
       switch (Utility.Random(3))
       {
         case 0:
           AddItem(new FancyShirt(GetRandomHue()));
           break;
         case 1:
           AddItem(new Doublet(GetRandomHue()));
           break;
         case 2:
           AddItem(new Shirt(GetRandomHue()));
           break;
       }

       switch (ShoeType)
       {
         case VendorShoeType.Shoes:
           AddItem(new Shoes(GetShoeHue()));
           break;
         case VendorShoeType.Boots:
           AddItem(new Boots(GetShoeHue()));
           break;
         case VendorShoeType.Sandals:
           AddItem(new Sandals(GetShoeHue()));
           break;
         case VendorShoeType.ThighBoots:
           AddItem(new ThighBoots(GetShoeHue()));
           break;
       }

       int hairHue = GetHairHue();

       Utility.AssignRandomHair(this, hairHue);
       Utility.AssignRandomFacialHair(this, hairHue);

       if (Female)
       {
         switch (Utility.Random(6))
         {
           case 0:
             AddItem(new ShortPants(GetRandomHue()));
             break;
           case 1:
           case 2:
             AddItem(new Kilt(GetRandomHue()));
             break;
           case 3:
           case 4:
           case 5:
             AddItem(new Skirt(GetRandomHue()));
             break;
         }
       }
       else
       {
         switch (Utility.Random(2))
         {
           case 0:
             AddItem(new LongPants(GetRandomHue()));
             break;
           case 1:
             AddItem(new ShortPants(GetRandomHue()));
             break;
         }
       }

       PackGold(100, 200);
     }

     #region SA
     public virtual void InitGargOutfit()
     {
       for (int i = 0; i < Items.Count; ++i)
       {
         Item item = Items[i];

         if (item is BaseClothing)
         {
           item.Delete();
         }
       }

       if (Female)
       {
         switch (Utility.Random(2))
         {
           case 0:
             AddItem(new FemaleGargishClothLegs(GetRandomHue()));
             AddItem(new FemaleGargishClothKilt(GetRandomHue()));
             AddItem(new FemaleGargishClothChest(GetRandomHue()));
             break;
           case 1:
             AddItem(new FemaleGargishClothKilt(GetRandomHue()));
             AddItem(new FemaleGargishClothChest(GetRandomHue()));
             break;
         }
       }
       else
       {
         switch (Utility.Random(2))
         {
           case 0:
             AddItem(new MaleGargishClothLegs(GetRandomHue()));
             AddItem(new MaleGargishClothKilt(GetRandomHue()));
             AddItem(new MaleGargishClothChest(GetRandomHue()));
             break;
           case 1:
             AddItem(new MaleGargishClothKilt(GetRandomHue()));
             AddItem(new MaleGargishClothChest(GetRandomHue()));
             break;
         }
       }
       PackGold(100, 200);
     }
     #endregion

     public virtual void Restock()
     {
       m_LastRestock = DateTime.UtcNow;

       var buyInfo = GetBuyInfo();

       foreach (IBuyItemInfo bii in buyInfo)
       {
         bii.OnRestock();
       }
     }

     private static readonly TimeSpan InventoryDecayTime = TimeSpan.FromHours(1.0);

     public virtual void VendorBuy(Mobile from)
     {
       if (!IsActiveSeller)
       {
         return;
       }

       if (!from.CheckAlive())
       {
         return;
       }

       if (!CheckVendorAccess(from))
       {
         Say(501522); // I shall not treat with scum like thee!
         return;
       }

       if (DateTime.UtcNow - m_LastRestock > RestockDelay)
       {
         Restock();
       }

       UpdateBuyInfo();

       int count = 0;
       List<BuyItemState> list;
       var buyInfo = GetBuyInfo();
       var sellInfo = GetSellInfo();

       list = new List<BuyItemState>(buyInfo.Length);
       Container cont = BuyPack;

       List<ObjectPropertyList> opls = null;

       for (int idx = 0; idx < buyInfo.Length; idx++)
       {
         IBuyItemInfo buyItem = buyInfo[idx];

         if (buyItem.Amount <= 0 || list.Count >= 250)
         {
           continue;
         }

         // NOTE: Only GBI supported; if you use another implementation of IBuyItemInfo, this will crash
         GenericBuyInfo gbi = (GenericBuyInfo)buyItem;
         IEntity disp = gbi.GetDisplayEntity();

         list.Add(
           new BuyItemState(
             buyItem.Name,
             cont.Serial,
             disp == null ? (Serial)0x7FC0FFEE : disp.Serial,
             buyItem.Price,
             buyItem.Amount,
             buyItem.ItemID,
             buyItem.Hue));
             //if (buyItem is BaseWeapon || BaseArmor || BaseClothing|| BaseJewel || BaseWand)
             //{
             //   buyItem.Identified = true;
             //}
         count++;

         if (opls == null)
         {
           opls = new List<ObjectPropertyList>();
         }

         if (disp is Item)
         {
           opls.Add(((Item)disp).PropertyList);
         }
         else if (disp is Mobile)
         {
           opls.Add(((Mobile)disp).PropertyList);
         }
       }

       var playerItems = cont.Items;

       for (int i = playerItems.Count - 1; i >= 0; --i)
       {
         if (i >= playerItems.Count)
         {
           continue;
         }

         Item item = playerItems[i];

         if ((item.LastMoved + InventoryDecayTime) <= DateTime.UtcNow)
         {
           item.Delete();
         }
       }

       for (int i = 0; i < playerItems.Count; ++i)
       {
         Item item = playerItems[i];

         int price = 0;
         string name = null;

         foreach (IShopSellInfo ssi in sellInfo)
         {
           if (ssi.IsSellable(item))
           {
             price = ssi.GetBuyPriceFor(item);
             name = ssi.GetNameFor(item);
             break;
           }
         }

         if (name != null && list.Count < 250)
         {
           list.Add(new BuyItemState(name, cont.Serial, item.Serial, price, item.Amount, item.ItemID, item.Hue));
           count++;

           if (opls == null)
           {
             opls = new List<ObjectPropertyList>();
           }

           opls.Add(item.PropertyList);
         }
       }

       //one (not all) of the packets uses a byte to describe number of items in the list.  Osi = dumb.
       //if ( list.Count > 255 )
       //   Console.WriteLine( "Vendor Warning: Vendor {0} has more than 255 buy items, may cause client errors!", this );

       if (list.Count > 0)
       {
         list.Sort(new BuyItemStateComparer());

         SendPacksTo(from);

         NetState ns = from.NetState;

         if (ns == null)
         {
           return;
         }

         if (ns.ContainerGridLines)
         {
           from.Send(new VendorBuyContent6017(list));
         }
         else
         {
           from.Send(new VendorBuyContent(list));
         }

         from.Send(new VendorBuyList(this, list));

         if (ns.HighSeas)
         {
           from.Send(new DisplayBuyListHS(this));
         }
         else
         {
           from.Send(new DisplayBuyList(this));
         }

         from.Send(new MobileStatusExtended(from)); //make sure their gold amount is sent

         if (opls != null)
         {
           for (int i = 0; i < opls.Count; ++i)
           {
             from.Send(opls[i]);
           }
         }

         SayTo(from, 500186); // Greetings.  Have a look around.
       }
     }

     public virtual void SendPacksTo(Mobile from)
     {
       Item pack = FindItemOnLayer(Layer.ShopBuy);

       if (pack == null)
       {
         pack = new Backpack();
         pack.Layer = Layer.ShopBuy;
         pack.Movable = false;
         pack.Visible = false;
         AddItem(pack);
       }

       from.Send(new EquipUpdate(pack));

       pack = FindItemOnLayer(Layer.ShopSell);

       if (pack != null)
       {
         from.Send(new EquipUpdate(pack));
       }

       pack = FindItemOnLayer(Layer.ShopResale);

       if (pack == null)
       {
         pack = new Backpack();
         pack.Layer = Layer.ShopResale;
         pack.Movable = false;
         pack.Visible = false;
         AddItem(pack);
       }

       from.Send(new EquipUpdate(pack));
     }

     public virtual void VendorSell(Mobile from)
     {
       if (!IsActiveBuyer)
       {
         return;
       }

       if (!from.CheckAlive())
       {
         return;
       }

       if (!CheckVendorAccess(from))
       {
         Say(501522); // I shall not treat with scum like thee!
         return;
       }

       Container pack = from.Backpack;

       if (pack != null)
       {
         var info = GetSellInfo();

         Hashtable table = new Hashtable();

         foreach (IShopSellInfo ssi in info)
         {
           var items = pack.FindItemsByType(ssi.Types);

           foreach (Item item in items)
           {
             if (item is Container && (item).Items.Count != 0)
             {
               continue;
             }

             if (item.IsStandardLoot() && item.Movable && ssi.IsSellable(item))
             {
               table[item] = new SellItemState(item, ssi.GetSellPriceFor(item), ssi.GetNameFor(item));
             }
           }
         }

         if (table.Count > 0)
         {
           SendPacksTo(from);

           from.Send(new VendorSellList(this, table));
         }
         else
         {
           Say(true, "You have nothing I would be interested in.");
         }
       }
     }

     public override bool OnDragDrop(Mobile from, Item dropped)
     {
       /* TODO: Thou art giving me? and fame/karma for gold gifts */
       if (dropped is SmallBOD || dropped is LargeBOD)
       {
         PlayerMobile pm = from as PlayerMobile;

         if (Core.ML && pm != null && pm.NextBODTurnInTime > DateTime.UtcNow)
         {
           SayTo(from, 1079976); // You'll have to wait a few seconds while I inspect the last order.
           return false;
         }
         else if (!IsValidBulkOrder(dropped) || !SupportsBulkOrders(from))
         {
           SayTo(from, 1045130); // That order is for some other shopkeeper.
           return false;
         }
         else if ((dropped is SmallBOD && !((SmallBOD)dropped).Complete) ||
              (dropped is LargeBOD && !((LargeBOD)dropped).Complete))
         {
           SayTo(from, 1045131); // You have not completed the order yet.
           return false;
         }

         Item reward;
         int gold, fame;

         if (dropped is SmallBOD)
         {
           ((SmallBOD)dropped).GetRewards(out reward, out gold, out fame);
         }
         else
         {
           ((LargeBOD)dropped).GetRewards(out reward, out gold, out fame);
         }

         from.SendSound(0x3D);

         SayTo(from, 1045132); // Thank you so much!  Here is a reward for your effort.

         if (reward != null)
         {
           from.AddToBackpack(reward);
         }

         if (gold > 1000)
         {
           from.AddToBackpack(new BankCheck(gold));
         }
         else if (gold > 0)
         {
           from.AddToBackpack(new Gold(gold));
         }

         Titles.AwardFame(from, fame, true);

         OnSuccessfulBulkOrderReceive(from);

         if (Core.ML && pm != null)
         {
           pm.NextBODTurnInTime = DateTime.UtcNow + TimeSpan.FromSeconds(10.0);
         }

         dropped.Delete();
         return true;
       }

       return base.OnDragDrop(from, dropped);
     }

     private GenericBuyInfo LookupDisplayObject(object obj)
     {
       var buyInfo = GetBuyInfo();

       for (int i = 0; i < buyInfo.Length; ++i)
       {
         GenericBuyInfo gbi = (GenericBuyInfo)buyInfo[i];

         if (gbi.GetDisplayEntity() == obj)
         {
           return gbi;
         }
       }

       return null;
     }

     private void ProcessSinglePurchase(
       BuyItemResponse buy,
       IBuyItemInfo bii,
       List<BuyItemResponse> validBuy,
       ref int controlSlots,
       ref bool fullPurchase,
       ref int totalCost)
     {
       int amount = buy.Amount;

       if (amount > bii.Amount)
       {
         amount = bii.Amount;
       }

       if (amount <= 0)
       {
         return;
       }

       int slots = bii.ControlSlots * amount;

       if (controlSlots >= slots)
       {
         controlSlots -= slots;
       }
       else
       {
         fullPurchase = false;
         return;
       }

       totalCost += bii.Price * amount;
       validBuy.Add(buy);
     }

     private void ProcessValidPurchase(int amount, IBuyItemInfo bii, Mobile buyer, Container cont)
     {
       if (amount > bii.Amount)
       {
         amount = bii.Amount;
       }

       if (amount < 1)
       {
         return;
       }

       bii.Amount -= amount;

       IEntity o = bii.GetEntity();

       if (o is Item)
       {
         Item item = (Item)o;

         if (item.Stackable)
         {
           item.Amount = amount;

           if (cont == null || !cont.TryDropItem(buyer, item, false))
           {
             item.MoveToWorld(buyer.Location, buyer.Map);
           }
         }
         else
         {
           item.Amount = 1;

           if (cont == null || !cont.TryDropItem(buyer, item, false))
           {
             item.MoveToWorld(buyer.Location, buyer.Map);
           }

           for (int i = 1; i < amount; i++)
           {
             item = bii.GetEntity() as Item;

             if (item != null)
             {
               item.Amount = 1;

               if (cont == null || !cont.TryDropItem(buyer, item, false))
               {
                 item.MoveToWorld(buyer.Location, buyer.Map);
               }
             }
           }
         }
       }
       else if (o is Mobile)
       {
         Mobile m = (Mobile)o;

         m.Direction = (Direction)Utility.Random(8);
         m.MoveToWorld(buyer.Location, buyer.Map);
         m.PlaySound(m.GetIdleSound());

         if (m is BaseCreature)
         {
           ((BaseCreature)m).SetControlMaster(buyer);
         }

         for (int i = 1; i < amount; ++i)
         {
           m = bii.GetEntity() as Mobile;

           if (m != null)
           {
             m.Direction = (Direction)Utility.Random(8);
             m.MoveToWorld(buyer.Location, buyer.Map);

             if (m is BaseCreature)
             {
               ((BaseCreature)m).SetControlMaster(buyer);
             }
           }
         }
       }
     }

     public virtual bool OnBuyItems(Mobile buyer, List<BuyItemResponse> list)
     {
       if (!IsActiveSeller)
       {
         return false;
       }

       if (!buyer.CheckAlive())
       {
         return false;
       }

       if (!CheckVendorAccess(buyer))
       {
         Say(501522); // I shall not treat with scum like thee!
         return false;
       }

       UpdateBuyInfo();

       var buyInfo = GetBuyInfo();
       var info = GetSellInfo();
       int totalCost = 0;
       var validBuy = new List<BuyItemResponse>(list.Count);
       Container cont;
       bool bought = false;
       bool fromBank = false;
       bool fullPurchase = true;
       int controlSlots = buyer.FollowersMax - buyer.Followers;

       foreach (BuyItemResponse buy in list)
       {
         Serial ser = buy.Serial;
         int amount = buy.Amount;

         if (ser.IsItem)
         {
           Item item = World.FindItem(ser);

           if (item == null)
           {
             continue;
           }

           GenericBuyInfo gbi = LookupDisplayObject(item);

           if (gbi != null)
           {
             ProcessSinglePurchase(buy, gbi, validBuy, ref controlSlots, ref fullPurchase, ref totalCost);
           }
           else if (item != BuyPack && item.IsChildOf(BuyPack))
           {
             if (amount > item.Amount)
             {
               amount = item.Amount;
             }

             if (amount <= 0)
             {
               continue;
             }

             foreach (IShopSellInfo ssi in info)
             {
               if (ssi.IsSellable(item))
               {
                 if (ssi.IsResellable(item))
                 {
                   totalCost += ssi.GetBuyPriceFor(item) * amount;
                   validBuy.Add(buy);
                   break;
                 }
               }
             }
           }
         }
         else if (ser.IsMobile)
         {
           Mobile mob = World.FindMobile(ser);

           if (mob == null)
           {
             continue;
           }

           GenericBuyInfo gbi = LookupDisplayObject(mob);

           if (gbi != null)
           {
             ProcessSinglePurchase(buy, gbi, validBuy, ref controlSlots, ref fullPurchase, ref totalCost);
           }
         }
       } //foreach

       if (fullPurchase && validBuy.Count == 0)
       {
         SayTo(buyer, 500190); // Thou hast bought nothing!
       }
       else if (validBuy.Count == 0)
       {
         SayTo(buyer, 500187); // Your order cannot be fulfilled, please try again.
       }

       if (validBuy.Count == 0)
       {
         return false;
       }

       bought = (buyer.AccessLevel >= AccessLevel.GameMaster);

       cont = buyer.Backpack;
       if (!bought && cont != null)
       {
         if (cont.ConsumeTotal(typeof(Gold), totalCost))
         {
           bought = true;
         }
         else if (totalCost < 2000)
         {
           SayTo(buyer, 500192); //Begging thy pardon, but thou casnt afford that.
         }
       }

       if (!bought && totalCost >= 2000)
       {
         cont = buyer.FindBankNoCreate();
         if (cont != null && cont.ConsumeTotal(typeof(Gold), totalCost))
         {
           bought = true;
           fromBank = true;
         }
         else
         {
           SayTo(buyer, 500191); //Begging thy pardon, but thy bank account lacks these funds.
         }
       }

       if (!bought)
       {
         return false;
       }
       else
       {
         buyer.PlaySound(0x32);
       }

       cont = buyer.Backpack;
       if (cont == null)
       {
         cont = buyer.BankBox;
       }

       foreach (BuyItemResponse buy in validBuy)
       {
         Serial ser = buy.Serial;
         int amount = buy.Amount;

         if (amount < 1)
         {
           continue;
         }

         if (ser.IsItem)
         {
           Item item = World.FindItem(ser);

           if (item == null)
           {
             continue;
           }

           GenericBuyInfo gbi = LookupDisplayObject(item);

           if (gbi != null)
           {
             ProcessValidPurchase(amount, gbi, buyer, cont);
           }
           else
           {
             if (amount > item.Amount)
             {
               amount = item.Amount;
             }

             foreach (IShopSellInfo ssi in info)
             {
               if (ssi.IsSellable(item))
               {
                 if (ssi.IsResellable(item))
                 {
                   Item buyItem;
                   if (amount >= item.Amount)
                   {
                     buyItem = item;
                   }
                   else
                   {
                     buyItem = LiftItemDupe(item, item.Amount - amount);

                     if (buyItem == null)
                     {
                       buyItem = item;
                     }
                   }

                   if (cont == null || !cont.TryDropItem(buyer, buyItem, false))
                   {
                     buyItem.MoveToWorld(buyer.Location, buyer.Map);
                   }

                   break;
                 }
               }
             }
           }
         }
         else if (ser.IsMobile)
         {
           Mobile mob = World.FindMobile(ser);

           if (mob == null)
           {
             continue;
           }

           GenericBuyInfo gbi = LookupDisplayObject(mob);

           if (gbi != null)
           {
             ProcessValidPurchase(amount, gbi, buyer, cont);
           }
         }
       } //foreach

       if (fullPurchase)
       {
         if (buyer.AccessLevel >= AccessLevel.GameMaster)
         {
           SayTo(buyer, true, "I would not presume to charge thee anything.  Here are the goods you requested.");
         }
         else if (fromBank)
         {
           SayTo(
             buyer,
             true,
             "The total of thy purchase is {0} gold, which has been withdrawn from your bank account.  My thanks for the patronage.",
             totalCost);
         }
         else
         {
           SayTo(buyer, true, "The total of thy purchase is {0} gold.  My thanks for the patronage.", totalCost);
         }
       }
       else
       {
         if (buyer.AccessLevel >= AccessLevel.GameMaster)
         {
           SayTo(
             buyer,
             true,
             "I would not presume to charge thee anything.  Unfortunately, I could not sell you all the goods you requested.");
         }
         else if (fromBank)
         {
           SayTo(
             buyer,
             true,
             "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.",
             totalCost);
         }
         else
         {
           SayTo(
             buyer,
             true,
             "The total of thy purchase is {0} gold.  My thanks for the patronage.  Unfortunately, I could not sell you all the goods you requested.",
             totalCost);
         }
       }

       return true;
     }
//////////
//Automaited Staff
//////////
  #region VendorAccessLevels [01-04]

  private AccessLevel m_VendorAccessLevel = AccessLevel.Player;

  [CommandProperty(AccessLevel.GameMaster)]
  public AccessLevel VendorAccessLevel
  {
  get { return m_VendorAccessLevel; }
  set { m_VendorAccessLevel = value; }
  }

  #endregion Edited By: A.A.R
///////////
//End Automaited Staff
///////////
     public virtual bool CheckVendorAccess( Mobile from )
     {
//////////
//Automaited Staff
//////////
  #region VendorAccessLevels [02-04]

  if (from.AccessLevel < m_VendorAccessLevel)
  {
  from.SendMessage("You can't trade with this vendor");
  SayTo(from, true, "My apologies, I cannot sell to you at this time");
  return false;
  }

  #endregion Edited By: A.A.R
////////////
//End Automaited Staff
////////////
       GuardedRegion reg = (GuardedRegion)this.Region.GetRegion( typeof( GuardedRegion ) );

       if ( reg != null && !reg.CheckVendorAccess( this, from ) )
         return false;

       if ( this.Region != from.Region )
       {
         reg = (GuardedRegion)from.Region.GetRegion( typeof( GuardedRegion ) );

         if ( reg != null && !reg.CheckVendorAccess( this, from ) )
           return false;
       }

       return true;
     }

     public virtual bool OnSellItems(Mobile seller, List<SellItemResponse> list)
     {
       if (!IsActiveBuyer)
       {
         return false;
       }

       if (!seller.CheckAlive())
       {
         return false;
       }

       if (!CheckVendorAccess(seller))
       {
         Say(501522); // I shall not treat with scum like thee!
         return false;
       }

       seller.PlaySound(0x32);

       var info = GetSellInfo();
       var buyInfo = GetBuyInfo();
       int GiveGold = 0;
       int Sold = 0;
       Container cont;

       foreach (SellItemResponse resp in list)
       {
         if (resp.Item.RootParent != seller || resp.Amount <= 0 || !resp.Item.IsStandardLoot() || !resp.Item.Movable ||
           (resp.Item is Container && (resp.Item).Items.Count != 0))
         {
           continue;
         }

         foreach (IShopSellInfo ssi in info)
         {
           if (ssi.IsSellable(resp.Item))
           {
             Sold++;
             break;
           }
         }
       }

       if (Sold > MaxSell)
       {
         SayTo(seller, true, "You may only sell {0} items at a time!", MaxSell);
         return false;
       }
       else if (Sold == 0)
       {
         return true;
       }

       foreach (SellItemResponse resp in list)
       {
         if (resp.Item.RootParent != seller || resp.Amount <= 0 || !resp.Item.IsStandardLoot() || !resp.Item.Movable ||
           (resp.Item is Container && (resp.Item).Items.Count != 0))
         {
           continue;
         }

         foreach (IShopSellInfo ssi in info)
         {
           if (ssi.IsSellable(resp.Item))
           {
             int amount = resp.Amount;

             if (amount > resp.Item.Amount)
             {
               amount = resp.Item.Amount;
             }

             if (ssi.IsResellable(resp.Item))
             {
               bool found = false;

               foreach (IBuyItemInfo bii in buyInfo)
               {
                 if (bii.Restock(resp.Item, amount))
                 {
                   resp.Item.Consume(amount);
                   found = true;

                   break;
                 }
               }

               if (!found)
               {
                 cont = BuyPack;

                 if (amount < resp.Item.Amount)
                 {
                   Item item = LiftItemDupe(resp.Item, resp.Item.Amount - amount);

                   if (item != null)
                   {
                     item.SetLastMoved();
                     cont.DropItem(item);
                   }
                   else
                   {
                     resp.Item.SetLastMoved();
                     cont.DropItem(resp.Item);
                   }
                 }
                 else
                 {
                   resp.Item.SetLastMoved();
                   cont.DropItem(resp.Item);
                 }
               }
             }
             else
             {
               if (amount < resp.Item.Amount)
               {
                 resp.Item.Amount -= amount;
               }
               else
               {
                 resp.Item.Delete();
               }
             }

             GiveGold += ssi.GetSellPriceFor(resp.Item) * amount;
             break;
           }
         }
       }

       if (GiveGold > 0)
       {
         while (GiveGold > 60000)
         {
           seller.AddToBackpack(new Gold(60000));
           GiveGold -= 60000;
         }

         seller.AddToBackpack(new Gold(GiveGold));

         seller.PlaySound(0x0037); //Gold dropping sound

         if (SupportsBulkOrders(seller))
         {
           Item bulkOrder = CreateBulkOrder(seller, false);

           if (bulkOrder is LargeBOD)
           {
             seller.SendGump(new LargeBODAcceptGump(seller, (LargeBOD)bulkOrder));
           }
           else if (bulkOrder is SmallBOD)
           {
             seller.SendGump(new SmallBODAcceptGump(seller, (SmallBOD)bulkOrder));
           }
         }
       }
       //no cliloc for this?
       //SayTo( seller, true, "Thank you! I bought {0} item{1}. Here is your {2}gp.", Sold, (Sold > 1 ? "s" : ""), GiveGold );

       return true;
     }

     public override void Serialize(GenericWriter writer)
     {
       base.Serialize(writer);

       writer.Write((int)2 ); // version
///////////
//Automaited Staff
///////////
  #region VendorAccessLevels [03-04]

  writer.Write((int)VendorAccessLevel);

  #endregion Edited By: A.A.R
///////////
//End Automaited Staff
///////////
       var sbInfos = SBInfos;

       for (int i = 0; sbInfos != null && i < sbInfos.Count; ++i)
       {
         SBInfo sbInfo = sbInfos[i];
         var buyInfo = sbInfo.BuyInfo;

         for (int j = 0; buyInfo != null && j < buyInfo.Count; ++j)
         {
           GenericBuyInfo gbi = buyInfo[j];

           int maxAmount = gbi.MaxAmount;
           int doubled = 0;

           switch (maxAmount)
           {
             case 40:
               doubled = 1;
               break;
             case 80:
               doubled = 2;
               break;
             case 160:
               doubled = 3;
               break;
             case 320:
               doubled = 4;
               break;
             case 640:
               doubled = 5;
               break;
             case 999:
               doubled = 6;
               break;
           }

           if (doubled > 0)
           {
             writer.WriteEncodedInt(1 + ((j * sbInfos.Count) + i));
             writer.WriteEncodedInt(doubled);
           }
         }
       }

       writer.WriteEncodedInt(0);
     }

     public override void Deserialize(GenericReader reader)
     {
       base.Deserialize(reader);

       int version = reader.ReadInt();

       LoadSBInfo();

       var sbInfos = SBInfos;

       switch ( version )
       {
///////////
//Automatited Staff
///////////
  #region VendorAccessLevels [04-04]

  case 2:
  {
  m_VendorAccessLevel = (AccessLevel)reader.ReadInt();
  goto case 1;
  }

  #endregion Edited By: A.A.R
///////////
//End Automatited Staff
///////////
         case 1:
           {
             int index;

             while ((index = reader.ReadEncodedInt()) > 0)
             {
               int doubled = reader.ReadEncodedInt();

               if (sbInfos != null)
               {
                 index -= 1;
                 int sbInfoIndex = index % sbInfos.Count;
                 int buyInfoIndex = index / sbInfos.Count;

                 if (sbInfoIndex >= 0 && sbInfoIndex < sbInfos.Count)
                 {
                   SBInfo sbInfo = sbInfos[sbInfoIndex];
                   var buyInfo = sbInfo.BuyInfo;

                   if (buyInfo != null && buyInfoIndex >= 0 && buyInfoIndex < buyInfo.Count)
                   {
                     GenericBuyInfo gbi = buyInfo[buyInfoIndex];

                     int amount = 20;

                     switch (doubled)
                     {
                       case 1:
                         amount = 40;
                         break;
                       case 2:
                         amount = 80;
                         break;
                       case 3:
                         amount = 160;
                         break;
                       case 4:
                         amount = 320;
                         break;
                       case 5:
                         amount = 640;
                         break;
                       case 6:
                         amount = 999;
                         break;
                     }

                     gbi.Amount = gbi.MaxAmount = amount;
                   }
                 }
               }
             }

             break;
           }
       }

       if (IsParagon)
       {
         IsParagon = false;
       }

       Timer.DelayCall(TimeSpan.Zero, CheckMorph);
     }

     public override void AddCustomContextEntries(Mobile from, List<ContextMenuEntry> list)
     {
       if (from.Alive && IsActiveVendor)
       {
         if (SupportsBulkOrders(from))
         {
           list.Add(new BulkOrderInfoEntry(from, this));
         }

         if (IsActiveSeller)
         {
           list.Add(new VendorBuyEntry(from, this));
         }

         if (IsActiveBuyer)
         {
           list.Add(new VendorSellEntry(from, this));
         }
       }

       base.AddCustomContextEntries(from, list);
     }

     public virtual IShopSellInfo[] GetSellInfo()
     {
       return (IShopSellInfo[])m_ArmorSellInfo.ToArray(typeof(IShopSellInfo));
     }

     public virtual IBuyItemInfo[] GetBuyInfo()
     {
       return (IBuyItemInfo[])m_ArmorBuyInfo.ToArray(typeof(IBuyItemInfo));
     }
   }
}

namespace Server.ContextMenus
{
   public class VendorBuyEntry : ContextMenuEntry
   {
     private readonly BaseVendor m_Vendor;

     public VendorBuyEntry(Mobile from, BaseVendor vendor)
       : base(6103, 8)
     {
       m_Vendor = vendor;
       Enabled = vendor.CheckVendorAccess(from);
     }

     public override void OnClick()
     {
       m_Vendor.VendorBuy(Owner.From);
     }
   }

   public class VendorSellEntry : ContextMenuEntry
   {
     private readonly BaseVendor m_Vendor;

     public VendorSellEntry(Mobile from, BaseVendor vendor)
       : base(6104, 8)
     {
       m_Vendor = vendor;
       Enabled = vendor.CheckVendorAccess(from);
     }

     public override void OnClick()
     {
       m_Vendor.VendorSell(Owner.From);
     }
   }
}

namespace Server
{
   public interface IShopSellInfo
   {
     //get display name for an item
     string GetNameFor(Item item);

     //get price for an item which the player is selling
     int GetSellPriceFor(Item item);

     //get price for an item which the player is buying
     int GetBuyPriceFor(Item item);

     //can we sell this item to this vendor?
     bool IsSellable(Item item);

     //What do we sell?
     Type[] Types { get; }

     //does the vendor resell this item?
     bool IsResellable(Item item);
   }

   public interface IBuyItemInfo
   {
     //get a new instance of an object (we just bought it)
     IEntity GetEntity();

     int ControlSlots { get; }

     int PriceScalar { get; set; }

     //display price of the item
     int Price { get; }

     //display name of the item
     string Name { get; }

     //display hue
     int Hue { get; }

     //display id
     int ItemID { get; }

     //amount in stock
     int Amount { get; set; }

     //max amount in stock
     int MaxAmount { get; }

     //Attempt to restock with item, (return true if restock sucessful)
     bool Restock(Item item, int amount);

     //called when its time for the whole shop to restock
     void OnRestock();
   }
}
 
I got another weird issue im dealing with now too. I've created a bunch of custom NPC vendors, and Im trying to get them to stay the same. Every time the server restarts they go back to a generic random name, and body (male or female). Also ive noticed a LOT of bearded women vendors spawning all over britannia. At first I thought it was something wrong with the addations i've done to basevendor for the Automated staff, and having two of my towns spawn as elves (copying the gargoyle method of ilshenars garg city) So what I did was went back to a stock ServeUO Basevendor, and did about a 100 server restarts deleteing the vendors one at a time. When the server finally started, I had the same issue, a woman dressed like decard cain with a beard. I took note of some of the vendors near me, and restarted it, and everyone (including the now man dressed like decard cain with a different name) had changed their names. Got any ideas on how to fix this? I've done everything I can to try and fix Decard Cain but it changes every time.
Code:
using System;
using Server;
using System.Collections;
using Server.ContextMenus;
using System.Collections.Generic;
using Server.Misc;
using Server.Network;
using Server.Items;
using Server.Mobiles;
using Server.Gumps;

namespace Server.Mobiles
{
  public class DecardCain : BaseVendor
  {
  private readonly List<SBInfo> m_SBInfos = new List<SBInfo>();
  [Constructable]
  public DecardCain()
  : base("the sage")
  {
  this.Name = "Decard Cain";
       this.SetSkill(SkillName.ItemID, 90.0, 100.0);
  this.SetSkill(SkillName.TasteID, 75.0, 98.0);
  }

  public DecardCain(Serial serial)
  : base(serial)
  {
  }

  public override VendorShoeType ShoeType
  {
  get
  {
  return Utility.RandomBool() ? VendorShoeType.Sandals : VendorShoeType.Shoes;
  }
  }
  protected override List<SBInfo> SBInfos
  {
  get
  {
  return this.m_SBInfos;
  }
  }
  public override void InitSBInfo()
  {
  this.m_SBInfos.Add(new SBHealer());

  if (this.IsTokunoVendor)
  this.m_SBInfos.Add(new SBHealer());
  }

  public override void InitBody()
  {
  this.Female = false;
       this.HairHue = 1000;
       this.FacialHairHue = 1000;
       this.FacialHairItemID = 8268;
       this.Body = 400;
       this.Hue = 33770;
       this.Name = "Decard Cain";
  }

  public override void InitOutfit()
  {
     
       this.AddItem( new Robe( Utility.RandomBirdHue() ) );
       this.AddItem( new HalfApron( Utility.RandomBirdHue() ) );
       this.AddItem( new ShepherdsCrook() );
       this.AddItem( new Sandals() );
  }

  public override void Serialize(GenericWriter writer)
  {
  base.Serialize(writer);

  writer.Write((int)0); // version
  }

  public override void Deserialize(GenericReader reader)
  {
  base.Deserialize(reader);

  int version = reader.ReadInt();
  }
     public override void GetContextMenuEntries( Mobile from, List<ContextMenuEntry> list )
     {
       base.GetContextMenuEntries( from, list );
       list.Add( new DecardCainEntry( from, this ) );
     }

     public class DecardCainEntry : ContextMenuEntry
     {
       private Mobile m_Mobile;
       private Mobile m_Giver;
     
       public DecardCainEntry( Mobile from, Mobile giver ) : base( 6146, 3 )
       {
         m_Mobile = from;
         m_Giver = giver;
       }

       public override void OnClick()
       {
       

  if( !( m_Mobile is PlayerMobile ) )
         return;
       
         PlayerMobile mobile = (PlayerMobile) m_Mobile;

         {
           if ( ! mobile.HasGump( typeof( DecardCainGump ) ) )
           {
             mobile.SendGump( new DecardCainGump( mobile ));
           
           }
         }
       }
     }

     public override bool OnDragDrop( Mobile from, Item dropped )
     {     
       Mobile m = from;
       PlayerMobile mobile = m as PlayerMobile;

       if ( mobile != null)
       {
         if( dropped is BaseWeapon || dropped is BaseArmor || dropped is BaseClothing || dropped is BaseJewel || dropped is BaseTalisman || dropped is BaseWand || dropped is BaseInstrument )
         {
           BaseWeapon item1 = dropped as BaseWeapon;
           BaseArmor item2 = dropped as BaseArmor;
           BaseClothing item3 = dropped as BaseClothing;
           BaseJewel item4 = dropped as BaseJewel;
           BaseTalisman item5 = dropped as BaseTalisman;
           BaseWand item6 = dropped as BaseWand;
           BaseInstrument item7 = dropped as BaseInstrument;
         
           Container bank = m.FindBankNoCreate();
         
           if ( ( m.Backpack == null || m.Backpack.GetAmount( typeof( Gold ) ) < 100 ) && ( bank == null || bank.GetAmount( typeof( Gold ) ) < 100 ) )
           {
             SayTo( m, "Ah, young adventurer you have an unidentified item. If you wish me to Identify it you will need 100 gold." );
           }
           else
           {
             if( item1.Identified == false )
             {
               if ( ( m.Backpack != null && m.Backpack.ConsumeTotal( typeof( Gold ), 100 ) ) || ( bank != null && bank.ConsumeTotal( typeof( Gold ), 100 ) ) )
               {
                 item1.Identified = true;
                 SayTo( m, "My thanks to you. Here is the information about the weapon you requested." );
               }
             }
             else if( item1.Identified == true )
             {
               SayTo( m, "Unfortunately I can not tell you more about this weapon then you already know." );
             }
             else if( item2.Identified == false )
             {
               if ( ( m.Backpack != null && m.Backpack.ConsumeTotal( typeof( Gold ), 100 ) ) || ( bank != null && bank.ConsumeTotal( typeof( Gold ), 100 ) ) )
               {
                 item2.Identified = true;
                 SayTo( m, "My thanks to you. Here is the information about the armour you requested." );
               }
             }
             else if( item2.Identified == true )
             {
               SayTo( m, "Unfortunately I can not tell you more about this armour then you already know." );
             }
             else if( item3.Identified == false )
             {
               if ( ( m.Backpack != null && m.Backpack.ConsumeTotal( typeof( Gold ), 100 ) ) || ( bank != null && bank.ConsumeTotal( typeof( Gold ), 100 ) ) )
               {
                 item3.Identified = true;
                 SayTo( m, "My thanks to you. Here is the information about this article clothing you requested." );
               }
             }
             else if( item3.Identified == true )
             {
               SayTo( m, "Unfortunately I can not tell you more about  this article clothing then you already know." );
             }
             else if( item4.Identified == false )
             {
               if ( ( m.Backpack != null && m.Backpack.ConsumeTotal( typeof( Gold ), 100 ) ) || ( bank != null && bank.ConsumeTotal( typeof( Gold ), 100 ) ) )
               {
                 item4.Identified = true;
                 SayTo( m, "My thanks to you. Here is the information about the jewelry you requested." );
               }
             }
             else if( item4.Identified == true )
             {
               SayTo( m, "Unfortunately I can not tell you more about this jewelry then you already know." );
             }
             else if( item5.Identified == false )
             {
               if ( ( m.Backpack != null && m.Backpack.ConsumeTotal( typeof( Gold ), 100 ) ) || ( bank != null && bank.ConsumeTotal( typeof( Gold ), 100 ) ) )
               {
                 item5.Identified = true;
                 SayTo( m, "My thanks to you. Here is the information about the talisman you requested." );
               }
             }
             else if( item5.Identified == true )
             {
               SayTo( m, "Unfortunately I can not tell you more about this talisman then you already know." );
             }
             else if( item6.Identified == false )
             {
               if ( ( m.Backpack != null && m.Backpack.ConsumeTotal( typeof( Gold ), 100 ) ) || ( bank != null && bank.ConsumeTotal( typeof( Gold ), 100 ) ) )
               {
                 item6.Identified = true;
                 SayTo( m, "My thanks to you. Here is the information about the magic wand you requested." );
               }
             }
             else if( item6.Identified == true )
             {
               SayTo( m, "Unfortunately I can not tell you more about this magic wand then you already know, other then it can be charged with arcane gems." );
             }
             else if( item7.Identified == false )
             {
               if ( ( m.Backpack != null && m.Backpack.ConsumeTotal( typeof( Gold ), 100 ) ) || ( bank != null && bank.ConsumeTotal( typeof( Gold ), 100 ) ) )
               {
                 item7.Identified = true;
                 SayTo( m, "My thanks to you. Here is the information about the musical instrument you requested." );
               }
             }
             else if( item7.Identified == true )
             {
               SayTo( m, "Unfortunately I can not tell you more about this musical instrument then you already know. Tinkers and bards do sell tools to retune these items when they have wore out." );
             }
           }
         }
         else
         {
           SayTo( m, "I appreciate the gesture, but I am only here to help you identify items that need to be identified. This does not appear to need to be identified." );
         }         
       }

       return false;
   
     }
   }
}
I figure its got to be in basevendor somewhere otherwise the stock vendors would keep their names between restarts. I should also add that everything in the InitBody works except keeping his body as male and female false, and his name. (as well as the outfit)
 
I figured out part of the problem with my vendors changeing names and such, They are on the Nurem's Distro and it is set to go inactive if no one is arround, BUT that doesn't help with my decard cain becomeing a beared woman after restarts lol.
I got one other question too, When you are trying to put an item on a vendor thats already on it, lets say a healers robe, but you want to replace it with another robe (different color whatever) whats the line of test that you'd use to remove the old robe, so when they spawn they aren't wearing two robes (that seem to be causing client crashes). Would you use the Find Item by layer method and remove it?
 
Back