From 187a653d686a842e597e5d6ff49d004149b1c08e Mon Sep 17 00:00:00 2001 From: Anri Date: Fri, 2 Aug 2024 01:12:03 +0300 Subject: [PATCH] Thermals fix (#1474) * BugFixAndRefactor * BugFix * Licence * FixFixFix * BalanceMoment * CommentFix * QoLAddition * FixIfIssue * Update Content.Client/SS220/Overlays/IgnoreLightVisionOverlay.cs Co-authored-by: Dexler <69513582+DexlerXD@users.noreply.github.com> --------- Co-authored-by: Dexler <69513582+DexlerXD@users.noreply.github.com> --- .../Overlays/IgnoreLightVisionOverlay.cs | 176 ++++++++++++++++++ .../SS220/Overlays/ThermalVisionOverlay.cs | 28 +++ .../SS220/Thermals/ThermalVisionOverlay.cs | 93 --------- .../SS220/Thermals/ThermalVisionSystem.cs | 1 + Content.Server/Mindshield/MindShieldSystem.cs | 12 -- .../ThermalVisionClothingComponent.cs | 2 +- .../Thermals/ThermalVisionImplantComponent.cs | 2 +- .../Thermals/ThermalVisionImplantSystem.cs | 21 ++- Resources/Locale/ru-RU/clothing/glasses.ftl | 8 - .../ru-RU/ss220/clothing/Eyes/glasses.ftl | 9 + .../ThermalVisionProto.yml | 4 +- .../ThermalVisionAction.yml | 6 +- .../SS220/Recipes/Lathes/devices.yml | 16 +- 13 files changed, 241 insertions(+), 137 deletions(-) create mode 100644 Content.Client/SS220/Overlays/IgnoreLightVisionOverlay.cs create mode 100644 Content.Client/SS220/Overlays/ThermalVisionOverlay.cs delete mode 100644 Content.Client/SS220/Thermals/ThermalVisionOverlay.cs delete mode 100644 Resources/Locale/ru-RU/clothing/glasses.ftl diff --git a/Content.Client/SS220/Overlays/IgnoreLightVisionOverlay.cs b/Content.Client/SS220/Overlays/IgnoreLightVisionOverlay.cs new file mode 100644 index 000000000000..d9295ef52e74 --- /dev/null +++ b/Content.Client/SS220/Overlays/IgnoreLightVisionOverlay.cs @@ -0,0 +1,176 @@ +// Original code github.com/CM-14 Licence MIT, EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt +using System.Numerics; +using Content.Shared.SS220.Thermals; +using Content.Shared.Mobs.Components; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.Player; +using Robust.Shared.Enums; +using Robust.Shared.Map; +using System.Diagnostics.CodeAnalysis; +using Content.Shared.Mobs; +using Content.Shared.Stealth.Components; +using Content.Client.Stealth; + +namespace Content.Client.SS220.Overlays; + +public abstract class IgnoreLightVisionOverlay : Overlay +{ + [Dependency] protected readonly IEntityManager Entity = default!; + [Dependency] protected readonly IPlayerManager PlayerManager = default!; + [Dependency] private readonly IComponentFactory _componentFactory = default!; + + /// Defines radius in which you can see entities in containers + protected float ShowCloseRadius; + protected float ShowRadius; + + private readonly ContainerSystem _container; + private readonly EntityLookupSystem _entityLookup; + private readonly StealthSystem _stealthSystem; + /// If use lesser value wierd thing happens with admin spawn menu and GetEntitiesInRange. + private const float MIN_CLOSE_RANGE = 1.5f; + /// Useless const due to how stealth work, but if they change it... + private const float STEALTH_VISION_TRESHHOLD = 0; + public override OverlaySpace Space => OverlaySpace.WorldSpace; + + public IgnoreLightVisionOverlay(float showRadius) + { + IoCManager.InjectDependencies(this); + + _container = Entity.System(); + _entityLookup = Entity.System(); + _stealthSystem = Entity.System(); + + ShowRadius = showRadius < MIN_CLOSE_RANGE ? MIN_CLOSE_RANGE : showRadius; + ShowCloseRadius = ShowRadius / 4 < MIN_CLOSE_RANGE ? MIN_CLOSE_RANGE : ShowRadius / 4; + } + protected override void Draw(in OverlayDrawArgs args) + { + if (PlayerManager.LocalEntity == null) + return; + if (!Entity.TryGetComponent(PlayerManager.LocalEntity, out var mobstateComp)) + return; + if (mobstateComp.CurrentState != MobState.Alive) + return; + if (!Entity.TryGetComponent(PlayerManager.LocalEntity, out ThermalVisionComponent? thermalVision) || + thermalVision.State == ThermalVisionState.Off) + return; + + if (!Entity.TryGetComponent(PlayerManager.LocalEntity, + out var playerTransform)) + return; // maybe need to log it + + var handle = args.WorldHandle; + var eye = args.Viewport.Eye; + var eyeRot = eye?.Rotation ?? default; + + var entities = _entityLookup.GetEntitiesInRange(playerTransform.Coordinates, ShowRadius); + var entitiesClose = _entityLookup.GetEntitiesInRange(playerTransform.Coordinates, ShowCloseRadius); + + foreach (var (uid, stateComp) in entities) + { + var isCloseToOwner = entitiesClose.Contains((uid, stateComp)); + + if (CantBeRendered(uid, out var sprite, out var xform)) + continue; + if (CantBeSeenByThermals((uid, stateComp))) + continue; + if (IsStealthToThermals(uid, isCloseToOwner)) + continue; + if (_container.IsEntityOrParentInContainer(uid)) + if (CantBeVisibleInContainer(uid, isCloseToOwner)) + continue; + + Render((uid, sprite, xform), eye?.Position.MapId, handle, eyeRot); + } + handle.SetTransform(Matrix3x2.Identity); + } + protected abstract void Render(Entity ent, + MapId? map, DrawingHandleWorld handle, Angle eyeRot); + /// + /// function wich defines what entities can be seen, f.e. pai or human, bread dog or reaper + /// Also contains list of components which defines it + /// + /// True if entities could be seen by thermals. Without any other obstacles + private bool CantBeSeenByThermals(Entity target) + { + var states = target.Comp.AllowedStates; + + if (states.Contains(MobState.Dead) && + states.Contains(MobState.Alive) && + target.Comp.CurrentState == MobState.Dead) + return true; + else + return false; + + return true; + } + private bool CantBeRendered(EntityUid target, [NotNullWhen(false)] out SpriteComponent? sprite, + [NotNullWhen(false)] out TransformComponent? xform) + { + sprite = null; + xform = null; + + if (!Entity.TryGetComponent(target, out sprite)) + return true; + if (!Entity.TryGetComponent(target, out xform)) + return true; + + return false; + } + /// + /// function wich defines what entities visible or not. + /// Also contains const values of invis perception + /// + /// True if entities could be seen by thermals. Without any other obstacles + private bool IsStealthToThermals(EntityUid target, bool isCloseToOwner) + { + if (!Entity.TryGetComponent(target, out var component)) + return false; + + if (!isCloseToOwner && + _stealthSystem.GetVisibility(target, component) < STEALTH_VISION_TRESHHOLD) + return true; + + return false; + } + /// function wich defines what entities visible or not. + /// Also contains const values of invis perception + /// True if entities could be seen by thermals. Without any other obstacles + private bool CantBeVisibleInContainer(EntityUid target, bool isCloseToOwner) + { + var blacklistComponentNames = new List() { "DarkReaper", "Devourer" }; + + if (isCloseToOwner == false) + return true; + + var currentEntUid = target; + while (_container.TryGetContainingContainer((currentEntUid, null, null), out var container)) + { + currentEntUid = container.Owner; + + if (currentEntUid == PlayerManager.LocalEntity ) + return true; + if (HasComponentFromList(currentEntUid, blacklistComponentNames)) + return true; + } + + return false; + } + /// Checks if entity has a components from list + /// True if entity has any of the listed components + /// Throw excep if List contains false comp name + private bool HasComponentFromList(EntityUid target, List blacklistComponentNames) + { + foreach (var compName in blacklistComponentNames) + { + if (!_componentFactory.TryGetRegistration(compName, out var compReg)) + throw new Exception($"Cant find registration for component {compName} in blacklistComponents"); + + if (Entity.HasComponent(target, compReg.Type)) + return true; + } + return false; + } + +} diff --git a/Content.Client/SS220/Overlays/ThermalVisionOverlay.cs b/Content.Client/SS220/Overlays/ThermalVisionOverlay.cs new file mode 100644 index 000000000000..f95744e184db --- /dev/null +++ b/Content.Client/SS220/Overlays/ThermalVisionOverlay.cs @@ -0,0 +1,28 @@ +// Original code github.com/CM-14 Licence MIT, EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt +using Robust.Client.Graphics; +using Robust.Client.GameObjects; +using Robust.Shared.Map; + +namespace Content.Client.SS220.Overlays; + +public sealed class ThermalVisionOverlay : IgnoreLightVisionOverlay +{ + private readonly TransformSystem _transformSystem = default!; + + public ThermalVisionOverlay(float showRadius) : base(showRadius) + { + _transformSystem = Entity.System(); + } + protected override void Render(Entity ent, + MapId? map, DrawingHandleWorld handle, Angle eyeRot) + { + var (uid, sprite, xform) = ent; + if (xform.MapID != map) + return; + + var position = _transformSystem.GetWorldPosition(xform); + var rotation = _transformSystem.GetWorldRotation(xform); + + sprite.Render(handle, eyeRot, rotation, position: position); + } +} diff --git a/Content.Client/SS220/Thermals/ThermalVisionOverlay.cs b/Content.Client/SS220/Thermals/ThermalVisionOverlay.cs deleted file mode 100644 index 962365c8ba54..000000000000 --- a/Content.Client/SS220/Thermals/ThermalVisionOverlay.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Original code github.com/CM-14 Licence MIT, EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt -using System.Numerics; -using Content.Shared.SS220.Thermals; -using Content.Shared.Mobs.Components; -using Robust.Client.GameObjects; -using Robust.Client.Graphics; -using Robust.Client.Player; -using Robust.Shared.Enums; -using Robust.Shared.Map; -using Robust.Shared.Prototypes; -using Serilog; -using Robust.Client.ComponentTrees; - -namespace Content.Client.SS220.Thermals; - -public sealed class ThermalVisionOverlay : Overlay -{ - [Dependency] private readonly IEntityManager _entity = default!; - [Dependency] private readonly IPlayerManager _playerManager = default!; - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - - private readonly ContainerSystem _container; - private readonly TransformSystem _transform; - private readonly EntityLookupSystem _entityLookup; - private readonly float _showRadius; - private readonly float _showCloseRadius; - private const float MIN_RANGE = 0.3f; - public override OverlaySpace Space => OverlaySpace.WorldSpace; - - public ThermalVisionOverlay(float showRadius) - { - IoCManager.InjectDependencies(this); - - _container = _entity.System(); - _transform = _entity.System(); - _entityLookup = _entity.System(); - - _showRadius = showRadius; - _showCloseRadius = _showRadius / 4 < MIN_RANGE ? MIN_RANGE : _showRadius / 4; - } - - protected override void Draw(in OverlayDrawArgs args) - { - if (_playerManager.LocalEntity == null) - return; - - if (!_entity.TryGetComponent(_playerManager.LocalEntity, out ThermalVisionComponent? thermalVision) || - thermalVision.State == ThermalVisionState.Off) - return; - - if (_entity.TryGetComponent(_playerManager.LocalEntity, - out var playerTransform) == false) - return; // maybe need to log it - var handle = args.WorldHandle; - var eye = args.Viewport.Eye; - var eyeRot = eye?.Rotation ?? default; - - if (_showRadius < MIN_RANGE) - return; // can cause execp also need to log it - - var entities = _entityLookup.GetEntitiesInRange(playerTransform.Coordinates, _showRadius); - var entitiesClose = _entityLookup.GetEntitiesInRange(playerTransform.Coordinates, _showCloseRadius); - - foreach (var (uid, stateComp) in entities) - { - if (_entity.TryGetComponent(uid, out var sprite) == false) - continue; - if (_entity.TryGetComponent(uid, out var xform) == false) - continue; - if (_container.IsEntityOrParentInContainer(uid) - && entitiesClose.Contains((uid, stateComp)) == false) - continue; - - Render((uid, sprite, xform), eye?.Position.MapId, handle, eyeRot); - } - handle.SetTransform(Matrix3x2.Identity); - } - - private void Render(Entity ent, - MapId? map, DrawingHandleWorld handle, Angle eyeRot) - { - var (uid, sprite, xform) = ent; - if (xform.MapID != map) - return; - - - - var position = _transform.GetWorldPosition(xform); - var rotation = _transform.GetWorldRotation(xform); - - sprite.Render(handle, eyeRot, rotation, position: position); - } -} diff --git a/Content.Client/SS220/Thermals/ThermalVisionSystem.cs b/Content.Client/SS220/Thermals/ThermalVisionSystem.cs index c046073eb894..6fb2c4f3182c 100644 --- a/Content.Client/SS220/Thermals/ThermalVisionSystem.cs +++ b/Content.Client/SS220/Thermals/ThermalVisionSystem.cs @@ -1,5 +1,6 @@ // Original code github.com/CM-14 Licence MIT, All edits under © SS220, EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt using Content.Shared.SS220.Thermals; +using Content.Client.SS220.Overlays; using Robust.Client.Graphics; using Robust.Client.Player; using Robust.Shared.Player; diff --git a/Content.Server/Mindshield/MindShieldSystem.cs b/Content.Server/Mindshield/MindShieldSystem.cs index 7771ef0007ac..7d962da2ac9e 100644 --- a/Content.Server/Mindshield/MindShieldSystem.cs +++ b/Content.Server/Mindshield/MindShieldSystem.cs @@ -9,7 +9,6 @@ using Content.Shared.Mindshield.Components; using Content.Shared.Revolutionary.Components; using Content.Shared.Tag; -using Content.Server.SS220.Thermals; namespace Content.Server.Mindshield; @@ -33,10 +32,6 @@ public sealed class MindShieldSystem : EntitySystem [ValidatePrototypeId] public const string MindSlaveTag = "MindSlave"; //SS220-mindslave end - //SS220 Thermal implant begin - [ValidatePrototypeId] - public const string ThermalImplantTag = "ThermalImplant"; - //SS220 Thermal implant ends public override void Initialize() { @@ -62,13 +57,6 @@ public void ImplantCheck(EntityUid uid, SubdermalImplantComponent comp, ref Impl _sharedSubdermalImplant.ForceRemove(ev.Implanted.Value, ev.Implant); } //SS220-mindslave end - //SS220 Thermalvisionimplant begins - if (_tag.HasTag(ev.Implant, ThermalImplantTag) && ev.Implanted != null) - { - EnsureComp(ev.Implanted.Value); - } - // else (_tag.HasTag(ev.Implant, ThermalImplantTag) && ev.Implanted != null) - //SS220 Thermalvisionimplant ends } /// diff --git a/Content.Server/SS220/Thermals/ThermalVisionClothingComponent.cs b/Content.Server/SS220/Thermals/ThermalVisionClothingComponent.cs index a046d32b739e..be1202586484 100644 --- a/Content.Server/SS220/Thermals/ThermalVisionClothingComponent.cs +++ b/Content.Server/SS220/Thermals/ThermalVisionClothingComponent.cs @@ -9,6 +9,6 @@ namespace Content.Server.SS220.Thermals; [RegisterComponent] public sealed partial class ThermalVisionClothingComponent : Component { - [DataField, ViewVariables] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float ThermalVisionRadius = 8f; } diff --git a/Content.Server/SS220/Thermals/ThermalVisionImplantComponent.cs b/Content.Server/SS220/Thermals/ThermalVisionImplantComponent.cs index f441689986c3..c68ce5bc2127 100644 --- a/Content.Server/SS220/Thermals/ThermalVisionImplantComponent.cs +++ b/Content.Server/SS220/Thermals/ThermalVisionImplantComponent.cs @@ -10,7 +10,7 @@ namespace Content.Server.SS220.Thermals; public sealed partial class ThermalVisionImplantComponent : Component { [DataField] - public bool IsAcive = false; + public bool IsActive = false; [DataField, ViewVariables] public float ThermalVisionRadius = 8f; } diff --git a/Content.Server/SS220/Thermals/ThermalVisionImplantSystem.cs b/Content.Server/SS220/Thermals/ThermalVisionImplantSystem.cs index f8f04b6957eb..af60b6ed2d5e 100644 --- a/Content.Server/SS220/Thermals/ThermalVisionImplantSystem.cs +++ b/Content.Server/SS220/Thermals/ThermalVisionImplantSystem.cs @@ -1,30 +1,30 @@ //EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt using Content.Shared.SS220.Thermals; - namespace Content.Server.SS220.Thermals; - /// -/// Handles enabling of thermal vision when clothing is equipped and disabling when unequipped. +/// Handles enabling of thermal vision when impanted with thermalVisionImplant. /// public sealed class SharedThermalVisionImplantSystem : EntitySystem { - public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnThermalVisionAction); } - private void OnThermalVisionAction(Entity ent, ref UseThermalVisionEvent args) { - if (!TryComp(args.Performer, out var thermalVisionImpalnt)) + if (ent.Comp.IsActive && + HasComp(args.Performer)) + { + RemComp(args.Performer); + ent.Comp.IsActive = !ent.Comp.IsActive; + args.Handled = true; return; + } - if (HasComp(args.Performer) && thermalVisionImpalnt.IsAcive) - RemComp(args.Performer); - else if (!TryComp(args.Performer, out var thermalVision)) + if (!TryComp(args.Performer, out var thermalVision)) AddComp(args.Performer, new ThermalVisionComponent(ent.Comp.ThermalVisionRadius)); else { @@ -32,6 +32,7 @@ private void OnThermalVisionAction(Entity ent, re Dirty(args.Performer, thermalVision); } - thermalVisionImpalnt.IsAcive = !thermalVisionImpalnt.IsAcive; + ent.Comp.IsActive = !ent.Comp.IsActive; + args.Handled = true; } } diff --git a/Resources/Locale/ru-RU/clothing/glasses.ftl b/Resources/Locale/ru-RU/clothing/glasses.ftl deleted file mode 100644 index 480cf4329b2c..000000000000 --- a/Resources/Locale/ru-RU/clothing/glasses.ftl +++ /dev/null @@ -1,8 +0,0 @@ -ent-ThermalVisorChameleon = очки с термальным визором - .desc = Термальный визор позволяет видеть существ сквозь стены, но в конечном радиусе. Функция хамелеон дополняет этот прекрасный инструмент. - -ent-ThermalVisorRND = термальный визор - .desc = Термальный визор позволяет видеть существ сквозь стены, но в конечном радиусе. - -ent-ClothingEyesThermalGlassesSecurity = термальные очки охраны - .desc = Модернизированные солнцезащитные очки с функцией защиты от вспышек, визором СБ и термальными визорами. diff --git a/Resources/Locale/ru-RU/ss220/clothing/Eyes/glasses.ftl b/Resources/Locale/ru-RU/ss220/clothing/Eyes/glasses.ftl index df894787abab..9d0868fabeb4 100644 --- a/Resources/Locale/ru-RU/ss220/clothing/Eyes/glasses.ftl +++ b/Resources/Locale/ru-RU/ss220/clothing/Eyes/glasses.ftl @@ -1,2 +1,11 @@ ent-ClothingEyesGlassesCentcom = очки Центком .desc = Модернизированные солнцезащитные очки с функцией защиты от вспышек и визором СБ. + +ent-ThermalVisorChameleon = очки с термальным визором + .desc = Термальный визор позволяет видеть существ сквозь стены, но в конечном радиусе. Функция хамелеон дополняет этот прекрасный инструмент. + +ent-ThermalVisorRND = термальный визор + .desc = Термальный визор позволяет видеть существ сквозь стены, но в конечном радиусе. + +ent-ClothingEyesThermalGlassesSecurity = термальные очки охраны + .desc = Модернизированные солнцезащитные очки с функцией защиты от вспышек, визором СБ и термальными визорами. diff --git a/Resources/Prototypes/SS220/Entities/ThermalVisionGoogles/ThermalVisionProto.yml b/Resources/Prototypes/SS220/Entities/ThermalVisionGoogles/ThermalVisionProto.yml index 5968f9a585b6..bb01612b5a6c 100644 --- a/Resources/Prototypes/SS220/Entities/ThermalVisionGoogles/ThermalVisionProto.yml +++ b/Resources/Prototypes/SS220/Entities/ThermalVisionGoogles/ThermalVisionProto.yml @@ -3,7 +3,7 @@ id: ThermalVisorChameleon name: optical thermal chameleon scanner description: Useful both for security and cargonia. - suffix: ThermalGoogles + suffix: Syndicate components: - type: ThermalVisionClothing - type: Sprite @@ -34,6 +34,7 @@ id: ThermalVisorRND name: Advanced Thermal Glasses description: This glasses alows you to see persons through the walls in finate radius + suffix: RND components: - type: ThermalVisionClothing thermalVisionRadius: 5 @@ -48,6 +49,7 @@ id: ClothingEyesThermalGlassesSecurity name: Advanced Security Glasses with SecHUD and Thermal Visor description: This glasses provided with SecHUD and Thermal Visor, which alows you to see persons through the walls in finate radius + suffix: SecRND components: - type: ThermalVisionClothing thermalVisionRadius: 5 diff --git a/Resources/Prototypes/SS220/Entities/ThermalVisionImplant/ThermalVisionAction.yml b/Resources/Prototypes/SS220/Entities/ThermalVisionImplant/ThermalVisionAction.yml index 8df5eb3ec062..074b838e67a3 100644 --- a/Resources/Prototypes/SS220/Entities/ThermalVisionImplant/ThermalVisionAction.yml +++ b/Resources/Prototypes/SS220/Entities/ThermalVisionImplant/ThermalVisionAction.yml @@ -1,7 +1,7 @@ - type: entity id: ActionActivateThermalVision - name: ThermalVision - description: I CAN SEE EVERYTYNG + name: Переключить термальные сенсоры + description: Переключает термальные сенсоры в импланте владельца, что позволяет видеть живых существ сквозь преграды в ограниченном радиусе. noSpawn: true components: - type: InstantAction @@ -11,4 +11,4 @@ sprite: /Textures/SS220/Misc/ThermalEye.rsi state: EyeON event: !type:UseThermalVisionEvent - useDelay: 4 \ No newline at end of file + useDelay: 1 diff --git a/Resources/Prototypes/SS220/Recipes/Lathes/devices.yml b/Resources/Prototypes/SS220/Recipes/Lathes/devices.yml index d5d1c9d82b76..2345dde71244 100644 --- a/Resources/Prototypes/SS220/Recipes/Lathes/devices.yml +++ b/Resources/Prototypes/SS220/Recipes/Lathes/devices.yml @@ -3,17 +3,17 @@ result: ThermalVisorRND completetime: 4 materials: - Steel: 200 - Glass: 100 - Plasma: 200 - Plastic: 100 + Steel: 500 + Glass: 300 + Plasma: 600 + Plastic: 400 - type: latheRecipe id: ClothingEyesThermalGlassesSecurity result: ClothingEyesThermalGlassesSecurity completetime: 4 materials: - Steel: 400 - Glass: 300 - Plasma: 200 - Plastic: 100 + Steel: 800 + Glass: 400 + Plasma: 600 + Plastic: 400