Add more DNA interactions (#21989)
* Add more DNA interactions * remove unused import * update based on feedback * Add event for chemistrysystem.injector * move event to shared; transfer dna to implanter * doafter and interaction event fixes * add BreakOnHandChange * doh * use events instead of updating component directly * Add DataFields to ForensicScannerComponent fields * Convert most events to system api call
This commit is contained in:
@@ -58,6 +58,12 @@ namespace Content.Client.Forensics
|
||||
{
|
||||
text.AppendLine(dna);
|
||||
}
|
||||
text.AppendLine();
|
||||
text.AppendLine(Loc.GetString("forensic-scanner-interface-residues"));
|
||||
foreach (var residue in msg.Residues)
|
||||
{
|
||||
text.AppendLine(residue);
|
||||
}
|
||||
Diagnostics.Text = text.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Chemistry.ReactionEffects;
|
||||
using Content.Server.Fluids.EntitySystems;
|
||||
using Content.Server.Forensics;
|
||||
using Content.Server.HealthExaminable;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Alert;
|
||||
@@ -22,6 +21,8 @@ using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Content.Shared.Speech.EntitySystems;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Content.Server.Forensics;
|
||||
|
||||
namespace Content.Server.Body.Systems;
|
||||
|
||||
@@ -38,6 +39,7 @@ public sealed class BloodstreamSystem : EntitySystem
|
||||
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
||||
[Dependency] private readonly SharedStutteringSystem _stutteringSystem = default!;
|
||||
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||
[Dependency] private readonly ForensicsSystem _forensicsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -322,11 +324,7 @@ public sealed class BloodstreamSystem : EntitySystem
|
||||
component.BloodTemporarySolution.AddSolution(temp, _prototypeManager);
|
||||
if (_puddleSystem.TrySpillAt(uid, component.BloodTemporarySolution, out var puddleUid, false))
|
||||
{
|
||||
if (TryComp<DnaComponent>(uid, out var dna))
|
||||
{
|
||||
var comp = EnsureComp<ForensicsComponent>(puddleUid);
|
||||
comp.DNAs.Add(dna.DNA);
|
||||
}
|
||||
_forensicsSystem.TransferDna(puddleUid, uid, false);
|
||||
}
|
||||
|
||||
component.BloodTemporarySolution.RemoveAllSolution();
|
||||
@@ -378,11 +376,7 @@ public sealed class BloodstreamSystem : EntitySystem
|
||||
|
||||
if (_puddleSystem.TrySpillAt(uid, tempSol, out var puddleUid))
|
||||
{
|
||||
if (TryComp<DnaComponent>(uid, out var dna))
|
||||
{
|
||||
var comp = EnsureComp<ForensicsComponent>(puddleUid);
|
||||
comp.DNAs.Add(dna.DNA);
|
||||
}
|
||||
_forensicsSystem.TransferDna(puddleUid, uid, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Stacks;
|
||||
using Robust.Shared.Player;
|
||||
using Content.Shared.Forensics;
|
||||
|
||||
namespace Content.Server.Chemistry.EntitySystems;
|
||||
|
||||
@@ -290,7 +291,7 @@ public sealed partial class ChemistrySystem
|
||||
("target", Identity.Entity(target, EntityManager))), injector, user);
|
||||
|
||||
Dirty(component);
|
||||
AfterInject(component, injector);
|
||||
AfterInject(component, injector, target);
|
||||
}
|
||||
|
||||
private void TryInject(InjectorComponent component, EntityUid injector, EntityUid targetEntity, Solution targetSolution, EntityUid user, bool asRefill)
|
||||
@@ -328,10 +329,10 @@ public sealed partial class ChemistrySystem
|
||||
("target", Identity.Entity(targetEntity, EntityManager))), injector, user);
|
||||
|
||||
Dirty(component);
|
||||
AfterInject(component, injector);
|
||||
AfterInject(component, injector, targetEntity);
|
||||
}
|
||||
|
||||
private void AfterInject(InjectorComponent component, EntityUid injector)
|
||||
private void AfterInject(InjectorComponent component, EntityUid injector, EntityUid target)
|
||||
{
|
||||
// Automatically set syringe to draw after completely draining it.
|
||||
if (_solutions.TryGetSolution(injector, InjectorComponent.SolutionName, out var solution)
|
||||
@@ -339,9 +340,13 @@ public sealed partial class ChemistrySystem
|
||||
{
|
||||
component.ToggleState = SharedInjectorComponent.InjectorToggleMode.Draw;
|
||||
}
|
||||
|
||||
// Leave some DNA from the injectee on it
|
||||
var ev = new TransferDnaEvent { Donor = target, Recipient = injector };
|
||||
RaiseLocalEvent(target, ref ev);
|
||||
}
|
||||
|
||||
private void AfterDraw(InjectorComponent component, EntityUid injector)
|
||||
private void AfterDraw(InjectorComponent component, EntityUid injector, EntityUid target)
|
||||
{
|
||||
// Automatically set syringe to inject after completely filling it.
|
||||
if (_solutions.TryGetSolution(injector, InjectorComponent.SolutionName, out var solution)
|
||||
@@ -349,6 +354,10 @@ public sealed partial class ChemistrySystem
|
||||
{
|
||||
component.ToggleState = SharedInjectorComponent.InjectorToggleMode.Inject;
|
||||
}
|
||||
|
||||
// Leave some DNA from the drawee on it
|
||||
var ev = new TransferDnaEvent { Donor = target, Recipient = injector };
|
||||
RaiseLocalEvent(target, ref ev);
|
||||
}
|
||||
|
||||
private void TryDraw(InjectorComponent component, EntityUid injector, EntityUid targetEntity, Solution targetSolution, EntityUid user, BloodstreamComponent? stream = null)
|
||||
@@ -389,7 +398,7 @@ public sealed partial class ChemistrySystem
|
||||
("target", Identity.Entity(targetEntity, EntityManager))), injector, user);
|
||||
|
||||
Dirty(component);
|
||||
AfterDraw(component, injector);
|
||||
AfterDraw(component, injector, targetEntity);
|
||||
}
|
||||
|
||||
private void DrawFromBlood(EntityUid user, EntityUid injector, EntityUid target, InjectorComponent component, Solution injectorSolution, BloodstreamComponent stream, FixedPoint2 transferAmount)
|
||||
@@ -414,7 +423,7 @@ public sealed partial class ChemistrySystem
|
||||
("target", Identity.Entity(target, EntityManager))), injector, user);
|
||||
|
||||
Dirty(component);
|
||||
AfterDraw(component, injector);
|
||||
AfterDraw(component, injector, target);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Weapons.Melee.Events;
|
||||
using Content.Shared.Timing;
|
||||
using Robust.Shared.GameStates;
|
||||
using Content.Shared.Forensics;
|
||||
|
||||
namespace Content.Server.Chemistry.EntitySystems
|
||||
{
|
||||
@@ -138,6 +139,9 @@ namespace Content.Server.Chemistry.EntitySystems
|
||||
_reactiveSystem.DoEntityReaction(target.Value, removedSolution, ReactionMethod.Injection);
|
||||
_solutions.TryAddSolution(target.Value, targetSolution, removedSolution);
|
||||
|
||||
var ev = new TransferDnaEvent { Donor = target.Value, Recipient = uid };
|
||||
RaiseLocalEvent(target.Value, ref ev);
|
||||
|
||||
// same LogType as syringes...
|
||||
_adminLogger.Add(LogType.ForceFeed, $"{_entMan.ToPrettyString(user):user} injected {_entMan.ToPrettyString(target.Value):target} with a solution {SolutionContainerSystem.ToPrettyString(removedSolution):removedSolution} using a {_entMan.ToPrettyString(uid):using}");
|
||||
|
||||
|
||||
@@ -13,21 +13,27 @@ namespace Content.Server.Forensics
|
||||
/// <summary>
|
||||
/// A list of fingerprint GUIDs that the forensic scanner found from the <see cref="ForensicsComponent"/> on an entity.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
[ViewVariables(VVAccess.ReadOnly), DataField("fingerprints")]
|
||||
public List<string> Fingerprints = new();
|
||||
|
||||
/// <summary>
|
||||
/// A list of glove fibers that the forensic scanner found from the <see cref="ForensicsComponent"/> on an entity.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
[ViewVariables(VVAccess.ReadOnly), DataField("fibers")]
|
||||
public List<string> Fibers = new();
|
||||
|
||||
/// <summary>
|
||||
/// DNA that the forensic scanner found from the <see cref="DNAComponent"/> on an entity.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
[ViewVariables(VVAccess.ReadOnly), DataField("dnas")]
|
||||
public List<string> DNAs = new();
|
||||
|
||||
/// <summary>
|
||||
/// Residue that the forensic scanner found from the <see cref="ForensicsComponent"/> on an entity.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly), DataField("residues")]
|
||||
public List<string> Residues = new();
|
||||
|
||||
/// <summary>
|
||||
/// What is the name of the entity that was scanned last?
|
||||
/// </summary>
|
||||
|
||||
@@ -11,5 +11,27 @@ namespace Content.Server.Forensics
|
||||
|
||||
[DataField("dnas")]
|
||||
public HashSet<string> DNAs = new();
|
||||
|
||||
[DataField("residues")]
|
||||
public HashSet<string> Residues = new();
|
||||
|
||||
/// <summary>
|
||||
/// How long it takes to wipe the prints/blood/etc. off of this entity
|
||||
/// </summary>
|
||||
[DataField("cleanDelay")]
|
||||
public float CleanDelay = 12.0f;
|
||||
|
||||
/// <summary>
|
||||
/// How close you must be to wipe the prints/blood/etc. off of this entity
|
||||
/// </summary>
|
||||
[DataField("cleanDistance")]
|
||||
public float CleanDistance = 1.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Can the DNA be cleaned off of this entity?
|
||||
/// e.g. you can clean the DNA off of a knife, but not a puddle
|
||||
/// </summary>
|
||||
[DataField("canDnaBeCleaned")]
|
||||
public bool CanDnaBeCleaned = true;
|
||||
}
|
||||
}
|
||||
|
||||
15
Content.Server/Forensics/Components/ResidueComponent.cs
Normal file
15
Content.Server/Forensics/Components/ResidueComponent.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Content.Server.Forensics;
|
||||
|
||||
/// <summary>
|
||||
/// This controls residues left on items
|
||||
/// which the forensics system uses.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class ResidueComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public LocId ResidueAdjective = "residue-unknown";
|
||||
|
||||
[DataField]
|
||||
public string? ResidueColor;
|
||||
}
|
||||
@@ -51,6 +51,7 @@ namespace Content.Server.Forensics
|
||||
component.Fingerprints,
|
||||
component.Fibers,
|
||||
component.DNAs,
|
||||
component.Residues,
|
||||
component.LastScannedName,
|
||||
component.PrintCooldown,
|
||||
component.PrintReadyAt);
|
||||
@@ -74,6 +75,7 @@ namespace Content.Server.Forensics
|
||||
scanner.Fingerprints = new();
|
||||
scanner.Fibers = new();
|
||||
scanner.DNAs = new();
|
||||
scanner.Residues = new();
|
||||
}
|
||||
|
||||
else
|
||||
@@ -81,6 +83,7 @@ namespace Content.Server.Forensics
|
||||
scanner.Fingerprints = forensics.Fingerprints.ToList();
|
||||
scanner.Fibers = forensics.Fibers.ToList();
|
||||
scanner.DNAs = forensics.DNAs.ToList();
|
||||
scanner.Residues = forensics.Residues.ToList();
|
||||
}
|
||||
|
||||
scanner.LastScannedName = MetaData(args.Args.Target.Value).EntityName;
|
||||
@@ -222,6 +225,12 @@ namespace Content.Server.Forensics
|
||||
{
|
||||
text.AppendLine(dna);
|
||||
}
|
||||
text.AppendLine();
|
||||
text.AppendLine(Loc.GetString("forensic-scanner-interface-residues"));
|
||||
foreach (var residue in component.Residues)
|
||||
{
|
||||
text.AppendLine(residue);
|
||||
}
|
||||
|
||||
_paperSystem.SetContent(printed, text.ToString());
|
||||
_audioSystem.PlayPvs(component.SoundPrint, uid,
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Chemistry.EntitySystems;
|
||||
using Content.Server.DoAfter;
|
||||
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;
|
||||
|
||||
namespace Content.Server.Forensics
|
||||
@@ -8,11 +16,19 @@ 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!;
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<FingerprintComponent, ContactInteractionEvent>(OnInteract);
|
||||
SubscribeLocalEvent<FingerprintComponent, MapInitEvent>(OnFingerprintInit);
|
||||
SubscribeLocalEvent<DnaComponent, MapInitEvent>(OnDNAInit);
|
||||
|
||||
SubscribeLocalEvent<DnaComponent, BeingGibbedEvent>(OnBeingGibbed);
|
||||
SubscribeLocalEvent<ForensicsComponent, MeleeHitEvent>(OnMeleeHit);
|
||||
SubscribeLocalEvent<ForensicsComponent, AfterInteractEvent>(OnAfterInteract);
|
||||
SubscribeLocalEvent<ForensicsComponent, CleanForensicsDoAfterEvent>(OnCleanForensicsDoAfter);
|
||||
SubscribeLocalEvent<DnaComponent, TransferDnaEvent>(OnTransferDnaEvent);
|
||||
}
|
||||
|
||||
private void OnInteract(EntityUid uid, FingerprintComponent component, ContactInteractionEvent args)
|
||||
@@ -30,6 +46,79 @@ namespace Content.Server.Forensics
|
||||
component.DNA = GenerateDNA();
|
||||
}
|
||||
|
||||
private void OnBeingGibbed(EntityUid uid, DnaComponent component, BeingGibbedEvent args)
|
||||
{
|
||||
foreach(EntityUid part in args.GibbedParts)
|
||||
{
|
||||
var partComp = EnsureComp<ForensicsComponent>(part);
|
||||
partComp.DNAs.Add(component.DNA);
|
||||
partComp.CanDnaBeCleaned = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMeleeHit(EntityUid uid, ForensicsComponent component, MeleeHitEvent args)
|
||||
{
|
||||
if((args.BaseDamage.DamageDict.TryGetValue("Blunt", out var bluntDamage) && bluntDamage.Value > 0) ||
|
||||
(args.BaseDamage.DamageDict.TryGetValue("Slash", out var slashDamage) && slashDamage.Value > 0) ||
|
||||
(args.BaseDamage.DamageDict.TryGetValue("Piercing", out var pierceDamage) && pierceDamage.Value > 0))
|
||||
{
|
||||
foreach(EntityUid hitEntity in args.HitEntities)
|
||||
{
|
||||
if(TryComp<DnaComponent>(hitEntity, out var hitEntityComp))
|
||||
component.DNAs.Add(hitEntityComp.DNA);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAfterInteract(EntityUid uid, ForensicsComponent component, AfterInteractEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (!_tagSystem.HasTag(args.Used, "CleansForensics"))
|
||||
return;
|
||||
|
||||
if((component.DNAs.Count > 0 && component.CanDnaBeCleaned) || (component.Fingerprints.Count + component.Fibers.Count > 0))
|
||||
{
|
||||
var doAfterArgs = new DoAfterArgs(EntityManager, args.User, component.CleanDelay, new CleanForensicsDoAfterEvent(), uid, target: args.Target, used: args.Used)
|
||||
{
|
||||
BreakOnHandChange = true,
|
||||
NeedHand = true,
|
||||
BreakOnDamage = true,
|
||||
BreakOnTargetMove = true,
|
||||
MovementThreshold = 0.01f,
|
||||
DistanceThreshold = component.CleanDistance,
|
||||
};
|
||||
|
||||
|
||||
_doAfterSystem.TryStartDoAfter(doAfterArgs);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCleanForensicsDoAfter(EntityUid uid, ForensicsComponent component, CleanForensicsDoAfterEvent args)
|
||||
{
|
||||
if (args.Handled || args.Cancelled || args.Args.Target == null)
|
||||
return;
|
||||
|
||||
if (!TryComp<ForensicsComponent>(args.Target, out var targetComp))
|
||||
return;
|
||||
|
||||
targetComp.Fibers = new();
|
||||
targetComp.Fingerprints = new();
|
||||
|
||||
if (targetComp.CanDnaBeCleaned)
|
||||
targetComp.DNAs = new();
|
||||
|
||||
// leave behind evidence it was cleaned
|
||||
if (TryComp<FiberComponent>(args.Used, out var fiber))
|
||||
targetComp.Fibers.Add(string.IsNullOrEmpty(fiber.FiberColor) ? Loc.GetString("forensic-fibers", ("material", fiber.FiberMaterial)) : Loc.GetString("forensic-fibers-colored", ("color", fiber.FiberColor), ("material", fiber.FiberMaterial)));
|
||||
|
||||
if (TryComp<ResidueComponent>(args.Used, out var residue))
|
||||
targetComp.Residues.Add(string.IsNullOrEmpty(residue.ResidueColor) ? Loc.GetString("forensic-residue", ("adjective", residue.ResidueAdjective)) : Loc.GetString("forensic-residue-colored", ("color", residue.ResidueColor), ("adjective", residue.ResidueAdjective)));
|
||||
}
|
||||
|
||||
public string GenerateFingerprint()
|
||||
{
|
||||
var fingerprint = new byte[16];
|
||||
@@ -64,5 +153,31 @@ namespace Content.Server.Forensics
|
||||
if (TryComp<FingerprintComponent>(user, out var fingerprint))
|
||||
component.Fingerprints.Add(fingerprint.Fingerprint ?? "");
|
||||
}
|
||||
|
||||
private void OnTransferDnaEvent(EntityUid uid, DnaComponent component, ref TransferDnaEvent args)
|
||||
{
|
||||
var recipientComp = EnsureComp<ForensicsComponent>(args.Recipient);
|
||||
recipientComp.DNAs.Add(component.DNA);
|
||||
recipientComp.CanDnaBeCleaned = args.CanDnaBeCleaned;
|
||||
}
|
||||
|
||||
#region Public API
|
||||
|
||||
/// <summary>
|
||||
/// Transfer DNA from one entity onto the forensics of another
|
||||
/// </summary>
|
||||
/// <param name="recipient">The entity receiving the DNA</param>
|
||||
/// <param name="donor">The entity applying its DNA</param>
|
||||
/// <param name="canDnaBeCleaned">If this DNA be cleaned off of the recipient. e.g. cleaning a knife vs cleaning a puddle of blood</param>
|
||||
public void TransferDna(EntityUid recipient, EntityUid donor, bool canDnaBeCleaned = true)
|
||||
{
|
||||
if (TryComp<DnaComponent>(donor, out var donorComp))
|
||||
{
|
||||
EnsureComp<ForensicsComponent>(recipient, out var recipientComp);
|
||||
recipientComp.DNAs.Add(donorComp.DNA);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace Content.Server.Medical
|
||||
[Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
|
||||
[Dependency] private readonly StunSystem _stun = default!;
|
||||
[Dependency] private readonly ThirstSystem _thirst = default!;
|
||||
[Dependency] private readonly ForensicsSystem _forensics = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Make an entity vomit, if they have a stomach.
|
||||
@@ -85,9 +86,7 @@ namespace Content.Server.Medical
|
||||
|
||||
if (_puddle.TrySpillAt(uid, solution, out var puddle, false))
|
||||
{
|
||||
var forensics = EnsureComp<ForensicsComponent>(puddle);
|
||||
if (TryComp<DnaComponent>(uid, out var dna))
|
||||
forensics.DNAs.Add(dna.DNA);
|
||||
_forensics.TransferDna(puddle, uid, false);
|
||||
}
|
||||
|
||||
// Force sound to play as spill doesn't work if solution is empty.
|
||||
|
||||
@@ -54,6 +54,7 @@ public sealed class DrinkSystem : EntitySystem
|
||||
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
|
||||
[Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
|
||||
[Dependency] private readonly StomachSystem _stomach = default!;
|
||||
[Dependency] private readonly ForensicsSystem _forensics = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -399,9 +400,7 @@ public sealed class DrinkSystem : EntitySystem
|
||||
//TODO: Grab the stomach UIDs somehow without using Owner
|
||||
_stomach.TryTransferSolution(firstStomach.Value.Comp.Owner, drained, firstStomach.Value.Comp);
|
||||
|
||||
var comp = EnsureComp<ForensicsComponent>(uid);
|
||||
if (TryComp<DnaComponent>(args.Target, out var dna))
|
||||
comp.DNAs.Add(dna.DNA);
|
||||
_forensics.TransferDna(uid, args.Target.Value);
|
||||
|
||||
if (!forceDrink && solution.Volume > 0)
|
||||
args.Repeat = true;
|
||||
|
||||
@@ -15,6 +15,8 @@ using Content.Shared.Temperature;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Containers;
|
||||
using System.Linq;
|
||||
using Content.Shared.Inventory.Events;
|
||||
using Content.Server.Forensics;
|
||||
|
||||
namespace Content.Server.Nutrition.EntitySystems
|
||||
{
|
||||
@@ -30,6 +32,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
[Dependency] private readonly SharedItemSystem _items = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly ForensicsSystem _forensics = default!;
|
||||
|
||||
private const float UpdateTimer = 3f;
|
||||
|
||||
@@ -44,6 +47,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
{
|
||||
SubscribeLocalEvent<SmokableComponent, IsHotEvent>(OnSmokableIsHotEvent);
|
||||
SubscribeLocalEvent<SmokableComponent, ComponentShutdown>(OnSmokableShutdownEvent);
|
||||
SubscribeLocalEvent<SmokableComponent, GotEquippedEvent>(OnSmokeableEquipEvent);
|
||||
|
||||
InitializeCigars();
|
||||
InitializePipes();
|
||||
@@ -85,6 +89,14 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
_active.Remove(uid);
|
||||
}
|
||||
|
||||
private void OnSmokeableEquipEvent(EntityUid uid, SmokableComponent component, GotEquippedEvent args)
|
||||
{
|
||||
if (args.Slot == "mask")
|
||||
{
|
||||
_forensics.TransferDna(uid, args.Equipee, false);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
_timer += frameTime;
|
||||
|
||||
@@ -24,3 +24,30 @@ public sealed partial class ForensicPadDoAfterEvent : DoAfterEvent
|
||||
|
||||
public override DoAfterEvent Clone() => this;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CleanForensicsDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An event to apply DNA evidence from a donor onto some recipient.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct TransferDnaEvent()
|
||||
{
|
||||
/// <summary>
|
||||
/// The entity donating the DNA.
|
||||
/// </summary>
|
||||
public EntityUid Donor;
|
||||
|
||||
/// <summary>
|
||||
/// The entity receiving the DNA.
|
||||
/// </summary>
|
||||
public EntityUid Recipient;
|
||||
|
||||
/// <summary>
|
||||
/// Can the DNA be cleaned off?
|
||||
/// </summary>
|
||||
public bool CanDnaBeCleaned = true;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Content.Shared.Forensics
|
||||
public readonly List<string> Fingerprints = new();
|
||||
public readonly List<string> Fibers = new();
|
||||
public readonly List<string> DNAs = new();
|
||||
public readonly List<string> Residues = new();
|
||||
public readonly string LastScannedName = string.Empty;
|
||||
public readonly TimeSpan PrintCooldown = TimeSpan.Zero;
|
||||
public readonly TimeSpan PrintReadyAt = TimeSpan.Zero;
|
||||
@@ -16,6 +17,7 @@ namespace Content.Shared.Forensics
|
||||
List<string> fingerprints,
|
||||
List<string> fibers,
|
||||
List<string> dnas,
|
||||
List<string> residues,
|
||||
string lastScannedName,
|
||||
TimeSpan printCooldown,
|
||||
TimeSpan printReadyAt)
|
||||
@@ -23,6 +25,7 @@ namespace Content.Shared.Forensics
|
||||
Fingerprints = fingerprints;
|
||||
Fibers = fibers;
|
||||
DNAs = dnas;
|
||||
Residues = residues;
|
||||
LastScannedName = lastScannedName;
|
||||
PrintCooldown = printCooldown;
|
||||
PrintReadyAt = printReadyAt;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Forensics;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Implants.Components;
|
||||
using Content.Shared.Popups;
|
||||
@@ -72,6 +73,9 @@ public abstract class SharedImplanterSystem : EntitySystem
|
||||
else
|
||||
ImplantMode(implanter, component);
|
||||
|
||||
var ev = new TransferDnaEvent { Donor = target, Recipient = implanter };
|
||||
RaiseLocalEvent(target, ref ev);
|
||||
|
||||
Dirty(component);
|
||||
}
|
||||
|
||||
@@ -140,6 +144,10 @@ public abstract class SharedImplanterSystem : EntitySystem
|
||||
implantComp.ImplantedEntity = null;
|
||||
implanterContainer.Insert(implant);
|
||||
permanentFound = implantComp.Permanent;
|
||||
|
||||
var ev = new TransferDnaEvent { Donor = target, Recipient = implanter };
|
||||
RaiseLocalEvent(target, ref ev);
|
||||
|
||||
//Break so only one implant is drawn
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ forensic-scanner-interface-title = Forensic scanner
|
||||
forensic-scanner-interface-fingerprints = Fingerprints
|
||||
forensic-scanner-interface-fibers = Fibers
|
||||
forensic-scanner-interface-dnas = DNAs
|
||||
forensic-scanner-interface-residues = Residues
|
||||
forensic-scanner-interface-no-data = No scan data available
|
||||
forensic-scanner-interface-print = Print
|
||||
forensic-scanner-interface-clear = Clear
|
||||
|
||||
11
Resources/Locale/en-US/forensics/residues.ftl
Normal file
11
Resources/Locale/en-US/forensics/residues.ftl
Normal file
@@ -0,0 +1,11 @@
|
||||
forensic-residue = {LOC($adjective)} residue
|
||||
forensic-residue-colored = {LOC($adjective)} {LOC($color)} residue
|
||||
|
||||
residue-unknown = unknown
|
||||
residue-slippery = slippery
|
||||
|
||||
residue-green = green
|
||||
residue-blue = blue
|
||||
residue-red = red
|
||||
residue-grey = grey
|
||||
residue-brown = brown
|
||||
@@ -611,3 +611,6 @@
|
||||
tags:
|
||||
- DroneUsable
|
||||
- Mop
|
||||
- CleansForensics
|
||||
- type: Fiber
|
||||
fiberColor: fibers-white
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
- type: Tag
|
||||
tags:
|
||||
- Soap
|
||||
- CleansForensics
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Janitorial/soap.rsi
|
||||
layers:
|
||||
@@ -68,6 +69,9 @@
|
||||
- type: Food
|
||||
solution: soap
|
||||
- type: BadFood
|
||||
- type: Residue
|
||||
residueAdjective: residue-slippery
|
||||
residueColor: residue-green
|
||||
|
||||
- type: entity
|
||||
name: soap
|
||||
@@ -90,6 +94,9 @@
|
||||
reagents:
|
||||
- ReagentId: SoapReagent
|
||||
Quantity: 100
|
||||
- type: Residue
|
||||
residueAdjective: residue-slippery
|
||||
residueColor: residue-grey
|
||||
|
||||
- type: entity
|
||||
name: soap
|
||||
@@ -105,6 +112,9 @@
|
||||
fillBaseName: deluxe-
|
||||
- type: Item
|
||||
heldPrefix: deluxe
|
||||
- type: Residue
|
||||
residueAdjective: residue-slippery
|
||||
residueColor: residue-brown
|
||||
|
||||
- type: entity
|
||||
name: soap
|
||||
@@ -127,6 +137,9 @@
|
||||
flavors:
|
||||
- clean
|
||||
- punishment
|
||||
- type: Residue
|
||||
residueAdjective: residue-slippery
|
||||
residueColor: residue-red
|
||||
|
||||
- type: entity
|
||||
name: soaplet
|
||||
@@ -189,6 +202,9 @@
|
||||
flavors:
|
||||
- clean
|
||||
- meaty
|
||||
- type: Residue
|
||||
residueAdjective: residue-slippery
|
||||
residueColor: residue-red
|
||||
|
||||
- type: entity
|
||||
name: omega soap
|
||||
@@ -214,3 +230,6 @@
|
||||
reagents:
|
||||
- ReagentId: SoapReagent
|
||||
Quantity: 240
|
||||
- type: Residue
|
||||
residueAdjective: residue-slippery
|
||||
residueColor: residue-blue
|
||||
@@ -1124,3 +1124,6 @@
|
||||
|
||||
- type: Tag
|
||||
id: boots
|
||||
|
||||
- type: Tag
|
||||
id: CleansForensics
|
||||
Reference in New Issue
Block a user