From beffc2299a93e01a2994c124c34e2016f7c66fe0 Mon Sep 17 00:00:00 2001 From: SkyMarshal Date: Tue, 31 Jan 2012 02:00:45 -0700 Subject: [PATCH] Final updates on Fingerprints fix for traitors getting assassinate and protect targets for the same person Ported blood rejection --- code/WorkInProgress/detective_work.dm | 411 ++++++++++++------ code/WorkInProgress/meteors.dm | 154 +++++++ code/defines/atom.dm | 2 +- code/game/atom_procs.dm | 50 ++- code/game/dna.dm | 1 - code/game/gamemodes/traitor/traitor.dm | 3 +- code/game/machinery/doors/airlock.dm | 6 +- code/game/objects/closets/secure/security.dm | 2 +- code/game/objects/devices/scanners.dm | 70 +-- code/game/objects/items/item.dm | 2 +- code/game/objects/items/weapons/cards_ids.dm | 10 +- code/modules/admin/verbs/adminhelp.dm | 11 +- code/modules/chemical/Chemistry-Machinery.dm | 33 +- code/modules/chemical/Chemistry-Reagents.dm | 6 + code/modules/chemical/Chemistry-Tools.dm | 9 +- code/modules/mob/living/carbon/give.dm | 3 + .../mob/living/carbon/human/human_defense.dm | 1 + code/modules/mob/new_player/new_player.dm | 1 + icons/obj/chemical.dmi | Bin 28974 -> 29906 bytes icons/obj/syringe.dmi | Bin 947 -> 1140 bytes 20 files changed, 554 insertions(+), 221 deletions(-) create mode 100644 code/WorkInProgress/meteors.dm diff --git a/code/WorkInProgress/detective_work.dm b/code/WorkInProgress/detective_work.dm index 154cfdb3fb..a8c0b8dbea 100644 --- a/code/WorkInProgress/detective_work.dm +++ b/code/WorkInProgress/detective_work.dm @@ -49,6 +49,8 @@ atom/proc/add_fibers(mob/living/carbon/human/M) suit_fibers += "Material from a pair of [M.gloves.name]." if(!suit_fibers.len) del suit_fibers +#define 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 = "High-Res Forensic Scanning Computer" @@ -67,9 +69,9 @@ obj/machinery/computer/forensic_scanning // 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. - list/files = list() + list/files //This holds objects (1) without prints, and their fibers(2) and blood(3). - list/misc = list() + list/misc obj/item/weapon/f_card/card scan_data = "" @@ -102,15 +104,16 @@ obj/machinery/computer/forensic_scanning if(scanning) if(scan_process) dat += "Scan Object: {[scanning.name]}
" - dat += "{Cancel Scan} {Print}

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

" + dat += "{Scan} {Print}
" else if(isai) dat += "{No Object Inserted}
" else dat += "{No Object Inserted}
" - dat += "{Scan} {Print}

" + dat += "{Scan} {Print}
" + dat += "{Access Database}

