From 565e39a28f4391771c573afb3a0d8d17e447766d Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Sat, 5 Sep 2015 23:08:14 +0930 Subject: [PATCH 1/5] Porting forensics from Aurora. --- code/__defines/misc.dm | 36 +- code/datums/supplypacks.dm | 14 + code/game/atoms.dm | 10 +- code/game/jobs/job/security.dm | 3 +- code/game/machinery/buttons.dm | 2 - code/game/machinery/door_control.dm | 16 - code/game/machinery/doors/airlock.dm | 2 +- code/game/machinery/doors/door.dm | 2 - code/game/machinery/igniter.dm | 2 - .../effects/decals/Cleanable/humans.dm | 13 + .../effects/decals/Cleanable/tracks.dm | 7 + code/game/objects/effects/decals/cleanable.dm | 3 + code/game/objects/items.dm | 14 +- .../crates_lockers/closets/secure/security.dm | 1 - code/game/turfs/simulated.dm | 5 + code/game/turfs/turf.dm | 3 + code/modules/clothing/clothing.dm | 6 + code/modules/clothing/suits/jobs.dm | 4 +- code/modules/detectivework/footprints.dm | 0 code/modules/detectivework/forensics.dm | 4 + .../detectivework/microscope/dnascanner.dm | 153 ++++++ .../detectivework/microscope/microscope.dm | 108 ++++ .../detectivework/microscope/slides.dm | 42 ++ code/modules/detectivework/scanner.dm | 115 ----- .../modules/detectivework/scanning_console.dm | 313 ------------ code/modules/detectivework/tools/crimekit.dm | 17 + .../{evidence.dm => tools/evidencebag.dm} | 53 -- code/modules/detectivework/tools/luminol.dm | 13 + .../{footprints_and_rag.dm => tools/rag.dm} | 26 +- .../detectivework/tools/sample_kits.dm | 158 ++++++ code/modules/detectivework/tools/storage.dm | 44 ++ code/modules/detectivework/tools/swabs.dm | 119 +++++ code/modules/detectivework/tools/uvlight.dm | 69 +++ code/modules/mob/living/carbon/carbon.dm | 2 - code/modules/mob/living/carbon/human/human.dm | 6 + .../mob/living/carbon/human/human_defines.dm | 1 + code/modules/organs/blood.dm | 2 + code/modules/projectiles/ammunition.dm | 2 + code/modules/projectiles/guns/projectile.dm | 10 + code/modules/reagents/Chemistry-Reagents.dm | 7 - .../Chemistry-Reagents-Medicine.dm | 10 +- .../Chemistry-Reagents-Other.dm | 25 +- code/modules/reagents/Chemistry-Recipes.dm | 32 +- .../reagents/reagent_containers/spray.dm | 16 +- icons/obj/device.dmi | Bin 25377 -> 23892 bytes icons/obj/forensics.dmi | Bin 0 -> 16704 bytes maps/exodus-1.dmm | 482 +++++++++--------- nano/templates/dnaforensics.tmpl | 45 ++ polaris.dme | 16 +- 49 files changed, 1198 insertions(+), 835 deletions(-) create mode 100644 code/modules/detectivework/footprints.dm create mode 100644 code/modules/detectivework/microscope/dnascanner.dm create mode 100644 code/modules/detectivework/microscope/microscope.dm create mode 100644 code/modules/detectivework/microscope/slides.dm delete mode 100644 code/modules/detectivework/scanner.dm delete mode 100644 code/modules/detectivework/scanning_console.dm create mode 100644 code/modules/detectivework/tools/crimekit.dm rename code/modules/detectivework/{evidence.dm => tools/evidencebag.dm} (65%) create mode 100644 code/modules/detectivework/tools/luminol.dm rename code/modules/detectivework/{footprints_and_rag.dm => tools/rag.dm} (99%) create mode 100644 code/modules/detectivework/tools/sample_kits.dm create mode 100644 code/modules/detectivework/tools/storage.dm create mode 100644 code/modules/detectivework/tools/swabs.dm create mode 100644 code/modules/detectivework/tools/uvlight.dm create mode 100644 icons/obj/forensics.dmi create mode 100644 nano/templates/dnaforensics.tmpl diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index 2345d895fa..0f7d1825e8 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -63,24 +63,24 @@ #define LIFE_HUD 10 // STATUS_HUD that only reports dead or alive //some colors -#define COLOR_WHITE "#FFFFFF" -#define COLOR_SILVER "#C0C0C0" -#define COLOR_GRAY "#808080" -#define COLOR_BLACK "#000000" -#define COLOR_RED "#FF0000" -#define COLOR_MAROON "#800000" -#define COLOR_YELLOW "#FFFF00" -#define COLOR_OLIVE "#808000" -#define COLOR_LIME "#00FF00" -#define COLOR_GREEN "#008000" -#define COLOR_CYAN "#00FFFF" -#define COLOR_TEAL "#008080" -#define COLOR_BLUE "#0000FF" -#define COLOR_NAVY "#000080" -#define COLOR_PINK "#FF00FF" -#define COLOR_PURPLE "#800080" -#define COLOR_ORANGE "#FF9900" - +#define COLOR_WHITE "#FFFFFF" +#define COLOR_SILVER "#C0C0C0" +#define COLOR_GRAY "#808080" +#define COLOR_BLACK "#000000" +#define COLOR_RED "#FF0000" +#define COLOR_MAROON "#800000" +#define COLOR_YELLOW "#FFFF00" +#define COLOR_OLIVE "#808000" +#define COLOR_LIME "#00FF00" +#define COLOR_GREEN "#008000" +#define COLOR_CYAN "#00FFFF" +#define COLOR_TEAL "#008080" +#define COLOR_BLUE "#0000FF" +#define COLOR_NAVY "#000080" +#define COLOR_PINK "#FF00FF" +#define COLOR_PURPLE "#800080" +#define COLOR_ORANGE "#FF9900" +#define COLOR_LUMINOL "#66FFFF" // Shuttles. // These define the time taken for the shuttle to get to the space station, and the time before it leaves again. diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm index 59b183975c..c5dc43ac02 100644 --- a/code/datums/supplypacks.dm +++ b/code/datums/supplypacks.dm @@ -43,6 +43,20 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee group = "Security" hidden = 1 +/datum/supply_packs/forensics + name = "Auxiliary forensic tools" + contains = list(/obj/item/weapon/forensics/sample_kit, + /obj/item/weapon/forensics/sample_kit/powder, + /obj/item/weapon/storage/box/swabs, + /obj/item/weapon/storage/box/swabs, + /obj/item/weapon/storage/box/swabs, + /obj/item/weapon/storage/box/slides, + /obj/item/weapon/reagent_containers/spray/luminol) + cost = 30 + containertype = /obj/structure/closet/crate + containername = "Auxiliary forensic tools" + group = "Security" + /datum/supply_packs/food name = "Kitchen supply crate" contains = list(/obj/item/weapon/reagent_containers/food/condiment/flour, diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 77279ab117..953967764e 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -6,12 +6,14 @@ var/list/fingerprintshidden var/fingerprintslast = null var/list/blood_DNA + var/was_bloodied var/blood_color var/last_bumped = 0 var/pass_flags = 0 var/throwpass = 0 var/germ_level = GERM_LEVEL_AMBIENT // The higher the germ level, the more germ on the atom. var/simulated = 1 //filter for actions - used by lighting overlays + var/fluorescent // Shows up under a UV light. ///Chemistry. var/datum/reagents/reagents = null @@ -23,6 +25,9 @@ //Detective Work, used for the duplicate data points kept in the scanners var/list/original_atom +/atom/proc/reveal_blood() + return + /atom/proc/assume_air(datum/gas_mixture/giver) return null @@ -304,7 +309,7 @@ its easier to just keep the beam vertical. fingerprints = list() //Hash this shit. - var/full_print = md5(H.dna.uni_identity) + var/full_print = H.get_full_print() // Add the fingerprints // @@ -387,6 +392,7 @@ its easier to just keep the beam vertical. if(!blood_DNA || !istype(blood_DNA, /list)) //if our list of DNA doesn't exist yet (or isn't a list) initialise it. blood_DNA = list() + was_bloodied = 1 blood_color = "#A10808" if(istype(M)) if (!istype(M.dna, /datum/dna)) @@ -406,10 +412,10 @@ its easier to just keep the beam vertical. if(toxvomit) this.icon_state = "vomittox_[pick(1,4)]" - /atom/proc/clean_blood() if(!simulated) return + fluorescent = 0 src.germ_level = 0 if(istype(blood_DNA, /list)) blood_DNA = null diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm index 20f4ab73bc..4bf3fd442a 100644 --- a/code/game/jobs/job/security.dm +++ b/code/game/jobs/job/security.dm @@ -111,12 +111,11 @@ H.equip_to_slot_or_del(new /obj/item/weapon/flame/lighter/zippo(H), slot_l_store) if(H.backbag == 1)//Why cant some of these things spawn in his office? H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/evidence(H), slot_l_hand) - H.equip_to_slot_or_del(new /obj/item/device/detective_scanner(H), slot_r_store) else H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/evidence(H), slot_in_backpack) - H.equip_to_slot_or_del(new /obj/item/device/detective_scanner(H), slot_in_backpack) if(H.mind.role_alt_title && H.mind.role_alt_title == "Forensic Technician") H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/forensics/blue(H), slot_wear_suit) + H.equip_to_slot_or_del(new /obj/item/weapon/storage/briefcase/crimekit, slot_r_hand) else H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/det_trench(H), slot_wear_suit) H.equip_to_slot_or_del(new /obj/item/clothing/head/det(H), slot_head) diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index ec844b6004..70557a2e18 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -15,6 +15,4 @@ return src.attack_hand(user) /obj/machinery/button/attackby(obj/item/weapon/W, mob/user as mob) - if(istype(W, /obj/item/device/detective_scanner)) - return return src.attack_hand(user) \ No newline at end of file diff --git a/code/game/machinery/door_control.dm b/code/game/machinery/door_control.dm index 6662b20b67..b51d72ccd8 100644 --- a/code/game/machinery/door_control.dm +++ b/code/game/machinery/door_control.dm @@ -24,22 +24,6 @@ user << "Error, no route to host." /obj/machinery/button/remote/attackby(obj/item/weapon/W, mob/user as mob) - /* For later implementation - if (istype(W, /obj/item/weapon/screwdriver)) - { - if(wiresexposed) - icon_state = "doorctrl0" - wiresexposed = 0 - - else - icon_state = "doorctrl-open" - wiresexposed = 1 - - return - } - */ - if(istype(W, /obj/item/device/detective_scanner)) - return return src.attack_hand(user) /obj/machinery/button/remote/emag_act(var/remaining_charges, var/mob/user) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 121331f126..d32c7e45ee 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -750,7 +750,7 @@ About the new airlock wires panel: if(src.isElectrified()) if(src.shock(user, 75)) return - if(istype(C, /obj/item/device/detective_scanner) || istype(C, /obj/item/taperoll)) + if(istype(C, /obj/item/taperoll)) return src.add_fingerprint(user) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 2d1680aa7d..f583b620a4 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -202,8 +202,6 @@ ..() /obj/machinery/door/attackby(obj/item/I as obj, mob/user as mob) - if(istype(I, /obj/item/device/detective_scanner)) - return src.add_fingerprint(user) if(istype(I, /obj/item/stack/material) && I.get_material_name() == src.get_material_name()) diff --git a/code/game/machinery/igniter.dm b/code/game/machinery/igniter.dm index fa385a0115..5fd791843d 100755 --- a/code/game/machinery/igniter.dm +++ b/code/game/machinery/igniter.dm @@ -72,8 +72,6 @@ // src.sd_SetLuminosity(0) /obj/machinery/sparker/attackby(obj/item/weapon/W as obj, mob/user as mob) - if(istype(W, /obj/item/device/detective_scanner)) - return if (istype(W, /obj/item/weapon/screwdriver)) add_fingerprint(user) src.disable = !src.disable diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index 6d3d7cd1df..9f3e677270 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -22,6 +22,19 @@ var/global/list/image/splatter_cache=list() var/amount = 5 var/drytime +/obj/effect/decal/cleanable/blood/reveal_blood() + if(!fluorescent) + fluorescent = 1 + basecolor = COLOR_LUMINOL + update_icon() + +/obj/effect/decal/cleanable/blood/clean_blood() + fluorescent = 0 + if(invisibility != 100) + invisibility = 100 + amount = 0 + processing_objects -= src + /obj/effect/decal/cleanable/blood/Destroy() for(var/datum/disease/D in viruses) D.cure(0) diff --git a/code/game/objects/effects/decals/Cleanable/tracks.dm b/code/game/objects/effects/decals/Cleanable/tracks.dm index ae05e0e4cc..0df1a5e12a 100644 --- a/code/game/objects/effects/decals/Cleanable/tracks.dm +++ b/code/game/objects/effects/decals/Cleanable/tracks.dm @@ -29,6 +29,13 @@ var/global/list/image/fluidtrack_cache=list() src.basecolor=_color src.wet=_wet +/obj/effect/decal/cleanable/blood/tracks/reveal_blood() + if(!fluorescent) + if(stack && stack.len) + for(var/datum/fluidtrack/track in stack) + track.basecolor = COLOR_LUMINOL + ..() + // Footprints, tire trails... /obj/effect/decal/cleanable/blood/tracks amount = 0 diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm index dc5e6c57e8..93d6a4bb52 100644 --- a/code/game/objects/effects/decals/cleanable.dm +++ b/code/game/objects/effects/decals/cleanable.dm @@ -1,6 +1,9 @@ /obj/effect/decal/cleanable var/list/random_icon_states = list() +/obj/effect/decal/cleanable/clean_blood() + qdel(src) + /obj/effect/decal/cleanable/New() if (random_icon_states && length(src.random_icon_states) > 0) src.icon_state = pick(src.random_icon_states) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 9fa9ce9ff2..afabd9ae8a 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -29,9 +29,9 @@ //It should be used purely for appearance. For gameplay effects caused by items covering body parts, use body_parts_covered. var/flags_inv = 0 var/body_parts_covered = 0 //see setup.dm for appropriate bit flags - + var/item_flags = 0 //Miscellaneous flags pertaining to equippable objects. - + //var/heat_transfer_coefficient = 1 //0 prevents all transfers, 1 is invisible var/gas_transfer_coefficient = 1 // for leaking gas from turf to mask and vice-versa (for masks right now, but at some point, i'd like to include space helmets) var/permeability_coefficient = 1 // for chemicals/diseases @@ -494,6 +494,12 @@ var/list/global/slot_flags_enumeration = list( var/obj/item/clothing/gloves/G = src G.transfer_blood = 0 +/obj/item/reveal_blood() + if(was_bloodied && !fluorescent) + fluorescent = 1 + blood_color = COLOR_LUMINOL + blood_overlay.color = COLOR_LUMINOL + update_icon() /obj/item/add_blood(mob/living/carbon/human/M as mob) if (!..()) @@ -608,10 +614,10 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. usr.visible_message("[zoomdevicename ? "[usr] looks up from the [src.name]" : "[usr] lowers the [src.name]"].") return - + /obj/item/proc/pwr_drain() return 0 // Process Kill /obj/item/proc/resolve_attackby(atom/A, mob/source) return A.attackby(src,source) - + diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index fbd9441feb..21022bceaa 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -281,7 +281,6 @@ new /obj/item/weapon/storage/box/evidence(src) new /obj/item/device/radio/headset/headset_sec(src) new /obj/item/device/radio/headset/headset_sec/alt(src) - new /obj/item/device/detective_scanner(src) new /obj/item/clothing/suit/storage/vest/detective(src) new /obj/item/ammo_magazine/c45m/rubber(src) new /obj/item/ammo_magazine/c45m/rubber(src) diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index 8336a52569..15c6759980 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -14,6 +14,11 @@ var/max_fire_temperature_sustained = 0 //The max temperature of the fire which it was subjected to var/dirt = 0 +/turf/simulated/clean_blood() + for(var/obj/effect/decal/cleanable/blood/B in contents) + B.fluorescent = 0 + B.invisibility = 100 + /turf/simulated/New() ..() if(istype(loc, /area/chapel)) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index e6612a867f..3eb48aa0e7 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -216,3 +216,6 @@ var/const/enterloopsanity = 100 if(A.density && !(A.flags & ON_BORDER)) return 1 return 0 + +/turf/proc/update_blood_overlays() + return diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index a88ba411c2..319c2a2c48 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -2,6 +2,7 @@ name = "clothing" siemens_coefficient = 0.9 var/list/species_restricted = null //Only these species can wear this kit. + var/gunshot_residue //Used by forensics. /* Sprites used when the clothing item is refit. This is done by setting icon_override. @@ -15,6 +16,11 @@ /obj/item/clothing/proc/update_clothing_icon() return +// Aurora forensics port. +/obj/item/clothing/clean_blood() + ..() + gunshot_residue = null + //BS12: Species-restricted clothing check. /obj/item/clothing/mob_can_equip(M as mob, slot) diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm index c06198b287..88112918a3 100644 --- a/code/modules/clothing/suits/jobs.dm +++ b/code/modules/clothing/suits/jobs.dm @@ -96,7 +96,7 @@ item_state = "det_suit" blood_overlay_type = "coat" body_parts_covered = UPPER_TORSO|ARMS - allowed = list(/obj/item/weapon/tank/emergency_oxygen, /obj/item/device/flashlight,/obj/item/weapon/gun/energy,/obj/item/weapon/gun/projectile,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter,/obj/item/device/detective_scanner,/obj/item/device/taperecorder) + allowed = list(/obj/item/weapon/tank/emergency_oxygen, /obj/item/device/flashlight,/obj/item/weapon/gun/energy,/obj/item/weapon/gun/projectile,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter,/obj/item/device/taperecorder) armor = list(melee = 50, bullet = 10, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0) /obj/item/clothing/suit/storage/det_trench/grey @@ -109,7 +109,7 @@ desc = "A forensics technician jacket." item_state = "det_suit" body_parts_covered = UPPER_TORSO|ARMS - allowed = list(/obj/item/weapon/tank/emergency_oxygen, /obj/item/device/flashlight,/obj/item/weapon/gun/energy,/obj/item/weapon/gun/projectile,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/device/detective_scanner,/obj/item/device/taperecorder) + allowed = list(/obj/item/weapon/tank/emergency_oxygen, /obj/item/device/flashlight,/obj/item/weapon/gun/energy,/obj/item/weapon/gun/projectile,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/device/taperecorder) armor = list(melee = 10, bullet = 10, laser = 15, energy = 10, bomb = 0, bio = 0, rad = 0) /obj/item/clothing/suit/storage/forensics/red diff --git a/code/modules/detectivework/footprints.dm b/code/modules/detectivework/footprints.dm new file mode 100644 index 0000000000..e69de29bb2 diff --git a/code/modules/detectivework/forensics.dm b/code/modules/detectivework/forensics.dm index bca3090c3f..27e2231d24 100644 --- a/code/modules/detectivework/forensics.dm +++ b/code/modules/detectivework/forensics.dm @@ -1,3 +1,7 @@ +/obj/item/weapon/forensics + icon = 'icons/obj/forensics.dmi' + w_class = 1 + //This is the output of the stringpercent(print) proc, and means about 80% of //the print must be there for it to be complete. (Prints are 32 digits) var/const/FINGERPRINT_COMPLETE = 6 diff --git a/code/modules/detectivework/microscope/dnascanner.dm b/code/modules/detectivework/microscope/dnascanner.dm new file mode 100644 index 0000000000..4b3cafea50 --- /dev/null +++ b/code/modules/detectivework/microscope/dnascanner.dm @@ -0,0 +1,153 @@ +//DNA machine +/obj/machinery/dnaforensics + name = "DNA analyzer" + desc = "A high tech machine that is designed to read DNA samples properly." + icon = 'icons/obj/forensics.dmi' + icon_state = "dnaopen" + anchored = 1 + density = 1 + + var/obj/item/weapon/forensics/swab/bloodsamp = null + var/closed = 0 + var/scanning = 0 + var/scanner_progress = 0 + var/scanner_rate = 2.50 + var/last_process_worldtime = 0 + var/report_num = 0 + +/obj/machinery/dnaforensics/attackby(var/obj/item/W, mob/user as mob) + + if(bloodsamp) + user << "There is already a sample in the machine." + return + + if(closed) + user << "Open the cover before inserting the sample." + return + + var/obj/item/weapon/forensics/swab/swab = W + if(istype(swab) && swab.is_used()) + user.unEquip(W) + src.bloodsamp = swab + swab.loc = src + user << "You insert \the [W] into \the [src]." + else + user << "\The [src] only accepts used swabs." + return + +/obj/machinery/dnaforensics/ui_interact(mob/user, ui_key = "main",var/datum/nanoui/ui = null) + if(stat & (NOPOWER)) return + if(user.stat || user.restrained()) return + var/list/data = list() + data["scan_progress"] = round(scanner_progress) + data["scanning"] = scanning + data["bloodsamp"] = (bloodsamp ? bloodsamp.name : "") + data["bloodsamp_desc"] = (bloodsamp ? (bloodsamp.desc ? bloodsamp.desc : "No information on record.") : "") + data["lidstate"] = closed + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data) + if (!ui) + ui = new(user, src, ui_key, "dnaforensics.tmpl", "QuikScan DNA Analyzer", 540, 326) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/dnaforensics/Topic(href, href_list) + + if(..()) return 1 + + if(stat & (NOPOWER)) + return 0 // don't update UIs attached to this object + + if(href_list["scanItem"]) + if(scanning) + scanning = 0 + else + if(bloodsamp) + if(closed == 1) + scanner_progress = 0 + scanning = 1 + usr << "Scan initiated." + update_icon() + else + usr << "Please close sample lid before initiating scan." + else + usr << "Insert an item to scan." + + if(href_list["ejectItem"]) + if(bloodsamp) + bloodsamp.forceMove(src.loc) + bloodsamp = null + + if(href_list["toggleLid"]) + toggle_lid() + + return 1 + +/obj/machinery/dnaforensics/process() + if(scanning) + if(!bloodsamp || bloodsamp.loc != src) + bloodsamp = null + scanning = 0 + else if(scanner_progress >= 100) + complete_scan() + return + else + //calculate time difference + var/deltaT = (world.time - last_process_worldtime) * 0.1 + scanner_progress = min(100, scanner_progress + scanner_rate * deltaT) + last_process_worldtime = world.time + +/obj/machinery/dnaforensics/proc/complete_scan() + src.visible_message("\icon[src] makes an insistent chime.", 2) + update_icon() + if(bloodsamp) + var/obj/item/weapon/paper/P = new(src) + P.name = "[src] report #[++report_num]: [bloodsamp.name]" + P.stamped = list(/obj/item/weapon/stamp) + P.overlays = list("paper_stamped") + //dna data itself + var/data = "No scan information available." + if(bloodsamp.dna != null) + data = "Spectometric analysis on provided sample has determined the presence of [bloodsamp.dna.len] strings of DNA.

