Better DNA forensics & ReagentData (#26699)

* Added the ability for blood to track DNA using ReagentData; Forensic Scanner now accounts for solution DNA, non-DNA holders have "Unknown DNA"

* Removes touch DNA for puddles, adds DNA to vomit

* DNA now leaves traces in containers and those marked without don't show DNA on scan (except for puddles), gibbed parts have DNA

* Fix stupid metamorphic glass bug grrr

* Removed SpillableComponent since DnaSubstanceTraceComponent is used instead

* Removes data field from maps, adds DNA tracking for some missed items

* Give default value, fix missing values.

* Fixes recipe bug

* Review changes

* Make the Data list into a nullable type

* Revert map changes

* Move gibbed unknown DNA to forensicssystem
This commit is contained in:
SlamBamActionman
2024-08-09 01:27:27 +02:00
committed by GitHub
parent c43fcdfa06
commit 07174d0aaf
45 changed files with 307 additions and 66 deletions

View File

@@ -1,11 +1,16 @@
using Content.Server.Body.Components;
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.DoAfter;
using Content.Server.Fluids.EntitySystems;
using Content.Server.Forensics.Components;
using Content.Server.Popups;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Popups;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.DoAfter;
using Content.Shared.Fluids.Components;
using Content.Shared.Forensics;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
@@ -23,20 +28,35 @@ namespace Content.Server.Forensics
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
public override void Initialize()
{
SubscribeLocalEvent<FingerprintComponent, ContactInteractionEvent>(OnInteract);
SubscribeLocalEvent<FingerprintComponent, MapInitEvent>(OnFingerprintInit);
SubscribeLocalEvent<DnaComponent, MapInitEvent>(OnDNAInit);
SubscribeLocalEvent<DnaComponent, BeingGibbedEvent>(OnBeingGibbed);
SubscribeLocalEvent<ForensicsComponent, BeingGibbedEvent>(OnBeingGibbed);
SubscribeLocalEvent<ForensicsComponent, MeleeHitEvent>(OnMeleeHit);
SubscribeLocalEvent<ForensicsComponent, GotRehydratedEvent>(OnRehydrated);
SubscribeLocalEvent<CleansForensicsComponent, AfterInteractEvent>(OnAfterInteract, after: new[] { typeof(AbsorbentSystem) });
SubscribeLocalEvent<ForensicsComponent, CleanForensicsDoAfterEvent>(OnCleanForensicsDoAfter);
SubscribeLocalEvent<DnaComponent, TransferDnaEvent>(OnTransferDnaEvent);
SubscribeLocalEvent<DnaSubstanceTraceComponent, SolutionContainerChangedEvent>(OnSolutionChanged);
SubscribeLocalEvent<CleansForensicsComponent, GetVerbsEvent<UtilityVerb>>(OnUtilityVerb);
}
private void OnSolutionChanged(Entity<DnaSubstanceTraceComponent> ent, ref SolutionContainerChangedEvent ev)
{
var soln = GetSolutionsDNA(ev.Solution);
if (soln.Count > 0)
{
var comp = EnsureComp<ForensicsComponent>(ent.Owner);
foreach (string dna in soln)
{
comp.DNAs.Add(dna);
}
}
}
private void OnInteract(EntityUid uid, FingerprintComponent component, ContactInteractionEvent args)
@@ -51,15 +71,26 @@ namespace Content.Server.Forensics
private void OnDNAInit(EntityUid uid, DnaComponent component, MapInitEvent args)
{
component.DNA = GenerateDNA();
if (component.DNA == String.Empty)
{
component.DNA = GenerateDNA();
var ev = new GenerateDnaEvent { Owner = uid, DNA = component.DNA };
RaiseLocalEvent(uid, ref ev);
}
}
private void OnBeingGibbed(EntityUid uid, DnaComponent component, BeingGibbedEvent args)
private void OnBeingGibbed(EntityUid uid, ForensicsComponent component, BeingGibbedEvent args)
{
string dna = Loc.GetString("forensics-dna-unknown");
if (TryComp(uid, out DnaComponent? dnaComp))
dna = dnaComp.DNA;
foreach (EntityUid part in args.GibbedParts)
{
var partComp = EnsureComp<ForensicsComponent>(part);
partComp.DNAs.Add(component.DNA);
partComp.DNAs.Add(dna);
partComp.CanDnaBeCleaned = false;
}
}
@@ -106,6 +137,34 @@ namespace Content.Server.Forensics
}
}
public List<string> GetSolutionsDNA(EntityUid uid)
{
List<string> list = new();
if (TryComp<SolutionContainerManagerComponent>(uid, out var comp))
{
foreach (var (_, soln) in _solutionContainerSystem.EnumerateSolutions((uid, comp)))
{
list.AddRange(GetSolutionsDNA(soln.Comp.Solution));
}
}
return list;
}
public List<string> GetSolutionsDNA(Solution soln)
{
List<string> list = new();
foreach (var reagent in soln.Contents)
{
foreach (var data in reagent.Reagent.EnsureReagentData())
{
if (data is DnaData)
{
list.Add(((DnaData) data).DNA);
}
}
}
return list;
}
private void OnAfterInteract(Entity<CleansForensicsComponent> cleanForensicsEntity, ref AfterInteractEvent args)
{
if (args.Handled || !args.CanReach || args.Target == null)