text:
using Subterfuge.Remake.Core.Players;
using Subterfuge.Remake.Core.Timing;
using Subterfuge.Remake.Core.Topologies;

namespace Subterfuge.Remake.Core.Entities.Positions
{
	public class Watchtower : Outpost
	{
		/// <summary>
		/// Generator constructor
		/// </summary>
		/// <param name="id">The id of the outpost</param>
		/// <param name="outpostStartPosition">Position of outpost</param>
		public Watchtower(
			string id,
			RftVector outpostStartPosition,
			TimeMachine timeMachine
		) : base(id, outpostStartPosition, timeMachine) {
		}

		/// <summary>
		/// Generator constructor
		/// </summary>
		/// <param name="id">THe id of the outpost</param>
		/// <param name="outpostStartPosition">Position of outpost</param>
		/// <param name="outpostOwner">Owner of outpost</param>
		public Watchtower(
			string id,
			RftVector outpostStartPosition,
			Player outpostOwner,
			TimeMachine timeMachine
		) : base(id, outpostStartPosition, timeMachine, outpostOwner, Constants.BaseWatchtowerVisionRadius) {
		}

		public override OutpostType GetOutpostType()
		{
			return OutpostType.Watchtower;
		}
	}
}


text:
using Subterfuge.Remake.Core.GameEvents.EventPublishers;
using Subterfuge.Remake.Core.Players;
using Subterfuge.Remake.Core.Timing;
using Subterfuge.Remake.Core.Topologies;

namespace Subterfuge.Remake.Core.Entities.Positions
{
	public class Generator : Outpost
	{
		/// <summary>
		/// Generator constructor
		/// </summary>
		/// <param name="id">ID of the outpost</param>
		/// <param name="outpostStartPosition">Position of outpost</param>
		public Generator(string id, RftVector outpostStartPosition, TimeMachine timeMachine) : base(id, outpostStartPosition, timeMachine)
		{
		}

		/// <summary>
		/// Generator constructor
		/// </summary>
		/// <param name="id">ID of the outpost</param>
		/// <param name="outpostStartPosition">Position of outpost</param>
		/// <param name="outpostOwner">Owner of outpost</param>
		public Generator(string id, RftVector outpostStartPosition, Player outpostOwner, TimeMachine timeMachine) : base(id, outpostStartPosition, timeMachine, outpostOwner)
		{
		}

		public override OutpostType GetOutpostType()
		{
			return OutpostType.Generator;
		}
	}
}

repo_name: Subterfuge-Revived/Remake-Core

repo_language: C#

mime_type: text/plain


text:
using System;
using System.Collections.Generic;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents;
using Subterfuge.Remake.Core.GameEvents.EventPublishers;
using Subterfuge.Remake.Core.Players;
using Subterfuge.Remake.Core.Timing;
using Subterfuge.Remake.Core.Topologies;

namespace Subterfuge.Remake.Core.Entities.Positions
{
	/// <summary>
	/// Factory Class
	/// </summary>
	public class Factory : Outpost
	{

		/// <summary>
		/// Factory Constructor
		/// </summary>
		/// <param name="id">ID of the outpost</param>
		/// <param name="outpostStartPosition">Position of outpost</param>
		public Factory(string id, RftVector outpostStartPosition, TimeMachine timeMachine) : base(id, outpostStartPosition, timeMachine)
		{
			AddComponent(new DrillerProducer(this, timeMachine));
		}

		/// <summary>
		/// Factory Constructor
		/// </summary>
		/// <param name="id">ID of the outpost</param>
		/// <param name="outpostStartPosition">Position of outpost</param>
		/// <param name="outpostOwner">Owner of outpost</param>
		public Factory(string id, RftVector outpostStartPosition, Player outpostOwner, TimeMachine timeMachine) : base(id, outpostStartPosition, timeMachine, outpostOwner)
		{
			AddComponent(new DrillerProducer(this, timeMachine));
		}

		public override OutpostType GetOutpostType()
		{
			return OutpostType.Factory;
		}
	}
}


text:
using System;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.Players;
using Subterfuge.Remake.Core.Timing;
using Subterfuge.Remake.Core.Topologies;

namespace Subterfuge.Remake.Core.Entities.Positions
{
    public class OutpostFactory
    {
        public static Outpost CreateOutpost(
            OutpostType outpostType,
            Player owner,
            RftVector outpostLocation,
            TimeMachine timeMachine,
            int initialDrillers = Constants.InitialDrillersPerOutpost
        )
        {
            Outpost outpost = null;
            switch (outpostType)
            {
                case OutpostType.Factory:
                    outpost = new Factory(Guid.NewGuid().ToString(), outpostLocation, owner, timeMachine);
                    break;
                case OutpostType.Generator:
                    outpost = new Generator(Guid.NewGuid().ToString(), outpostLocation, owner, timeMachine);
                    break;
                case OutpostType.Mine:
                    outpost = new Mine(Guid.NewGuid().ToString(), outpostLocation, owner, timeMachine);
                    break;
                case OutpostType.Watchtower:
                    outpost = new Watchtower(Guid.NewGuid().ToString(), outpostLocation, owner, timeMachine);
                    break;
                default:
                    return null;
            }
            outpost.GetComponent<DrillerCarrier>().SetDrillerCount(initialDrillers);
            return outpost;
        }

        public static Outpost CreateOutpostWithId(
            string id,
            OutpostType outpostType,
            Player owner,
            RftVector outpostLocation,
            TimeMachine timeMachine,
            int initialDrillers = Constants.InitialDrillersPerOutpost
        )
        {
            Outpost outpost = null;
            switch (outpostType)
            {
                case OutpostType.Factory:
                    outpost = new Factory(id, outpostLocation, owner, timeMachine);
                    break;
                case OutpostType.Generator:
                    outpost = new Generator(id, outpostLocation, owner, timeMachine);
                    break;
                case OutpostType.Mine:
                    outpost = new Mine(id, outpostLocation, owner, timeMachine);
                    break;
                case OutpostType.Watchtower:
                    outpost = new Watchtower(id, outpostLocation, owner, timeMachine);
                    break;
                default:
                    return null;
            }
            outpost.GetComponent<DrillerCarrier>().SetDrillerCount(initialDrillers);
            return outpost;
        }
    }
}


text:
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents;
using Subterfuge.Remake.Core.Players;
using Subterfuge.Remake.Core.Timing;
using Subterfuge.Remake.Core.Topologies;

namespace Subterfuge.Remake.Core.Entities.Positions
{
	public class Mine : Outpost
	{
		/// <summary>
		/// Mine constructor
		/// </summary>
		/// <param name="id">THe id of the mine</param>
		/// <param name="outpostStartPosition">Position of outpost</param>
		public Mine(
			string id,
			RftVector outpostStartPosition,
			TimeMachine timeMachine
		) : base(id, outpostStartPosition, timeMachine) {
		}

		/// <summary>
		/// Mine constructor
		/// </summary>
		/// <param name="id">The id of the mine</param>
		/// <param name="outpostStartPosition">Position of outpost</param>
		/// <param name="outpostOwner">Owner of outpost</param>
		public Mine(
			string id,
			RftVector outpostStartPosition,
			Player outpostOwner,
			TimeMachine timeMachine
		) : base(id, outpostStartPosition, timeMachine, outpostOwner) {
			AddComponent(new NeptuniumProducer(this, timeMachine));
		}

		/// <summary>
		/// Mine constructor. Use in preparation to replace a non-mine outpost with a mine outpost with the same properties.
		/// </summary>
		/// <param name="o">The outpost to replicate as a mine</param>
		public Mine(
			Outpost o,
			TimeMachine timeMachine
		) : base(o, timeMachine) {
			AddComponent(new NeptuniumProducer(this, timeMachine));
		}

		public override OutpostType GetOutpostType()
		{
			return OutpostType.Mine;
		}
	}
}


text:
using Newtonsoft.Json;
using Subterfuge.Remake.Api.Network;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.Entities.Positions;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.PlayerTriggeredEvents
{
	public class DrillMineEvent : PlayerTriggeredEvent
	{
		public Outpost OriginalOutpost;
		public Mine CreatedMine;

		public DrillMineEvent(GameRoomEvent mining) : base(mining)
		{
		}

		public DrillMineEventData GetEventData()
		{
			return JsonConvert.DeserializeObject<DrillMineEventData>(Model.GameEventData.SerializedEventData);
		}

		public override bool ForwardAction(TimeMachine timeMachine)
		{
			var state = timeMachine.GetState();
			Entity drillLocation = state.GetEntity(GetEventData().SourceId);
			if (drillLocation != null && drillLocation is Outpost && !(drillLocation is Mine) && !((Outpost)drillLocation).GetComponent<DrillerCarrier>().IsDestroyed())
			{
				OriginalOutpost = (Outpost)drillLocation;
				var drillerCarrier = drillLocation.GetComponent<DrillerCarrier>();
				if (state.GetOutposts().Contains(OriginalOutpost) && !drillerCarrier.GetOwner().IsEliminated() && drillerCarrier.GetDrillerCount() >= drillerCarrier.GetOwner().GetRequiredDrillersToMine())
				{
					CreatedMine = new Mine(OriginalOutpost, timeMachine);
					if (state.ReplaceOutpost(OriginalOutpost, CreatedMine))
					{
						drillerCarrier.AlterDrillers(drillerCarrier.GetOwner().GetRequiredDrillersToMine() * -1);
						drillerCarrier.GetOwner().AlterMinesDrilled(1);
						EventSuccess = true;
					}
				}
			}
			else
			{
				EventSuccess = false;
			}
			return EventSuccess;
		}

		public override bool BackwardAction(TimeMachine timeMachine)
		{
			if (EventSuccess)
			{
				var drillerCarrier = CreatedMine.GetComponent<DrillerCarrier>();
				timeMachine.GetState().ReplaceOutpost(CreatedMine, OriginalOutpost);
				drillerCarrier.GetOwner().AlterMinesDrilled(-1);
				drillerCarrier.AlterDrillers(drillerCarrier.GetOwner().GetRequiredDrillersToMine());
			}
			return EventSuccess;
		}

		public override bool WasEventSuccessful()
		{
			return EventSuccess;
		}
	}
}


