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

@@ -8,10 +8,12 @@ using Content.Shared.Alert;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reaction;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Drunk;
using Content.Shared.FixedPoint;
using Content.Shared.Forensics;
using Content.Shared.HealthExaminable;
using Content.Shared.Mobs.Systems;
using Content.Shared.Popups;
@@ -54,6 +56,7 @@ public sealed class BloodstreamSystem : EntitySystem
SubscribeLocalEvent<BloodstreamComponent, ReactionAttemptEvent>(OnReactionAttempt);
SubscribeLocalEvent<BloodstreamComponent, SolutionRelayEvent<ReactionAttemptEvent>>(OnReactionAttempt);
SubscribeLocalEvent<BloodstreamComponent, RejuvenateEvent>(OnRejuvenate);
SubscribeLocalEvent<BloodstreamComponent, GenerateDnaEvent>(OnDnaGenerated);
}
private void OnMapInit(Entity<BloodstreamComponent> ent, ref MapInitEvent args)
@@ -183,8 +186,18 @@ public sealed class BloodstreamSystem : EntitySystem
bloodSolution.MaxVolume = entity.Comp.BloodMaxVolume;
tempSolution.MaxVolume = entity.Comp.BleedPuddleThreshold * 4; // give some leeway, for chemstream as well
// Ensure blood that should have DNA has it; must be run here, in case DnaComponent has not yet been initialized
if (TryComp<DnaComponent>(entity.Owner, out var donorComp) && donorComp.DNA == String.Empty)
{
donorComp.DNA = _forensicsSystem.GenerateDNA();
var ev = new GenerateDnaEvent { Owner = entity.Owner, DNA = donorComp.DNA };
RaiseLocalEvent(entity.Owner, ref ev);
}
// Fill blood solution with BLOOD
bloodSolution.AddReagent(entity.Comp.BloodReagent, entity.Comp.BloodMaxVolume - bloodSolution.Volume);
bloodSolution.AddReagent(new ReagentId(entity.Comp.BloodReagent, GetEntityBloodData(entity.Owner)), entity.Comp.BloodMaxVolume - bloodSolution.Volume);
}
private void OnDamageChanged(Entity<BloodstreamComponent> ent, ref DamageChangedEvent args)
@@ -349,7 +362,7 @@ public sealed class BloodstreamSystem : EntitySystem
}
if (amount >= 0)
return _solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, amount, out _);
return _solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, amount, null, GetEntityBloodData(uid));
// Removal is more involved,
// since we also wanna handle moving it to the temporary solution
@@ -370,10 +383,7 @@ public sealed class BloodstreamSystem : EntitySystem
tempSolution.AddSolution(temp, _prototypeManager);
}
if (_puddleSystem.TrySpillAt(uid, tempSolution, out var puddleUid, sound: false))
{
_forensicsSystem.TransferDna(puddleUid, uid, canDnaBeCleaned: false);
}
_puddleSystem.TrySpillAt(uid, tempSolution, out var puddleUid, sound: false);
tempSolution.RemoveAllSolution();
}
@@ -436,10 +446,7 @@ public sealed class BloodstreamSystem : EntitySystem
_solutionContainerSystem.RemoveAllSolution(component.TemporarySolution.Value);
}
if (_puddleSystem.TrySpillAt(uid, tempSol, out var puddleUid))
{
_forensicsSystem.TransferDna(puddleUid, uid, canDnaBeCleaned: false);
}
_puddleSystem.TrySpillAt(uid, tempSol, out var puddleUid);
}
/// <summary>
@@ -464,6 +471,40 @@ public sealed class BloodstreamSystem : EntitySystem
component.BloodReagent = reagent;
if (currentVolume > 0)
_solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, currentVolume, out _);
_solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, currentVolume, null, GetEntityBloodData(uid));
}
private void OnDnaGenerated(Entity<BloodstreamComponent> entity, ref GenerateDnaEvent args)
{
if (_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.BloodSolutionName, ref entity.Comp.BloodSolution, out var bloodSolution))
{
foreach (var reagent in bloodSolution.Contents)
{
List<ReagentData> reagentData = reagent.Reagent.EnsureReagentData();
reagentData.RemoveAll(x => x is DnaData);
reagentData.AddRange(GetEntityBloodData(entity.Owner));
}
}
}
/// <summary>
/// Get the reagent data for blood that a specific entity should have.
/// </summary>
public List<ReagentData> GetEntityBloodData(EntityUid uid)
{
var bloodData = new List<ReagentData>();
var dnaData = new DnaData();
if (TryComp<DnaComponent>(uid, out var donorComp))
{
dnaData.DNA = donorComp.DNA;
} else
{
dnaData.DNA = Loc.GetString("forensics-dna-unknown");
}
bloodData.Add(dnaData);
return bloodData;
}
}