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>
This commit is contained in:
ScarKy0 2025-12-14 03:04:28 +01:00 committed by BarryNorfolk
parent 4a47f4784f
commit de23957918
16 changed files with 208 additions and 25 deletions

View File

@ -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<KillSignComponent, ComponentStartup>(KillSignAdded);
SubscribeLocalEvent<KillSignComponent, ComponentShutdown>(KillSignRemoved);
SubscribeLocalEvent<KillSignComponent, AfterAutoHandleStateEvent>(AfterAutoHandleState);
}
private void KillSignRemoved(EntityUid uid, KillSignComponent component, ComponentShutdown args)
private void KillSignRemoved(Entity<KillSignComponent> ent, ref ComponentShutdown args)
{
if (!TryComp<SpriteComponent>(uid, out var sprite))
return;
if (!_sprite.LayerMapTryGet((uid, sprite), KillSignKey.Key, out var layer, false))
return;
_sprite.RemoveLayer((uid, sprite), layer);
RemoveKillsign(ent);
}
private void KillSignAdded(EntityUid uid, KillSignComponent component, ComponentStartup args)
private void KillSignAdded(Entity<KillSignComponent> ent, ref ComponentStartup args)
{
if (!TryComp<SpriteComponent>(uid, out var sprite))
AddKillsign(ent);
}
private void AfterAutoHandleState(Entity<KillSignComponent> 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 AddKillsign(Entity<KillSignComponent> ent)
{
// 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 (_sprite.LayerMapTryGet((uid, sprite), KillSignKey.Key, out var _, false))
if (!TryComp<SpriteComponent>(ent, out var sprite))
return;
var adj = _sprite.GetLocalBounds((uid, sprite)).Height / 2 + ((1.0f / 32) * 6.0f);
if (_sprite.LayerMapTryGet((ent, sprite), KillSignKey.Key, out var _, false))
return;
var layer = _sprite.AddLayer((uid, sprite), new SpriteSpecifier.Rsi(new ResPath("Objects/Misc/killsign.rsi"), "sign"));
_sprite.LayerMapSet((uid, sprite), KillSignKey.Key, layer);
if (ent.Comp.Sprite == null)
return;
_sprite.LayerSetOffset((uid, sprite), layer, new Vector2(0.0f, adj));
sprite.LayerSetShader(layer, "unshaded");
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<KillSignComponent> ent)
{
if (!TryComp<SpriteComponent>(ent, out var sprite))
return;
if (!_sprite.LayerMapTryGet((ent, sprite), KillSignKey.Key, out var layer, false))
return;
_sprite.RemoveLayer((ent, sprite), layer);
}
private enum KillSignKey

View File

@ -573,13 +573,32 @@ public sealed partial class AdminVerbSystem
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/killsign.rsi"), "icon"),
Act = () =>
{
EnsureComp<KillSignComponent>(args.Target);
EnsureComp<KillSignComponent>(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<KillSignComponent>(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()
{

View File

@ -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;
/// <summary>
/// Displays a sprite above an entity.
/// By default a huge sign saying "KILL".
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(raiseAfterAutoHandleState: true)]
public sealed partial class KillSignComponent : Component
{
/// <summary>
/// The sprite show above the entity.
/// </summary>
[DataField, AutoNetworkedField]
public SpriteSpecifier? Sprite = new SpriteSpecifier.Rsi(new ResPath("Objects/Misc/killsign.rsi"), "kill");
/// <summary>
/// Whether the granted layer should always be forced to be unshaded.
/// </summary>
[DataField, AutoNetworkedField]
public bool ForceUnshaded = true;
/// <summary>
/// Whether the granted layer should be offset to be above the entity.
/// </summary>
[DataField, AutoNetworkedField]
public bool DoOffset = true;
/// <summary>
/// Prevents the sign from displaying to the owner of the component, allowing everyone but them to see it.
/// </summary>
[DataField, AutoNetworkedField]
public bool HideFromOwner = false;
/// <summary>
/// The scale of the sprite.
/// </summary>
[DataField, AutoNetworkedField]
public Vector2 Scale = Vector2.One;
}

View File

@ -59,6 +59,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
@ -83,6 +84,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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B

View File

Before

Width:  |  Height:  |  Size: 867 B

After

Width:  |  Height:  |  Size: 867 B

View File

@ -1,25 +1,119 @@
{
"version": 1,
"license": "CC-BY-NC-SA-3.0",
"copyright": "Created by github user @moonheart08",
"copyright": "Created by github user @moonheart08 | bald, cat, dog, furry, it, nerd, peak, raider, stinky and icon-hidden states edited by ScarKy0(Github)",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "sign",
"name": "bald",
"directions": 1,
"delays": [
[
0.1,
0.1
0.15,
0.15
]
]
},
{
"name": "cat",
"directions": 1,
"delays": [
[
0.15,
0.15
]
]
},
{
"name": "dog",
"directions": 1,
"delays": [
[
0.15,
0.15
]
]
},
{
"name": "furry",
"directions": 1,
"delays": [
[
0.15,
0.15
]
]
},
{
"name": "it",
"directions": 1,
"delays": [
[
0.15,
0.15
]
]
},
{
"name": "kill",
"directions": 1,
"delays": [
[
0.15,
0.15
]
]
},
{
"name": "nerd",
"directions": 1,
"delays": [
[
0.15,
0.15
]
]
},
{
"name": "peak",
"directions": 1,
"delays": [
[
0.15,
0.15
]
]
},
{
"name": "raider",
"directions": 1,
"delays": [
[
0.15,
0.15
]
]
},
{
"name": "stinky",
"directions": 1,
"delays": [
[
0.15,
0.15
]
]
},
{
"name": "icon",
"directions": 1
},
{
"name": "icon-hidden",
"directions": 1
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B