text:
using Subterfuge.Remake.Api.Network;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.PlayerTriggeredEvents
{
    public class PauseGameEvent : PlayerTriggeredEvent
    {
        public PauseGameEvent(GameRoomEvent model) : base(model, Priority.PAUSE_EVENT)
        {
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            timeMachine.TogglePause(true);
            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            timeMachine.TogglePause(false);
            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }
    }
}


text:
using System.Linq;
using Newtonsoft.Json;
using Subterfuge.Remake.Api.Network;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.Entities.Positions;
using Subterfuge.Remake.Core.Entities.Specialists;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.PlayerTriggeredEvents
{
    public class HireSpecialistEvent : PlayerTriggeredEvent
    {
        private IEntity HiredAt;
        private Specialist HiredSpecialist;

        public HireSpecialistEvent(GameRoomEvent model) : base(model)
        {
        }

        public HireSpecialistEventData GetEventData()
        {
            return JsonConvert.DeserializeObject<HireSpecialistEventData>(Model.GameEventData.SerializedEventData);
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            HireSpecialistEventData hireEvent = GetEventData();

            var hireLocation = timeMachine.GetState().GetEntity(hireEvent.HireLocation);
            if (hireLocation == null)
            {
                EventSuccess = false;
                return EventSuccess;
            }

            var specialist = this.IssuedBy().SpecialistPool.HireSpecialist(hireEvent.SpecialistTypeIdHired);
            hireLocation.GetComponent<SpecialistManager>()
                .HireSpecialist(specialist, timeMachine);

            HiredSpecialist = specialist;
            HiredAt = hireLocation;

            EventSuccess = true;
            return EventSuccess;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            if (EventSuccess)
            {
                HiredAt.GetComponent<SpecialistManager>().UndoHireSpecialist(HiredSpecialist, timeMachine);

                this.IssuedBy()
                    .SpecialistPool
                    .UndoSpecialistHire();

                return true;
            }

            return false;
        }

        public override bool WasEventSuccessful()
        {
            return EventSuccess;
        }
    }
}


text:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Subterfuge.Remake.Api.Network;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.Entities.Positions;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;
using Subterfuge.Remake.Core.Topologies;

namespace Subterfuge.Remake.Core.GameEvents.PlayerTriggeredEvents
{
    /// <summary>
    /// The event to launch a new sub. Create a new instance and add it to the time machine with `Game.timeMachine.add()`
    /// </summary>
    public class LaunchEvent : PlayerTriggeredEvent
    {
        /// <summary>
        /// A reference to the sub once it is launched
        /// </summary>
        private Sub _launchedSub;

        private readonly List<GameEvent> _combatEvents = new List<GameEvent>();
        public LaunchEvent(GameRoomEvent launch) : base(launch)
        {
        }

        public void SetLaunchedSub(Sub sub)
        {
            _launchedSub = sub;
        }

        /// <summary>
        /// Performs the backwards event
        /// </summary>
        public override bool BackwardAction(TimeMachine timeMachine)
        {
            if (this.EventSuccess)
            {
                timeMachine.GetState().GetEntity(GetEventData().SourceId).GetComponent<SubLauncher>().UndoLaunch(timeMachine, this);
            }
            return this.EventSuccess;
        }

        public override bool WasEventSuccessful()
        {
            return this.EventSuccess;
        }

        public LaunchEventData GetEventData()
        {
            return JsonConvert.DeserializeObject<LaunchEventData>(Model.GameEventData.SerializedEventData);
        }

        /// <summary>
        /// Performs the forward event
        /// </summary>
        public override bool ForwardAction(TimeMachine timeMachine)
        {
            this._launchedSub = timeMachine.GetState().GetEntity(GetEventData().SourceId).GetComponent<SubLauncher>().LaunchSub(timeMachine, this);

            if (_launchedSub != null && !_launchedSub.GetComponent<DrillerCarrier>().GetOwner().IsEliminated())
            {
                this.EventSuccess = true;
            } else
            {
                this.EventSuccess = false;
            }

            return this.EventSuccess;
        }

        /// <summary>
        /// Gets the sub instance of the launch
        /// </summary>
        /// <returns>The sub that was launched</returns>
        public Sub GetActiveSub()
        {
            return _launchedSub;
        }
    }
}


text:
using System.Linq;
using Newtonsoft.Json;
using Subterfuge.Remake.Api.Network;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.PlayerTriggeredEvents
{
    public class PlayerLeaveGameEvent : PlayerTriggeredEvent
    {
        public PlayerLeaveGameEvent(GameRoomEvent model) : base(model)
        {
        }

        public PlayerLeaveGameEventData GetEventData()
        {
            return JsonConvert.DeserializeObject<PlayerLeaveGameEventData>(Model.GameEventData.SerializedEventData);
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            var playerToLeave = timeMachine.GetState().GetPlayers()
                .FirstOrDefault(player => player.GetId() == GetEventData().Player.Id);

            if (playerToLeave != null)
            {
                playerToLeave.SetEliminated(true);
                EventSuccess = true;
                return true;
            }
            EventSuccess = false;
            return false;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            var playerToLeave = timeMachine.GetState().GetPlayers()
                .FirstOrDefault(player => player.GetId() == GetEventData().Player.Id);

            if (playerToLeave != null)
            {
                playerToLeave.SetEliminated(false);
                EventSuccess = true;
                return true;
            }
            EventSuccess = false;
            return false;
        }

        public override bool WasEventSuccessful()
        {
            return EventSuccess;
        }
    }
}


text:
using Newtonsoft.Json;
using Subterfuge.Remake.Api.Network;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.PlayerTriggeredEvents
{
    public class ToggleShieldEvent : PlayerTriggeredEvent
    {
        public ToggleShieldEvent(GameRoomEvent model) : base(model)
        {

        }

        public ToggleShieldEventData GetEventData()
        {
            return JsonConvert.DeserializeObject<ToggleShieldEventData>(Model.GameEventData.SerializedEventData);
        }
        public override bool ForwardAction(TimeMachine timeMachine)
        {
            ShieldManager shieldManager = timeMachine.GetState().GetEntity(GetEventData().SourceId).GetComponent<ShieldManager>();
            DrillerCarrier drillerCarrier = timeMachine.GetState().GetEntity(GetEventData().SourceId).GetComponent<DrillerCarrier>();
            if (shieldManager != null && !drillerCarrier.GetOwner().IsEliminated())
            {
                shieldManager.ToggleShield();
                EventSuccess = true;
            }
            else
            {
                EventSuccess = false;
            }

            return EventSuccess;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            if (EventSuccess)
            {
                ShieldManager shieldManager = timeMachine.GetState().GetEntity(GetEventData().SourceId).GetComponent<ShieldManager>();
                shieldManager.ToggleShield();
            }
            return EventSuccess;
        }

        public override bool WasEventSuccessful()
        {
            return EventSuccess;
        }
    }
}


text:
using Newtonsoft.Json;
using Subterfuge.Remake.Api.Network;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.PlayerTriggeredEvents
{
    public class PromoteSpecialistEvent : PlayerTriggeredEvent
    {
        public PromoteSpecialistEvent(GameRoomEvent model) : base(model)
        {
        }

        public PromoteSpecialistEventData GetEventData()
        {
            return JsonConvert.DeserializeObject<PromoteSpecialistEventData>(Model.GameEventData.SerializedEventData);
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            throw new System.NotImplementedException();
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            throw new System.NotImplementedException();
        }

        public override bool WasEventSuccessful()
        {
            throw new System.NotImplementedException();
        }
    }
}


text:
using Newtonsoft.Json;
using Subterfuge.Remake.Api.Network;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.PlayerTriggeredEvents
{
    public class GameEndEvent : PlayerTriggeredEvent
    {
        public GameEndEvent(GameRoomEvent model) : base(model)
        {
        }

        public GameEndEventData GetEventData()
        {
            return JsonConvert.DeserializeObject<GameEndEventData>(Model.GameEventData.SerializedEventData);
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }
    }
}


text:
using Subterfuge.Remake.Api.Network;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.PlayerTriggeredEvents
{
    public class UnpauseGameEvent : PlayerTriggeredEvent
    {
        public UnpauseGameEvent(GameRoomEvent model) : base(model, Priority.UNPAUSE_EVENT)
        {
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            timeMachine.TogglePause(false);
            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            timeMachine.TogglePause(true);
            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }

    }
}


text:
using System;
using Microsoft.DotNet.PlatformAbstractions;
using Newtonsoft.Json;
using Subterfuge.Remake.Api.Network;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Players;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.PlayerTriggeredEvents
{
    public abstract class PlayerTriggeredEvent : GameEvent
    {
        protected readonly GameRoomEvent Model;
        protected PlayerTriggeredEvent(GameRoomEvent model) : base(new GameTick(model.GameEventData.OccursAtTick), Priority.PlayerIssuedCommand)
        {
            this.Model = model;
        }

        protected PlayerTriggeredEvent(GameRoomEvent model, Priority overridePriority) : base(new GameTick(model.GameEventData.OccursAtTick), overridePriority)
        {
            this.Model = model;
        }

        public Player IssuedBy()
        {
            return new Player(Model.IssuedBy);
        }

        public DateTime GetUnixTimeIssued()
        {
            return Model.TimeIssued;
        }

        public override string GetEventId()
        {
            return Model.Id;
        }

        public GameRoomEvent GetBaseGameEventModel()
        {
            return Model;
        }

        public override bool Equals(object other)
        {
            PlayerTriggeredEvent asEvent = other as PlayerTriggeredEvent;
            if (asEvent == null)
                return false;

            return asEvent.OccursAt == this.OccursAt &&
                   asEvent.IssuedBy().PlayerInstance.Equals(this.IssuedBy().PlayerInstance) &&
                   asEvent.GetBaseGameEventModel().Id == this.GetBaseGameEventModel().Id;
        }

        public override int GetHashCode()
        {
            var hashBuilder = new HashCodeCombiner();
            hashBuilder.Add(IssuedBy().PlayerInstance);
            hashBuilder.Add(OccursAt);
            hashBuilder.Add(Priority);
            hashBuilder.Add(GetBaseGameEventModel().Id);
            return hashBuilder.GetHashCode();
        }
    }
}


