using System; using System.Collections.Generic; using System.Linq; using Content.Server.GameTicking; using Content.Server.Maps; using Content.Shared.Station; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Log; namespace Content.Server.Station; /// /// System that manages the jobs available on a station, and maybe other things later. /// public class StationSystem : EntitySystem { [Dependency] private GameTicker _gameTicker = default!; private uint _idCounter = 1; private Dictionary _stationInfo = new(); /// /// List of stations for the current round. /// public IReadOnlyDictionary StationInfo => _stationInfo; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnRoundEnd); } /// /// Cleans up station info. /// private void OnRoundEnd(GameRunLevelChangedEvent eventArgs) { if (eventArgs.New == GameRunLevel.PreRoundLobby) _stationInfo = new(); } public class StationInfoData { public readonly string Name; /// /// Job list associated with the game map. /// public readonly GameMapPrototype MapPrototype; /// /// The round job list. /// private readonly Dictionary _jobList; public IReadOnlyDictionary JobList => _jobList; public StationInfoData(string name, GameMapPrototype mapPrototype, Dictionary jobList) { Name = name; MapPrototype = mapPrototype; _jobList = jobList; } public bool TryAssignJob(string jobName) { if (_jobList.ContainsKey(jobName)) { switch (_jobList[jobName]) { case > 0: _jobList[jobName]--; return true; case -1: return true; default: return false; } } else { return false; } } } /// /// Creates a new station and attaches it to the given grid. /// /// grid to attach to /// game map prototype of the station /// name of the station to assign, if not the default /// optional grid component of the grid. /// The ID of the resulting station /// Thrown when the given entity is not a grid. public StationId InitialSetupStationGrid(EntityUid mapGrid, GameMapPrototype mapPrototype, string? stationName = null, IMapGridComponent? gridComponent = null) { if (!Resolve(mapGrid, ref gridComponent)) throw new ArgumentException("Tried to initialize a station on a non-grid entity!"); var jobListDict = mapPrototype.AvailableJobs.ToDictionary(x => x.Key, x => x.Value[1]); var id = AllocateStationInfo(); _stationInfo[id] = new StationInfoData(stationName ?? mapPrototype.MapName, mapPrototype, jobListDict); var station = EntityManager.AddComponent(mapGrid); station.Station = id; _gameTicker.UpdateJobsAvailable(); // new station means new jobs, tell any lobby-goers. Logger.InfoS("stations", $"Setting up new {mapPrototype.ID} called {mapPrototype.MapName} on grid {mapGrid}:{gridComponent.GridIndex}"); return id; } /// /// Adds the given grid to the given station. /// /// grid to attach /// station to attach the grid to /// optional grid component of the grid. /// Thrown when the given entity is not a grid. public void AddGridToStation(EntityUid mapGrid, StationId station, IMapGridComponent? gridComponent = null) { if (!Resolve(mapGrid, ref gridComponent)) throw new ArgumentException("Tried to initialize a station on a non-grid entity!"); var stationComponent = EntityManager.AddComponent(mapGrid); stationComponent.Station = station; Logger.InfoS("stations", $"Adding grid {mapGrid}:{gridComponent.GridIndex} to station {station} named {_stationInfo[station].Name}"); } /// /// Attempts to assign a job on the given station. /// /// station to assign to /// name of the job /// assignment success public bool TryAssignJobToStation(StationId stationId, string jobName) { if (stationId != StationId.Invalid) return _stationInfo[stationId].TryAssignJob(jobName); else return false; } /// /// Checks if the given job is available. /// /// station to check /// name of the job /// job availability public bool IsJobAvailableOnStation(StationId stationId, string jobName) { if (_stationInfo[stationId].JobList.TryGetValue(jobName, out var amount)) return amount != 0; return false; } private StationId AllocateStationInfo() { return new StationId(_idCounter++); } }