using Robust.Shared.Player;
using Robust.Server.GameObjects;
-namespace Content.Server.Eye.Blinding
+namespace Content.Server.Eye.Blinding;
+
+public sealed class ActivatableUIRequiresVisionSystem : EntitySystem
{
- public sealed class ActivatableUIRequiresVisionSystem : EntitySystem
+ [Dependency] private readonly PopupSystem _popupSystem = default!;
+ [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
+
+ public override void Initialize()
{
- [Dependency] private readonly ActivatableUISystem _activatableUISystem = default!;
- [Dependency] private readonly PopupSystem _popupSystem = default!;
- [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
+ base.Initialize();
+ SubscribeLocalEvent<ActivatableUIRequiresVisionComponent, ActivatableUIOpenAttemptEvent>(OnOpenAttempt);
+ SubscribeLocalEvent<BlindableComponent, BlindnessChangedEvent>(OnBlindnessChanged);
+ }
- public override void Initialize()
- {
- base.Initialize();
- SubscribeLocalEvent<ActivatableUIRequiresVisionComponent, ActivatableUIOpenAttemptEvent>(OnOpenAttempt);
- SubscribeLocalEvent<BlindableComponent, BlindnessChangedEvent>(OnBlindnessChanged);
- }
+ private void OnOpenAttempt(EntityUid uid, ActivatableUIRequiresVisionComponent component, ActivatableUIOpenAttemptEvent args)
+ {
+ if (args.Cancelled)
+ return;
- private void OnOpenAttempt(EntityUid uid, ActivatableUIRequiresVisionComponent component, ActivatableUIOpenAttemptEvent args)
+ if (TryComp<BlindableComponent>(args.User, out var blindable) && blindable.Sources > 0)
{
- if (args.Cancelled)
- return;
-
- if (TryComp<BlindableComponent>(args.User, out var blindable) && blindable.Sources > 0)
- {
- _popupSystem.PopupCursor(Loc.GetString("blindness-fail-attempt"), args.User, Shared.Popups.PopupType.MediumCaution);
- args.Cancel();
- }
+ _popupSystem.PopupCursor(Loc.GetString("blindness-fail-attempt"), args.User, Shared.Popups.PopupType.MediumCaution);
+ args.Cancel();
}
+ }
- private void OnBlindnessChanged(EntityUid uid, BlindableComponent component, BlindnessChangedEvent args)
- {
- if (!args.Blind)
- return;
+ private void OnBlindnessChanged(EntityUid uid, BlindableComponent component, BlindnessChangedEvent args)
+ {
+ if (!args.Blind)
+ return;
- if (!TryComp<ActorComponent>(uid, out var actor))
- return;
+ if (!TryComp<ActorComponent>(uid, out var actor))
+ return;
- var uiList = _userInterfaceSystem.GetAllUIsForSession(actor.PlayerSession);
- if (uiList == null)
- return;
+ var uiList = _userInterfaceSystem.GetAllUIsForSession(actor.PlayerSession);
+ if (uiList == null)
+ return;
- Queue<BoundUserInterface> closeList = new(); // foreach collection modified moment
+ Queue<BoundUserInterface> closeList = new(); // foreach collection modified moment
- foreach (var ui in uiList)
- {
- if (HasComp<ActivatableUIRequiresVisionComponent>(ui.Owner))
- closeList.Enqueue(ui);
- }
+ foreach (var ui in uiList)
+ {
+ if (HasComp<ActivatableUIRequiresVisionComponent>(ui.Owner))
+ closeList.Enqueue(ui);
+ }
- foreach (var ui in closeList)
- {
- _userInterfaceSystem.CloseUi(ui, actor.PlayerSession);
- }
+ foreach (var ui in closeList)
+ {
+ _userInterfaceSystem.CloseUi(ui, actor.PlayerSession);
}
}
}
using Content.Server.Disease;
using Content.Server.Medical.Components;
using Content.Server.Popups;
+using Content.Server.PowerCell;
+using Content.Server.UserInterface;
using Content.Shared.Damage;
using Content.Shared.DoAfter;
using Content.Shared.IdentityManagement;
{
public sealed class HealthAnalyzerSystem : EntitySystem
{
- [Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly DiseaseSystem _disease = default!;
- [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
+ [Dependency] private readonly PowerCellSystem _cell = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
public override void Initialize()
{
base.Initialize();
- SubscribeLocalEvent<HealthAnalyzerComponent, ActivateInWorldEvent>(HandleActivateInWorld);
SubscribeLocalEvent<HealthAnalyzerComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<HealthAnalyzerComponent, HealthAnalyzerDoAfterEvent>(OnDoAfter);
}
- private void HandleActivateInWorld(EntityUid uid, HealthAnalyzerComponent healthAnalyzer, ActivateInWorldEvent args)
- {
- OpenUserInterface(args.User, healthAnalyzer);
- }
-
private void OnAfterInteract(EntityUid uid, HealthAnalyzerComponent healthAnalyzer, AfterInteractEvent args)
{
- if (args.Target == null || !args.CanReach || !HasComp<MobStateComponent>(args.Target))
+ if (args.Target == null || !args.CanReach || !HasComp<MobStateComponent>(args.Target) || !_cell.HasActivatableCharge(uid, user: args.User))
return;
_audio.PlayPvs(healthAnalyzer.ScanningBeginSound, uid);
private void OnDoAfter(EntityUid uid, HealthAnalyzerComponent component, DoAfterEvent args)
{
- if (args.Handled || args.Cancelled || args.Args.Target == null)
+ if (args.Handled || args.Cancelled || args.Args.Target == null || !_cell.TryUseActivatableCharge(uid, user: args.User))
return;
_audio.PlayPvs(component.ScanningEndSound, args.Args.User);
// Below is for the traitor item
// Piggybacking off another component's doafter is complete CBT so I gave up
// and put it on the same component
+ /*
+ * this code is cursed wuuuuuuut
+ */
if (string.IsNullOrEmpty(component.Disease))
{
args.Handled = true;
_popupSystem.PopupEntity(Loc.GetString("disease-scanner-gave-self", ("disease", component.Disease)),
args.Args.User, args.Args.User);
}
-
-
else
{
_popupSystem.PopupEntity(Loc.GetString("disease-scanner-gave-other", ("target", Identity.Entity(args.Args.Target.Value, EntityManager)),
-using Content.Shared.Interaction.Events;
using Content.Shared.Pinpointer;
using Robust.Server.GameObjects;
/// Raised when a battery's charge or capacity changes (capacity affects relative charge percentage).
/// </summary>
[ByRefEvent]
- public record struct ChargeChangedEvent(float Charge, float MaxCharge);
+ public readonly record struct ChargeChangedEvent(float Charge, float MaxCharge);
}
--- /dev/null
+namespace Content.Server.PowerCell;
+
+/// <summary>
+/// Indicates that the entity's ActivatableUI requires power or else it closes.
+/// </summary>
+[RegisterComponent]
+public sealed class PowerCellDrawComponent : Component
+{
+ [ViewVariables(VVAccess.ReadWrite), DataField("enabled")]
+ public bool Enabled = false;
+
+ /// <summary>
+ /// How much the entity draws while the UI is open.
+ /// Set to 0 if you just wish to check for power upon opening the UI.
+ /// </summary>
+ [ViewVariables(VVAccess.ReadWrite), DataField("drawRate")]
+ public float DrawRate = 1f;
+
+ /// <summary>
+ /// How much power is used whenever the entity is "used".
+ /// This is used to ensure the UI won't open again without a minimum use power.
+ /// </summary>
+ [ViewVariables(VVAccess.ReadWrite), DataField("useRate")]
+ public float UseRate = 0f;
+}
--- /dev/null
+namespace Content.Server.PowerCell;
+
+/// <summary>
+/// Raised directed on an entity when its active power cell has no more charge to supply.
+/// </summary>
+[ByRefEvent]
+public readonly record struct PowerCellSlotEmptyEvent;
using Robust.Shared.Containers;
using System.Diagnostics.CodeAnalysis;
using Content.Server.Kitchen.Components;
+using Content.Server.UserInterface;
using Content.Shared.Containers.ItemSlots;
+using Content.Shared.Popups;
using Content.Shared.Rejuvenate;
+using Content.Shared.UserInterface;
+using Robust.Server.GameObjects;
namespace Content.Server.PowerCell;
public sealed class PowerCellSystem : SharedPowerCellSystem
{
+ [Dependency] private readonly ActivatableUISystem _activatable = default!;
[Dependency] private readonly SolutionContainerSystem _solutionsSystem = default!;
[Dependency] private readonly ExplosionSystem _explosionSystem = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _sharedAppearanceSystem = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
public override void Initialize()
{
SubscribeLocalEvent<BatteryComponent, BeingMicrowavedEvent>(OnMicrowaved);
}
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+ var query = EntityQueryEnumerator<PowerCellDrawComponent, PowerCellSlotComponent>();
+
+ while (query.MoveNext(out var uid, out var comp, out var slot))
+ {
+ if (!comp.Enabled)
+ continue;
+
+ if (!TryGetBatteryFromSlot(uid, out var battery, slot))
+ continue;
+
+ if (battery.TryUseCharge(comp.DrawRate * frameTime))
+ continue;
+
+ comp.Enabled = false;
+ var ev = new PowerCellSlotEmptyEvent();
+ RaiseLocalEvent(uid, ref ev);
+ }
+ }
+
private void OnRejuvenate(EntityUid uid, PowerCellComponent component, RejuvenateEvent args)
{
component.IsRigged = false;
QueueDel(uid);
}
+ #region Activatable
+
+ /// <summary>
+ /// Returns whether the entity has a slotted battery and <see cref="PowerCellDrawComponent.UseRate"/> charge.
+ /// </summary>
+ /// <param name="user">Popup to this user with the relevant detail if specified.</param>
+ public bool HasActivatableCharge(EntityUid uid, PowerCellDrawComponent? battery = null, PowerCellSlotComponent? cell = null, EntityUid? user = null)
+ {
+ if (!Resolve(uid, ref battery, ref cell, false))
+ return false;
+
+ return HasCharge(uid, battery.UseRate, cell, user);
+ }
+
+ /// <summary>
+ /// Tries to use the <see cref="PowerCellDrawComponent.UseRate"/> for this entity.
+ /// </summary>
+ /// <param name="user">Popup to this user with the relevant detail if specified.</param>
+ public bool TryUseActivatableCharge(EntityUid uid, PowerCellDrawComponent? battery = null, PowerCellSlotComponent? cell = null, EntityUid? user = null)
+ {
+ if (!Resolve(uid, ref battery, ref cell, false))
+ return false;
+
+ if (TryUseCharge(uid, battery.UseRate, cell, user))
+ {
+ _activatable.CheckUsage(uid);
+ return true;
+ }
+
+ return false;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Returns whether the entity has a slotted battery and charge for the requested action.
+ /// </summary>
+ /// <param name="user">Popup to this user with the relevant detail if specified.</param>
+ public bool HasCharge(EntityUid uid, float charge, PowerCellSlotComponent? component = null, EntityUid? user = null)
+ {
+ if (!TryGetBatteryFromSlot(uid, out var battery, component))
+ {
+ if (user != null)
+ _popup.PopupEntity(Loc.GetString("power-cell-no-battery"), uid, user.Value);
+
+ return false;
+ }
+
+ if (battery.CurrentCharge < charge)
+ {
+ if (user != null)
+ _popup.PopupEntity(Loc.GetString("power-cell-insufficient"), uid, user.Value);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Tries to use charge from a slotted battery.
+ /// </summary>
+ public bool TryUseCharge(EntityUid uid, float charge, PowerCellSlotComponent? component = null, EntityUid? user = null)
+ {
+ if (!TryGetBatteryFromSlot(uid, out var battery, component))
+ {
+ if (user != null)
+ _popup.PopupEntity(Loc.GetString("power-cell-no-battery"), uid, user.Value);
+
+ return false;
+ }
+
+ if (!battery.TryUseCharge(charge))
+ {
+ if (user != null)
+ _popup.PopupEntity(Loc.GetString("power-cell-insufficient"), uid, user.Value);
+
+ return false;
+ }
+
+ return true;
+ }
+
public bool TryGetBatteryFromSlot(EntityUid uid, [NotNullWhen(true)] out BatteryComponent? battery, PowerCellSlotComponent? component = null)
{
if (!Resolve(uid, ref component, false))
--- /dev/null
+using Content.Server.PowerCell;
+using Content.Shared.UserInterface;
+
+namespace Content.Server.UserInterface;
+
+/// <summary>
+/// Specifies that the attached entity requires <see cref="PowerCellDrawComponent"/> power.
+/// </summary>
+[RegisterComponent]
+public sealed class ActivatableUIRequiresPowerCellComponent : Component
+{
+
+}
--- /dev/null
+using Content.Server.PowerCell;
+using Content.Shared.PowerCell;
+using Robust.Shared.Containers;
+
+namespace Content.Server.UserInterface;
+
+public sealed partial class ActivatableUISystem
+{
+ [Dependency] private readonly PowerCellSystem _cell = default!;
+
+ private void InitializePower()
+ {
+ SubscribeLocalEvent<ActivatableUIRequiresPowerCellComponent, ActivatableUIOpenAttemptEvent>(OnBatteryOpenAttempt);
+ SubscribeLocalEvent<ActivatableUIRequiresPowerCellComponent, BoundUIOpenedEvent>(OnBatteryOpened);
+ SubscribeLocalEvent<ActivatableUIRequiresPowerCellComponent, BoundUIClosedEvent>(OnBatteryClosed);
+
+ SubscribeLocalEvent<PowerCellDrawComponent, EntRemovedFromContainerMessage>(OnPowerCellRemoved);
+ }
+
+ private void OnPowerCellRemoved(EntityUid uid, PowerCellDrawComponent component, EntRemovedFromContainerMessage args)
+ {
+ if (TryComp<PowerCellDrawComponent>(uid, out var draw))
+ {
+ draw.Enabled = false;
+ }
+
+ if (HasComp<ActivatableUIRequiresPowerCellComponent>(uid) &&
+ TryComp<ActivatableUIComponent>(uid, out var activatable) &&
+ activatable.Key != null)
+ {
+ _uiSystem.TryCloseAll(uid, activatable.Key);
+ }
+ }
+
+ private void OnBatteryOpened(EntityUid uid, ActivatableUIRequiresPowerCellComponent component, BoundUIOpenedEvent args)
+ {
+ if (!TryComp<PowerCellDrawComponent>(uid, out var draw))
+ return;
+
+ draw.Enabled = true;
+ }
+
+ private void OnBatteryClosed(EntityUid uid, ActivatableUIRequiresPowerCellComponent component, BoundUIClosedEvent args)
+ {
+ if (!TryComp<PowerCellDrawComponent>(uid, out var draw))
+ return;
+
+ draw.Enabled = false;
+ }
+
+ /// <summary>
+ /// Call if you want to check if the UI should close due to a recent battery usage.
+ /// </summary>
+ public void CheckUsage(EntityUid uid, ActivatableUIComponent? active = null, ActivatableUIRequiresPowerCellComponent? component = null, PowerCellDrawComponent? draw = null)
+ {
+ if (!Resolve(uid, ref component, ref draw, ref active, false) || active.Key == null)
+ return;
+
+ if (_cell.HasCharge(uid, draw.UseRate))
+ return;
+
+ _uiSystem.TryCloseAll(uid, active.Key);
+ }
+
+ private void OnBatteryOpenAttempt(EntityUid uid, ActivatableUIRequiresPowerCellComponent component, ActivatableUIOpenAttemptEvent args)
+ {
+ if (!TryComp<PowerCellDrawComponent>(uid, out var draw))
+ return;
+
+ // Check if we have the appropriate drawrate / userate to even open it.
+ if (args.Cancelled || !_cell.HasCharge(uid, MathF.Max(draw.DrawRate, draw.UseRate), user: args.User))
+ {
+ args.Cancel();
+ return;
+ }
+ }
+}
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Verbs;
-using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Server.Player;
-namespace Content.Server.UserInterface
+namespace Content.Server.UserInterface;
+
+public sealed partial class ActivatableUISystem : EntitySystem
{
- [UsedImplicitly]
- internal sealed class ActivatableUISystem : EntitySystem
- {
- [Dependency] private readonly IAdminManager _adminManager = default!;
- [Dependency] private readonly ActionBlockerSystem _blockerSystem = default!;
- [Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
+ [Dependency] private readonly IAdminManager _adminManager = default!;
+ [Dependency] private readonly ActionBlockerSystem _blockerSystem = default!;
+ [Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
- public override void Initialize()
- {
- base.Initialize();
+ public override void Initialize()
+ {
+ base.Initialize();
- SubscribeLocalEvent<ActivatableUIComponent, ActivateInWorldEvent>(OnActivate);
- SubscribeLocalEvent<ActivatableUIComponent, UseInHandEvent>(OnUseInHand);
- SubscribeLocalEvent<ActivatableUIComponent, HandDeselectedEvent>(OnHandDeselected);
- SubscribeLocalEvent<ActivatableUIComponent, GotUnequippedHandEvent>((uid, aui, _) => CloseAll(uid, aui));
- // *THIS IS A BLATANT WORKAROUND!* RATIONALE: Microwaves need it
- SubscribeLocalEvent<ActivatableUIComponent, EntParentChangedMessage>(OnParentChanged);
- SubscribeLocalEvent<ActivatableUIComponent, BoundUIClosedEvent>(OnUIClose);
- SubscribeLocalEvent<BoundUserInterfaceMessageAttempt>(OnBoundInterfaceInteractAttempt);
+ SubscribeLocalEvent<ActivatableUIComponent, ActivateInWorldEvent>(OnActivate);
+ SubscribeLocalEvent<ActivatableUIComponent, UseInHandEvent>(OnUseInHand);
+ SubscribeLocalEvent<ActivatableUIComponent, HandDeselectedEvent>(OnHandDeselected);
+ SubscribeLocalEvent<ActivatableUIComponent, GotUnequippedHandEvent>((uid, aui, _) => CloseAll(uid, aui));
+ // *THIS IS A BLATANT WORKAROUND!* RATIONALE: Microwaves need it
+ SubscribeLocalEvent<ActivatableUIComponent, EntParentChangedMessage>(OnParentChanged);
+ SubscribeLocalEvent<ActivatableUIComponent, BoundUIClosedEvent>(OnUIClose);
+ SubscribeLocalEvent<BoundUserInterfaceMessageAttempt>(OnBoundInterfaceInteractAttempt);
- SubscribeLocalEvent<ActivatableUIComponent, GetVerbsEvent<ActivationVerb>>(AddOpenUiVerb);
+ SubscribeLocalEvent<ActivatableUIComponent, GetVerbsEvent<ActivationVerb>>(AddOpenUiVerb);
- SubscribeLocalEvent<ServerUserInterfaceComponent, OpenUiActionEvent>(OnActionPerform);
- }
+ SubscribeLocalEvent<ServerUserInterfaceComponent, OpenUiActionEvent>(OnActionPerform);
- private void OnBoundInterfaceInteractAttempt(BoundUserInterfaceMessageAttempt ev)
- {
- if (!TryComp(ev.Target, out ActivatableUIComponent? comp))
- return;
+ InitializePower();
+ }
- if (!comp.RequireHands)
- return;
+ private void OnBoundInterfaceInteractAttempt(BoundUserInterfaceMessageAttempt ev)
+ {
+ if (!TryComp(ev.Target, out ActivatableUIComponent? comp))
+ return;
- if (!TryComp(ev.Sender.AttachedEntity, out HandsComponent? hands) || hands.Hands.Count == 0)
- ev.Cancel();
- }
+ if (!comp.RequireHands)
+ return;
- private void OnActionPerform(EntityUid uid, ServerUserInterfaceComponent component, OpenUiActionEvent args)
- {
- if (args.Handled || args.Key == null)
- return;
+ if (!TryComp(ev.Sender.AttachedEntity, out HandsComponent? hands) || hands.Hands.Count == 0)
+ ev.Cancel();
+ }
- if (!TryComp(args.Performer, out ActorComponent? actor))
- return;
+ private void OnActionPerform(EntityUid uid, ServerUserInterfaceComponent component, OpenUiActionEvent args)
+ {
+ if (args.Handled || args.Key == null)
+ return;
- args.Handled = _uiSystem.TryToggleUi(uid, args.Key, actor.PlayerSession);
- }
+ if (!TryComp(args.Performer, out ActorComponent? actor))
+ return;
- private void AddOpenUiVerb(EntityUid uid, ActivatableUIComponent component, GetVerbsEvent<ActivationVerb> args)
- {
- if (!args.CanAccess)
- return;
+ args.Handled = _uiSystem.TryToggleUi(uid, args.Key, actor.PlayerSession);
+ }
- if (component.RequireHands && args.Hands == null)
- return;
+ private void AddOpenUiVerb(EntityUid uid, ActivatableUIComponent component, GetVerbsEvent<ActivationVerb> args)
+ {
+ if (!args.CanAccess)
+ return;
- if (component.InHandsOnly && args.Using != uid)
- return;
+ if (component.RequireHands && args.Hands == null)
+ return;
- if (!args.CanInteract && (!component.AllowSpectator || !HasComp<GhostComponent>(args.User)))
- return;
+ if (component.InHandsOnly && args.Using != uid)
+ return;
- ActivationVerb verb = new();
- verb.Act = () => InteractUI(args.User, component);
- verb.Text = Loc.GetString(component.VerbText);
- // TODO VERBS add "open UI" icon?
- args.Verbs.Add(verb);
- }
+ if (!args.CanInteract && (!component.AllowSpectator || !HasComp<GhostComponent>(args.User)))
+ return;
- private void OnActivate(EntityUid uid, ActivatableUIComponent component, ActivateInWorldEvent args)
- {
- if (args.Handled) return;
- if (component.InHandsOnly) return;
- args.Handled = InteractUI(args.User, component);
- }
-
- private void OnUseInHand(EntityUid uid, ActivatableUIComponent component, UseInHandEvent args)
- {
- if (args.Handled) return;
- args.Handled = InteractUI(args.User, component);
- }
+ ActivationVerb verb = new();
+ verb.Act = () => InteractUI(args.User, component);
+ verb.Text = Loc.GetString(component.VerbText);
+ // TODO VERBS add "open UI" icon?
+ args.Verbs.Add(verb);
+ }
- private void OnParentChanged(EntityUid uid, ActivatableUIComponent aui, ref EntParentChangedMessage args)
- {
- CloseAll(uid, aui);
- }
+ private void OnActivate(EntityUid uid, ActivatableUIComponent component, ActivateInWorldEvent args)
+ {
+ if (args.Handled) return;
+ if (component.InHandsOnly) return;
+ args.Handled = InteractUI(args.User, component);
+ }
- private void OnUIClose(EntityUid uid, ActivatableUIComponent component, BoundUIClosedEvent args)
- {
- if (args.Session != component.CurrentSingleUser) return;
- if (args.UiKey != component.Key) return;
- SetCurrentSingleUser(uid, null, component);
- }
+ private void OnUseInHand(EntityUid uid, ActivatableUIComponent component, UseInHandEvent args)
+ {
+ if (args.Handled) return;
+ args.Handled = InteractUI(args.User, component);
+ }
- private bool InteractUI(EntityUid user, ActivatableUIComponent aui)
- {
- if (!_blockerSystem.CanInteract(user, aui.Owner) && (!aui.AllowSpectator || !HasComp<GhostComponent>(user)))
- return false;
+ private void OnParentChanged(EntityUid uid, ActivatableUIComponent aui, ref EntParentChangedMessage args)
+ {
+ CloseAll(uid, aui);
+ }
- if (aui.RequireHands && !HasComp<HandsComponent>(user))
- return false;
+ private void OnUIClose(EntityUid uid, ActivatableUIComponent component, BoundUIClosedEvent args)
+ {
+ if (args.Session != component.CurrentSingleUser) return;
+ if (args.UiKey != component.Key) return;
+ SetCurrentSingleUser(uid, null, component);
+ }
- if (!EntityManager.TryGetComponent(user, out ActorComponent? actor)) return false;
+ private bool InteractUI(EntityUid user, ActivatableUIComponent aui)
+ {
+ if (!_blockerSystem.CanInteract(user, aui.Owner) && (!aui.AllowSpectator || !HasComp<GhostComponent>(user)))
+ return false;
- if (aui.AdminOnly && !_adminManager.IsAdmin(actor.PlayerSession)) return false;
+ if (aui.RequireHands && !HasComp<HandsComponent>(user))
+ return false;
- var ui = aui.UserInterface;
- if (ui == null) return false;
+ if (!EntityManager.TryGetComponent(user, out ActorComponent? actor)) return false;
- if (aui.SingleUser && (aui.CurrentSingleUser != null) && (actor.PlayerSession != aui.CurrentSingleUser))
- {
- // If we get here, supposedly, the object is in use.
- // Check with BUI that it's ACTUALLY in use just in case.
- // Since this could brick the object if it goes wrong.
- if (ui.SubscribedSessions.Count != 0) return false;
- }
+ if (aui.AdminOnly && !_adminManager.IsAdmin(actor.PlayerSession)) return false;
- // If we've gotten this far, fire a cancellable event that indicates someone is about to activate this.
- // This is so that stuff can require further conditions (like power).
- var oae = new ActivatableUIOpenAttemptEvent(user);
- var uae = new UserOpenActivatableUIAttemptEvent(user, aui.Owner);
- RaiseLocalEvent(user, uae, false);
- RaiseLocalEvent((aui).Owner, oae, false);
- if (oae.Cancelled || uae.Cancelled) return false;
+ var ui = aui.UserInterface;
+ if (ui == null) return false;
- // Give the UI an opportunity to prepare itself if it needs to do anything
- // before opening
- var bae = new BeforeActivatableUIOpenEvent(user);
- RaiseLocalEvent((aui).Owner, bae, false);
+ if (aui.SingleUser && (aui.CurrentSingleUser != null) && (actor.PlayerSession != aui.CurrentSingleUser))
+ {
+ // If we get here, supposedly, the object is in use.
+ // Check with BUI that it's ACTUALLY in use just in case.
+ // Since this could brick the object if it goes wrong.
+ if (ui.SubscribedSessions.Count != 0) return false;
+ }
- SetCurrentSingleUser((aui).Owner, actor.PlayerSession, aui);
- ui.Toggle(actor.PlayerSession);
+ // If we've gotten this far, fire a cancellable event that indicates someone is about to activate this.
+ // This is so that stuff can require further conditions (like power).
+ var oae = new ActivatableUIOpenAttemptEvent(user);
+ var uae = new UserOpenActivatableUIAttemptEvent(user, aui.Owner);
+ RaiseLocalEvent(user, uae, false);
+ RaiseLocalEvent((aui).Owner, oae, false);
+ if (oae.Cancelled || uae.Cancelled) return false;
- //Let the component know a user opened it so it can do whatever it needs to do
- var aae = new AfterActivatableUIOpenEvent(user, actor.PlayerSession);
- RaiseLocalEvent((aui).Owner, aae, false);
+ // Give the UI an opportunity to prepare itself if it needs to do anything
+ // before opening
+ var bae = new BeforeActivatableUIOpenEvent(user);
+ RaiseLocalEvent((aui).Owner, bae, false);
- return true;
- }
+ SetCurrentSingleUser((aui).Owner, actor.PlayerSession, aui);
+ ui.Toggle(actor.PlayerSession);
- public void SetCurrentSingleUser(EntityUid uid, IPlayerSession? v, ActivatableUIComponent? aui = null)
- {
- if (!Resolve(uid, ref aui))
- return;
- if (!aui.SingleUser)
- return;
+ //Let the component know a user opened it so it can do whatever it needs to do
+ var aae = new AfterActivatableUIOpenEvent(user, actor.PlayerSession);
+ RaiseLocalEvent((aui).Owner, aae, false);
- aui.CurrentSingleUser = v;
+ return true;
+ }
- RaiseLocalEvent(uid, new ActivatableUIPlayerChangedEvent(), false);
- }
+ public void SetCurrentSingleUser(EntityUid uid, IPlayerSession? v, ActivatableUIComponent? aui = null)
+ {
+ if (!Resolve(uid, ref aui))
+ return;
+ if (!aui.SingleUser)
+ return;
- public void CloseAll(EntityUid uid, ActivatableUIComponent? aui = null)
- {
- if (!Resolve(uid, ref aui, false)) return;
- aui.UserInterface?.CloseAll();
- }
+ aui.CurrentSingleUser = v;
- private void OnHandDeselected(EntityUid uid, ActivatableUIComponent? aui, HandDeselectedEvent args)
- {
- if (!Resolve(uid, ref aui, false)) return;
- if (!aui.CloseOnHandDeselect)
- return;
- CloseAll(uid, aui);
- }
+ RaiseLocalEvent(uid, new ActivatableUIPlayerChangedEvent(), false);
}
- public sealed class ActivatableUIOpenAttemptEvent : CancellableEntityEventArgs
+ public void CloseAll(EntityUid uid, ActivatableUIComponent? aui = null)
{
- public EntityUid User { get; }
- public ActivatableUIOpenAttemptEvent(EntityUid who)
- {
- User = who;
- }
+ if (!Resolve(uid, ref aui, false)) return;
+ aui.UserInterface?.CloseAll();
}
- public sealed class UserOpenActivatableUIAttemptEvent : CancellableEntityEventArgs //have to one-up the already stroke-inducing name
+ private void OnHandDeselected(EntityUid uid, ActivatableUIComponent? aui, HandDeselectedEvent args)
{
- public EntityUid User { get; }
- public EntityUid Target { get; }
- public UserOpenActivatableUIAttemptEvent(EntityUid who, EntityUid target)
- {
- User = who;
- Target = target;
- }
+ if (!Resolve(uid, ref aui, false)) return;
+ if (!aui.CloseOnHandDeselect)
+ return;
+ CloseAll(uid, aui);
}
+}
- public sealed class AfterActivatableUIOpenEvent : EntityEventArgs
+public sealed class ActivatableUIOpenAttemptEvent : CancellableEntityEventArgs
+{
+ public EntityUid User { get; }
+ public ActivatableUIOpenAttemptEvent(EntityUid who)
{
- public EntityUid User { get; }
- public readonly IPlayerSession Session;
+ User = who;
+ }
+}
- public AfterActivatableUIOpenEvent(EntityUid who, IPlayerSession session)
- {
- User = who;
- Session = session;
- }
+public sealed class UserOpenActivatableUIAttemptEvent : CancellableEntityEventArgs //have to one-up the already stroke-inducing name
+{
+ public EntityUid User { get; }
+ public EntityUid Target { get; }
+ public UserOpenActivatableUIAttemptEvent(EntityUid who, EntityUid target)
+ {
+ User = who;
+ Target = target;
}
+}
- /// <summary>
- /// This is after it's decided the user can open the UI,
- /// but before the UI actually opens.
- /// Use this if you need to prepare the UI itself
- /// </summary>
- public sealed class BeforeActivatableUIOpenEvent : EntityEventArgs
+public sealed class AfterActivatableUIOpenEvent : EntityEventArgs
+{
+ public EntityUid User { get; }
+ public readonly IPlayerSession Session;
+
+ public AfterActivatableUIOpenEvent(EntityUid who, IPlayerSession session)
{
- public EntityUid User { get; }
- public BeforeActivatableUIOpenEvent(EntityUid who)
- {
- User = who;
- }
+ User = who;
+ Session = session;
}
+}
- public sealed class ActivatableUIPlayerChangedEvent : EntityEventArgs
+/// <summary>
+/// This is after it's decided the user can open the UI,
+/// but before the UI actually opens.
+/// Use this if you need to prepare the UI itself
+/// </summary>
+public sealed class BeforeActivatableUIOpenEvent : EntityEventArgs
+{
+ public EntityUid User { get; }
+ public BeforeActivatableUIOpenEvent(EntityUid who)
{
+ User = who;
}
}
+
+public sealed class ActivatableUIPlayerChangedEvent : EntityEventArgs
+{
+}
-power-cell-component-examine-details = The charge indicator reads {$currentCharge} %.
\ No newline at end of file
+power-cell-component-examine-details = The charge indicator reads [color=#5E7C16]{$currentCharge}[/color] %.
+power-cell-no-battery = No power cell found
+power-cell-insufficient = Insufficient power
stunbaton-component-low-charge = Insufficient charge...
stunbaton-component-on-examine = The light is currently [color=darkgreen]on[/color].
-stunbaton-component-on-examine-charge = The charge indicator reads {$charge} %
+stunbaton-component-on-examine-charge = The charge indicator reads [color=#5E7C16]{$charge}[/color] %
- type: entity
- id: StationMap
+ id: HandheldStationMap
name: station map
description: Displays a readout of the current station.
- parent: BaseItem
+ parent:
+ - BaseItem
+ - PowerCellSlotSmallItem
suffix: Handheld
components:
- type: StationMap
- state: tablet
- state: generic
shader: unshaded
+ - type: PowerCellDraw
+ drawRate: 0
+ useRate: 20
+ - type: ActivatableUIRequiresPowerCell
- type: ActivatableUI
inHandsOnly: true
singleUser: true
- type: entity
name: handheld crew monitor
- parent: BaseItem
+ parent:
+ - BaseItem
+ - PowerCellSlotSmallItem
id: HandheldCrewMonitor
description: A hand-held crew monitor displaying the status of suit sensors.
components:
- type: Sprite
sprite: Objects/Specific/Medical/handheldcrewmonitor.rsi
state: scanner
+ - type: PowerCellDraw
+ drawRate: 0
+ useRate: 20
+ - type: ActivatableUIRequiresPowerCell
- type: ActivatableUI
key: enum.CrewMonitoringUIKey.Key
closeOnHandDeselect: false
- type: entity
name: health analyzer
- parent: BaseItem
+ parent:
+ - BaseItem
+ - PowerCellSlotSmallItem
id: HandheldHealthAnalyzer
description: A hand-held body scanner capable of distinguishing vital signs of the subject.
components:
sprite: Objects/Specific/Medical/healthanalyzer.rsi
netsync: false
state: analyzer
+ - type: PowerCellDraw
+ drawRate: 0
+ useRate: 20
+ - type: ActivatableUIRequiresPowerCell
- type: ActivatableUI
key: enum.HealthAnalyzerUiKey.Key
closeOnHandDeselect: false
storagebase: !type:Container
ents: []
+
+# PowerCellSlot parents
+- type: entity
+ name: a
+ id: PowerCellSlotSmallItem
+ abstract: true
+ components:
+ - 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: entity
+ name: a
+ id: PowerCellSlotMediumItem
+ abstract: true
+ components:
+ - 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: PowerCellMedium
- type: entity
- id: WallStationMapBroken
+ id: StationMapBroken
name: station map
description: A virtual map of the surrounding station.
suffix: Wall broken
acts: [ "Destruction" ]
- type: entity
- id: WallStationMap
+ id: StationMap
name: station map
- parent: WallStationMapBroken
+ parent: StationMapBroken
suffix: Wall
placement:
mode: SnapgridCenter
collection: GlassBreak
- !type:SpawnEntitiesBehavior
spawn:
- WallStationMapBroken:
+ StationMapBroken:
min: 1
max: 1
- !type:DoActsBehavior