Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Penlights #122

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions Content.Client/Eye/PenLight/UI/PenLightBoundUserInterface.cs
Original file line number Diff line number Diff line change
@@ -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<MetaDataComponent>(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();
}
}
}
11 changes: 11 additions & 0 deletions Content.Client/Eye/PenLight/UI/PenLightWindow.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc 'pen-light-exam-title'}"
SetSize="0 -300">
<ScrollContainer VerticalExpand="True">
<BoxContainer Name="RootContainer" Orientation="Vertical" HorizontalExpand="True">
<Label Name="NoPatientDataText" Text="{Loc 'pen-light-window-no-patient-data-text'}" Visible="False"/>
<Label Name="ExamDataLabel"/>
</BoxContainer>
</ScrollContainer>
</controls:FancyWindow>
78 changes: 78 additions & 0 deletions Content.Client/Eye/PenLight/UI/PenLightWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -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<IEntityManager>();
}
public void Diagnose(PenLightUserMessage msg)
{
var target = _entityManager.GetEntity(msg.TargetEntity);

if (target == null || !_entityManager.TryGetComponent<DamageableComponent>(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<MetaDataComponent>(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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
118 changes: 118 additions & 0 deletions Content.Server/Medical/PenLightSystem.cs
Original file line number Diff line number Diff line change
@@ -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;
/// <summary>
/// This stores the eye exam system for <see cref="PenLightComponent"/>
/// </summary>
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!;
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<PenLightComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<PenLightComponent, PenLightDoAfterEvent>(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<PenLightComponent> 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;
}


/// <summary>
/// Actually handles the exam interaction.
/// </summary>
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<ActorComponent>(user, out var actor)
|| !_uiSystem.TryGetUi(penlight, PenLightUiKey.Key, out var ui))
return;

_uiSystem.OpenUi(ui, actor.PlayerSession);
}

/// <summary>
/// Runs the checks for the different types of eye damage
/// </summary>
private void Diagnose(EntityUid penlight, EntityUid target)
{
if (!_uiSystem.TryGetUi(penlight, PenLightUiKey.Key, out var ui)
|| !HasComp<EyeComponent>(target))
return;
// Blind
var blind = _entityManager.HasComponent<PermanentBlindnessComponent>(target);

// Drunk
var drunk = _entityManager.HasComponent<DrunkComponent>(target);

// EyeDamage
var eyeDamage = false;
if (TryComp<BlindableComponent>(target, out var eyeDam))
{
eyeDamage = eyeDam.EyeDamage > 0 && eyeDam.EyeDamage < 6; //6 means perma-blind
}

// Hallucinating
var seeingRainbows = _entityManager.HasComponent<SeeingRainbowsComponent>(target);

// Healthy
var healthy = !(blind || drunk || eyeDamage || seeingRainbows);

_uiSystem.SendUiMessage(ui, new PenLightUserMessage(GetNetEntity(target),
blind,
drunk,
eyeDamage,
healthy,
seeingRainbows
));
}
}
33 changes: 33 additions & 0 deletions Content.Shared/Medical/PenLightComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Content.Shared.DoAfter;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Medical;

/// <summary>
/// This for penlights; a tool used to check for eye damage.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause]
public sealed partial class PenLightComponent : Component
{
/// <summary>
/// Cooldown Time, exams take a bit
/// </summary>
[AutoPausedField]
public TimeSpan? NextExamTime;

/// <summary>
/// The min time between exams
/// </summary>
[DataField]
public TimeSpan ExamDelay = TimeSpan.FromSeconds(3);

/// <summary>
/// How long the doafter for the exam takes
/// </summary>
[DataField(required: true)]
public float ExamSpeed { get; set; }

}

[Serializable, NetSerializable]
public sealed partial class PenLightDoAfterEvent : SimpleDoAfterEvent { }
9 changes: 9 additions & 0 deletions Content.Shared/Medical/PenLightUiKey.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Robust.Shared.Serialization;

namespace Content.Shared.Medical;

[Serializable, NetSerializable]
public enum PenLightUiKey : byte
{
Key
}
24 changes: 24 additions & 0 deletions Content.Shared/Medical/PenLightUserMessage.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}

Loading
Loading