" + for(var/blood in bloodsamp.dna) + data += "\blue Blood type: [bloodsamp.dna[blood]]
\nDNA: [blood]

" + else + data += "No DNA found.
" + P.info = "[src] analysis report #[report_num]
" + P.info += "Scanned item:
[bloodsamp.name]
[bloodsamp.desc]

" + data + P.forceMove(src.loc) + P.update_icon() + scanning = 0 + update_icon() + return + +/obj/machinery/dnaforensics/attack_ai(mob/user as mob) + ui_interact(user) + +/obj/machinery/dnaforensics/attack_hand(mob/user as mob) + ui_interact(user) + +/obj/machinery/dnaforensics/verb/toggle_lid() + set category = "Object" + set name = "Toggle Lid" + set src in oview(1) + + if(usr.stat || !isliving(usr)) + return + + if(scanning) + usr << "You can't do that while [src] is scanning!" + return + + closed = !closed + src.update_icon() + +/obj/machinery/dnaforensics/update_icon() + ..() + if(!(stat & NOPOWER) && scanning) + icon_state = "dnaworking" + else if(closed) + icon_state = "dnaclosed" + else + icon_state = "dnaopen" diff --git a/code/modules/detectivework/microscope/microscope.dm b/code/modules/detectivework/microscope/microscope.dm new file mode 100644 index 0000000000..f420e2ee39 --- /dev/null +++ b/code/modules/detectivework/microscope/microscope.dm @@ -0,0 +1,108 @@ +//microscope code itself +/obj/machinery/microscope + name = "high powered electron microscope" + desc = "A highly advanced microscope capable of zooming up to 3000x." + icon = 'icons/obj/forensics.dmi' + icon_state = "microscope" + anchored = 1 + density = 1 + + var/obj/item/weapon/sample = null + var/report_num = 0 + +/obj/machinery/microscope/attackby(obj/item/weapon/W as obj, mob/user as mob) + + if(sample) + user << "There is already a slide in the microscope." + return + + if(istype(W, /obj/item/weapon/forensics/slide) || istype(W, /obj/item/weapon/sample/print)) + user << "You insert \the [W] into the microscope." + user.unEquip(W) + W.forceMove(src) + sample = W + update_icon() + return + +/obj/machinery/microscope/attack_hand(mob/user) + + if(!sample) + user << "The microscope has no sample to examine." + return + + user << "The microscope whirrs as you examine \the [sample]." + + if(!do_after(user, 25) || !sample) + return + + user << "Printing findings now..." + var/obj/item/weapon/paper/report = new(get_turf(src)) + report.stamped = list(/obj/item/weapon/stamp) + report.overlays = list("paper_stamped") + report_num++ + + if(istype(sample, /obj/item/weapon/forensics/slide)) + var/obj/item/weapon/forensics/slide/slide = sample + if(slide.has_swab) + var/obj/item/weapon/forensics/swab/swab = slide.has_swab + + report.name = "GSR report #[++report_num]: [swab.name]" + report.info = "Scanned item:
[swab.name]

