diff --git a/Content.Server/Bed/Cryostorage/CryostorageSystem.cs b/Content.Server/Bed/Cryostorage/CryostorageSystem.cs index 1369fa20f1..dd89ba2f72 100644 --- a/Content.Server/Bed/Cryostorage/CryostorageSystem.cs +++ b/Content.Server/Bed/Cryostorage/CryostorageSystem.cs @@ -1,17 +1,14 @@ -using System.Globalization; -using System.Linq; using Content.Server.Chat.Managers; +using Content.Server.Chat.Systems; using Content.Server.GameTicking; +using Content.Server.Ghost; using Content.Server.Hands.Systems; using Content.Server.Inventory; using Content.Server.Popups; -using Content.Server.Chat.Systems; using Content.Server.Station.Components; using Content.Server.Station.Systems; using Content.Server.StationRecords; using Content.Server.StationRecords.Systems; -using Content.Shared.StationRecords; -using Content.Shared.UserInterface; using Content.Shared.Access.Systems; using Content.Shared.Bed.Cryostorage; using Content.Shared.Chat; @@ -19,6 +16,8 @@ using Content.Shared.Climbing.Systems; using Content.Shared.Database; using Content.Shared.Hands.Components; using Content.Shared.Mind.Components; +using Content.Shared.StationRecords; +using Content.Shared.UserInterface; using Robust.Server.Audio; using Robust.Server.Containers; using Robust.Server.GameObjects; @@ -27,6 +26,7 @@ using Robust.Shared.Containers; using Robust.Shared.Enums; using Robust.Shared.Network; using Robust.Shared.Player; +using System.Globalization; namespace Content.Server.Bed.Cryostorage; @@ -40,7 +40,7 @@ public sealed class CryostorageSystem : SharedCryostorageSystem [Dependency] private readonly ChatSystem _chatSystem = default!; [Dependency] private readonly ClimbSystem _climb = default!; [Dependency] private readonly ContainerSystem _container = default!; - [Dependency] private readonly GameTicker _gameTicker = default!; + [Dependency] private readonly GhostSystem _ghostSystem = default!; [Dependency] private readonly HandsSystem _hands = default!; [Dependency] private readonly ServerInventorySystem _inventory = default!; [Dependency] private readonly PopupSystem _popup = default!; @@ -210,7 +210,7 @@ public sealed class CryostorageSystem : SharedCryostorageSystem if (userId != null && Mind.TryGetMind(userId.Value, out var mind) && HasComp(mind.Value.Comp.CurrentEntity)) { - _gameTicker.OnGhostAttempt(mind.Value, false); + _ghostSystem.OnGhostAttempt(mind.Value, false); } } diff --git a/Content.Server/Body/Systems/BodySystem.cs b/Content.Server/Body/Systems/BodySystem.cs index bd5edb0ea5..4279f3ed2b 100644 --- a/Content.Server/Body/Systems/BodySystem.cs +++ b/Content.Server/Body/Systems/BodySystem.cs @@ -1,5 +1,5 @@ using Content.Server.Body.Components; -using Content.Server.GameTicking; +using Content.Server.Ghost; using Content.Server.Humanoid; using Content.Shared.Body.Components; using Content.Shared.Body.Part; @@ -17,7 +17,7 @@ namespace Content.Server.Body.Systems; public sealed class BodySystem : SharedBodySystem { - [Dependency] private readonly GameTicker _ticker = default!; + [Dependency] private readonly GhostSystem _ghostSystem = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly HumanoidAppearanceSystem _humanoidSystem = default!; [Dependency] private readonly MobStateSystem _mobState = default!; @@ -43,7 +43,7 @@ public sealed class BodySystem : SharedBodySystem if (_mobState.IsDead(ent) && _mindSystem.TryGetMind(ent, out var mindId, out var mind)) { mind.TimeOfDeath ??= _gameTiming.RealTime; - _ticker.OnGhostAttempt(mindId, canReturnGlobal: true, mind: mind); + _ghostSystem.OnGhostAttempt(mindId, canReturnGlobal: true, mind: mind); } } diff --git a/Content.Server/Chat/SuicideSystem.cs b/Content.Server/Chat/SuicideSystem.cs index 884292b0fa..69d87472fb 100644 --- a/Content.Server/Chat/SuicideSystem.cs +++ b/Content.Server/Chat/SuicideSystem.cs @@ -1,18 +1,18 @@ -using Content.Server.GameTicking; +using Content.Server.Ghost; +using Content.Shared.Administration.Logs; +using Content.Shared.Chat; using Content.Shared.Damage; using Content.Shared.Database; using Content.Shared.Hands.Components; using Content.Shared.Interaction.Events; using Content.Shared.Item; using Content.Shared.Mind; +using Content.Shared.Mind.Components; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Popups; using Content.Shared.Tag; using Robust.Shared.Player; -using Content.Shared.Administration.Logs; -using Content.Shared.Chat; -using Content.Shared.Mind.Components; namespace Content.Server.Chat; @@ -23,7 +23,7 @@ public sealed class SuicideSystem : EntitySystem [Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly GameTicker _gameTicker = default!; + [Dependency] private readonly GhostSystem _ghostSystem = default!; [Dependency] private readonly SharedSuicideSystem _suicide = default!; public override void Initialize() @@ -82,7 +82,7 @@ public sealed class SuicideSystem : EntitySystem if (_tagSystem.HasTag(victim, "CannotSuicide")) args.CanReturnToBody = true; - if (_gameTicker.OnGhostAttempt(victim.Comp.Mind.Value, args.CanReturnToBody, mind: mindComponent)) + if (_ghostSystem.OnGhostAttempt(victim.Comp.Mind.Value, args.CanReturnToBody, mind: mindComponent)) args.Handled = true; } diff --git a/Content.Server/Clothing/Systems/CursedMaskSystem.cs b/Content.Server/Clothing/Systems/CursedMaskSystem.cs index 2045ff5ccd..825e85e2c6 100644 --- a/Content.Server/Clothing/Systems/CursedMaskSystem.cs +++ b/Content.Server/Clothing/Systems/CursedMaskSystem.cs @@ -1,5 +1,5 @@ using Content.Server.Administration.Logs; -using Content.Server.GameTicking; +using Content.Server.Ghost; using Content.Server.Mind; using Content.Server.NPC; using Content.Server.NPC.HTN; @@ -21,7 +21,7 @@ namespace Content.Server.Clothing.Systems; public sealed class CursedMaskSystem : SharedCursedMaskSystem { [Dependency] private readonly IAdminLogManager _adminLog = default!; - [Dependency] private readonly GameTicker _ticker = default!; + [Dependency] private readonly GhostSystem _ghostSystem = default!; [Dependency] private readonly HTNSystem _htn = default!; [Dependency] private readonly MindSystem _mind = default!; [Dependency] private readonly NPCSystem _npc = default!; @@ -39,7 +39,7 @@ public sealed class CursedMaskSystem : SharedCursedMaskSystem if (TryComp(wearer, out var actor) && actor.PlayerSession.GetMind() is { } mind) { var session = actor.PlayerSession; - if (!_ticker.OnGhostAttempt(mind, false)) + if (!_ghostSystem.OnGhostAttempt(mind, false)) return; ent.Comp.StolenMind = mind; diff --git a/Content.Server/GameTicking/GameTicker.GamePreset.cs b/Content.Server/GameTicking/GameTicker.GamePreset.cs index 5a2b375dd6..5642e84f90 100644 --- a/Content.Server/GameTicking/GameTicker.GamePreset.cs +++ b/Content.Server/GameTicking/GameTicker.GamePreset.cs @@ -1,27 +1,16 @@ -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; using Content.Server.GameTicking.Presets; using Content.Server.Maps; using Content.Shared.CCVar; -using Content.Shared.Damage; -using Content.Shared.Damage.Prototypes; -using Content.Shared.Database; -using Content.Shared.FixedPoint; -using Content.Shared.Ghost; -using Content.Shared.Mind; -using Content.Shared.Mobs; -using Content.Shared.Mobs.Components; -using Content.Shared.Mobs.Systems; using JetBrains.Annotations; using Robust.Shared.Player; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading.Tasks; namespace Content.Server.GameTicking { public sealed partial class GameTicker { - [Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!; - public const float PresetFailedCooldownIncrease = 30f; /// @@ -198,94 +187,6 @@ namespace Content.Server.GameTicking } } - public bool OnGhostAttempt(EntityUid mindId, bool canReturnGlobal, bool viaCommand = false, MindComponent? mind = null) - { - if (!Resolve(mindId, ref mind)) - return false; - - var playerEntity = mind.CurrentEntity; - - if (playerEntity != null && viaCommand) - _adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(playerEntity.Value):player} is attempting to ghost via command"); - - var handleEv = new GhostAttemptHandleEvent(mind, canReturnGlobal); - RaiseLocalEvent(handleEv); - - // Something else has handled the ghost attempt for us! We return its result. - if (handleEv.Handled) - return handleEv.Result; - - if (mind.PreventGhosting) - { - if (mind.Session != null) // Logging is suppressed to prevent spam from ghost attempts caused by movement attempts - { - _chatManager.DispatchServerMessage(mind.Session, Loc.GetString("comp-mind-ghosting-prevented"), - true); - } - - return false; - } - - if (TryComp(playerEntity, out var comp) && !comp.CanGhostInteract) - return false; - - if (mind.VisitingEntity != default) - { - _mind.UnVisit(mindId, mind: mind); - } - - var position = Exists(playerEntity) - ? Transform(playerEntity.Value).Coordinates - : GetObserverSpawnPoint(); - - if (position == default) - return false; - - // Ok, so, this is the master place for the logic for if ghosting is "too cheaty" to allow returning. - // There's no reason at this time to move it to any other place, especially given that the 'side effects required' situations would also have to be moved. - // + If CharacterDeadPhysically applies, we're physically dead. Therefore, ghosting OK, and we can return (this is critical for gibbing) - // Note that we could theoretically be ICly dead and still physically alive and vice versa. - // (For example, a zombie could be dead ICly, but may retain memories and is definitely physically active) - // + If we're in a mob that is critical, and we're supposed to be able to return if possible, - // we're succumbing - the mob is killed. Therefore, character is dead. Ghosting OK. - // (If the mob survives, that's a bug. Ghosting is kept regardless.) - var canReturn = canReturnGlobal && _mind.IsCharacterDeadPhysically(mind); - - if (_configurationManager.GetCVar(CCVars.GhostKillCrit) && - canReturnGlobal && - TryComp(playerEntity, out MobStateComponent? mobState)) - { - if (_mobState.IsCritical(playerEntity.Value, mobState)) - { - canReturn = true; - - //todo: what if they dont breathe lol - //cry deeply - - FixedPoint2 dealtDamage = 200; - if (TryComp(playerEntity, out var damageable) - && TryComp(playerEntity, out var thresholds)) - { - var playerDeadThreshold = _mobThresholdSystem.GetThresholdForState(playerEntity.Value, MobState.Dead, thresholds); - dealtDamage = playerDeadThreshold - damageable.TotalDamage; - } - - DamageSpecifier damage = new(_prototypeManager.Index("Asphyxiation"), dealtDamage); - - _damageable.TryChangeDamage(playerEntity, damage, true); - } - } - - var ghost = _ghost.SpawnGhost((mindId, mind), position, canReturn); - if (ghost == null) - return false; - - if (playerEntity != null) - _adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(playerEntity.Value):player} ghosted{(!canReturn ? " (non-returnable)" : "")}"); - - return true; - } - private void IncrementRoundNumber() { var playerIds = _playerGameStatuses.Keys.Select(player => player.UserId).ToArray(); @@ -304,17 +205,4 @@ namespace Content.Server.GameTicking RoundId = task.GetAwaiter().GetResult(); } } - - public sealed class GhostAttemptHandleEvent : HandledEntityEventArgs - { - public MindComponent Mind { get; } - public bool CanReturnGlobal { get; } - public bool Result { get; set; } - - public GhostAttemptHandleEvent(MindComponent mind, bool canReturnGlobal) - { - Mind = mind; - CanReturnGlobal = canReturnGlobal; - } - } } diff --git a/Content.Server/Ghost/GhostCommand.cs b/Content.Server/Ghost/GhostCommand.cs index b553d64201..a2f361d29d 100644 --- a/Content.Server/Ghost/GhostCommand.cs +++ b/Content.Server/Ghost/GhostCommand.cs @@ -1,4 +1,3 @@ -using Content.Server.GameTicking; using Content.Server.Popups; using Content.Shared.Administration; using Content.Shared.Mind; @@ -41,7 +40,7 @@ namespace Content.Server.Ghost mind = _entities.GetComponent(mindId); } - if (!_entities.System().OnGhostAttempt(mindId, true, true, mind)) + if (!_entities.System().OnGhostAttempt(mindId, true, true, mind)) { shell.WriteLine(Loc.GetString("ghost-command-denied")); } diff --git a/Content.Server/Ghost/GhostSystem.cs b/Content.Server/Ghost/GhostSystem.cs index b68c279b3e..b045214329 100644 --- a/Content.Server/Ghost/GhostSystem.cs +++ b/Content.Server/Ghost/GhostSystem.cs @@ -1,17 +1,23 @@ -using System.Linq; -using System.Numerics; +using Content.Server.Administration.Logs; +using Content.Server.Chat.Managers; using Content.Server.GameTicking; using Content.Server.Ghost.Components; using Content.Server.Mind; using Content.Server.Roles.Jobs; using Content.Server.Warps; using Content.Shared.Actions; +using Content.Shared.CCVar; +using Content.Shared.Damage; +using Content.Shared.Damage.Prototypes; +using Content.Shared.Database; using Content.Shared.Examine; using Content.Shared.Eye; +using Content.Shared.FixedPoint; using Content.Shared.Follower; using Content.Shared.Ghost; using Content.Shared.Mind; using Content.Shared.Mind.Components; +using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Events; @@ -19,11 +25,15 @@ using Content.Shared.Movement.Systems; using Content.Shared.Storage.Components; using Robust.Server.GameObjects; using Robust.Server.Player; +using Robust.Shared.Configuration; using Robust.Shared.Map; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; using Robust.Shared.Player; +using Robust.Shared.Prototypes; using Robust.Shared.Timing; +using System.Linq; +using System.Numerics; namespace Content.Server.Ghost { @@ -44,6 +54,14 @@ namespace Content.Server.Ghost [Dependency] private readonly TransformSystem _transformSystem = default!; [Dependency] private readonly VisibilitySystem _visibilitySystem = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; + [Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IAdminLogManager _adminLogger = default!; + [Dependency] private readonly IConfigurationManager _configurationManager = default!; + [Dependency] private readonly IChatManager _chatManager = default!; + [Dependency] private readonly SharedMindSystem _mind = default!; + [Dependency] private readonly GameTicker _gameTicker = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; private EntityQuery _ghostQuery; private EntityQuery _physicsQuery; @@ -144,7 +162,7 @@ namespace Content.Server.Ghost if (component.MustBeDead && (_mobState.IsAlive(uid) || _mobState.IsCritical(uid))) return; - _ticker.OnGhostAttempt(mindId, component.CanReturn, mind: mind); + OnGhostAttempt(mindId, component.CanReturn, mind: mind); } private void OnGhostStartup(EntityUid uid, GhostComponent component, ComponentStartup args) @@ -473,5 +491,102 @@ namespace Content.Server.Ghost Log.Debug($"Spawned ghost \"{ToPrettyString(ghost)}\" for {mind.Comp.CharacterName}."); return ghost; } + + public bool OnGhostAttempt(EntityUid mindId, bool canReturnGlobal, bool viaCommand = false, MindComponent? mind = null) + { + if (!Resolve(mindId, ref mind)) + return false; + + var playerEntity = mind.CurrentEntity; + + if (playerEntity != null && viaCommand) + _adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(playerEntity.Value):player} is attempting to ghost via command"); + + var handleEv = new GhostAttemptHandleEvent(mind, canReturnGlobal); + RaiseLocalEvent(handleEv); + + // Something else has handled the ghost attempt for us! We return its result. + if (handleEv.Handled) + return handleEv.Result; + + if (mind.PreventGhosting) + { + if (mind.Session != null) // Logging is suppressed to prevent spam from ghost attempts caused by movement attempts + { + _chatManager.DispatchServerMessage(mind.Session, Loc.GetString("comp-mind-ghosting-prevented"), + true); + } + + return false; + } + + if (TryComp(playerEntity, out var comp) && !comp.CanGhostInteract) + return false; + + if (mind.VisitingEntity != default) + { + _mind.UnVisit(mindId, mind: mind); + } + + var position = Exists(playerEntity) + ? Transform(playerEntity.Value).Coordinates + : _gameTicker.GetObserverSpawnPoint(); + + if (position == default) + return false; + + // Ok, so, this is the master place for the logic for if ghosting is "too cheaty" to allow returning. + // There's no reason at this time to move it to any other place, especially given that the 'side effects required' situations would also have to be moved. + // + If CharacterDeadPhysically applies, we're physically dead. Therefore, ghosting OK, and we can return (this is critical for gibbing) + // Note that we could theoretically be ICly dead and still physically alive and vice versa. + // (For example, a zombie could be dead ICly, but may retain memories and is definitely physically active) + // + If we're in a mob that is critical, and we're supposed to be able to return if possible, + // we're succumbing - the mob is killed. Therefore, character is dead. Ghosting OK. + // (If the mob survives, that's a bug. Ghosting is kept regardless.) + var canReturn = canReturnGlobal && _mind.IsCharacterDeadPhysically(mind); + + if (_configurationManager.GetCVar(CCVars.GhostKillCrit) && + canReturnGlobal && + TryComp(playerEntity, out MobStateComponent? mobState)) + { + if (_mobState.IsCritical(playerEntity.Value, mobState)) + { + canReturn = true; + + //todo: what if they dont breathe lol + //cry deeply + + FixedPoint2 dealtDamage = 200; + + if (TryComp(playerEntity, out var damageable) + && TryComp(playerEntity, out var thresholds)) + { + var playerDeadThreshold = _mobThresholdSystem.GetThresholdForState(playerEntity.Value, MobState.Dead, thresholds); + dealtDamage = playerDeadThreshold - damageable.TotalDamage; + } + + DamageSpecifier damage = new(_prototypeManager.Index("Asphyxiation"), dealtDamage); + + _damageable.TryChangeDamage(playerEntity, damage, true); + } + } + + var ghost = SpawnGhost((mindId, mind), position, canReturn); + + if (ghost == null) + return false; + + if (playerEntity != null) + _adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(playerEntity.Value):player} ghosted{(!canReturn ? " (non-returnable)" : "")}"); + + return true; + } + } + + public sealed class GhostAttemptHandleEvent(MindComponent mind, bool canReturnGlobal) : HandledEntityEventArgs + { + public MindComponent Mind { get; } = mind; + public bool CanReturnGlobal { get; } = canReturnGlobal; + public bool Result { get; set; } } } diff --git a/Content.Server/Materials/MaterialReclaimerSystem.cs b/Content.Server/Materials/MaterialReclaimerSystem.cs index b02212844b..f6abcad7bc 100644 --- a/Content.Server/Materials/MaterialReclaimerSystem.cs +++ b/Content.Server/Materials/MaterialReclaimerSystem.cs @@ -1,31 +1,29 @@ -using Content.Server.Chemistry.Containers.EntitySystems; +using Content.Server.Administration.Logs; using Content.Server.Fluids.EntitySystems; -using Content.Server.GameTicking; +using Content.Server.Ghost; using Content.Server.Popups; -using Content.Server.Power.Components; +using Content.Server.Repairable; using Content.Server.Stack; using Content.Server.Wires; using Content.Shared.Body.Systems; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.EntitySystems; +using Content.Shared.Database; +using Content.Shared.Destructible; +using Content.Shared.Emag.Components; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Materials; using Content.Shared.Mind; using Content.Shared.Nutrition.EntitySystems; +using Content.Shared.Power; using Robust.Server.GameObjects; using Robust.Shared.Player; +using Robust.Shared.Prototypes; using Robust.Shared.Utility; using System.Linq; -using Content.Server.Administration.Logs; -using Content.Server.Repairable; -using Content.Shared.Database; -using Content.Shared.Destructible; -using Content.Shared.Emag.Components; -using Content.Shared.Power; -using Robust.Shared.Prototypes; namespace Content.Server.Materials; @@ -34,7 +32,7 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem { [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly AppearanceSystem _appearance = default!; - [Dependency] private readonly GameTicker _ticker = default!; + [Dependency] private readonly GhostSystem _ghostSystem = default!; [Dependency] private readonly MaterialStorageSystem _materialStorage = default!; [Dependency] private readonly OpenableSystem _openable = default!; [Dependency] private readonly PopupSystem _popup = default!; @@ -99,7 +97,7 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem if (TryComp(victim, out ActorComponent? actor) && _mind.TryGetMind(actor.PlayerSession, out var mindId, out var mind)) { - _ticker.OnGhostAttempt(mindId, false, mind: mind); + _ghostSystem.OnGhostAttempt(mindId, false, mind: mind); if (mind.OwnedEntity is { Valid: true } suicider) { _popup.PopupEntity(Loc.GetString("recycler-component-suicide-message"), suicider); diff --git a/Content.Server/Mind/MindSystem.cs b/Content.Server/Mind/MindSystem.cs index 4271d76b44..c3e29cc363 100644 --- a/Content.Server/Mind/MindSystem.cs +++ b/Content.Server/Mind/MindSystem.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using Content.Server.Administration.Logs; using Content.Server.GameTicking; using Content.Server.Ghost; @@ -13,6 +12,7 @@ using Robust.Server.Player; using Robust.Shared.Network; using Robust.Shared.Player; using Robust.Shared.Utility; +using System.Diagnostics.CodeAnalysis; namespace Content.Server.Mind; @@ -194,7 +194,7 @@ public sealed class MindSystem : SharedMindSystem component = EnsureComp(entity.Value); if (component.HasMind) - _gameTicker.OnGhostAttempt(component.Mind.Value, false); + _ghosts.OnGhostAttempt(component.Mind.Value, false); if (TryComp(entity.Value, out var actor)) { diff --git a/Content.Server/Morgue/CrematoriumSystem.cs b/Content.Server/Morgue/CrematoriumSystem.cs index f6859b610a..656457dc98 100644 --- a/Content.Server/Morgue/CrematoriumSystem.cs +++ b/Content.Server/Morgue/CrematoriumSystem.cs @@ -1,4 +1,4 @@ -using Content.Server.GameTicking; +using Content.Server.Ghost; using Content.Server.Morgue.Components; using Content.Server.Storage.Components; using Content.Server.Storage.EntitySystems; @@ -13,8 +13,6 @@ using Content.Shared.Standing; using Content.Shared.Storage; using Content.Shared.Storage.Components; using Content.Shared.Verbs; -using Robust.Server.GameObjects; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.Player; @@ -25,7 +23,7 @@ public sealed class CrematoriumSystem : EntitySystem { [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly GameTicker _ticker = default!; + [Dependency] private readonly GhostSystem _ghostSystem = default!; [Dependency] private readonly EntityStorageSystem _entityStorage = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly StandingStateSystem _standing = default!; @@ -154,7 +152,7 @@ public sealed class CrematoriumSystem : EntitySystem var victim = args.Victim; if (TryComp(victim, out ActorComponent? actor) && _minds.TryGetMind(victim, out var mindId, out var mind)) { - _ticker.OnGhostAttempt(mindId, false, mind: mind); + _ghostSystem.OnGhostAttempt(mindId, false, mind: mind); if (mind.OwnedEntity is { Valid: true } entity) {