text:
using System;
using Microsoft.DotNet.PlatformAbstractions;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat
{
    public abstract class PositionalGameEvent : GameEvent
    {
        private readonly IEntity _expectedRegenerationLocation;

        protected PositionalGameEvent(GameTick occursAt, Priority priority, IEntity expectedRegenerationLocation) : base(occursAt, priority)
        {
            _expectedRegenerationLocation = expectedRegenerationLocation;
        }

        public override string GetEventId()
        {
            return GetHashCode().ToString();
        }

        public override bool Equals(object other)
        {
            PositionalGameEvent asEvent = other as PositionalGameEvent;
            if (asEvent == null)
                return false;

            return asEvent.OccursAt == this.OccursAt &&
                   asEvent.Priority == this.Priority &&
                   asEvent._expectedRegenerationLocation == this._expectedRegenerationLocation;
        }

        public override int GetHashCode()
        {
            var hashBuilder = new HashCodeCombiner();
            hashBuilder.Add(_expectedRegenerationLocation);
            hashBuilder.Add(OccursAt);
            hashBuilder.Add(Priority);
            return hashBuilder.GetHashCode();
        }

    }
}


text:
using System.Collections.Generic;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents;
using Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents.CombatResolve;
using Subterfuge.Remake.Core.GameEvents.Validators;
using Subterfuge.Remake.Core.Players;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat
{
    /// <summary>
    /// CombatEvent. It is considered a 'combat' if you arrive at any outpost, even your own.
    /// </summary>
    public class CombatEvent : PositionalGameEvent
    {
        public readonly IEntity _combatant1;
        public readonly IEntity _combatant2;

        public List<PositionalGameEvent> CombatEventList = new List<PositionalGameEvent>();
        private readonly CombatResolveEvent _combatResolveEvent;

        /// <summary>
        /// Constructor for the combat event
        /// </summary>
        /// <param name="combatant1">The first combatant</param>
        /// <param name="combatant2">The second combatant</param>
        /// <param name="tick">The tick the combat occurs</param>
        public CombatEvent(IEntity combatant1, IEntity combatant2, GameTick tick) : base(tick, Priority.COMBAT_EVENT, combatant1)
        {
            this._combatant1 = combatant1;
            this._combatant2 = combatant2;
            _combatResolveEvent = new CombatResolveEvent(tick, combatant1, combatant2, this);
            CombatEventList.Add(_combatResolveEvent);
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            if (!Validator.ValidateICombatable(timeMachine.GetState(), _combatant1) || !Validator.ValidateICombatable(timeMachine.GetState(), _combatant2))
            {
                this.EventSuccess = false;
                return false;
            }

            var skipUnnaturalEvents = false;

            // Sort the list in order of priority.
            CombatEventList.Sort();
            CombatEventList.ForEach(action =>
            {
                if (action is NeutralizeSpecialistEffects)
                {
                    skipUnnaturalEvents = true;
                }

                if (skipUnnaturalEvents && IsEventUnnatural(action))
                {
                    // NoOp
                }
                else
                {
                    action.ForwardAction(timeMachine);
                }
            });

            this.EventSuccess = true;
            return true;
        }

        private bool IsEventUnnatural(GameEvent gameEvent)
        {
            return PriorityExtensions.NaturalEvents().Contains(gameEvent.Priority);
        }

        public bool IsFriendlyCombat()
        {
            return Equals(_combatant1.GetComponent<DrillerCarrier>().GetOwner(), _combatant2.GetComponent<DrillerCarrier>().GetOwner());
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            if (EventSuccess)
            {
                var skipUnnaturalEvents = false;

                CombatEventList.Sort();
                CombatEventList.Reverse();
                CombatEventList.ForEach(action =>
                {
                    if (skipUnnaturalEvents && IsEventUnnatural(action))
                    {
                        // NoOp
                    }
                    else
                    {
                        action.BackwardAction(timeMachine);
                    }

                    if (action is NeutralizeSpecialistEffects)
                    {
                        skipUnnaturalEvents = true;
                    }
                });
            }

            return this.EventSuccess;
        }

        public override bool WasEventSuccessful()
        {
            return this.EventSuccess;
        }

        public void AddEffectToCombat(PositionalGameEvent combatEffect)
        {
            CombatEventList.Add(combatEffect);
        }

        public IEntity? GetEntityOwnedBy(Player player)
        {
            if (Equals(_combatant1.GetComponent<DrillerCarrier>().GetOwner(), player))
            {
                return _combatant1;
            }
            if (Equals(_combatant2.GetComponent<DrillerCarrier>().GetOwner(), player))
            {
                return _combatant2;
            }

            return null;
        }

        public IEntity? GetEnemyEntity(Player player)
        {
            if (Equals(_combatant1.GetComponent<DrillerCarrier>().GetOwner(), player))
            {
                return _combatant2;
            }
            if (Equals(_combatant2.GetComponent<DrillerCarrier>().GetOwner(), player))
            {
                return _combatant1;
            }

            return null;
        }

        public CombatResolution GetCombatResolution()
        {
            return _combatResolveEvent.CombatResolution;
        }
    }
}


text:
using System;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents.CombatResolve;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class CombatResolveEvent : PositionalGameEvent
    {
        private readonly IEntity _combatant1;
        private readonly IEntity _combatant2;

        public CombatResolution CombatResolution;
        private CombatEvent _combatEvent;

        public CombatResolveEvent(
            GameTick occursAt,
            IEntity combatant1,
            IEntity combatant2,
            CombatEvent combatEvent
        ) : base(occursAt, Priority.COMBAT_RESOLVE, combatant1)
        {
            _combatant1 = combatant1;
            _combatant2 = combatant2;
            _combatEvent = combatEvent;
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            switch (DetermineCombatType())
            {
                case CombatType.FRIENDLY:
                    CombatResolution = new FriendlyCombatResolution(OccursAt, _combatant1, _combatant2);
                    break;
                case CombatType.SUB_TO_SUB:
                    CombatResolution = new SubToSubResolution(OccursAt, _combatant1, _combatant2);
                    break;
                case CombatType.SUB_TO_OUTPOST:
                    CombatResolution = new SubToOutpostResolution(OccursAt, _combatant1, _combatant2);
                    break;
                default:
                    break;
            }

            return CombatResolution.ForwardAction(timeMachine);
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            return CombatResolution.BackwardAction(timeMachine);
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }

        private CombatType DetermineCombatType()
        {
            if (Equals(_combatant1.GetComponent<DrillerCarrier>().GetOwner(), _combatant2.GetComponent<DrillerCarrier>().GetOwner()))
            {
                return CombatType.FRIENDLY;
            }

            if (_combatant1 is Sub && _combatant2 is Sub)
            {
                return CombatType.SUB_TO_SUB;
            }

            return CombatType.SUB_TO_OUTPOST;
        }
    }
}

public enum CombatType
{
    Unknown = 0,
    SUB_TO_SUB = 1,
    SUB_TO_OUTPOST = 2,
    FRIENDLY = 3,
}


text:
using System.Collections.Generic;
using System.Linq;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.Entities.Positions;
using Subterfuge.Remake.Core.Entities.Specialists;
using Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents.CombatResolve;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class FriendlyCombatResolution : CombatResolution
    {
        private Sub _sub;
        private Outpost _outpost;

        private int _drillersTransferred;
        private List<Specialist> _specialistsTransferred;

        public FriendlyCombatResolution(
            GameTick occursAt,
            IEntity combatant1,
            IEntity combatant2
        ) : base(occursAt, CombatType.FRIENDLY, combatant1)
        {
            _sub = (Sub)(combatant1 is Sub ? combatant1 : combatant2);
            _outpost = (Outpost)(combatant1 is Outpost ? combatant1 : combatant2);
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            _drillersTransferred = _sub.GetComponent<DrillerCarrier>().GetDrillerCount();
            _specialistsTransferred = _sub.GetComponent<SpecialistManager>().GetSpecialists();

            _outpost.GetComponent<DrillerCarrier>().AlterDrillers(_drillersTransferred);
            _sub.GetComponent<DrillerCarrier>().AlterDrillers(_drillersTransferred * -1);
            _sub.GetComponent<SpecialistManager>().TransferSpecialistsTo(_outpost.GetComponent<SpecialistManager>(), timeMachine);
            timeMachine.GetState().RemoveSub(_sub);
            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            _outpost.GetComponent<DrillerCarrier>().AlterDrillers(_drillersTransferred * -1);
            _outpost.GetComponent<SpecialistManager>()
                .TransferSpecialistsById(_sub.GetComponent<SpecialistManager>(), _specialistsTransferred.Select(it => it.GetId()).ToList(), timeMachine);
            timeMachine.GetState().AddSub(_sub);
            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }
    }
}