" + + if(swab.gsr) + report.info += "Residue from a [swab.gsr] bullet detected." + else + report.info += "No gunpowder residue found." + + else if(slide.has_sample) + var/obj/item/weapon/sample/fibers/fibers = slide.has_sample + report.name = "Fiber report #[++report_num]: [fibers.name]" + report.info = "Scanned item:
[fibers.name]

" + if(fibers.evidence) + report.info = "Molecular analysis on provided sample has determined the presence of unique fiber strings.

" + for(var/fiber in fibers.evidence) + report.info += "Most likely match for fibers: [fiber]

" + else + report.info += "No fibers found." + else + report.name = "Empty slide report #[report_num]" + report.info = "Evidence suggests that there's nothing in this slide." + else if(istype(sample, /obj/item/weapon/sample/print)) + report.name = "Fingerprint report #[report_num]: [sample.name]" + report.info = "Fingerprint analysis report #[report_num]: [sample.name]
" + var/obj/item/weapon/sample/print/card = sample + if(card.evidence && card.evidence.len) + report.info += "Surface analysis has determined unique fingerprint strings:

" + for(var/prints in card.evidence) + report.info += "Fingerprint string: " + if(!is_complete_print(prints)) + report.info += "INCOMPLETE PRINT" + else + report.info += "[prints]" + report.info += "
" + else + report.info += "No information available." + + if(report) + report.update_icon() + if(report.info) + user << report.info + return + +/obj/machinery/microscope/AltClick() + if(usr.lying || !Adjacent(usr) || !ishuman(usr)) + return ..() + if(!sample) + usr << "\The [src] does not have a sample in it." + return + usr << "You remove \the [sample] from \the [src]." + sample.forceMove(get_turf(src)) + usr.put_in_hands(sample) + sample = null + update_icon() + return + +/obj/machinery/microscope/update_icon() + icon_state = "microscope" + if(sample) + icon_state += "slide" diff --git a/code/modules/detectivework/microscope/slides.dm b/code/modules/detectivework/microscope/slides.dm new file mode 100644 index 0000000000..8226e6a51e --- /dev/null +++ b/code/modules/detectivework/microscope/slides.dm @@ -0,0 +1,42 @@ +/obj/item/weapon/forensics/slide + name = "microscope slide" + desc = "A pair of thin glass panes used in the examination of samples beneath a microscope." + icon_state = "slide" + var/obj/item/weapon/forensics/swab/has_swab + var/obj/item/weapon/sample/fibers/has_sample + +/obj/item/weapon/forensics/slide/attackby(var/obj/item/weapon/W, var/mob/user) + if(has_swab || has_sample) + user << "There is already a sample in the slide." + return + if(istype (W, /obj/item/weapon/forensics/swab)) + has_swab = W + else if(istype(W, /obj/item/weapon/sample/fibers)) + has_sample = W + else + user << "You don't think this will fit." + return + user << "You insert the sample into the slide." + user.unEquip(W) + W.forceMove(src) + update_icon() + +/obj/item/weapon/forensics/slide/attack_self(var/mob/user) + if(has_swab || has_sample) + user << "You remove \the sample from \the [src]." + if(has_swab) + has_swab.loc = get_turf(src) + has_swab = null + if(has_sample) + has_sample.forceMove(get_turf(src)) + has_sample = null + update_icon() + return + +/obj/item/weapon/forensics/slide/update_icon() + if(!has_swab && !has_sample) + icon_state = "slide" + else if(has_swab) + icon_state = "slideswab" + else if(has_sample) + icon_state = "slidefiber" diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm deleted file mode 100644 index dc372e2356..0000000000 --- a/code/modules/detectivework/scanner.dm +++ /dev/null @@ -1,115 +0,0 @@ -/obj/item/device/detective_scanner - name = "forensic scanner" - desc = "Used to scan objects for DNA and fingerprints." - icon_state = "forensic1" - var/list/stored = list() - w_class = 3.0 - item_state = "electronic" - flags = CONDUCT | NOBLUDGEON - slot_flags = SLOT_BELT - -/obj/item/device/detective_scanner/attack(mob/living/carbon/human/M as mob, mob/user as mob) - if (!ishuman(M)) - user << "[M] is not human and cannot have the fingerprints." - flick("forensic0",src) - return 0 - if (( !( istype(M.dna, /datum/dna) ) || M.gloves) ) - user << "No fingerprints found on [M]" - flick("forensic0",src) - return 0 - else - var/obj/item/weapon/f_card/F = new /obj/item/weapon/f_card( user.loc ) - F.amount = 1 - F.add_fingerprint(M) - F.icon_state = "fingerprint1" - F.name = text("FPrintC- '[M.name]'") - user << "Done printing." - user << "[M]'s Fingerprints: [md5(M.dna.uni_identity)]" - if ( M.blood_DNA && M.blood_DNA.len ) - user << "Blood found on [M]. Analysing..." - spawn(15) - for(var/blood in M.blood_DNA) - user << "Blood type: [M.blood_DNA[blood]]\nDNA: [blood]" - return - -/obj/item/device/detective_scanner/afterattack(atom/A as obj|turf, mob/user, proximity) - if(!proximity) return - if(ismob(A)) - return - if(istype(A,/obj/machinery/computer/forensic_scanning)) - user.visible_message("[user] takes a cord out of [src] and hooks its end into [A]" ,\ - "You download data from [src] to [A]") - var/obj/machinery/computer/forensic_scanning/F = A - F.sync_data(stored) - return - - if(istype(A,/obj/item/weapon/f_card)) - user << "The scanner displays on the screen: \"ERROR 43: Object on Excluded Object List.\"" - flick("forensic0",src) - return - - add_fingerprint(user) - - //General - if ((!A.fingerprints || !A.fingerprints.len) && !A.suit_fibers && !A.blood_DNA) - user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.gender == MALE ? "him" : "her"] humming[prob(70) ? " gently." : "."]" ,\ - "Unable to locate any fingerprints, materials, fibers, or blood on [A]!",\ - "You hear a faint hum of electrical equipment.") - flick("forensic0",src) - return 0 - - if(add_data(A)) - user << "Object already in internal memory. Consolidating data..." - flick("forensic2",src) - return - - //PRINTS - if(A.fingerprints && A.fingerprints.len) - user << "Isolated [A.fingerprints.len] fingerprints:" - user << "Data Stored: Scan with Hi-Res Forensic Scanner to retrieve." - var/list/complete_prints = list() - for(var/i in A.fingerprints) - var/print = A.fingerprints[i] - if(stringpercent(print) <= FINGERPRINT_COMPLETE) - complete_prints += print - if(complete_prints.len < 1) - user << "No intact prints found" - else - user << "Found [complete_prints.len] intact prints" - for(var/i in complete_prints) - user << "    [i]" - - //FIBERS - if(A.suit_fibers && A.suit_fibers.len) - user << "Fibers/Materials Data Stored: Scan with Hi-Res Forensic Scanner to retrieve." - flick("forensic2",src) - - //Blood - if (A.blood_DNA && A.blood_DNA.len) - user << "Blood detected. Analysing..." - spawn(15) - for(var/blood in A.blood_DNA) - user << "Blood type: \red [A.blood_DNA[blood]] \t \black DNA: \red [blood]" - - user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.gender == MALE ? "him" : "her"] humming[prob(70) ? " gently." : "."]" ,\ - "You finish scanning \the [A].",\ - "You hear a faint hum of electrical equipment.") - flick("forensic2",src) - return 0 - -/obj/item/device/detective_scanner/proc/add_data(atom/A as mob|obj|turf|area) - var/datum/data/record/forensic/old = stored["\ref [A]"] - var/datum/data/record/forensic/fresh = new(A) - - if(old) - fresh.merge(old) - . = 1 - stored["\ref [A]"] = fresh - -/obj/item/device/detective_scanner/verb/wipe() - set name = "Wipe Forensic Data" - set category = "Object" - set src in view(1) - if (alert("Are you sure you want to wipe all data from [src]?",,"Yes","No") == "Yes") - stored = list() - usr << "Forensic data erase complete." diff --git a/code/modules/detectivework/scanning_console.dm b/code/modules/detectivework/scanning_console.dm deleted file mode 100644 index 25658a06f0..0000000000 --- a/code/modules/detectivework/scanning_console.dm +++ /dev/null @@ -1,313 +0,0 @@ -/obj/machinery/computer/forensic_scanning - name = "high-res forensic scanning computer" - icon_keyboard = "security_key" - icon_screen = "forensic" - - var/screen = "database" - var/authenticated = 0 - req_access = list(access_forensics_lockers) - var/scan_progress = -1 - var/obj/item/scanning - var/datum/data/record/forensic/current - - var/list/filters = list() - var/list/current_list = list() - - var/list/files = list() - -/obj/machinery/computer/forensic_scanning/proc/get_printable_data(var/datum/data/record/forensic/fresh) - . += "

