From 04d01f687fb479d7f86e2df81cce6b9285dcbad6 Mon Sep 17 00:00:00 2001 From: SleepyScarecrow <136123749+SleepyScarecrow@users.noreply.github.com> Date: Tue, 6 Aug 2024 17:51:21 -0400 Subject: [PATCH] Added Penlights (#567) # Description Added in penlights that spawn in Medical Staff PDAs. --- # TODO - [x] EyeCheck system - [x] Add in the bloody pens. ---

Media

https://github.com/user-attachments/assets/dc746aa2-782e-4d86-b9ef-9e012343fb87

--- # Changelog :cl: Tilkku - add: Added Pen Lights - add: Eye Examination --------- Signed-off-by: SleepyScarecrow <136123749+SleepyScarecrow@users.noreply.github.com> Co-authored-by: VMSolidus --- .../PenLight/UI/PenLightBoundUserInterface.cs | 47 +++++++ .../Eye/PenLight/UI/PenLightWindow.xaml | 11 ++ .../Eye/PenLight/UI/PenLightWindow.xaml.cs | 78 ++++++++++++ .../EyeProtection/EyeProtectionSystem.cs | 2 +- Content.Server/Medical/PenLightSystem.cs | 118 ++++++++++++++++++ Content.Shared/Medical/PenLightComponent.cs | 33 +++++ Content.Shared/Medical/PenLightUiKey.cs | 9 ++ Content.Shared/Medical/PenLightUserMessage.cs | 24 ++++ .../en-US/medical/components/penlight.ftl | 11 ++ .../Entities/Objects/Devices/pda.yml | 54 ++++++++ .../Entities/Objects/Tools/penlight.yml | 90 +++++++++++++ .../Objects/Tools/cmopenlight.rsi/meta.json | 17 +++ .../Tools/cmopenlight.rsi/world-on.png | Bin 0 -> 4345 bytes .../Objects/Tools/cmopenlight.rsi/world.png | Bin 0 -> 4325 bytes .../Objects/Tools/penlight.rsi/meta.json | 17 +++ .../Objects/Tools/penlight.rsi/world-on.png | Bin 0 -> 253 bytes .../Objects/Tools/penlight.rsi/world.png | Bin 0 -> 234 bytes 17 files changed, 510 insertions(+), 1 deletion(-) create mode 100644 Content.Client/Eye/PenLight/UI/PenLightBoundUserInterface.cs create mode 100644 Content.Client/Eye/PenLight/UI/PenLightWindow.xaml create mode 100644 Content.Client/Eye/PenLight/UI/PenLightWindow.xaml.cs create mode 100644 Content.Server/Medical/PenLightSystem.cs create mode 100644 Content.Shared/Medical/PenLightComponent.cs create mode 100644 Content.Shared/Medical/PenLightUiKey.cs create mode 100644 Content.Shared/Medical/PenLightUserMessage.cs create mode 100644 Resources/Locale/en-US/medical/components/penlight.ftl create mode 100644 Resources/Prototypes/Entities/Objects/Tools/penlight.yml create mode 100644 Resources/Textures/Objects/Tools/cmopenlight.rsi/meta.json create mode 100644 Resources/Textures/Objects/Tools/cmopenlight.rsi/world-on.png create mode 100644 Resources/Textures/Objects/Tools/cmopenlight.rsi/world.png create mode 100644 Resources/Textures/Objects/Tools/penlight.rsi/meta.json create mode 100644 Resources/Textures/Objects/Tools/penlight.rsi/world-on.png create mode 100644 Resources/Textures/Objects/Tools/penlight.rsi/world.png diff --git a/Content.Client/Eye/PenLight/UI/PenLightBoundUserInterface.cs b/Content.Client/Eye/PenLight/UI/PenLightBoundUserInterface.cs new file mode 100644 index 00000000000..c4887531151 --- /dev/null +++ b/Content.Client/Eye/PenLight/UI/PenLightBoundUserInterface.cs @@ -0,0 +1,47 @@ +using Content.Shared.Medical; +using JetBrains.Annotations; +using Robust.Client.GameObjects; + +namespace Content.Client.Eye.PenLight.UI +{ + [UsedImplicitly] + public sealed class PenLightBoundUserInterface : BoundUserInterface + { + [ViewVariables] + private PenLightWindow? _window; + + public PenLightBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } + + protected override void Open() + { + base.Open(); + _window = new PenLightWindow + { + Title = EntMan.GetComponent(Owner).EntityName, + }; + _window.OnClose += Close; + _window.OpenCentered(); + } + + protected override void ReceiveMessage(BoundUserInterfaceMessage message) + { + if (_window == null + || message is not PenLightUserMessage cast) + return; + + _window.Diagnose(cast); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + if (_window != null) + _window.OnClose -= Close; + + _window?.Dispose(); + } + } +} diff --git a/Content.Client/Eye/PenLight/UI/PenLightWindow.xaml b/Content.Client/Eye/PenLight/UI/PenLightWindow.xaml new file mode 100644 index 00000000000..149b8a13828 --- /dev/null +++ b/Content.Client/Eye/PenLight/UI/PenLightWindow.xaml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/Content.Client/Eye/PenLight/UI/PenLightWindow.xaml.cs b/Content.Client/Eye/PenLight/UI/PenLightWindow.xaml.cs new file mode 100644 index 00000000000..809a569fa47 --- /dev/null +++ b/Content.Client/Eye/PenLight/UI/PenLightWindow.xaml.cs @@ -0,0 +1,78 @@ +using Content.Client.UserInterface.Controls; +using Content.Shared.Damage; +using Content.Shared.IdentityManagement; +using Content.Shared.Medical; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.XAML; +using System.Text; + + +namespace Content.Client.Eye.PenLight.UI +{ + [GenerateTypedNameReferences] + public sealed partial class PenLightWindow : FancyWindow + { + private readonly IEntityManager _entityManager; + private const int LightHeight = 150; + private const int LightWidth = 900; + + public PenLightWindow() + { + RobustXamlLoader.Load(this); + + var dependencies = IoCManager.Instance!; + _entityManager = dependencies.Resolve(); + } + public void Diagnose(PenLightUserMessage msg) + { + var target = _entityManager.GetEntity(msg.TargetEntity); + + if (target == null || !_entityManager.TryGetComponent(target, out var damageable)) + { + NoPatientDataText.Visible = true; + ExamDataLabel.Text = string.Empty; + return; + } + + NoPatientDataText.Visible = false; + + + string entityName = Loc.GetString("pen-light-window-entity-unknown-text"); + if (_entityManager.HasComponent(target.Value)) + entityName = Identity.Name(target.Value, _entityManager); + + var sb = new StringBuilder(); + sb.AppendLine(Loc.GetString("pen-light-window-entity-eyes-text", ("entityName", entityName))); + + // Check if Blind and return early if true + if (msg.Blind == true) + { + sb.AppendLine(Loc.GetString("pen-light-exam-blind-text")); + ExamDataLabel.Text = sb.ToString(); + SetHeight = LightHeight; + SetWidth = LightWidth; + return; + } + // EyeDamage + if (msg.EyeDamage == true) + sb.AppendLine(Loc.GetString("pen-light-exam-eyedamage-text")); + + // Drunk + if (msg.Drunk == true) + sb.AppendLine(Loc.GetString("pen-light-exam-drunk-text")); + + // Hallucinating + if (msg.SeeingRainbows == true) + sb.AppendLine(Loc.GetString("pen-light-exam-hallucinating-text")); + + // Healthy + if (msg.Healthy == true) + sb.AppendLine(Loc.GetString("pen-light-exam-healthy-text")); + + ExamDataLabel.Text = sb.ToString(); + + SetHeight = LightHeight; + SetWidth = LightWidth; + } + } +} \ No newline at end of file diff --git a/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs b/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs index 2d54c03b51b..744483cfb82 100644 --- a/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs +++ b/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs @@ -11,7 +11,7 @@ public sealed class EyeProtectionSystem : EntitySystem { [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] private readonly BlindableSystem _blindingSystem = default!; - + public override void Initialize() { base.Initialize(); diff --git a/Content.Server/Medical/PenLightSystem.cs b/Content.Server/Medical/PenLightSystem.cs new file mode 100644 index 00000000000..f48a84d0476 --- /dev/null +++ b/Content.Server/Medical/PenLightSystem.cs @@ -0,0 +1,118 @@ +using Content.Server.DoAfter; +using Content.Server.PowerCell; +using Content.Shared.Damage; +using Content.Shared.DoAfter; +using Content.Shared.Drugs; +using Content.Shared.Drunk; +using Content.Shared.Eye.Blinding.Components; +using Content.Shared.Interaction; +using Content.Shared.Medical; +using Content.Shared.Mobs.Systems; +using Content.Shared.Traits.Assorted.Components; +using Robust.Server.GameObjects; +using Robust.Shared.Player; +using Robust.Shared.Timing; + +namespace Content.Server.Medical; +/// +/// This stores the eye exam system for +/// +public sealed class PenLightSystem : EntitySystem +{ + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly DoAfterSystem _doAfter = default!; + [Dependency] private readonly PowerCellSystem _powerCell = default!; + [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; + /// + public override void Initialize() + { + SubscribeLocalEvent(OnAfterInteract); + SubscribeLocalEvent(OnDoAfter); + } + + private void OnAfterInteract(EntityUid uid, PenLightComponent component, AfterInteractEvent args) + { + if (args.Handled + || args.Target is not { } target) + return; + + args.Handled = TryStartExam(uid, target, args.User, component); + } + + private void OnDoAfter(Entity uid, ref PenLightDoAfterEvent args) + { + if (args.Handled + || args.Cancelled + || args.Target == null + || !_powerCell.HasDrawCharge(uid, user: args.User)) + return; + + OpenUserInterface(args.User, uid); + Diagnose(uid, args.Target.Value); + args.Handled = true; + } + + + /// + /// Actually handles the exam interaction. + /// + public bool TryStartExam(EntityUid uid, EntityUid target, EntityUid user, PenLightComponent? component = null) + { + if (!Resolve(uid, ref component)) + return false; + + return _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, component.ExamSpeed, new PenLightDoAfterEvent(), + uid, target, uid) + { + BlockDuplicate = true, + BreakOnUserMove = true, + BreakOnTargetMove = true, + BreakOnHandChange = true, + NeedHand = true + }); + } + private void OpenUserInterface(EntityUid user, EntityUid penlight) + { + if (!TryComp(user, out var actor) + || !_uiSystem.TryGetUi(penlight, PenLightUiKey.Key, out var ui)) + return; + + _uiSystem.OpenUi(ui, actor.PlayerSession); + } + + /// + /// Runs the checks for the different types of eye damage + /// + private void Diagnose(EntityUid penlight, EntityUid target) + { + if (!_uiSystem.TryGetUi(penlight, PenLightUiKey.Key, out var ui) + || !HasComp(target)) + return; + // Blind + var blind = _entityManager.HasComponent(target); + + // Drunk + var drunk = _entityManager.HasComponent(target); + + // EyeDamage + var eyeDamage = false; + if (TryComp(target, out var eyeDam)) + { + eyeDamage = eyeDam.EyeDamage > 0 && eyeDam.EyeDamage < 6; //6 means perma-blind + } + + // Hallucinating + var seeingRainbows = _entityManager.HasComponent(target); + + // Healthy + var healthy = !(blind || drunk || eyeDamage || seeingRainbows); + + _uiSystem.SendUiMessage(ui, new PenLightUserMessage(GetNetEntity(target), + blind, + drunk, + eyeDamage, + healthy, + seeingRainbows + )); + } +} diff --git a/Content.Shared/Medical/PenLightComponent.cs b/Content.Shared/Medical/PenLightComponent.cs new file mode 100644 index 00000000000..50dacae3dc8 --- /dev/null +++ b/Content.Shared/Medical/PenLightComponent.cs @@ -0,0 +1,33 @@ +using Content.Shared.DoAfter; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; +namespace Content.Shared.Medical; + +/// +/// This for penlights; a tool used to check for eye damage. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause] +public sealed partial class PenLightComponent : Component +{ + /// + /// Cooldown Time, exams take a bit + /// + [AutoPausedField] + public TimeSpan? NextExamTime; + + /// + /// The min time between exams + /// + [DataField] + public TimeSpan ExamDelay = TimeSpan.FromSeconds(3); + + /// + /// How long the doafter for the exam takes + /// + [DataField(required: true)] + public float ExamSpeed { get; set; } + +} + +[Serializable, NetSerializable] +public sealed partial class PenLightDoAfterEvent : SimpleDoAfterEvent { } \ No newline at end of file diff --git a/Content.Shared/Medical/PenLightUiKey.cs b/Content.Shared/Medical/PenLightUiKey.cs new file mode 100644 index 00000000000..52fc6ce3401 --- /dev/null +++ b/Content.Shared/Medical/PenLightUiKey.cs @@ -0,0 +1,9 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.Medical; + +[Serializable, NetSerializable] +public enum PenLightUiKey : byte +{ + Key +} diff --git a/Content.Shared/Medical/PenLightUserMessage.cs b/Content.Shared/Medical/PenLightUserMessage.cs new file mode 100644 index 00000000000..42502b2171b --- /dev/null +++ b/Content.Shared/Medical/PenLightUserMessage.cs @@ -0,0 +1,24 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.Medical; +[Serializable, NetSerializable] +public sealed class PenLightUserMessage : BoundUserInterfaceMessage +{ + public readonly NetEntity? TargetEntity; + public bool? Blind; + public bool? Drunk; + public bool? EyeDamage; + public bool? Healthy; + public bool? SeeingRainbows; + + public PenLightUserMessage(NetEntity? targetEntity, bool? blind, bool? drunk, bool? eyeDamage, bool? healthy, bool? seeingRainbows) + { + TargetEntity = targetEntity; + Blind = blind; + Drunk = drunk; + EyeDamage = eyeDamage; + Healthy = healthy; + SeeingRainbows = seeingRainbows; + } +} + diff --git a/Resources/Locale/en-US/medical/components/penlight.ftl b/Resources/Locale/en-US/medical/components/penlight.ftl new file mode 100644 index 00000000000..f0639ad7381 --- /dev/null +++ b/Resources/Locale/en-US/medical/components/penlight.ftl @@ -0,0 +1,11 @@ +penlight-off = The pen light is off. +pen-light-exam-title = Pen Light +pen-light-window-entity-eyes-text = {$entityName}'s conditions: +pen-light-window-no-patient-data-text = No patient data. +pen-light-window-entity-unknown-text = unknown + +pen-light-exam-blind-text = The patient's eyes are glassy and unfocused. They can't follow the light at all. +pen-light-exam-drunk-text = The patient's eyes are slow to follow the light, droopy. +pen-light-exam-eyedamage-text = The patient's eyes are partially focused, though they struggle to look at the light for too long. +pen-light-exam-hallucinating-text = The patient's eyes are wandering around, with dilated pupils. They don't focus on the light. +pen-light-exam-healthy-text = The patient follows the light perfectly with no stuttering. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index 0f68afefe69..2c28f60da58 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -151,6 +151,12 @@ - type: Pda id: MedicalInternIDCard state: pda-internmed + penSlot: # Pen Lights + startingItem: PenLightBase + priority: -1 + whitelist: + tags: + - Write - type: PdaBorderColor borderColor: "#717059" accentVColor: "#447987" @@ -534,6 +540,12 @@ - type: Pda id: CMOIDCard state: pda-cmo + penSlot: # Fancy Pen Light + startingItem: CMOPenLight + priority: -1 + whitelist: + tags: + - Write - type: PdaBorderColor borderColor: "#d7d7d0" accentHColor: "#447987" @@ -550,6 +562,12 @@ - type: Pda id: MedicalIDCard state: pda-medical + penSlot: # Pen Lights + startingItem: PenLightBase + priority: -1 + whitelist: + tags: + - Write - type: PdaBorderColor borderColor: "#d7d7d0" accentVColor: "#447987" @@ -568,6 +586,12 @@ - type: Pda id: ParamedicIDCard state: pda-paramedic + penSlot: # Pen Lights + startingItem: PenLightBase + priority: -1 + whitelist: + tags: + - Write - type: PdaBorderColor borderColor: "#d7d7d0" accentVColor: "#2a4b5b" @@ -583,6 +607,12 @@ - type: Pda id: ChemistIDCard state: pda-chemistry + penSlot: # Pen Lights + startingItem: PenLightBase + priority: -1 + whitelist: + tags: + - Write - type: PdaBorderColor borderColor: "#d7d7d0" accentVColor: "#B34200" @@ -917,6 +947,12 @@ - type: Pda id: PsychologistIDCard state: pda-medical + penSlot: # Pen Lights + startingItem: PenLightBase + priority: -1 + whitelist: + tags: + - Write - type: PdaBorderColor borderColor: "#d7d7d0" accentVColor: "#447987" @@ -1002,6 +1038,12 @@ - type: Pda id: BrigmedicIDCard state: pda-brigmedic + penSlot: # Pen Lights + startingItem: PenLightBase + priority: -1 + whitelist: + tags: + - Write - type: PdaBorderColor borderColor: "#A32D26" accentHColor: "#d7d7d0" @@ -1079,6 +1121,12 @@ - type: Pda id: SeniorPhysicianIDCard state: pda-seniorphysician + penSlot: # Pen Lights + startingItem: PenLightBase + priority: -1 + whitelist: + tags: + - Write - type: PdaBorderColor borderColor: "#d7d7d0" accentHColor: "#447987" @@ -1129,6 +1177,12 @@ - type: Pda id: SyndicateIDCard state: pda-syndi-agent + penSlot: # Pen Lights + startingItem: PenLightBase + priority: -1 + whitelist: + tags: + - Write - type: PdaBorderColor borderColor: "#891417" - type: Icon diff --git a/Resources/Prototypes/Entities/Objects/Tools/penlight.yml b/Resources/Prototypes/Entities/Objects/Tools/penlight.yml new file mode 100644 index 00000000000..7f8a9b262c0 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Tools/penlight.yml @@ -0,0 +1,90 @@ +- type: entity + name: Pen Light + parent: Pen + id: PenLightBase + description: A pen-sized light, used by medical staff. + components: + - type: HandheldLight + addPrefix: false + - type: Sprite + sprite: Objects/Tools/penlight.rsi + layers: + - state: world + - state: world-on + shader: unshaded + visible: false + map: [ "light" ] + - type: Item + sprite: Objects/Tools/penlight.rsi + heldPrefix: off + - type: PointLight + enabled: false + mask: /Textures/Effects/LightMasks/cone.png + autoRot: true + radius: 2 + netsync: false + - type: PenLight + examSpeed: 3 #time in seconds + - type: Appearance + - type: UserInterface + interfaces: + - key: enum.PenLightUiKey.Key + type: PenLightBoundUserInterface + - type: ToggleableLightVisuals + - type: ContainerContainer + containers: + cell_slot: !type:ContainerSlot {} + - type: PowerCellSlot + cellSlotId: cell_slot + - type: ItemSlots + slots: + cell_slot: + name: power-cell-slot-component-slot-name-default + startingItem: PowerCellSmall + - type: Tag + tags: + - Flashlight + - Write + - Pen + +- type: entity + name: Chief Medical Officer's Pen Light + parent: PenLightBase + id: CMOPenLight + description: A pen-sized light, this one belonging to the Chief Medical Officer. When you get promoted you get a better pen. + components: + - type: HandheldLight + addPrefix: false + - type: Sprite + sprite: Objects/Tools/cmopenlight.rsi + layers: + - state: world + - state: world-on + shader: unshaded + visible: false + map: [ "light" ] + - type: Item + sprite: Objects/Tools/cmopenlight.rsi + heldPrefix: off + - type: PointLight + enabled: false + mask: /Textures/Effects/LightMasks/cone.png + autoRot: true + radius: 2 + netsync: false + - type: PenLight + examSpeed: 1.5 #time in seconds + - type: Appearance + - type: ToggleableLightVisuals + - type: PowerCellSlot + cellSlotId: cell_slot + - type: ItemSlots + slots: + cell_slot: + name: power-cell-slot-component-slot-name-default + startingItem: PowerCellSmall + - type: Tag + tags: + - Flashlight + - Write + - Pen diff --git a/Resources/Textures/Objects/Tools/cmopenlight.rsi/meta.json b/Resources/Textures/Objects/Tools/cmopenlight.rsi/meta.json new file mode 100644 index 00000000000..8f4b8ba253f --- /dev/null +++ b/Resources/Textures/Objects/Tools/cmopenlight.rsi/meta.json @@ -0,0 +1,17 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "MistakeNot4892, https://github.com/NebulaSS13/Nebula/blob/dev/icons/obj/lighting/penlight.dmi", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "world" + }, + { + "name": "world-on" + } + ] +} diff --git a/Resources/Textures/Objects/Tools/cmopenlight.rsi/world-on.png b/Resources/Textures/Objects/Tools/cmopenlight.rsi/world-on.png new file mode 100644 index 0000000000000000000000000000000000000000..fbd87cad2035e7c2b6594b9c55a43c83c01d4fcc GIT binary patch literal 4345 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/penlight.rsi/world.png b/Resources/Textures/Objects/Tools/penlight.rsi/world.png new file mode 100644 index 0000000000000000000000000000000000000000..4cf616bf959f0b7b8905868edf5cdb484cb863b5 GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C^*N{ z#WAE}&fBX8c^edXSOa|K9C;YSXuiRx*JR<5f=x>sXZ(qq()`n3vy{J^8>pV)L41Su zu`}UbnX~yS+CT3Vclyd|VKRM{xA>9thCMsiq_Vz5j0Rj>jF-*<-@ zeTmsegyx;!rmfae$yf39$OVO0)rXoS=C#;1d0!URTO1)UE&c94)>?lbc8(;?10eS^ ZFz`#