diff --git a/Content.Server/Forensics/Components/CleansForensicsComponent.cs b/Content.Server/Forensics/Components/CleansForensicsComponent.cs new file mode 100644 index 0000000000..a1f40c9527 --- /dev/null +++ b/Content.Server/Forensics/Components/CleansForensicsComponent.cs @@ -0,0 +1,14 @@ +namespace Content.Server.Forensics; + +/// +/// This component is for items that can clean up forensic evidence +/// +[RegisterComponent] +public sealed partial class CleansForensicsComponent : Component +{ + /// + /// How long it takes to wipe prints/blood/etc. off of things using this entity + /// + [DataField] + public float CleanDelay = 12.0f; +} diff --git a/Content.Server/Forensics/Components/ForensicsComponent.cs b/Content.Server/Forensics/Components/ForensicsComponent.cs index 27eccf3334..e4579c5f3a 100644 --- a/Content.Server/Forensics/Components/ForensicsComponent.cs +++ b/Content.Server/Forensics/Components/ForensicsComponent.cs @@ -15,12 +15,6 @@ namespace Content.Server.Forensics [DataField("residues")] public HashSet Residues = new(); - /// - /// How long it takes to wipe the prints/blood/etc. off of this entity - /// - [DataField("cleanDelay")] - public float CleanDelay = 12.0f; - /// /// How close you must be to wipe the prints/blood/etc. off of this entity /// @@ -29,7 +23,7 @@ namespace Content.Server.Forensics /// /// Can the DNA be cleaned off of this entity? - /// e.g. you can clean the DNA off of a knife, but not a puddle + /// e.g. you can wipe the DNA off of a knife, but not a cigarette /// [DataField("canDnaBeCleaned")] public bool CanDnaBeCleaned = true; diff --git a/Content.Server/Forensics/Components/IgnoresFingerprintsComponent.cs b/Content.Server/Forensics/Components/IgnoresFingerprintsComponent.cs new file mode 100644 index 0000000000..4ecaf849af --- /dev/null +++ b/Content.Server/Forensics/Components/IgnoresFingerprintsComponent.cs @@ -0,0 +1,7 @@ +namespace Content.Server.Forensics.Components; + +/// +/// This component is for entities we do not wish to track fingerprints/fibers, like puddles +/// +[RegisterComponent] +public sealed partial class IgnoresFingerprintsComponent : Component { } diff --git a/Content.Server/Forensics/Systems/ForensicsSystem.cs b/Content.Server/Forensics/Systems/ForensicsSystem.cs index 3c6d1d30af..16bd2a50ee 100644 --- a/Content.Server/Forensics/Systems/ForensicsSystem.cs +++ b/Content.Server/Forensics/Systems/ForensicsSystem.cs @@ -1,12 +1,13 @@ using Content.Server.Body.Components; -using Content.Server.Chemistry.EntitySystems; using Content.Server.DoAfter; +using Content.Server.Fluids.EntitySystems; +using Content.Server.Forensics.Components; +using Content.Server.Popups; using Content.Shared.DoAfter; using Content.Shared.Forensics; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Inventory; -using Content.Shared.Tag; using Content.Shared.Weapons.Melee.Events; using Robust.Shared.Random; @@ -16,8 +17,8 @@ namespace Content.Server.Forensics { [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly InventorySystem _inventory = default!; - [Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; public override void Initialize() { SubscribeLocalEvent(OnInteract); @@ -26,7 +27,7 @@ namespace Content.Server.Forensics SubscribeLocalEvent(OnBeingGibbed); SubscribeLocalEvent(OnMeleeHit); - SubscribeLocalEvent(OnAfterInteract); + SubscribeLocalEvent(OnAfterInteract, after: new[] { typeof(AbsorbentSystem) }); SubscribeLocalEvent(OnCleanForensicsDoAfter); SubscribeLocalEvent(OnTransferDnaEvent); } @@ -70,15 +71,15 @@ namespace Content.Server.Forensics } } - private void OnAfterInteract(EntityUid uid, ForensicsComponent component, AfterInteractEvent args) + private void OnAfterInteract(EntityUid uid, CleansForensicsComponent component, AfterInteractEvent args) { if (args.Handled) return; - if (!_tagSystem.HasTag(args.Used, "CleansForensics")) + if (!TryComp(args.Target, out var forensicsComp)) return; - if((component.DNAs.Count > 0 && component.CanDnaBeCleaned) || (component.Fingerprints.Count + component.Fibers.Count > 0)) + if((forensicsComp.DNAs.Count > 0 && forensicsComp.CanDnaBeCleaned) || (forensicsComp.Fingerprints.Count + forensicsComp.Fibers.Count > 0)) { var doAfterArgs = new DoAfterArgs(EntityManager, args.User, component.CleanDelay, new CleanForensicsDoAfterEvent(), uid, target: args.Target, used: args.Used) { @@ -87,11 +88,11 @@ namespace Content.Server.Forensics BreakOnDamage = true, BreakOnTargetMove = true, MovementThreshold = 0.01f, - DistanceThreshold = component.CleanDistance, + DistanceThreshold = forensicsComp.CleanDistance, }; - _doAfterSystem.TryStartDoAfter(doAfterArgs); + _popupSystem.PopupEntity(Loc.GetString("forensics-cleaning", ("target", args.Target)), args.User, args.User); args.Handled = true; } @@ -141,6 +142,9 @@ namespace Content.Server.Forensics private void ApplyEvidence(EntityUid user, EntityUid target) { + if (HasComp(target)) + return; + var component = EnsureComp(target); if (_inventory.TryGetSlotEntity(user, "gloves", out var gloves)) { @@ -175,6 +179,7 @@ namespace Content.Server.Forensics { EnsureComp(recipient, out var recipientComp); recipientComp.DNAs.Add(donorComp.DNA); + recipientComp.CanDnaBeCleaned = canDnaBeCleaned; } } diff --git a/Resources/Locale/en-US/forensics/forensics.ftl b/Resources/Locale/en-US/forensics/forensics.ftl index 2326aeb9c2..957cc444a8 100644 --- a/Resources/Locale/en-US/forensics/forensics.ftl +++ b/Resources/Locale/en-US/forensics/forensics.ftl @@ -24,3 +24,5 @@ forensic-scanner-verb-message = Perform a forensic scan forensic-pad-fingerprint-name = {$entity}'s fingerprints forensic-pad-gloves-name = fibers from {$entity} + +forensics-cleaning = You begin cleaning the evidence off of {THE($target)}... \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Effects/puddle.yml b/Resources/Prototypes/Entities/Effects/puddle.yml index fe31e2bb1c..2ddde99ebb 100644 --- a/Resources/Prototypes/Entities/Effects/puddle.yml +++ b/Resources/Prototypes/Entities/Effects/puddle.yml @@ -162,3 +162,4 @@ - type: ExaminableSolution solution: puddle - type: BadDrink + - type: IgnoresFingerprints \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml index 4119b12a46..be823f2b65 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml @@ -611,6 +611,6 @@ tags: - DroneUsable - Mop - - CleansForensics + - type: CleansForensics - type: Fiber fiberColor: fibers-white diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml index 5905c6b128..4defea6264 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml @@ -7,7 +7,6 @@ - type: Tag tags: - Soap - - CleansForensics - type: Sprite sprite: Objects/Specific/Janitorial/soap.rsi layers: @@ -69,6 +68,7 @@ - type: Food solution: soap - type: BadFood + - type: CleansForensics - type: Residue residueAdjective: residue-slippery residueColor: residue-green @@ -137,6 +137,8 @@ flavors: - clean - punishment + - type: CleansForensics + cleanDelay: 8.0 - type: Residue residueAdjective: residue-slippery residueColor: residue-red diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 0a5044b848..8cb13ab8b6 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -1150,7 +1150,4 @@ id: MindShield - type: Tag - id: boots - -- type: Tag - id: CleansForensics + id: boots \ No newline at end of file