]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
It's time to build a barbershop! (#22565)
authorEd <96445749+TheShuEd@users.noreply.github.com>
Fri, 22 Dec 2023 09:54:00 +0000 (12:54 +0300)
committerGitHub <noreply@github.com>
Fri, 22 Dec 2023 09:54:00 +0000 (02:54 -0700)
* barber!

* 5% change to maintenance

12 files changed:
Content.Client/MagicMirror/MagicMirrorBoundUserInterface.cs
Content.Server/MagicMirror/MagicMirrorComponent.cs
Content.Server/MagicMirror/MagicMirrorSystem.cs
Content.Shared/MagicMirror/SharedMagicMirrorSystem.cs
Resources/Audio/Items/attributions.yml
Resources/Audio/Items/scissors.ogg [new file with mode: 0644]
Resources/Locale/en-US/prototypes/catalog/fills/crates/service-crates.ftl
Resources/Prototypes/Catalog/Fills/Crates/service.yml
Resources/Prototypes/Catalog/Fills/Lockers/misc.yml
Resources/Prototypes/Entities/Objects/Specific/Service/barber.yml [new file with mode: 0644]
Resources/Textures/Objects/Tools/scissors.rsi/icon.png [new file with mode: 0644]
Resources/Textures/Objects/Tools/scissors.rsi/meta.json [new file with mode: 0644]

index ba4362a472e84a4818b0d80d5eed1b59cc3d4b89..ebb6780853ef83d466c576bd781a8f22c3ee9c9e 100644 (file)
@@ -64,5 +64,16 @@ public sealed class MagicMirrorBoundUserInterface : BoundUserInterface
 
         _window.UpdateState(data);
     }
+    protected override void Dispose(bool disposing)
+    {
+        base.Dispose(disposing);
+        if (!disposing)
+            return;
+
+        if (_window != null)
+            _window.OnClose -= Close;
+
+        _window?.Dispose();
+    }
 }
 
index d9c2fff6dafe1857721d7e911543d9db013fb4ff..b974b513cd9b74f45cffd6117e705a2b222282af 100644 (file)
@@ -1,6 +1,25 @@
+using Content.Shared.Humanoid;
+using Robust.Shared.Audio;
+
 namespace Content.Server.MagicMirror;
 
 [RegisterComponent]
 public sealed partial class MagicMirrorComponent : Component
 {
+    public Entity<HumanoidAppearanceComponent>? Target;
+
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float AddSlotTime = 5f;
+
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float RemoveSlotTime = 2f;
+
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float SelectSlotTime = 3f;
+
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float ChangeSlotTime = 1f;
+
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public SoundSpecifier ChangeHairSound = new SoundPathSpecifier("/Audio/Items/scissors.ogg");
 }
index a599a2c868a90eb0180e0248dd750be25af66ca3..eb989eafd61842fa5b82cdc7473ba603b9f74d1c 100644 (file)
@@ -1,16 +1,22 @@
 using System.Linq;
+using Content.Server.DoAfter;
 using Content.Server.Humanoid;
 using Content.Server.UserInterface;
+using Content.Shared.DoAfter;
 using Content.Shared.Humanoid;
 using Content.Shared.Humanoid.Markings;
+using Content.Shared.Interaction;
 using Content.Shared.MagicMirror;
 using Robust.Server.GameObjects;
