2023-08-28 16:53:24 -07:00
using Content.Server.GameTicking ;
2022-05-10 13:43:30 -05:00
using Content.Server.Spawners.Components ;
using Content.Server.Station.Systems ;
2023-08-05 23:51:25 +12:00
using Robust.Shared.Map ;
2022-05-10 13:43:30 -05:00
using Robust.Shared.Random ;
namespace Content.Server.Spawners.EntitySystems ;
public sealed class SpawnPointSystem : EntitySystem
{
[Dependency] private readonly GameTicker _gameTicker = default ! ;
[Dependency] private readonly IRobustRandom _random = default ! ;
[Dependency] private readonly StationSystem _stationSystem = default ! ;
[Dependency] private readonly StationSpawningSystem _stationSpawning = default ! ;
public override void Initialize ( )
{
2024-02-01 05:12:09 -05:00
SubscribeLocalEvent < PlayerSpawningEvent > ( OnPlayerSpawning ) ;
2022-05-10 13:43:30 -05:00
}
2024-02-01 05:12:09 -05:00
private void OnPlayerSpawning ( PlayerSpawningEvent args )
2022-05-10 13:43:30 -05:00
{
2023-03-22 20:29:55 +11:00
if ( args . SpawnResult ! = null )
return ;
2022-05-10 13:43:30 -05:00
// TODO: Cache all this if it ends up important.
2023-08-05 23:51:25 +12:00
var points = EntityQueryEnumerator < SpawnPointComponent , TransformComponent > ( ) ;
var possiblePositions = new List < EntityCoordinates > ( ) ;
2025-08-31 20:50:37 +02:00
while ( points . MoveNext ( out var uid , out var spawnPoint , out var xform ) )
2022-05-10 13:43:30 -05:00
{
2023-08-05 23:51:25 +12:00
if ( args . Station ! = null & & _stationSystem . GetOwningStation ( uid , xform ) ! = args . Station )
2022-05-10 13:43:30 -05:00
continue ;
2025-06-13 14:15:48 +03:00
//CP14 always spawn gods on gods spawnpoints
2025-06-15 21:25:58 +03:00
if ( spawnPoint . SpawnType = = SpawnPointType . Unset & & ( args . Job = = null | | spawnPoint . Job = = args . Job ) )
2025-06-13 14:15:48 +03:00
{
possiblePositions . Clear ( ) ;
possiblePositions . Add ( xform . Coordinates ) ;
break ;
}
//CP14end
2022-05-10 13:43:30 -05:00
if ( _gameTicker . RunLevel = = GameRunLevel . InRound & & spawnPoint . SpawnType = = SpawnPointType . LateJoin )
{
2023-08-05 23:51:25 +12:00
possiblePositions . Add ( xform . Coordinates ) ;
2022-05-10 13:43:30 -05:00
}
2023-03-22 20:29:55 +11:00
2023-08-28 16:53:24 -07:00
if ( _gameTicker . RunLevel ! = GameRunLevel . InRound & &
spawnPoint . SpawnType = = SpawnPointType . Job & &
2025-08-31 20:50:37 +02:00
( args . Job = = null | | spawnPoint . Job = = null | | spawnPoint . Job = = args . Job ) )
2022-05-10 13:43:30 -05:00
{
2023-08-05 23:51:25 +12:00
possiblePositions . Add ( xform . Coordinates ) ;
2022-05-10 13:43:30 -05:00
}
}
2023-08-05 23:51:25 +12:00
if ( possiblePositions . Count = = 0 )
2022-05-10 13:43:30 -05:00
{
2023-08-05 23:51:25 +12:00
// Ok we've still not returned, but we need to put them /somewhere/.
// TODO: Refactor gameticker spawning code so we don't have to do this!
var points2 = EntityQueryEnumerator < SpawnPointComponent , TransformComponent > ( ) ;
2022-05-27 06:01:07 +02:00
2025-08-31 20:50:37 +02:00
if ( points2 . MoveNext ( out _ , out var xform ) )
2023-08-05 23:51:25 +12:00
{
2025-08-31 20:50:37 +02:00
Log . Error ( $"Unable to pick a valid spawn point, picking random spawner as a backup.\nRunLevel: {_gameTicker.RunLevel} Station: {ToPrettyString(args.Station)} Job: {args.Job}" ) ;
2023-08-05 23:51:25 +12:00
possiblePositions . Add ( xform . Coordinates ) ;
}
else
{
2025-08-31 20:50:37 +02:00
Log . Error ( $"No spawn points were available!\nRunLevel: {_gameTicker.RunLevel} Station: {ToPrettyString(args.Station)} Job: {args.Job}" ) ;
2023-08-05 23:51:25 +12:00
return ;
}
2022-05-10 13:43:30 -05:00
}
2023-08-05 23:51:25 +12:00
var spawnLoc = _random . Pick ( possiblePositions ) ;
args . SpawnResult = _stationSpawning . SpawnPlayerMob (
spawnLoc ,
args . Job ,
args . HumanoidCharacterProfile ,
args . Station ) ;
2022-05-10 13:43:30 -05:00
}
}