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