" dat += "[scan_data]" if(scan_data && !scan_process) dat += "
{Erase Data}" @@ -122,59 +125,56 @@ obj/machinery/computer/forensic_scanning return - proc/add_data_scanner(var/obj/item/device/detective_scanner/W as obj) - for(var/i = 1, i < W.stored.len, i++) + proc/add_data_scanner(var/obj/item/device/detective_scanner/W) + for(var/i = 1, i < (W.stored.len + 1), i++) var/list/data = W.stored[i] - var/atom/A = new - A = W - world << "[A] at [A.loc]" - A.fingerprints = data[2] - A.suit_fibers = data[3] - A.blood_DNA = data[4] - add_data(A,1) - del(A) + add_data(data[1],1,data[2],data[3],data[4]) - proc/add_data(var/atom/A, var/override = 0) + proc/add_data(var/atom/A, var/override = 0, var/tempfingerprints, var/tempsuit_fibers,var/tempblood_DNA) //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((!A.fingerprints || A.fingerprints.len < 1) && !override) //No prints + var + backup_prints + backup_fibers + backup_DNA + if(override) + backup_prints = A.fingerprints + A.fingerprints = tempfingerprints + backup_fibers = A.suit_fibers + A.suit_fibers = tempsuit_fibers + backup_DNA = A.blood_DNA + A.blood_DNA = tempblood_DNA + if((!A.fingerprints || !length(A.fingerprints))) //No prints var/merged = 0 - for(var/i = 1, i < misc.len, i++) //Lets see if we can find it. - var/list/templist = misc[i] - var/check = templist[1] - if(check == A) //There it is! - merged = 1 - var/list/fibers = templist[2] - if(A.suit_fibers) - for(var/j = 1, j < A.suit_fibers.len, j++) //Fibers~~~ - var/test_print1 = A.suit_fibers[j] - var/found = 0 - for(var/k = 1, k <= fibers.len, k++) //Lets see if the fiber is already in there - var/test_print2 = fibers[k] - if(test_print2 == test_print1) //It is! Do nothing! - found = 1 - break - if(!found) //It isn't! Add! - fibers += A.suit_fibers[j] - var/list/blood = templist[3] - if(A.blood_DNA) - for(var/j = 1, j < A.blood_DNA.len, j++) //Blood~~~ - var/test_print1 = A.blood_DNA[j] - var/found = 0 - for(var/k = 1, k <= blood.len, k++) //Lets see if the fiber is already in there - var/test_print2 = blood[k] - if(test_print2 == test_print1) //It is! Do nothing! - found = 1 - break - if(!found) //It isn't! Add! - blood += A.blood_DNA[j] - var/list/sum_list[3] //Pack it back up! - sum_list[1] = A - sum_list[2] = fibers - sum_list[3] = blood - misc[i] = sum_list //Store it! - break //We found it, we're done here. + if(!misc) + misc = list() + if(misc) + for(var/i = 1, i < (misc.len + 1), i++) //Lets see if we can find it. + var/list/templist = misc[i] + var/check = templist[1] + if(check == A) //There it is! + merged = 1 + var/list/fibers = templist[2] + if(!fibers) + fibers = list() + if(A.suit_fibers) + for(var/j = 1, j < (A.suit_fibers.len + 1), j++) //Fibers~~~ + if(!fibers.Find(A.suit_fibers[j])) //It isn't! Add! + fibers += A.suit_fibers[j] + var/list/blood = templist[3] + if(!blood) + blood = list() + if(A.blood_DNA) + for(var/j = 1, j < (A.blood_DNA.len + 1), j++) //Blood~~~ + if(!blood.Find(A.blood_DNA[j])) //It isn't! Add! + blood += A.blood_DNA[j] + var/list/sum_list[3] //Pack it back up! + sum_list[1] = A + sum_list[2] = fibers + sum_list[3] = blood + misc[i] = sum_list //Store it! + break //We found it, we're done here. if(!merged) //Nope! Guess we have to add it! var/list/templist[4] templist[1] = A @@ -184,30 +184,34 @@ obj/machinery/computer/forensic_scanning misc[misc.len] = templist //Store it! return !merged else //Has prints. - var/list/found_prints[A.fingerprints.len] - for(var/i = 1, i < found_prints.len, i++) + var/list/found_prints[A.fingerprints.len + 1] + for(var/i = 1, i < (found_prints.len + 1), i++) found_prints[i] = 0 - for(var/i = 1, i < files.len, i++) //Lets see if we can find the owner of the prints - var/merged = 0 + if(!files) + files = list() + for(var/i = 1, i < (files.len + 1), i++) //Lets see if we can find the owner of the prints var/list/perp_list = files[i] var/list/perp_prints = params2list(perp_list[1]) var/perp = perp_prints[1] - for(var/m = 1, m < A.fingerprints.len, m++) //Compare database prints with prints on object. + var/found2 = 0 + for(var/m = 1, m < (A.fingerprints.len + 1), m++) //Compare database prints with prints on object. var/list/test_prints_list = params2list(A.fingerprints[m]) var/checker = test_prints_list[1] if(checker == perp) //Found 'em! Merge! found_prints[m] = 1 - for(var/n = 2, n < perp_list.len, n++) //Lets see if it is already in the database + for(var/n = 2, n < (perp_list.len + 1), n++) //Lets see if it is already in the database var/list/target = perp_list[n] if(target[1] == A) //Found the original object! - merged = 1 + found2 = 1 var/list/prints = target[2] + if(!prints) + prints = list() if(A.fingerprints) - for(var/j = 1, j < A.fingerprints.len, j++) //Fingerprints~~~ + for(var/j = 1, j < (A.fingerprints.len + 1), j++) //Fingerprints~~~ var/list/print_test1 = params2list(A.fingerprints[j]) var/test_print1 = print_test1[1] var/found = 0 - for(var/k = 1, k <= prints.len, k++) //Lets see if the print is already in there + for(var/k = 1, k <= (prints.len + 1), k++) //Lets see if the print is already in there var/list/print_test2 = params2list(prints[k]) var/test_print2 = print_test2[1] if(test_print2 == test_print1) //It is! Merge! @@ -217,28 +221,18 @@ obj/machinery/computer/forensic_scanning if(!found) //It isn't! Add! prints += A.fingerprints[j] var/list/fibers = target[3] + if(!fibers) + fibers = list() if(A.suit_fibers) for(var/j = 1, j < A.suit_fibers.len, j++) //Fibers~~~ - var/test_print1 = A.suit_fibers[j] - var/found = 0 - for(var/k = 1, k <= fibers.len, k++) //Lets see if the fiber is already in there - var/test_print2 = fibers[k] - if(test_print2 == test_print1) //It is! Do nothing! - found = 1 - break //We found it, we're done here. - if(!found) //It isn't! Add! + if(!fibers.Find(A.suit_fibers[j])) //It isn't! Add! fibers += A.suit_fibers[j] var/list/blood = target[4] + if(!blood) + blood = list() if(A.blood_DNA) for(var/j = 1, j < A.blood_DNA.len, j++) //Blood~~~ - var/test_print1 = A.blood_DNA[j] - var/found = 0 - for(var/k = 1, k <= blood.len, k++) //Lets see if the blood is already in there - var/test_print2 = blood[k] - if(test_print2 == test_print1) //It is! Do nothing! - found = 1 - break //We found it, we're done here. - if(!found) //It isn't! Add! + if(!blood.Find(A.blood_DNA[j])) //It isn't! Add! blood += A.blood_DNA[j] var/list/sum_list[4] //Pack it back up! sum_list[1] = A @@ -248,65 +242,78 @@ obj/machinery/computer/forensic_scanning perp_list[n] = sum_list //Store it! files[i] = perp_list break //We found it, we're done here. - if(merged) - update_fingerprints(i) //Lets update the calculated sum of the stored prints. - for(var/m = 1, m < found_prints.len, m++) //Uh Oh! A print wasn't used! New datapoint! - if(found_prints.len[m] == 0) - var/list/newperp[2] - var/list/sum_list - sum_list[1] = A - sum_list[2] = A.fingerprints - sum_list[3] = A.suit_fibers - sum_list[4] = A.blood_DNA - newperp[2] = sum_list - newperp[1] = A.fingerprints[m] + if(!found2) //Add a new datapoint to this perp! + var/list/sum_list[4] + sum_list[1] = A + sum_list[2] = A.fingerprints + sum_list[3] = A.suit_fibers + sum_list[4] = A.blood_DNA + perp_list.len++ + perp_list[perp_list.len] = sum_list + files[i] = perp_list + for(var/m = 1, m < found_prints.len, m++) //Uh Oh! A print wasn't used! New datapoint! + if(found_prints[m] == 0) + var/list/newperp[2] + var/list/sum_list[4] + sum_list[1] = A + sum_list[2] = A.fingerprints + sum_list[3] = A.suit_fibers + sum_list[4] = A.blood_DNA + newperp[2] = sum_list + newperp[1] = A.fingerprints[m] + if(!files) + files = newperp + else files.len++ files[files.len] = newperp + update_fingerprints() //Lets update the calculated sum of the stored prints. + if(override) + A.fingerprints = backup_prints + A.suit_fibers = backup_fibers + A.blood_DNA = backup_DNA return - proc/update_fingerprints(var/index) //I am tired, but this updates the master print, which is used to determine completion of a print. - if(!index) - return - var/list/perp_list = files[1] - var/list/perp_prints = params2list(perp_list[1]) - var/perp = perp_prints[1] - var/list/found_prints = list() - for(var/i = 2, i < perp_list.len, i++) - var/list/test_list = perp_list[i] - var/list/test_prints = test_list[2] - for(var/j = 1, j < test_prints.len) - var/list/test_list_2 = params2list(test_prints[j]) - var/test_prints_2 = test_list_2[1] - if(test_prints_2 == perp) - found_prints += test_list_2[2] - break - for(var/prints in found_prints) - perp_prints[2] = stringmerge(perp_prints[2],prints) - perp_list[1] = perp + "&" + perp_prints[2] - files[1] = perp_list + proc/update_fingerprints() //I am tired, but this updates the master print, which is used to determine completion of a print. + for(var/k = 1, k < (files.len + 1), k++) + var/list/perp_list = files[k] + var/list/perp_prints = params2list(perp_list[1]) + var/perp = perp_prints[1] + var/list/found_prints = list() + for(var/i = 2, i < (perp_list.len + 1), i++) + var/list/test_list = perp_list[i] + var/list/test_prints = test_list[2] + for(var/j = 1, j < (test_prints.len + 1), j++) + var/list/test_list_2 = params2list(test_prints[j]) + var/test_prints_2 = test_list_2[1] + if(test_prints_2 == perp) + found_prints += test_list_2[2] + break + for(var/prints in found_prints) + perp_prints[2] = stringmerge(perp_prints[2],prints) + perp_list[1] = perp + "&" + perp_prints[2] + files[k] = perp_list return -// attackby(var/obj/item/device/detective_scanner/W as obj, mob/user as mob) -// ..() -// if (istype(W, /obj/item/device/detective_scanner)) -// -//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. -// -// var/list/data = W.stored -// if(files.len || misc.len) -// -// -// -// else -// -// -// src.add_fingerprint(user) -// if (W) -// W.add_fingerprint(user) -// return + proc/process_card() //I am tired, but this updates the master print from a fingerprint card + //which is used to determine completion of a print. + if(card.fingerprints) + for(var/k = 1, k < (card.fingerprints.len + 1), k++) + var/list/test_prints = params2list(card.fingerprints[k]) + var/print = test_prints[1] + for(var/i = 1, i < (files.len + 1), i++) + var/list/test_list = files[i] + var/list/perp_prints = params2list(test_list[1]) + var/perp = perp_prints[1] + if(perp == print) + test_list[1] = print + "&" + print + files[i] = test_list + break + del(card) + return + proc/get_name(var/atom/A) + return A.name Topic(href,href_list) switch(href_list["operation"]) @@ -349,6 +356,141 @@ obj/machinery/computer/forensic_scanning I.loc = src else temp = "Invalid Object Rejected." + if("card") + var/mob/M = usr + var/obj/item/I = M.equipped() + if(I && istype(I,/obj/item/weapon/f_card)) + card = I + M.drop_item() + I.loc = src + process_card() + usr << "You insert the card, and it is destroyed by the machinery in the process of comparing prints." + else + usr << "\red Invalid Object Rejected." + if("database") + canclear = 1 + if(!misc && !files) + temp = "Database is empty." + else + if(files) + temp = "Criminal Evidence Database

