Simplified Detective.

-Changed the focus from the high-res scanner to the regular scanner. It will simply scan the fingerprints and display them to the detective. For extra functionality, it'll store it's findings in a log and then you can print it out in a report by using attack_self().

-Detectives can now use the medical computer.
-Removed the pda forensic scanning functionality.
-Got rid of now useless high-res scanner computer. Got rid of the now useless fingerprint cards.
-Added a medical computer to the detective's office and replaced the useless medical cabinet with an empty one.

Other

-Got rid of diseases magically moving down a stage.
-Optimized playsound()
-Added an attack_self() to sprayers so that you can change the reagent use of them between 5 and 10.




git-svn-id: http://tgstation13.googlecode.com/svn/trunk@5168 316c924e-a436-60f5-8080-3fe189b3f50e
This commit is contained in:
giacomand@gmail.com
2012-11-23 00:39:18 +00:00
parent 65a2126d9f
commit f1d24f27f9
20 changed files with 197 additions and 1205 deletions

View File

@@ -46,583 +46,4 @@ atom/proc/add_fibers(mob/living/carbon/human/M)
if(prob(20*item_multiplier) && !(fibertext in suit_fibers))
//world.log << "Added fibertext: [fibertext]"
suit_fibers += "Material from a pair of [M.gloves.name]."
if(!suit_fibers.len) del suit_fibers
var/const/FINGERPRINT_COMPLETE = 6 //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)
obj/machinery/computer/forensic_scanning
name = "\improper High-Res Forensic Scanning Computer"
icon_state = "forensic"
var/obj/item/scanning
var/temp = ""
var/canclear = 1
var/authenticated = 0
//Here's the structure for files: each entry is a list, and entry one in that list is the string of their
//full and scrambled fingerprint. This acts as the method to arrange evidence. Each subsequent entry is list
//in the form (from entries):
// 1: Object
// 2: All prints on the object
// 3: All fibers on the object
// 4: All blood on the object
//This is then used to show what objects were used to "find" the full print, as well as the fibers on it.
var/list/files
//This holds objects (1) without prints, and their fibers(2) and blood(3).
var/list/misc
var/obj/item/weapon/f_card/card
var/scan_data = ""
var/scan_name = ""
var/scan_process = 0
req_access = list(access_forensics_lockers)
New()
..()
new /obj/item/weapon/book/manual/detective(get_turf(src))
return
attack_ai(mob/user)
return attack_hand(user)
attack_hand(mob/user)
if(..())
return
user.set_machine(src)
var/dat = ""
var/isai = 0
if(istype(usr,/mob/living/silicon))
isai = 1
if(temp)
dat += "<tt>[temp]</tt><br><br>"
if(canclear) dat += "<a href='?src=\ref[src];operation=clear'>{Clear Screen}</a>"
else
if(!authenticated)
dat += "<a href='?src=\ref[src];operation=login'>{Log In}</a>"
else
dat += "<a href='?src=\ref[src];operation=logout'>{Log Out}</a><br><hr><br>"
if(scanning)
if(scan_process)
dat += "Scan Object: {[scanning.name]}<br>"
dat += "<a href='?src=\ref[src];operation=cancel'>{Cancel Scan}</a> {Print}<br>"
else
if(isai) dat += "Scan Object: {[scanning.name]}<br>"
else dat += "Scan Object: <a href='?src=\ref[src];operation=eject'>{[scanning.name]}</a><br>"
dat += "<a href='?src=\ref[src];operation=scan'>{Scan}</a> <a href='?src=\ref[src];operation=print'>{Print}</a><br>"
else
if(isai) dat += "{No Object Inserted}<br>"
else dat += "<a href='?src=\ref[src];operation=insert'>{No Object Inserted}</a><br>"
dat += "{Scan} <a href='?src=\ref[src];operation=print'>{Print}</a><br>"
dat += "<a href='?src=\ref[src];operation=database'>{Access Database}</a><br><br>"
dat += "<tt>[scan_data]</tt>"
if(scan_data && !scan_process)
dat += "<br><a href='?src=\ref[src];operation=erase'>{Erase Data}</a>"
user << browse(dat,"window=scanner")
onclose(user,"scanner")
Topic(href,href_list)
switch(href_list["operation"])
if("login")
var/mob/M = usr
if(istype(M,/mob/living/silicon))
authenticated = 1
updateDialog()
return
if (allowed(M))
authenticated = 1
if("logout")
authenticated = 0
if("clear")
if(canclear)
temp = null
if("eject")
if(scanning)
scanning.loc = loc
scanning = null
else
temp = "Eject Failed: No Object"
if("insert")
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 = null
I.w_class = 1
I.icon_state = "evidenceobj"
I.desc = "An empty evidence bag."
else
scanning = I
M.drop_item()
I.loc = src
else
usr << "Invalid Object Rejected."
if("card") //Processing a fingerprint card.
var/mob/M = usr
var/obj/item/I = M.get_active_hand()
if(!(I && istype(I,/obj/item/weapon/f_card)))
I = card
if(I && istype(I,/obj/item/weapon/f_card))
card = I
if(!card.fingerprints)
card.fingerprints = list()
if(card.amount > 1 || !card.fingerprints.len)
usr << "\red ERROR: No prints/too many cards."
if(card.loc == src)
card.loc = src.loc
card = null
return
M.drop_item()
I.loc = src
process_card()
else
usr << "\red Invalid Object Rejected."
if("database") //Viewing all records in each database
canclear = 1
if(href_list["delete_record"])
delete_dossier(href_list["delete_record"])
if(href_list["delete_aux"])
delete_record(href_list["delete_aux"])
if((!misc || !misc.len) && (!files || !files.len))
temp = "Database is empty."
else
if(files && files.len)
temp = "<b>Criminal Evidence Database</b><br><br>"
temp += "Consolidated data points:<br>"
for(var/print in files)
var/list/file = files[print]
temp += "<a href='?src=\ref[src];operation=record;identifier=[print]'>{[file[2]]}</a><br>"
temp += "<br><a href='?src=\ref[src];operation=card'>{Insert Finger Print Card (To complete a Dossier)}</a><br><br><br>"
else
temp = ""
if(misc && misc.len)
temp += "<b>Auxiliary Evidence Database</b><br><br>"
temp += "This is where anything without fingerprints goes.<br><br>"
for(var/atom in misc)
var/list/data_entry = misc[atom]
temp += "<a href='?src=\ref[src];operation=auxiliary;identifier=[atom]'>{[data_entry[3]]}</a><br>"
if("record") //Viewing a record from the "files" database.
canclear = 0
if(files)
var/list/dossier = files[href_list["identifier"]]
if(href_list["ren"])
var/new_title = copytext(sanitize(input("Rename to what?", "Dossier Editing", "Dossier [files.Find(href_list["identifier"])]") as null|text),1,MAX_MESSAGE_LEN)
if(new_title)
dossier[2] = new_title
else
usr << "Illegal or blank name."
temp = "<b>Criminal Evidence Database</b><br><br>"
temp += "Consolidated data points: [dossier[2]]<br>"
var/print_string = "Fingerprints: Print not complete!<br>"
if(stringpercent(dossier[1]) <= FINGERPRINT_COMPLETE)
print_string = "Fingerprints: (80% or higher completion reached)<br>[dossier[1]]<br>"
temp += print_string
for(var/object in dossier)
if(object == dossier[1] || object == dossier[2])
continue
temp += "<hr>"
var/list/outputs = dossier[object]
var/list/prints = outputs[1]
temp += "<big><b>Object:</b> [outputs[4]]</big><br>"
temp += "&nbsp<b>Fingerprints:</b><br>"
temp += "&nbsp;&nbsp;&nbsp;&nbsp;[prints.len] Unique fingerprints found.<br>"
var/complete_prints = 0
for(var/print in prints)
if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE)
complete_prints++
temp += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[prints[print]]<br>"
if(complete_prints)
temp += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;And [prints.len - complete_prints] unknown unique prints.<br>"
else
temp += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;No prints of sufficient completeness.<br>"
var/list/fibers = outputs[2]
if(fibers && fibers.len)
temp += "&nbsp<b>Fibers:</b><br>"
for(var/j = 1, j <= fibers.len, j++)
temp += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[fibers[j]]<br>"
var/list/blood = outputs[3]
if(blood && blood.len)
temp += "&nbsp<b>Blood:</b><br>"
for(var/named in blood)
temp += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Type: [blood[named]], DNA: [named]<br>"
temp += "<br><a href='?src=\ref[src];operation=record;identifier=[href_list["identifier"]];ren=true'>{Rename this Dossier}</a>"
temp += "<br><a href='?src=\ref[src];operation=database;delete_record=[href_list["identifier"]]'>{Delete this Dossier}</a>"
temp += "<br><a href='?src=\ref[src];operation=databaseprint;identifier=[href_list["identifier"]]'>{Print}</a>"
else
temp = "ERROR. Database not found!<br>"
temp += "<br><a href='?src=\ref[src];operation=database'>{Return}</a>"
if("databaseprint") //Printing from the "files" database.
if(files)
var/obj/item/weapon/paper/P = new(loc)
P.name = "\improper Database File (Dossier [files.Find(href_list["identifier"])])"
P.overlays += "paper_words"
P.info = "<b>Criminal Evidence Database</b><br><br>"
var/list/dossier = files[href_list["identifier"]]
P.info += "Consolidated data points: [dossier[2]]<br>"
var/print_string = "Fingerprints: Print not complete!<br>"
if(stringpercent(dossier[1]) <= FINGERPRINT_COMPLETE)
print_string = "Fingerprints: (80% or higher completion reached)<br>[dossier[1]]<br>"
P.info += print_string
for(var/object in dossier)
if(object == dossier[1] || object == dossier[2])
continue
P.info += "<hr>"
var/list/outputs = dossier[object]
var/list/prints = outputs[1]
P.info += "<big><b>Object:</b> [outputs[4]]</big><br>"
P.info += "&nbsp<b>Fingerprints:</b><br>"
P.info += "&nbsp;&nbsp;&nbsp;&nbsp;[prints.len] Unique fingerprints found.<br>"
var/complete_prints = 0
for(var/print in prints)
if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE)
complete_prints++
P.info += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[prints[print]]<br>"
if(complete_prints)
P.info += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;And [prints.len - complete_prints] unknown unique prints.<br>"
else
P.info += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;No prints of sufficient completeness.<br>"
var/list/fibers = outputs[2]
if(fibers && fibers.len)
P.info += "&nbsp<b>Fibers:</b><br>"
for(var/j = 1, j <= fibers.len, j++)
P.info += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[fibers[j]]<br>"
var/list/blood = outputs[3]
if(blood && blood.len)
P.info += "&nbsp<b>Blood:</b><br>"
for(var/named in blood)
P.info += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Type: [blood[named]], DNA: [named]<br>"
else
usr << "ERROR. Database not found!<br>"
if("auxiliary") //Viewing a record from the "misc" database.
canclear = 0
if(misc)
temp = "<b>Auxiliary Evidence Database</b><br><br>"
var/list/outputs = misc[href_list["identifier"]]
temp += "<big><b>Consolidated data points:</b> [outputs[3]]</big><br>"
var/list/prints = outputs[4]
if(prints)
temp += "&nbsp<b>Fingerprints:</b><br>"
temp += "&nbsp;&nbsp;&nbsp;&nbsp;[prints.len] Unique fingerprints found.<br>"
var/complete_prints = 0
for(var/print in prints)
if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE)
complete_prints++
temp += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[prints[print]]<br>"
if(complete_prints)
temp += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;And [prints.len - complete_prints] unknown unique prints.<br>"
else
temp += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;No prints of sufficient completeness.<br>"
var/list/fibers = outputs[1]
if(fibers && fibers.len)
temp += "&nbsp<b>Fibers:</b><br>"
for(var/fiber in fibers)
temp += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[fiber]<br>"
var/list/blood = outputs[2]
if(blood && blood.len)
temp += "&nbsp<b>Blood:</b><br>"
for(var/named in blood)
temp += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Type: [blood[named]], DNA: [named]<br>"
temp += "<br><a href='?src=\ref[src];operation=database;delete_aux=[href_list["identifier"]]'>{Delete This Record}</a>"
temp += "<br><a href='?src=\ref[src];operation=auxiliaryprint;identifier=[href_list["identifier"]]'>{Print}</a>"
else
temp = "ERROR. Database not found!<br>"
temp += "<br><a href='?src=\ref[src];operation=database'>{Return}</a>"
if("auxiliaryprint") //Printing from the "misc" database.
if(misc)
var/obj/item/weapon/paper/P = new(loc)
var/list/outputs = misc[href_list["identifier"]]
P.name = "\improper Auxiliary Database File ([outputs[3]])"
P.overlays += "paper_words"
P.info = "<b>Auxiliary Evidence Database</b><br><br>"
P.info += "<big><b>Consolidated data points:</b> [outputs[3]]</big><br>"
var/list/prints = outputs[4]
if(prints)
P.info += "&nbsp<b>Fingerprints:</b><br>"
P.info += "&nbsp;&nbsp;&nbsp;&nbsp;[prints.len] Unique fingerprints found.<br>"
var/complete_prints = 0
for(var/print in prints)
if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE)
complete_prints++
P.info += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[prints[print]]<br>"
if(complete_prints)
P.info += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;And [prints.len - complete_prints] unknown unique prints.<br>"
else
P.info += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;No prints of sufficient completeness.<br>"
var/list/fibers = outputs[1]
if(fibers && fibers.len)
P.info += "&nbsp<b>Fibers:</b><br>"
for(var/fiber in fibers)
P.info += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[fiber]<br>"
var/list/blood = outputs[2]
if(blood && blood.len)
P.info += "&nbsp<b>Blood:</b><br>"
for(var/named in blood)
P.info += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Type: [blood[named]], DNA: [named]<br>"
else
usr << "ERROR. Database not found!<br>"
if("scan")
if(istype(scanning,/obj/item/weapon/f_card))
card = scanning
scanning = initial(scanning)
process_card()
else if(scanning)
scan_process = 3
scan_data = "Scanning [scanning]: 25% complete"
updateDialog()
sleep(50)
if(!scan_process)
scan_data = null
updateDialog()
return
scan_data = "Scanning [scanning]: 50% complete"
updateDialog()
scan_process = 2
sleep(50)
if(!scan_process)
scan_data = null
updateDialog()
return
scan_data = "Scanning [scanning]: 75% complete"
updateDialog()
scan_process = 1
sleep(50)
if(!scan_process)
scan_data = null
updateDialog()
return
if(scanning)
scan_process = 0
scan_name = scanning.name
scan_data = "<u>[scanning]</u><br><br>"
if (scanning.blood_DNA)
scan_data += "Blood Found:<br>"
for(var/blood in scanning.blood_DNA)
scan_data += "Blood type: [scanning.blood_DNA[blood]]\nDNA: [blood]<br><br>"
else
scan_data += "No Blood Found<br><br>"
if(!scanning.fingerprints)
scan_data += "No Fingerprints Found<br><br>"
else
scan_data += "Isolated [scanning.fingerprints.len] Fingerprints. Loaded into database.<br>"
add_data(scanning)
if(!scanning.suit_fibers)
scan_data += "No Fibers/Materials Located<br>"
else
scan_data += "Fibers/Materials Found:<br>"
for(var/data in scanning.suit_fibers)
scan_data += "- [data]<br>"
if(istype(scanning,/obj/item/device/detective_scanner) || (istype(scanning, /obj/item/device/pda) && scanning:cartridge && scanning:cartridge.access_security))
scan_data += "<br><b>Data transfered from \the [scanning] to Database.</b><br>"
add_data_scanner(scanning)
else if(!scanning.fingerprints)
scan_data += "<br><b><a href='?src=\ref[src];operation=add'>Add to Database?</a></b><br>"
else
temp = "Scan Failed: No Object"
if("print") //Printing scan data
if(scan_data)
temp = "Scan Data Printed."
var/obj/item/weapon/paper/P = new(loc)
P.name = "\improper Scan Data ([scan_name])"
P.info = "<tt>[scan_data]</tt>"
P.overlays += "paper_words"
else
temp = "Print Failed: No Data"
if("erase")
scan_data = ""
if("cancel")
scan_process = 0
if("add") //Adding an object (Manually) to the database.
if(scanning)
add_data(scanning)
else
temp = "Data Transfer Failed: No Object."
if("rename")
if(!files || !files[href_list["identifier"]])
temp = "ERROR: Record/Database not found!"
else
var/new_title = copytext(sanitize(input("Rename to what?", "Dossier Editing", "Dossier [files.Find(href_list["identifier"])]") as null|text),1,MAX_MESSAGE_LEN)
if(new_title)
var/list/file = files[href_list["identifier"]]
file[2] = new_title
updateUsrDialog()
ex_act()
return
proc/add_data_scanner(var/obj/item/device/W)
if(istype(W, /obj/item/device/detective_scanner))
if(W:stored)
for(var/atom in W:stored)
var/list/data = W:stored[atom]
add_data_master(atom,data[1],data[2],data[3],data[4])
W:stored = list()
else if(istype(W, /obj/item/device/pda) && W:cartridge && W:cartridge.access_security)
if(W:cartridge.stored_data)
for(var/atom in W:cartridge.stored_data)
var/list/data = W:cartridge.stored_data[atom]
add_data_master(atom,data[1],data[2],data[3],data[4])
W:cartridge.stored_data = list()
return
proc/add_data(var/atom/scanned_atom)
return add_data_master("\ref [scanned_atom]", scanned_atom.fingerprints,\
scanned_atom.suit_fibers, scanned_atom.blood_DNA, "[scanned_atom.name] (Direct Scan)")
/********************************
*****DO NOT DIRECTLY CALL ME*****
********************************/
proc/add_data_master(var/atom_reference, var/list/atom_fingerprints, var/list/atom_suit_fibers, var/list/atom_blood_DNA, var/atom_name)
//What follows is massive. It cross references all stored data in the scanner with the other stored data,
//and what is already in the computer. Not sure how bad the lag may/may not be.
if(!misc)
misc = list()
var/list/data_entry = misc[atom_reference]
if(data_entry)
var/list/fibers = data_entry[1]
if(!fibers)
fibers = list()
if(atom_suit_fibers)
for(var/fiber in atom_suit_fibers) //Fibers~~~
if(!fibers.Find(fiber)) //It isn't! Add!
fibers += fiber
var/list/blood = data_entry[2]
if(!blood)
blood = list()
if(atom_blood_DNA)
for(var/main_blood in atom_blood_DNA)
if(!blood[main_blood])
blood[main_blood] = atom_blood_DNA[blood]
var/list/prints = data_entry[4]
if(!prints && atom_fingerprints)
prints = list()
if(atom_fingerprints)
for(var/print in atom_fingerprints)
if(!prints[print])
prints[print] = atom_fingerprints[print]
else
var/list/templist[4]
templist[1] = atom_suit_fibers
templist[2] = atom_blood_DNA
templist[3] = atom_name
templist[4] = atom_fingerprints
misc[atom_reference] = templist //Store it!
//Has prints.
if(atom_fingerprints)
if(!files)
files = list()
for(var/main_print in atom_fingerprints)
data_entry = files[main_print]
if(data_entry)//The print is already in here!
var/list/internal_atom = data_entry[atom_reference] //Lets see if we can find the current object
if(internal_atom)
//We must be on a roll! Just update what needs to be updated.
var/list/internal_prints = internal_atom[1]
for(var/print in atom_fingerprints) //Sorry for the double loop! D:
var/associated_print = internal_prints[print]
var/reference_print = atom_fingerprints[print]
if(associated_print && associated_print != reference_print) //It does not match
internal_prints[print] = stringmerge(associated_print, reference_print)
else if(!associated_print)
internal_prints[print] = reference_print
//If the main print was updated, lets update the master as well.
if(print == main_print && (!associated_print || (associated_print && associated_print != reference_print)))
update_fingerprints(main_print, internal_prints[print])
//Fibers.
var/list/fibers = internal_atom[2]
if(!fibers)
fibers = list()
if(atom_suit_fibers)
for(var/fiber in atom_suit_fibers) //Fibers~~~
if(!fibers.Find(fiber)) //It isn't! Add!
fibers += fiber
//Blood.
var/list/blood = internal_atom[3]
if(!blood)
blood = list()
if(atom_blood_DNA)
for(var/main_blood in atom_blood_DNA)
if(!blood[main_blood])
blood[main_blood] = atom_blood_DNA[blood]
continue
//It's not in there! We gotta add it.
update_fingerprints(main_print, atom_fingerprints[main_print])
var/list/data_point[4]
data_point[1] = atom_fingerprints
data_point[2] = atom_suit_fibers
data_point[3] = atom_blood_DNA
data_point[4] = atom_name
data_entry[atom_reference] = data_point
continue
//No print at all! New data entry, go!
var/list/data_point[4]
data_point[1] = atom_fingerprints
data_point[2] = atom_suit_fibers
data_point[3] = atom_blood_DNA
data_point[4] = atom_name
var/list/new_file[2]
new_file[1] = atom_fingerprints[main_print]
new_file[2] = "Dossier [files.len + 1]"
new_file[atom_reference] = data_point
files[main_print] = new_file
return 1
/********************************
***END DO NOT DIRECTLY CALL ME***
********************************/
proc/update_fingerprints(var/ref_print, var/new_print)
var/list/master = files[ref_print]
if(master)
master[1] = stringmerge(master[1],new_print)
else
CRASH("Fucking hell. Something went wrong, and it tried to update a null print or something. Tell SkyMarshal (and give him this call stack)")
return
proc/process_card() //Same as above, but for fingerprint cards
if(card.fingerprints && !(card.amount > 1) && islist(card.fingerprints) && files && files.len)
usr << "You insert the card, and it is destroyed by the machinery in the process of comparing prints."
var/found = 0
for(var/master_print in card.fingerprints)
var/list/data_entry = files[master_print]
if(data_entry)
found = 1
data_entry[1] = master_print
if(found)
usr << "The machinery finds it can complete a match."
else
usr << "No match found."
del(card)
else
usr << "\red ERROR: No prints/too many cards."
if(card.loc == src)
card.loc = src.loc
card = null
return
return
proc/delete_record(var/atom_ref) //Deletes an entry in the misc database at the given location
if(misc && misc.len)
misc.Remove(atom_ref)
return
proc/delete_dossier(var/print) //Deletes a Dossier at a given location.
if(files && files.len)
files.Remove(print)
return
detective
icon_state = "old"
name = "PowerScan Mk.I"
if(!suit_fibers.len) del suit_fibers

