diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index 5e9d0f70042..2e71bd1ac69 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -108,14 +108,6 @@ var/list/uplink_items = list() cost = 8 job = list("Clown") -//Detective -/datum/uplink_item/jobspecific/evidenceforger - name = "Evidence Forger" - desc = "An evidence scanner that allows you forge evidence by setting the output before scanning the item." - item = /obj/item/device/detective_scanner/forger - cost = 6 - job = list("Detective") - /datum/uplink_item/jobspecific/conversionkit name = "Conversion Kit Bundle" desc = "A bundle that comes with a professional revolver conversion kit and 1 box of .357 ammo. The kit allows you to convert your revolver to fire lethal rounds or vice versa, modification is nearly perfect and will not result in catastrophic failure." diff --git a/code/game/atoms.dm b/code/game/atoms.dm index def6c6e4c11..b58e3bf099f 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -251,35 +251,32 @@ its easier to just keep the beam vertical. /atom/proc/add_hiddenprint(mob/living/M as mob) if(isnull(M)) return if(isnull(M.key)) return - if (!( src.flags ) & FPRINT) - return - if (ishuman(M)) + if(ishuman(M)) var/mob/living/carbon/human/H = M - if (!istype(H.dna, /datum/dna)) + if(!istype(H.dna, /datum/dna)) return 0 - if (H.gloves) - if(src.fingerprintslast != H.key) - src.fingerprintshidden += text("\[[time_stamp()]\] (Wearing gloves). Real name: [], Key: []",H.real_name, H.key) - src.fingerprintslast = H.key + if(H.gloves) + if(fingerprintslast != H.ckey) + fingerprintshidden += text("\[[time_stamp()]\] (Wearing gloves). Real name: [], Key: []",H.real_name, H.key) + fingerprintslast = H.ckey return 0 - if (!( src.fingerprints )) - if(src.fingerprintslast != H.key) - src.fingerprintshidden += text("\[[time_stamp()]\] Real name: [], Key: []",H.real_name, H.key) - src.fingerprintslast = H.key + if(!( fingerprints )) + if(fingerprintslast != H.ckey) + fingerprintshidden += text("\[[time_stamp()]\] Real name: [], Key: []",H.real_name, H.key) + fingerprintslast = H.ckey return 1 else - if(src.fingerprintslast != M.key) - src.fingerprintshidden += text("\[[time_stamp()]\] Real name: [], Key: []",M.real_name, M.key) - src.fingerprintslast = M.key + if(fingerprintslast != M.ckey) + fingerprintshidden += text("\[[time_stamp()]\] Real name: [], Key: []",M.real_name, M.key) + fingerprintslast = M.ckey return + +//Set ignoregloves to add prints irrespective of the mob having gloves on. /atom/proc/add_fingerprint(mob/living/M as mob, ignoregloves = 0) if(isnull(M)) return - if(isAI(M)) return if(isnull(M.key)) return - if (!( src.flags ) & FPRINT) - return - if (ishuman(M)) + if(ishuman(M)) //Add the list if it does not exist. if(!fingerprintshidden) fingerprintshidden = list() @@ -301,25 +298,25 @@ its easier to just keep the beam vertical. H.dna.real_name = H.real_name H.check_dna() - //Now, deal with gloves. - if (H.gloves && H.gloves != src) - if(fingerprintslast != H.key) - fingerprintshidden += text("\[[]\](Wearing gloves). Real name: [], Key: []",time_stamp(), H.real_name, H.key) - fingerprintslast = H.key - H.gloves.add_fingerprint(M) + //Check if the gloves (if any) hide fingerprints + if(H.gloves) + var/obj/item/clothing/gloves/G = H.gloves + if(G.transfer_prints) + ignoregloves = 1 - //Deal with gloves the pass finger/palm prints. + //Now, deal with gloves. if(!ignoregloves) - if(H.gloves != src) - if(prob(75) && istype(H.gloves, /obj/item/clothing/gloves/latex)) - return 0 - else if(H.gloves && !istype(H.gloves, /obj/item/clothing/gloves/latex)) - return 0 + if(H.gloves && H.gloves != src) + if(fingerprintslast != H.ckey) + fingerprintshidden += text("\[[]\](Wearing gloves). Real name: [], Key: []",time_stamp(), H.real_name, H.key) + fingerprintslast = H.ckey + H.gloves.add_fingerprint(M) + return 0 //More adminstuffz - if(fingerprintslast != H.key) + if(fingerprintslast != H.ckey) fingerprintshidden += text("\[[]\]Real name: [], Key: []",time_stamp(), H.real_name, H.key) - fingerprintslast = H.key + fingerprintslast = H.ckey //Make the list if it does not exist. if(!fingerprints) @@ -329,75 +326,37 @@ its easier to just keep the beam vertical. var/full_print = md5(H.dna.uni_identity) // Add the fingerprints - // - if(fingerprints[full_print]) - switch(stringpercent(fingerprints[full_print])) //tells us how many stars are in the current prints. - - if(28 to 32) - if(prob(1)) - fingerprints[full_print] = full_print // You rolled a one buddy. - else - fingerprints[full_print] = stars(full_print, rand(0,40)) // 24 to 32 - - if(24 to 27) - if(prob(3)) - fingerprints[full_print] = full_print //Sucks to be you. - else - fingerprints[full_print] = stars(full_print, rand(15, 55)) // 20 to 29 - - if(20 to 23) - if(prob(5)) - fingerprints[full_print] = full_print //Had a good run didn't ya. - else - fingerprints[full_print] = stars(full_print, rand(30, 70)) // 15 to 25 - - if(16 to 19) - if(prob(5)) - fingerprints[full_print] = full_print //Welp. - else - fingerprints[full_print] = stars(full_print, rand(40, 100)) // 0 to 21 - - if(0 to 15) - if(prob(5)) - fingerprints[full_print] = stars(full_print, rand(0,50)) // small chance you can smudge. - else - fingerprints[full_print] = full_print - - else - fingerprints[full_print] = stars(full_print, rand(0, 20)) //Initial touch, not leaving much evidence the first time. - + fingerprints[full_print] = full_print return 1 else //Smudge up dem prints some - if(fingerprintslast != M.key) + if(fingerprintslast != M.ckey) fingerprintshidden += text("\[[]\]Real name: [], Key: []",time_stamp(), M.real_name, M.key) - fingerprintslast = M.key + fingerprintslast = M.ckey - //Cleaning up shit. - if(fingerprints && !fingerprints.len) - del(fingerprints) return /atom/proc/transfer_fingerprints_to(var/atom/A) - if(!istype(A.fingerprints,/list)) + // Make sure everything are lists. + if(!islist(A.fingerprints)) A.fingerprints = list() - - if(!istype(A.fingerprintshidden,/list)) + if(!islist(A.fingerprintshidden)) A.fingerprintshidden = list() - if(!istype(fingerprintshidden, /list)) + if(!islist(fingerprints)) + fingerprints = list() + if(!islist(fingerprintshidden)) fingerprintshidden = list() - //skytodo - //A.fingerprints |= fingerprints //detective - //A.fingerprintshidden |= fingerprintshidden //admin - if(A.fingerprints && fingerprints) + // Transfer + if(fingerprints) A.fingerprints |= fingerprints.Copy() //detective - if(A.fingerprintshidden && fingerprintshidden) - A.fingerprintshidden |= fingerprintshidden.Copy() //admin A.fingerprintslast = fingerprintslast + if(fingerprintshidden) + A.fingerprintshidden |= fingerprintshidden.Copy() //admin + A.fingerprintslast = fingerprintslast //returns 1 if made bloody, returns 0 otherwise diff --git a/code/modules/DetectiveWork/detective_work.dm b/code/modules/DetectiveWork/detective_work.dm index 047fa29e506..93c94aebf8e 100644 --- a/code/modules/DetectiveWork/detective_work.dm +++ b/code/modules/DetectiveWork/detective_work.dm @@ -5,10 +5,10 @@ atom/var/list/suit_fibers atom/proc/add_fibers(mob/living/carbon/human/M) if(M.gloves && istype(M.gloves,/obj/item/clothing/)) var/obj/item/clothing/gloves/G = M.gloves - if(G.transfer_blood) //bloodied gloves transfer blood to touched objects + if(G.transfer_blood > 1) //bloodied gloves transfer blood to touched objects if(add_blood(G.bloody_hands_mob)) //only reduces the bloodiness of our gloves if the item wasn't already bloody G.transfer_blood-- - else if(M.bloody_hands) + else if(M.bloody_hands > 1) if(add_blood(M.bloody_hands_mob)) M.bloody_hands-- if(!suit_fibers) suit_fibers = list() @@ -19,13 +19,13 @@ atom/proc/add_fibers(mob/living/carbon/human/M) if(prob(10*item_multiplier) && !(fibertext in suit_fibers)) //world.log << "Added fibertext: [fibertext]" suit_fibers += fibertext - if(!(M.wear_suit.body_parts_covered & 32)) + if(!(M.wear_suit.body_parts_covered & UPPER_TORSO)) if(M.w_uniform) fibertext = "Fibers from \a [M.w_uniform]." if(prob(12*item_multiplier) && !(fibertext in suit_fibers)) //Wearing a suit means less of the uniform exposed. //world.log << "Added fibertext: [fibertext]" suit_fibers += fibertext - if(!(M.wear_suit.body_parts_covered & 64)) + if(!(M.wear_suit.body_parts_covered & HANDS)) if(M.gloves) fibertext = "Material from a pair of [M.gloves.name]." if(prob(20*item_multiplier) && !(fibertext in suit_fibers)) @@ -45,583 +45,4 @@ atom/proc/add_fibers(mob/living/carbon/human/M) fibertext = "Material from a pair of [M.gloves.name]." 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 += "[temp]

