using Content.Server.GameTicking; using Content.Server.RoundEnd; using Content.Server.Spawners.Components; using Content.Server.Station.Systems; using Content.Shared.Preferences; using Content.Shared.Roles; using Robust.Server.Containers; using Robust.Shared.Containers; using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Server.Spawners.EntitySystems; public sealed class ContainerSpawnPointSystem : EntitySystem { [Dependency] private readonly ContainerSystem _container = default!; [Dependency] private readonly GameTicker _gameTicker = default!; [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly StationSpawningSystem _stationSpawning = default!; [Dependency] private readonly StationJobsSystem _jobs = default!; // WD edit [Dependency] private readonly RoundEndSystem _roundEnd = default!; // WD edit public override void Initialize() { base.Initialize(); SubscribeLocalEvent(HandlePlayerSpawning, before: new[] { typeof(SpawnPointSystem) }); SubscribeLocalEvent(OnShutdown); // WD edit } public void HandlePlayerSpawning(PlayerSpawningEvent args) { if (args.SpawnResult != null) return; // DeltaV - Ignore these two desired spawn types if (args.DesiredSpawnPointType is SpawnPointType.Observer or SpawnPointType.LateJoin) return; // If it's just a spawn pref check if it's for cryo (silly). if (args.HumanoidCharacterProfile?.SpawnPriority != SpawnPriorityPreference.Cryosleep && (!_proto.TryIndex(args.Job, out var jobProto) || jobProto.JobEntity == null)) return; var query = EntityQueryEnumerator(); var possibleContainers = new List>(); while (query.MoveNext(out var uid, out var spawnPoint, out var container, out var xform)) { if (args.Station != null && _station.GetOwningStation(uid, xform) != args.Station) continue; // DeltaV - Custom override for override spawnpoints, only used for prisoners currently. This shouldn't run for any other jobs if (args.DesiredSpawnPointType == SpawnPointType.Job) { if (spawnPoint.SpawnType != SpawnPointType.Job || spawnPoint.Job != args.Job) continue; possibleContainers.Add((uid, spawnPoint, container, xform)); continue; } // If it's unset, then we allow it to be used for both roundstart and midround joins if (spawnPoint.SpawnType == SpawnPointType.Unset) { // make sure we also check the job here for various reasons. if (spawnPoint.Job == null || spawnPoint.Job == args.Job) possibleContainers.Add((uid, spawnPoint, container, xform)); continue; } if (_gameTicker.RunLevel == GameRunLevel.InRound && spawnPoint.SpawnType == SpawnPointType.LateJoin) possibleContainers.Add((uid, spawnPoint, container, xform)); if (_gameTicker.RunLevel != GameRunLevel.InRound && spawnPoint.SpawnType == SpawnPointType.Job && (args.Job == null || spawnPoint.Job == args.Job)) possibleContainers.Add((uid, spawnPoint, container, xform)); } if (possibleContainers.Count == 0) return; // we just need some default coords so we can spawn the player entity. var baseCoords = possibleContainers[0].Comp3.Coordinates; args.SpawnResult = _stationSpawning.SpawnPlayerMob( baseCoords, args.Job, args.HumanoidCharacterProfile, args.Station); _random.Shuffle(possibleContainers); foreach (var (uid, spawnPoint, manager, xform) in possibleContainers) { if (!_container.TryGetContainer(uid, spawnPoint.ContainerId, out var container, manager)) continue; if (!_container.Insert(args.SpawnResult.Value, container, containerXform: xform)) continue; return; } Del(args.SpawnResult); args.SpawnResult = null; } // WD edit start - constructible AI private void OnShutdown(Entity ent, ref ComponentShutdown args) { if (ent.Comp.Job == null) return; var station = _roundEnd.GetStation(); if (!station.HasValue) return; var stationInMap = _station.GetStationInMap(Transform(station.Value).MapID); if (!stationInMap.HasValue) return; _jobs.TryAdjustJobSlot( stationInMap.Value, ent.Comp.Job!, -1); } // WD edit end }