text:
using System.Collections.Generic;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Positions;
using Subterfuge.Remake.Core.Entities.Specialists;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents.CombatResolve;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class SubToOutpostResolution : CombatResolution
    {
        private Sub _sub;
        private Outpost _outpost;

        private readonly CombatDrillersEffect _drillerCombatDrillers;
        private readonly CombatShieldEffect _shield;
        private readonly CombatSpecialistCaptureEffect _combatSpecialistCapture;
        private readonly CombatOwnershipTransferEffect _combatOwnershipTransfer;
        private readonly CombatRemoveEmptyEntitiesEffect _combatRemoveEmptyEntities;

        public SubToOutpostResolution(
            GameTick occursAt,
            IEntity combatant1,
            IEntity combatant2
        ) : base(occursAt, CombatType.SUB_TO_OUTPOST, combatant1)
        {
            _sub = (Sub)(combatant1 is Sub ? combatant1 : combatant2);
            _outpost = (Outpost)(combatant1 is Outpost ? combatant1 : combatant2);
            _drillerCombatDrillers = new CombatDrillersEffect(occursAt, _sub, _outpost);
            _shield = new CombatShieldEffect(occursAt, _sub, _outpost);
            _combatSpecialistCapture = new CombatSpecialistCaptureEffect(occursAt, _sub, _outpost);
            _combatOwnershipTransfer = new CombatOwnershipTransferEffect(occursAt, _sub, _outpost);
            _combatRemoveEmptyEntities = new CombatRemoveEmptyEntitiesEffect(occursAt, _sub, _outpost, this);
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            _shield.ForwardAction(timeMachine);
            _drillerCombatDrillers.ForwardAction(timeMachine);
            _combatSpecialistCapture.ForwardAction(timeMachine);
            _combatOwnershipTransfer.ForwardAction(timeMachine);
            _combatRemoveEmptyEntities.ForwardAction(timeMachine);
            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            _combatRemoveEmptyEntities.BackwardAction(timeMachine);
            _combatOwnershipTransfer.BackwardAction(timeMachine);
            _combatSpecialistCapture.BackwardAction(timeMachine);
            _drillerCombatDrillers.BackwardAction(timeMachine);
            _shield.BackwardAction(timeMachine);
            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }
    }
}


text:
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents.CombatResolve
{
    public abstract class CombatResolution : PositionalGameEvent
    {
        public IEntity Winner { get; set; }
        public IEntity Loser { get; set; }
        public bool IsTie { get; set; } = false;
        protected CombatType _combatType;

        protected CombatResolution(
            GameTick occursAt,
            CombatType combatType,
            IEntity expectedWinLocation
        ) : base(occursAt, Priority.COMBAT_RESOLVE, expectedWinLocation)
        {
            _combatType = combatType;
        }
    }
}


text:
using System.Collections.Generic;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Positions;
using Subterfuge.Remake.Core.Entities.Specialists;
using Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents.CombatResolve;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class SubToSubResolution: CombatResolution
    {
        private Sub _sub1;
        private Sub _sub2;

        private readonly CombatDrillersEffect _drillerCombatDrillers;
        private readonly CombatShieldEffect _shield;
        private readonly CombatSpecialistCaptureEffect _combatSpecialistCapture;
        private readonly CombatRemoveEmptyEntitiesEffect _combatRemoveEmptyEntities;

        public SubToSubResolution(
            GameTick occursAt,
            IEntity combatant1,
            IEntity combatant2
        ) : base(occursAt, CombatType.SUB_TO_SUB, combatant1)
        {
            _sub1 = combatant1 as Sub;
            _sub2 = combatant2 as Sub;
            _drillerCombatDrillers = new CombatDrillersEffect(occursAt, _sub1, _sub2);
            _shield = new CombatShieldEffect(occursAt, _sub1, _sub2);
            _combatSpecialistCapture = new CombatSpecialistCaptureEffect(occursAt, _sub1, _sub2);
            _combatRemoveEmptyEntities = new CombatRemoveEmptyEntitiesEffect(occursAt, _sub1, _sub2, this);
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            _shield.ForwardAction(timeMachine);
            _drillerCombatDrillers.ForwardAction(timeMachine);
            _combatSpecialistCapture.ForwardAction(timeMachine);
            _combatRemoveEmptyEntities.ForwardAction(timeMachine);
            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            _combatRemoveEmptyEntities.BackwardAction(timeMachine);
            _combatSpecialistCapture.BackwardAction(timeMachine);
            _drillerCombatDrillers.BackwardAction(timeMachine);
            _shield.BackwardAction(timeMachine);
            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }
    }
}


text:
using System;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class CombatShieldEffect : PositionalGameEvent
    {
        private readonly IEntity _combatant1;
        private readonly IEntity _combatant2;

        private int _preCombatShields1;
        private int _preCombatShields2;
        private int _preCombatDrillers1;
        private int _preCombatDrillers2;

        public CombatShieldEffect(
            GameTick occursAt,
            IEntity combatant1,
            IEntity combatant2
        ) : base(occursAt, Priority.SHIELD_COMBAT, combatant1)
        {
            _combatant1 = combatant1;
            _combatant2 = combatant2;
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            _preCombatDrillers1 = _combatant1.GetComponent<DrillerCarrier>().GetDrillerCount();
            _preCombatDrillers2 = _combatant2.GetComponent<DrillerCarrier>().GetDrillerCount();
            _preCombatShields1 = _combatant1.GetComponent<ShieldManager>().GetShields();
            _preCombatShields2 = _combatant2.GetComponent<ShieldManager>().GetShields();

            var shieldDamage1 = Math.Min(_preCombatShields1, _preCombatDrillers2);
            var shieldDamage2 = Math.Min(_preCombatShields2, _preCombatDrillers1);

            // Effect shields and driller counts
            _combatant2.GetComponent<DrillerCarrier>().AlterDrillers(shieldDamage1 * -1);
            _combatant1.GetComponent<ShieldManager>().AlterShields(shieldDamage1 * -1);

            _combatant1.GetComponent<DrillerCarrier>().AlterDrillers(shieldDamage2 * -1);
            _combatant2.GetComponent<ShieldManager>().AlterShields(shieldDamage2 * -1);
            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            _combatant1.GetComponent<DrillerCarrier>().SetDrillerCount(_preCombatDrillers1);
            _combatant2.GetComponent<DrillerCarrier>().SetDrillerCount(_preCombatDrillers2);
            _combatant1.GetComponent<ShieldManager>().SetShields(_preCombatShields1);
            _combatant2.GetComponent<ShieldManager>().SetShields(_preCombatShields2);
            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }
    }
}


text:
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class CombatDrillersEffect : PositionalGameEvent
    {
        private readonly IEntity _combatant1;
        private readonly IEntity _combatant2;

        private int _preCombatDrillers1;
        private int _preCombatDrillers2;

        public CombatDrillersEffect(
            GameTick occursAt,
            IEntity combatant1,
            IEntity combatant2
        ) : base(occursAt, Priority.DRILLER_COMBAT, combatant1)
        {
            _combatant1 = combatant1;
            _combatant2 = combatant2;
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            _preCombatDrillers1 = _combatant1.GetComponent<DrillerCarrier>().GetDrillerCount();
            _preCombatDrillers2 = _combatant2.GetComponent<DrillerCarrier>().GetDrillerCount();
            _combatant1.GetComponent<DrillerCarrier>().AlterDrillers(_preCombatDrillers2 * -1);
            _combatant2.GetComponent<DrillerCarrier>().AlterDrillers(_preCombatDrillers1 * -1);
            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            _combatant1.GetComponent<DrillerCarrier>().SetDrillerCount(_preCombatDrillers1);
            _combatant2.GetComponent<DrillerCarrier>().SetDrillerCount(_preCombatDrillers2);
            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }
    }
}


text:
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents.CombatResolve;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class CombatRemoveEmptyEntitiesEffect : PositionalGameEvent
    {
        private readonly IEntity _combatant1;
        private readonly IEntity _combatant2;
        private readonly CombatResolution _combatResolution;

        public CombatRemoveEmptyEntitiesEffect(
            GameTick occursAt,
            IEntity combatant1,
            IEntity combatant2,
            CombatResolution combatResolution
        ) : base(occursAt, Priority.COMBAT_RESOLVE, combatant1)
        {
            _combatant1 = combatant1;
            _combatant2 = combatant2;
            _combatResolution = combatResolution;
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            if (_combatant1.GetComponent<DrillerCarrier>().GetDrillerCount() <= 0 &&
                _combatant2.GetComponent<DrillerCarrier>().GetDrillerCount() <= 0)
            {
                // Tie.
                _combatResolution.IsTie = true;
            }
            else
            {
                if (_combatant1 is Sub sub1 && sub1.GetComponent<DrillerCarrier>().GetDrillerCount() <= 0)
                {
                    timeMachine.GetState().RemoveSub(sub1);
                    _combatResolution.Winner = _combatant2;
                    _combatResolution.Loser = _combatant1;
                }
                if (_combatant2 is Sub sub2 && sub2.GetComponent<DrillerCarrier>().GetDrillerCount() <= 0)
                {
                    timeMachine.GetState().RemoveSub(sub2);
                    _combatResolution.Winner = _combatant1;
                    _combatResolution.Loser = _combatant2;
                }
            }

            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            if (_combatant1 is Sub sub1 && !timeMachine.GetState().SubExists(sub1))
            {
                timeMachine.GetState().AddSub(sub1);
            }
            if (_combatant2 is Sub sub2 && !timeMachine.GetState().SubExists(sub2))
            {
                timeMachine.GetState().AddSub(sub2);
            }

            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }
    }
}