" - if(canclear) dat += "{Clear Screen}" - else - if(!authenticated) - dat += "{Log In}" - else - dat += "{Log Out}


" - if(scanning) - if(scan_process) - dat += "Scan Object: {[scanning.name]}
" - dat += "{Cancel Scan} {Print}
" - else - if(isai) dat += "Scan Object: {[scanning.name]}
" - else dat += "Scan Object: {[scanning.name]}
" - dat += "{Scan} {Print}
" - else - if(isai) dat += "{No Object Inserted}
" - else dat += "{No Object Inserted}
" - dat += "{Scan} {Print}
" - dat += "{Access Database}

" - dat += "[scan_data]" - if(scan_data && !scan_process) - dat += "
{Erase Data}" - 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 -= scanning - I.icon_state = "evidenceobj" - 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 = "Criminal Evidence Database

" - temp += "Consolidated data points:
" - for(var/print in files) - var/list/file = files[print] - temp += "{[file[2]]}
" - temp += "
{Insert Finger Print Card (To complete a Dossier)}


" - else - temp = "" - if(misc && misc.len) - temp += "Auxiliary Evidence Database

" - temp += "This is where anything without fingerprints goes.

" - for(var/atom in misc) - var/list/data_entry = misc[atom] - temp += "{[data_entry[3]]}
" - 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 = "Criminal Evidence Database

" - temp += "Consolidated data points: [dossier[2]]
" - var/print_string = "Fingerprints: Print not complete!
" - if(stringpercent(dossier[1]) <= FINGERPRINT_COMPLETE) - print_string = "Fingerprints: (80% or higher completion reached)
[dossier[1]]
" - temp += print_string - for(var/object in dossier) - if(object == dossier[1] || object == dossier[2]) - continue - temp += "
" - var/list/outputs = dossier[object] - var/list/prints = outputs[1] - temp += "Object: [outputs[4]]
" - temp += " Fingerprints:
" - temp += "    [prints.len] Unique fingerprints found.
" - var/complete_prints = 0 - for(var/print in prints) - if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE) - complete_prints++ - temp += "      [prints[print]]
" - if(complete_prints) - temp += "      And [prints.len - complete_prints] unknown unique prints.
" - else - temp += "      No prints of sufficient completeness.
" - var/list/fibers = outputs[2] - if(fibers && fibers.len) - temp += " Fibers:
" - for(var/j = 1, j <= fibers.len, j++) - temp += "      [fibers[j]]
" - var/list/blood = outputs[3] - if(blood && blood.len) - temp += " Blood:
" - for(var/named in blood) - temp += "      Type: [blood[named]], DNA: [named]
" - temp += "
{Rename this Dossier}" - temp += "
{Delete this Dossier}" - temp += "
{Print}" - else - temp = "ERROR. Database not found!
" - temp += "
{Return}" - if("databaseprint") //Printing from the "files" database. - if(files) - var/obj/item/weapon/paper/P = new(loc) - var/list/dossier = files[href_list["identifier"]] - P.name = "\improper Database File ([dossier[2]])" - P.overlays += "paper_words" - P.info = "Criminal Evidence Database