+using Robust.Shared.Audio.Systems;
 using Robust.Shared.Player;
 
 namespace Content.Server.MagicMirror;
 
 public sealed class MagicMirrorSystem : EntitySystem
 {
+    [Dependency] private readonly SharedAudioSystem _audio = default!;
+    [Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
     [Dependency] private readonly MarkingManager _markings = default!;
     [Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
     [Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
@@ -22,9 +28,27 @@ public sealed class MagicMirrorSystem : EntitySystem
         SubscribeLocalEvent<MagicMirrorComponent, ActivatableUIOpenAttemptEvent>(OnOpenUIAttempt);
         SubscribeLocalEvent<MagicMirrorComponent, AfterActivatableUIOpenEvent>(AfterUIOpen);
         SubscribeLocalEvent<MagicMirrorComponent, MagicMirrorSelectMessage>(OnMagicMirrorSelect);
-        SubscribeLocalEvent<MagicMirrorComponent, MagicMirrorChangeColorMessage>(OnMagicMirrorChangeColor);
-        SubscribeLocalEvent<MagicMirrorComponent, MagicMirrorAddSlotMessage>(OnMagicMirrorAddSlot);
-        SubscribeLocalEvent<MagicMirrorComponent, MagicMirrorRemoveSlotMessage>(OnMagicMirrorRemoveSlot);
+        SubscribeLocalEvent<MagicMirrorComponent, MagicMirrorChangeColorMessage>(OnTryMagicMirrorChangeColor);
+        SubscribeLocalEvent<MagicMirrorComponent, MagicMirrorAddSlotMessage>(OnTryMagicMirrorAddSlot);
+        SubscribeLocalEvent<MagicMirrorComponent, MagicMirrorRemoveSlotMessage>(OnTryMagicMirrorRemoveSlot);
+
+        SubscribeLocalEvent<MagicMirrorComponent, AfterInteractEvent>(OnMagicMirrorInteract);
+
+        SubscribeLocalEvent<MagicMirrorComponent, SelectDoAfterEvent>(OnSelectSlotDoAfter);
+        SubscribeLocalEvent<MagicMirrorComponent, ChangeColorDoAfterEvent>(OnChangeColorDoAfter);
+        SubscribeLocalEvent<MagicMirrorComponent, RemoveSlotDoAfterEvent>(OnRemoveSlotDoAfter);
+        SubscribeLocalEvent<MagicMirrorComponent, AddSlotDoAfterEvent>(OnAddSlotDoAfter);
+    }
+
+    private void OnMagicMirrorInteract(Entity<MagicMirrorComponent> mirror, ref AfterInteractEvent args)
+    {
+        if (!TryComp<ActorComponent>(args.User, out var actor)) return;
+        if (TryComp<HumanoidAppearanceComponent>(args.Target, out var humanoid))
+        {
+            mirror.Comp.Target = new Entity<HumanoidAppearanceComponent>(args.Target.Value, humanoid);
+            UpdateInterface(mirror.Owner, mirror.Comp.Target.Value.Owner, actor.PlayerSession);
+            Log.Debug($"Target {mirror.Comp.Target}!");
+        };
     }
 
     private void OnOpenUIAttempt(EntityUid uid, MagicMirrorComponent mirror, ActivatableUIOpenAttemptEvent args)
@@ -33,16 +57,32 @@ public sealed class MagicMirrorSystem : EntitySystem
             args.Cancel();
     }
 
-    private void OnMagicMirrorSelect(EntityUid uid, MagicMirrorComponent component,
-        MagicMirrorSelectMessage message)
+    private void OnMagicMirrorSelect(EntityUid uid, MagicMirrorComponent component, MagicMirrorSelectMessage message)
     {
-        if (message.Session.AttachedEntity == null || !TryComp<HumanoidAppearanceComponent>(message.Session.AttachedEntity.Value, out var humanoid))
+        if (component.Target == null) return;
+        if (message.Session.AttachedEntity == null) return;
+
+        var doAfter = new SelectDoAfterEvent(message);
+        _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Session.AttachedEntity.Value, component.SelectSlotTime, doAfter, uid, target: component.Target.Value.Owner, used: uid)
         {
+            BreakOnTargetMove = true,
+            BreakOnDamage = true,
+            BreakOnHandChange = false,
+            BreakOnUserMove = true,
+            BreakOnWeightlessMove = false,
+            NeedHand = true
+        });
+
+        _audio.PlayPvs(component.ChangeHairSound, uid);
+    }
+    private void OnSelectSlotDoAfter(EntityUid uid, MagicMirrorComponent component, SelectDoAfterEvent args)
+    {
+        if (args.Handled || args.Args.Target == null || args.Cancelled)
             return;
-        }
+        if (component.Target == null) return;
 
         var category = MarkingCategories.Hair;
