From 40ae49bb8502ef7dddc63efa74f9daf7425eef16 Mon Sep 17 00:00:00 2001 From: ScarKy0 <106310278+ScarKy0@users.noreply.github.com> Date: Sun, 14 Dec 2025 03:04:28 +0100 Subject: [PATCH] Killsign cleanup (#41845) * init * rsi * review * scale * it * cat, dog, nerd * rsi * I just microbalanced animation speed * raider, stinky resprite * review * HideFromOwner * hidden smite * copyright * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- .../Administration/Systems/KillSignSystem.cs | 61 ++++++++--- .../Systems/AdminVerbSystem.Smites.cs | 21 +++- .../Components/KillSignComponent.cs | 43 +++++++- .../Locale/en-US/administration/smites.ftl | 2 + .../Objects/Misc/killsign.rsi/bald.png | Bin 0 -> 478 bytes .../Objects/Misc/killsign.rsi/cat.png | Bin 0 -> 444 bytes .../Objects/Misc/killsign.rsi/dog.png | Bin 0 -> 448 bytes .../Objects/Misc/killsign.rsi/furry.png | Bin 0 -> 457 bytes .../Objects/Misc/killsign.rsi/icon-hidden.png | Bin 0 -> 248 bytes .../Textures/Objects/Misc/killsign.rsi/it.png | Bin 0 -> 367 bytes .../Misc/killsign.rsi/{sign.png => kill.png} | Bin .../Objects/Misc/killsign.rsi/meta.json | 102 +++++++++++++++++- .../Objects/Misc/killsign.rsi/nerd.png | Bin 0 -> 490 bytes .../Objects/Misc/killsign.rsi/peak.png | Bin 0 -> 460 bytes .../Objects/Misc/killsign.rsi/raider.png | Bin 0 -> 443 bytes .../Objects/Misc/killsign.rsi/stinky.png | Bin 0 -> 423 bytes 16 files changed, 206 insertions(+), 23 deletions(-) create mode 100644 Resources/Textures/Objects/Misc/killsign.rsi/bald.png create mode 100644 Resources/Textures/Objects/Misc/killsign.rsi/cat.png create mode 100644 Resources/Textures/Objects/Misc/killsign.rsi/dog.png create mode 100644 Resources/Textures/Objects/Misc/killsign.rsi/furry.png create mode 100644 Resources/Textures/Objects/Misc/killsign.rsi/icon-hidden.png create mode 100644 Resources/Textures/Objects/Misc/killsign.rsi/it.png rename Resources/Textures/Objects/Misc/killsign.rsi/{sign.png => kill.png} (100%) create mode 100644 Resources/Textures/Objects/Misc/killsign.rsi/nerd.png create mode 100644 Resources/Textures/Objects/Misc/killsign.rsi/peak.png create mode 100644 Resources/Textures/Objects/Misc/killsign.rsi/raider.png create mode 100644 Resources/Textures/Objects/Misc/killsign.rsi/stinky.png diff --git a/Content.Client/Administration/Systems/KillSignSystem.cs b/Content.Client/Administration/Systems/KillSignSystem.cs index f15cfe6442..f17c384c1e 100644 --- a/Content.Client/Administration/Systems/KillSignSystem.cs +++ b/Content.Client/Administration/Systems/KillSignSystem.cs @@ -1,46 +1,77 @@ using System.Numerics; using Content.Shared.Administration.Components; using Robust.Client.GameObjects; -using Robust.Shared.Utility; +using Robust.Client.Player; namespace Content.Client.Administration.Systems; public sealed class KillSignSystem : EntitySystem { [Dependency] private readonly SpriteSystem _sprite = default!; + [Dependency] private readonly IPlayerManager _player = default!; public override void Initialize() { SubscribeLocalEvent(KillSignAdded); SubscribeLocalEvent(KillSignRemoved); + SubscribeLocalEvent(AfterAutoHandleState); } - private void KillSignRemoved(EntityUid uid, KillSignComponent component, ComponentShutdown args) + private void KillSignRemoved(Entity ent, ref ComponentShutdown args) { - if (!TryComp(uid, out var sprite)) - return; + RemoveKillsign(ent); + } - if (!_sprite.LayerMapTryGet((uid, sprite), KillSignKey.Key, out var layer, false)) - return; + private void KillSignAdded(Entity ent, ref ComponentStartup args) + { + AddKillsign(ent); + } - _sprite.RemoveLayer((uid, sprite), layer); + private void AfterAutoHandleState(Entity ent, ref AfterAutoHandleStateEvent args) + { + // After receiving a new state for the component, we remove the old killsign and build a new one. + // This is so changes to the sprite can be displayed live and allowing them to be edited via ViewVariables. + // This could just update an existing sprite, but this is both easier and runs rarely anyway. + RemoveKillsign(ent); + AddKillsign(ent); } - private void KillSignAdded(EntityUid uid, KillSignComponent component, ComponentStartup args) + private void AddKillsign(Entity ent) { - if (!TryComp(uid, out var sprite)) + // If we hide from owner and we ARE the owner, don't add a killsign. + // This could use session specific networking to FULLY hide it, but I am too lazy right now. + if (ent.Comp.HideFromOwner && _player.LocalEntity == ent) + return; + + if (!TryComp(ent, out var sprite)) return; - if (_sprite.LayerMapTryGet((uid, sprite), KillSignKey.Key, out var _, false)) + if (_sprite.LayerMapTryGet((ent, sprite), KillSignKey.Key, out var _, false)) return; - var adj = _sprite.GetLocalBounds((uid, sprite)).Height / 2 + ((1.0f / 32) * 6.0f); + if (ent.Comp.Sprite == null) + return; - var layer = _sprite.AddLayer((uid, sprite), new SpriteSpecifier.Rsi(new ResPath("Objects/Misc/killsign.rsi"), "sign")); - _sprite.LayerMapSet((uid, sprite), KillSignKey.Key, layer); + var adj = _sprite.GetLocalBounds((ent, sprite)).Height / 2 + ((1.0f / 32) * 6.0f); + + var layer = _sprite.AddLayer((ent, sprite), ent.Comp.Sprite); + _sprite.LayerMapSet((ent, sprite), KillSignKey.Key, layer); + _sprite.LayerSetScale((ent, sprite), layer, ent.Comp.Scale); + _sprite.LayerSetOffset((ent, sprite), layer, ent.Comp.DoOffset ? new Vector2(0.0f, adj) : new Vector2(0.0f, 0.0f)); + + if (ent.Comp.ForceUnshaded) + sprite.LayerSetShader(layer, "unshaded"); + } + + private void RemoveKillsign(Entity ent) + { + if (!TryComp(ent, out var sprite)) + return; + + if (!_sprite.LayerMapTryGet((ent, sprite), KillSignKey.Key, out var layer, false)) + return; - _sprite.LayerSetOffset((uid, sprite), layer, new Vector2(0.0f, adj)); - sprite.LayerSetShader(layer, "unshaded"); + _sprite.RemoveLayer((ent, sprite), layer); } private enum KillSignKey diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs index b7f88e6c3c..f367acbd79 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs @@ -573,13 +573,32 @@ public sealed partial class AdminVerbSystem Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/killsign.rsi"), "icon"), Act = () => { - EnsureComp(args.Target); + EnsureComp(args.Target, out var comp); + comp.HideFromOwner = false; // We set it to false anyway, in case the hidden smite was used beforehand. + Dirty(args.Target, comp); }, Impact = LogImpact.Extreme, Message = string.Join(": ", killSignName, Loc.GetString("admin-smite-kill-sign-description")) }; args.Verbs.Add(killSign); + var hiddenKillSignName = Loc.GetString("admin-smite-kill-sign-hidden-name").ToLowerInvariant(); + Verb hiddenKillSign = new() + { + Text = hiddenKillSignName, + Category = VerbCategory.Smite, + Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/killsign.rsi"), "icon-hidden"), + Act = () => + { + EnsureComp(args.Target, out var comp); + comp.HideFromOwner = true; + Dirty(args.Target, comp); + }, + Impact = LogImpact.Extreme, + Message = string.Join(": ", hiddenKillSignName, Loc.GetString("admin-smite-kill-sign-hidden-description")) + }; + args.Verbs.Add(hiddenKillSign); + var cluwneName = Loc.GetString("admin-smite-cluwne-name").ToLowerInvariant(); Verb cluwne = new() { diff --git a/Content.Shared/Administration/Components/KillSignComponent.cs b/Content.Shared/Administration/Components/KillSignComponent.cs index 34c36759cc..796a98a71d 100644 --- a/Content.Shared/Administration/Components/KillSignComponent.cs +++ b/Content.Shared/Administration/Components/KillSignComponent.cs @@ -1,6 +1,43 @@ -using Robust.Shared.GameStates; +using System.Numerics; +using Robust.Shared.GameStates; +using Robust.Shared.Utility; namespace Content.Shared.Administration.Components; -[RegisterComponent, NetworkedComponent] -public sealed partial class KillSignComponent : Component; +/// +/// Displays a sprite above an entity. +/// By default a huge sign saying "KILL". +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(raiseAfterAutoHandleState: true)] +public sealed partial class KillSignComponent : Component +{ + /// + /// The sprite show above the entity. + /// + [DataField, AutoNetworkedField] + public SpriteSpecifier? Sprite = new SpriteSpecifier.Rsi(new ResPath("Objects/Misc/killsign.rsi"), "kill"); + + /// + /// Whether the granted layer should always be forced to be unshaded. + /// + [DataField, AutoNetworkedField] + public bool ForceUnshaded = true; + + /// + /// Whether the granted layer should be offset to be above the entity. + /// + [DataField, AutoNetworkedField] + public bool DoOffset = true; + + /// + /// Prevents the sign from displaying to the owner of the component, allowing everyone but them to see it. + /// + [DataField, AutoNetworkedField] + public bool HideFromOwner = false; + + /// + /// The scale of the sprite. + /// + [DataField, AutoNetworkedField] + public Vector2 Scale = Vector2.One; +} diff --git a/Resources/Locale/en-US/administration/smites.ftl b/Resources/Locale/en-US/administration/smites.ftl index e8dfbd2055..0702afb33c 100644 --- a/Resources/Locale/en-US/administration/smites.ftl +++ b/Resources/Locale/en-US/administration/smites.ftl @@ -58,6 +58,7 @@ admin-smite-vomit-organs-name = Vomit Organs admin-smite-ghostkick-name = Ghost Kick admin-smite-nyanify-name = Cat Ears admin-smite-kill-sign-name = Kill Sign +admin-smite-kill-sign-hidden-name = Hidden Kill Sign admin-smite-omni-accent-name = Omni-Accent admin-smite-crawler-name = Crawler admin-smite-homing-rod-name = Homing Rod @@ -82,6 +83,7 @@ admin-smite-become-bread-description = It turns them into bread. Really, that's admin-smite-ghostkick-description = Silently kicks the user, dropping their connection. admin-smite-nyanify-description = Forcibly add cat ears, there is no escape. admin-smite-kill-sign-description = Marks a player for death by their fellows. +admin-smite-kill-sign-hidden-description = Marks a player for death by their fellows. Hidden from the targeted player. admin-smite-cluwne-description = Cluwnes them. The suit cannot be removed and the station's crew may murder them freely. admin-smite-anger-pointing-arrows-description = Angers the pointing arrows, causing them to assault this entity explosively. admin-smite-dust-description = Reduces the target to a small pile of ash. diff --git a/Resources/Textures/Objects/Misc/killsign.rsi/bald.png b/Resources/Textures/Objects/Misc/killsign.rsi/bald.png new file mode 100644 index 0000000000000000000000000000000000000000..f821c632b4504b283e8de594f68e33bd27d76df4 GIT binary patch literal 478 zcmV<40U`d0P)&69m%`Wi z<^WHt$?5HN=6wHp`D~?e9K*RWyL`@r?=akeG)IHh-uur-(fzqSCjjsd!87h2y#}Q5 z5Ohr}2=EWV^SxPTjmPZb8XAP40(Q%-+DQqGO$eCQ$sC*F75M9n_y;P_-F)j!ST&*Y z1ljJJuIheH04NX)p0zPRhsLc4rGa4ZtX(=OIsu>#LkaT*p(fN}*xMI`l0+5YL+T4+ zpkx%s>2fZc)Ne9w z6NC}-MV!vB-L@Lft8wgW!HD@HPUq`Pbk%rU=CwKiDGkU~Ykw=H0g3dpTVO~G-T|Gq zfP|(nra)5|B?g}Xog4sFo{KgVCuo`@E(FlcMH@~5Xwnhah1MX#|XjC<~ zxL80JjVgDGGv2_9S5v3GFOyQIJo}?4AhmY@O z+r7UnuIuOB%z9SRiP-}@#a@W6xp7=alBe?bak_by8^?7dIprmEFrsFR!KOTlX6-VV z%5y=~j4?2PN71ZZ22*(mF#}fBx<0hWglqQ;oVfq}8EpTk61ZoACC~@7_Df452U`2C zl6d$G7~BDf`jkBcQ4jSH(E+{=KNh|Y-xt9iAl0ul+e>CYkm}br+hgS*ssy<4uF*(! zBzY>_c-Ls8I+9!=B&T&LQYOTtZ3#RRtR66B#|A^b^(hXL8iOG_>=S|`U6VeXAE2r2Qrk!D@*y|2} zG;sqY_RQ06feL>$S8iknrzJ&zKPiG*RvrJb)1)XI$GLkxi}!jp{b~odg+7|U#jZW$ z|9pw!k;G>vrAO`;jQ>6 z&CxRe;l_^H5r9_AIuXr3W=CZ_PoKp1(TZUOE%7z~m>rcdpS`rUK`mefl|}ERbLsbNTod{RgPWXxgwHIUO2;RhZulr z%6XbZyT)1un_lW^GI_F^2)UCdG!gnF4|+{F6k)97iBN>T$q$0AwD=u0@IQ2=9r_ik zPP?e!pi^J!26>E)xb-D&kdEUxj^j9va|0XzoXBLJR}o)T00000NkvXXu0mjf5KPC_ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Misc/killsign.rsi/icon-hidden.png b/Resources/Textures/Objects/Misc/killsign.rsi/icon-hidden.png new file mode 100644 index 0000000000000000000000000000000000000000..443177e07be311be1b0181baee46c5d1f61a973a GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?31We{epSZZGe6kO%$ z;usRqnw%iPx;R0kr-_lR$KV)KX4`+Q93CFC?;E>i15F(|VX95r3a za5pBRgJ++Bf*R{&X0}`@i2`Q8LNR;uUdkVD6rGOq8dtJ0LLj$z-Jt#<0rJEJLC$iIgn zhc1tNosY}=U$Ru3@41I3ZO4fiRV9g5<4dzSX0%??FWBg93~+}JeG?DUP`6pHEcnkbE!E-$7u zf=U4R-!gC^r4dY2s=~m7Q=bdSlFhBTmjMPIocdfqmMjlhl>TUAeL-m2dBhilD$WCy z47P*Nmh*@mgsRTh0_T5NTUGo4=YLo^^uOV99$|G}5ClOG1VIqG%?q@Wf)|BvCr$tW N002ovPDHLkV1gLPo+AqgfjsmULuQX#)*FNBN`M{88+nO$LenRk$uMCVI*_zg+Kh;(F)THWq ze)Y_Mr%fjPQb@UE`ZxG$=z42K8B6WT8!gB0KK-S1hwu9q-+9S8vwMVZfB7-%?XSx6 z;!;_^_;cZF5W){ybeFNtuvos=^nQ7K$-Eu4A`LrPli0tu-?VGZ4z2lE@R6QxxZ4yTi{urVTzDn}l%RDd()6!! z9a=b7e2u~s3;r%K8TLfY=dBhTOV5QjDkLcWh%0#%Z(#1%AE$m}UfenE*tz90#|wdI c&i}LgJq$9A%`C3$z{q3pboFyt=akR{0P>E}Jpcdz literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Misc/killsign.rsi/peak.png b/Resources/Textures/Objects/Misc/killsign.rsi/peak.png new file mode 100644 index 0000000000000000000000000000000000000000..165c6c56e520f0d0dbfcc22a3caa55bcd01f8404 GIT binary patch literal 460 zcmV;-0WTb8pV9{ym;6xBhHfx69#nwBfVB>96wMzug}; zAFbE-tJ!dSV|zS%Xca-l z@4i}d(JV<>_3Q##MR?*HU%M+{Oce3Ck;DUj1!yJD?OH`}6!BWgbGud%94;Q{u7Fg5 z8i|=t6{sTU39kW>6L`c_P{$n6-*|wS3gUB2w+7&p060!ZDg%Q6j?Ont&*LFg-f z7!U;L9&jxI1Od87sSZ|CN<30jykQuIVHk#CyfjzU8~+6I2`?-F00006BAu|h0aX81`om3iJ9l% z1SiGFD%~0>2>%_b=CNu z=g0Jzwq73l%d_p?p_Om#htE`3jqiDWOpj?tnThJ;?W-AIF2o;d%@STeXWyg0cSZKw z1fUuSLIVgZ9qK9WKAQI!%n!RNW(%Mi2tor0D;?@7uAVnelMsUWVOO!OgLOa(1X-&q z0D}B2d2PznNv_sV=XpK0wZ3ky8z;BI)l$7LydK+1ZUNT2-~&#HbwJJ*V7&`I;FMSg zjIsszYcVzawJCcQY(11 lUoCjUFbu;m48!>Q>;V4g^rOpyR{8({002ovPDHLkV1nEm!KDBI literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Misc/killsign.rsi/stinky.png b/Resources/Textures/Objects/Misc/killsign.rsi/stinky.png new file mode 100644 index 0000000000000000000000000000000000000000..1924bd354d979119b085a931831b815be0b052a1 GIT binary patch literal 423 zcmV;Y0a*TtP)sgB`Z-Ro6z~dSm?*2_eRKLjG`#YKc<+y&71x7(01%z>rS6*EL9sU zpBHV6kEc!XxSlq$&o!2+U1l(~#b@MD_>7cPY#=La|Gxj6+cIOJK&I~YQ+#MWKvv{l zcBc=@jP4wy~ItIJU76fhQ(D#QQRB8;iM! zLt{&93Io_!EEHx#v92`~k2f~r%HX9?m<`3c*3g&|$DA2Sjm)@j4#t>~)X0qc=48DD zl{=t_z4%g*