View File

@@ -89,6 +89,5 @@
new /obj/item/weapon/evidencebag(src)
new /obj/item/weapon/evidencebag(src)
new /obj/item/weapon/evidencebag(src)
new /obj/item/weapon/f_card(src)
..()
return

View File

@@ -1,158 +1,25 @@
/*
obj/item/clothing/shoes/var
track_blood = 0
mob/living/carbon/human/track_blood_mob
track_blood_type*/
mob/var
bloody_hands = 0
mob/living/carbon/human/bloody_hands_mob
track_blood
mob/living/carbon/human/track_blood_mob
track_blood_type
obj/item/clothing/gloves/var
transfer_blood = 0
mob/living/carbon/human/bloody_hands_mob
/*
obj/effect/decal/cleanable/var
track_amt = 3
mob/blood_owner
/mob
turf/Exited(mob/living/carbon/human/M)
if(istype(M,/mob/living) && !istype(M,/mob/living/carbon/metroid))
if(!istype(src, /turf/space)) // Bloody tracks code starts here
var/dofoot = 1
if(istype(M,/mob/living/simple_animal))
if(!(istype(M,/mob/living/simple_animal/cat) || istype(M,/mob/living/simple_animal/corgi) || istype(M,/mob/living/simple_animal/constructwraith)))
dofoot = 0
var/bloody_hands = 0
var/mob/living/carbon/human/bloody_hands_mob
var/track_blood
var/mob/living/carbon/human/track_blood_mob
var/track_blood_type
if(dofoot)
if(!istype(src, /turf/space)) // Bloody tracks code starts here
if(M.track_blood > 0)
M.track_blood--
src.add_bloody_footprints(M.track_blood_mob,1,M.dir,get_tracks(M),M.track_blood_type)
else if(istype(M,/mob/living/carbon/human))
if(M.shoes && istype(M.shoes,/obj/item/clothing/shoes))
var/obj/item/clothing/shoes/S = M.shoes
if(S.track_blood > 0)
S.track_blood--
src.add_bloody_footprints(S.track_blood_mob,1,M.dir,S.name,S.track_blood_type) // And bloody tracks end here
. = ..()
turf/Entered(mob/living/carbon/human/M)
if(istype(M,/mob/living) && !istype(M,/mob/living/carbon/metroid))
var/dofoot = 1
if(istype(M,/mob/living/simple_animal))
if(!(istype(M,/mob/living/simple_animal/cat) || istype(M,/mob/living/simple_animal/corgi) || istype(M,/mob/living/simple_animal/constructwraith)))
dofoot = 0
if(dofoot)
if(M.track_blood > 0)
M.track_blood--
src.add_bloody_footprints(M.track_blood_mob,0,M.dir,get_tracks(M),M.track_blood_type)
else if(istype(M,/mob/living/carbon/human))
if(M.shoes && istype(M.shoes,/obj/item/clothing/shoes) && !istype(src,/turf/space))
var/obj/item/clothing/shoes/S = M.shoes
if(S.track_blood > 0)
S.track_blood--
src.add_bloody_footprints(S.track_blood_mob,0,M.dir,S.name,S.track_blood_type)
/obj/item/clothing/gloves
var/transfer_blood = 0
var/mob/living/carbon/human/bloody_hands_mob
for(var/obj/effect/decal/cleanable/B in src)
if(B:track_amt <= 0) continue
if(B.type != /obj/effect/decal/cleanable/blood/tracks)
if(istype(B, /obj/effect/decal/cleanable/xenoblood) || istype(B, /obj/effect/decal/cleanable/blood) || istype(B, /obj/effect/decal/cleanable/oil) || istype(B, /obj/effect/decal/cleanable/robot_debris))
var/track_type = "blood"
if(istype(B, /obj/effect/decal/cleanable/xenoblood))
track_type = "xeno"
else if(istype(B, /obj/effect/decal/cleanable/oil) || istype(B, /obj/effect/decal/cleanable/robot_debris))
track_type = "oil"
/proc/blood_incompatible(donor,receiver)
if(istype(M,/mob/living/carbon/human))
if(M.shoes && istype(M.shoes,/obj/item/clothing/shoes))
var/obj/item/clothing/shoes/S = M.shoes
S.add_blood(B.blood_owner)
S.track_blood_mob = B.blood_owner
S.track_blood = max(S.track_blood,8)
S.track_blood_type = track_type
else
M.add_blood(B.blood_owner)
M.track_blood_mob = B.blood_owner
M.track_blood = max(M.track_blood,rand(4,8))
M.track_blood_type = track_type
B.track_amt--
break
. = ..()
var/donor_antigen = copytext(donor,1,lentext(donor))
var/receiver_antigen = copytext(receiver,1,lentext(receiver))
var/donor_rh = findtext("+",donor)
var/receiver_rh = findtext("+",receiver)
turf/proc/add_bloody_footprints(mob/living/carbon/human/M,leaving,d,info,bloodcolor)
for(var/obj/effect/decal/cleanable/blood/tracks/T in src)
if(T.dir == d && findtext(T.icon_state, bloodcolor))
if((leaving && T.icon_state == "steps2") || (!leaving && T.icon_state == "steps1"))
T.desc = "These bloody footprints appear to have been made by [info]."
if(!T.blood_DNA)
T.blood_DNA = list()
if(istype(M,/mob/living/carbon/human))
T.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type
else if(istype(M,/mob/living/carbon/alien))
T.blood_DNA["UNKNOWN DNA"] = "X*"
else if(istype(M,/mob/living/carbon/monkey))
T.blood_DNA["Non-human DNA"] = "A+"
return
var/obj/effect/decal/cleanable/blood/tracks/this = new(src)
this.icon = 'icons/effects/footprints.dmi'
var/preiconstate = ""
if(info == "animal paws")
preiconstate = "paw"
else if(info == "alien claws")
preiconstate = "claw"
else if(info == "small alien feet")
preiconstate = "paw"
if(leaving)
this.icon_state = "[bloodcolor][preiconstate]2"
else
this.icon_state = "[bloodcolor][preiconstate]1"
this.dir = d
if(bloodcolor == "blood")
this.desc = "These bloody footprints appear to have been made by [info]."
else if(bloodcolor == "xeno")
this.desc = "These acidic bloody footprints appear to have been made by [info]."
else if(bloodcolor == "oil")
this.name = "oil"
this.desc = "These oil footprints appear to have been made by [info]."
if(istype(M,/mob/living/carbon/human))
if(!this.blood_DNA)
this.blood_DNA = list()
this.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type
proc/get_tracks(mob/M)
if(istype(M,/mob/living))
if(istype(M,/mob/living/carbon/human))
. = "human feet"
else if(istype(M,/mob/living/carbon/monkey) || istype(M,/mob/living/simple_animal/cat) || istype(M,/mob/living/simple_animal/corgi) || istype(M,/mob/living/simple_animal/crab))
. = "animal paws"
else if(istype(M,/mob/living/silicon/robot))
. = "robot feet"
else if(istype(M,/mob/living/carbon/alien/humanoid))
. = "alien claws"
else if(istype(M,/mob/living/carbon/alien/larva))
. = "small alien feet"
else
. = "an unknown creature"*/
proc/blood_incompatible(donor,receiver)
var
donor_antigen = copytext(donor,1,lentext(donor))
receiver_antigen = copytext(receiver,1,lentext(receiver))
donor_rh = findtext("+",donor)
receiver_rh = findtext("+",receiver)
if(donor_rh && !receiver_rh) return 1
switch(receiver_antigen)
if("A")
@@ -164,6 +31,7 @@ proc/blood_incompatible(donor,receiver)
//AB is a universal receiver.
return 0
/obj/item/weapon/reagent_containers/glass/rag
name = "damp rag"
desc = "For cleaning up messes, you suppose."
@@ -175,26 +43,26 @@ proc/blood_incompatible(donor,receiver)
volume = 5
can_be_placed_into = null
attack(atom/target as obj|turf|area, mob/user as mob , flag)
if(ismob(target) && target.reagents && reagents.total_volume)
user.visible_message("\red \The [target] has been smothered with \the [src] by \the [user]!", "\red You smother \the [target] with \the [src]!", "You hear some struggling and muffled cries of surprise")
src.reagents.reaction(target, TOUCH)
spawn(5) src.reagents.clear_reagents()
return
else
..()
afterattack(atom/A as obj|turf|area, mob/user as mob)
if(istype(A) && src in user)
user.visible_message("[user] starts to wipe down [A] with [src]!")
if(do_after(user,30))
user.visible_message("[user] finishes wiping off the [A]!")
A.clean_blood()
/obj/item/weapon/reagent_containers/glass/rag/attack(atom/target as obj|turf|area, mob/user as mob , flag)
if(ismob(target) && target.reagents && reagents.total_volume)
user.visible_message("\red \The [target] has been smothered with \the [src] by \the [user]!", "\red You smother \the [target] with \the [src]!", "You hear some struggling and muffled cries of surprise")
src.reagents.reaction(target, TOUCH)
spawn(5) src.reagents.clear_reagents()
return
else
..()
examine()
if (!usr)
return
usr << "That's \a [src]."
usr << desc
return
/obj/item/weapon/reagent_containers/glass/rag/afterattack(atom/A as obj|turf|area, mob/user as mob)
if(istype(A) && src in user)
user.visible_message("[user] starts to wipe down [A] with [src]!")
if(do_after(user,30))
user.visible_message("[user] finishes wiping off the [A]!")
A.clean_blood()
return
/obj/item/weapon/reagent_containers/glass/rag/examine()
if (!usr)
return
usr << "That's \a [src]."
usr << desc
return