[fresh.fields["name"]]

" - . += "Scanned in [fresh.fields["area"]] at [worldtime2text(fresh.fields["time"])]
" - var/list/prints = fresh.fields["fprints"] - if(prints.len) - . += "

Fingerprints:

" - var/incomplete = 0 - for(var/fullprint in prints) - var/print = prints[fullprint] - if(is_complete_print(print)) - . += "[print]
" - else - incomplete++ - if(incomplete) - . += "[incomplete] incomplete fingerprints." - else - . += "
No fingerprints recorded.
" - - var/list/fibers = fresh.fields["fibers"] - if(fibers.len) - . += "

Fibers:

" - . += "" - else - . += "
No fibers recorded." - - var/list/bloods = fresh.fields["blood"] - if(bloods.len) - . += "

Blood:

" - . += "" - else - . += "
No blood recorded." - -/obj/machinery/computer/forensic_scanning/proc/add_record(var/datum/data/record/forensic/fresh) - var/datum/data/record/forensic/old = files[fresh.uid] - if(old) - fresh.merge(old) - fresh.fields["label"] = old.fields["label"] - files[fresh.uid] = fresh - - //updating partial prints on other things - var/list/fprints = fresh.fields["fprints"] - if(fprints.len) - for(var/id in files) - var/datum/data/record/forensic/rec = files[id] - if(rec.update_prints(fprints)) - files[id] = rec - -/obj/machinery/computer/forensic_scanning/proc/process_card(var/obj/item/weapon/f_card/card) - if(card.fingerprints) - usr << "\The [src] sucks in \the [card] and whirrs, scanning it." - var/found = 0 - for(var/id in files) - var/datum/data/record/forensic/rec = files[id] - found = rec.update_prints(card.fingerprints) - if (found) - files[id] = rec - if(found) - usr << "Complete match found." - else - usr << "No match found." - return 1 - else - usr << "No fingerprints detected on [card]." - return 0 - -//Takes a list of forensic records, with key being reference to object, and updates internal database. -/obj/machinery/computer/forensic_scanning/proc/sync_data(var/list/newdata) - for(var/id in newdata) - var/datum/data/record/forensic/fresh = newdata[id] - add_record(fresh) - -/obj/machinery/computer/forensic_scanning/proc/get_filtered_set() - .= list() - for(var/id in files) - var/datum/data/record/forensic/cur = files[id] - var/add = 1 - if(filters["name"]) - add = 0 - for(var/filter in filters["name"]) - if(findtext(cur.fields["name"], filter)) - add = 1 - break - - if(filters["area"]) - add = 0 - for(var/filter in filters["area"]) - if(findtext(cur.fields["area"], filter)) - add = 1 - break - - if(filters["fprints"]) - add = 0 - var/list/prints = cur.fields["fprints"] - for(var/pid in prints) - var/print = prints[pid] - if (is_complete_print(print)) - for(var/filter in filters["fprints"]) - if(findtext(print, filter)) - add = 1 - break - - if(filters["fibers"]) - add = 0 - for(var/fiber in cur.fields["fibers"]) - for(var/filter in filters["fibers"]) - if(findtext(fiber, filter)) - add = 1 - break - - if(filters["blood"]) - add = 0 - for(var/DNA in cur.fields["blood"]) - for(var/filter in filters["blood"]) - if(findtext(DNA, filter)) - add = 1 - break - - if(filters["label"]) - add = 0 - for(var/filter in filters["label"]) - if(cur.fields["label"] && findtext(cur.fields["label"], filter)) - add = 1 - break - if (add) - .+=cur - -/obj/machinery/computer/forensic_scanning/attack_hand(mob/user) - if(..()) - return - user.set_machine(src) - - var/dat - if(!authenticated) - dat += "{Log In}" - else - dat += "{Log Out}" - dat += " | " - dat += "Database" - dat += " | " - dat += "Record details" - dat += " | " - dat += "Scanning" - dat +="