-        switch (message.Category)
+        switch (args.Message.Category)
         {
             case MagicMirrorCategory.Hair:
                 category = MarkingCategories.Hair;
@@ -54,21 +94,35 @@ public sealed class MagicMirrorSystem : EntitySystem
                 return;
         }
 
-        _humanoid.SetMarkingId(message.Session.AttachedEntity.Value, category, message.Slot, message.Marking);
+        _humanoid.SetMarkingId(component.Target.Value.Owner, category, args.Message.Slot, args.Message.Marking);
 
-        UpdateInterface(uid, message.Session.AttachedEntity.Value, message.Session);
+        UpdateInterface(uid, component.Target.Value.Owner, args.Message.Session);
     }
 
-    private void OnMagicMirrorChangeColor(EntityUid uid, MagicMirrorComponent component,
-        MagicMirrorChangeColorMessage message)
+    private void OnTryMagicMirrorChangeColor(EntityUid uid, MagicMirrorComponent component, MagicMirrorChangeColorMessage message)
     {
-        if (message.Session.AttachedEntity == null || !TryComp<HumanoidAppearanceComponent>(message.Session.AttachedEntity.Value, out var humanoid))
+        if (component.Target == null) return;
+        if (message.Session.AttachedEntity == null) return;
+
+        var doAfter = new ChangeColorDoAfterEvent(message);
+        _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Session.AttachedEntity.Value, component.ChangeSlotTime, doAfter, uid, target: component.Target.Value.Owner, used: uid)
         {
+            BreakOnTargetMove = true,
+            BreakOnDamage = true,
+            BreakOnHandChange = false,
+            BreakOnUserMove = true,
+            BreakOnWeightlessMove = false,
+            NeedHand = true
+        });
+    }
+    private void OnChangeColorDoAfter(EntityUid uid, MagicMirrorComponent component, ChangeColorDoAfterEvent args)
+    {
+        if (args.Handled || args.Args.Target == null || args.Cancelled)
             return;
-        }
+        if (component.Target == null) return;
 
         var category = MarkingCategories.Hair;
-        switch (message.Category)
+        switch (args.Message.Category)
         {
             case MagicMirrorCategory.Hair:
                 category = MarkingCategories.Hair;
@@ -80,22 +134,39 @@ public sealed class MagicMirrorSystem : EntitySystem
                 return;
         }
 
-        _humanoid.SetMarkingColor(message.Session.AttachedEntity.Value, category, message.Slot, message.Colors);
+        _humanoid.SetMarkingColor(component.Target.Value.Owner, category, args.Message.Slot, args.Message.Colors);
 
         // using this makes the UI feel like total ass
-        // UpdateInterface(uid, message.Session.AttachedEntity.Value, message.Session);
+        // UpdateInterface(uid, component.Target, message.Session);
     }
 
-    private void OnMagicMirrorRemoveSlot(EntityUid uid, MagicMirrorComponent component,
-        MagicMirrorRemoveSlotMessage message)
+    private void OnTryMagicMirrorRemoveSlot(EntityUid uid, MagicMirrorComponent component, MagicMirrorRemoveSlotMessage message)
     {
-        if (message.Session.AttachedEntity == null || !TryComp<HumanoidAppearanceComponent>(message.Session.AttachedEntity.Value, out var humanoid))
+        if (component.Target == null) return;
+        if (message.Session.AttachedEntity == null) return;
+
+        var doAfter = new RemoveSlotDoAfterEvent(message);
+        _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Session.AttachedEntity.Value, component.RemoveSlotTime, doAfter, uid, target: component.Target.Value.Owner, used: uid)
         {
+            BreakOnTargetMove = true,
+            BreakOnDamage = true,
+            BreakOnHandChange = false,
+            BreakOnUserMove = true,
+            BreakOnWeightlessMove = false,
+            NeedHand = true
+        });
+
+        _audio.PlayPvs(component.ChangeHairSound, uid);
+    }
+    private void OnRemoveSlotDoAfter(EntityUid uid, MagicMirrorComponent component, RemoveSlotDoAfterEvent args)
+    {
+        if (args.Handled || args.Args.Target == null || args.Cancelled)
             return;
-        }
+
+        if (component.Target == null) return;
 
         var category = MarkingCategories.Hair;