" + temp += "Consolidated data points:
" + for(var/i = 1, i < (files.len + 1), i++) + temp += "{Dossier [i]}
" + temp += "
{Insert Finger Print Card}


" + else + temp = "" + if(misc) + temp += "Auxiliary Evidence Database

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

" + for(var/i = 1, i < (misc.len + 1), i++) + var/list/temp_list = misc[i] + var/item_name = get_name(temp_list[1]) + temp += "{[item_name]}
" + if("record") + canclear = 0 + if(files) + temp = "Criminal Evidence Database

" + temp += "Consolidated data points: Dossier [href_list["identifier"]]
" + var/identifier = text2num(href_list["identifier"]) + var/list/dossier = files[identifier] + var/list/prints = params2list(dossier[1]) + var/print_string = "Fingerprints: Print not complete!
" + if(stringpercent(prints[2]) <= FINGERPRINT_COMPLETE) + print_string = "Fingerprints: (80% or higher completion reached)
" + prints[2] + "
" + temp += print_string + for(var/i = 2, i < (dossier.len + 1), i++) + var/list/outputs = dossier[i] + var/item_name = get_name(outputs[1]) + var/list/prints_len = outputs[2] + temp += "Object: [item_name]
" + temp += "    [prints_len.len] Unique fingerprints found.
" + var/list/fibers = outputs[3] + if(fibers) + var/dat = "[fibers[1]]" + for(var/j = 2, j < (fibers.len + 1), j++) + dat += ",
      [fibers[j]]" + temp += "    Fibers: [dat]
" + else + temp += "    No fibers found.
" + var/list/blood = outputs[4] + if(blood) + var/dat = "[blood[1]]" + if(blood.len > 1) + for(var/j = 2, j < (blood.len + 1), j++) + dat += ",
      [blood[j]]" + temp += "    Blood: [dat]
" + else + temp += "    No blood found.
" + else + temp = "ERROR. Database not found!
" + temp += "
{Print}" + temp += "
{Return}" + if("databaseprint") + if(files) + var/obj/item/weapon/paper/P = new(loc) + P.name = "Database File (Dossier [href_list["identifier"]])" + P.overlays += "paper_words" + P.info = "Criminal Evidence Database

" + P.info += "Consolidated data points: Dossier [href_list["identifier"]]
" + var/list/dossier = files[text2num(href_list["identifier"])] + var/list/prints = params2list(dossier[1]) + var/print_string = "Fingerprints: Print not complete!
" + if(stringpercent(prints[2]) <= FINGERPRINT_COMPLETE) + print_string = "Fingerprints: " + prints[2] + "
" + P.info += print_string + for(var/i = 2, i < (dossier.len + 1), i++) + var/list/outputs = dossier[i] + var/item_name = get_name(outputs[1]) + var/list/prints_len = outputs[2] + P.info += "Object: [item_name]
" + P.info += "    [prints_len.len] Unique fingerprints found.
" + var/list/fibers = outputs[3] + if(fibers) + var/dat = "[fibers[1]]" + for(var/j = 2, j < (fibers.len + 1), j++) + dat += ",
      [fibers[j]]" + P.info += "    Fibers: [dat]
" + else + P.info += "    No fibers found.
" + var/list/blood = outputs[4] + if(blood) + var/dat = "[blood[1]]" + if(blood.len > 1) + for(var/j = 2, j < (blood.len + 1), j++) + dat += ",
      [blood[j]]" + P.info += "    Blood: [dat]
" + else + P.info += "    No blood found." + else + usr << "ERROR. Database not found!
" + if("auxiliary") + canclear = 0 + if(misc) + temp = "Auxiliary Evidence Database

" + var/identifier = text2num(href_list["identifier"]) + var/list/outputs = misc[identifier] + var/item_name = get_name(outputs[1]) + temp += "Consolidated data points: [item_name]
" + var/list/fibers = outputs[2] + if(fibers) + var/dat = "[fibers[1]]" + for(var/j = 2, j < (fibers.len + 1), j++) + dat += ",
      [fibers[j]]" + temp += "    Fibers: [dat]