" - switch(screen) - if("database") //Database screen - dat += "Search filters:
" - var/list/filternames = list("Object"="name", "Area"="area", "Fingerprints"="fprints", "Fibers"="fibers", "DNA"="blood", "Label"="label") - for(var/filter in filternames) - var/fname = filternames[filter] - dat += "
[filter]: [filters[fname] ? list2text(filters[fname], ",") : "All"]" - - current_list = get_filtered_set() - dat+= "


" - if(current_list.len < 1) - dat += "No data matching your request found." - else - dat += "" - dat += "" - for(var/datum/data/record/forensic/record in current_list) - dat += "" - dat += "" - for(var/criteria in list("fprints", "fibers", "blood")) - var/list/data = record.fields[criteria] - dat += "" - dat += "" - dat += "" - dat += "" - dat += "
ObjectAreaFingerprintsFibersBloodLabel
[record.fields["name"]][record.fields["area"]][data.len ? data.len : "None"][record.fields["label"] ? record.fields["label"] : ""]Delete
" - dat += "Print all listed
" - - if("details") //Details screen - if(!current) - dat += "
NO RECORD SELECTED" - else - dat += get_printable_data(current) - dat += "
Labels: " - dat += "[current.fields["label"] ? current.fields["label"] : "None"]
" - dat += "Print record
" - - if("scan") //Scanning screen - dat += "Object: [scanning ? scanning.name : "-----"]
" - if (scanning) - if (scan_progress > 0) - dat += "Scan in progress." - dat += " Cancel
" - else - dat += "Scan
" - dat += "Insert fingerprint card here: -----" - - user << browse(dat,"window=fscanner") - onclose(user,"fscanner") - -/obj/machinery/computer/forensic_scanning/Topic(href,href_list) - if(..()) return 1 - switch(href_list["operation"]) - if("login") - var/mob/M = usr - if(istype(M,/mob/living/silicon) || allowed(M)) - authenticated = 1 - if("logout") - authenticated = 0 - if("filter") - var/filterstr = sanitize(input("Input the search criteria. Multiple values can be input, separated by a comma.", "Filter setting") as text|null) - if(filterstr) - filters[href_list["filter"]] = text2list(filterstr,",") - else - filters[href_list["filter"]] = null - if("screen") - screen = href_list["screen"] - if("details") - if(href_list["identifier"]) - screen = "details" - current = files[href_list["identifier"]] - else - usr << "No record found." - if("delete") - if(href_list["identifier"]) - if(alert("Are you sure you want to delete this record?","Record deletion", "Yes", "No") == "Yes") - files.Remove(href_list["identifier"]) - if(current && current.uid == href_list["identifier"]) - current = null - if("label") - if(current) - var/label = sanitize(input(usr,"Input the label for this record. Multiple values can be input, separated by a comma.", "Labeling record", current.fields["label"]) as text|null) - current.fields["label"] = label - if("object") - if(scanning) - scanning.loc = get_turf(src) - scan_progress = -1 - scanning = null - else - var/mob/M = usr - var/obj/item/I = M.get_active_hand() - if(I && istype(I)) - if(istype(I, /obj/item/weapon/evidencebag)) - scanning = I.contents[1] - scanning.loc = src - I.overlays.Cut() - I.w_class = 1 - I.icon_state = "evidenceobj" - else - scanning = I - M.drop_item() - I.loc = src - else - usr << "Invalid object, rejected." - if("scan") - if(scanning) - scan_progress = 10 - if("cancel") - scan_progress = -1 - if("card") - var/mob/M = usr - var/obj/item/I = M.get_active_hand() - if(istype(I, /obj/item/weapon/f_card)) - if(process_card(I)) - M.drop_item() - qdel(I) - else - usr << "Invalid fingerprint card, rejected." - if("print") - if(current) - var/obj/item/weapon/paper/P = new(loc) - P.name = "\improper Forensics Data ([current.fields["name"]])" - P.icon_state = "paper_words" - P.info = "Forensics Database - [worldtime2text(world.time)]

" - P.info += get_printable_data(current) - if("printall") - var/obj/item/weapon/paper/P = new(loc) - P.name = "\improper Forensics Data" - P.icon_state = "paper_words" - P.info = "Forensics Database - [worldtime2text(world.time)]