text:
using System.Collections.Generic;
using System.Linq;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.Entities.Positions;
using Subterfuge.Remake.Core.Entities.Specialists;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Players;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class CombatOwnershipTransferEffect : PositionalGameEvent
    {
        // Ownership transfer only applies to sub-to-outpost combat.
        private readonly Sub _sub;
        private readonly Outpost _outpost;

        private IEntity _winner;
        private readonly CombatType _combatType;

        private Player _initialOwner;
        private List<Specialist> specialistsTransferred;
        private int drillersTransferred;

        public CombatOwnershipTransferEffect(
            GameTick occursAt,
            IEntity combatant1,
            IEntity combatant2
        ) : base(occursAt, Priority.COMBAT_RESOLVE, combatant1)
        {
            _combatType = DetermineCombatType(combatant1, combatant2);

            if (_combatType == CombatType.SUB_TO_OUTPOST)
            {
                _sub = (Sub)(combatant1 is Sub ? combatant1 : combatant2);
                _outpost = (Outpost)(combatant1 is Outpost ? combatant1 : combatant2);
            }
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            if (_combatType == CombatType.SUB_TO_OUTPOST)
            {
                _winner = GetWinner();
                if (_winner is Sub)
                {
                    // Swap ownership
                    _initialOwner = _outpost.GetComponent<DrillerCarrier>().GetOwner();
                    _outpost.GetComponent<DrillerCarrier>().SetOwner(_winner.GetComponent<DrillerCarrier>().GetOwner());

                    // Transfer drillers
                    drillersTransferred = _sub.GetComponent<DrillerCarrier>().GetDrillerCount();
                    _outpost.GetComponent<DrillerCarrier>().AlterDrillers(drillersTransferred);
                    _sub.GetComponent<DrillerCarrier>().AlterDrillers(drillersTransferred * -1);

                    // Transfer specialists
                    specialistsTransferred = _sub.GetComponent<SpecialistManager>().GetSpecialists();
                    _sub.GetComponent<SpecialistManager>()
                        .TransferSpecialistsTo(_outpost.GetComponent<SpecialistManager>(), timeMachine);
                }
                else
                {
                    // Defender won.

                    // Transfer specialists
                    specialistsTransferred = _sub.GetComponent<SpecialistManager>().GetSpecialists();
                    _sub.GetComponent<SpecialistManager>()
                        .TransferSpecialistsTo(_outpost.GetComponent<SpecialistManager>(), timeMachine);
                }
            }

            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            if (_combatType == CombatType.SUB_TO_OUTPOST)
            {
                if (_winner is Sub)
                {
                    // Put specialists back on the sub.
                    _outpost.GetComponent<SpecialistManager>()
                        .TransferSpecialistsById(_sub.GetComponent<SpecialistManager>(), specialistsTransferred.Select(it => it.GetId()).ToList(), timeMachine);

                    // Put drillers back on the sub.
                    _sub.GetComponent<DrillerCarrier>().AlterDrillers(drillersTransferred);
                    _outpost.GetComponent<DrillerCarrier>().AlterDrillers(drillersTransferred * -1);

                    // Restore ownership.
                    _outpost.GetComponent<DrillerCarrier>().SetOwner(_initialOwner);
                }
                else
                {
                    // Put specialists back on the sub.
                    _outpost.GetComponent<SpecialistManager>()
                        .TransferSpecialistsById(_sub.GetComponent<SpecialistManager>(), specialistsTransferred.Select(it => it.GetId()).ToList(), timeMachine);
                }
            }

            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }

        private IEntity? GetWinner()
        {
            var subDrillerCount = _sub.GetComponent<DrillerCarrier>().GetDrillerCount();
            var outpostDrillerCount = _outpost.GetComponent<DrillerCarrier>().GetDrillerCount();
            if (subDrillerCount <= 0 && outpostDrillerCount <= 0)
            {
                // Attacker wins in the case of a tie
                return _sub;
            }

            if (subDrillerCount <= 0)
            {
                return _outpost;
            }

            if (outpostDrillerCount <= 0)
            {
                return _sub;
            }

            return _sub;
        }

        private CombatType DetermineCombatType(IEntity _combatant1, IEntity _combatant2)
        {
            if (Equals(_combatant1.GetComponent<DrillerCarrier>().GetOwner(), _combatant2.GetComponent<DrillerCarrier>().GetOwner()))
            {
                return CombatType.FRIENDLY;
            }

            if (_combatant1 is Sub && _combatant2 is Sub)
            {
                return CombatType.SUB_TO_SUB;
            }

            return CombatType.SUB_TO_OUTPOST;
        }
    }
}


text:
using System.Collections.Generic;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.Entities.Specialists;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class CombatSpecialistCaptureEffect : PositionalGameEvent
    {
        public readonly IEntity Combatant1;
        public readonly IEntity Combatant2;

        private List<Specialist> combatant1Specialists;
        private List<Specialist> combatant2Specialists;
        private IEntity? winner;

        public CombatSpecialistCaptureEffect(
            GameTick occursAt,
            IEntity combatant1,
            IEntity combatant2
        ) : base(occursAt, Priority.COMBAT_RESOLVE, combatant1)
        {
            Combatant1 = combatant1;
            Combatant2 = combatant2;
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            combatant1Specialists = Combatant1.GetComponent<SpecialistManager>().GetSpecialists();
            combatant2Specialists = Combatant2.GetComponent<SpecialistManager>().GetSpecialists();

            winner = GetWinner();
            if (winner != null)
            {
                var loser = winner == Combatant1 ? Combatant2 : Combatant1;
                loser.GetComponent<SpecialistManager>().CaptureAllForward(timeMachine, loser);
            }
            else
            {
                // If no winner, all specialists die.
                Combatant1.GetComponent<SpecialistManager>().KillAll();
                Combatant2.GetComponent<SpecialistManager>().KillAll();
            }

            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            if (winner != null)
            {
                var loser = winner == Combatant1 ? Combatant2 : Combatant1;
                loser.GetComponent<SpecialistManager>().UncaptureAll(timeMachine, loser);
            }
            else
            {
                Combatant1.GetComponent<SpecialistManager>().ReviveAll(combatant1Specialists);
                Combatant2.GetComponent<SpecialistManager>().ReviveAll(combatant2Specialists);
            }

            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }

        private IEntity? GetWinner()
        {
            var combatantOneDrillerCount = Combatant1.GetComponent<DrillerCarrier>().GetDrillerCount();
            var combatantTwoDrillerCount = Combatant2.GetComponent<DrillerCarrier>().GetDrillerCount();
            if (combatantOneDrillerCount <= 0 && combatantTwoDrillerCount <= 0)
            {
                return null;
            }

            if (combatantOneDrillerCount <= 0)
            {
                return Combatant2;
            }

            return combatantTwoDrillerCount <= 0 ? Combatant1 : null;
        }
    }
}


text:
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class RedirectEntityEffect : PositionalGameEvent
    {
        private IEntity _enemy;

        private IEntity _originalDestination;

        public RedirectEntityEffect(
            GameTick occursAt,
            IEntity enemy
        ) : base(occursAt, Priority.SPECIALIST_SUB_REDIRECT, enemy)
        {
            _enemy = enemy;
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            _originalDestination = _enemy.GetComponent<PositionManager>().GetDestination();
            var _source = _enemy.GetComponent<PositionManager>().GetSource();
            _enemy.GetComponent<PositionManager>().SetDestination(_source);
            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            _enemy.GetComponent<PositionManager>().SetDestination(_originalDestination);
            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }
    }
}


text:
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class SlowTargetEffect : PositionalGameEvent
    {

        private IEntity _enemy;
        private float _slowBy;

        public SlowTargetEffect(
            GameTick occursAt,
            IEntity enemy,
            float slowBy
        ) : base(occursAt, Priority.SPECIALIST_SLOW_EFFECT, enemy)
        {
            _enemy = enemy;
            _slowBy = slowBy;
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            _enemy.GetComponent<SpeedManager>().DecreaseSpeed(_slowBy);
            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            _enemy.GetComponent<SpeedManager>().IncreaseSpeed(_slowBy);
            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }
    }
}


text:
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Players.Currency;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class GlobalCurrencyProductionEvent : GameEvent
    {
        public GlobalCurrencyProductionEvent(
            GameTick occursAt
        ) : base(occursAt, Priority.RESOURCE_PRODUCTION)
        {
        }

        public static void SpawnNewCurrencyEvent(TimeMachine timeMachine)
        {
            // Create another production event in the future.
            var ticksPerCurrencyGain = (int)(1440 / GameTick.MinutesPerTick);
            var newCurrencyEvent = new GlobalCurrencyProductionEvent(timeMachine.GetCurrentTick().Advance(ticksPerCurrencyGain));
            timeMachine.AddEvent(newCurrencyEvent);
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            timeMachine
                .GetState()
                .GetPlayers()
                .ForEach(player =>
                {
                    player.CurrencyManager.AddCurrency(CurrencyType.Specialist, 1);
                });

            // Create another production event in the future.
            SpawnNewCurrencyEvent(timeMachine);

            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            timeMachine
                .GetState()
                .GetPlayers()
                .ForEach(player =>
                {
                    player.CurrencyManager.AddCurrency(CurrencyType.Specialist, -1);
                });
            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }

        public override string GetEventId()
        {
            return OccursAt.GetTick().ToString();
        }

        public override bool Equals(object other)
        {
            GlobalCurrencyProductionEvent asEvent = other as GlobalCurrencyProductionEvent;
            if (asEvent == null)
                return false;

            return asEvent.OccursAt == this.OccursAt;
        }

        public override int GetHashCode()
        {
            return OccursAt.GetHashCode();
        }
    }
}


text:
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Players;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class RegenerateShieldPostCombatEffect : PositionalGameEvent
    {
        private Player _expectedWinner;
        private CombatEvent _combatEvent;
        private float _percentRegen;

        private int shieldsBeforeRestore;

        public RegenerateShieldPostCombatEffect(
            CombatEvent combatEvent,
            Player expectedPlayerToWin,
            float percentageToRegenerate
        ) : base(combatEvent.OccursAt, Priority.POST_COMBAT, combatEvent._combatant1)
        {
            _combatEvent = combatEvent;
            _expectedWinner = _expectedWinner;
            _percentRegen = percentageToRegenerate;
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            var winningLocation = _combatEvent.GetCombatResolution().Winner;
            if (Equals(winningLocation.GetComponent<DrillerCarrier>().GetOwner(), _expectedWinner))
            {
                var maxShields = winningLocation.GetComponent<ShieldManager>().GetShieldCapacity();
                winningLocation.GetComponent<ShieldManager>().SetShields((int)(maxShields * _percentRegen));
            }

            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            var winningLocation = _combatEvent.GetCombatResolution().Winner;
            if (Equals(winningLocation.GetComponent<DrillerCarrier>().GetOwner(), _expectedWinner))
            {
                winningLocation.GetComponent<ShieldManager>().SetShields(shieldsBeforeRestore);
            }

            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }
    }
}


