]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Add envelopes (#30298)
authorthemias <89101928+themias@users.noreply.github.com>
Tue, 30 Jul 2024 01:49:05 +0000 (21:49 -0400)
committerGitHub <noreply@github.com>
Tue, 30 Jul 2024 01:49:05 +0000 (21:49 -0400)
* Add envelopes

* oops

* Remove unused loc string

* comments and fixes

12 files changed:
Content.Client/Paper/EnvelopeSystem.cs [new file with mode: 0644]
Content.Shared/Paper/EnvelopeComponent.cs [new file with mode: 0644]
Content.Shared/Paper/EnvelopeSystem.cs [new file with mode: 0644]
Resources/Locale/en-US/paper/envelope.ftl [new file with mode: 0644]
Resources/Prototypes/Catalog/Fills/Boxes/general.yml
Resources/Prototypes/Catalog/Fills/Crates/service.yml
Resources/Prototypes/Catalog/VendingMachines/Inventories/cart.yml
Resources/Prototypes/Entities/Objects/Misc/paper.yml
Resources/Textures/Interface/Paper/paper_heading_postage_stamp.svg.96dpi.png [new file with mode: 0644]
Resources/Textures/Interface/Paper/paper_heading_postage_stamp.svg.96dpi.png.yml [new file with mode: 0644]
Resources/Textures/Objects/Storage/boxes.rsi/envelope.png [new file with mode: 0644]
Resources/Textures/Objects/Storage/boxes.rsi/meta.json

diff --git a/Content.Client/Paper/EnvelopeSystem.cs b/Content.Client/Paper/EnvelopeSystem.cs
new file mode 100644 (file)
index 0000000..f405ed1
--- /dev/null
@@ -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
+    }
+}
diff --git a/Content.Shared/Paper/EnvelopeComponent.cs b/Content.Shared/Paper/EnvelopeComponent.cs
new file mode 100644 (file)
index 0000000..e56fbd8
--- /dev/null
@@ -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
+{
+}
diff --git a/Content.Shared/Paper/EnvelopeSystem.cs b/Content.Shared/Paper/EnvelopeSystem.cs
new file mode 100644 (file)
index 0000000..560c2c8
--- /dev/null
@@ -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);
+        }
+    }
+}
diff --git a/Resources/Locale/en-US/paper/envelope.ftl b/Resources/Locale/en-US/paper/envelope.ftl
new file mode 100644 (file)
index 0000000..bb7993d
--- /dev/null
@@ -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: 
\ No newline at end of file
index 85ee9f9ab89490398d56aad6edff1d103bda8c56..cadf413f47fcb9d1ca804f1b7e751f1e8db23e99 100644 (file)
       - id: DartYellow
         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
\ No newline at end of file
index 693ddab14eca4b8ebd776cb92d022f576ffd8142..d922056a8bf93393466ea33b5559d0e1d7d3afb4 100644 (file)
     - id: BoxFolderRed
     - id: BoxFolderYellow
     - id: NewtonCradle
+    - id: BoxEnvelope
 
 - type: entity
   id: CrateServiceFaxMachine
index cb0ef3246d3d5e78870f43a6b4adc20db79b98d8..303b2090530aaad038dd644d9856f4af45d75e15 100644 (file)
@@ -8,6 +8,7 @@
     RubberStampApproved: 1
     RubberStampDenied: 1
     Paper: 10
+    Envelope: 10
     EncryptionKeyCargo: 2
     EncryptionKeyEngineering: 2
     EncryptionKeyMedical: 2
index 42b850f2b218d616a84b28c6304d390e0c56d1ed..12e1a09a0cef6340beaf68537578fe32952047e4 100644 (file)
         Blunt: 10
   - type: StealTarget
     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" ]
\ No newline at end of file
diff --git a/Resources/Textures/Interface/Paper/paper_heading_postage_stamp.svg.96dpi.png b/Resources/Textures/Interface/Paper/paper_heading_postage_stamp.svg.96dpi.png
new file mode 100644 (file)
index 0000000..ec3566f
Binary files /dev/null and b/Resources/Textures/Interface/Paper/paper_heading_postage_stamp.svg.96dpi.png differ
diff --git a/Resources/Textures/Interface/Paper/paper_heading_postage_stamp.svg.96dpi.png.yml b/Resources/Textures/Interface/Paper/paper_heading_postage_stamp.svg.96dpi.png.yml
new file mode 100644 (file)
index 0000000..5c43e23
--- /dev/null
@@ -0,0 +1,2 @@
+sample:
+  filter: true
diff --git a/Resources/Textures/Objects/Storage/boxes.rsi/envelope.png b/Resources/Textures/Objects/Storage/boxes.rsi/envelope.png
new file mode 100644 (file)
index 0000000..93d5209
Binary files /dev/null and b/Resources/Textures/Objects/Storage/boxes.rsi/envelope.png differ
index 6963a9cdad0b5edb18602ebd0daa77b38ad4d31a..cdae38099d9d0fbd20d88f30590636db86ad8abd 100644 (file)
         },
         {
             "name": "vials"
+        },
+        {
+            "name": "envelope"
         }
     ]
 }