-        switch (message.Category)
+        switch (args.Message.Category)
         {
             case MagicMirrorCategory.Hair:
                 category = MarkingCategories.Hair;
@@ -107,21 +178,37 @@ public sealed class MagicMirrorSystem : EntitySystem
                 return;
         }
 
-        _humanoid.RemoveMarking(message.Session.AttachedEntity.Value, category, message.Slot);
+        _humanoid.RemoveMarking(component.Target.Value.Owner, category, args.Message.Slot);
 
-        UpdateInterface(uid, message.Session.AttachedEntity.Value, message.Session);
+        UpdateInterface(uid, component.Target.Value.Owner, args.Message.Session);
     }
 
-    private void OnMagicMirrorAddSlot(EntityUid uid, MagicMirrorComponent component,
-        MagicMirrorAddSlotMessage message)
+    private void OnTryMagicMirrorAddSlot(EntityUid uid, MagicMirrorComponent component, MagicMirrorAddSlotMessage message)
     {
-        if (message.Session.AttachedEntity == null || !TryComp<HumanoidAppearanceComponent>(message.Session.AttachedEntity.Value, out var humanoid))
+        if (component.Target == null) return;
+        if (message.Session.AttachedEntity == null) return;
+
+        var doAfter = new AddSlotDoAfterEvent(message);
+        _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Session.AttachedEntity.Value, component.AddSlotTime, doAfter, uid, target: component.Target.Value.Owner, used: uid)
         {
+            BreakOnTargetMove = true,
+            BreakOnDamage = true,
+            BreakOnHandChange = false,
+            BreakOnUserMove = true,
+            BreakOnWeightlessMove = false,
+            NeedHand = true
+        });
+        _audio.PlayPvs(component.ChangeHairSound, uid);
+    }
+    private void OnAddSlotDoAfter(EntityUid uid, MagicMirrorComponent component, AddSlotDoAfterEvent args)
+    {
+        if (args.Handled || args.Args.Target == null || args.Cancelled)
             return;
-        }
+
+        if (component.Target == null) return;
 
         var category = MarkingCategories.Hair;
-        switch (message.Category)
+        switch (args.Message.Category)
         {
             case MagicMirrorCategory.Hair:
                 category = MarkingCategories.Hair;
@@ -133,23 +220,21 @@ public sealed class MagicMirrorSystem : EntitySystem
                 return;
         }
 
-        var marking = _markings.MarkingsByCategoryAndSpecies(category, humanoid.Species).Keys.FirstOrDefault();
+        var marking = _markings.MarkingsByCategoryAndSpecies(category, component.Target.Value.Comp.Species).Keys.FirstOrDefault();
         if (string.IsNullOrEmpty(marking))
         {
             return;
         }
 
-        _humanoid.AddMarking(message.Session.AttachedEntity.Value, marking, Color.Black);
+        _humanoid.AddMarking(component.Target.Value.Owner, marking, Color.Black);
 
-        UpdateInterface(uid, message.Session.AttachedEntity.Value, message.Session);
+        UpdateInterface(uid, component.Target.Value.Owner, args.Message.Session);
     }
 