" - P.info += "Consolidated data points: [dossier[2]]
" - var/print_string = "Fingerprints: Print not complete!
" - if(stringpercent(dossier[1]) <= FINGERPRINT_COMPLETE) - print_string = "Fingerprints: (80% or higher completion reached)
[dossier[1]]
" - P.info += print_string - for(var/object in dossier) - if(object == dossier[1] || object == dossier[2]) - continue - P.info += "
" - var/list/outputs = dossier[object] - var/list/prints = outputs[1] - P.info += "Object: [outputs[4]]
" - P.info += " Fingerprints:
" - P.info += "    [prints.len] Unique fingerprints found.
" - var/complete_prints = 0 - for(var/print in prints) - if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE) - complete_prints++ - P.info += "      [prints[print]]
" - if(complete_prints) - P.info += "      And [prints.len - complete_prints] unknown unique prints.
" - else - P.info += "      No prints of sufficient completeness.
" - var/list/fibers = outputs[2] - if(fibers && fibers.len) - P.info += " Fibers:
" - for(var/j = 1, j <= fibers.len, j++) - P.info += "      [fibers[j]]
" - var/list/blood = outputs[3] - if(blood && blood.len) - P.info += " Blood:
" - for(var/named in blood) - P.info += "      Type: [blood[named]], DNA: [named]
" - else - usr << "ERROR. Database not found!
" - if("auxiliary") //Viewing a record from the "misc" database. - canclear = 0 - if(misc) - temp = "Auxiliary Evidence Database

" - var/list/outputs = misc[href_list["identifier"]] - temp += "Consolidated data points: [outputs[3]]
" - var/list/prints = outputs[4] - if(prints) - temp += " Fingerprints:
" - temp += "    [prints.len] Unique fingerprints found.
" - var/complete_prints = 0 - for(var/print in prints) - if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE) - complete_prints++ - temp += "      [prints[print]]
" - if(complete_prints) - temp += "      And [prints.len - complete_prints] unknown unique prints.
" - else - temp += "      No prints of sufficient completeness.
" - var/list/fibers = outputs[1] - if(fibers && fibers.len) - temp += " Fibers:
" - for(var/fiber in fibers) - temp += "      [fiber]
" - var/list/blood = outputs[2] - if(blood && blood.len) - temp += " Blood:
" - for(var/named in blood) - temp += "      Type: [blood[named]], DNA: [named]
" - temp += "
{Delete This Record}" - temp += "
{Print}" - else - temp = "ERROR. Database not found!
" - temp += "
{Return}" - 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 = "Auxiliary Evidence Database

" - P.info += "Consolidated data points: [outputs[3]]
" - var/list/prints = outputs[4] - if(prints) - P.info += " Fingerprints:
" - P.info += "    [prints.len] Unique fingerprints found.
" - var/complete_prints = 0 - for(var/print in prints) - if(stringpercent(prints[print]) <= FINGERPRINT_COMPLETE) - complete_prints++ - P.info += "      [prints[print]]
" - if(complete_prints) - P.info += "      And [prints.len - complete_prints] unknown unique prints.
" - else - P.info += "      No prints of sufficient completeness.
" - var/list/fibers = outputs[1] - if(fibers && fibers.len) - P.info += " Fibers:
" - for(var/fiber in fibers) - P.info += "      [fiber]
" - var/list/blood = outputs[2] - if(blood && blood.len) - P.info += " Blood:
" - for(var/named in blood) - P.info += "      Type: [blood[named]], DNA: [named]
" - else - usr << "ERROR. Database not found!
" - 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 = "[scanning]

" - if (scanning.blood_DNA) - scan_data += "Blood Found:
" - for(var/blood in scanning.blood_DNA) - scan_data += "Blood type: [scanning.blood_DNA[blood]]\nDNA: [blood]

" - else - scan_data += "No Blood Found

" - if(!scanning.fingerprints) - scan_data += "No Fingerprints Found

