Revert "Added Kill Tome (Death Note). (#39011)"
This reverts commit d0c104e4b0.
Revert suggested due to code issues and passed the voting.
@ScarKy0 has interest in fixing it
@xsainteer
<https://youtu.be/8RmeZKz-i_w?t=2151>
This commit is contained in:
@@ -1,38 +0,0 @@
|
|||||||
using Content.Shared.Damage;
|
|
||||||
using Content.Shared.Damage.Prototypes;
|
|
||||||
using Content.Shared.FixedPoint;
|
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Shared.KillTome;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Paper with that component is KillTome.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
|
||||||
public sealed partial class KillTomeComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// if delay is not specified, it will use this default value
|
|
||||||
/// </summary>
|
|
||||||
[DataField, AutoNetworkedField]
|
|
||||||
public TimeSpan DefaultKillDelay = TimeSpan.FromSeconds(40);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Damage specifier that will be used to kill the target.
|
|
||||||
/// </summary>
|
|
||||||
[DataField, AutoNetworkedField]
|
|
||||||
public DamageSpecifier Damage = new()
|
|
||||||
{
|
|
||||||
DamageDict = new Dictionary<string, FixedPoint2>
|
|
||||||
{
|
|
||||||
{ "Blunt", 200 }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// to keep a track of already killed people so they won't be killed again
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public HashSet<EntityUid> KilledEntities = [];
|
|
||||||
}
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using Content.Shared.Administration.Logs;
|
|
||||||
using Content.Shared.Damage;
|
|
||||||
using Content.Shared.Database;
|
|
||||||
using Content.Shared.Humanoid;
|
|
||||||
using Content.Shared.Mobs;
|
|
||||||
using Content.Shared.Mobs.Components;
|
|
||||||
using Content.Shared.NameModifier.EntitySystems;
|
|
||||||
using Content.Shared.Paper;
|
|
||||||
using Content.Shared.Popups;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
namespace Content.Shared.KillTome;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This handles KillTome functionality.
|
|
||||||
/// </summary>
|
|
||||||
|
|
||||||
/// Kill Tome Rules:
|
|
||||||
// 1. The humanoid whose name is written in this note shall die.
|
|
||||||
// 2. If the name is shared by multiple humanoids, a random humanoid with that name will die.
|
|
||||||
// 3. Each name shall be written on a new line.
|
|
||||||
// 4. Names must be written in the format: "Name, Delay (in seconds)" (e.g., John Doe, 40).
|
|
||||||
// 5. A humanoid can be killed by the same Kill Tome only once.
|
|
||||||
public sealed class KillTomeSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
|
||||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
|
||||||
[Dependency] private readonly DamageableSystem _damageSystem = default!;
|
|
||||||
[Dependency] private readonly ISharedAdminLogManager _adminLogs = default!;
|
|
||||||
[Dependency] private readonly NameModifierSystem _nameModifierSystem = default!;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
SubscribeLocalEvent<KillTomeComponent, PaperAfterWriteEvent>(OnPaperAfterWriteInteract);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
|
||||||
{
|
|
||||||
// Getting all the entities that are targeted by Kill Tome and checking if their kill time has passed.
|
|
||||||
// If it has, we kill them and remove the KillTomeTargetComponent.
|
|
||||||
var query = EntityQueryEnumerator<KillTomeTargetComponent>();
|
|
||||||
|
|
||||||
while (query.MoveNext(out var uid, out var targetComp))
|
|
||||||
{
|
|
||||||
if (_gameTiming.CurTime < targetComp.KillTime)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// The component doesn't get removed fast enough and the update loop will run through it a few more times.
|
|
||||||
// This check is here to ensure it will not spam popups or kill you several times over.
|
|
||||||
if (targetComp.Dead)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Kill(uid, targetComp);
|
|
||||||
|
|
||||||
_popupSystem.PopupPredicted(Loc.GetString("killtome-death"),
|
|
||||||
Loc.GetString("killtome-death-others", ("target", uid)),
|
|
||||||
uid,
|
|
||||||
uid,
|
|
||||||
PopupType.LargeCaution);
|
|
||||||
|
|
||||||
targetComp.Dead = true;
|
|
||||||
|
|
||||||
RemCompDeferred<KillTomeTargetComponent>(uid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPaperAfterWriteInteract(Entity<KillTomeComponent> ent, ref PaperAfterWriteEvent args)
|
|
||||||
{
|
|
||||||
// if the entity is not a paper, we don't do anything
|
|
||||||
if (!TryComp<PaperComponent>(ent.Owner, out var paper))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var content = paper.Content;
|
|
||||||
|
|
||||||
var lines = content.Split('\n', StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
|
|
||||||
var showPopup = false;
|
|
||||||
|
|
||||||
foreach (var line in lines)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(line))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var parts = line.Split(',', 2, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
|
|
||||||
var name = parts[0].Trim();
|
|
||||||
|
|
||||||
var delay = ent.Comp.DefaultKillDelay;
|
|
||||||
|
|
||||||
if (parts.Length == 2 && Parse.TryInt32(parts[1].Trim(), out var parsedDelay) && parsedDelay > 0)
|
|
||||||
delay = TimeSpan.FromSeconds(parsedDelay);
|
|
||||||
|
|
||||||
if (!CheckIfEligible(name, ent.Comp, out var uid))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compiler will complain if we don't check for null here.
|
|
||||||
if (uid is not { } realUid)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
showPopup = true;
|
|
||||||
|
|
||||||
EnsureComp<KillTomeTargetComponent>(realUid, out var targetComp);
|
|
||||||
|
|
||||||
targetComp.KillTime = _gameTiming.CurTime + delay;
|
|
||||||
targetComp.Damage = ent.Comp.Damage;
|
|
||||||
|
|
||||||
Dirty(realUid, targetComp);
|
|
||||||
|
|
||||||
ent.Comp.KilledEntities.Add(realUid);
|
|
||||||
|
|
||||||
Dirty(ent);
|
|
||||||
|
|
||||||
_adminLogs.Add(LogType.Chat,
|
|
||||||
LogImpact.High,
|
|
||||||
$"{ToPrettyString(args.Actor)} has written {ToPrettyString(uid)}'s name in Kill Tome.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have written at least one eligible name, we show the popup (So the player knows death note worked).
|
|
||||||
if (showPopup)
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("killtome-kill-success"), ent.Owner, args.Actor, PopupType.Large);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A person to be killed by KillTome must:
|
|
||||||
// 1. be with the name
|
|
||||||
// 2. have HumanoidAppearanceComponent (so it targets only humanoids, obv)
|
|
||||||
// 3. not be already dead
|
|
||||||
// 4. not be already killed by Kill Tome
|
|
||||||
|
|
||||||
// If all these conditions are met, we return true and the entityUid of the person to kill.
|
|
||||||
private bool CheckIfEligible(string name, KillTomeComponent comp, [NotNullWhen(true)] out EntityUid? entityUid)
|
|
||||||
{
|
|
||||||
if (!TryFindEntityByName(name, out var uid) ||
|
|
||||||
!TryComp<MobStateComponent>(uid, out var mob))
|
|
||||||
{
|
|
||||||
entityUid = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uid is not { } realUid)
|
|
||||||
{
|
|
||||||
entityUid = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (comp.KilledEntities.Contains(realUid))
|
|
||||||
{
|
|
||||||
entityUid = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mob.CurrentState == MobState.Dead)
|
|
||||||
{
|
|
||||||
entityUid = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
entityUid = uid;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryFindEntityByName(string name, [NotNullWhen(true)] out EntityUid? entityUid)
|
|
||||||
{
|
|
||||||
var query = EntityQueryEnumerator<HumanoidAppearanceComponent>();
|
|
||||||
|
|
||||||
while (query.MoveNext(out var uid, out _))
|
|
||||||
{
|
|
||||||
if (!_nameModifierSystem.GetBaseName(uid).Equals(name, StringComparison.OrdinalIgnoreCase))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
entityUid = uid;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
entityUid = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Kill(EntityUid uid, KillTomeTargetComponent comp)
|
|
||||||
{
|
|
||||||
_damageSystem.TryChangeDamage(uid, comp.Damage, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
using Content.Shared.Damage;
|
|
||||||
using Content.Shared.FixedPoint;
|
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
|
||||||
|
|
||||||
namespace Content.Shared.KillTome;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Entity with this component is a Kill Tome target.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause]
|
|
||||||
public sealed partial class KillTomeTargetComponent : Component
|
|
||||||
{
|
|
||||||
///<summary>
|
|
||||||
/// Damage that will be dealt to the target.
|
|
||||||
/// </summary>
|
|
||||||
[DataField, AutoNetworkedField]
|
|
||||||
public DamageSpecifier Damage = new()
|
|
||||||
{
|
|
||||||
DamageDict = new Dictionary<string, FixedPoint2>
|
|
||||||
{
|
|
||||||
{ "Blunt", 200 }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The time when the target is killed.
|
|
||||||
/// </summary>
|
|
||||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField]
|
|
||||||
[AutoPausedField]
|
|
||||||
public TimeSpan KillTime = TimeSpan.Zero;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates this target has been killed by the killtome.
|
|
||||||
/// </summary>
|
|
||||||
[DataField, AutoNetworkedField]
|
|
||||||
public bool Dead;
|
|
||||||
|
|
||||||
// Disallows cheat clients from seeing who is about to die to the killtome.
|
|
||||||
public override bool SendOnlyToOwner => true;
|
|
||||||
}
|
|
||||||
@@ -187,7 +187,6 @@ public sealed class PaperSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
var ev = new PaperWriteAttemptEvent(entity.Owner);
|
var ev = new PaperWriteAttemptEvent(entity.Owner);
|
||||||
RaiseLocalEvent(args.Actor, ref ev);
|
RaiseLocalEvent(args.Actor, ref ev);
|
||||||
|
|
||||||
if (ev.Cancelled)
|
if (ev.Cancelled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -212,9 +211,6 @@ public sealed class PaperSystem : EntitySystem
|
|||||||
|
|
||||||
entity.Comp.Mode = PaperAction.Read;
|
entity.Comp.Mode = PaperAction.Read;
|
||||||
UpdateUserInterface(entity);
|
UpdateUserInterface(entity);
|
||||||
|
|
||||||
var writeAfterEv = new PaperAfterWriteEvent(args.Actor);
|
|
||||||
RaiseLocalEvent(entity.Owner, ref writeAfterEv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnRandomPaperContentMapInit(Entity<RandomPaperContentComponent> ent, ref MapInitEvent args)
|
private void OnRandomPaperContentMapInit(Entity<RandomPaperContentComponent> ent, ref MapInitEvent args)
|
||||||
@@ -323,14 +319,6 @@ public record struct PaperWriteEvent(EntityUid User, EntityUid Paper);
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cancellable event for attempting to write on a piece of paper.
|
/// Cancellable event for attempting to write on a piece of paper.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="Paper">The paper that the writing will take place on.</param>
|
/// <param name="paper">The paper that the writing will take place on.</param>
|
||||||
[ByRefEvent]
|
[ByRefEvent]
|
||||||
public record struct PaperWriteAttemptEvent(EntityUid Paper, string? FailReason = null, bool Cancelled = false);
|
public record struct PaperWriteAttemptEvent(EntityUid Paper, string? FailReason = null, bool Cancelled = false);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event raised on paper after it was written on by someone.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Actor">Entity that wrote something on the paper.</param>
|
|
||||||
[ByRefEvent]
|
|
||||||
public readonly record struct PaperAfterWriteEvent(EntityUid Actor);
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
killtome-rules =
|
|
||||||
Kill Tome Rules:
|
|
||||||
1. The humanoid whose name is written in this note shall die.
|
|
||||||
2. If the name is shared by multiple humanoids, a random humanoid with that name will die.
|
|
||||||
3. Each name shall be written on a new line.
|
|
||||||
4. Names must be written in the format: "Name, Delay (in seconds)" (e.g., John Doe, 40).
|
|
||||||
5. A humanoid can be killed by the same Kill Tome only once.
|
|
||||||
|
|
||||||
killtome-kill-success = The name is written. The countdown begins.
|
|
||||||
killtome-death = You feel sudden pain in your chest!
|
|
||||||
killtome-death-others = {CAPITALIZE($target)} grabs onto {POSS-ADJ($target)} chest and falls to the ground!
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
- type: entity
|
|
||||||
name: black tome
|
|
||||||
parent: BasePaper
|
|
||||||
id: KillTome
|
|
||||||
suffix: KillTome, Admeme # To stay true to the lore, please never make this accessible outside of divine intervention (admeme).
|
|
||||||
description: A worn black tome. It smells like old paper.
|
|
||||||
components:
|
|
||||||
- type: Sprite
|
|
||||||
sprite: Objects/Misc/killtome.rsi
|
|
||||||
state: icon
|
|
||||||
- type: KillTome
|
|
||||||
defaultKillDelay: 40
|
|
||||||
damage:
|
|
||||||
types:
|
|
||||||
Blunt: 200
|
|
||||||
- type: Paper
|
|
||||||
content: killtome-rules
|
|
||||||
- type: ActivatableUI
|
|
||||||
key: enum.PaperUiKey.Key
|
|
||||||
requiresComplex: false
|
|
||||||
- type: UserInterface
|
|
||||||
interfaces:
|
|
||||||
enum.PaperUiKey.Key:
|
|
||||||
type: PaperBoundUserInterface
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 558 B |
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"license": "CC-BY-SA-3.0",
|
|
||||||
"copyright": "alexmactep",
|
|
||||||
"size": {
|
|
||||||
"x": 32,
|
|
||||||
"y": 32
|
|
||||||
},
|
|
||||||
"states": [
|
|
||||||
{
|
|
||||||
"name": "icon"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user