From c3e339f747dc53d4a00fe9a6060316f9162b9117 Mon Sep 17 00:00:00 2001 From: Tenteratus <143085120+Tenteratus@users.noreply.github.com> Date: Wed, 19 Jun 2024 20:59:36 +0300 Subject: [PATCH] Night vision (#370) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit система ночного зрения --- .../Eye/NightVision/NightVisionOverlay.cs | 86 +++++++++++++++++++ .../Eye/NightVision/NightVisionSystem.cs | 47 ++++++++++ .../Inventory/InventorySystem.Relay.cs | 5 ++ .../Components/NightVisionComponent.cs | 35 ++++++++ .../NightVision/Components/PNVComponent.cs | 14 +++ .../NightVision/Systems/NightVisionSystem.cs | 79 +++++++++++++++++ .../Eye/NightVision/Systems/PNVSystem.cs | 68 +++++++++++++++ .../Prototypes/Starshine/Actions/PNV.yml | 12 +++ 8 files changed, 346 insertions(+) create mode 100644 Content.Client/Starshine/Eye/NightVision/NightVisionOverlay.cs create mode 100644 Content.Client/Starshine/Eye/NightVision/NightVisionSystem.cs create mode 100644 Content.Shared/Starshine/Eye/NightVision/Components/NightVisionComponent.cs create mode 100644 Content.Shared/Starshine/Eye/NightVision/Components/PNVComponent.cs create mode 100644 Content.Shared/Starshine/Eye/NightVision/Systems/NightVisionSystem.cs create mode 100644 Content.Shared/Starshine/Eye/NightVision/Systems/PNVSystem.cs create mode 100644 Resources/Prototypes/Starshine/Actions/PNV.yml diff --git a/Content.Client/Starshine/Eye/NightVision/NightVisionOverlay.cs b/Content.Client/Starshine/Eye/NightVision/NightVisionOverlay.cs new file mode 100644 index 00000000000000..7feb507c5e1c19 --- /dev/null +++ b/Content.Client/Starshine/Eye/NightVision/NightVisionOverlay.cs @@ -0,0 +1,86 @@ +using Content.Shared.Starshine.Eye.NightVision.Components; //creater - vladospupuos +using Robust.Client.Graphics; +using Robust.Client.Player; +using Robust.Shared.Enums; +using Robust.Shared.Prototypes; + +namespace Content.Client.GG.Eye.NightVision +{ + public sealed class NightVisionOverlay : Overlay + { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly ILightManager _lightManager = default!; + + + public override bool RequestScreenTexture => true; + public override OverlaySpace Space => OverlaySpace.WorldSpace; + private readonly ShaderInstance _greyscaleShader; + public Color NightvisionColor = Color.Green; + + private NightVisionComponent _nightvisionComponent = default!; + + public NightVisionOverlay(Color color) + { + IoCManager.InjectDependencies(this); + _greyscaleShader = _prototypeManager.Index("GreyscaleFullscreen").InstanceUnique(); + + NightvisionColor = color; + } + protected override bool BeforeDraw(in OverlayDrawArgs args) + { + if (!_entityManager.TryGetComponent(_playerManager.LocalSession?.AttachedEntity, out EyeComponent? eyeComp)) + return false; + + if (args.Viewport.Eye != eyeComp.Eye) + return false; + + var playerEntity = _playerManager.LocalSession?.AttachedEntity; + + if (playerEntity == null) + return false; + + if (!_entityManager.TryGetComponent(playerEntity, out var nightvisionComp)) + return false; + + _nightvisionComponent = nightvisionComp; + + var nightvision = _nightvisionComponent.IsNightVision; + + if (!nightvision && _nightvisionComponent.DrawShadows) // Disable our Night Vision + { + _lightManager.DrawLighting = true; + _nightvisionComponent.DrawShadows = false; + _nightvisionComponent.GraceFrame = true; + return true; + } + + return nightvision; + } + + protected override void Draw(in OverlayDrawArgs args) + { + if (ScreenTexture == null) + return; + + if (!_nightvisionComponent.GraceFrame) + { + _nightvisionComponent.DrawShadows = true; // Enable our Night Vision + _lightManager.DrawLighting = false; + } + else + { + _nightvisionComponent.GraceFrame = false; + } + + _greyscaleShader?.SetParameter("SCREEN_TEXTURE", ScreenTexture); + + var worldHandle = args.WorldHandle; + var viewport = args.WorldBounds; + worldHandle.UseShader(_greyscaleShader); + worldHandle.DrawRect(viewport, NightvisionColor); + worldHandle.UseShader(null); + } + } +} diff --git a/Content.Client/Starshine/Eye/NightVision/NightVisionSystem.cs b/Content.Client/Starshine/Eye/NightVision/NightVisionSystem.cs new file mode 100644 index 00000000000000..490db00dacf0b8 --- /dev/null +++ b/Content.Client/Starshine/Eye/NightVision/NightVisionSystem.cs @@ -0,0 +1,47 @@ +using Content.Client.Overlays; +using Content.Shared.GameTicking; +using Content.Shared.Starshine.Eye.NightVision.Components; +using Content.Shared.Inventory.Events; +using Robust.Client.Graphics; +using Robust.Client.Player; +using Robust.Shared.Player; + +namespace Content.Client.GG.Eye.NightVision; + +public sealed class NightVisionSystem : EquipmentHudSystem +{ + [Dependency] private readonly IOverlayManager _overlayMan = default!; + [Dependency] private readonly ILightManager _lightManager = default!; + + + private NightVisionOverlay _overlay = default!; + + public override void Initialize() + { + base.Initialize(); + + _overlay = new(Color.Green); + } + + protected override void UpdateInternal(RefreshEquipmentHudEvent component) + { + base.UpdateInternal(component); + + foreach (var comp in component.Components) + { + _overlay.NightvisionColor = comp.NightVisionColor; + } + if (!_overlayMan.HasOverlay()) + { + _overlayMan.AddOverlay(_overlay); + } + _lightManager.DrawLighting = false; + } + + protected override void DeactivateInternal() + { + base.DeactivateInternal(); + _overlayMan.RemoveOverlay(_overlay); + _lightManager.DrawLighting = true; + } +} diff --git a/Content.Shared/Inventory/InventorySystem.Relay.cs b/Content.Shared/Inventory/InventorySystem.Relay.cs index ea368884e0506a..acdfec18b8aa11 100644 --- a/Content.Shared/Inventory/InventorySystem.Relay.cs +++ b/Content.Shared/Inventory/InventorySystem.Relay.cs @@ -7,6 +7,7 @@ using Content.Shared.IdentityManagement.Components; using Content.Shared.Inventory.Events; using Content.Shared.Movement.Systems; +using Content.Shared.Starshine.Eye.NightVision.Systems; // NightVision using Content.Shared.Overlays; using Content.Shared.Radio; using Content.Shared.Slippery; @@ -39,6 +40,10 @@ public void InitializeRelay() SubscribeLocalEvent(RelayInventoryEvent); SubscribeLocalEvent(RelayInventoryEvent); + // NightVision-Start + SubscribeLocalEvent(RelayInventoryEvent); + // NightVision-End + // ComponentActivatedClientSystems SubscribeLocalEvent>(RelayInventoryEvent); SubscribeLocalEvent>(RelayInventoryEvent); diff --git a/Content.Shared/Starshine/Eye/NightVision/Components/NightVisionComponent.cs b/Content.Shared/Starshine/Eye/NightVision/Components/NightVisionComponent.cs new file mode 100644 index 00000000000000..3e88efc1454fd6 --- /dev/null +++ b/Content.Shared/Starshine/Eye/NightVision/Components/NightVisionComponent.cs @@ -0,0 +1,35 @@ +using Content.Shared.Actions; +using Content.Shared.Starshine.Eye.NightVision.Systems; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Starshine.Eye.NightVision.Components; + +[RegisterComponent] +[NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(NightVisionSystem))] +public sealed partial class NightVisionComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite), DataField("isOn"), AutoNetworkedField] + public bool IsNightVision; + + [DataField("color")] + public Color NightVisionColor = Color.Green; + + [DataField] + public bool IsToggle = false; + + [DataField] public EntityUid? ActionContainer; + + [Access(Other = AccessPermissions.ReadWriteExecute)] + public bool DrawShadows = false; + + [Access(Other = AccessPermissions.ReadWriteExecute)] + public bool GraceFrame = false; + + [DataField("playSoundOn")] + public bool PlaySoundOn = true; + public SoundSpecifier OnOffSound = new SoundPathSpecifier("/Audio/Backmen/Misc/night-vision-sound-effect_E_minor.ogg"); +} + +public sealed partial class NVInstantActionEvent : InstantActionEvent { } diff --git a/Content.Shared/Starshine/Eye/NightVision/Components/PNVComponent.cs b/Content.Shared/Starshine/Eye/NightVision/Components/PNVComponent.cs new file mode 100644 index 00000000000000..08a1bca44dafa2 --- /dev/null +++ b/Content.Shared/Starshine/Eye/NightVision/Components/PNVComponent.cs @@ -0,0 +1,14 @@ +using Content.Shared.Actions; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Starshine.Eye.NightVision.Components; + + +[RegisterComponent, NetworkedComponent] +public sealed partial class PNVComponent : Component +{ + [DataField] public EntProtoId ActionProto = "NVToggleAction"; + [DataField] public EntityUid? ActionContainer; +} diff --git a/Content.Shared/Starshine/Eye/NightVision/Systems/NightVisionSystem.cs b/Content.Shared/Starshine/Eye/NightVision/Systems/NightVisionSystem.cs new file mode 100644 index 00000000000000..5786269320923d --- /dev/null +++ b/Content.Shared/Starshine/Eye/NightVision/Systems/NightVisionSystem.cs @@ -0,0 +1,79 @@ +using Content.Shared.Starshine.Eye.NightVision.Components; +using Content.Shared.Inventory; +using Content.Shared.Actions; +using JetBrains.Annotations; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Network; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Starshine.Eye.NightVision.Systems; + +public sealed class NightVisionSystem : EntitySystem +{ + [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly INetManager _net = default!; + + public override void Initialize() + { + base.Initialize(); + + if(_net.IsServer) + SubscribeLocalEvent(OnComponentStartup); + SubscribeLocalEvent(OnActionToggle); + } + + [ValidatePrototypeId] + private const string SwitchNightVisionAction = "SwitchNightVision"; + + private void OnComponentStartup(EntityUid uid, NightVisionComponent component, ComponentStartup args) + { + if (component.IsToggle) + _actionsSystem.AddAction(uid, ref component.ActionContainer, SwitchNightVisionAction); + } + + private void OnActionToggle(EntityUid uid, NightVisionComponent component, NVInstantActionEvent args) + { + component.IsNightVision = !component.IsNightVision; + var changeEv = new NightVisionnessChangedEvent(component.IsNightVision); + RaiseLocalEvent(uid, ref changeEv); + Dirty(uid, component); + _actionsSystem.SetCooldown(component.ActionContainer, TimeSpan.FromSeconds(1)); + if (component is { IsNightVision: true, PlaySoundOn: true }) + { + if(_net.IsServer) + _audioSystem.PlayPvs(component.OnOffSound, uid); + } + } + + [PublicAPI] + public void UpdateIsNightVision(EntityUid uid, NightVisionComponent? component = null) + { + if (!Resolve(uid, ref component, false)) + return; + + var old = component.IsNightVision; + + + var ev = new CanVisionAttemptEvent(); + RaiseLocalEvent(uid, ev); + component.IsNightVision = ev.NightVision; + + if (old == component.IsNightVision) + return; + + var changeEv = new NightVisionnessChangedEvent(component.IsNightVision); + RaiseLocalEvent(uid, ref changeEv); + Dirty(uid, component); + } +} + +[ByRefEvent] +public record struct NightVisionnessChangedEvent(bool NightVision); + + +public sealed class CanVisionAttemptEvent : CancellableEntityEventArgs, IInventoryRelayEvent +{ + public bool NightVision => Cancelled; + public SlotFlags TargetSlots => SlotFlags.EYES | SlotFlags.MASK | SlotFlags.HEAD; +} diff --git a/Content.Shared/Starshine/Eye/NightVision/Systems/PNVSystem.cs b/Content.Shared/Starshine/Eye/NightVision/Systems/PNVSystem.cs new file mode 100644 index 00000000000000..7276a1900cb29d --- /dev/null +++ b/Content.Shared/Starshine/Eye/NightVision/Systems/PNVSystem.cs @@ -0,0 +1,68 @@ +using Content.Shared.Starshine.Eye.NightVision.Components; +using Content.Shared.Inventory; +using Content.Shared.Actions; +using Content.Shared.Inventory.Events; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Network; + +namespace Content.Shared.Starshine.Eye.NightVision.Systems; + +public sealed class PNVSystem : EntitySystem +{ + [Dependency] private readonly NightVisionSystem _nightvisionableSystem = default!; + [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly INetManager _net = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnEquipped); + SubscribeLocalEvent(OnUnequipped); + SubscribeLocalEvent>(OnPNVTrySee); + } + + private void OnPNVTrySee(EntityUid uid, PNVComponent component, InventoryRelayedEvent args) + { + args.Args.Cancel(); + } + + private void OnEquipped(EntityUid uid, PNVComponent component, GotEquippedEvent args) + { + if (args.Slot is not ("eyes" or "mask" or "head")) + return; + + if (HasComp(args.Equipee)) + return; + + var nvcomp = EnsureComp(args.Equipee); + + _nightvisionableSystem.UpdateIsNightVision(args.Equipee, nvcomp); + if(component.ActionContainer == null) + _actionsSystem.AddAction(args.Equipee, ref component.ActionContainer, component.ActionProto); + _actionsSystem.SetCooldown(component.ActionContainer, TimeSpan.FromSeconds(1)); // GCD? + + if (nvcomp.PlaySoundOn) + { + if(_net.IsServer) + _audioSystem.PlayPvs(nvcomp.OnOffSound, uid); + } + + } + + private void OnUnequipped(EntityUid uid, PNVComponent component, GotUnequippedEvent args) + { + if (args.Slot is not ("eyes" or "mask" or "head")) + return; + + if (!TryComp(args.Equipee, out var nvcomp)) + return; + + _nightvisionableSystem.UpdateIsNightVision(args.Equipee, nvcomp); + _actionsSystem.RemoveAction(args.Equipee, component.ActionContainer); + component.ActionContainer = null; + + RemCompDeferred(args.Equipee); + } +} diff --git a/Resources/Prototypes/Starshine/Actions/PNV.yml b/Resources/Prototypes/Starshine/Actions/PNV.yml new file mode 100644 index 00000000000000..1842ea8bf536e7 --- /dev/null +++ b/Resources/Prototypes/Starshine/Actions/PNV.yml @@ -0,0 +1,12 @@ +- type: entity + id: SwitchNightVision + name: switch night vision + description: Switches night vision + noSpawn: true + components: + - type: InstantAction + useDelay: 2.5 + icon: + sprite: Clothing/Eyes/Glasses/ninjavisor.rsi + state: icon + event: !type:NVInstantActionEvent