text:
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class NeutralizeSpecialistEffects : PositionalGameEvent
    {

        private IEntity _combatant1;
        private IEntity _combatant2;
        public NeutralizeSpecialistEffects(
            GameTick occursAt,
            IEntity source
        ) : base(occursAt, Priority.SPECIALIST_NEUTRALIZE_SPECIALIST_EFFECTS, source)
        {
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            throw new System.NotImplementedException();
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            throw new System.NotImplementedException();
        }

        public override bool WasEventSuccessful()
        {
            throw new System.NotImplementedException();
        }
    }
}


text:
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class StealDrillerEffect : PositionalGameEvent
    {

        private IEntity _friendly;
        private IEntity _stealFrom;
        public StealDrillerEffect(
            GameTick occursAt,
            IEntity friendly,
            IEntity stealFrom
        ) : base(occursAt, Priority.SPECIALIST_STEAL_EFFECT, friendly)
        {
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            throw new System.NotImplementedException();
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            throw new System.NotImplementedException();
        }

        public override bool WasEventSuccessful()
        {
            throw new System.NotImplementedException();
        }
    }
}


text:
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class AlterDrillerEffect : PositionalGameEvent
    {
        private IEntity _friendly;
        private IEntity _enemy;

        private int _friendlyDrillerDelta;
        private int _enemyDrillerDelta;

        public AlterDrillerEffect(
            CombatEvent combatEvent,
            IEntity friendly,
            int friendlyDrillerDelta,
            int enemyDrillerDelta
        ) : base(combatEvent.OccursAt, Priority.SPECIALIST_DRILLER_EFFECT, friendly)
        {
            _friendly = friendly;
            _enemy = combatEvent._combatant1 == _friendly ? combatEvent._combatant2 : combatEvent._combatant1;
            _friendlyDrillerDelta = friendlyDrillerDelta;
            _enemyDrillerDelta = enemyDrillerDelta;
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            _friendlyDrillerDelta = _friendly.GetComponent<DrillerCarrier>().AlterDrillers(_friendlyDrillerDelta);
            _enemyDrillerDelta = _enemy.GetComponent<DrillerCarrier>().AlterDrillers(_enemyDrillerDelta);
            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            _friendlyDrillerDelta = _friendly.GetComponent<DrillerCarrier>().AlterDrillers(_friendlyDrillerDelta * -1);
            _enemyDrillerDelta = _enemy.GetComponent<DrillerCarrier>().AlterDrillers(_enemyDrillerDelta * -1);
            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }
    }
}


text:
using System.Collections.Generic;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.Entities.Positions;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class EntityExplodeEffect : PositionalGameEvent
    {

        private IEntity _entityExploding;
        private GameState _state;

        private List<IEntity> entitiesDestroyed;

        public EntityExplodeEffect(
            GameTick occursAt,
            IEntity entityExploding,
            GameState currentState
        ) : base(occursAt, Priority.SPECIALIST_EXPLODE, entityExploding)
        {
            _entityExploding = entityExploding;
            _state = currentState;
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            entitiesDestroyed = _state.EntitesInRange(Constants.BaseSubVisionRadius,
                _entityExploding.GetComponent<PositionManager>().CurrentLocation);

            // Remove all of the entities from the game state.
            foreach(IEntity e in entitiesDestroyed)
            {
                if (e is Sub)
                {
                    timeMachine.GetState().RemoveSub(e as Sub);
                }
                else
                {
                    e.GetComponent<DrillerCarrier>().Destroy();
                }
            }

            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            foreach(IEntity e in entitiesDestroyed)
            {
                if (e is Sub)
                {
                    timeMachine.GetState().AddSub(e as Sub);
                }
                else
                {
                    // TODO: This is not perfect... Need to ensure that we can "redo" a destroy event somehow.
                    e.GetComponent<DrillerCarrier>().UndoDestroy(10);
                }
            }

            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }
    }
}


text:
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class AlterShieldEffect : PositionalGameEvent
    {
        private IEntity _expectedWinLocation;

        private int _shieldDelta;
        public AlterShieldEffect(
            CombatEvent combatEvent,
            IEntity expectedWinLocation,
            int shieldDelta
        ) : base(combatEvent.OccursAt, Priority.SPECIALIST_SHIELD_EFFECT, expectedWinLocation)
        {
            _expectedWinLocation = expectedWinLocation;
            _shieldDelta = shieldDelta;
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            _shieldDelta = _expectedWinLocation.GetComponent<ShieldManager>().AlterShields(_shieldDelta);
            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            _shieldDelta = _expectedWinLocation.GetComponent<ShieldManager>().AlterShields(-1 * _shieldDelta);
            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }
    }
}


text:
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class DemoteSpecialistsEffect : PositionalGameEvent
    {

        private IEntity _combatant1;
        public DemoteSpecialistsEffect(
            GameTick occursAt,
            IEntity demoteSpecialistsAtEntity
        ) : base(occursAt, Priority.SPECIALIST_DEMOTE_EFFECT, demoteSpecialistsAtEntity)
        {
            _combatant1 = demoteSpecialistsAtEntity;
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            throw new System.NotImplementedException();
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            throw new System.NotImplementedException();
        }

        public override bool WasEventSuccessful()
        {
            throw new System.NotImplementedException();
        }
    }
}


text:
using System.Collections.Generic;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.Entities.Specialists;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class KillSpecialistsEffect : PositionalGameEvent
    {
        private IEntity _killSpecialistsAt;

        public List<Specialist> killedSpecialists = new List<Specialist>();

        public KillSpecialistsEffect(
            GameTick occursAt,
            IEntity killSpecialistsAt
        ) : base(occursAt, Priority.SPECIALIST_KILL_SPECIALISTS, killSpecialistsAt)
        {
            _killSpecialistsAt = killSpecialistsAt;
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            killedSpecialists = _killSpecialistsAt.GetComponent<SpecialistManager>().GetSpecialists();
            _killSpecialistsAt.GetComponent<SpecialistManager>().KillAll();
            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            _killSpecialistsAt.GetComponent<SpecialistManager>().ReviveAll(killedSpecialists);
            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }
    }
}


text:
using System;
using Microsoft.DotNet.PlatformAbstractions;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class ResourceProductionEvent : PositionalGameEvent
    {
        public readonly IEntity ProductionLocation;
        public bool _ignoresCapacity = false;
        public ProducedResourceType ResourceType { get; }
        public int ValueProduced;
        private ResourceProducer _producerReference;

        public ResourceProductionEvent(
            GameTick occursAt,
            IEntity locationProducedAt,
            ProducedResourceType producedType,
            int valueProduced,
            bool ignoresCapacity
        ) : base(occursAt, Priority.RESOURCE_PRODUCTION, locationProducedAt)
        {
            ProductionLocation = locationProducedAt;
            ResourceType = producedType;
            ValueProduced = valueProduced;
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            switch (ResourceType)
            {
                case ProducedResourceType.Driller:
                    // Ensure unowned outposts do not produce drillers
                    if (ProductionLocation.GetComponent<DrillerCarrier>().GetOwner() == null)
                    {
                        ValueProduced = 0;
                    }
                    else
                    {
                        ValueProduced = ProductionLocation.GetComponent<DrillerCarrier>().AlterDrillers(GetNextProductionAmount(timeMachine.GetState()));
                    }
                    break;
                case ProducedResourceType.Neptunium:
                    ValueProduced = ProductionLocation.GetComponent<DrillerCarrier>().GetOwner().AlterNeptunium(GetNextProductionAmount(timeMachine.GetState()));
                    break;
                case ProducedResourceType.Shield:
                    // Ensure unowned outposts do not produce shields
                    if (ProductionLocation.GetComponent<DrillerCarrier>().GetOwner() == null)
                    {
                        ValueProduced = 0;
                    }
                    else
                    {
                        ValueProduced = ProductionLocation.GetComponent<ShieldManager>().AlterShields(GetNextProductionAmount(timeMachine.GetState()));
                    }
                    break;
            }

            return true;
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            switch (ResourceType)
            {
                case ProducedResourceType.Driller:
                    ProductionLocation.GetComponent<DrillerCarrier>().AlterDrillers(-1 * ValueProduced);
                    ProductionLocation.GetComponent<DrillerProducer>().Producer.SetNextProductionTick(timeMachine.GetCurrentTick());
                    break;
                case ProducedResourceType.Neptunium:
                    ProductionLocation.GetComponent<DrillerCarrier>().GetOwner().AlterNeptunium(-1 * ValueProduced);
                    ProductionLocation.GetComponent<NeptuniumProducer>().Producer.SetNextProductionTick(timeMachine.GetCurrentTick());
                    break;
                case ProducedResourceType.Shield:
                    ProductionLocation.GetComponent<ShieldManager>().AlterShields(-1 * ValueProduced);
                    ProductionLocation.GetComponent<ShieldProducer>().Producer.SetNextProductionTick(timeMachine.GetCurrentTick());
                    break;
            }
            return true;
        }

        public override bool WasEventSuccessful()
        {
            return true;
        }

        public int GetNextProductionAmount(GameState state)
        {
            var owner = ProductionLocation.GetComponent<DrillerCarrier>().GetOwner();
            if (ProductionLocation.GetComponent<DrillerCarrier>().IsDestroyed() || (owner != null && owner.IsEliminated()))
            {
                return 0;
            }

            switch (ResourceType)
            {
                case ProducedResourceType.Driller:
                    var extraDrillerCapacity = state.GetExtraDrillerCapacity(owner);

                    if (!_ignoresCapacity)
                    {
                        // Get the min of the extra capacity vs. production count.
                        return Math.Min(Math.Max(0, extraDrillerCapacity), ValueProduced);
                    }

                    return ValueProduced;
                case ProducedResourceType.Neptunium:
                    return state.GetPlayerOutposts(ProductionLocation.GetComponent<DrillerCarrier>().GetOwner()).Count;
                case ProducedResourceType.Shield:
                    return ValueProduced;
                default:
                    return ValueProduced;
            }
        }

        public override bool Equals(object other)
        {
            ResourceProductionEvent asEvent = other as ResourceProductionEvent;
            if (asEvent == null)
                return false;

            return asEvent.OccursAt == this.OccursAt &&
                   asEvent.Priority == this.Priority &&
                   asEvent.ProductionLocation == this.ProductionLocation &&
                   asEvent.ResourceType == this.ResourceType;
        }

        public override int GetHashCode()
        {
            var hashBuilder = new HashCodeCombiner();
            hashBuilder.Add(OccursAt);
            hashBuilder.Add(Priority);
            hashBuilder.Add(ProductionLocation);
            hashBuilder.Add(ResourceType);
            return hashBuilder.GetHashCode();
        }
    }

    public enum ProducedResourceType
    {
        Unknown = 0,
        Driller = 1,
        Shield = 2,
        Neptunium = 3,
    }
}


text:
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents
{
    public class SwapSpecialistEffect : PositionalGameEvent
    {
        private IEntity _combatant1;
        private IEntity _combatant2;
        public SwapSpecialistEffect(
            GameTick occursAt,
            IEntity entityOne,
            IEntity entityTwo
        ) : base(occursAt, Priority.SPECIALIST_SWAP_SPECIALISTS_EFFECT, entityOne)
        {
            _combatant1 = entityOne;
            _combatant2 = entityTwo;
        }

        public override bool ForwardAction(TimeMachine timeMachine)
        {
            throw new System.NotImplementedException();
        }

        public override bool BackwardAction(TimeMachine timeMachine)
        {
            throw new System.NotImplementedException();
        }

        public override bool WasEventSuccessful()
        {
            throw new System.NotImplementedException();
        }
    }
}


text:
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;
using Subterfuge.Remake.Core.Entities.Positions;
using Subterfuge.Remake.Core.Entities.Specialists;

namespace Subterfuge.Remake.Core.GameEvents.Validators
{
    /// <summary>
    /// Validation object to ensure that objects exists and are properly created.
    /// To prevent hacks
    /// </summary>
    public class Validator
    {
        /// <summary>
        /// Validates an ICombatable
        /// </summary>
        /// <param name="state">The gamestate</param>
        /// <param name="combatable">The ICombatable to validate</param>
        /// <returns></returns>
        public static bool ValidateICombatable(GameState state, IEntity combatable)
        {
            if(combatable is Outpost)
            {
                return ValidateOutpost(state, (Outpost)combatable);
            } else if (combatable is Sub)
            {
                return ValidateSub(state, (Sub)combatable);
            }
            return false;
        }

        /// <summary>
        /// Validates a sub
        /// </summary>
        /// <param name="state">The game state</param>
        /// <param name="sub">The sub to validate</param>
        /// <returns>If the sub is valid</returns>
        public static bool ValidateSub(GameState state, Sub sub)
        {
            if (sub == null)
                return false;
            if (!state.SubExists(sub))
                return false;
            if (sub.GetComponent<DrillerCarrier>().GetDrillerCount() < 0)
                return false;
            if (sub.GetComponent<SpecialistManager>() == null)
                return false;
            if (sub.GetComponent<SpecialistManager>().GetUncapturedSpecialistCount() < 0)
                return false;
            if (sub.GetComponent<SpecialistManager>().GetUncapturedSpecialistCount() > sub.GetComponent<SpecialistManager>().GetCapacity())
                return false;
            if (sub.GetComponent<DrillerCarrier>().GetOwner() != null && !state.PlayerExists(sub.GetComponent<DrillerCarrier>().GetOwner()))
                return false;
            return true;
        }

        /// <summary>
        /// Validates an outpost
        /// </summary>
        /// <param name="state">The game state</param>
        /// <param name="outpost">The outpost to validate</param>
        /// <returns>If the outpost is valid</returns>
        public static bool ValidateOutpost(GameState state, Outpost outpost)
        {
            if (outpost == null)
                return false;
            if (!state.OutpostExists(outpost))
                return false;
            if (outpost.GetComponent<DrillerCarrier>().GetDrillerCount() < 0)
                return false;
            if (outpost.GetComponent<SpecialistManager>() == null)
                return false;
            if (outpost.GetComponent<SpecialistManager>().GetUncapturedSpecialistCount() < 0)
                return false;
            if (outpost.GetComponent<SpecialistManager>().GetUncapturedSpecialistCount() > outpost.GetComponent<SpecialistManager>().GetCapacity())
                return false;
            if (outpost.GetComponent<DrillerCarrier>().GetOwner() != null && !state.PlayerExists(outpost.GetComponent<DrillerCarrier>().GetOwner()))
                return false;
            return true;
        }

        /// <summary>
        /// Validates a specialist
        /// </summary>
        /// <param name="specialist">The specialist to validate</param>
        /// <returns>If the specialist is valid</returns>
        public static bool ValidateSpecialist(Specialist specialist)
        {
            if (specialist.GetOwner() == null)
                return false;
            return true;
        }

    }
}


text:
using System;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.EventPublishers
{
    public class DirectionalEventArgs : EventArgs
    {
        public TimeMachineDirection Direction { get; set; }
        public TimeMachine TimeMachine { get; set; }
    }

    public enum TimeMachineDirection
    {
        FORWARD = 1,
        REVERSE = 2,
    }
}


text:
using System;
using System.Collections.Generic;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Positions;
using Subterfuge.Remake.Core.Entities.Specialists;

namespace Subterfuge.Remake.Core.GameEvents.EventPublishers
{
    public interface ISpecialistEventPublisher
    {
        event EventHandler<OnSpecialistHireEventArgs> OnSpecialistHire;
        event EventHandler<OnSpecialistsCapturedEventArgs> OnSpecialistCapture;
        event EventHandler<OnSpecialistPromotionEventArgs> OnSpecialistPromotion;
        event EventHandler<OnSpecialistTransferEventArgs> OnSpecialistTransfer;
    }

    public class OnSpecialistHireEventArgs : DirectionalEventArgs
    {
        public Specialist HiredSpecialist { get; set; }
        public IEntity HireLocation { get; set; }
    }

    public class OnSpecialistsCapturedEventArgs: DirectionalEventArgs
    {
        public IEntity Location { get; set; }
    }

    public class OnSpecialistPromotionEventArgs: DirectionalEventArgs
    {
        public Specialist PromotedTo { get; set; }
        public IEntity Location { get; set; }
    }

    public class OnSpecialistTransferEventArgs: DirectionalEventArgs
    {
        public List<Specialist> specialist { get; set; }
        public IEntity AddedTo { get; set; }
        public IEntity? RemovedFrom { get; set; }
    }
}


text:
using System;
using Subterfuge.Remake.Core.Entities;

namespace Subterfuge.Remake.Core.GameEvents.EventPublishers
{
    public interface ICourseChangeEventPublisher
    {
        event EventHandler<OnCourseChangeEventArgs> OnCourseChange;
    }

    public class OnCourseChangeEventArgs: DirectionalEventArgs
    {
        public Sub Sub { get; set; }
        public IEntity OriginalDestination { get; set; }
        public IEntity NewDestination { get; set; }
    }

}


text:
using System;
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.EventPublishers
{
    public interface ITickEventPublisher
    {
        event EventHandler<OnTickEventArgs> OnTick;
        event EventHandler<OnGameEventTriggeredEventArgs> OnGameEvent;
    }

    public class OnTickEventArgs: DirectionalEventArgs
    {
        public GameTick CurrentTick { get; set; }
        public GameState CurrentState { get; set; }
    }

    public class OnGameEventTriggeredEventArgs: DirectionalEventArgs
    {
        public GameEvent GameEvent { get; set; }
        public GameTick CurrentTick { get; set; }
        public GameState CurrentState { get; set; }
    }
}


text:
using System;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.EventPublishers
{
    public interface IResourceProductionEventPublisher
    {
        event EventHandler<ProductionEventArgs> OnResourceProduced;
    }

    public class ProductionEventArgs: DirectionalEventArgs
    {
        public GameTick NextProduction { get; set; }
        public GameTick TickProducedAt { get; set; }
        public ResourceProductionEvent ProductionEvent { get; set; }
        public ProducedResourceType ProducedResourceType { get; set; }
    }
}


text:
using System;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.GameEvents.Combat;
using Subterfuge.Remake.Core.GameEvents.Combat.CombatEvents.CombatResolve;
using Subterfuge.Remake.Core.Players;

namespace Subterfuge.Remake.Core.GameEvents.EventPublishers
{
    public interface ICombatEventPublisher
    {
        event EventHandler<OnRegisterCombatEventArgs> OnRegisterCombatEffects;
        event EventHandler<OnLocationTargetedEventArgs> OnLocationTargeted;
    }

    public class OnRegisterCombatEventArgs: DirectionalEventArgs
    {
        public GameState CurrentState { get; set; }
        public CombatEvent CombatEvent { get; set; }
    }

    public class OnLocationTargetedEventArgs: DirectionalEventArgs
    {
        public IEntity TargetedBy { get; set; }
        public IEntity Destination { get; set; }
    }
}


text:
using System;
using Subterfuge.Remake.Core.Entities.Components;

namespace Subterfuge.Remake.Core.GameEvents.EventPublishers
{
    public interface IShieldEventPublisher
    {
        event EventHandler<OnToggleShieldEventArgs> OnToggleShield;
        event EventHandler<OnShieldCapacityChangeEventArgs> OnShieldCapacityChange;
        event EventHandler<OnShieldValueChangeEventArgs> OnShieldValueChange;
    }

    public class OnToggleShieldEventArgs : DirectionalEventArgs
    {
        public ShieldManager ShieldManager { get; set; }
        public bool isEnabled { get; set; }
    }

    public class OnShieldCapacityChangeEventArgs : DirectionalEventArgs
    {
        public int CapacityDelta { get; set; }
        public ShieldManager ShieldManager { get; set; }
    }

