context: using System;
  using System.Collections.Generic;
  using Server.Engines.Craft;
  using Server.Items;
  using System.Linq;
  
  namespace Server.Engines.BulkOrders
  {
      public class SmallTinkerBOD : SmallBOD
      {
          public override BODType BODType { get { return BODType.Tinkering; } }
  
          private GemType _GemType;
  
          [CommandProperty(AccessLevel.GameMaster)]
          public GemType GemType
          {
              get { return _GemType; }
              set
              {
                  if (this.Type != null && this.Type.IsSubclassOf(typeof(BaseJewel)))
                  {
                      _GemType = value;
                      AssignGemNumber(this.Type);
  
                      InvalidateProperties();
                  }
              }
          }
  
          public static double[] m_TinkerMaterialChances = new double[]
          {
              0.501953125, // None
              0.250000000, // Dull Copper
              0.125000000, // Shadow Iron
              0.062500000, // Copper
              0.031250000, // Bronze
              0.015625000, // Gold
              0.007812500, // Agapite
              0.003906250, // Verite
              0.001953125  // Valorite
          };
  
          [Constructable]
          public SmallTinkerBOD()
          {
              SmallBulkEntry[] entries;
              bool useMaterials;
  
              if (useMaterials = 0.75 > Utility.RandomDouble())
                  entries = SmallBulkEntry.TinkeringSmalls;
              else
                  entries = SmallBulkEntry.TinkeringSmallsRegular;
  
              if (entries.Length > 0)
              {
                  int amountMax = Utility.RandomList(10, 15, 20);
  
                  BulkMaterialType material;
  
                  if (useMaterials)
                      material = GetRandomMaterial(BulkMaterialType.DullCopper, m_TinkerMaterialChances);
                  else
                      material = BulkMaterialType.None;
  
                  bool reqExceptional = useMaterials ? Utility.RandomBool() : false;
  
                  SmallBulkEntry entry = entries[Utility.Random(entries.Length)];
  
                  if (material != BulkMaterialType.None && CannotAssignMaterial(entry.Type))
                  {
                      material = BulkMaterialType.None;
                  }
  
                  Hue = 1109;
                  AmountMax = amountMax;
                  Type = entry.Type;
                  Number = entry.Number;
                  Graphic = entry.Graphic;
                  RequireExceptional = reqExceptional;
                  Material = material;
                  GraphicHue = entry.Hue;
  
                  if (entry.Type.IsSubclassOf(typeof(BaseJewel)))
                  {
                      AssignGemType(entry.Type);
                  }
              }
          }
  
          public SmallTinkerBOD(int amountCur, int amountMax, Type type, int number, int graphic, bool reqExceptional, BulkMaterialType mat, int hue, GemType gemType)
          {
              Hue = 1109;
              AmountMax = amountMax;
              AmountCur = amountCur;
              Type = type;
              Number = number;
              Graphic = graphic;
              RequireExceptional = reqExceptional;
              Material = mat;
              GraphicHue = hue;
              GemType = gemType;
          }
  
          public SmallTinkerBOD(Serial serial)
              : base(serial)
          {
          }
  
          private SmallTinkerBOD(SmallBulkEntry entry, BulkMaterialType material, int amountMax, bool reqExceptional)
          {
              Hue = 1109;
              AmountMax = amountMax;
              Type = entry.Type;
              Number = entry.Number;
              Graphic = entry.Graphic;
              RequireExceptional = reqExceptional;
              Material = material;
          }
  
          public static SmallTinkerBOD CreateRandomFor(Mobile m)
          {
              SmallBulkEntry[] entries;
              bool useMaterials;
  
              if (useMaterials = 0.75 > Utility.RandomDouble())
                  entries = SmallBulkEntry.TinkeringSmalls;
              else
                  entries = SmallBulkEntry.TinkeringSmallsRegular;
  
              if (entries.Length > 0)
              {
                  double theirSkill = BulkOrderSystem.GetBODSkill(m, SkillName.Tinkering);
                  int amountMax;
  
                  if (theirSkill >= 70.1)
                      amountMax = Utility.RandomList(10, 15, 20, 20);
                  else if (theirSkill >= 50.1)
                      amountMax = Utility.RandomList(10, 15, 15, 20);
                  else
                      amountMax = Utility.RandomList(10, 10, 15, 20);
  
                  BulkMaterialType material = BulkMaterialType.None;
  
                  if (useMaterials && theirSkill >= 70.1)
                  {
                      for (int i = 0; i < 20; ++i)
                      {
                          BulkMaterialType check = GetRandomMaterial(BulkMaterialType.DullCopper, m_TinkerMaterialChances);
                          double skillReq = GetRequiredSkill(check);
  
                          if (theirSkill >= skillReq)
                          {
                              material = check;
                              break;
                          }
                      }
                  }
  
                  double excChance = 0.0;
  
                  if (useMaterials && theirSkill >= 70.1)
                      excChance = (theirSkill + 80.0) / 200.0;
  
                  bool reqExceptional = (excChance > Utility.RandomDouble());
  
                  CraftSystem system = DefTinkering.CraftSystem;
  
                  List<SmallBulkEntry> validEntries = new List<SmallBulkEntry>();
  
                  for (int i = 0; i < entries.Length; ++i)
                  {
                      CraftItem item = system.CraftItems.SearchFor(entries[i].Type);
  
                      if (item != null)
                      {
                          bool allRequiredSkills = true;
                          double chance = item.GetSuccessChance(m, null, system, false, ref allRequiredSkills);
  
                          if (allRequiredSkills && chance >= 0.0)
                          {
                              if (reqExceptional)
                                  chance = item.GetExceptionalChance(system, chance, m);
  
                              if (chance > 0.0)
                                  validEntries.Add(entries[i]);
                          }
                      }
                  }
  
                  if (validEntries.Count > 0)
                  {
                      SmallBulkEntry entry = validEntries[Utility.Random(validEntries.Count)];
  
                      if (material != BulkMaterialType.None && CannotAssignMaterial(entry.Type))
                      {
                          material = BulkMaterialType.None;
                      }
  
                      var bod = new SmallTinkerBOD(entry, material, amountMax, reqExceptional);
  
                      if (entry.Type.IsSubclassOf(typeof(BaseJewel)))
                      {
                          bod.AssignGemType(entry.Type);
                      }
  
                      return bod;
                  }
              }
  
              return null;
          }
  
          public static bool CannotAssignMaterial(Type t)
          {
  
gt:             return _NonMaterials.Any(x => x == t || t.IsSubclassOf(x));