From 74457787c257d93b0702a23d2d8ef17df6ae7c2f Mon Sep 17 00:00:00 2001 From: mirrorcult Date: Sun, 9 Jan 2022 22:47:37 -0700 Subject: [PATCH] Follow verb for ghosts (#6016) * Follow verb for ghosts * oop * Use parenting instead * Update Content.Shared/Follower/FollowerSystem.cs Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> * mfw * parent fixes * figs * oop * porbis Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> --- .../Follower/Components/FollowedComponent.cs | 14 +++ .../Follower/Components/FollowerComponent.cs | 11 ++ Content.Shared/Follower/FollowerSystem.cs | 106 ++++++++++++++++++ .../Locale/en-US/follower/follow-verb.ftl | 1 + 4 files changed, 132 insertions(+) create mode 100644 Content.Shared/Follower/Components/FollowedComponent.cs create mode 100644 Content.Shared/Follower/Components/FollowerComponent.cs create mode 100644 Content.Shared/Follower/FollowerSystem.cs create mode 100644 Resources/Locale/en-US/follower/follow-verb.ftl diff --git a/Content.Shared/Follower/Components/FollowedComponent.cs b/Content.Shared/Follower/Components/FollowedComponent.cs new file mode 100644 index 0000000000..013af41302 --- /dev/null +++ b/Content.Shared/Follower/Components/FollowedComponent.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Robust.Shared.Analyzers; +using Robust.Shared.GameObjects; + +namespace Content.Shared.Follower.Components; + +/// +/// Attached to entities that are currently being followed by a ghost. +/// +[RegisterComponent, ComponentProtoName("Followed"), Friend(typeof(FollowerSystem))] +public class FollowedComponent : Component +{ + public HashSet Following = new(); +} diff --git a/Content.Shared/Follower/Components/FollowerComponent.cs b/Content.Shared/Follower/Components/FollowerComponent.cs new file mode 100644 index 0000000000..c1f204d2a4 --- /dev/null +++ b/Content.Shared/Follower/Components/FollowerComponent.cs @@ -0,0 +1,11 @@ +using Robust.Shared.Analyzers; +using Robust.Shared.GameObjects; + +namespace Content.Shared.Follower.Components; + +[RegisterComponent, ComponentProtoName("Follower")] +[Friend(typeof(FollowerSystem))] +public class FollowerComponent : Component +{ + public EntityUid Following; +} diff --git a/Content.Shared/Follower/FollowerSystem.cs b/Content.Shared/Follower/FollowerSystem.cs new file mode 100644 index 0000000000..d99d02f47a --- /dev/null +++ b/Content.Shared/Follower/FollowerSystem.cs @@ -0,0 +1,106 @@ +using Content.Shared.Database; +using Content.Shared.Ghost; +using Content.Shared.Movement.EntitySystems; +using Content.Shared.Verbs; +using Robust.Shared.GameObjects; +using Robust.Shared.Localization; +using Content.Shared.Follower.Components; +using Robust.Shared.Maths; + +namespace Content.Shared.Follower; + +public class FollowerSystem : EntitySystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnGetAlternativeVerbs); + SubscribeLocalEvent(OnFollowerMove); + SubscribeLocalEvent(OnFollowedTerminating); + } + + private void OnGetAlternativeVerbs(GetAlternativeVerbsEvent ev) + { + if (!HasComp(ev.User)) + return; + + var verb = new Verb + { + Priority = 10, + Act = (() => + { + StartFollowingEntity(ev.User, ev.Target); + }), + Impact = LogImpact.Low, + Text = Loc.GetString("verb-follow-text"), + IconTexture = "/Textures/Interface/VerbIcons/open.svg.192dpi.png", + }; + + ev.Verbs.Add(verb); + } + + private void OnFollowerMove(EntityUid uid, FollowerComponent component, RelayMoveInputEvent args) + { + StopFollowingEntity(uid, component.Following); + } + + // Since we parent our observer to the followed entity, we need to detach + // before they get deleted so that we don't get recursively deleted too. + private void OnFollowedTerminating(EntityUid uid, FollowedComponent component, EntityTerminatingEvent args) + { + StopAllFollowers(uid, component); + } + + /// + /// Makes an entity follow another entity, by parenting to it. + /// + /// The entity that should follow + /// The entity to be followed + public void StartFollowingEntity(EntityUid follower, EntityUid entity) + { + var followerComp = EnsureComp(follower); + followerComp.Following = entity; + + var followedComp = EnsureComp(entity); + followedComp.Following.Add(follower); + + var xform = Transform(follower); + xform.AttachParent(entity); + xform.LocalPosition = Vector2.Zero; + } + + /// + /// Forces an entity to stop following another entity, if it is doing so. + /// + public void StopFollowingEntity(EntityUid uid, EntityUid target, + FollowedComponent? followed=null) + { + if (!Resolve(target, ref followed)) + return; + + if (!HasComp(uid)) + return; + + followed.Following.Remove(uid); + if (followed.Following.Count == 0) + RemComp(target); + RemComp(uid); + Transform(uid).AttachToGridOrMap(); + } + + /// + /// Forces all of an entity's followers to stop following it. + /// + public void StopAllFollowers(EntityUid uid, + FollowedComponent? followed=null) + { + if (!Resolve(uid, ref followed)) + return; + + foreach (var player in followed.Following) + { + StopFollowingEntity(player, uid, followed); + } + } +} diff --git a/Resources/Locale/en-US/follower/follow-verb.ftl b/Resources/Locale/en-US/follower/follow-verb.ftl new file mode 100644 index 0000000000..dbcac9d352 --- /dev/null +++ b/Resources/Locale/en-US/follower/follow-verb.ftl @@ -0,0 +1 @@ +verb-follow-text = Follow