Add envelopes (#30298)
* Add envelopes * oops * Remove unused loc string * comments and fixes
This commit is contained in:
35
Content.Client/Paper/EnvelopeSystem.cs
Normal file
35
Content.Client/Paper/EnvelopeSystem.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using Content.Shared.Paper;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Client.Paper;
|
||||||
|
|
||||||
|
public sealed class EnvelopeSystem : VisualizerSystem<EnvelopeComponent>
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<EnvelopeComponent, AfterAutoHandleStateEvent>(OnAfterAutoHandleState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAfterAutoHandleState(Entity<EnvelopeComponent> ent, ref AfterAutoHandleStateEvent args)
|
||||||
|
{
|
||||||
|
UpdateAppearance(ent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateAppearance(Entity<EnvelopeComponent> ent, SpriteComponent? sprite = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(ent.Owner, ref sprite))
|
||||||
|
return;
|
||||||
|
|
||||||
|
sprite.LayerSetVisible(EnvelopeVisualLayers.Open, ent.Comp.State == EnvelopeComponent.EnvelopeState.Open);
|
||||||
|
sprite.LayerSetVisible(EnvelopeVisualLayers.Sealed, ent.Comp.State == EnvelopeComponent.EnvelopeState.Sealed);
|
||||||
|
sprite.LayerSetVisible(EnvelopeVisualLayers.Torn, ent.Comp.State == EnvelopeComponent.EnvelopeState.Torn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum EnvelopeVisualLayers : byte
|
||||||
|
{
|
||||||
|
Open,
|
||||||
|
Sealed,
|
||||||
|
Torn
|
||||||
|
}
|
||||||
|
}
|
||||||
63
Content.Shared/Paper/EnvelopeComponent.cs
Normal file
63
Content.Shared/Paper/EnvelopeComponent.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using Content.Shared.DoAfter;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Paper;
|
||||||
|
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
|
||||||
|
public sealed partial class EnvelopeComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The current open/sealed/torn state of the envelope
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables, DataField, AutoNetworkedField]
|
||||||
|
public EnvelopeState State = EnvelopeState.Open;
|
||||||
|
|
||||||
|
[DataField, ViewVariables]
|
||||||
|
public string SlotId = "letter_slot";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores the current sealing/tearing doafter of the envelope
|
||||||
|
/// to prevent doafter spam/prediction issues
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables]
|
||||||
|
public DoAfterId? EnvelopeDoAfter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How long it takes to seal the envelope closed
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables]
|
||||||
|
public TimeSpan SealDelay = TimeSpan.FromSeconds(1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How long it takes to tear open the envelope
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables]
|
||||||
|
public TimeSpan TearDelay = TimeSpan.FromSeconds(1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The sound to play when the envelope is sealed closed
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables]
|
||||||
|
public SoundPathSpecifier? SealSound = new SoundPathSpecifier("/Audio/Effects/packetrip.ogg");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The sound to play when the envelope is torn open
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables]
|
||||||
|
public SoundPathSpecifier? TearSound = new SoundPathSpecifier("/Audio/Effects/poster_broken.ogg");
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum EnvelopeState : byte
|
||||||
|
{
|
||||||
|
Open,
|
||||||
|
Sealed,
|
||||||
|
Torn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed partial class EnvelopeDoAfterEvent : SimpleDoAfterEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
108
Content.Shared/Paper/EnvelopeSystem.cs
Normal file
108
Content.Shared/Paper/EnvelopeSystem.cs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
using Content.Shared.DoAfter;
|
||||||
|
using Content.Shared.Containers.ItemSlots;
|
||||||
|
using Content.Shared.Verbs;
|
||||||
|
using Robust.Shared.Audio.Systems;
|
||||||
|
using Content.Shared.Examine;
|
||||||
|
|
||||||
|
namespace Content.Shared.Paper;
|
||||||
|
|
||||||
|
public sealed class EnvelopeSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||||
|
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<EnvelopeComponent, ItemSlotInsertAttemptEvent>(OnInsertAttempt);
|
||||||
|
SubscribeLocalEvent<EnvelopeComponent, ItemSlotEjectAttemptEvent>(OnEjectAttempt);
|
||||||
|
SubscribeLocalEvent<EnvelopeComponent, GetVerbsEvent<AlternativeVerb>>(OnGetAltVerbs);
|
||||||
|
SubscribeLocalEvent<EnvelopeComponent, EnvelopeDoAfterEvent>(OnDoAfter);
|
||||||
|
SubscribeLocalEvent<EnvelopeComponent, ExaminedEvent>(OnExamine);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnExamine(Entity<EnvelopeComponent> ent, ref ExaminedEvent args)
|
||||||
|
{
|
||||||
|
if (ent.Comp.State == EnvelopeComponent.EnvelopeState.Sealed)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("envelope-sealed-examine", ("envelope", ent.Owner)));
|
||||||
|
}
|
||||||
|
else if (ent.Comp.State == EnvelopeComponent.EnvelopeState.Torn)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("envelope-torn-examine", ("envelope", ent.Owner)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGetAltVerbs(Entity<EnvelopeComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
|
||||||
|
{
|
||||||
|
if (!args.CanAccess || !args.CanInteract || args.Hands == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ent.Comp.State == EnvelopeComponent.EnvelopeState.Torn)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var user = args.User;
|
||||||
|
args.Verbs.Add(new AlternativeVerb()
|
||||||
|
{
|
||||||
|
Text = Loc.GetString(ent.Comp.State == EnvelopeComponent.EnvelopeState.Open ? "envelope-verb-seal" : "envelope-verb-tear"),
|
||||||
|
IconEntity = GetNetEntity(ent.Owner),
|
||||||
|
Act = () =>
|
||||||
|
{
|
||||||
|
TryStartDoAfter(ent, user, ent.Comp.State == EnvelopeComponent.EnvelopeState.Open ? ent.Comp.SealDelay : ent.Comp.TearDelay);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInsertAttempt(Entity<EnvelopeComponent> ent, ref ItemSlotInsertAttemptEvent args)
|
||||||
|
{
|
||||||
|
args.Cancelled |= ent.Comp.State != EnvelopeComponent.EnvelopeState.Open;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEjectAttempt(Entity<EnvelopeComponent> ent, ref ItemSlotEjectAttemptEvent args)
|
||||||
|
{
|
||||||
|
args.Cancelled |= ent.Comp.State == EnvelopeComponent.EnvelopeState.Sealed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TryStartDoAfter(Entity<EnvelopeComponent> ent, EntityUid user, TimeSpan delay)
|
||||||
|
{
|
||||||
|
if (ent.Comp.EnvelopeDoAfter.HasValue)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var doAfterEventArgs = new DoAfterArgs(EntityManager, user, delay, new EnvelopeDoAfterEvent(), ent.Owner, ent.Owner)
|
||||||
|
{
|
||||||
|
BreakOnDamage = true,
|
||||||
|
NeedHand = true,
|
||||||
|
BreakOnHandChange = true,
|
||||||
|
MovementThreshold = 0.01f,
|
||||||
|
DistanceThreshold = 1.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_doAfterSystem.TryStartDoAfter(doAfterEventArgs, out var doAfterId))
|
||||||
|
ent.Comp.EnvelopeDoAfter = doAfterId;
|
||||||
|
}
|
||||||
|
private void OnDoAfter(Entity<EnvelopeComponent> ent, ref EnvelopeDoAfterEvent args)
|
||||||
|
{
|
||||||
|
ent.Comp.EnvelopeDoAfter = null;
|
||||||
|
|
||||||
|
if (args.Cancelled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ent.Comp.State == EnvelopeComponent.EnvelopeState.Open)
|
||||||
|
{
|
||||||
|
_audioSystem.PlayPredicted(ent.Comp.SealSound, ent.Owner, args.User);
|
||||||
|
ent.Comp.State = EnvelopeComponent.EnvelopeState.Sealed;
|
||||||
|
Dirty(ent.Owner, ent.Comp);
|
||||||
|
}
|
||||||
|
else if (ent.Comp.State == EnvelopeComponent.EnvelopeState.Sealed)
|
||||||
|
{
|
||||||
|
_audioSystem.PlayPredicted(ent.Comp.TearSound, ent.Owner, args.User);
|
||||||
|
ent.Comp.State = EnvelopeComponent.EnvelopeState.Torn;
|
||||||
|
Dirty(ent.Owner, ent.Comp);
|
||||||
|
|
||||||
|
if (_itemSlotsSystem.TryGetSlot(ent.Owner, ent.Comp.SlotId, out var slotComp))
|
||||||
|
_itemSlotsSystem.TryEjectToHands(ent.Owner, slotComp, args.User);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Resources/Locale/en-US/paper/envelope.ftl
Normal file
11
Resources/Locale/en-US/paper/envelope.ftl
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
envelope-verb-seal = Seal
|
||||||
|
envelope-verb-tear = Tear
|
||||||
|
|
||||||
|
envelope-letter-slot = Letter
|
||||||
|
|
||||||
|
envelope-sealed-examine = [color=gray]{CAPITALIZE(THE($envelope))} is sealed.[/color]
|
||||||
|
envelope-torn-examine = [color=yellow]{CAPITALIZE(THE($envelope))} is torn and unusable![/color]
|
||||||
|
|
||||||
|
envelope-default-message = TO:
|
||||||
|
|
||||||
|
FROM:
|
||||||
@@ -432,3 +432,17 @@
|
|||||||
- id: DartYellow
|
- id: DartYellow
|
||||||
amount: 2
|
amount: 2
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: envelope box
|
||||||
|
parent: BoxCardboard
|
||||||
|
id: BoxEnvelope
|
||||||
|
description: A box filled with envelopes.
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: box
|
||||||
|
- state: envelope
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: Envelope
|
||||||
|
amount: 9
|
||||||
@@ -128,6 +128,7 @@
|
|||||||
- id: BoxFolderRed
|
- id: BoxFolderRed
|
||||||
- id: BoxFolderYellow
|
- id: BoxFolderYellow
|
||||||
- id: NewtonCradle
|
- id: NewtonCradle
|
||||||
|
- id: BoxEnvelope
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: CrateServiceFaxMachine
|
id: CrateServiceFaxMachine
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
RubberStampApproved: 1
|
RubberStampApproved: 1
|
||||||
RubberStampDenied: 1
|
RubberStampDenied: 1
|
||||||
Paper: 10
|
Paper: 10
|
||||||
|
Envelope: 10
|
||||||
EncryptionKeyCargo: 2
|
EncryptionKeyCargo: 2
|
||||||
EncryptionKeyEngineering: 2
|
EncryptionKeyEngineering: 2
|
||||||
EncryptionKeyMedical: 2
|
EncryptionKeyMedical: 2
|
||||||
|
|||||||
@@ -564,3 +564,81 @@
|
|||||||
Blunt: 10
|
Blunt: 10
|
||||||
- type: StealTarget
|
- type: StealTarget
|
||||||
stealGroup: BoxFolderQmClipboard
|
stealGroup: BoxFolderQmClipboard
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: envelope
|
||||||
|
parent: BaseItem
|
||||||
|
id: Envelope
|
||||||
|
description: 'A small envelope for keeping prying eyes off of your sensitive documents.'
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Misc/bureaucracy.rsi
|
||||||
|
layers:
|
||||||
|
- state: envelope_open
|
||||||
|
map: ["enum.EnvelopeVisualLayers.Open"]
|
||||||
|
- state: envelope_closed
|
||||||
|
map: ["enum.EnvelopeVisualLayers.Sealed"]
|
||||||
|
visible: false
|
||||||
|
- state: envelope_torn
|
||||||
|
map: ["enum.EnvelopeVisualLayers.Torn"]
|
||||||
|
visible: false
|
||||||
|
- state: paper_stamp-generic
|
||||||
|
map: ["enum.PaperVisualLayers.Stamp"]
|
||||||
|
visible: false
|
||||||
|
- type: Paper
|
||||||
|
escapeFormatting: false
|
||||||
|
content: envelope-default-message
|
||||||
|
- type: PaperVisuals
|
||||||
|
headerImagePath: "/Textures/Interface/Paper/paper_heading_postage_stamp.svg.96dpi.png"
|
||||||
|
headerMargin: 216.0, 0.0, 0.0, 0.0
|
||||||
|
contentMargin: 0.0, 0.0, 0.0, 0.0
|
||||||
|
maxWritableArea: 368.0, 256.0
|
||||||
|
- type: Envelope
|
||||||
|
- type: ContainerContainer
|
||||||
|
containers:
|
||||||
|
letter_slot: !type:ContainerSlot
|
||||||
|
- type: ItemSlots
|
||||||
|
slots:
|
||||||
|
letter_slot:
|
||||||
|
name: envelope-letter-slot
|
||||||
|
insertSound: /Audio/Effects/packetrip.ogg
|
||||||
|
ejectSound: /Audio/Effects/packetrip.ogg
|
||||||
|
whitelist:
|
||||||
|
tags:
|
||||||
|
- Paper
|
||||||
|
- type: ActivatableUI
|
||||||
|
key: enum.PaperUiKey.Key
|
||||||
|
requireHands: false
|
||||||
|
- type: UserInterface
|
||||||
|
interfaces:
|
||||||
|
enum.PaperUiKey.Key:
|
||||||
|
type: PaperBoundUserInterface
|
||||||
|
- type: Item
|
||||||
|
size: Tiny
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- Trash
|
||||||
|
- Document
|
||||||
|
#- type: Appearance, hide stamp marks until we have some kind of displacement
|
||||||
|
- type: Flammable
|
||||||
|
fireSpread: true
|
||||||
|
canResistFire: false
|
||||||
|
alwaysCombustible: true
|
||||||
|
canExtinguish: true
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Heat: 1
|
||||||
|
- type: FireVisuals
|
||||||
|
sprite: Effects/fire.rsi
|
||||||
|
normalState: fire
|
||||||
|
- type: Damageable
|
||||||
|
damageModifierSet: Wood
|
||||||
|
- type: Destructible
|
||||||
|
thresholds:
|
||||||
|
- trigger:
|
||||||
|
!type:DamageTrigger
|
||||||
|
damage: 15
|
||||||
|
behaviors:
|
||||||
|
- !type:EmptyAllContainersBehaviour
|
||||||
|
- !type:DoActsBehavior
|
||||||
|
acts: [ "Destruction" ]
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,2 @@
|
|||||||
|
sample:
|
||||||
|
filter: true
|
||||||
BIN
Resources/Textures/Objects/Storage/boxes.rsi/envelope.png
Normal file
BIN
Resources/Textures/Objects/Storage/boxes.rsi/envelope.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 158 B |
@@ -220,6 +220,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "vials"
|
"name": "vials"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "envelope"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user