diff --git a/code/modules/projectiles/projectile_parent.dm b/code/modules/projectiles/projectile_parent.dm
index 946bba97c4e15..72b406978ffed 100644
--- a/code/modules/projectiles/projectile_parent.dm
+++ b/code/modules/projectiles/projectile_parent.dm
@@ -28,8 +28,6 @@
var/max_range = PROJ_INFINITE_RANGE
/// What kind of implant this projectile leaves in impacted mobs
var/implanted = null
- /// Forensic ID of the gun, etc that shot this projectile, used for forensics on implanted projectiles
- var/forensic_ID = null
/// The mob/thing that fired this projectile
var/atom/shooter = null
/// Mob-typed copy of `shooter` var to save time on casts later
diff --git a/code/obj.dm b/code/obj.dm
index 083a8a670ccde..2e26ff0c2141a 100644
--- a/code/obj.dm
+++ b/code/obj.dm
@@ -21,6 +21,9 @@
var/_health = 100
var/_max_health = 100
+ /// if gun/bullet related, forensic profile of it
+ var/forensic_ID = null
+
New()
. = ..()
if (HAS_FLAG(object_flags, HAS_DIRECTIONAL_BLOCKING))
@@ -472,3 +475,12 @@ ADMIN_INTERACT_PROCS(/obj, proc/admin_command_obj_speak)
return TRUE
/obj/proc/after_abcu_spawn()
+
+/// creates an id profile for any forenics purpose. override as needed
+/obj/proc/CreateID()
+ . = ""
+
+ do
+ for(var/i = 1 to 10) // 20 characters are way too fuckin' long for anyone to care about
+ . += "[pick(numbersAndLetters)]"
+ while(. in forensic_IDs)
diff --git a/code/obj/item/clothing/gloves.dm b/code/obj/item/clothing/gloves.dm
index 68a309f6062c3..70bb5ee0ba9da 100644
--- a/code/obj/item/clothing/gloves.dm
+++ b/code/obj/item/clothing/gloves.dm
@@ -58,7 +58,7 @@ ABSTRACT_TYPE(/obj/item/clothing/gloves)
. += "It seems to have some wires attached to it.[src.max_uses > 0 ? " There are [src.uses]/[src.max_uses] charges left!" : ""]"
// reworked this proc a bit so it can't run more than 5 times, just in case
- proc/CreateID()
+ CreateID()
var/newID = null
for (var/i=5, i>0, i--)
newID = GenID()
diff --git a/code/obj/item/deployable_turret.dm b/code/obj/item/deployable_turret.dm
index 0c05d62162e06..5f59ed662f539 100644
--- a/code/obj/item/deployable_turret.dm
+++ b/code/obj/item/deployable_turret.dm
@@ -18,9 +18,15 @@ ABSTRACT_TYPE(/obj/item/turret_deployer)
var/associated_turret = null //what kind of turret should this spawn?
var/turret_health = 100
- New()
+ New(newLoc, forensics_id)
..()
icon_state = "[src.icon_tag]_deployer"
+ if (!src.forensic_ID)
+ if (forensics_id)
+ src.forensic_ID = forensics_id
+ else
+ src.forensic_ID = src.CreateID()
+ forensic_IDs.Add(src.forensic_ID)
get_desc()
. = "
[SPAN_NOTICE("It looks [damage_words]")]"
@@ -133,11 +139,18 @@ ADMIN_INTERACT_PROCS(/obj/deployable_turret, proc/admincmd_shoot, proc/admincmd_
var/deconstructable = TRUE
var/can_toggle_activation = TRUE // whether you can enable or disable the turret with a screwdriver, used for map setpiece turrets
- New(loc, direction)
+ New(loc, direction, forensics_id)
..()
src.set_dir(direction || src.dir) // don't set the dir if we weren't passed one
src.set_initial_angle()
+ if (!src.forensic_ID)
+ if (forensics_id)
+ src.forensic_ID = forensics_id
+ else
+ src.forensic_ID = src.CreateID()
+ forensic_IDs.Add(src.forensic_ID)
+
src.icon_state = "[src.icon_tag]_base"
src.appearance_flags |= RESET_TRANSFORM
src.underlays += src
@@ -191,9 +204,25 @@ ADMIN_INTERACT_PROCS(/obj/deployable_turret, proc/admincmd_shoot, proc/admincmd_
proc/shoot(target)
SPAWN(0)
+ var/list/casing_turfs
+ var/turf/picked_turf
+ if (src.current_projectile.casing)
+ casing_turfs = list()
+ for (var/direction in alldirs)
+ var/turf/T = get_step(src, direction)
+ if (T && !T.density)
+ casing_turfs += T
for(var/i in 1 to src.current_projectile.shot_number) //loop animation until finished
flick("[src.icon_tag]_fire",src)
muzzle_flash_any(src, 0, "muzzle_flash")
+ if (src.current_projectile.casing)
+ picked_turf = pick(casing_turfs)
+ var/obj/item/casing/turret_casing = new src.current_projectile.casing(picked_turf, src.forensic_ID)
+ // prevent infinite casing stacks
+ if (length(picked_turf.contents) > 10)
+ SPAWN(30 SECONDS)
+ if (!QDELETED(turret_casing) && get_turf(turret_casing) == picked_turf)
+ qdel(turret_casing)
sleep(src.current_projectile.shot_delay)
shoot_projectile_ST_pixel_spread(src, current_projectile, target, 0, 0 , spread)
@@ -353,7 +382,7 @@ ADMIN_INTERACT_PROCS(/obj/deployable_turret, proc/admincmd_shoot, proc/admincmd_
qdel(src)
proc/spawn_deployer()
- var/obj/item/turret_deployer/deployer = new src.associated_deployer(src.loc)
+ var/obj/item/turret_deployer/deployer = new src.associated_deployer(src.loc, src.forensic_ID)
deployer.turret_health = src.health // NO FREE REPAIRS, ASSHOLES
deployer.damage_words = src.damage_words
deployer.quick_deploy_fuel = src.quick_deploy_fuel
diff --git a/code/obj/item/gun/gun_parent.dm b/code/obj/item/gun/gun_parent.dm
index 5f3f5d14d2c7d..32823893af965 100644
--- a/code/obj/item/gun/gun_parent.dm
+++ b/code/obj/item/gun/gun_parent.dm
@@ -34,7 +34,6 @@ var/list/forensic_IDs = new/list() //Global list of all guns, based on bioholder
var/slowdown = 0 //Movement delay attack after attack
var/slowdown_time = 10 //For this long
- var/forensic_ID = null
var/add_residue = 0 // Does this gun add gunshot residue when fired (Convair880)?
var/shoot_delay = 4
@@ -132,15 +131,6 @@ var/list/forensic_IDs = new/list() //Global list of all guns, based on bioholder
user.back.Attackby(src, user)
return TRUE
-/obj/item/gun/proc/CreateID() //Creates a new tracking id for the gun and returns it.
- . = ""
-
- do
- for(var/i = 1 to 10) // 20 characters are way too fuckin' long for anyone to care about
- . += "[pick(numbersAndLetters)]"
- while(. in forensic_IDs)
-
-
///CHECK_LOCK
///Call to run a weaponlock check vs the users implant
///Return 0 for fail
diff --git a/code/obj/item/gun/kinetic.dm b/code/obj/item/gun/kinetic.dm
index 7a43e252e4557..5be1a45b5b16f 100644
--- a/code/obj/item/gun/kinetic.dm
+++ b/code/obj/item/gun/kinetic.dm
@@ -378,7 +378,6 @@ ABSTRACT_TYPE(/obj/item/survival_rifle_barrel)
icon = 'icons/obj/items/casings.dmi'
icon_state = "medium"
w_class = W_CLASS_TINY
- var/forensic_ID = null
burn_possible = FALSE
small
diff --git a/code/obj/item/implant.dm b/code/obj/item/implant.dm
index a5eb1953f878f..54bc62b8ac4ad 100644
--- a/code/obj/item/implant.dm
+++ b/code/obj/item/implant.dm
@@ -845,7 +845,6 @@ ABSTRACT_TYPE(/obj/item/implant/revenge)
scan_category = "not_shown"
var/bleed_time = 60
var/bleed_timer = 0
- var/forensic_ID = null // match a bullet to a gun holy heckkkkk
var/leaves_wound = TRUE
New()
diff --git a/code/procs/scanprocs.dm b/code/procs/scanprocs.dm
index 51b0d640d66a7..48500a5c2d249 100644
--- a/code/procs/scanprocs.dm
+++ b/code/procs/scanprocs.dm
@@ -679,20 +679,10 @@
if (G.glove_ID)
glove_data += "[G.glove_ID] [G.material_prints ? "([G.material_prints])" : null]"
- if (istype(A, /obj/item/casing/))
- var/obj/item/casing/C = A
- if(C.forensic_ID)
- forensic_data += "
[SPAN_NOTICE("Forensic profile of [C]:")] [C.forensic_ID]"
-
- if (istype(A, /obj/item/implant/projectile))
- var/obj/item/implant/projectile/P = A
- if(P.forensic_ID)
- forensic_data += "
[SPAN_NOTICE("Forensic profile of [P]:")] [P.forensic_ID]"
-
- if (istype(A, /obj/item/gun))
- var/obj/item/gun/G = A
- if(G.forensic_ID)
- forensic_data += "
[SPAN_NOTICE("Forensic profile of [G]:")] [G.forensic_ID]"
+ if (istype(A, /obj))
+ var/obj/O = A
+ if(O.forensic_ID)
+ forensic_data += "
[SPAN_NOTICE("Forensic profile of [O]:")] [O.forensic_ID]"
if (istype(A, /turf/simulated/wall))
var/turf/simulated/wall/W = A