Add action to pull down mask (#9015)
* Add action to pull down mask * Update based on review comments * fix access * cleanup * Update based on review comments * revert change to ToggleableClothingSystem * switch to unequip * Specify the unequip is for togglemaskevent only * fix issue of activating mask in hands with something else in mask slot * Update based on review comments * switch to dependency for ActionSystem for consistency * whoops other instance too * review changes
This commit is contained in:
20
Content.Server/Clothing/Components/MaskComponent.cs
Normal file
20
Content.Server/Clothing/Components/MaskComponent.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using Content.Shared.Actions;
|
||||||
|
using Content.Shared.Actions.ActionTypes;
|
||||||
|
|
||||||
|
namespace Content.Server.Clothing.Components
|
||||||
|
{
|
||||||
|
[Access(typeof(MaskSystem))]
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class MaskComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This mask can be toggled (pulled up/down)
|
||||||
|
/// </summary>
|
||||||
|
[DataField("toggleAction")]
|
||||||
|
public InstantAction? ToggleAction = null;
|
||||||
|
|
||||||
|
public bool IsToggled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class ToggleMaskEvent : InstantActionEvent { }
|
||||||
|
}
|
||||||
106
Content.Server/Clothing/MaskSystem.cs
Normal file
106
Content.Server/Clothing/MaskSystem.cs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
using Content.Shared.Actions;
|
||||||
|
using Content.Shared.Toggleable;
|
||||||
|
using Content.Shared.Inventory;
|
||||||
|
using Content.Shared.Inventory.Events;
|
||||||
|
using Content.Shared.Item;
|
||||||
|
using Content.Server.Actions;
|
||||||
|
using Content.Server.Atmos.Components;
|
||||||
|
using Content.Server.Body.Components;
|
||||||
|
using Content.Server.Clothing.Components;
|
||||||
|
using Content.Server.Disease.Components;
|
||||||
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
|
using Content.Server.Popups;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
|
namespace Content.Server.Clothing
|
||||||
|
{
|
||||||
|
public sealed class MaskSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||||
|
[Dependency] private readonly ActionsSystem _actionSystem = default!;
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<MaskComponent, ToggleMaskEvent>(OnToggleMask);
|
||||||
|
SubscribeLocalEvent<MaskComponent, GetItemActionsEvent>(OnGetActions);
|
||||||
|
SubscribeLocalEvent<MaskComponent, GotUnequippedEvent>(OnGotUnequipped);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGetActions(EntityUid uid, MaskComponent component, GetItemActionsEvent args)
|
||||||
|
{
|
||||||
|
if (component.ToggleAction != null && !args.InHands)
|
||||||
|
args.Actions.Add(component.ToggleAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnToggleMask(EntityUid uid, MaskComponent mask, ToggleMaskEvent args)
|
||||||
|
{
|
||||||
|
if (mask.ToggleAction == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_inventorySystem.TryGetSlotEntity(args.Performer, "mask", out var existing) || !mask.Owner.Equals(existing))
|
||||||
|
return;
|
||||||
|
|
||||||
|
mask.IsToggled ^= true;
|
||||||
|
_actionSystem.SetToggled(mask.ToggleAction, mask.IsToggled);
|
||||||
|
|
||||||
|
if (mask.IsToggled)
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("action-mask-pull-down-popup-message", ("mask", mask.Owner)), args.Performer, Filter.Entities(args.Performer));
|
||||||
|
else
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("action-mask-pull-up-popup-message", ("mask", mask.Owner)), args.Performer, Filter.Entities(args.Performer));
|
||||||
|
|
||||||
|
ToggleMaskComponents(uid, mask, args.Performer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set to untoggled when unequipped, so it isn't left in a 'pulled down' state
|
||||||
|
private void OnGotUnequipped(EntityUid uid, MaskComponent mask, GotUnequippedEvent args)
|
||||||
|
{
|
||||||
|
if (mask.ToggleAction == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mask.IsToggled = false;
|
||||||
|
_actionSystem.SetToggled(mask.ToggleAction, mask.IsToggled);
|
||||||
|
|
||||||
|
ToggleMaskComponents(uid, mask, args.Equipee, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ToggleMaskComponents(EntityUid uid, MaskComponent mask, EntityUid wearer, bool isEquip = false)
|
||||||
|
{
|
||||||
|
//toggle visuals
|
||||||
|
if (TryComp<SharedItemComponent>(mask.Owner, out var item))
|
||||||
|
{
|
||||||
|
//TODO: sprites for 'pulled down' state. defaults to invisible due to no sprite with this prefix
|
||||||
|
item.EquippedPrefix = mask.IsToggled ? "toggled" : null;
|
||||||
|
Dirty(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
//toggle ingestion blocking
|
||||||
|
if (TryComp<IngestionBlockerComponent>(uid, out var blocker))
|
||||||
|
blocker.Enabled = !mask.IsToggled;
|
||||||
|
|
||||||
|
//toggle disease protection
|
||||||
|
if (TryComp<DiseaseProtectionComponent>(uid, out var diseaseProtection))
|
||||||
|
diseaseProtection.IsActive = !mask.IsToggled;
|
||||||
|
|
||||||
|
//toggle breath tool connection (skip during equip since that is handled in LungSystem)
|
||||||
|
if (isEquip || !TryComp<BreathToolComponent>(uid, out var breathTool))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mask.IsToggled)
|
||||||
|
{
|
||||||
|
breathTool.DisconnectInternals();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
breathTool.IsFunctional = true;
|
||||||
|
|
||||||
|
if (TryComp(wearer, out InternalsComponent? internals))
|
||||||
|
{
|
||||||
|
breathTool.ConnectedInternalsEntity = wearer;
|
||||||
|
internals.ConnectBreathTool(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using Content.Server.Clothing;
|
||||||
|
|
||||||
namespace Content.Server.Nutrition.EntitySystems;
|
namespace Content.Server.Nutrition.EntitySystems;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -7,7 +9,7 @@ namespace Content.Server.Nutrition.EntitySystems;
|
|||||||
/// In the event that more head-wear & mask functionality is added (like identity systems, or raising/lowering of
|
/// In the event that more head-wear & mask functionality is added (like identity systems, or raising/lowering of
|
||||||
/// masks), then this component might become redundant.
|
/// masks), then this component might become redundant.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[RegisterComponent, Access(typeof(FoodSystem), typeof(DrinkSystem))]
|
[RegisterComponent, Access(typeof(FoodSystem), typeof(DrinkSystem), typeof(MaskSystem))]
|
||||||
public sealed class IngestionBlockerComponent : Component
|
public sealed class IngestionBlockerComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
4
Resources/Locale/en-US/actions/actions/mask.ftl
Normal file
4
Resources/Locale/en-US/actions/actions/mask.ftl
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
action-name-mask = Toggle Mask
|
||||||
|
action-description-mask-toggle = Handy, but prevents insertion of pie into your pie hole.
|
||||||
|
action-mask-pull-up-popup-message = You pull up your {$mask}.
|
||||||
|
action-mask-pull-down-popup-message = You pull down your {$mask}.
|
||||||
@@ -7,3 +7,16 @@
|
|||||||
state: icon
|
state: icon
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
Slots: [mask]
|
Slots: [mask]
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
abstract: true
|
||||||
|
parent: ClothingMaskBase
|
||||||
|
id: ClothingMaskPullableBase
|
||||||
|
components:
|
||||||
|
- type: Mask
|
||||||
|
toggleAction:
|
||||||
|
name: action-name-mask
|
||||||
|
description: action-description-mask-toggle
|
||||||
|
icon: Clothing/Mask/gas.rsi/icon.png
|
||||||
|
iconOn: Interface/Inventory/blocked.png
|
||||||
|
event: !type:ToggleMaskEvent
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingMaskBase
|
parent: ClothingMaskPullableBase
|
||||||
id: ClothingMaskGas
|
id: ClothingMaskGas
|
||||||
name: gas mask
|
name: gas mask
|
||||||
description: A face-covering mask that can be connected to an air supply.
|
description: A face-covering mask that can be connected to an air supply.
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
protection: 0.05
|
protection: 0.05
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingMaskBase
|
parent: ClothingMaskPullableBase
|
||||||
id: ClothingMaskGasSecurity
|
id: ClothingMaskGasSecurity
|
||||||
name: security gas mask
|
name: security gas mask
|
||||||
description: A standard issue Security gas mask.
|
description: A standard issue Security gas mask.
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
protection: 0.05
|
protection: 0.05
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingMaskBase
|
parent: ClothingMaskPullableBase
|
||||||
id: ClothingMaskGasSyndicate
|
id: ClothingMaskGasSyndicate
|
||||||
name: syndicate gas mask
|
name: syndicate gas mask
|
||||||
description: A close-fitting tactical mask that can be connected to an air supply.
|
description: A close-fitting tactical mask that can be connected to an air supply.
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
- type: FlashImmunity
|
- type: FlashImmunity
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingMaskBase
|
parent: ClothingMaskPullableBase
|
||||||
id: ClothingMaskGasAtmos
|
id: ClothingMaskGasAtmos
|
||||||
name: atmospheric gas mask
|
name: atmospheric gas mask
|
||||||
description: Improved gas mask utilized by atmospheric technicians. It's flameproof!
|
description: Improved gas mask utilized by atmospheric technicians. It's flameproof!
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
protection: 0.05
|
protection: 0.05
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingMaskBase
|
parent: ClothingMaskPullableBase
|
||||||
id: ClothingMaskGasExplorer
|
id: ClothingMaskGasExplorer
|
||||||
name: explorer gas mask
|
name: explorer gas mask
|
||||||
description: A military-grade gas mask that can be connected to an air supply.
|
description: A military-grade gas mask that can be connected to an air supply.
|
||||||
@@ -116,7 +116,7 @@
|
|||||||
Heat: 0.95
|
Heat: 0.95
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingMaskBase
|
parent: ClothingMaskPullableBase
|
||||||
id: ClothingMaskBreathMedical
|
id: ClothingMaskBreathMedical
|
||||||
name: medical mask
|
name: medical mask
|
||||||
description: A close-fitting sterile mask that can be connected to an air supply.
|
description: A close-fitting sterile mask that can be connected to an air supply.
|
||||||
@@ -131,7 +131,7 @@
|
|||||||
protection: 0.10
|
protection: 0.10
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingMaskBase
|
parent: ClothingMaskPullableBase
|
||||||
id: ClothingMaskBreath
|
id: ClothingMaskBreath
|
||||||
name: breath mask
|
name: breath mask
|
||||||
description: Might as well keep this on 24/7.
|
description: Might as well keep this on 24/7.
|
||||||
@@ -182,7 +182,7 @@
|
|||||||
- type: BreathMask
|
- type: BreathMask
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingMaskBase
|
parent: ClothingMaskPullableBase
|
||||||
id: ClothingMaskSterile
|
id: ClothingMaskSterile
|
||||||
name: sterile mask
|
name: sterile mask
|
||||||
description: A sterile mask designed to help prevent the spread of diseases.
|
description: A sterile mask designed to help prevent the spread of diseases.
|
||||||
@@ -211,7 +211,7 @@
|
|||||||
replacement: mumble
|
replacement: mumble
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingMaskBase
|
parent: ClothingMaskPullableBase
|
||||||
id: ClothingMaskPlague
|
id: ClothingMaskPlague
|
||||||
name: plague doctor mask
|
name: plague doctor mask
|
||||||
description: A bad omen.
|
description: A bad omen.
|
||||||
|
|||||||
Reference in New Issue
Block a user