" + else + temp += "    No fibers found." + var/list/blood = outputs[3] + if(blood) + var/dat = "[blood[1]]" + for(var/j = 2, j < (blood.len + 1), j++) + dat += ",
      [blood[j]]" + temp += "    Blood: [dat]
" + else + temp += "    No blood found.
" + else + temp = "ERROR. Database not found!
" + temp += "
{Return}" if("scan") if(scanning) scan_process = 3 @@ -380,19 +522,19 @@ obj/machinery/computer/forensic_scanning scan_data = "[scanning]

" if (scanning.blood_DNA) scan_data += "Blood Found:
" - for(var/i = 1, i < scanning.blood_DNA.len, i++) + for(var/i = 1, i < (scanning.blood_DNA.len + 1), i++) var/list/templist = scanning.blood_DNA[i] scan_data += "-Blood type: [templist[2]]\nDNA: [templist[1]]

" else scan_data += "No Blood Found

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

" else var/list/L = scanning.fingerprints scan_data += "Isolated [L.len] Fingerprints. Loaded into database.
" add_data(scanning) - if(!scanning.suit_fibers.len) + if(!scanning.suit_fibers) /*if(istype(scanning,/obj/item/device/detective_scanner)) var/obj/item/device/detective_scanner/scanner = scanning if(scanner.stored_name) @@ -418,7 +560,8 @@ obj/machinery/computer/forensic_scanning scan_data += "- [data]
" if(istype(scanning,/obj/item/device/detective_scanner)) scan_data += "
Data transfered from Scanner to Database.
" - else if(!scanning.fingerprints.len) + add_data_scanner(scanning) + else if(!length(scanning.fingerprints)) scan_data += "
Add to Database?
" else temp = "Scan Failed: No Object" @@ -538,8 +681,8 @@ proc/get_tracks(mob/M) proc/blood_incompatible(donor,receiver) var - donor_antigen = copytext(donor,1,2) - receiver_antigen = copytext(receiver,1,2) + 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 diff --git a/code/WorkInProgress/meteors.dm b/code/WorkInProgress/meteors.dm new file mode 100644 index 0000000000..35c370fb0b --- /dev/null +++ b/code/WorkInProgress/meteors.dm @@ -0,0 +1,154 @@ +#define METEOR_TEMPERATURE + +/var/const/meteor_wave_delay = 625 //minimum wait between waves in tenths of seconds +//set to at least 100 unless you want evarr ruining every round + +/var/const/meteors_in_wave = 20 +/var/const/meteors_in_small_wave = 10 + +/proc/meteor_wave(var/number = meteors_in_wave) + if(!ticker || wavesecret) + return + + var/startx + var/starty + var/endx + var/endy + var/turf/pickedstart + var/turf/pickedgoal + switch(pick(1,2,3,4)) + if(1) //NORTH + starty = world.maxy-3 + startx = rand(1, world.maxx-1) + endy = 1 + endx = rand(1, world.maxx-1) + if(2) //EAST + starty = rand(1,world.maxy-1) + startx = world.maxx-3 + endy = rand(1, world.maxy-1) + endx = 1 + if(3) //SOUTH + starty = 3 + startx = rand(1, world.maxx-1) + endy = world.maxy-1 + endx = rand(1, world.maxx-1) + if(4) //WEST + starty = rand(1, world.maxy-1) + startx = 3 + endy = rand(1,world.maxy-1) + endx = world.maxx-1 + pickedstart = locate(startx, starty, 1) + pickedgoal = locate(endx, endy, 1) + wavesecret = 1 + for(var/i = 0 to number) + spawn(rand(10,100)) + spawn_meteor(pickedstart, pickedgoal) + spawn(meteor_wave_delay) + wavesecret = 0 + +/proc/spawn_meteors(var/turf/pickedstart, var/turf/pickedgoal, var/number = meteors_in_small_wave) + for(var/i = 0; i < number; i++) + spawn(0) + spawn_meteor(pickedstart, pickedgoal) + +/proc/spawn_meteor(var/turf/pickedstart, var/turf/pickedgoal) + + var/route = rand(1,5) + var/turf/tempgoal = pickedgoal + for(var/i, i < route, i++) + tempgoal = get_step(tempgoal,rand(1,8)) + + var/obj/effect/meteor/M + switch(rand(1, 100)) + if(1 to 15) + M = new /obj/effect/meteor/big(pickedstart) + if(16 to 75) + M = new /obj/effect/meteor( pickedstart ) + if(76 to 100) + M = new /obj/effect/meteor/small( pickedstart ) + + M.dest = tempgoal + + do + sleep(1) + walk_towards(M, M.dest, 1) + while (!istype(M.loc, /turf/space) || pickedstart.loc.name != "Space" ) //FUUUCK, should never happen. + + return + +/obj/effect/meteor + name = "meteor" + icon = 'meteor.dmi' + icon_state = "flaming" + density = 1 + anchored = 1.0 + var/hits = 1 + var/dest + pass_flags = PASSTABLE + +/obj/effect/meteor/small + name = "small meteor" + icon_state = "smallf" + pass_flags = PASSTABLE | PASSGRILLE + +/obj/effect/meteor/Move() + var/turf/T = src.loc + if (istype(T, /turf)) + T.hotspot_expose(METEOR_TEMPERATURE, 1000) + ..() + return + +/obj/effect/meteor/Bump(atom/A) + spawn(0) + for(var/mob/M in range(10, src)) + if(!M.stat && !istype(M, /mob/living/silicon/ai)) //bad idea to shake an ai's view + shake_camera(M, 3, 1) + if (A) + A.meteorhit(src) + playsound(src.loc, 'meteorimpact.ogg', 40, 1) + if (--src.hits <= 0) + if(prob(15))// && !istype(A, /obj/structure/grille)) + explosion(src.loc, 4, 5, 6, 7, 0) + playsound(src.loc, "explosion", 50, 1) + del(src) + return + + +/obj/effect/meteor/ex_act(severity) + + if (severity < 4) + del(src) + return + +/obj/effect/meteor/big + name = "big meteor" + hits = 5 + + ex_act(severity) + return + + Bump(atom/A) + spawn(0) + for(var/mob/M in range(10, src)) + if(!M.stat && !istype(M, /mob/living/silicon/ai)) //bad idea to shake an ai's view + shake_camera(M, 3, 1) + if (A) + if(isobj(A)) + del(A) + else + A.meteorhit(src) + src.hits-- + return + playsound(src.loc, 'meteorimpact.ogg', 40, 1) + if (--src.hits <= 0) + if(prob(15) && !istype(A, /obj/structure/grille)) + explosion(src.loc, 1, 2, 3, 4, 0) + playsound(src.loc, "explosion", 50, 1) + del(src) + return + +/obj/effect/meteor/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/pickaxe)) + del(src) + return + ..() \ No newline at end of file diff --git a/code/defines/atom.dm b/code/defines/atom.dm index df67c32085..5db2913830 100644 --- a/code/defines/atom.dm +++ b/code/defines/atom.dm @@ -2,7 +2,7 @@ layer = 2 var/level = 2 var/flags = FPRINT - var/list/fingerprints + var/list/fingerprints = list() var/list/fingerprintshidden = new/list() var/fingerprintslast = null var/list/blood_DNA = null diff --git a/code/game/atom_procs.dm b/code/game/atom_procs.dm index 02753978f7..b4cde466f1 100644 --- a/code/game/atom_procs.dm +++ b/code/game/atom_procs.dm @@ -93,32 +93,25 @@ src.fingerprintshidden += text("(Wearing gloves). Real name: [], Key: []",H.real_name, H.key) src.fingerprintslast = H.key return 0 - if (!( src.fingerprints )) - src.fingerprints = list(text("[]&[]", md5(H.dna.uni_identity), stars(md5(H.dna.uni_identity), rand(40,60)))) - if(src.fingerprintslast != H.key) - src.fingerprintshidden += text("Real name: [], Key: []",H.real_name, H.key) - src.fingerprintslast = H.key - return 1 else if(src.fingerprintslast != H.key) src.fingerprintshidden += text("Real name: [], Key: []",H.real_name, H.key) src.fingerprintslast = H.key var/new_prints = 0 var/prints - for(var/i = 1, i < src.fingerprints.len, i++) + for(var/i = 1, i < (src.fingerprints.len + 1), i++) var/list/L = params2list(src.fingerprints[i]) if(L[1] == md5(H.dna.uni_identity)) new_prints = i prints = L[2] break else - src.fingerprints[i] = L[1] + "&" + stars(L[2], rand(90,95)) + src.fingerprints[i] = L[1] + "&" + stars(L[2], rand(80,90)) if(new_prints) - src.fingerprints[new_prints] = list(text("[]&[]", md5(H.dna.uni_identity), stringmerge(prints,stars(md5(H.dna.uni_identity), rand(40,60))))) - return 1 - else - src.fingerprints += text("[]&[]", md5(H.dna.uni_identity), stars(md5(H.dna.uni_identity), rand(40,60))) - return 1 + src.fingerprints[new_prints] = text("[]&[]", md5(H.dna.uni_identity), stringmerge(prints,stars(md5(H.dna.uni_identity), rand(15,30)))) + else if(new_prints == 0) + src.fingerprints += text("[]&[]", md5(H.dna.uni_identity), stars(md5(H.dna.uni_identity), rand(15,30))) + return 1 else if(src.fingerprintslast != M.key) src.fingerprintshidden += text("Real name: [], Key: []",M.real_name, M.key) @@ -140,26 +133,37 @@ I.Blend(new /icon('blood.dmi', "itemblood"),ICON_MULTIPLY) I.Blend(new /icon(src.icon, src.icon_state),ICON_UNDERLAY) src.icon = I - src.blood_DNA.len++ - src.blood_DNA[src.blood_DNA.len] = list(M.dna.unique_enzymes, M.b_type) + if(src.blood_DNA) + src.blood_DNA.len++ + src.blood_DNA[src.blood_DNA.len] = list(M.dna.unique_enzymes,M.b_type) + else + var/list/blood_DNA_temp[1] + blood_DNA_temp[1] = list(M.dna.unique_enzymes, M.b_type) + src.blood_DNA = blood_DNA_temp else if (istype(src, /turf/simulated)) var/turf/simulated/source2 = src var/list/objsonturf = range(0,src) - var/i - for(i=1, i<=objsonturf.len, i++) - if(istype(objsonturf[i],/obj/effect/decal/cleanable/blood)) - return + if(objsonturf) + for(var/i=1, i<=objsonturf.len, i++) + if(istype(objsonturf[i],/obj/effect/decal/cleanable/blood)) + return var/obj/effect/decal/cleanable/blood/this = new /obj/effect/decal/cleanable/blood(source2) - this.blood_DNA.len++ - this.blood_DNA[this.blood_DNA.len] = list(M.dna.unique_enzymes, M.b_type) + var/list/blood_DNA_temp[1] + blood_DNA_temp[1] = list(M.dna.unique_enzymes, M.b_type) + this.blood_DNA = blood_DNA_temp this.virus2 = M.virus2 for(var/datum/disease/D in M.viruses) var/datum/disease/newDisease = new D.type this.viruses += newDisease newDisease.holder = this else if (istype(src, /mob/living/carbon/human)) - src.blood_DNA.len++ - src.blood_DNA[src.blood_DNA.len] = list(M.dna.unique_enzymes,M.b_type) + if(src.blood_DNA) + src.blood_DNA.len++ + src.blood_DNA[src.blood_DNA.len] = list(M.dna.unique_enzymes,M.b_type) + else + var/list/blood_DNA_temp[1] + blood_DNA_temp[1] = list(M.dna.unique_enzymes, M.b_type) + src.blood_DNA = blood_DNA_temp else return else diff --git a/code/game/dna.dm b/code/game/dna.dm index c94ca9f46f..acb1d477f6 100644 --- a/code/game/dna.dm +++ b/code/game/dna.dm @@ -69,7 +69,6 @@ unique_enzymes = md5(character.real_name) original_name = character.real_name - b_type = character.b_type reg_dna[unique_enzymes] = character.real_name /////////////////////////// DNA DATUM diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index 9c4492eadf..000a13d8da 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -109,7 +109,8 @@ objective = steal_objective var/inthere = 0 for(var/j, j<= target.len, j++) - if(target[j] == objective) + var/datum/objective/temp = target[j] + if(temp:target == objective:target) inthere = 1 break if(!inthere) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 5389935bd4..d5144e09d0 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -429,6 +429,8 @@ About the new airlock wires panel: return 0 if(!prob(prb)) return 0 //you lucked out, no shock for you + if(istype(usr.equipped(),/obj/item/weapon/shard)) + return 0 var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(5, 1, src) s.start() //sparks always. @@ -817,10 +819,10 @@ About the new airlock wires panel: usr.machine = src if (href_list["wires"]) var/t1 = text2num(href_list["wires"]) - if (!( istype(usr.equipped(), /obj/item/weapon/wirecutters) )) + if (!istype(usr.equipped(), /obj/item/weapon/wirecutters) || !istype(usr.equipped(),/obj/item/weapon/shard)) usr << "You need wirecutters!" return - if (src.isWireColorCut(t1)) + if (src.isWireColorCut(t1) && istype(usr.equipped(), /obj/item/weapon/wirecutters)) src.mend(t1) else src.cut(t1) diff --git a/code/game/objects/closets/secure/security.dm b/code/game/objects/closets/secure/security.dm index fb964a64f9..a1da400009 100644 --- a/code/game/objects/closets/secure/security.dm +++ b/code/game/objects/closets/secure/security.dm @@ -85,7 +85,7 @@ /obj/structure/closet/secure_closet/detective name = "Detective" req_access = list(access_forensics_lockers) - icon_state = "cabinetdetective" + icon_state = "cabinetdetective_locked" icon_closed = "cabinetdetective" icon_locked = "cabinetdetective_locked" icon_opened = "cabinetdetective_open" diff --git a/code/game/objects/devices/scanners.dm b/code/game/objects/devices/scanners.dm index 06b16694e8..ab5f245e49 100644 --- a/code/game/objects/devices/scanners.dm +++ b/code/game/objects/devices/scanners.dm @@ -131,7 +131,7 @@ MASS SPECTROMETER user << "\blue Blood type: [templist[2]]\nDNA: [templist[1]]" return - afterattack(atom/A as mob|obj|turf|area, mob/user as mob) + afterattack(atom/A as obj|turf|area, mob/user as mob) if(src.loc != user) return 0 src.add_fingerprint(user) @@ -141,34 +141,42 @@ MASS SPECTROMETER var/list/templist = A.blood_DNA[i] user << "\blue Blood type: [templist[2]]\nDNA: [templist[1]]" return - if (!( A.fingerprints ) && !(A.suit_fibers) && !(A.blood_DNA)) + var/duplicate = 0 + if ((!A.fingerprints || A.fingerprints.len == 0) && !(A.suit_fibers) && !(A.blood_DNA)) user << "\blue Unable to locate any fingerprints, materials, fibers, or blood on [A]!" return 0 else if (A.blood_DNA) user << "\blue Blood found on [A]. Analysing..." sleep(15) - var/duplicate = add_data(A) - if(duplicate) - user << "\blue Blood already in memory." - for(var/i = 1, i < A.blood_DNA.len, i++) + if(!duplicate) + duplicate = 1 + var/i = add_data(A) + if(i) + user << "\blue Blood already in memory." + for(var/i = 1, i < (A.blood_DNA.len + 1), i++) var/list/templist = A.blood_DNA[i] user << "\blue Blood type: [templist[2]]\nDNA: [templist[1]]" else user << "\blue No Blood Located" - if(!( A.fingerprints )) + if(!A.fingerprints || A.fingerprints.len == 0) user << "\blue No Fingerprints Located." else user << text("\blue Isolated [A.fingerprints.len] fingerprints: Data Stored: Scan with Hi-Res Forensic Scanner to retrieve.") - var/duplicate = add_data(A) - if(duplicate) - user << "\blue Figerprints already in memory." + if(!duplicate) + duplicate = 1 + var/i = add_data(A) + if(i) + user << "\blue Fingerprints already in memory." if(!A.suit_fibers) user << "\blue No Fibers/Materials Located." else user << "\blue Fibers/Materials Data Stored: Scan with Hi-Res Forensic Scanner to retrieve." - var/duplicate = add_data(A) - if(duplicate) - user << "\blue Fibers/Materials already in memory." + + if(!duplicate) + duplicate = 1 + var/i = add_data(A) + if(i) + user << "\blue Fibers/Materials already in memory." // else // if ((src.amount < 1 && src.printing)) // user << "\blue Fingerprints found. Need more cards to print." @@ -188,18 +196,20 @@ MASS SPECTROMETER proc/add_data(atom/A as mob|obj|turf|area) var/merged = 0 - for(var/i = 1, i < stored.len, i++) //Lets see if the object is already in there! + for(var/i = 1, i < (stored.len + 1), i++) //Lets see if the object is already in there! var/list/temp = stored[i] var/checker = temp[1] if(checker == A) //It is! Merge! merged = 1 var/list/prints = temp[2] + if(!prints) + prints = list() if(A.fingerprints) - for(var/j = 1, j < A.fingerprints.len, j++) //Fingerprints~~~ + for(var/j = 1, j < (A.fingerprints.len + 1), j++) //Fingerprints~~~ var/list/print_test1 = params2list(A.fingerprints[j]) var/test_print1 = print_test1[1] var/found = 0 - for(var/k = 1, k <= prints.len, k++) //Lets see if the print is already in there + for(var/k = 1, k < (prints.len + 1), k++) //Lets see if the print is already in there var/list/print_test2 = params2list(prints[k]) var/test_print2 = print_test2[1] if(test_print2 == test_print1) //It is! Merge! @@ -209,28 +219,18 @@ MASS SPECTROMETER if(!found) //It isn't! Add! prints += A.fingerprints[j] var/list/fibers = temp[3] + if(!fibers) + fibers = list() if(A.suit_fibers) - for(var/j = 1, j < A.suit_fibers.len, j++) //Fibers~~~ - var/test_print1 = A.suit_fibers[j] - var/found = 0 - for(var/k = 1, k <= fibers.len, k++) //Lets see if the fiber is already in there - var/test_print2 = fibers[k] - if(test_print2 == test_print1) //It is! Do nothing! - found = 1 - break //We found it, we're done here. - if(!found) //It isn't! Add! + for(var/j = 1, j < (A.suit_fibers.len + 1), j++) //Fibers~~~ + if(!fibers.Find(A.suit_fibers[j])) //It isn't! Add! fibers += A.suit_fibers[j] var/list/blood = temp[4] + if(!blood) + blood = list() if(A.blood_DNA) - for(var/j = 1, j < A.blood_DNA.len, j++) //Blood~~~ - var/test_print1 = A.blood_DNA[j] - var/found = 0 - for(var/k = 1, k <= blood.len, k++) //Lets see if the blood is already in there - var/test_print2 = blood[k] - if(test_print2 == test_print1) //It is! Do nothing! - found = 1 - break //We found it, we're done here. - if(!found) //It isn't! Add! + for(var/j = 1, j < (A.blood_DNA.len + 1), j++) //Blood~~~ + if(!blood.Find(A.blood_DNA[j])) //It isn't! Add! blood += A.blood_DNA[j] var/list/sum_list[4] //Pack it back up! sum_list[1] = A @@ -247,7 +247,7 @@ MASS SPECTROMETER sum_list[4] = A.blood_DNA stored.len++ stored[stored.len] = sum_list - return !merged + return merged /obj/item/device/healthanalyzer diff --git a/code/game/objects/items/item.dm b/code/game/objects/items/item.dm index 351dd922f5..a2167decfb 100644 --- a/code/game/objects/items/item.dm +++ b/code/game/objects/items/item.dm @@ -228,7 +228,7 @@ user << "\blue The wardrobe is full." return user << "\blue You pick up all the items." - user.visible_message("\blue [user] gathers up the pile of stuff, and puts it into \the [src]") + user.visible_message("\blue [user] gathers up the pile of stuff, and puts it into \the [W]") I.update_icon() /obj/item/attack_self(mob/user as mob) diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index 8352ccf718..482271c349 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -201,11 +201,11 @@ FINGERPRINT CARD /obj/item/weapon/f_card/proc/display() - if (src.fingerprints) + if (length(src.fingerprints)) var/dat = "Fingerprints on Card
" - var/L = params2list(src.fingerprints) - for(var/i in L) - dat += text("[]
", i) + for(var/i = 1, i < (src.fingerprints.len + 1), i++) + var/list/L = params2list(src.fingerprints[i]) + dat += text("[]
", L[1]) //Foreach goto(41) return dat else @@ -270,7 +270,7 @@ FINGERPRINT CARD ..() if (!istype(usr, /mob/living/silicon)) - if (src.fingerprints) + if (length(src.fingerprints)) if (src.amount > 1) var/obj/item/weapon/f_card/F = new /obj/item/weapon/f_card( (ismob(src.loc) ? src.loc.loc : src.loc) ) F.amount = --src.amount diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 14c44bc578..686339aa6a 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -19,15 +19,10 @@ usr << "Your message has been broadcast to administrators." log_admin("HELP: [key_name(src)]: [msg]") - var/list/replacechars = list("'","\"",">","<","(",")") +/* var/list/replacechars = list("'","\"",">","<","(",")") for(var/rep in replacechars) - var/list/temp = dd_text2list(msg, rep) - if(temp.len > 1) - for(var/i = 1, i < temp.len, i++) - world << temp[i] - temp[i] = copytext(temp[i],1,lentext(temp[i])) - msg = dd_list2text(temp) - world << msg + msg = dd_replacetext(msg, rep, "") + world << msg*/ send2adminirc("#bs12admin","HELP: [src.key]: [msg]") if(tension_master) tension_master.new_adminhelp() diff --git a/code/modules/chemical/Chemistry-Machinery.dm b/code/modules/chemical/Chemistry-Machinery.dm index c5570ee26b..aebb052e6e 100644 --- a/code/modules/chemical/Chemistry-Machinery.dm +++ b/code/modules/chemical/Chemistry-Machinery.dm @@ -196,19 +196,27 @@ return attackby(var/obj/item/weapon/reagent_containers/glass/B as obj, var/mob/user as mob) - if(!istype(B, /obj/item/weapon/reagent_containers/glass)) + if(!istype(B, /obj/item/weapon/reagent_containers/glass) && !istype(B,/obj/item/weapon/reagent_containers/syringe)) return if(src.beaker) - user << "A beaker is already loaded into the machine." + if(istype(beaker,/obj/item/weapon/reagent_containers/syringe)) + user << "A syringe is already loaded into the machine." + else + user << "A beaker is already loaded into the machine." return src.beaker = B user.drop_item() B.loc = src - user << "You add the beaker to the machine!" - src.updateUsrDialog() - icon_state = "mixer1" + if(istype(B,/obj/item/weapon/reagent_containers/syringe)) + user << "You add the syringe to the machine!" + src.updateUsrDialog() + icon_state = "mixers" + else + user << "You add the beaker to the machine!" + src.updateUsrDialog() + icon_state = "mixer1" Topic(href, href_list) if(stat & BROKEN) return @@ -222,7 +230,18 @@ if (href_list["analyze"]) var/dat = "" if(!condi) - dat += "Chemmaster 3000Chemical infos:

Name:
[href_list["name"]]

Description:
[href_list["desc"]]


(Back)" + if(href_list["name"] == "Blood") + var/datum/reagent/blood/G + for(var/datum/reagent/F in R.reagent_list) + if(F.name == href_list["name"]) + G = F + break + var/A = G.name + var/B = G.data["blood_type"] + var/C = G.data["blood_DNA"] + dat += "Chemmaster 3000Chemical infos:

Name:
[A]

Description:
Blood Type: [B]
DNA: [C]


(Back)" + else + dat += "Chemmaster 3000Chemical infos:

Name:
[href_list["name"]]

Description:
[href_list["desc"]]


(Back)" else dat += "Condimaster 3000Condiment infos:

Name:
[href_list["name"]]

Description:
[href_list["desc"]]


(Back)" usr << browse(dat, "window=chem_master;size=575x400") @@ -316,7 +335,7 @@ dat += "Add to buffer:
" for(var/datum/reagent/G in R.reagent_list) dat += "[G.name] , [G.volume] Units - " - dat += "(Analyze) " + dat += "(Analyze) " dat += "(1) " if(G.volume >= 5) dat += "(5) " if(G.volume >= 10) dat += "(10) " diff --git a/code/modules/chemical/Chemistry-Reagents.dm b/code/modules/chemical/Chemistry-Reagents.dm index 5402eda0c3..52062de5e8 100644 --- a/code/modules/chemical/Chemistry-Reagents.dm +++ b/code/modules/chemical/Chemistry-Reagents.dm @@ -101,6 +101,12 @@ datum id = "blood" reagent_state = LIQUID color = "#C80000" // rgb: 200, 0, 0 + on_mob_life(var/mob/living/M) + if(istype(M, /mob/living/carbon/human) && blood_incompatible(data["blood_type"],M.dna.b_type)) + M.adjustToxLoss(rand(1.5,3)) + M.adjustOxyLoss(rand(1.5,3)) + ..() + return reaction_mob(var/mob/M, var/method=TOUCH, var/volume) var/datum/reagent/blood/self = src diff --git a/code/modules/chemical/Chemistry-Tools.dm b/code/modules/chemical/Chemistry-Tools.dm index b7531cfb1d..9f7d5ec418 100644 --- a/code/modules/chemical/Chemistry-Tools.dm +++ b/code/modules/chemical/Chemistry-Tools.dm @@ -863,6 +863,7 @@ amount_per_transfer_from_this = 5 possible_transfer_amounts = null //list(5,10,15) volume = 15 + var/has_blood = 0 var/mode = SYRINGE_DRAW on_reagent_change() @@ -1023,6 +1024,10 @@ update_icon() var/rounded_vol = round(reagents.total_volume,5) + has_blood = 0 + for(var/datum/reagent/blood/B in reagents.reagent_list) + has_blood = 1 + break if(ismob(loc)) var/mode_t switch(mode) @@ -1030,9 +1035,9 @@ mode_t = "d" if (SYRINGE_INJECT) mode_t = "i" - icon_state = "[mode_t][rounded_vol]" + icon_state = "[mode_t][(has_blood?"b":"")][rounded_vol]" else - icon_state = "[rounded_vol]" + icon_state = "[(has_blood?"b":"")][rounded_vol]" item_state = "syringe_[rounded_vol]" diff --git a/code/modules/mob/living/carbon/give.dm b/code/modules/mob/living/carbon/give.dm index b551bfb86e..5226f4d9bb 100644 --- a/code/modules/mob/living/carbon/give.dm +++ b/code/modules/mob/living/carbon/give.dm @@ -1,4 +1,5 @@ mob/living/carbon/verb/give() + set category = "IC" set name = "Give" set src in view(1) if(src.stat == 2 || usr.stat == 2|| src.client == null) @@ -42,6 +43,7 @@ mob/living/carbon/verb/give() src.l_hand = I else usr << "Their hands are full." + return else usr.drop_item(I) src.r_hand = I @@ -70,6 +72,7 @@ mob/living/carbon/verb/give() src.r_hand = I else usr << "Their hands are full." + return else usr.drop_item(I) src.l_hand = I diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index dd398804db..67773f5f5f 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -112,6 +112,7 @@ emp_act else H.add_blood(src) if(H.wear_suit) H.wear_suit.add_blood(src) else if(H.w_uniform) H.w_uniform.add_blood(src) + if(H.shoes) H.shoes.add_blood(src) switch(hit_area) if("head")//Harder to score a stun but if you do it lasts a bit longer diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 1c1eee6d2a..87c6f98191 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -354,6 +354,7 @@ proc/create_character() spawning = 1 var/mob/living/carbon/human/new_character = new(loc) + new_character.be_syndicate = src.preferences.be_special close_spawn_windows() diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi index 08a708f72ba54659d29810bf08cf5b4331698090..d52b9b7be1e3f6811c02ca89d838df15b0797cb3 100644 GIT binary patch delta 10976 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 G@c#ppkZ*zj delta 10037 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 diff --git a/icons/obj/syringe.dmi b/icons/obj/syringe.dmi index 08d86cb7e5d587eca6737deee362ff519926a74c..022680cda984a70bf74336ba1cb6333de7e385f9 100644 GIT binary patch delta 1046 zcmV+x1nK*;2lNObiBL{Q4GJ0x0000DNk~Le0002M0001>2m=5B0B!b@Z;>HNk#Q$~ z%m6cKX=x@VCVa{8R<7f~z`(qc>+%2q00DGTPE!Ct=GbNc006goR9JLGWpiV4X>fFD zZ*Bkpc$|%sK?=e!5JlI?DMGuKM(xs#v`82B4h<8{EVPmYrMGXe;L`cK8F>8v!jRgW z`^zwz?mFnVkBR4}Iho_G(dxsLLs<@gd#!@!d&t|8@|1lUD_dzr98;OCR<}4k{5JoH zMkHF1uyTl%Q(8HN0Yolhz?T7G28;DIG%ZC7j2w)ho zCIn*SZS)7KO+R+uFTVn=+YBm%)FLSW00QJmL_t(|ob8+qdzvs5g#qVB=4KavyRlkC zu&&+z|Azwt$Y{u=gqWnB_fcy-M(*JvJf4U_000000002EbHd^pEd*a|7c+$@48z58 zxms^F8}^lLx7%;u|9?iPHW;c`fN}+ebq!N>asjo)!r*eb+wG(Vi#4!_3f2!lWO}uN zqG+|2>7`ietJO4p9FBJY0001g0000WgO`Xq?JaLEjXsEdJ>dHSUj5%FLx{E7gXct zte>%%MZce(4srt%&krER&&PAZ;y7l-oXGz#kFxx|$@ec8xqdak2HyfyzE9}N z`bdZ4JHYaxEy#2S=0Rb=4-&?5uMMOu_uN375A1|IA^r3E=C^??`RliXBu(Fa9smFU z;5cneJu#ox9j}dPZa#1P`~cd3UOrESv(^pta0N^R!|2n1A}0001>2m=5B0K5^GACVzS2Fw66 zz`($fYbSqcX=x@VCVa{8R<7e|d2)0B0004WQchCV=-0C=2@lfeqYFc3t~$ybE-E{)ow7ip0m>_0SYG<(oW5|sXZg9UH0bDM?7%)4xD z&i!Q=O?Msi+sDN7)11t4*J$-&%Ap*Gy;i~VJ>-AwNO{V>#L8A$5yw=r)#?_fhu`v# zXhfnF2`iUaxuum`7(nD927DP1X26&LL|!7mm;hq}j2(c;OAau0fN@w}^FOFI{n&lq zVg+ic(Y&ynfpq`?0x?NMK~#90?U)O9qA(PMA+C?Cty}1>hphsFef|Gm*gzucHYVvK z-m8B*-+_pZgvkwZ%p?f_0000007XU!F7k#LA-Nx5LN_gBs|5kr~7X1ST^Zf{| z7l@;K{aHIu#Wx+q)&mNd=ce>|Uw(5iTp+R@P{9)q0CNk+)&T%lKv23wnQjH;bCmfY z`w9X800017HF}lW9}I1_+s>t*B+*O%exbih%Q6$E97F@Lb!R?zkc++Bl5^<$@Wy|h z&rur;%I`9h>X`YkUm%hml;1I#VtYPEZqS#{ksI{obHiic;5k0Qj%*<#Xit@;P#R(E~Y`WAIcyN6qC_5C%WVm-D&UAfE%^ z;$fd|eP=#+|ND<4A6(ws^xgHBOS^y0zk&b&00000fbXGORZx3yA*3v%`1|m%qIP0u zUCN>;WVKrHG`L<1p(x~4Yaq-lBkORB1(w&0}fpf=&4Y_?6od5+7+ z?Y7`u!N-QVLFJG26ieQ>pfcF9p5aR{C|lMBYuPe4ShTEv#7X`1{KDH{Q@$bcc39Rm f^Z$bYfPZ-d$|bpl)3pj400000NkvXXu0mjfjG2`{