    public class OnShieldValueChangeEventArgs : DirectionalEventArgs
    {
        public int ShieldDelta { get; set; }
        public ShieldManager ShieldManager { get; set; }
    }
}


text:
using Subterfuge.Remake.Core.GameEvents.Base;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.EventPublishers
{
    public interface IReversibleEventHandler
    {
        bool ForwardEvent(TimeMachine timeMachine, GameEvent gameEvent);
        bool BackwardsEvent(TimeMachine timeMachine, GameEvent gameEvent);
    }
}


text:
using System;
using Subterfuge.Remake.Core.Entities.Components;

namespace Subterfuge.Remake.Core.GameEvents.EventPublishers
{
    public interface ISpeedEventPublisher
    {
        event EventHandler<OnSpeedChangedEventArgs> OnSpeedChanged;
    }

    public class OnSpeedChangedEventArgs : DirectionalEventArgs
    {
        public float PreviousSpeed { get; set; }
        public float NewSpeed { get; set; }
        public SpeedManager SpeedManager { get; set; }
    }
}


text:
using System;
using Subterfuge.Remake.Core.Players;

namespace Subterfuge.Remake.Core.GameEvents.EventPublishers
{
    public class ICurrencyEventPublisher
    {
        private event EventHandler<GainCurrencyEventArgs> OnGainCurrency;
        private event EventHandler<SpendCurrencyEventArgs> OnSpendCurrency;
    }

    public class GainCurrencyEventArgs: DirectionalEventArgs
    {
        public Player PlayerGainingCurrency { get; set; }
        public int AmountGained { get; set; }
    }

    public class SpendCurrencyEventArgs: DirectionalEventArgs
    {
        public Player PlayerSpendingCurrency { get; set; }
        public int AmountSpent { get; set; }
    }
}


text:
using System;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.GameEvents.PlayerTriggeredEvents;

namespace Subterfuge.Remake.Core.GameEvents.EventPublishers
{
    public interface ISubLaunchEventPublisher
    {
        event EventHandler<OnSubLaunchEventArgs> OnSubLaunched;
    }

    public class OnSubLaunchEventArgs : DirectionalEventArgs
    {
        public LaunchEvent LaunchEvent { get; set; }
        public IEntity Source { get; set; }
        public IEntity Destination { get; set; }
        public Sub LaunchedSub { get; set; }
    }
}


text:
using System;
using Subterfuge.Remake.Core.Entities;
using Subterfuge.Remake.Core.Entities.Components;

namespace Subterfuge.Remake.Core.GameEvents.EventPublishers
{
    public interface IVisionEventPublisher
    {
        event EventHandler<OnVisionRangeChangeEventArgs> OnVisionRangeChange;
        event EventHandler<OnEntityEnterVisionRangeEventArgs> OnEntityEnterVisionRange;
        event EventHandler<OnEntityLeaveVisionRangeEventArgs> OnEntityLeaveVisionRange;
    }

    public class OnVisionRangeChangeEventArgs : DirectionalEventArgs
    {
        public float PreviousVisionRange { get; set; }
        public float NewVisionRange { get; set; }
        public VisionManager VisionManager { get; set; }
    }

    public class OnEntityEnterVisionRangeEventArgs : DirectionalEventArgs
    {
        public IEntity EntityInVision { get; set; }
        public VisionManager VisionManager { get; set; }
    }

    public class OnEntityLeaveVisionRangeEventArgs : DirectionalEventArgs
    {
        public IEntity EntityLeavingVision { get; set; }
        public VisionManager VisionManager { get; set; }
    }
}


text:
using System;
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Base
{
    /// <summary>
    /// An instave of a GameEvent that can be added to the TimeMachine.
    /// </summary>
    public abstract class GameEvent : IComparable, IReversible
    {
        /// <summary>
        /// If the event was successfully triggered
        /// </summary>
        protected bool EventSuccess;

        /// <summary>
        /// Sets the tick when this event occurs.
        /// </summary>
        public GameTick OccursAt { get; set; }

        public Priority Priority { get; }

        /// <summary>
        /// This function will be executed when determing the game's state for the time machine.
        /// This function will check all conditions required to perform the command as well as perform the command
        /// to show the outcome of the command.
        /// </summary>
        public abstract bool ForwardAction(TimeMachine timeMachine);

        /// <summary>
        /// This function will be executed when going back in time in order to undo an action.
        /// For example, this will un-hire a specialist returning the hire point to the queen, or un-launch a sub returning the drillers to the owner.
        /// </summary>
        public abstract bool BackwardAction(TimeMachine timeMachine);

        /// <summary>
        /// Get the id of this game event.
        /// </summary>
        /// <returns>The id of this game event.</returns>
        public abstract string GetEventId();

        public GameEvent(
            GameTick occursAt,
            Priority priority
        )
        {
            this.OccursAt = occursAt;
            this.Priority = priority;
        }

        /// <summary>
        /// Comparison override for the priority queue sorting
        /// </summary>
        /// <param name="obj">The object to compare to</param>
        /// <returns>if the object is before, after another event</returns>
        public int CompareTo(object obj)
        {
            // 1 = this event occurs last.
            // -1 = this event occurs first.
            GameEvent comparedEvent = obj as GameEvent;
            if (comparedEvent == null) return 1;

            if (this.OccursAt > comparedEvent.OccursAt)
            {
                return 1;
            }
            if (this.OccursAt < comparedEvent.OccursAt)
            {
                return -1;
            }

            if (Priority > comparedEvent.Priority)
            {
                return -1;
            }

            if (Priority < comparedEvent.Priority)
            {
                return 1;
            }

            // Do further comparison. The game events should NEVER be the same!
            return String.Compare(GetEventId(), comparedEvent.GetEventId(), StringComparison.Ordinal);
        }

        public abstract override bool Equals(Object other);
        public abstract override int  GetHashCode();

        public static bool operator ==(GameEvent? left, GameEvent? right)
        {
            return Equals(left, right);
        }

        public static bool operator !=(GameEvent? left, GameEvent? right)
        {
            return !Equals(left, right);
        }

        public abstract bool WasEventSuccessful();
    }
}


text:
using Subterfuge.Remake.Api.Network;
using Subterfuge.Remake.Core.GameEvents.PlayerTriggeredEvents;

namespace Subterfuge.Remake.Core.GameEvents.Base
{
    public static class GameEventFactory
    {
        public static PlayerTriggeredEvent ParseGameEvent(GameRoomEvent model)
        {
            switch (model.GameEventData.EventDataType)
            {
                case EventDataType.LaunchEventData:
                    return new LaunchEvent(model);
                case EventDataType.DrillMineEventData:
                    return new DrillMineEvent(model);
                case EventDataType.ToggleShieldEventData:
                    return new ToggleShieldEvent(model);
                case EventDataType.GameEndEventData:
                    return new GameEndEvent(model);
                case EventDataType.PauseGameEventData:
                    return new PauseGameEvent(model);
                case EventDataType.UnpauseGameEventData:
                    return new UnpauseGameEvent(model);
                case EventDataType.PlayerLeaveGameEventData:
                    return new PlayerLeaveGameEvent(model);
                case EventDataType.HireSpecialistEventData:
                    return new HireSpecialistEvent(model);
                case EventDataType.PromoteSpecialistEventData:
                    return new PromoteSpecialistEvent(model);
                default:
                    return null;
            }
        }
    }
}


text:
using System.Collections.Generic;

namespace Subterfuge.Remake.Core.GameEvents.Base
{
    public enum Priority
    {
        PAUSE_EVENT = 1000,
        UNPAUSE_EVENT = 999,

        PlayerIssuedCommand = 100,
        SPECIALIST_CAPCITY_CHANGE = 99,
        COMBAT_EVENT = 98,

        RESOURCE_PRODUCTION = 90,

        // Combat priorities applied by specialists
        SPECIALIST_EXPLODE = 89,
        SPECIALIST_NEUTRALIZE_SPECIALIST_EFFECTS = 80,
        SPECIALIST_DEMOTE_EFFECT = 60,
        SPECIALIST_SHIELD_EFFECT = 40,
        SPECIALIST_DRILLER_EFFECT = 30,
        SPECIALIST_STEAL_EFFECT = 25,
        SPECIALIST_SUB_REDIRECT = 20,
        SPECIALIST_SLOW_EFFECT = 15,
        SPECIALIST_SWAP_SPECIALISTS_EFFECT = 12,
        SPECIALIST_KILL_SPECIALISTS = 10,

        // Natural Combat events
        SHIELD_COMBAT = 2,
        DRILLER_COMBAT = 1,

        // Ownership transfer and specialist capture happens here.
        // At this event, the combat is done.
        // Friendly combats immediately jump to this stage.
        COMBAT_RESOLVE = 0,

        // Actions to apply after the combat has been completed.
        POST_COMBAT = -1,
    }

    public static class PriorityExtensions
    {
        public static List<Priority> NaturalEvents()
        {
            return new List<Priority>()
            {
                Priority.COMBAT_EVENT,
                Priority.COMBAT_RESOLVE,
                Priority.SHIELD_COMBAT,
                Priority.DRILLER_COMBAT,
                Priority.RESOURCE_PRODUCTION
            };
        }
    }

}


text:
using Subterfuge.Remake.Core.Timing;

namespace Subterfuge.Remake.Core.GameEvents.Base
{
    /// <summary>
    /// Any reversible action
    /// </summary>
    public interface IReversible
    {
        /// <summary>
        /// Applies the forward action
        /// </summary>
        /// <returns>If the action was successful</returns>
        bool ForwardAction(TimeMachine timeMachine);

        /// <summary>
        /// Applies the backward action. Snould never be called before ForwardAction.
        /// </summary>
        /// <returns>If the backward action was successful</returns>
        bool BackwardAction(TimeMachine timeMachine);

        /// <summary>
        /// Function to verify if the event was successful during launch.
        /// </summary>
        /// <returns>If the event occured</returns>
        bool WasEventSuccessful();
    }
}