-    private void UpdateInterface(EntityUid uid, EntityUid playerUid, ICommonSession session, HumanoidAppearanceComponent? humanoid = null)
+    private void UpdateInterface(EntityUid uid, EntityUid playerUid, ICommonSession session)
     {
-        if (!Resolve(playerUid, ref humanoid) || session is not { } player)
-        {
-            return;
-        }
+        if (!TryComp<HumanoidAppearanceComponent>(playerUid, out var humanoid)) return;
+        if (session is not { } player) return;
 
         var hair = humanoid.MarkingSet.TryGetCategory(MarkingCategories.Hair, out var hairMarkings)
             ? new List<Marking>(hairMarkings)
@@ -171,9 +256,9 @@ public sealed class MagicMirrorSystem : EntitySystem
 
     private void AfterUIOpen(EntityUid uid, MagicMirrorComponent component, AfterActivatableUIOpenEvent args)
     {
-        var looks = Comp<HumanoidAppearanceComponent>(args.User);
-        var actor = Comp<ActorComponent>(args.User);
+        if (!TryComp<HumanoidAppearanceComponent>(args.User, out var humanoid)) return;
+        component.Target = new Entity<HumanoidAppearanceComponent>(args.User, humanoid);
 
         UpdateInterface(uid, args.User, args.Session);
     }
-}
\ No newline at end of file
+}
index 831beb06d64d9f4b040bba4025aab0009f180f8a..7d389c90e02a96623e7b813314063840525436e5 100644 (file)
@@ -1,3 +1,4 @@
+using Content.Shared.DoAfter;
 using Content.Shared.Humanoid.Markings;
 using Robust.Shared.Serialization;
 
@@ -104,3 +105,51 @@ public sealed class MagicMirrorUiData : BoundUserInterfaceMessage
     public int FacialHairSlotTotal { get; }
 
 }
+
+[Serializable, NetSerializable]
+public sealed partial class RemoveSlotDoAfterEvent : DoAfterEvent
+{
+    public MagicMirrorRemoveSlotMessage Message;
+
+    public RemoveSlotDoAfterEvent(MagicMirrorRemoveSlotMessage message)
+    {
+        Message = message;
+    }
+    public override DoAfterEvent Clone() => this;
+}
+
+[Serializable, NetSerializable]
+public sealed partial class AddSlotDoAfterEvent : DoAfterEvent
+{
+    public MagicMirrorAddSlotMessage Message;
+
+    public AddSlotDoAfterEvent(MagicMirrorAddSlotMessage message)
+    {
+        Message = message;
+    }
+    public override DoAfterEvent Clone() => this;
+}
+
+[Serializable, NetSerializable]
+public sealed partial class SelectDoAfterEvent : DoAfterEvent
+{
+    public MagicMirrorSelectMessage Message;
+
+    public SelectDoAfterEvent(MagicMirrorSelectMessage message)
+    {
+        Message = message;
+    }
+    public override DoAfterEvent Clone() => this;
+}
+
+[Serializable, NetSerializable]
+public sealed partial class ChangeColorDoAfterEvent : DoAfterEvent
+{
+    public MagicMirrorChangeColorMessage Message;
+
+    public ChangeColorDoAfterEvent(MagicMirrorChangeColorMessage message)
+    {
+        Message = message;
+    }
+    public override DoAfterEvent Clone() => this;
+}
index 7822272424bac3e2bf126fc33acd1401ae86579d..7e186cc076d0b6a37551cd59f7e07cce88e00c5a 100644 (file)
@@ -81,4 +81,9 @@
 - files: ["ring.ogg"]
   license: "CC-BY-SA-3.0"
   copyright: "Taken from /tg/station"
