Use distinct action labels for toggling internals on and off. (#36073)
* Use distinct action labels for toggling internals on and off. * Implement specific actions for enabling/disabling internals Avoids potential confusing race conditions where two people might perform the "Toggle Internals On" action an the same person, which would have jsut toggled twice. * If no gas tank, will give popup --------- Co-authored-by: beck-thompson <beck314159@hotmail.com>
This commit is contained in:
@@ -50,7 +50,7 @@ public sealed class InternalsSystem : SharedInternalsSystem
|
|||||||
if (!_respirator.CanMetabolizeGas(uid, tank.Value.Comp.Air))
|
if (!_respirator.CanMetabolizeGas(uid, tank.Value.Comp.Air))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ToggleInternals(uid, uid, force: false, component);
|
ToggleInternals(uid, uid, force: false, component, ToggleMode.On);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInhaleLocation(Entity<InternalsComponent> ent, ref InhaleLocationEvent args)
|
private void OnInhaleLocation(Entity<InternalsComponent> ent, ref InhaleLocationEvent args)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Content.Shared.Atmos.EntitySystems;
|
|||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.IdentityManagement;
|
||||||
using Content.Shared.Internals;
|
using Content.Shared.Internals;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
@@ -50,73 +51,91 @@ public abstract class SharedInternalsSystem : EntitySystem
|
|||||||
|
|
||||||
InteractionVerb verb = new()
|
InteractionVerb verb = new()
|
||||||
{
|
{
|
||||||
Act = () =>
|
|
||||||
{
|
|
||||||
ToggleInternals(ent, user, force: false, ent);
|
|
||||||
},
|
|
||||||
Message = Loc.GetString("action-description-internals-toggle"),
|
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/dot.svg.192dpi.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/dot.svg.192dpi.png")),
|
||||||
Text = Loc.GetString("action-name-internals-toggle"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (AreInternalsWorking(ent))
|
||||||
|
{
|
||||||
|
verb.Act = () => ToggleInternals(ent, user, force: false, ent, ToggleMode.Off);
|
||||||
|
verb.Message = Loc.GetString("action-description-internals-toggle-off");
|
||||||
|
verb.Text = Loc.GetString("action-name-internals-toggle-off");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
verb.Act = () => ToggleInternals(ent, user, force: false, ent, ToggleMode.On);
|
||||||
|
verb.Message = Loc.GetString("action-description-internals-toggle-on");
|
||||||
|
verb.Text = Loc.GetString("action-name-internals-toggle-on");
|
||||||
|
}
|
||||||
|
|
||||||
args.Verbs.Add(verb);
|
args.Verbs.Add(verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ToggleInternals(
|
protected bool ToggleInternals(
|
||||||
EntityUid uid,
|
EntityUid target,
|
||||||
EntityUid user,
|
EntityUid user,
|
||||||
bool force,
|
bool force,
|
||||||
InternalsComponent? internals = null)
|
InternalsComponent? internals = null,
|
||||||
|
ToggleMode mode = ToggleMode.Toggle)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref internals, logMissing: false))
|
if (!Resolve(target, ref internals, logMissing: false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check if a mask is present.
|
// Check if a mask is present.
|
||||||
if (internals.BreathTools.Count == 0)
|
if (internals.BreathTools.Count == 0)
|
||||||
{
|
{
|
||||||
_popupSystem.PopupClient(Loc.GetString("internals-no-breath-tool"), uid, user);
|
var message = user == target ? Loc.GetString("internals-self-no-breath-tool") : Loc.GetString("internals-other-no-breath-tool", ("ent", Identity.Name(target, EntityManager, user)));
|
||||||
|
_popupSystem.PopupClient(message, target, user);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if tank is present.
|
||||||
|
var tank = FindBestGasTank(target);
|
||||||
|
|
||||||
|
// If they're not on then check if we have a mask to use
|
||||||
|
if (tank == null)
|
||||||
|
{
|
||||||
|
var message = user == target ? Loc.GetString("internals-self-no-tank") : Loc.GetString("internals-other-no-tank", ("ent", Identity.Name(target, EntityManager, user)));
|
||||||
|
_popupSystem.PopupClient(message, target, user);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the toggle do-after if it's on someone else.
|
// Start the toggle do-after if it's on someone else.
|
||||||
if (!force && user != uid)
|
if (!force && user != target)
|
||||||
{
|
{
|
||||||
return StartToggleInternalsDoAfter(user, (uid, internals));
|
return StartToggleInternalsDoAfter(user, (target, internals), mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle off.
|
// Toggle off.
|
||||||
if (TryComp(internals.GasTankEntity, out GasTankComponent? gas))
|
if (TryComp(internals.GasTankEntity, out GasTankComponent? gas))
|
||||||
{
|
{
|
||||||
|
if (mode == ToggleMode.On)
|
||||||
|
return false;
|
||||||
|
|
||||||
return _gasTank.DisconnectFromInternals((internals.GasTankEntity.Value, gas), user);
|
return _gasTank.DisconnectFromInternals((internals.GasTankEntity.Value, gas), user);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Check if tank is present.
|
|
||||||
var tank = FindBestGasTank(uid);
|
|
||||||
|
|
||||||
// If they're not on then check if we have a mask to use
|
// No tank was connected, we’ll try to toggle internals on
|
||||||
if (tank == null)
|
|
||||||
{
|
|
||||||
_popupSystem.PopupClient(Loc.GetString("internals-no-tank"), uid, user);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _gasTank.ConnectToInternals(tank.Value, user: user);
|
// If the intent was to disable internals there’s nothing left to do
|
||||||
}
|
if (mode == ToggleMode.Off)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return _gasTank.ConnectToInternals(tank.Value, user: user);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool StartToggleInternalsDoAfter(EntityUid user, Entity<InternalsComponent> targetEnt)
|
private bool StartToggleInternalsDoAfter(EntityUid user, Entity<InternalsComponent> targetEnt, ToggleMode mode)
|
||||||
{
|
{
|
||||||
// Is the target not you? If yes, use a do-after to give them time to respond.
|
// Is the target not you? If yes, use a do-after to give them time to respond.
|
||||||
var isUser = user == targetEnt.Owner;
|
var isUser = user == targetEnt.Owner;
|
||||||
var delay = !isUser ? targetEnt.Comp.Delay : TimeSpan.Zero;
|
var delay = !isUser ? targetEnt.Comp.Delay : TimeSpan.Zero;
|
||||||
|
|
||||||
return _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, delay, new InternalsDoAfterEvent(), targetEnt, target: targetEnt)
|
return _doAfter.TryStartDoAfter(
|
||||||
{
|
new DoAfterArgs(EntityManager, user, delay, new InternalsDoAfterEvent(mode), targetEnt, target: targetEnt)
|
||||||
BreakOnDamage = true,
|
{
|
||||||
BreakOnMove = true,
|
BreakOnDamage = true,
|
||||||
MovementThreshold = 0.1f,
|
BreakOnMove = true,
|
||||||
});
|
MovementThreshold = 0.1f,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDoAfter(Entity<InternalsComponent> ent, ref InternalsDoAfterEvent args)
|
private void OnDoAfter(Entity<InternalsComponent> ent, ref InternalsDoAfterEvent args)
|
||||||
@@ -124,7 +143,7 @@ public abstract class SharedInternalsSystem : EntitySystem
|
|||||||
if (args.Cancelled || args.Handled)
|
if (args.Cancelled || args.Handled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ToggleInternals(ent, args.User, force: true, ent);
|
ToggleInternals(ent, args.User, force: true, ent, args.ToggleMode);
|
||||||
|
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,24 @@ using Robust.Shared.Serialization;
|
|||||||
|
|
||||||
namespace Content.Shared.Internals;
|
namespace Content.Shared.Internals;
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
public enum ToggleMode
|
||||||
public sealed partial class InternalsDoAfterEvent : SimpleDoAfterEvent
|
|
||||||
{
|
{
|
||||||
|
Toggle,
|
||||||
|
On,
|
||||||
|
Off
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed partial class InternalsDoAfterEvent : DoAfterEvent
|
||||||
|
{
|
||||||
|
public ToggleMode ToggleMode = ToggleMode.Toggle;
|
||||||
|
|
||||||
|
public InternalsDoAfterEvent(ToggleMode mode)
|
||||||
|
{
|
||||||
|
ToggleMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override DoAfterEvent Clone() => this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed partial class ToggleInternalsAlertEvent : BaseAlertEvent;
|
public sealed partial class ToggleInternalsAlertEvent : BaseAlertEvent;
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
action-name-internals-toggle = Toggle Internals
|
action-name-internals-toggle-on = Toggle Internals On
|
||||||
action-description-internals-toggle = Breathe from the equipped gas tank. Also requires equipped breath mask.
|
action-description-internals-toggle-on = Breathe from the equipped gas tank. Also requires equipped breath mask.
|
||||||
|
action-name-internals-toggle-off = Toggle Internals Off
|
||||||
|
action-description-internals-toggle-off = Breathe from the environment.
|
||||||
|
|
||||||
internals-no-breath-tool = You are not wearing a breathing tool
|
internals-self-no-breath-tool = You are not wearing a breathing tool
|
||||||
internals-no-tank = You are not wearing a gas tank
|
internals-other-no-breath-tool = {$ent} is not wearing a breathing tool
|
||||||
|
internals-self-no-tank = You are not wearing a gas tank
|
||||||
|
internals-other-no-tank = {$ent} is not wearing a gas tank
|
||||||
|
|||||||
Reference in New Issue
Block a user