View File

@@ -1,172 +1,130 @@
//CONTAINS: Detective's Scanner
/obj/item/device/detective_scanner
name = "Scanner"
desc = "Used to scan objects for DNA and fingerprints."
desc = "Used to scan objects for DNA and fingerprints. Can print a report of the findings."
icon_state = "forensic1"
var/amount = 20.0
var/list/stored = list()
w_class = 3.0
item_state = "electronic"
flags = FPRINT | TABLEPASS | CONDUCT | USEDELAY
slot_flags = SLOT_BELT
var/scanning = 0
var/list/log = list()
attackby(obj/item/weapon/f_card/W as obj, mob/user as mob)
..()
if (istype(W, /obj/item/weapon/f_card))
if (W.fingerprints)
return
if (src.amount == 20)
return
if (W.amount + src.amount > 20)
src.amount = 20
W.amount = W.amount + src.amount - 20
/obj/item/device/detective_scanner/attack_self(var/mob/user)
if(log.len && !scanning)
scanning = 1
user << "<span class='notice'>Printing report, please wait...</span>"
spawn(100)
var/obj/item/weapon/paper/P = new(get_turf(src))
P.info = "<center><font size='4'>Scanner Report</font></center><HR><BR>"
P.info += dd_list2text(log, "<BR>")
P.info_links = P.info
user.put_in_hands(P)
log = list()
scanning = 0
if(user)
user << "<span class='notice'>Report printed. Log cleared.<span>"
else
user << "<span class='notice'>The scanner has no logs or is in use.</span>"
/obj/item/device/detective_scanner/attack(mob/living/carbon/human/M as mob, mob/user as mob)
if(!scanning)
scanning = 1
spawn(0)
add_log(user, "<font color='blue'>Scanning [M]...</font>")
if (!ishuman(M))
add_log(user, "<span class='warning'>[M] is not human and cannot have the fingerprints.</span>")
else
src.amount += W.amount
//W = null
del(W)
add_fingerprint(user)
if (W)
W.add_fingerprint(user)
return
if (( !( istype(M.dna, /datum/dna) ) || M.gloves) )
add_log(user, "<span class='info'>No fingerprints found on [M]</span>")
else
add_log(user, "<span class='info'>Fingerprints found on [M]. Analysing...</span>")
sleep(30)
add_log(user, "<span class='info'>[M]'s Fingerprints: [md5(M.dna.uni_identity)]</span>")
attack(mob/living/carbon/human/M as mob, mob/user as mob)
if (!ishuman(M))
user << "\red [M] is not human and cannot have the fingerprints."
return 0
if (( !( istype(M.dna, /datum/dna) ) || M.gloves) )
user << "\blue No fingerprints found on [M]"
return 0
else
if (src.amount < 1)
user << text("\blue Fingerprints scanned on [M]. Need more cards to print.")
if ( !M.blood_DNA || !M.blood_DNA.len )
add_log(user, "<span class='info'>No blood found on [M]</span>")
if(M.blood_DNA)
del(M.blood_DNA)
else
src.amount--
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 << "\blue Done printing."
user << "\blue [M]'s Fingerprints: [md5(M.dna.uni_identity)]"
if ( !M.blood_DNA || !M.blood_DNA.len )
user << "\blue No blood found on [M]"
if(M.blood_DNA)
del(M.blood_DNA)
else
user << "\blue Blood found on [M]. Analysing..."
spawn(15)
add_log(user, "<span class='info'>Blood found on [M]. Analysing...</span>")
sleep(30)
for(var/blood in M.blood_DNA)
user << "\blue Blood type: [M.blood_DNA[blood]]\nDNA: [blood]"
add_log(user, "<span class='info'>Blood type: [M.blood_DNA[blood]]\nDNA: [blood]</span>")
add_log(null, "<font color='blue'>Ending scan report.</font>")
scanning = 0
return
/obj/item/device/detective_scanner/afterattack(atom/A as obj|turf|area, mob/user as mob)
if(!in_range(A,user))
return
if(!isturf(A) && !isobj(A))
return
if(loc != user)
return
afterattack(atom/A as obj|turf|area, mob/user as mob)
if(!in_range(A,user))
return
if(loc != user)
return
if(istype(A,/obj/machinery/computer/forensic_scanning)) //breaks shit.
return
if(istype(A,/obj/item/weapon/f_card))
user << "The scanner displays on the screen: \"ERROR 43: Object on Excluded Object List.\""
return
if(!scanning)
scanning = 1
add_fingerprint(user)
spawn(0)
//Special case for blood splaters.
if (istype(A, /obj/effect/decal/cleanable/blood) || istype(A, /obj/effect/rune))
if(!isnull(A.blood_DNA))
for(var/blood in A.blood_DNA)
user << "\blue Blood type: [A.blood_DNA[blood]]\nDNA: [blood]"
return
//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." : "."]" ,\
"\blue Unable to locate any fingerprints, materials, fibers, or blood on [A]!",\
"You hear a faint hum of electrical equipment.")
return 0
if(add_data(A))
user << "\blue Object already in internal memory. Consolidating data..."
return
//PRINTS
if(!A.fingerprints || !A.fingerprints.len)
if(A.fingerprints)
del(A.fingerprints)
else
user << "\blue Isolated [A.fingerprints.len] fingerprints: 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 << "\blue &nbsp;&nbsp;No intact prints found"
add_log(user, "<font color='blue'>Scanning [A]...</font>")
//PRINTS
if(!A.fingerprints || !A.fingerprints.len)
if(A.fingerprints)
del(A.fingerprints)
else
user << "\blue &nbsp;&nbsp;Found [complete_prints.len] intact prints"
for(var/i in complete_prints)
user << "\blue &nbsp;&nbsp;&nbsp;&nbsp;[i]"
//FIBERS
if(A.suit_fibers)
user << "\blue Fibers/Materials Data Stored: Scan with Hi-Res Forensic Scanner to retrieve."
//Blood
if (A.blood_DNA)
user << "\blue Blood found on [A]. Analysing..."
spawn(15)
for(var/blood in A.blood_DNA)
user << "Blood type: \red [A.blood_DNA[blood]] \t \black DNA: \red [blood]"
if(prob(80) || !A.fingerprints)
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.")
return 0
else
user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.gender == MALE ? "him" : "her"] humming[prob(70) ? " gently." : "."]\n[user.gender == MALE ? "He" : "She"] seems to perk up slightly at the readout." ,\
"The results of the scan pique your interest.",\
"You hear a faint hum of electrical equipment, and someone making a thoughtful noise.")
return 0
return
proc/add_data(atom/A as mob|obj|turf|area)
//I love hashtables.
var/list/data_entry = stored["\ref [A]"]
if(islist(data_entry)) //Yay, it was already stored!
//Merge the fingerprints.
var/list/data_prints = data_entry[1]
for(var/print in A.fingerprints)
var/merged_print = data_prints[print]
if(!merged_print)
data_prints[print] = A.fingerprints[print]
var/list/completed_prints = list()
// Bah this looks awful but basically it loop throught the last 15 entries.
for(var/i in A.fingerprints)
var/print = A.fingerprints[i]
completed_prints += print
if(completed_prints.len < 1)
add_log(user, "<span class='info'>No intact prints found</span>")
else
data_prints[print] = stringmerge(data_prints[print],A.fingerprints[print])
add_log(user, "<span class='info'>Found [completed_prints.len] intact print[completed_prints.len == 1 ? "" : "s"]. Analysing...</span>")
sleep(30)
for(var/i in completed_prints)
add_log(user, "&nbsp;&nbsp;&nbsp;&nbsp;[i]")
//Now the fibers
var/list/fibers = data_entry[2]
if(!fibers)
fibers = list()
//FIBERS
if(A.suit_fibers && A.suit_fibers.len)
for(var/j = 1, j <= A.suit_fibers.len, j++) //Fibers~~~
if(!fibers.Find(A.suit_fibers[j])) //It isn't! Add!
fibers += A.suit_fibers[j]
var/list/blood = data_entry[3]
if(!blood)
blood = list()
if(A.blood_DNA && A.blood_DNA.len)
for(var/main_blood in A.blood_DNA)
if(!blood[main_blood])
blood[main_blood] = A.blood_DNA[blood]
return 1
var/list/sum_list[4] //Pack it back up!
sum_list[1] = A.fingerprints
sum_list[2] = A.suit_fibers
sum_list[3] = A.blood_DNA
sum_list[4] = "\The [A] in \the [get_area(A)]"
stored["\ref [A]"] = sum_list
return 0
add_log(user, "<span class='info'>Fibers found. Analysing...</span>")
sleep(30)
for(var/fiber in A.suit_fibers)
add_log(user, "&nbsp;&nbsp;&nbsp;&nbsp;[fiber]")
//Blood
if (A.blood_DNA && A.blood_DNA.len)
add_log(user, "<span class='info'>Blood found. Analysing...</span>")
sleep(30)
for(var/blood in A.blood_DNA)
add_log(user, "&nbsp;&nbsp;&nbsp;&nbsp;Blood type: <font color='red'>[A.blood_DNA[blood]]</font> DNA: <font color='red'>[blood]</font>")
//General
if ((!A.fingerprints || !A.fingerprints.len) && (!A.suit_fibers || !A.suit_fibers.len) && (!A.blood_DNA || !A.blood_DNA.len))
add_log(null, "Unable to locate any fingerprints, materials, fibers, or blood.")
user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.gender == MALE ? "him" : "her"] humming[prob(70) ? " gently." : "."]" ,\
"<span class='notice'>Unable to locate any fingerprints, materials, fibers, or blood on [A]!</span>",\
"You hear a faint hum of electrical equipment.")
else
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.")
add_log(null, "<font color='blue'>Ending scan report.</font>")
scanning = 0
return 0
/obj/item/device/detective_scanner/proc/add_log(var/mob/user, var/msg)
if(scanning)
if(user)
user << msg
log += "<span class='prefix'>[time2text(world.time + 432000, "hh:mm:ss")]</span>:&nbsp;&nbsp;[msg]"
else
CRASH("[src] \ref[src] is adding a log when it was never put in scanning mode!")

View File

@@ -71,6 +71,11 @@
log_game("[key_name(user)] fired Space lube from a spray bottle.")
return
/obj/item/weapon/reagent_containers/spray/attack_self(var/mob/user)
amount_per_transfer_from_this = (amount_per_transfer_from_this == 10 ? 5 : 10)
user << "<span class='notice'>You switched [amount_per_transfer_from_this == 10 ? "on" : "off"] the pressure nozzle. You'll now use [amount_per_transfer_from_this] units per spray.</span>"
/obj/item/weapon/reagent_containers/spray/examine()
set src in usr