" - for(var/datum/data/record/forensic/cur in current_list) - P.info += get_printable_data(cur) - - updateUsrDialog() - -/obj/machinery/computer/forensic_scanning/process() - if (!..()) - return - if(scanning) - if(scan_progress > 0) - scan_progress-- - updateUsrDialog() - if(scan_progress == 0) - scan_progress = -1 - ping("Scan complete.") - var/datum/data/record/forensic/fresh = new(scanning) - add_record(fresh) - updateUsrDialog() diff --git a/code/modules/detectivework/tools/crimekit.dm b/code/modules/detectivework/tools/crimekit.dm new file mode 100644 index 0000000000..8b12203b21 --- /dev/null +++ b/code/modules/detectivework/tools/crimekit.dm @@ -0,0 +1,17 @@ +//crime scene kit +/obj/item/weapon/storage/briefcase/crimekit + name = "crime scene kit" + desc = "A stainless steel-plated carrycase for all your forensic needs. Feels heavy." + icon = 'icons/obj/forensics.dmi' + icon_state = "case" + item_state = "case" + storage_slots = 14 + +/obj/item/weapon/storage/briefcase/crimekit/New() + ..() + new /obj/item/weapon/storage/box/swabs(src) + new /obj/item/weapon/storage/box/fingerprints(src) + new /obj/item/weapon/reagent_containers/spray/luminol(src) + new /obj/item/device/uv_light(src) + new /obj/item/weapon/forensics/sample_kit(src) + new /obj/item/weapon/forensics/sample_kit/powder(src) \ No newline at end of file diff --git a/code/modules/detectivework/evidence.dm b/code/modules/detectivework/tools/evidencebag.dm similarity index 65% rename from code/modules/detectivework/evidence.dm rename to code/modules/detectivework/tools/evidencebag.dm index fa2feaca63..31c5b6a358 100644 --- a/code/modules/detectivework/evidence.dm +++ b/code/modules/detectivework/tools/evidencebag.dm @@ -96,56 +96,3 @@ /obj/item/weapon/evidencebag/examine(mob/user) ..(user) if (stored_item) user.examinate(stored_item) - -/obj/item/weapon/storage/box/evidence - name = "evidence bag box" - desc = "A box claiming to contain evidence bags. Also holds fingerprint cards." - icon = 'icons/obj/storage.dmi' - icon_state = "box" - storage_slots= 14 - max_w_class = 3 - max_storage_space = 38 - can_hold = list(/obj/item/weapon/f_card, /obj/item/weapon/evidencebag) - use_to_pickup = 1 - New() - new /obj/item/weapon/evidencebag(src) - new /obj/item/weapon/evidencebag(src) - new /obj/item/weapon/evidencebag(src) - new /obj/item/weapon/evidencebag(src) - new /obj/item/weapon/evidencebag(src) - new /obj/item/weapon/evidencebag(src) - ..() - return - -/obj/item/weapon/f_card - name = "finger print card" - desc = "Used to take fingerprints." - icon = 'icons/obj/card.dmi' - icon_state = "fingerprint0" - var/amount = 10.0 - item_state = "paper" - throwforce = 1 - w_class = 1.0 - slot_flags = SLOT_EARS - throw_speed = 3 - throw_range = 5 - -/obj/item/weapon/f_card/add_fingerprint(mob/living/M as mob, ignoregloves = 0) - if(..()) - var/mob/living/carbon/human/H = M - var/full_print = md5(H.dna.uni_identity) - fingerprints[full_print] = full_print - -/obj/item/weapon/f_card/examine(mob/user) - ..() - if(fingerprints.len) - user << "Fingerprints on this card:" - for(var/print in fingerprints) - user << "\t[fingerprints[print]]" - -/obj/item/weapon/fcardholder - name = "fingerprint card case" - desc = "Apply finger print card." - icon = 'icons/obj/items.dmi' - icon_state = "fcardholder0" - item_state = "clipboard" diff --git a/code/modules/detectivework/tools/luminol.dm b/code/modules/detectivework/tools/luminol.dm new file mode 100644 index 0000000000..ddf00a628a --- /dev/null +++ b/code/modules/detectivework/tools/luminol.dm @@ -0,0 +1,13 @@ +/obj/item/weapon/reagent_containers/spray/luminol + name = "luminol bottle" + desc = "A bottle containing an odourless, colorless liquid." + icon = 'icons/obj/forensics.dmi' + icon_state = "luminol" + item_state = "cleaner" + amount_per_transfer_from_this = 10 + possible_transfer_amounts = list(5,10) + volume = 250 + +/obj/item/weapon/reagent_containers/spray/luminol/New() + ..() + reagents.add_reagent("luminol", 250) \ No newline at end of file diff --git a/code/modules/detectivework/footprints_and_rag.dm b/code/modules/detectivework/tools/rag.dm similarity index 99% rename from code/modules/detectivework/footprints_and_rag.dm rename to code/modules/detectivework/tools/rag.dm index e94611bf10..816a228a9c 100644 --- a/code/modules/detectivework/footprints_and_rag.dm +++ b/code/modules/detectivework/tools/rag.dm @@ -71,7 +71,7 @@ icon_state = "raglit" else icon_state = "rag" - + var/obj/item/weapon/reagent_containers/food/drinks/bottle/B = loc if(istype(B)) B.update_icon() @@ -83,7 +83,7 @@ if(reagents.total_volume) var/target_text = trans_dest? "\the [trans_dest]" : "\the [user.loc]" user.visible_message("\The [user] begins to wring out [src] over [target_text].", "You begin to wring out [src] over [target_text].") - + if(do_after(user, reagents.total_volume*5)) //50 for a fully soaked rag if(trans_dest) reagents.trans_to(trans_dest, reagents.total_volume) @@ -114,29 +114,29 @@ if(user.zone_sel.selecting == "mouth") user.do_attack_animation(src) user.visible_message( - "\The [user] smothers [target] with [src]!", - "You smother [target] with [src]!", + "\The [user] smothers [target] with [src]!", + "You smother [target] with [src]!", "You hear some struggling and muffled cries of surprise" ) - + //it's inhaled, so... maybe CHEM_BLOOD doesn't make a whole lot of sense but it's the best we can do for now reagents.trans_to_mob(target, amount_per_transfer_from_this, CHEM_BLOOD) update_name() else wipe_down(target, user) return - + return ..() - + /obj/item/weapon/reagent_containers/glass/rag/afterattack(atom/A as obj|turf|area, mob/user as mob, proximity) - if(!proximity) + if(!proximity) return if(istype(A, /obj/structure/reagent_dispensers)) if(!reagents.get_free_space()) user << "\The [src] is already soaked." return - + if(A.reagents && A.reagents.trans_to_obj(src, reagents.maximum_volume)) user.visible_message("\The [user] soaks [src] using [A].", "You soak [src] using [A].") update_name() @@ -167,7 +167,7 @@ return if(!can_ignite()) return - + //also copied from matches if(reagents.get_reagent_amount("phoron")) // the phoron explodes when exposed to fire visible_message("\The [src] conflagrates violently!") @@ -176,7 +176,7 @@ e.start() qdel(src) return - + processing_objects += src set_light(2, null, "#E38F46") on_fire = 1 @@ -187,7 +187,7 @@ processing_objects -= src set_light(0) on_fire = 0 - + //rags sitting around with 1 second of burn time left is dumb. //ensures players always have a few seconds of burn time left when they light their rag if(burn_time <= 5) @@ -209,7 +209,7 @@ var/turf/location = get_turf(src) if(location) location.hotspot_expose(700, 5) - + if(burn_time <= 0) processing_objects -= src new /obj/effect/decal/cleanable/ash(location) diff --git a/code/modules/detectivework/tools/sample_kits.dm b/code/modules/detectivework/tools/sample_kits.dm new file mode 100644 index 0000000000..fa5c7312a8 --- /dev/null +++ b/code/modules/detectivework/tools/sample_kits.dm @@ -0,0 +1,158 @@ +/obj/item/weapon/sample + name = "forensic sample" + icon = 'icons/obj/forensics.dmi' + w_class = 1 + var/list/evidence = list() + +/obj/item/weapon/sample/New(var/newloc, var/atom/supplied) + ..(newloc) + if(supplied) + copy_evidence(supplied) + name = "[initial(name)] (\the [supplied])" + +/obj/item/weapon/sample/print/New(var/newloc, var/atom/supplied) + ..(newloc, supplied) + if(evidence && evidence.len) + icon_state = "fingerprint1" + +/obj/item/weapon/sample/proc/copy_evidence(var/atom/supplied) + if(supplied.suit_fibers && supplied.suit_fibers.len) + evidence = supplied.suit_fibers.Copy() + supplied.suit_fibers.Cut() + +/obj/item/weapon/sample/proc/merge_evidence(var/obj/item/weapon/sample/supplied, var/mob/user) + if(!supplied.evidence || !supplied.evidence.len) + return 0 + evidence |= supplied.evidence + name = "[initial(name)] (combined)" + user << "You transfer the contents of \the [supplied] into \the [src]." + return 1 + +/obj/item/weapon/sample/print/merge_evidence(var/obj/item/weapon/sample/supplied, var/mob/user) + if(!supplied.evidence || !supplied.evidence.len) + return 0 + for(var/print in supplied.evidence) + if(evidence[print]) + evidence[print] = stringmerge(evidence[print],supplied.evidence[print]) + else + evidence[print] = supplied.evidence[print] + name = "[initial(name)] (combined)" + user << "You overlay \the [src] and \the [supplied], combining the print records." + return 1 + +/obj/item/weapon/sample/attackby(var/obj/O, var/mob/user) + if(O.type == src.type) + user.unEquip(O) + if(merge_evidence(O, user)) + qdel(O) + return 1 + return ..() + +/obj/item/weapon/sample/fibers + name = "fiber bag" + desc = "Used to hold fiber evidence for the detective." + icon_state = "fiberbag" + +/obj/item/weapon/sample/print + name = "fingerprint card" + desc = "Records a set of fingerprints." + icon = 'icons/obj/card.dmi' + icon_state = "fingerprint0" + item_state = "paper" + +/obj/item/weapon/sample/print/attack_self(var/mob/user) + if(evidence && evidence.len) + return + if(!ishuman(user)) + return + var/mob/living/carbon/human/H = user + if(H.gloves) + user << "Take \the [H.gloves] off first." + return + + user << "You firmly press your fingertips onto the card." + var/fullprint = H.get_full_print() + evidence[fullprint] = fullprint + name = "[initial(name)] (\the [H])" + icon_state = "fingerprint1" + +/obj/item/weapon/sample/print/attack(var/mob/living/M, var/mob/user) + + if(!ishuman(M)) + return ..() + + if(evidence && evidence.len) + return 0 + + var/mob/living/carbon/human/H = M + + if(H.gloves) + user << "\The [H] is wearing gloves." + return 1 + + if(user != H && H.a_intent != "help" && !H.lying) + user.visible_message("\The [user] tries to take prints from \the [H], but they move away.") + return 1 + + if(user.zone_sel.selecting == "r_hand" || user.zone_sel.selecting == "l_hand") + var/has_hand + var/obj/item/organ/external/O = H.organs_by_name["r_hand"] + if(istype(O) && !O.is_stump()) + has_hand = 1 + else + O = H.organs_by_name["l_hand"] + if(istype(O) && !O.is_stump()) + has_hand = 1 + if(!has_hand) + user << "They don't have any hands." + return 1 + user.visible_message("[user] takes a copy of \the [H]'s fingerprints.") + var/fullprint = H.get_full_print() + evidence[fullprint] = fullprint + copy_evidence(src) + name = "[initial(name)] (\the [H])" + icon_state = "fingerprint1" + return 1 + return 0 + +/obj/item/weapon/sample/print/copy_evidence(var/atom/supplied) + if(supplied.fingerprints && supplied.fingerprints.len) + for(var/print in supplied.fingerprints) + evidence[print] = supplied.fingerprints[print] + supplied.fingerprints.Cut() + +/obj/item/weapon/forensics/sample_kit + name = "fiber collection kit" + desc = "A magnifying glass and tweezers. Used to lift suit fibers." + icon_state = "m_glass" + w_class = 2 + var/evidence_type = "fiber" + var/evidence_path = /obj/item/weapon/sample/fibers + +/obj/item/weapon/forensics/sample_kit/proc/can_take_sample(var/mob/user, var/atom/supplied) + return (supplied.suit_fibers && supplied.suit_fibers.len) + +/obj/item/weapon/forensics/sample_kit/proc/take_sample(var/mob/user, var/atom/supplied) + var/obj/item/weapon/sample/S = new evidence_path(get_turf(user), supplied) + user << "You transfer [S.evidence.len] [S.evidence.len > 1 ? "[evidence_type]s" : "[evidence_type]"] to \the [S]." + +/obj/item/weapon/forensics/sample_kit/afterattack(var/atom/A, var/mob/user, var/proximity) + if(!proximity) + return + add_fingerprint(user) + if(can_take_sample(user, A)) + take_sample(user,A) + return 1 + else + user << "You are unable to locate any [evidence_type]s on \the [A]." + return ..() + +/obj/item/weapon/forensics/sample_kit/powder + name = "fingerprint powder" + desc = "A jar containing aluminum powder and a specialized brush." + icon_state = "dust" + evidence_type = "fingerprint" + evidence_path = /obj/item/weapon/sample/print + +/obj/item/weapon/forensics/sample_kit/powder/can_take_sample(var/mob/user, var/atom/supplied) + return (supplied.fingerprints && supplied.fingerprints.len) diff --git a/code/modules/detectivework/tools/storage.dm b/code/modules/detectivework/tools/storage.dm new file mode 100644 index 0000000000..1555124cc9 --- /dev/null +++ b/code/modules/detectivework/tools/storage.dm @@ -0,0 +1,44 @@ +/obj/item/weapon/storage/box/swabs + name = "box of swab kits" + desc = "Sterilized equipment within. Do not contaminate." + icon = 'icons/obj/forensics.dmi' + icon_state = "dnakit" + can_hold = list(/obj/item/weapon/forensics/swab) + storage_slots = 14 + +/obj/item/weapon/storage/box/swabs/New() + ..() + for(var/i=0;i\The [H] is wearing a mask.
" + return 1 + + if(!H.dna || !H.dna.unique_enzymes) + user << "They don't seem to have DNA!" + return 1 + + if(user != H && H.a_intent != "help" && !H.lying) + user.visible_message("\The [user] tries to take a swab sample from \the [H], but they move away.") + return 1 + + if(user.zone_sel.selecting == "mouth") + if(!H.organs_by_name["head"]) + user << "They don't have a head." + return 1 + if(!H.check_has_mouth()) + user << "They don't have a mouth." + return 1 + user.visible_message("[user] swabs \the [H]'s mouth for a saliva sample.") + dna = list(H.dna.unique_enzymes) + sample_type = "DNA" + + else if(user.zone_sel.selecting == "r_hand" || user.zone_sel.selecting == "l_hand") + var/has_hand + var/obj/item/organ/external/O = H.organs_by_name["r_hand"] + if(istype(O) && !O.is_stump()) + has_hand = 1 + else + O = H.organs_by_name["l_hand"] + if(istype(O) && !O.is_stump()) + has_hand = 1 + if(!has_hand) + user << "They don't have any hands." + return 1 + user.visible_message("[user] swabs [H]'s palm for a sample.") + sample_type = "GSR" + gsr = H.gunshot_residue + else + return 0 + + if(sample_type) + used = 1 + name = "[initial(name)] ([sample_type] - [H])" + desc = "[initial(desc)] The label on the vial reads 'Sample of [sample_type] from [H].'." + icon_state = "swab_used" + return 1 + return 0 + +/obj/item/weapon/forensics/swab/afterattack(var/atom/A, var/mob/user, var/proximity) + + if(!proximity || istype(A, /obj/item/weapon/forensics/slide)) + return + + if(is_used()) + user << "This swab has already been used." + return + + add_fingerprint(user) + + var/list/choices = list() + if(A.blood_DNA) + choices |= "Blood" + if(istype(A, /obj/item/clothing)) + choices |= "Gunshot Residue" + + var/choice + if(!choices.len) + user << "There is no evidence on \the [A]." + return + else if(choices.len == 1) + choice = choices[1] + else + choice = input("What kind of evidence are you looking for?","Evidence Collection") as null|anything in choices + + if(!choice) + return + + var/sample_type + if(choice == "Blood") + if(!A.blood_DNA || !A.blood_DNA.len) return + dna = A.blood_DNA.Copy() + sample_type = "blood" + else if(choice == "Gunshot Residue") + var/obj/item/clothing/B = A + if(!istype(B) || !B.gunshot_residue) + user << "There is no residue on \the [A]." + return + gsr = B.gunshot_residue + sample_type = "residue" + + if(sample_type) + user.visible_message("\The [user] swabs \the [A] for a sample.", "You swab \the [A] for a sample.") + name = "[initial(name)] ([sample_type] - [A])" + desc = "[initial(desc)] The label on the vial reads 'Sample of [sample_type] from [A].'." + icon_state = "swab_used" + diff --git a/code/modules/detectivework/tools/uvlight.dm b/code/modules/detectivework/tools/uvlight.dm new file mode 100644 index 0000000000..b4e77c0ff2 --- /dev/null +++ b/code/modules/detectivework/tools/uvlight.dm @@ -0,0 +1,69 @@ +/obj/item/device/uv_light + name = "\improper UV light" + desc = "A small handheld black light." + icon_state = "uv_off" + slot_flags = SLOT_BELT + w_class = 2 + item_state = "electronic" + matter = list(DEFAULT_WALL_MATERIAL = 150) + origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1) + + var/list/scanned = list() + var/list/stored_alpha = list() + var/list/reset_objects = list() + + var/range = 3 + var/on = 0 + var/step_alpha = 50 + +/obj/item/device/uv_light/attack_self(var/mob/user) + on = !on + if(on) + set_light(range, 2, "#007fff") + processing_objects |= src + icon_state = "uv_on" + else + set_light(0) + clear_last_scan() + processing_objects -= src + icon_state = "uv_off" + +/obj/item/device/uv_light/proc/clear_last_scan() + if(scanned.len) + for(var/atom/O in scanned) + O.invisibility = scanned[O] + if(O.fluorescent == 2) O.fluorescent = 1 + scanned.Cut() + if(stored_alpha.len) + for(var/atom/O in stored_alpha) + O.alpha = stored_alpha[O] + if(O.fluorescent == 2) O.fluorescent = 1 + stored_alpha.Cut() + if(reset_objects.len) + for(var/obj/item/I in reset_objects) + I.overlays -= I.blood_overlay + if(I.fluorescent == 2) I.fluorescent = 1 + reset_objects.Cut() + +/obj/item/device/uv_light/process() + clear_last_scan() + if(on) + step_alpha = round(255/range) + var/turf/origin = get_turf(src) + if(!origin) + return + for(var/turf/T in range(range, origin)) + var/use_alpha = 255 - (step_alpha * get_dist(origin, T)) + for(var/atom/A in T.contents) + if(A.fluorescent == 1) + A.fluorescent = 2 //To prevent light crosstalk. + if(A.invisibility) + scanned[A] = A.invisibility + A.invisibility = 0 + stored_alpha[A] = A.alpha + A.alpha = use_alpha + if(istype(A, /obj/item)) + var/obj/item/O = A + if(O.was_bloodied && !(O.blood_overlay in O.overlays)) + O.overlays |= O.blood_overlay + reset_objects |= O \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index a12f25cfd4..fd6fd0f658 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -318,9 +318,7 @@ H.germ_level = 0 update_icons() //apply the now updated overlays to the mob - //Throwing stuff - /mob/proc/throw_item(atom/target) return diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 78129c4910..8a05673299 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1018,8 +1018,14 @@ verbs += /mob/living/carbon/human/proc/bloody_doodle return 1 //we applied blood to the item +/mob/living/carbon/human/proc/get_full_print() + if(!dna ||!dna.uni_identity) + return + return md5(dna.uni_identity) + /mob/living/carbon/human/clean_blood(var/clean_feet) .=..() + gunshot_residue = null if(clean_feet && !shoes && istype(feet_blood_DNA, /list) && feet_blood_DNA.len) feet_blood_color = null qdel(feet_blood_DNA) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 0ff79e2aa2..bde26ceb60 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -81,6 +81,7 @@ var/hand_blood_color var/list/flavor_texts = list() + var/gunshot_residue mob_bump_flag = HUMAN mob_push_flags = ~HEAVY diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm index 4c756ace0c..ebc490601d 100644 --- a/code/modules/organs/blood.dm +++ b/code/modules/organs/blood.dm @@ -316,4 +316,6 @@ proc/blood_splatter(var/target,var/datum/reagent/blood/source,var/large) if(source.data["virus2"]) B.virus2 = virus_copylist(source.data["virus2"]) + B.fluorescent = 0 + B.invisibility = 0 return B diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm index bb23b9c3ee..219ebff141 100644 --- a/code/modules/projectiles/ammunition.dm +++ b/code/modules/projectiles/ammunition.dm @@ -7,6 +7,8 @@ slot_flags = SLOT_BELT | SLOT_EARS throwforce = 1 w_class = 1 + + var/leaves_residue = 1 var/caliber = "" //Which kind of guns it can be loaded into var/projectile_type //The bullet type to create when New() is called var/obj/item/projectile/BB = null //The loaded bullet - make it so that the projectiles are created only when needed? diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm index 2f48fcaf13..d032cb3848 100644 --- a/code/modules/projectiles/guns/projectile.dm +++ b/code/modules/projectiles/guns/projectile.dm @@ -68,6 +68,16 @@ /obj/item/weapon/gun/projectile/proc/process_chambered() if (!chambered) return + // Aurora forensics port, gunpowder residue. + if(chambered.leaves_residue) + var/mob/living/carbon/human/H = loc + if(istype(H)) + if(!H.gloves) + H.gunshot_residue = chambered.caliber + else + var/obj/item/clothing/G = H.gloves + G.gunshot_residue = chambered.caliber + switch(handle_casings) if(EJECT_CASINGS) //eject casing onto ground. chambered.loc = get_turf(src) diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm index 0df72664fd..9330c8cdf5 100644 --- a/code/modules/reagents/Chemistry-Reagents.dm +++ b/code/modules/reagents/Chemistry-Reagents.dm @@ -115,10 +115,3 @@ /datum/reagent/proc/reaction_mob(var/mob/target) touch_mob(target) - -/datum/reagent/woodpulp - name = "Wood Pulp" - id = "woodpulp" - description = "A mass of wood fibers." - reagent_state = LIQUID - color = "#B97A57" diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm index b2cd248b25..18e31ddc02 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm @@ -375,19 +375,27 @@ /datum/reagent/sterilizine name = "Sterilizine" id = "sterilizine" - description = "Sterilizes wounds in preparation for surgery." + description = "Sterilizes wounds in preparation for surgery and thoroughly removes blood." reagent_state = LIQUID color = "#C8A5DC" touch_met = 5 /datum/reagent/sterilizine/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) M.germ_level -= min(removed*20, M.germ_level) + for(var/obj/item/I in M.contents) + I.was_bloodied = null + M.was_bloodied = null /datum/reagent/sterilizine/touch_obj(var/obj/O) O.germ_level -= min(volume*20, O.germ_level) + O.was_bloodied = null /datum/reagent/sterilizine/touch_turf(var/turf/T) T.germ_level -= min(volume*20, T.germ_level) + for(var/obj/item/I in T.contents) + I.was_bloodied = null + for(var/obj/effect/decal/cleanable/blood/B in T) + qdel(B) /datum/reagent/leporazine name = "Leporazine" diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm index 63cfb46235..aecbf766b9 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm @@ -278,10 +278,7 @@ touch_met = 50 /datum/reagent/space_cleaner/touch_obj(var/obj/O) - if(istype(O, /obj/effect/decal/cleanable)) - qdel(O) - else - O.clean_blood() + O.clean_blood() /datum/reagent/space_cleaner/touch_turf(var/turf/T) if(volume >= 1) @@ -382,3 +379,23 @@ id = "glue" description = "An extremely powerful bonding agent." color = "#FFFFCC" + +/datum/reagent/woodpulp + name = "Wood Pulp" + id = "woodpulp" + description = "A mass of wood fibers." + reagent_state = LIQUID + color = "#B97A57" + +/datum/reagent/luminol + name = "Luminol" + id = "luminol" + description = "A compound that interacts with blood on the molecular level." + reagent_state = LIQUID + color = "#F2F3F4" + +/datum/reagent/luminol/touch_obj(var/obj/O) + O.reveal_blood() + +/datum/reagent/luminol/touch_mob(var/mob/living/L) + L.reveal_blood() diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index f5c44ecaa6..7c19f42565 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -2051,30 +2051,10 @@ required_reagents = list("space_up" = 1, "bluecuracao" = 1, "melonliquor" = 1) result_amount = 3 -/* Removed xenoarcheology stuff -datum - chemical_reaction - lithiumsodiumtungstate //LiNa2WO4, not the easiest chem to mix - name = "Lithium Sodium Tungstate" - id = "lithiumsodiumtungstate" - result = "lithiumsodiumtungstate" - required_reagents = list("lithium" = 1, "sodium" = 2, "tungsten" = 1, "oxygen" = 4) - result_amount = 8 +/datum/chemical_reaction/luminol + name = "Luminol" + id = "luminol" + result = "luminol" + required_reagents = list("hydrogen" = 2, "carbon" = 2, "ammonia" = 2) + result_amount = 6 - density_separated_liquid - name = "Density separated sample" - id = "density_separated_sample" - result = "density_separated_sample" - secondary_results = list("chemical_waste" = 1) - required_reagents = list("ground_rock" = 1, "lithiumsodiumtungstate" = 2) - result_amount = 2 - - analysis_liquid - name = "Analysis sample" - id = "analysis_sample" - result = "analysis_sample" - secondary_results = list("chemical_waste" = 1) - required_reagents = list("density_separated_sample" = 5) - result_amount = 4 - requires_heating = 1 -*/ diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 15059ee327..efc8d9c2b8 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -55,7 +55,7 @@ /obj/item/weapon/reagent_containers/spray/proc/Spray_at(atom/A as mob|obj, mob/user as mob, proximity) if (A.density && proximity) - A.visible_message("[usr] sprays [A] with [src].") + A.visible_message("[usr] sprays [A] with [src].") reagents.splash(A, amount_per_transfer_from_this) else spawn(0) @@ -107,6 +107,14 @@ ..() reagents.add_reagent("cleaner", volume) +/obj/item/weapon/reagent_containers/spray/sterilizine + name = "sterilizine" + desc = "Great for hiding incriminating bloodstains and sterilizing scalpels." + +/obj/item/weapon/reagent_containers/spray/sterilizine/New() + ..() + reagents.add_reagent("sterilizine", volume) + /obj/item/weapon/reagent_containers/spray/pepper name = "pepperspray" desc = "Manufactured by UhangInc, used to blind and down an opponent quickly." @@ -161,12 +169,12 @@ volume = 600 origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 3, TECH_ENGINEERING = 3) -/obj/item/weapon/reagent_containers/spray/chemsprayer/Spray_at(atom/A as mob|obj) +/obj/item/weapon/reagent_containers/spray/chemsprayer/Spray_at(atom/A as mob|obj) var/direction = get_dir(src, A) var/turf/T = get_turf(A) var/turf/T1 = get_step(T,turn(direction, 90)) - var/turf/T2 = get_step(T,turn(direction, -90)) - var/list/the_targets = list(T, T1, T2) + var/turf/T2 = get_step(T,turn(direction, -90)) + var/list/the_targets = list(T, T1, T2) for(var/a = 1 to 3) spawn(0) diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index c8d94e2dcba70aca82e97d88dd03b541a22f388a..dfade93ae945b8bd0c46f34ab96e30e18cc1819f 100644 GIT binary patch literal 23892 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 KCRLX`;{OlWCN@+6 literal 25377 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