using Content.Shared.Doors.Components; using Content.Shared.Doors.Systems; using Content.Shared.SprayPainter.Prototypes; using Robust.Client.Animations; using Robust.Client.GameObjects; using Robust.Shared.Prototypes; namespace Content.Client.Doors; public sealed class DoorSystem : SharedDoorSystem { [Dependency] private readonly AnimationPlayerSystem _animationSystem = default!; [Dependency] private readonly IComponentFactory _componentFactory = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SpriteSystem _sprite = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnAppearanceChange); } protected override void OnComponentInit(Entity ent, ref ComponentInit args) { var comp = ent.Comp; comp.OpenSpriteStates = new List<(DoorVisualLayers, string)>(2); comp.ClosedSpriteStates = new List<(DoorVisualLayers, string)>(2); comp.OpenSpriteStates.Add((DoorVisualLayers.Base, comp.OpenSpriteState)); comp.ClosedSpriteStates.Add((DoorVisualLayers.Base, comp.ClosedSpriteState)); comp.OpeningAnimation = new Animation { Length = TimeSpan.FromSeconds(comp.OpeningAnimationTime), AnimationTracks = { new AnimationTrackSpriteFlick { LayerKey = DoorVisualLayers.Base, KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.OpeningSpriteState, 0f), }, }, }, }; comp.ClosingAnimation = new Animation { Length = TimeSpan.FromSeconds(comp.ClosingAnimationTime), AnimationTracks = { new AnimationTrackSpriteFlick { LayerKey = DoorVisualLayers.Base, KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.ClosingSpriteState, 0f), }, }, }, }; comp.EmaggingAnimation = new Animation { Length = TimeSpan.FromSeconds(comp.EmaggingAnimationTime), AnimationTracks = { new AnimationTrackSpriteFlick { LayerKey = DoorVisualLayers.BaseUnlit, KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.EmaggingSpriteState, 0f), }, }, }, }; } private void OnAppearanceChange(Entity entity, ref AppearanceChangeEvent args) { if (args.Sprite == null) return; if (!AppearanceSystem.TryGetData(entity, DoorVisuals.State, out var state, args.Component)) state = DoorState.Closed; if (AppearanceSystem.TryGetData(entity, PaintableVisuals.Prototype, out var prototype, args.Component)) UpdateSpriteLayers((entity.Owner, args.Sprite), prototype); if (_animationSystem.HasRunningAnimation(entity, DoorComponent.AnimationKey)) _animationSystem.Stop(entity.Owner, DoorComponent.AnimationKey); UpdateAppearanceForDoorState(entity, args.Sprite, state); } private void UpdateAppearanceForDoorState(Entity entity, SpriteComponent sprite, DoorState state) { _sprite.SetDrawDepth((entity.Owner, sprite), state is DoorState.Open ? entity.Comp.OpenDrawDepth : entity.Comp.ClosedDrawDepth); switch (state) { case DoorState.Open: foreach (var (layer, layerState) in entity.Comp.OpenSpriteStates) { _sprite.LayerSetRsiState((entity.Owner, sprite), layer, layerState); } return; case DoorState.Closed: foreach (var (layer, layerState) in entity.Comp.ClosedSpriteStates) { _sprite.LayerSetRsiState((entity.Owner, sprite), layer, layerState); } return; case DoorState.Opening: if (entity.Comp.OpeningAnimationTime == 0.0) return; _animationSystem.Play(entity, (Animation)entity.Comp.OpeningAnimation, DoorComponent.AnimationKey); return; case DoorState.Closing: if (entity.Comp.ClosingAnimationTime == 0.0 || entity.Comp.CurrentlyCrushing.Count != 0) return; _animationSystem.Play(entity, (Animation)entity.Comp.ClosingAnimation, DoorComponent.AnimationKey); return; case DoorState.Denying: _animationSystem.Play(entity, (Animation)entity.Comp.DenyingAnimation, DoorComponent.AnimationKey); return; case DoorState.Emagging: _animationSystem.Play(entity, (Animation)entity.Comp.EmaggingAnimation, DoorComponent.AnimationKey); return; } } private void UpdateSpriteLayers(Entity sprite, string targetProto) { if (!_prototypeManager.Resolve(targetProto, out var target)) return; if (!target.TryGetComponent(out SpriteComponent? targetSprite, _componentFactory)) return; _sprite.SetBaseRsi(sprite.AsNullable(), targetSprite.BaseRSI); } }