using Content.Server.Station.Events; using Content.Server.Station.Systems; using Content.Shared.GameTicking; using Robust.Shared.Player; namespace Content.Server._Sunrise.Roles; public sealed class RelativeJobsCountSystem : EntitySystem { [Dependency] private readonly StationJobsSystem _jobsSystem = default!; [Dependency] private readonly ISharedPlayerManager _player = default!; private ISawmill _sawmill = default!; /// public override void Initialize() { SubscribeLocalEvent(OnPlayerJoinedStation); SubscribeLocalEvent(OnStationInit); _sawmill = Logger.GetSawmill("sunrise.relative_job"); } private void OnPlayerJoinedStation(PlayerSpawnCompleteEvent args) { if (!TryComp(args.Station, out var relativeJobsComponent)) return; if (args.JobId == null) return; IncreaseSlotsByOtherJobs(args.Station, args.JobId, relativeJobsComponent); } private void OnStationInit(ref StationPostInitEvent args) { if (!TryComp(args.Station, out var relativeJobsComponent)) return; // Это должно вызываться один раз перед тем, как игроки заспавнятся за свои работки IncreaseSlotsByOnline((args.Station, relativeJobsComponent)); } #region Slot increase logic /// /// Увеличивает количество слотов ролей за счет количества общего онлайна /// Параметры указаны в прототипе станции через /// private void IncreaseSlotsByOnline(Entity station) { var totalPlayer = _player.PlayerCount; // Проходимся по всем переданным настройкам для ролей // И добавляем им слоты foreach (var settings in station.Comp.Online) { if (!_jobsSystem.TryGetJobSlot(station, settings.TargetJob, out _)) continue; // Максимально возможное количество дополнительных слотов. // Выставляется как самое низкое из максимальных значений var maxSlots = GetMaxSlots(settings, station.Comp); // Расчет количества дополнительных слотов. Минимально 0, максимальное зависит от maxSlots var additionalSlots = maxSlots >= 0 ? (int) Math.Clamp(totalPlayer / settings.AnyTargetOnlineIncreaseSlot, 0f, maxSlots) : (int) Math.Round(totalPlayer / settings.AnyTargetOnlineIncreaseSlot); AddSlots(station, settings, additionalSlots); } } /// /// Увеличивает количество слотов ролей за счет количества других ролей. /// Параметры указаны в прототипе станции через /// private void IncreaseSlotsByOtherJobs(EntityUid station, string playerJobId, RelativeJobsCountComponent component) { // Проходимся по всем переданным настройкам для ролей // И добавляем им слоты foreach (var settings in component.Jobs) { // Проходимся по внутреннему списку ролей, от количества игроках на которых зависит количество слотов для нашей целей роли foreach (var (relativeJob, modifier) in settings.Dependency) { // Так как это вызывается, когда игрок зашел в раунд, то мы проверяем, является ли текущий зашедший игрок нужной нам работкой // Если это нужная работка мы увеличим слоты. Если не нужная, то пойдет нахуй if (playerJobId != relativeJob.ToString()) continue; if (!_jobsSystem.TryGetJobSlot(station, settings.TargetJob, out _)) continue; AddSlots((station, component), settings, modifier); } } } private void AddSlots(Entity station, IRelativeCountSettings settings, int value) { var maxSlots = GetMaxSlots(settings, station.Comp); var toAdd = maxSlots >= 0 ? Math.Clamp(value, 0, maxSlots) : value; if (toAdd == 0) return; _jobsSystem.TryAdjustJobSlot(station, settings.TargetJob, toAdd, true); RemoveAdditionalSlot(station, settings, toAdd); } private void RemoveAdditionalSlot(Entity station, IRelativeCountSettings settings, int value) { if (!station.Comp.TotalMaxCount.ContainsKey(settings.TargetJob)) { _sawmill.Error($"Target job {settings.TargetJob} not presented in TotalMaxCount dictionary"); return; } // Если TotalMaxCount равен -1 (без ограничений), не вычитаем из него if (station.Comp.TotalMaxCount[settings.TargetJob] == -1) return; station.Comp.TotalMaxCount[settings.TargetJob] -= value; } #endregion #region Helpers /// /// Смотрит, не вышло ли количество слотов данной должности за установленные максимальные пределы /// /// Текущее количество открытых слотов /// Текущие базовые параметры /// Компонент /// Вышло ли количество слотов данной работы за максимальные пределы private bool IsMaximumSlotsReached(int? targetJobCount, IRelativeCountSettings settings, RelativeJobsCountComponent component) { if (settings.MaxSlots == -1) return false; if (!component.TotalMaxCount.TryGetValue(settings.TargetJob, out var targetCount)) { _sawmill.Error($"Target job {settings.TargetJob} not presented in TotalMaxCount dictionary"); return true; } if (targetJobCount >= targetCount) return true; if (targetJobCount == null || targetJobCount >= settings.MaxSlots) return true; return false; } private static int GetMaxSlots(IRelativeCountSettings settings, RelativeJobsCountComponent component) { if (!component.TotalMaxCount.TryGetValue(settings.TargetJob, out var totalMax)) return 0; if (totalMax == -1) return -1; return Math.Clamp(Math.Min(settings.MaxSlots, totalMax), 0, int.MaxValue); } #endregion }