namespace SpaceGame.Api.Ships.AI; internal sealed class IdleShipBehaviorState : IShipBehaviorState { public string Kind => "idle"; public void Plan(SimulationEngine engine, ShipRuntime ship, SimulationWorld world) { ship.ControllerTask = new ControllerTaskRuntime { Kind = ControllerTaskKind.Idle, Threshold = world.Balance.ArrivalThreshold, Status = WorkStatus.Pending, }; } public void ApplyEvent(SimulationEngine engine, ShipRuntime ship, SimulationWorld world, string controllerEvent) { } } internal sealed class PatrolShipBehaviorState : IShipBehaviorState { public string Kind => "patrol"; public void Plan(SimulationEngine engine, ShipRuntime ship, SimulationWorld world) { if (ship.DefaultBehavior.PatrolPoints.Count == 0) { ship.DefaultBehavior.Kind = "idle"; ship.ControllerTask = new ControllerTaskRuntime { Kind = ControllerTaskKind.Idle, Threshold = world.Balance.ArrivalThreshold, Status = WorkStatus.Pending, }; return; } ship.ControllerTask = new ControllerTaskRuntime { Kind = ControllerTaskKind.Travel, TargetPosition = ship.DefaultBehavior.PatrolPoints[ship.DefaultBehavior.PatrolIndex], TargetSystemId = ship.SystemId, Threshold = 18f, }; } public void ApplyEvent(SimulationEngine engine, ShipRuntime ship, SimulationWorld world, string controllerEvent) { if (controllerEvent == "arrived" && ship.DefaultBehavior.PatrolPoints.Count > 0) { ship.DefaultBehavior.PatrolIndex = (ship.DefaultBehavior.PatrolIndex + 1) % ship.DefaultBehavior.PatrolPoints.Count; } } } internal sealed class ResourceHarvestShipBehaviorState : IShipBehaviorState { private readonly string? resourceItemId; private readonly string requiredModule; public ResourceHarvestShipBehaviorState(string kind, string? resourceItemId, string requiredModule) { Kind = kind; this.resourceItemId = resourceItemId; this.requiredModule = requiredModule; } public string Kind { get; } public void Plan(SimulationEngine engine, ShipRuntime ship, SimulationWorld world) => engine.PlanResourceHarvest(ship, world, resourceItemId, requiredModule); public void ApplyEvent(SimulationEngine engine, ShipRuntime ship, SimulationWorld world, string controllerEvent) { switch (ship.DefaultBehavior.Phase, controllerEvent) { case ("travel-to-node", "arrived"): ship.DefaultBehavior.Phase = SimulationEngine.GetShipCargoAmount(ship) >= ship.Definition.CargoCapacity ? "travel-to-station" : "extract"; break; case ("extract", "cargo-full"): ship.DefaultBehavior.Phase = "travel-to-station"; break; case ("extract", "node-depleted"): ship.DefaultBehavior.Phase = "travel-to-node"; ship.DefaultBehavior.NodeId = null; break; case ("travel-to-station", "arrived"): ship.DefaultBehavior.Phase = "dock"; break; case ("dock", "docked"): ship.DefaultBehavior.Phase = "unload"; break; case ("unload", "unloaded"): ship.DefaultBehavior.Phase = "undock"; break; case ("undock", "undocked"): ship.DefaultBehavior.Phase = "travel-to-node"; ship.DefaultBehavior.NodeId = null; break; } } } internal sealed class ConstructStationShipBehaviorState : IShipBehaviorState { public string Kind => "construct-station"; public void Plan(SimulationEngine engine, ShipRuntime ship, SimulationWorld world) => engine.PlanStationConstruction(ship, world); public void ApplyEvent(SimulationEngine engine, ShipRuntime ship, SimulationWorld world, string controllerEvent) { switch (ship.DefaultBehavior.Phase, controllerEvent) { case ("travel-to-station", "arrived"): ship.DefaultBehavior.Phase = "deliver-to-site"; break; case ("deliver-to-site", "construction-delivered"): ship.DefaultBehavior.Phase = "build-site"; break; case ("construct-module", "module-constructed"): case ("build-site", "site-constructed"): ship.DefaultBehavior.Phase = "travel-to-station"; ship.DefaultBehavior.ModuleId = null; break; } } } internal sealed class AttackTargetShipBehaviorState : IShipBehaviorState { public string Kind => "attack-target"; public void Plan(SimulationEngine engine, ShipRuntime ship, SimulationWorld world) => engine.PlanAttackTarget(ship, world); public void ApplyEvent(SimulationEngine engine, ShipRuntime ship, SimulationWorld world, string controllerEvent) { if (controllerEvent is "target-destroyed" or "target-lost") { ship.DefaultBehavior.TargetEntityId = null; } } } internal sealed class TradeHaulShipBehaviorState : IShipBehaviorState { public string Kind => "trade-haul"; public void Plan(SimulationEngine engine, ShipRuntime ship, SimulationWorld world) => engine.PlanTransportHaul(ship, world); public void ApplyEvent(SimulationEngine engine, ShipRuntime ship, SimulationWorld world, string controllerEvent) { switch (ship.DefaultBehavior.Phase, controllerEvent) { case ("travel-to-source", "arrived"): ship.DefaultBehavior.Phase = "dock-source"; break; case ("dock-source", "docked"): ship.DefaultBehavior.Phase = "load"; break; case ("load", "loaded"): ship.DefaultBehavior.Phase = "undock-from-source"; break; case ("undock-from-source", "undocked"): ship.DefaultBehavior.Phase = "travel-to-destination"; break; case ("travel-to-destination", "arrived"): ship.DefaultBehavior.Phase = "dock-destination"; break; case ("dock-destination", "docked"): ship.DefaultBehavior.Phase = "unload"; break; case ("unload", "unloaded"): ship.DefaultBehavior.Phase = "undock-from-destination"; break; case ("undock-from-destination", "undocked"): ship.DefaultBehavior.Phase = "travel-to-source"; break; } } }