context: using Server.Guilds;
  using Server.Gumps;
  using Server.Misc;
  using Server.Mobiles;
  using Server.Multis;
  using Server.Regions;
  using System;
  using System.Collections.Generic;
  using System.Linq;
  
  namespace Server.Engines.VvV
  {
      public enum UpdateType
      {
          Kill,
          Assist,
          Steal,
          TurnInVice,
          TurnInVirtue,
          Disarm
      }
  
      [PropertyObject]
      public class VvVBattle
      {
          public static readonly int Duration = 30;
          public static readonly int Cooldown = 5;
          public static readonly int Announcement = 2;
          public static readonly int KillCooldownDuration = 5;
          public static readonly int MaxTraps = 20;
          public static readonly int MaxTurrets = 10;
  
          //Battle Scoring
          public static readonly double ScoreToWin = 10000;
          public static readonly double OccupyPoints = 300;
          public static readonly double AltarPoints = 1000;
          public static readonly double KillPoints = 600;
          public static readonly double TurnInPoints = 500;
  
          public static readonly int AltarSilver = 100;
          public static readonly int TurnInSilver = 100;
          public static readonly int KillSilver = 50;
          public static readonly int WinSilver = 100;
          public static readonly int DisarmSilver = 50;
  
          // silver penalty in the event the battle is uncontested
          public static readonly double Penalty = 0.5;
  
          [CommandProperty(AccessLevel.GameMaster)]
          public double SilverPenalty
          {
              get
              {
                  if (!ViceVsVirtueSystem.EnhancedRules)
                      return 1.0;
  
                  return UnContested ? Penalty : 1.0;
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public ViceVsVirtueSystem System { get; set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public DateTime StartTime { get; private set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public DateTime CooldownEnds { get; private set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public DateTime LastOccupationCheck { get; set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public DateTime NextSigilSpawn { get; set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public DateTime NextAnnouncement { get; set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public DateTime NextAltarActivate { get; set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public DateTime NextManaSpike { get; set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public DateTime ManaSpikeEndEffects { get; set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public VvVCity City { get; private set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public VvVSigil Sigil { get; set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public bool OnGoing { get; private set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public bool UnContested { get; private set; }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public Region Region
          {
              get
              {
                  CityInfo info = CityInfo.Infos[City];
  
                  if (info != null)
                  {
                      return info.Region;
                  }
  
                  return null;
              }
  
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public bool ForceStart
          {
              get { return false; }
              set
              {
                  if (!OnGoing && value)
                      Begin();
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public bool ForceEnd
          {
              get { return false; }
              set
              {
                  if (OnGoing && value)
                      EndBattle();
              }
          }
  
          public List<BattleTeam> Teams { get; set; }
  
          public Dictionary<Mobile, DateTime> KillCooldown { get; set; }
          public Dictionary<Mobile, DateTime> BattleAggression { get; set; }
          public List<string> Messages { get; set; }
  
          public List<VvVAltar> Altars { get; set; }
          public int AltarIndex { get; set; }
  
          public List<VvVTrap> Traps { get; set; }
          public List<CannonTurret> Turrets { get; set; }
          public List<Mobile> Warned { get; set; }
  
          public VvVPriest VicePriest { get; private set; }
          public VvVPriest VirtuePriest { get; private set; }
  
          public Timer Timer { get; private set; }
  
          public int TrapCount => Traps.Where(t => !t.Deleted).Count();
          public int TurretCount => Turrets.Where(t => !t.Deleted).Count();
  
          [CommandProperty(AccessLevel.GameMaster)]
          public bool InCooldown => CooldownEnds > DateTime.UtcNow;
  
          public DateTime NextCombatHeatCycle { get; private set; }
  
          public VvVBattle(ViceVsVirtueSystem sys)
          {
              System = sys;
          }
  
          public void Begin()
          {
              OnGoing = true;
              NextCombatHeatCycle = DateTime.UtcNow;
              VvVCity newCity = City;
              List<VvVCity> cities = new List<VvVCity>();
  
              Teams = new List<BattleTeam>();
              KillCooldown = new Dictionary<Mobile, DateTime>();
              Messages = new List<string>();
              Altars = new List<VvVAltar>();
              Traps = new List<VvVTrap>();
              Warned = new List<Mobile>();
              Turrets = new List<CannonTurret>();
  
              for (int i = 0; i < 8; i++)
              {
                  if (!System.ExemptCities.Contains((VvVCity)i) && (VvVCity)i != newCity)
                      cities.Add((VvVCity)i);
              }
  
              if (cities.Count > 0)
              {
                  newCity = cities[Utility.Random(cities.Count)];
              }
              else if (System.ExemptCities.Contains(newCity))
              {
                  System.SendVvVMessage("All VvV cities are currently exempt.");
                  return;
              }
  
              ColUtility.Free(cities);
              City = newCity;
              BeginTimer();
  
              StartTime = DateTime.UtcNow;
              NextSigilSpawn = DateTime.UtcNow + TimeSpan.FromMinutes(Utility.RandomMinMax(1, 3));
  
              AltarIndex = 0;
              SpawnAltars();
              SpawnPriests(false);
  
              if (Region is GuardedRegion)
              {
                  GuardedRegion.Disable((GuardedRegion)Region);
              }
  
              NextAltarActivate = DateTime.UtcNow + TimeSpan.FromMinutes(1);
  
              System.SendVvVMessage(1154721, String.Format("#{0}", ViceVsVirtueSystem.GetCityLocalization(City).ToString()));
              // A Battle between Vice and Virtue is active! To Arms! The City of ~1_CITY~ is besieged!
          }
  
          public void SpawnAltars()
          {
              foreach (Point3D p in CityInfo.Infos[City].AltarLocs)
              {
                  VvVAltar altar = new VvVAltar(this);
                  altar.MoveToWorld(p, Map.Felucca);
  
                  Altars.Add(altar);
              }
          }
  
          public void SpawnPriests(bool movetoworld = true)
          {
              if (VicePriest == null || VicePriest.Deleted)
                  VicePriest = new VvVPriest(VvVType.Vice, this);
  
              if (VirtuePriest == null || VirtuePriest.Deleted)
                  VirtuePriest = new VvVPriest(VvVType.Virtue, this);
  
              if (movetoworld)
              {
                  Point3D p;
  
                  do
                  {
                      p = Map.Felucca.GetRandomSpawnPoint(CityInfo.Infos[City].PriestLocation);
                  }
                  while (!Map.Felucca.CanSpawnMobile(p));
  
                  VicePriest.MoveToWorld(p, Map.Felucca);
  
                  do
                  {
                      p = Map.Felucca.GetRandomSpawnPoint(CityInfo.Infos[City].PriestLocation);
                  }
                  while (!Map.Felucca.CanSpawnMobile(p));
  
                  VirtuePriest.MoveToWorld(p, Map.Felucca);
              }
          }
  
          public void BeginTimer()
          {
              EndTimer();
  
              Timer = Timer.DelayCall(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), OnTick);
              Timer.Start();
          }
  
          public void EndTimer()
          {
              if (Timer != null)
              {
                  Timer.Stop();
                  Timer = null;
              }
          }
  
          public void OnTick()
          {
              if (!OnGoing)
                  return;
  
              CheckParticipation();
              UpdateAllGumps();
  
              if (StartTime + TimeSpan.FromMinutes(Duration) < DateTime.UtcNow)
              {
                  EndBattle();
                  return;
              }
  
              if (LastOccupationCheck + TimeSpan.FromMinutes(1) < DateTime.UtcNow)
              {
                  CheckOccupation();
  
                  LastOccupationCheck = DateTime.UtcNow;
              }
  
              if (NextAltarActivate != DateTime.MinValue && NextAltarActivate < DateTime.UtcNow)
              {
                  ActivateAltar();
                  NextAltarActivate = DateTime.MinValue;
              }
  
              if (NextSigilSpawn != DateTime.MinValue && NextSigilSpawn < DateTime.UtcNow)
              {
                  if (Sigil == null || Sigil.Deleted)
                  {
                      SpawnSigil();
                  }
              }
  
              ActivateArrows();
  
              if (KillCooldown != null)
              {
                  List<Mobile> list = KillCooldown.Keys.Where(mob => KillCooldown[mob] < DateTime.UtcNow).ToList();
  
                  foreach (Mobile m in list)
                  {
                      KillCooldown.Remove(m);
                  }
  
                  ColUtility.Free(list);
              }
  
              if (Turrets != null)
              {
                  Turrets.ForEach(t => { t.Scan(); });
              }
          }
  
          public void CheckParticipation()
          {
              if (Region == null)
                  return;
  
              BattleTeam team = null;
              UnContested = true;
              bool checkAggression = ViceVsVirtueSystem.EnhancedRules && NextCombatHeatCycle < DateTime.UtcNow;
  
              foreach (PlayerMobile pm in Region.GetEnumeratedMobiles().OfType<PlayerMobile>())
              {
                  bool vvv = ViceVsVirtueSystem.IsVvV(pm);
  
                  if (!vvv && !Warned.Contains(pm) && pm.AccessLevel == AccessLevel.Player)
                  {
                      pm.SendGump(new BattleWarningGump(pm));
                      Warned.Add(pm);
                  }
                  else if (vvv && pm.Alive && !pm.Hidden && BaseBoat.FindBoatAt(pm.Location, pm.Map) == null && BaseHouse.FindHouseAt(pm) == null)
                  {
                      Guild g = pm.Guild as Guild;
  
                      if (g != null)
                      {
                          BattleTeam t = GetTeam(g);
  
                          if (team == null)
                          {
                              team = t;
                          }
                          else if (t != team && UnContested)
                          {
                              UnContested = false;
                          }
                      }
                  }
  
                  if (checkAggression && (vvv || ViceVsVirtueSystem.IsVvVCombatant(pm)))
                  {
                      AddAggression(pm);
                  }
              }
  
              if (checkAggression)
              {
                  CheckBattleAggression();
  
                  NextCombatHeatCycle = DateTime.UtcNow + TimeSpan.FromMinutes(1);
              }
          }
  
          public void AddAggression(Mobile m)
          {
              if (m is PlayerMobile)
              {
                  if (BattleAggression == null)
                  {
                      BattleAggression = new Dictionary<Mobile, DateTime>();
                  }
  
                  BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.HeatOfBattleStatus, 1153801, 1153827, Aggression.CombatHeatDelay, m, true));
                  BattleAggression[m] = DateTime.UtcNow + TimeSpan.FromMinutes(2);
              }
          }
  
          private void CheckBattleAggression()
          {
              if (BattleAggression == null)
                  return;
  
              List<Mobile> list = new List<Mobile>(BattleAggression.Keys);
  
              foreach (Mobile m in list)
              {
                  if (BattleAggression[m] < DateTime.UtcNow && !m.Region.IsPartOf(Region))
                  {
                      BattleAggression.Remove(m);
                  }
              }
  
              ColUtility.Free(list);
          }
  
          public bool HasBattleAggression(Mobile m)
          {
              if (BattleAggression == null || !BattleAggression.ContainsKey(m))
              {
                  return false;
              }
  
              if (BattleAggression[m] < DateTime.UtcNow)
              {
                  BattleAggression.Remove(m);
                  return false;
              }
  
              return true;
          }
  
          public void EndBattle()
          {
              OnGoing = false;
              EndTimer();
  
              if (Region is GuardedRegion)
              {
                  ((GuardedRegion)Region).Disabled = false;
  
                  foreach (PlayerMobile pm in Region.GetEnumeratedMobiles().OfType<PlayerMobile>())
                  {
                      pm.RecheckTownProtection();
                  }
              }
  
              foreach (VvVAltar altar in Altars)
              {
                  if (!altar.Deleted)
                      altar.Delete();
              }
  
              foreach (VvVTrap trap in Traps)
              {
                  if (!trap.Deleted)
                      trap.Delete();
              }
  
              foreach (CannonTurret turret in Turrets)
              {
                  if (!turret.Deleted)
                      turret.Delete();
              }
  
  
gt:             if (VicePriest != null)