pet dehydrated fish to make him nice to you (#14709)
* 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>
This commit is contained in:
23
Content.Server/Friends/Components/PettableFriendComponent.cs
Normal file
23
Content.Server/Friends/Components/PettableFriendComponent.cs
Normal file
@@ -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;
|
||||||
|
}
|
||||||
50
Content.Server/Friends/Systems/PettableFriendSystem.cs
Normal file
50
Content.Server/Friends/Systems/PettableFriendSystem.cs
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
Content.Server/NPC/Components/FactionExceptionComponent.cs
Normal file
17
Content.Server/NPC/Components/FactionExceptionComponent.cs
Normal file
@@ -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();
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Interaction;
|
using Content.Server.Interaction;
|
||||||
|
using Content.Server.NPC.Components;
|
||||||
using Content.Server.NPC.Pathfinding;
|
using Content.Server.NPC.Pathfinding;
|
||||||
using Content.Server.NPC.Systems;
|
using Content.Server.NPC.Systems;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
@@ -8,6 +9,7 @@ using Content.Shared.Interaction;
|
|||||||
using Content.Shared.Mobs;
|
using Content.Shared.Mobs;
|
||||||
using Content.Shared.Mobs.Components;
|
using Content.Shared.Mobs.Components;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
|
//using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators;
|
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators;
|
||||||
|
|
||||||
@@ -15,6 +17,7 @@ public abstract class NPCCombatOperator : HTNOperator
|
|||||||
{
|
{
|
||||||
[Dependency] protected readonly IEntityManager EntManager = default!;
|
[Dependency] protected readonly IEntityManager EntManager = default!;
|
||||||
private FactionSystem _factions = default!;
|
private FactionSystem _factions = default!;
|
||||||
|
private FactionExceptionSystem _factionException = default!;
|
||||||
protected InteractionSystem Interaction = default!;
|
protected InteractionSystem Interaction = default!;
|
||||||
private PathfindingSystem _pathfinding = default!;
|
private PathfindingSystem _pathfinding = default!;
|
||||||
|
|
||||||
@@ -38,6 +41,7 @@ public abstract class NPCCombatOperator : HTNOperator
|
|||||||
base.Initialize(sysManager);
|
base.Initialize(sysManager);
|
||||||
sysManager.GetEntitySystem<ExamineSystemShared>();
|
sysManager.GetEntitySystem<ExamineSystemShared>();
|
||||||
_factions = sysManager.GetEntitySystem<FactionSystem>();
|
_factions = sysManager.GetEntitySystem<FactionSystem>();
|
||||||
|
_factionException = sysManager.GetEntitySystem<FactionExceptionSystem>();
|
||||||
Interaction = sysManager.GetEntitySystem<InteractionSystem>();
|
Interaction = sysManager.GetEntitySystem<InteractionSystem>();
|
||||||
_pathfinding = sysManager.GetEntitySystem<PathfindingSystem>();
|
_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));
|
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: Need a perception system instead
|
||||||
// TODO: This will be expensive so will be good to optimise and cut corners.
|
// TODO: This will be expensive so will be good to optimise and cut corners.
|
||||||
foreach (var target in _factions
|
foreach (var target in _factions
|
||||||
@@ -93,7 +99,8 @@ public abstract class NPCCombatOperator : HTNOperator
|
|||||||
if (mobQuery.TryGetComponent(target, out var mobState) &&
|
if (mobQuery.TryGetComponent(target, out var mobState) &&
|
||||||
mobState.CurrentState > MobState.Alive ||
|
mobState.CurrentState > MobState.Alive ||
|
||||||
target == existingTarget ||
|
target == existingTarget ||
|
||||||
target == owner)
|
target == owner ||
|
||||||
|
(factionException != null && _factionException.IsIgnored(factionException, target)))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
33
Content.Server/NPC/Systems/FactionExceptionSystem.cs
Normal file
33
Content.Server/NPC/Systems/FactionExceptionSystem.cs
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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-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-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-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-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-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.
|
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-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-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-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-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-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!
|
petting-failure-possum = You reach out to pet {THE($target)}, but are met with hisses and snarls!
|
||||||
|
|||||||
@@ -88,3 +88,12 @@
|
|||||||
hard: false
|
hard: false
|
||||||
layer:
|
layer:
|
||||||
- LowImpassable
|
- 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
|
||||||
|
|||||||
Reference in New Issue
Block a user