-  source: "https://github.com/tgstation/tgstation/commit/c61c452d78425d89920b41ed5f95fd190e733a3c"
\ No newline at end of file
+  source: "https://github.com/tgstation/tgstation/commit/c61c452d78425d89920b41ed5f95fd190e733a3c"
+  
+- files: ["scissors.ogg"]
+  license: "CC0-1.0"
+  copyright: "User Hanbaal on freesound.org. Converted to ogg by TheShuEd"
+  source: "https://freesound.org/people/Hanbaal/sounds/178669/"
\ No newline at end of file
diff --git a/Resources/Audio/Items/scissors.ogg b/Resources/Audio/Items/scissors.ogg
new file mode 100644 (file)
index 0000000..1031c42
Binary files /dev/null and b/Resources/Audio/Items/scissors.ogg differ
index 2bed24a4ef6cdafb1965e72722bd600a38a279fa..d44be5e979d8040d22e6f88867ccac0f006d9f76 100644 (file)
@@ -32,7 +32,7 @@ ent-CrateJanitorBiosuit = Janitor bio suit crate
     .desc = Contains 2 biohazard suits to ensure that no disease will distract you from cleaning.
 
 ent-CrateServiceTheatre = Theatrical performances crate
-    .desc = Contains a moth cloak, maid uniform, clown and mime attributes, and other performance charms.
+    .desc = Contains a moth cloak, barber scissors, maid uniform, clown and mime attributes, and other performance charms.
 
 ent-CrateJanitorExplosive = Janitorial bomb suit crate
     .desc = Supplies a bomb suit for cleaning up any explosive compounds, buy one today!
index df789208e729c8ba000f2a66b6db579afea57039..a1cb914a1acd3d2450f6940e258e7802b6890548 100644 (file)
@@ -76,6 +76,7 @@
     - id: ClothingUniformJumpskirtJanimaid
     - id: ClothingNeckCloakVoid
     - id: RevolverCapGun
+    - id: BarberScissors
 
 - type: entity
   id: CrateServiceCustomSmokable
index 171546052af977c9f040be9630488f8b9b18ccc3..6acbe12af27d6ab65262d2240244b92f5875287a 100644 (file)
           prob: 0.20
         - id: DrinkSpaceLube
           prob: 0.20
+        - id: BarberScissors
+          prob: 0.05
         # Syndicate loot
         - id: null
           prob: 0.95
diff --git a/Resources/Prototypes/Entities/Objects/Specific/Service/barber.yml b/Resources/Prototypes/Entities/Objects/Specific/Service/barber.yml
new file mode 100644 (file)
index 0000000..e8cb94c
--- /dev/null
@@ -0,0 +1,25 @@
+- type: entity
+  id: BarberScissors
+  name: barber scissors
+  description: is able to reshape the hairstyle of any crew cut to your liking.
+  parent: BaseItem
+  components:
+  - type: Sprite
+    sprite: Objects/Tools/scissors.rsi
+    state: icon
+  - type: MagicMirror
+  - type: ActivatableUI
+    key: enum.MagicMirrorUiKey.Key
+    closeOnHandDeselect: true
+  - type: UserInterface
+    interfaces:
+    - key: enum.MagicMirrorUiKey.Key
+      type: MagicMirrorBoundUserInterface
+  - type: MeleeWeapon
+    wideAnimationRotation: -90
+    attackRate: 1
+    damage:
+      types:
+        Piercing: 6
+    soundHit:
+      path: "/Audio/Weapons/bladeslice.ogg"
\ No newline at end of file
diff --git a/Resources/Textures/Objects/Tools/scissors.rsi/icon.png b/Resources/Textures/Objects/Tools/scissors.rsi/icon.png
new file mode 100644 (file)
index 0000000..b92e522
Binary files /dev/null and b/Resources/Textures/Objects/Tools/scissors.rsi/icon.png differ
diff --git a/Resources/Textures/Objects/Tools/scissors.rsi/meta.json b/Resources/Textures/Objects/Tools/scissors.rsi/meta.json
new file mode 100644 (file)
index 0000000..b544b3b
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "version": 1,
+  "license": "CC0-1.0",
+  "copyright": "Created by TheShuEd(github) for Space Station 14",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "icon"
+    }
+  ]
+}