" - else - scan_data += "Isolated [scanning.fingerprints.len] Fingerprints. Loaded into database.
" - add_data(scanning) - - if(!scanning.suit_fibers) - scan_data += "No Fibers/Materials Located
" - else - scan_data += "Fibers/Materials Found:
" - for(var/data in scanning.suit_fibers) - scan_data += "- [data]
" - if(istype(scanning,/obj/item/device/detective_scanner) || (istype(scanning, /obj/item/device/pda) && scanning:cartridge && scanning:cartridge.access_security)) - scan_data += "
Data transfered from \the [scanning] to Database.
" - add_data_scanner(scanning) - else if(!scanning.fingerprints) - scan_data += "
Add to Database?
" - 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 = "[scan_data]" - 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)) - var/obj/item/device/detective_scanner/D = W - if(D.stored) - for(var/atom in D.stored) - var/list/data = D.stored[atom] - add_data_master(atom,data[1],data[2],data[3],data[4]) - D.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 ? atom_suit_fibers.Copy() : null - templist[2] = atom_blood_DNA ? atom_blood_DNA.Copy() : null - templist[3] = atom_name - templist[4] = atom_fingerprints ? atom_fingerprints.Copy() : null - 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 ? atom_fingerprints.Copy() : null - data_point[2] = atom_suit_fibers ? atom_suit_fibers.Copy() : null - data_point[3] = atom_blood_DNA ? atom_blood_DNA.Copy() : null - 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 ? atom_fingerprints.Copy() : null - data_point[2] = atom_suit_fibers ? atom_suit_fibers.Copy() : null - data_point[3] = atom_blood_DNA ? atom_blood_DNA.Copy() : null - 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" \ No newline at end of file + suit_fibers += "Material from a pair of [M.gloves.name]." \ No newline at end of file diff --git a/code/modules/DetectiveWork/evidence.dm b/code/modules/DetectiveWork/evidence.dm index 0c414417813..807c6138406 100644 --- a/code/modules/DetectiveWork/evidence.dm +++ b/code/modules/DetectiveWork/evidence.dm @@ -1,4 +1,4 @@ -//CONTAINS: Evidence bags and fingerprint cards +//CONTAINS: Evidence bags /obj/item/weapon/evidencebag name = "evidence bag" @@ -8,17 +8,22 @@ item_state = "" w_class = 1 -/obj/item/weapon/evidencebag/afterattack(obj/item/I, mob/user as mob, proximity) - if(!proximity) return - if(!in_range(I, user)) +/obj/item/weapon/evidencebag/afterattack(obj/item/I, mob/user,proximity) + if(!proximity || loc == I) return + evidencebagEquip(I, user) +/obj/item/weapon/evidencebag/attackby(obj/item/I, mob/user) + if(evidencebagEquip(I, user)) + return 1 + +/obj/item/weapon/evidencebag/proc/evidencebagEquip(obj/item/I, mob/user) if(!istype(I) || I.anchored == 1) - return ..() + return if(istype(I, /obj/item/weapon/evidencebag)) user << "You find putting an evidence bag in another evidence bag to be slightly absurd." - return + return 1 //now this is podracing if(I.w_class > 3) user << "[I] won't fit in [src]." @@ -26,7 +31,7 @@ if(contents.len) user << "[src] already has something inside it." - return ..() + return if(!isturf(I.loc)) //If it isn't on the floor. Do some checks to see if it's in our hands or a box. Otherwise give up. if(istype(I.loc,/obj/item/weapon/storage)) //in a container. @@ -40,8 +45,8 @@ else return - user.visible_message("[user] puts [I] into [src]", "You put [I] inside [src].",\ - "You hear a rustle as someone puts something into a plastic bag.") + user.visible_message("[user] puts [I] into [src].", "You put [I] inside [src].",\ + "You hear a rustle as someone puts something into a plastic bag.") icon_state = "evidence" @@ -58,14 +63,13 @@ desc = "An evidence bag containing [I]. [I.desc]" I.loc = src w_class = I.w_class - return - + return 1 /obj/item/weapon/evidencebag/attack_self(mob/user as mob) if(contents.len) var/obj/item/I = contents[1] - user.visible_message("[user] takes [I] out of [src]", "You take [I] out of [src].",\ - "You hear someone rustle around in a plastic bag, and remove something.") + user.visible_message("[user] takes [I] out of [src].", "You take [I] out of [src].",\ + "You hear someone rustle around in a plastic bag, and remove something.") overlays.Cut() //remove the overlays user.put_in_hands(I) w_class = 1 @@ -88,24 +92,4 @@ 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 - throw_speed = 3 - throw_range = 5 - - -/obj/item/weapon/fcardholder - name = "fingerprint card case" - desc = "Apply finger print card." - icon = 'icons/obj/items.dmi' - icon_state = "fcardholder0" - item_state = "clipboard" + return \ No newline at end of file diff --git a/code/modules/DetectiveWork/footprints_and_rag.dm b/code/modules/DetectiveWork/footprints_and_rag.dm index 899498029d3..04df3a507e6 100644 --- a/code/modules/DetectiveWork/footprints_and_rag.dm +++ b/code/modules/DetectiveWork/footprints_and_rag.dm @@ -1,3 +1,4 @@ + /mob var/bloody_hands = 0 var/mob/living/carbon/human/bloody_hands_mob @@ -26,19 +27,16 @@ can_be_placed_into = null flags = FPRINT | TABLEPASS | OPENCONTAINER | NOBLUDGEON -/obj/item/weapon/reagent_containers/glass/rag/attack_self(mob/user as mob) - return - /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") + user.visible_message("[user] has smothered \the [target] with \the [src]!", "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() + src.reagents.clear_reagents() return else ..() -/obj/item/weapon/reagent_containers/glass/rag/afterattack(atom/A as obj|turf|area, mob/user as mob, proximity) +/obj/item/weapon/reagent_containers/glass/rag/afterattack(atom/A as obj|turf|area, mob/user as mob,proximity) if(!proximity) return if(istype(A) && src in user) user.visible_message("[user] starts to wipe down [A] with [src]!") @@ -46,10 +44,3 @@ 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 \ No newline at end of file diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 1a95fb5595f..87ffd249bdb 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -9,7 +9,7 @@ while sprite_sheets should be used for "flexible" clothing items that do not need to be refitted (e.g. vox wearing jumpsuits). */ var/list/sprite_sheets_refit = null - + //BS12: Species-restricted clothing check. /obj/item/clothing/mob_can_equip(M as mob, slot) @@ -53,12 +53,12 @@ icon_override = sprite_sheets[target_species] else icon_override = initial(icon_override) - + if (sprite_sheets_obj && (target_species in sprite_sheets_obj)) icon = sprite_sheets_obj[target_species] else icon = initial(icon) - + //Ears: currently only used for headsets and earmuffs /obj/item/clothing/ears name = "ears" @@ -153,6 +153,7 @@ BLIND // can't see anything body_parts_covered = HANDS slot_flags = SLOT_GLOVES attack_verb = list("challenged") + var/transfer_prints = FALSE var/pickpocket = 0 //Master pickpocket? var/clipped = 0 species_restricted = list("exclude","Unathi","Tajaran") @@ -181,7 +182,7 @@ BLIND // can't see anything set src in usr ..() return - + /obj/item/clothing/under/proc/set_sensors(mob/usr as mob) var/mob/M = usr if (istype(M, /mob/dead/)) return diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm index 6e42aac7e44..6aa8c1c8d7d 100644 --- a/code/modules/clothing/gloves/miscellaneous.dm +++ b/code/modules/clothing/gloves/miscellaneous.dm @@ -63,6 +63,7 @@ siemens_coefficient = 0.30 permeability_coefficient = 0.01 _color="white" + transfer_prints = TRUE species_fit = list("Vox") sprite_sheets = list( "Vox" = 'icons/mob/species/vox/mask.dmi' diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm deleted file mode 100644 index 48d4812bac1..00000000000 --- a/code/modules/detectivework/scanner.dm +++ /dev/null @@ -1,401 +0,0 @@ -//CONTAINS: Detective's Scanner - - -/obj/item/device/detective_scanner - name = "Scanner" - desc = "Used to scan objects for DNA and fingerprints." - icon_state = "forensic1" - var/amount = 20.0 - var/list/stored = list() - w_class = 3.0 - item_state = "electronic" - flags = FPRINT | TABLEPASS | CONDUCT | NOBLUDGEON - slot_flags = SLOT_BELT - - 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 - else - src.amount += W.amount - //W = null - del(W) - add_fingerprint(user) - if (W) - W.add_fingerprint(user) - return - - 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." - flick("forensic0",src) - return 0 - if (( !( istype(M.dna, /datum/dna) ) || M.gloves) ) - user << "\blue No fingerprints found on [M]" - flick("forensic0",src) - return 0 - else - if (src.amount < 1) - user << text("\blue Fingerprints scanned on [M]. Need more cards to print.") - 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) - for(var/blood in M.blood_DNA) - user << "\blue Blood type: [M.blood_DNA[blood]]\nDNA: [blood]" - return - - afterattack(atom/A as obj|turf|area, mob/user as mob, proximity) - if(!proximity) 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.\"" - flick("forensic0",src) - return - - add_fingerprint(user) - - - //Special case for blood splaters. - if (istype(A, /obj/effect/decal/cleanable/blood) || istype(A, /obj/effect/rune) || istype(A, /obj/effect/decal/cleanable/blood/gibs)) - if(!isnull(A.blood_DNA)) - for(var/blood in A.blood_DNA) - user << "\blue Blood type: [A.blood_DNA[blood]]\nDNA: [blood]" - flick("forensic2",src) - 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.") - flick("forensic0",src) - return 0 - - if(add_data(A)) - user << "\blue Object already in internal memory. Consolidating data..." - flick("forensic2",src) - 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   No intact prints found" - else - user << "\blue   Found [complete_prints.len] intact prints" - for(var/i in complete_prints) - user << "\blue     [i]" - - //FIBERS - if(A.suit_fibers) - user << "\blue Fibers/Materials Data Stored: Scan with Hi-Res Forensic Scanner to retrieve." - flick("forensic2",src) - - //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.") - flick("forensic2",src) - 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.") - flick("forensic2",src) - return 0 - return - - proc/add_data(atom/A as mob|obj|turf|area) - //I love associative lists. - 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] - else - data_prints[print] = stringmerge(data_prints[print],A.fingerprints[print]) - - //Now the fibers - var/list/fibers = data_entry[2] - if(!fibers) - fibers = list() - 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 ? A.fingerprints.Copy() : null - sum_list[2] = A.suit_fibers ? A.suit_fibers.Copy() : null - sum_list[3] = A.blood_DNA ? A.blood_DNA.Copy() : null - sum_list[4] = "\The [A] in \the [get_area(A)]" - stored["\ref [A]"] = sum_list - return 0 - -/obj/item/device/detective_scanner/forger - var/list/custom_forgery[3] - var/forging = 0 - - New() - ..() - custom_forgery[1] = list() - custom_forgery[2] = list() - custom_forgery[3] = list() - - attack_self(var/mob/user as mob) - var/list/customprints = list() - var/list/customfiber = list() - var/list/customblood = list() - if(forging) - user << "\red You are already forging evidence" - return 0 - clear_forgery() - //fingerprint loop - while(1) - var/print = html_encode(input(usr,"Please enter a custom fingerprint or hit cancel to finish fingerprints") as text|null) - if(!usr.client) - forging = 0 - break - if(!print ) - break - customprints[print] = print - while(1) - var/fiber = html_encode(input(usr,"Please enter a custom fiber/material trace or hit cancel to finish fibers/materials") as text|null) - if(!usr.client) - forging = 0 - break - if(!fiber) - break - customfiber[fiber] = null - while(1) - var/blood = html_encode(input(usr,"Please enter a custom Blood DNA or hit cancel to finish forging") as text|null) - var/bloodtype = html_encode(input(usr,"Please enter a custom Blood Type") as text|null) - if(!usr.client) - forging = 0 - break - if(!blood) - break - customblood[blood] = bloodtype - forging = 0 - if(!customprints.len && !customfiber.len) - user << "\blue No forgery saved." - return - user << "\blue Forgery saved and will be tied to the next applicable scanned item." - custom_forgery[1] = customprints ? customprints.Copy() : null - custom_forgery[2] = customfiber ? customfiber.Copy() : null - custom_forgery[3] = customblood ? customblood.Copy() : null - -//shameless copy pasting - afterattack(atom/A as obj|turf|area, mob/user as mob) - var/list/custom_finger = list() - var/list/custom_fiber = list() - var/list/custom_blood = list() - - if(custom_forgery) - custom_finger = custom_forgery[1] - custom_fiber = custom_forgery[2] - custom_blood = custom_forgery[3] - - 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 - - add_fingerprint(user) - - - //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) - if(!custom_finger.len && !custom_fiber.len && !custom_blood.len) - 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 - else - 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], loading custom forgery instead.",\ - "You hear a faint hum of electrical equipment.") - - - 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) - if(custom_finger.len) - user << "\blue Isolated [custom_finger.len] fingerprints: Data Stored: Scan with Hi-Res Forensic Scanner to retrieve." - user << "\blue   Found [custom_finger.len] intact prints" - for(var/i in custom_finger) - user << "\blue     [i]" - else if(A.fingerprints && A.fingerprints.len) - 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   No intact prints found" - else - user << "\blue   Found [complete_prints.len] intact prints" - for(var/i in complete_prints) - user << "\blue     [i]" - - //FIBERS - if(custom_fiber.len) - user << "\blue Forged Fibers/Materials Data Found: Scan with Hi-Res Forensic Scanner to retrieve." - else if(A.suit_fibers) - user << "\blue Fibers/Materials Data Stored: Scan with Hi-Res Forensic Scanner to retrieve." - - - //Blood - if(custom_blood.len) - user << "\blue Forged Blood found. Analysing..." - spawn(15) - for(var/blood in custom_blood) - user << "Blood type: \red [custom_blood[blood]] \t \black DNA: \red [blood]" - else 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]" - return - - add_data(atom/A as mob|obj|turf|area) - //I love associative lists. - var/list/data_entry = stored["\ref [A]"] - var/list/custom_finger = list() - var/list/custom_fiber = list() - var/list/custom_blood = list() - - if(custom_forgery) - custom_finger = custom_forgery[1] - custom_fiber = custom_forgery[2] - custom_blood = custom_forgery[3] - - if(islist(data_entry)) //Yay, it was already stored! - //Merge the fingerprints. - var/list/data_prints = data_entry[1] - if(custom_finger.len) - for(var/print in custom_finger) - var/merged_print = data_prints[print] - if(!merged_print) - data_prints[print] = custom_finger - else - data_prints[print] = stringmerge(data_prints[print],custom_finger[print]) - else - for(var/print in A.fingerprints) - var/merged_print = data_prints[print] - if(!merged_print) - data_prints[print] = A.fingerprints[print] - else - data_prints[print] = stringmerge(data_prints[print],A.fingerprints[print]) - - //Now the fibers - var/list/fibers = data_entry[2] - if(!fibers) - fibers = list() - if(custom_fiber.len) - for(var/j = 1, j <= custom_fiber.len, j++) //Fibers~~~ - if(!fibers.Find(custom_fiber[j])) //It isn't! Add! - fibers += custom_fiber[j] - - else 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(custom_blood.len) - for(var/main_blood in custom_blood) - if(!blood[main_blood]) - blood[main_blood] = custom_blood[blood] - else 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! - if(custom_finger.len || custom_fiber.len || custom_blood.len) - sum_list[1] = custom_finger ? custom_finger.Copy() : null - sum_list[2] = custom_fiber ? custom_fiber.Copy() : null - sum_list[3] = custom_blood ? custom_blood.Copy() : null - else - sum_list[1] = A.fingerprints ? A.fingerprints.Copy() : null - sum_list[2] = A.suit_fibers ? A.suit_fibers.Copy() : null - sum_list[3] = A.blood_DNA ? A.blood_DNA.Copy() : null - sum_list[4] = "\The [A] in \the [get_area(A)]" - stored["\ref [A]"] = sum_list - clear_forgery() - return 0 - - proc/clear_forgery() - if(custom_forgery.len) - custom_forgery[1] = list() - custom_forgery[2] = list() - custom_forgery[3] = list() \ No newline at end of file diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm index 23496fc1f7b..624c2f19e19 100644 --- a/code/modules/organs/blood.dm +++ b/code/modules/organs/blood.dm @@ -73,7 +73,7 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 // Damaged heart virtually reduces the blood volume, as the blood isn't // being pumped properly anymore. var/datum/organ/internal/heart/heart = internal_organs_by_name["heart"] - + if(heart) if(heart.damage > 1 && heart.damage < heart.min_bruised_damage) blood_volume *= 0.8 @@ -314,13 +314,13 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 return D return res -proc/blood_incompatible(donor,receiver) - if(!donor || !receiver) return 0 - var - donor_antigen = copytext(donor,1,lentext(donor)) - receiver_antigen = copytext(receiver,1,lentext(receiver)) - donor_rh = (findtext(donor,"+")>0) - receiver_rh = (findtext(receiver,"+")>0) +/proc/blood_incompatible(donor,receiver) + + 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) + if(donor_rh && !receiver_rh) return 1 switch(receiver_antigen) if("A") diff --git a/maps/cyberiad.dmm b/maps/cyberiad.dmm index 3232b061196..56c2f38dcc0 100644 --- a/maps/cyberiad.dmm +++ b/maps/cyberiad.dmm @@ -1078,7 +1078,7 @@ "auL" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 5},/obj/structure/closet{name = "Evidence Closet"},/obj/effect/decal/cleanable/cobweb,/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/security/detectives_office) "auM" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/security/detectives_office) "auN" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/structure/table,/obj/structure/table,/obj/item/weapon/folder/red{pixel_y = 3},/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/security/detectives_office) -"auO" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/obj/machinery/atmospherics/pipe/manifold{_color = "red"; icon_state = "manifold-r-f"; level = 1; name = "pipe manifold"},/obj/structure/table,/obj/item/weapon/fcardholder,/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/security/detectives_office) +"auO" = (/obj/machinery/light,/obj/machinery/computer/secure_data,/turf/simulated/floor{icon_state = "floorgrime"},/area/security/detectives_office) "auP" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/security/detectives_office) "auQ" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/structure/disposalpipe/segment,/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id = "Secure Gate"; name = "Security Blast Door"; opacity = 0},/obj/machinery/door/airlock/maintenance{name = "Detective Maintenance"; req_access_txt = "4"},/turf/simulated/floor{icon_state = "floorgrime"},/area/security/detectives_office) "auR" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor/plating,/area/maintenance/fsmaint) @@ -1104,7 +1104,7 @@ "avl" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 5},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor{icon_state = "floorgrime"},/area/security/detectives_office) "avm" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor{icon_state = "floorgrime"},/area/security/detectives_office) "avn" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/effect/decal/cleanable/dirt,/turf/simulated/floor{icon_state = "floorgrime"},/area/security/detectives_office) -"avo" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/machinery/computer/med_data,/turf/simulated/floor{icon_state = "floorgrime"},/area/security/detectives_office) +"avo" = (/obj/machinery/computer/med_data,/turf/simulated/floor{icon_state = "floorgrime"},/area/security/detectives_office) "avp" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/structure/disposalpipe/segment,/turf/simulated/wall/r_wall,/area) "avq" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 9; pixel_y = 0},/turf/simulated/floor/plating,/area/maintenance/fsmaint) "avr" = (/obj/machinery/vending/chinese,/turf/simulated/floor/wood,/area/crew_quarters/mrchangs) @@ -1155,7 +1155,7 @@ "awk" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor{icon_state = "floorgrime"},/area/security/detectives_office) "awl" = (/turf/simulated/floor{icon_state = "floorgrime"},/area/security/detectives_office) "awm" = (/obj/structure/stool,/turf/simulated/floor{icon_state = "floorgrime"},/area/security/detectives_office) -"awn" = (/obj/machinery/computer/secure_data,/turf/simulated/floor{icon_state = "floorgrime"},/area/security/detectives_office) +"awn" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/obj/machinery/atmospherics/pipe/manifold{_color = "red"; icon_state = "manifold-r-f"; level = 1; name = "pipe manifold"},/obj/structure/table,/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/security/detectives_office) "awo" = (/obj/structure/disposalpipe/segment,/turf/simulated/wall/r_wall,/area) "awp" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plating,/area/maintenance/fsmaint) "awq" = (/obj/structure/stool/bed/chair/wood/wings,/turf/simulated/floor/wood,/area/crew_quarters/mrchangs) @@ -1199,7 +1199,6 @@ "axc" = (/obj/structure/table,/obj/item/weapon/paper_bin{pixel_x = -3; pixel_y = 7},/obj/item/weapon/pen,/turf/simulated/floor{icon_state = "floorgrime"},/area/security/detectives_office) "axd" = (/obj/machinery/photocopier,/turf/simulated/floor{icon_state = "floorgrime"},/area/security/detectives_office) "axe" = (/obj/structure/filingcabinet/chestdrawer,/turf/simulated/floor{icon_state = "floorgrime"},/area/security/detectives_office) -"axf" = (/obj/machinery/computer/forensic_scanning,/obj/machinery/light,/turf/simulated/floor{icon_state = "floorgrime"},/area/security/detectives_office) "axg" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/maintenance/fsmaint) "axh" = (/obj/structure/table/woodentable,/obj/machinery/atmospherics/unary/vent_scrubber{on = 1; scrub_N2O = 1; scrub_Toxins = 1},/turf/simulated/floor/wood,/area/crew_quarters/mrchangs) "axi" = (/obj/machinery/hologram/holopad,/turf/simulated/floor/wood,/area/crew_quarters/mrchangs) @@ -12634,10 +12633,10 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaqQaaaaaaaaaaframdaqTaqTaqTamdaaaaaaaaiaaiabnaaiaaiaflaaiarLaaiaaqaaqaaqarMarNaaqaaqaaqaaqarOarPaaqaaqaaqaaiarQarRarSarTarUarVaqBarWaaqarXarYarZasaabIasbascasdaseaqJasfamzasgashasiasjaskaslanDaaiasmasnaaiasoaspasqasrasrasrasrasrassaaiaaaaaaaaaafraabaoRaoSaoSaoSaoSaoTaoUaoVaoWaoWaoWaoWaoXaabafraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiaaiaaiaaiaaiaaiaaiaaaaaaaaaaaaaaaaqQaaaaaaaaaafqamdaqTaqTaqTamdaaiaaiaaiastasuasvaswasxasyaszaaiasAapiapjapkaplapmasBapoasCasDasEasFasGasHapmasIasJasKasLasMasMasNasOaaqasPasQasRasSaaqasTasUasVaqKaqJasWamzasgaqMashashashasXasYasZataatbaaiatcatdateatfatgathatiatiatjaaiaaaaaaaaaafraabapTapTapTapTapTaabapUaabapTapTapTapTapTaabafraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanIanIanIanIanIanIanIanIanIanIanIanIanIanIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiatkatlatmatnatoaaiaaaaaaaaaaaaaaaaqQaaaaaaaabaframdaqTaqTaqTatpamLatqamNatratsattatuatvattatwaaiaqhatxatyatzatAatBatCatDatEatFatGatHatIatJatKatLatMatMatNatMatMatOatPatQatRatSatTatUaaqatVatWatXatYatZauaamzasgaubaucaucaucaudaueaufaugauhaaiauiaujaukatfatfatfatfatfatfaaiaaaaaaaaaamIaaaaaaaaaaabaaaaaaaaaapUaaaaaaaaaaabaaaaaaaaaafqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiatkaulaumaunatkaaiaaaaaaaaaaaaaaaaqQaaaaaaaabaframdauoauoauoamdaaiaaiaaiaupauqaurausautauuauvaaiaqZauwauxauyauzarearfauAauBauCauDauBauEarmareauFauGauHauGauGauHauGauIaaqarXauJatTauKaaqauLauMauNauOauPauPauQauRaovaaqaaqaaqaaKaaqabnaaiaaiaaiauSauTauUatfauVauWauWauWauWaaiaaaaaaaaaafraabaosaosaosaosaosaabapUaabaosaosaosaosaosaabafraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIaaaaaaaaaaaaaaaaaaaaaaaaaaiatkauXauYauZatkaaiaaaaaaaaaaaaaaaaqQaaaaaaaaaaframdavaavaavaamdaaqaaqaaqaaqaaqaaqaaiavbavcaaiaaiaaiaaiavdacDaveacDacDaveacDaveacDacDabuaaiaaiavfavgavhaviavgavhaviavjaaiaaiaaiaaiaaiaaqavkavlavmavmavnavoavpavqaaqavravsavtaaKavuavvavwavxaaqaaqavyaaKaaqaaqaaqaaqaaqaaqaaiaaaaaaaaaafqaabaoRaoSaoSaoSaoSaoTaoUaoVaoWaoWaoWaoWaoXaabafraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIaaaavzavAavBaaaavCavDavEaaiavFavGavHavGavIaaiaaaaaaaaaaaaaaaaqQaaaaaaaaaafravJavKavKavKavLaaqavMavNavOavPavQavRavSavTavUavVavUavUavUavUavUavUavUavUavWavXavYavUavUavUavUavZavUavUavUavUawaadXawcawdaweawfawgawhaaqawiawjawkawlawmawnawoawpaaqawqawrawsaaKawtawuawtawvaaqawwawxawyawzawAawBawCawDawEaaiaaaaaaaaaafqaaaapTapTapTapTapTaabapUaabapTapTapTapTapTaaaafZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamcamcamcaaaamcamcamcamcamcamcamcamcamcaaaamcamcamcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIaaiawFawGawFaaiawHawIawHaaiawJawKawLawMawNaaiaaaaaaaaaaaaaaaaqQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaqawOawPawQawRawRawSawTawUawaawaawaawaawaawaawaawaawaawaawVawaawaawaawaawaawaawWawaawaawaawaawXawaawYawaawZawaawaaxaaaqaxbaxcaxdaxeawkaxfawoaxgaaqaxhaxiaxjaxkawtaxlaxmavxaaqaxnaxoaxpaxqaxraxsaxraxtaxraaiaaaaaaaaaafqaaaaabaaaaaaaaaaaaaabapUaaaaaaaaaaaaaaaaabaaaafraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamcaaaaaaamcamcamcamcamcamcamcamcamcaaaaaaamcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiatkaulaumaunatkaaiaaaaaaaaaaaaaaaaqQaaaaaaaabaframdauoauoauoamdaaiaaiaaiaupauqaurausautauuauvaaiaqZauwauxauyauzarearfauAauBauCauDauBauEarmareauFauGauHauGauGauHauGauIaaqarXauJatTauKaaqauLauMauNawnauPauPauQauRaovaaqaaqaaqaaKaaqabnaaiaaiaaiauSauTauUatfauVauWauWauWauWaaiaaaaaaaaaafraabaosaosaosaosaosaabapUaabaosaosaosaosaosaabafraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIaaaaaaaaaaaaaaaaaaaaaaaaaaiatkauXauYauZatkaaiaaaaaaaaaaaaaaaaqQaaaaaaaaaaframdavaavaavaamdaaqaaqaaqaaqaaqaaqaaiavbavcaaiaaiaaiaaiavdacDaveacDacDaveacDaveacDacDabuaaiaaiavfavgavhaviavgavhaviavjaaiaaiaaiaaiaaiaaqavkavlavmavmavnavmavpavqaaqavravsavtaaKavuavvavwavxaaqaaqavyaaKaaqaaqaaqaaqaaqaaqaaiaaaaaaaaaafqaabaoRaoSaoSaoSaoSaoTaoUaoVaoWaoWaoWaoWaoXaabafraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcamcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIaaaavzavAavBaaaavCavDavEaaiavFavGavHavGavIaaiaaaaaaaaaaaaaaaaqQaaaaaaaaaafravJavKavKavKavLaaqavMavNavOavPavQavRavSavTavUavVavUavUavUavUavUavUavUavUavWavXavYavUavUavUavUavZavUavUavUavUawaadXawcawdaweawfawgawhaaqawiawjawkawlawmavoawoawpaaqawqawrawsaaKawtawuawtawvaaqawwawxawyawzawAawBawCawDawEaaiaaaaaaaaaafqaaaapTapTapTapTapTaabapUaabapTapTapTapTapTaaaafZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamcamcamcaaaamcamcamcamcamcamcamcamcamcaaaamcamcamcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIaaiawFawGawFaaiawHawIawHaaiawJawKawLawMawNaaiaaaaaaaaaaaaaaaaqQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaqawOawPawQawRawRawSawTawUawaawaawaawaawaawaawaawaawaawaawVawaawaawaawaawaawaawWawaawaawaawaawXawaawYawaawZawaawaaxaaaqaxbaxcaxdaxeawkauOawoaxgaaqaxhaxiaxjaxkawtaxlaxmavxaaqaxnaxoaxpaxqaxraxsaxraxtaxraaiaaaaaaaaaafqaaaaabaaaaaaaaaaaaaabapUaaaaaaaaaaaaaaaaabaaaafraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamcaaaaaaamcamcamcamcamcamcamcamcamcaaaaaaamcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIaaiawFaxuawFaaqawHaxvawHaaiaxwaxxaxyaxzaxAaaiaaaaaaaaaaaaaaaaqQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaqaxBaxCaxDaxEaxFaaqaxGaxHaxIaxIaxJaxKaxLaxIaxMaxIaxIaxIaxNaxIaxIaxIaxIaxIaxIaxOaxPaxQaxQaxQaxRaxSaxTaxSaxUaxVaxSaxWaaqaaiaaiaaiaaiaaiaaiawoawpaaqaxXawraxYaaKawtaxZawtawvaaqayaaybaycaxraydaxraxraxtayeaaiaaaaaaaaaafqafqafraaaaaaaaaaabaabapUaabaaaaaaaaaaaaafrafrafraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamcamcamcamcamcamcamcamcamcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanIanIanIanIanIanIanIanIanIanIanIanIanIanIanIaaaaaiayfaygayhaaqayiayjaykaaiaylaymaynayoaypaaiaaaaaaaaaaaaaaaaqQaaaaaaaaaaaaaaaaaaaaaaaaaaaaaqaaqaaqaaqaaqaaqaaiaoyayqaaqayraysaytaaqayuaaqayvaywaaqayxaaqaaqaaqaaqaaqaaqaaqayyaaqaaqayzayAayBamzaaqaoyaaqayCaaqaaqapPanDanDanDanDanDayDawpaaqayEawrayFaaKayGaxlaxmavxaaqayHayIayJayKayKayLayKayMayNaaiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamcamcamcamcamcamcamcamcamcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanIanIanIanIanIanIanIanIanIanIanIanIaaiaaiaaiaaiayPayQayRaaqayPayQayRaaiaySayTayUayVayWaaiaaaaaaaaaaaaaaaapVapWapWapWapWapWapWayXaaaaaaaaaaaaaaaaaaaaaaaaaaiayYayZaaqazaazbazcaaqazdaaqazeazfazgazhaziazjazkazlazmaznazoazpazqazrazsawaawbaztazuazvazwazwazwazwazwazxazwazwazwazwazyazzazAazBazCazDazEazFazGawtawvaaqayHazHazIazJaxrazKazLazMazNaaiazOazPazPazPazPazPazQaaaaaaaaaaaaazRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamcamcamcamcamcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa