]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
pet dehydrated fish to make him nice to you (#14709)
authordeltanedas <39013340+deltanedas@users.noreply.github.com>
Fri, 14 Apr 2023 01:17:25 +0000 (01:17 +0000)
committerGitHub <noreply@github.com>
Fri, 14 Apr 2023 01:17:25 +0000 (18:17 -0700)
* petting fish to make him nice to you

* fix fishe, refactor a bit

* fishe

* pro

* feedback, for now

* refactor

* pro

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
Content.Server/Friends/Components/PettableFriendComponent.cs [new file with mode: 0644]
Content.Server/Friends/Systems/PettableFriendSystem.cs [new file with mode: 0644]
Content.Server/NPC/Components/FactionExceptionComponent.cs [new file with mode: 0644]
Content.Server/NPC/HTN/PrimitiveTasks/Operators/NPCCombatOperator.cs
Content.Server/NPC/Systems/FactionExceptionSystem.cs [new file with mode: 0644]
Resources/Locale/en-US/interaction/interaction-popup-component.ftl
Resources/Prototypes/Entities/Objects/Specific/rehydrateable.yml

diff --git a/Content.Server/Friends/Components/PettableFriendComponent.cs b/Content.Server/Friends/Components/PettableFriendComponent.cs
new file mode 100644 (file)
index 0000000..1840493
--- /dev/null
@@ -0,0 +1,23 @@
+using Content.Server.Friends.Systems;
+
+namespace Content.Server.Friends.Components;
+
+/// <summary>
+/// Pet something to become friends with it (use in hand, press Z)
+/// Uses FactionExceptionComponent behind the scenes
+/// </summary>
+[RegisterComponent, Access(typeof(PettableFriendSystem))]
+public sealed class PettableFriendComponent : Component
+{
+    /// <summary>
+    /// Localized popup sent when petting for the first time
+    /// </summary>
+    [DataField("successString", required: true), ViewVariables(VVAccess.ReadWrite)]
+    public string SuccessString = string.Empty;
+
+    /// <summary>
+    /// Localized popup sent when petting multiple times
+    /// </summary>
+    [DataField("failureString", required: true), ViewVariables(VVAccess.ReadWrite)]
+    public string FailureString = string.Empty;
+}
diff --git a/Content.Server/Friends/Systems/PettableFriendSystem.cs b/Content.Server/Friends/Systems/PettableFriendSystem.cs
new file mode 100644 (file)
index 0000000..6ef9724
--- /dev/null
@@ -0,0 +1,50 @@
+using Content.Server.Chemistry.Components;
+using Content.Server.Friends.Components;
+using Content.Server.NPC.Components;
+using Content.Server.NPC.Systems;
+using Content.Shared.Interaction.Events;
+using Content.Shared.Popups;
+
+namespace Content.Server.Friends.Systems;
+
+public sealed class PettableFriendSystem : EntitySystem
+{
+    [Dependency] private readonly FactionExceptionSystem _factionException = default!;
+    [Dependency] private readonly SharedPopupSystem _popup = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<PettableFriendComponent, UseInHandEvent>(OnUseInHand);
+        SubscribeLocalEvent<PettableFriendComponent, GotRehydratedEvent>(OnRehydrated);
+    }
+
+    private void OnUseInHand(EntityUid uid, PettableFriendComponent comp, UseInHandEvent args)
+    {
+        var user = args.User;
+        if (args.Handled || !TryComp<FactionExceptionComponent>(uid, out var factionException))
+            return;
+
+        if (_factionException.IsIgnored(factionException, user))
+        {
+            _popup.PopupEntity(Loc.GetString(comp.FailureString, ("target", uid)), user, user);
+            return;
+        }
+
+        // you have made a new friend :)
+        _popup.PopupEntity(Loc.GetString(comp.SuccessString, ("target", uid)), user, user);
+        _factionException.IgnoreEntity(factionException, user);
+        args.Handled = true;
+    }
+
+    private void OnRehydrated(EntityUid uid, PettableFriendComponent _, ref GotRehydratedEvent args)
+    {
+        // can only pet before hydrating, after that the fish cannot be negotiated with
+        if (!TryComp<FactionExceptionComponent>(uid, out var comp))
+            return;
+
+        var targetComp = AddComp<FactionExceptionComponent>(args.Target);
+        _factionException.IgnoreEntities(targetComp, comp.Ignored);
+    }
+}
diff --git a/Content.Server/NPC/Components/FactionExceptionComponent.cs b/Content.Server/NPC/Components/FactionExceptionComponent.cs
new file mode 100644 (file)
index 0000000..6611566
--- /dev/null
@@ -0,0 +1,17 @@
+using Content.Server.NPC.Systems;
+
+namespace Content.Server.NPC.Components;
+
+/// <summary>
+/// Prevents an NPC from attacking ignored entities from enemy factions.
+/// Can be added to if pettable, see PettableFriendComponent.
+/// </summary>
+[RegisterComponent, Access(typeof(FactionExceptionSystem))]
+public sealed class FactionExceptionComponent : Component
+{
+    /// <summary>
+    /// List of entities that this NPC will refuse to attack
+    /// </summary>
+    [DataField("ignored")]
+    public HashSet<EntityUid> Ignored = new();
+}
index b0b6b8d7854eb5632fa0f2af38a4e450804c0baa..9b22f70da95d41bc9d5ec83ee06a2ee160c26db4 100644 (file)
@@ -1,6 +1,7 @@
 using System.Threading;
 using System.Threading.Tasks;
 using Content.Server.Interaction;
+using Content.Server.NPC.Components;
 using Content.Server.NPC.Pathfinding;
 using Content.Server.NPC.Systems;
 using Content.Shared.Examine;
@@ -8,6 +9,7 @@ using Content.Shared.Interaction;
 using Content.Shared.Mobs;
 using Content.Shared.Mobs.Components;
 using Robust.Shared.Map;
+//using Robust.Shared.Prototypes;
 
 namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators;
 
@@ -15,6 +17,7 @@ public abstract class NPCCombatOperator : HTNOperator
 {
     [Dependency] protected readonly IEntityManager EntManager = default!;
     private FactionSystem _factions = default!;
+    private FactionExceptionSystem _factionException = default!;
     protected InteractionSystem Interaction = default!;
     private PathfindingSystem _pathfinding = default!;
 
@@ -38,6 +41,7 @@ public abstract class NPCCombatOperator : HTNOperator
         base.Initialize(sysManager);
         sysManager.GetEntitySystem<ExamineSystemShared>();
         _factions = sysManager.GetEntitySystem<FactionSystem>();
+        _factionException = sysManager.GetEntitySystem<FactionExceptionSystem>();
         Interaction = sysManager.GetEntitySystem<InteractionSystem>();
         _pathfinding = sysManager.GetEntitySystem<PathfindingSystem>();
     }
@@ -85,6 +89,8 @@ public abstract class NPCCombatOperator : HTNOperator
             paths.Add(UpdateTarget(owner, existingTarget, existingTarget, ownerCoordinates, blackboard, radius, canMove, xformQuery, targets));
         }
 
+        EntManager.TryGetComponent<FactionExceptionComponent>(owner, out var factionException);
+
         // TODO: Need a perception system instead
         // TODO: This will be expensive so will be good to optimise and cut corners.
         foreach (var target in _factions
@@ -93,7 +99,8 @@ public abstract class NPCCombatOperator : HTNOperator
             if (mobQuery.TryGetComponent(target, out var mobState) &&
                 mobState.CurrentState > MobState.Alive ||
                 target == existingTarget ||
-                target == owner)
+                target == owner ||
+                (factionException != null && _factionException.IsIgnored(factionException, target)))
             {
                 continue;
             }
diff --git a/Content.Server/NPC/Systems/FactionExceptionSystem.cs b/Content.Server/NPC/Systems/FactionExceptionSystem.cs
new file mode 100644 (file)
index 0000000..909fe39
--- /dev/null
@@ -0,0 +1,33 @@
+using Content.Server.NPC.Components;
+
+namespace Content.Server.NPC.Systems;
+
+/// <summary>
+/// Prevents an NPC from attacking some entities from an enemy faction.
+/// </summary>
+public sealed class FactionExceptionSystem : EntitySystem
+{
+    /// <summary>
+    /// Returns whether the entity from an enemy faction won't be attacked
+    /// </summary>
+    public bool IsIgnored(FactionExceptionComponent comp, EntityUid target)
+    {
+        return comp.Ignored.Contains(target);
+    }
+
+    /// <summary>
+    /// Prevents an entity from an enemy faction from being attacked
+    /// </summary>
+    public void IgnoreEntity(FactionExceptionComponent comp, EntityUid target)
+    {
+        comp.Ignored.Add(target);
+    }
+
+    /// <summary>
+    /// Prevents a list of entities from an enemy faction from being attacked
+    /// </summary>
+    public void IgnoreEntities(FactionExceptionComponent comp, IEnumerable<EntityUid> ignored)
+    {
+        comp.Ignored.UnionWith(ignored);
+    }
+}
index 759717ac4045259c45e4da15caa9d8bb16fb9358..40ace46de20af0ec69ccbbdd2799d0fbc246ef15 100644 (file)
@@ -9,6 +9,7 @@ petting-success-bird = You pet {THE($target)} on {POSS-ADJ($target)} cute feathe
 petting-success-cat = You pet {THE($target)} on {POSS-ADJ($target)} fuzzy little head.
 petting-success-corrupted-corgi = In an act of hubris, you pet {THE($target)} on {POSS-ADJ($target)} cursed little head.
 petting-success-crab = You pet {THE($target)} on {POSS-ADJ($target)} smooth little head.
+petting-success-dehydrated-carp = You pet {THE($target)} on {POSS-ADJ($target)} dry little head. {CAPITALIZE(OBJECT($target))} seems to like you now!
 petting-success-dog = You pet {THE($target)} on {POSS-ADJ($target)} soft floofy head.
 petting-success-frog = You pet {THE($target)} on {POSS-ADJ($target)} slippery little head.
 petting-success-goat = You pet {THE($target)} on {POSS-ADJ($target)} horned floofy head.
@@ -29,6 +30,7 @@ petting-failure-generic = You reach out to pet {THE($target)}, but {SUBJECT($tar
 petting-failure-bat = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} too hard to catch!
 petting-failure-corrupted-corgi = You reach out to pet {THE($target)}, but think better of it.
 petting-failure-crab = You reach out to pet {THE($target)}, but {SUBJECT($target)} snaps {POSS-ADJ($target)} claws in your general direction!
+petting-failure-dehydrated-carp = You pet {THE($target)} on {POSS-ADJ($target)} dry little head.
 petting-failure-goat = You reach out to pet {THE($target)}, but {SUBJECT($target)} stubbornly refuses!
 petting-failure-goose = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} too horrible!
 petting-failure-possum = You reach out to pet {THE($target)}, but are met with hisses and snarls!
index 097025120710896537d92af5d924ff0a4fbd5b7d..15d491136736d143d49c0469f96a96adfc58d827 100644 (file)
       hard: false
       layer:
       - LowImpassable
+  # pet fish before rehydrating and he will be nice to you
+  - type: FactionException
+  - type: PettableFriend
+    successString: petting-success-dehydrated-carp
+    failureString: petting-failure-dehydrated-carp
+  - type: EmitSoundOnUse
+    handle: false
+    sound:
+      path: /Audio/Effects/bite.ogg