context: using Server.Gumps;
  using Server.Items;
  using Server.Mobiles;
  using Server.Regions;
  using Server.Services.Virtues;
  using Server.Spells.Necromancy;
  using System;
  using System.Collections.Generic;
  using System.Linq;
  
  namespace Server.Engines.CannedEvil
  {
      public class ChampionSpawn : Item
      {
          public static readonly int MaxStrayDistance = 250;
  
          private bool m_Active;
          private bool m_RandomizeType;
          private ChampionSpawnType m_Type;
          private List<Mobile> m_Creatures;
          private List<Item> m_RedSkulls;
          private List<Item> m_WhiteSkulls;
          private ChampionPlatform m_Platform;
          private ChampionAltar m_Altar;
          private int m_Kills;
          private Mobile m_Champion;
  
          //private int m_SpawnRange;
          private Rectangle2D m_SpawnArea;
          private ChampionSpawnRegion m_Region;
  
          private TimeSpan m_ExpireDelay;
          private DateTime m_ExpireTime;
  
          private TimeSpan m_RestartDelay;
          private DateTime m_RestartTime;
  
          private Timer m_Timer, m_RestartTimer;
  
          private IdolOfTheChampion m_Idol;
  
          private bool m_HasBeenAdvanced;
          private bool m_ConfinedRoaming;
  
          private Dictionary<Mobile, int> m_DamageEntries;
  
          public List<Mobile> Creatures => m_Creatures;
  
          [CommandProperty(AccessLevel.GameMaster)]
          public string GroupName { get; set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public double SpawnMod { get; set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public int SpawnRadius { get; set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public double KillsMod { get; set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public bool AutoRestart { get; set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public string SpawnName { get; set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public bool ConfinedRoaming
          {
              get
              {
                  return m_ConfinedRoaming;
              }
              set
              {
                  m_ConfinedRoaming = value;
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public bool HasBeenAdvanced
          {
              get
              {
                  return m_HasBeenAdvanced;
              }
              set
              {
                  m_HasBeenAdvanced = value;
              }
          }
  
          [Constructable]
          public ChampionSpawn()
              : base(0xBD2)
          {
              Movable = false;
              Visible = false;
  
              m_Creatures = new List<Mobile>();
              m_RedSkulls = new List<Item>();
              m_WhiteSkulls = new List<Item>();
  
              m_Platform = new ChampionPlatform(this);
              m_Altar = new ChampionAltar(this);
              m_Idol = new IdolOfTheChampion(this);
  
              m_ExpireDelay = TimeSpan.FromMinutes(10.0);
              m_RestartDelay = TimeSpan.FromMinutes(10.0);
  
              m_DamageEntries = new Dictionary<Mobile, int>();
              m_RandomizeType = false;
  
              SpawnRadius = 35;
              SpawnMod = 1;
  
              Timer.DelayCall(TimeSpan.Zero, new TimerCallback(SetInitialSpawnArea));
          }
  
          public void SetInitialSpawnArea()
          {
              //Previous default used to be 24;
              SpawnArea = new Rectangle2D(new Point2D(X - SpawnRadius, Y - SpawnRadius),
                  new Point2D(X + SpawnRadius, Y + SpawnRadius));
          }
  
          public void UpdateRegion()
          {
              if (m_Region != null)
                  m_Region.Unregister();
  
              if (!Deleted && Map != Map.Internal)
              {
                  m_Region = new ChampionSpawnRegion(this);
                  m_Region.Register();
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public bool RandomizeType
          {
              get
              {
                  return m_RandomizeType;
              }
              set
              {
                  m_RandomizeType = value;
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public int Kills
          {
              get
              {
                  return m_Kills;
              }
              set
              {
                  m_Kills = value;
                  InvalidateProperties();
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public Rectangle2D SpawnArea
          {
              get
              {
                  return m_SpawnArea;
              }
              set
              {
                  m_SpawnArea = value;
                  InvalidateProperties();
                  UpdateRegion();
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public TimeSpan RestartDelay
          {
              get
              {
                  return m_RestartDelay;
              }
              set
              {
                  m_RestartDelay = value;
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public DateTime RestartTime => m_RestartTime;
  
          [CommandProperty(AccessLevel.GameMaster)]
          public TimeSpan ExpireDelay
          {
              get
              {
                  return m_ExpireDelay;
              }
              set
              {
                  m_ExpireDelay = value;
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public DateTime ExpireTime
          {
              get
              {
                  return m_ExpireTime;
              }
              set
              {
                  m_ExpireTime = value;
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public ChampionSpawnType Type
          {
              get
              {
                  return m_Type;
              }
              set
              {
                  m_Type = value;
                  InvalidateProperties();
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public bool Active
          {
              get
              {
                  return m_Active;
              }
              set
              {
                  if (value)
                      Start();
                  else
                      Stop();
  
                  PrimevalLichPuzzle.Update(this);
  
                  InvalidateProperties();
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public Mobile Champion
          {
              get
              {
                  return m_Champion;
              }
              set
              {
                  m_Champion = value;
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public int Level
          {
              get
              {
                  return m_RedSkulls.Count;
              }
              set
              {
                  for (int i = m_RedSkulls.Count - 1; i >= value; --i)
                  {
                      m_RedSkulls[i].Delete();
                      m_RedSkulls.RemoveAt(i);
                  }
  
                  for (int i = m_RedSkulls.Count; i < value; ++i)
                  {
                      Item skull = new Item(0x1854);
  
                      skull.Hue = 0x26;
                      skull.Movable = false;
                      skull.Light = LightType.Circle150;
  
                      skull.MoveToWorld(GetRedSkullLocation(i), Map);
  
                      m_RedSkulls.Add(skull);
                  }
  
                  InvalidateProperties();
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public int StartLevel { get; private set; }
  
          private void RemoveSkulls()
          {
              if (m_WhiteSkulls != null)
              {
                  for (int i = 0; i < m_WhiteSkulls.Count; ++i)
                      m_WhiteSkulls[i].Delete();
  
                  m_WhiteSkulls.Clear();
              }
  
              if (m_RedSkulls != null)
              {
                  for (int i = 0; i < m_RedSkulls.Count; i++)
                      m_RedSkulls[i].Delete();
  
                  m_RedSkulls.Clear();
              }
          }
  
          public int MaxKills
          {
              get
              {
                  int l = Level;
                  return ChampionSystem.MaxKillsForLevel(l);
              }
          }
  
          public bool IsChampionSpawn(Mobile m)
          {
              return m_Creatures.Contains(m);
          }
  
          public void SetWhiteSkullCount(int val)
          {
              for (int i = m_WhiteSkulls.Count - 1; i >= val; --i)
              {
                  m_WhiteSkulls[i].Delete();
                  m_WhiteSkulls.RemoveAt(i);
              }
  
              for (int i = m_WhiteSkulls.Count; i < val; ++i)
              {
                  Item skull = new Item(0x1854);
  
                  skull.Movable = false;
                  skull.Light = LightType.Circle150;
  
                  skull.MoveToWorld(GetWhiteSkullLocation(i), Map);
  
                  m_WhiteSkulls.Add(skull);
  
                  Effects.PlaySound(skull.Location, skull.Map, 0x29);
                  Effects.SendLocationEffect(new Point3D(skull.X + 1, skull.Y + 1, skull.Z), skull.Map, 0x3728, 10);
              }
          }
  
          public void Start(bool serverLoad = false)
          {
              if (m_Active || Deleted)
                  return;
  
              m_Active = true;
              m_HasBeenAdvanced = false;
  
              if (m_Timer != null)
                  m_Timer.Stop();
  
              m_Timer = new SliceTimer(this);
              m_Timer.Start();
  
              if (m_RestartTimer != null)
                  m_RestartTimer.Stop();
  
              m_RestartTimer = null;
  
              if (m_Altar != null)
                  m_Altar.Hue = 0;
  
              PrimevalLichPuzzle.Update(this);
  
              if (!serverLoad)
              {
                  double chance = Utility.RandomDouble();
  
                  if (chance < 0.1)
                      Level = 4;
                  else if (chance < 0.25)
                      Level = 3;
                  else if (chance < 0.5)
                      Level = 2;
                  else if (Utility.RandomBool())
                      Level = 1;
  
                  StartLevel = Level;
  
                  if (Level > 0 && m_Altar != null)
                  {
                      Effects.PlaySound(m_Altar.Location, m_Altar.Map, 0x29);
                      Effects.SendLocationEffect(new Point3D(m_Altar.X + 1, m_Altar.Y + 1, m_Altar.Z), m_Altar.Map, 0x3728, 10);
                  }
              }
          }
  
          public void Stop()
          {
              if (!m_Active || Deleted)
                  return;
  
              m_Active = false;
              m_HasBeenAdvanced = false;
  
              // We must despawn all the creatures.
              if (m_Creatures != null)
              {
                  for (int i = 0; i < m_Creatures.Count; ++i)
                      m_Creatures[i].Delete();
  
                  m_Creatures.Clear();
              }
  
              if (m_Timer != null)
                  m_Timer.Stop();
  
              m_Timer = null;
  
              if (m_RestartTimer != null)
                  m_RestartTimer.Stop();
  
              m_RestartTimer = null;
  
              if (m_Altar != null)
                  m_Altar.Hue = 0x455;
  
              PrimevalLichPuzzle.Update(this);
  
              RemoveSkulls();
              m_Kills = 0;
          }
  
          public void BeginRestart(TimeSpan ts)
          {
              if (m_RestartTimer != null)
                  m_RestartTimer.Stop();
  
              m_RestartTime = DateTime.UtcNow + ts;
  
              m_RestartTimer = new RestartTimer(this, ts);
              m_RestartTimer.Start();
          }
  
          public void EndRestart()
          {
              if (RandomizeType)
              {
                  switch (Utility.Random(5))
                  {
                      case 0:
                          Type = ChampionSpawnType.Abyss; break;
                      case 1:
                          Type = ChampionSpawnType.Arachnid; break;
                      case 2:
                          Type = ChampionSpawnType.ColdBlood; break;
                      case 3:
                          Type = ChampionSpawnType.VerminHorde; break;
                      case 4:
                          Type = ChampionSpawnType.UnholyTerror; break;
                  }
              }
  
              m_HasBeenAdvanced = false;
  
              Start();
          }
  
          #region Scroll of Transcendence
          private ScrollOfTranscendence CreateRandomSoT(bool felucca)
          {
              int level = Utility.RandomMinMax(1, 5);
  
              if (felucca)
                  level += 5;
  
              return ScrollOfTranscendence.CreateRandom(level, level);
          }
  
          #endregion
  
          public static void GiveScrollTo(Mobile killer, SpecialScroll scroll)
          {
              if (scroll == null || killer == null)	//sanity
                  return;
  
              if (scroll is ScrollOfTranscendence)
                  killer.SendLocalizedMessage(1094936); // You have received a Scroll of Transcendence!
              else
                  killer.SendLocalizedMessage(1049524); // You have received a scroll of power!
  
              if (killer.Alive)
                  killer.AddToBackpack(scroll);
              else
              {
                  if (killer.Corpse != null && !killer.Corpse.Deleted)
                      killer.Corpse.DropItem(scroll);
                  else
                      killer.AddToBackpack(scroll);
              }
  
              // Justice reward
              PlayerMobile pm = (PlayerMobile)killer;
              for (int j = 0; j < pm.JusticeProtectors.Count; ++j)
              {
                  Mobile prot = pm.JusticeProtectors[j];
  
                  if (prot.Map != killer.Map || prot.Murderer || prot.Criminal || !JusticeVirtue.CheckMapRegion(killer, prot))
                      continue;
  
                  int chance = 0;
  
                  switch (VirtueHelper.GetLevel(prot, VirtueName.Justice))
                  {
                      case VirtueLevel.Seeker:
                          chance = 60;
                          break;
                      case VirtueLevel.Follower:
                          chance = 80;
                          break;
                      case VirtueLevel.Knight:
                          chance = 100;
                          break;
                  }
  
                  if (chance > Utility.Random(100))
                  {
                      try
                      {
                          prot.SendLocalizedMessage(1049368); // You have been rewarded for your dedication to Justice!
  
                          SpecialScroll scrollDupe = Activator.CreateInstance(scroll.GetType()) as SpecialScroll;
  
                          if (scrollDupe != null)
                          {
                              scrollDupe.Skill = scroll.Skill;
                              scrollDupe.Value = scroll.Value;
                              prot.AddToBackpack(scrollDupe);
                          }
                      }
                      catch
                      {
                      }
                  }
              }
          }
  
          private DateTime _NextGhostCheck;
  
          public void OnSlice()
          {
              if (!m_Active || Deleted)
                  return;
  
              int currentRank = Rank;
  
              if (m_Champion != null)
              {
                  if (m_Champion.Deleted)
                  {
                      RegisterDamageTo(m_Champion);
  
                      if (m_Champion is BaseChampion)
                          AwardArtifact(((BaseChampion)m_Champion).GetArtifact());
  
                      m_DamageEntries.Clear();
  
                      if (m_Altar != null)
                      {
                          m_Altar.Hue = 0x455;
  
                          if (Map == Map.Felucca)
                          {
                              new StarRoomGate(true, m_Altar.Location, m_Altar.Map);
                          }
                      }
  
                      m_Champion = null;
                      Stop();
  
                      if (AutoRestart)
                          BeginRestart(m_RestartDelay);
                  }
                  else if (m_Champion.Alive && m_Champion.GetDistanceToSqrt(this) > MaxStrayDistance)
                  {
                      m_Champion.MoveToWorld(new Point3D(X, Y, Z - 15), Map);
                  }
              }
              else
              {
                  int kills = m_Kills;
  
                  for (int i = 0; i < m_Creatures.Count; ++i)
                  {
                      Mobile m = m_Creatures[i];
  
                      if (m.Deleted)
                      {
                          if (m.Corpse != null && !m.Corpse.Deleted)
                          {
                              ((Corpse)m.Corpse).BeginDecay(TimeSpan.FromMinutes(1));
                          }
                          m_Creatures.RemoveAt(i);
                          --i;
  
                          int rankOfMob = GetRankFor(m);
                          if (rankOfMob == currentRank)
                              ++m_Kills;
  
                          Mobile killer = m.FindMostRecentDamager(false);
  
                          RegisterDamageTo(m);
  
                          if (killer is BaseCreature)
                              killer = ((BaseCreature)killer).GetMaster();
  
                          if (killer is PlayerMobile)
                          {
                              #region Scroll of Transcendence
                              if (Map == Map.Felucca)
                              {
                                  if (Utility.RandomDouble() < ChampionSystem.ScrollChance)
                                  {
                                      PlayerMobile pm = (PlayerMobile)killer;
  
                                      if (Utility.RandomDouble() < ChampionSystem.TranscendenceChance)
                                      {
                                          ScrollOfTranscendence SoTF = CreateRandomSoT(true);
                                          GiveScrollTo(pm, SoTF);
                                      }
                                      else
                                      {
                                          PowerScroll PS = PowerScroll.CreateRandomNoCraft(5, 5);
                                          GiveScrollTo(pm, PS);
                                      }
                                  }
                              }
  
                              if (Map == Map.Ilshenar || Map == Map.Tokuno || Map == Map.Malas)
                              {
                                  if (Utility.RandomDouble() < 0.0015)
                                  {
                                      killer.SendLocalizedMessage(1094936); // You have received a Scroll of Transcendence!
                                      ScrollOfTranscendence SoTT = CreateRandomSoT(false);
                                      killer.AddToBackpack(SoTT);
                                  }
                              }
                              #endregion
  
                              int mobSubLevel = rankOfMob + 1;
                              if (mobSubLevel >= 0)
                              {
                                  bool gainedPath = false;
  
                                  int pointsToGain = mobSubLevel * 40;
  
                                  if (VirtueHelper.Award(killer, VirtueName.Valor, pointsToGain, ref gainedPath))
                                  {
                                      if (gainedPath)
                                          killer.SendLocalizedMessage(1054032); // You have gained a path in Valor!
                                      else
                                          killer.SendLocalizedMessage(1054030); // You have gained in Valor!
                                      //No delay on Valor gains
                                  }
  
                                  PlayerMobile.ChampionTitleInfo info = ((PlayerMobile)killer).ChampionTitles;
  
                                  info.Award(m_Type, mobSubLevel);
  
                                  Server.Engines.CityLoyalty.CityLoyaltySystem.OnSpawnCreatureKilled(m as BaseCreature, mobSubLevel);
                              }
                          }
                      }
                  }
  
                  // Only really needed once.
                  if (m_Kills > kills)
                      InvalidateProperties();
  
                  double n = m_Kills / (double)MaxKills;
                  int p = (int)(n * 100);
  
                  if (p >= 90)
                      AdvanceLevel();
                  else if (p > 0)
                      SetWhiteSkullCount(p / 20);
  
                  if (DateTime.UtcNow >= m_ExpireTime)
                      Expire();
  
                  Respawn();
              }
  
              if (m_Timer != null && m_Timer.Running && _NextGhostCheck < DateTime.UtcNow)
              {
                  foreach (PlayerMobile ghost in m_Region.GetEnumeratedMobiles().OfType<PlayerMobile>().Where(pm => !pm.Alive && (pm.Corpse == null || pm.Corpse.Deleted)))
                  {
                      Map map = ghost.Map;
                      Point3D loc = ExorcismSpell.GetNearestShrine(ghost, ref map);
  
                      if (loc != Point3D.Zero)
                      {
                          ghost.MoveToWorld(loc, map);
                      }
                      else
                      {
                          ghost.MoveToWorld(new Point3D(989, 520, -50), Map.Malas);
                      }
                  }
  
                  _NextGhostCheck = DateTime.UtcNow + TimeSpan.FromMinutes(Utility.RandomMinMax(5, 8));
              }
          }
  
          public void AdvanceLevel()
          {
              m_ExpireTime = DateTime.UtcNow + m_ExpireDelay;
  
              if (Level < 16)
              {
                  m_Kills = 0;
                  ++Level;
                  InvalidateProperties();
                  SetWhiteSkullCount(0);
  
                  if (m_Altar != null)
                  {
                      Effects.PlaySound(m_Altar.Location, m_Altar.Map, 0x29);
                      Effects.SendLocationEffect(new Point3D(m_Altar.X + 1, m_Altar.Y + 1, m_Altar.Z), m_Altar.Map, 0x3728, 10);
                  }
              }
              else
              {
                  SpawnChampion();
              }
          }
  
          public void SpawnChampion()
          {
              m_Kills = 0;
              Level = 0;
              StartLevel = 0;
              InvalidateProperties();
              SetWhiteSkullCount(0);
  
              try
              {
                  m_Champion = Activator.CreateInstance(ChampionSpawnInfo.GetInfo(m_Type).Champion) as Mobile;
              }
              catch
              {
              }
  
              if (m_Champion != null)
              {
                  Point3D p = new Point3D(X, Y, Z - 15);
  
                  m_Champion.MoveToWorld(p, Map);
                  ((BaseCreature)m_Champion).Home = p;
  
                  if (m_Champion is BaseChampion)
                  {
                      ((BaseChampion)m_Champion).OnChampPopped(this);
                  }
              }
          }
  
          public void Respawn()
          {
              if (!m_Active || Deleted || m_Champion != null)
                  return;
  
              int currentLevel = Level;
              int currentRank = Rank;
              int maxSpawn = (int)(MaxKills * 0.5d * SpawnMod);
              if (currentLevel >= 16)
                  maxSpawn = Math.Min(maxSpawn, MaxKills - m_Kills);
              if (maxSpawn < 3)
                  maxSpawn = 3;
  
              int spawnRadius = (int)(SpawnRadius * ChampionSystem.SpawnRadiusModForLevel(Level));
              Rectangle2D spawnBounds = new Rectangle2D(new Point2D(X - spawnRadius, Y - spawnRadius),
                  new Point2D(X + spawnRadius, Y + spawnRadius));
  
              int mobCount = 0;
              foreach (Mobile m in m_Creatures)
              {
                  if (GetRankFor(m) == currentRank)
                      ++mobCount;
              }
  
              while (mobCount <= maxSpawn)
              {
                  Mobile m = Spawn();
  
                  if (m == null)
                      return;
  
                  Point3D loc = GetSpawnLocation(spawnBounds, spawnRadius);
  
                  // Allow creatures to turn into Paragons at Ilshenar champions.
                  m.OnBeforeSpawn(loc, Map);
  
                  m_Creatures.Add(m);
                  m.MoveToWorld(loc, Map);
                  ++mobCount;
  
                  if (m is BaseCreature)
                  {
                      BaseCreature bc = m as BaseCreature;
                      bc.Tamable = false;
                      bc.IsChampionSpawn = true;
  
                      if (!m_ConfinedRoaming)
                      {
                          bc.Home = Location;
                          bc.RangeHome = spawnRadius;
                      }
                      else
                      {
                          bc.Home = bc.Location;
  
                          Point2D xWall1 = new Point2D(spawnBounds.X, bc.Y);
                          Point2D xWall2 = new Point2D(spawnBounds.X + spawnBounds.Width, bc.Y);
                          Point2D yWall1 = new Point2D(bc.X, spawnBounds.Y);
                          Point2D yWall2 = new Point2D(bc.X, spawnBounds.Y + spawnBounds.Height);
  
                          double minXDist = Math.Min(bc.GetDistanceToSqrt(xWall1), bc.GetDistanceToSqrt(xWall2));
                          double minYDist = Math.Min(bc.GetDistanceToSqrt(yWall1), bc.GetDistanceToSqrt(yWall2));
  
                          bc.RangeHome = (int)Math.Min(minXDist, minYDist);
                      }
                  }
              }
          }
  
          public Point3D GetSpawnLocation()
          {
              return GetSpawnLocation(m_SpawnArea, 24);
          }
  
          public Point3D GetSpawnLocation(Rectangle2D rect, int range)
          {
              Map map = Map;
  
              if (map == null)
                  return Location;
  
              int cx = Location.X;
              int cy = Location.Y;
  
              // Try 20 times to find a spawnable location.
              for (int i = 0; i < 20; i++)
              {
                  int dx = Utility.Random(range * 2);
                  int dy = Utility.Random(range * 2);
                  int x = rect.X + dx;
                  int y = rect.Y + dy;
  
                  // Make spawn area circular
                  //if ((cx - x) * (cx - x) + (cy - y) * (cy - y) > range * range)
                  //	continue;
  
                  int z = Map.GetAverageZ(x, y);
  
                  if (Map.CanSpawnMobile(new Point2D(x, y), z))
                      return new Point3D(x, y, z);
  
                  /* try @ platform Z if map z fails */
                  else if (Map.CanSpawnMobile(new Point2D(x, y), m_Platform.Location.Z))
                      return new Point3D(x, y, m_Platform.Location.Z);
              }
  
              return Location;
          }
  
          public int Rank => ChampionSystem.RankForLevel(Level);
  
          public int GetRankFor(Mobile m)
          {
              Type[][] types = ChampionSpawnInfo.GetInfo(m_Type).SpawnTypes;
              Type t = m.GetType();
  
              for (int i = 0; i < types.GetLength(0); i++)
              {
                  Type[] individualTypes = types[i];
  
                  for (int j = 0; j < individualTypes.Length; j++)
                  {
                      if (t == individualTypes[j])
                          return i;
                  }
              }
  
              return -1;
          }
  
          public Mobile Spawn()
          {
              Type[][] types = ChampionSpawnInfo.GetInfo(m_Type).SpawnTypes;
  
              int v = Rank;
  
              if (v >= 0 && v < types.Length)
                  return Spawn(types[v]);
  
              return null;
          }
  
          public Mobile Spawn(params Type[] types)
          {
              try
              {
                  return Activator.CreateInstance(types[Utility.Random(types.Length)]) as Mobile;
              }
              catch
              {
                  return null;
              }
          }
  
          public void Expire()
          {
              m_Kills = 0;
  
              if (m_WhiteSkulls.Count == 0)
              {
                  // They didn't even get 20%, go back a level
                  if (Level > StartLevel)
                      --Level;
  
                  InvalidateProperties();
              }
              else
              {
                  SetWhiteSkullCount(0);
              }
  
              m_ExpireTime = DateTime.UtcNow + m_ExpireDelay;
          }
  
          public Point3D GetRedSkullLocation(int index)
          {
              int x, y;
  
  
gt:             if (index < 5)