diff --git a/baystation12.dme b/baystation12.dme index 5699e226a80..2355bffb6db 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -882,6 +882,8 @@ #include "code\modules\customitems\item_spawning.dm" #include "code\modules\DetectiveWork\detective_work.dm" #include "code\modules\DetectiveWork\evidence.dm" +#include "code\modules\DetectiveWork\footprints_and_rag.dm" +#include "code\modules\DetectiveWork\scanner.dm" #include "code\modules\flufftext\Dreaming.dm" #include "code\modules\flufftext\Hallucination.dm" #include "code\modules\flufftext\TextFilters.dm" diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm index bf54f9bb601..8343001fc8b 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -1030,7 +1030,7 @@ icon_state = "cone" /obj/item/weapon/paper - name = "Paper" + name = "\improper Paper" icon = 'paper.dmi' icon_state = "paper" var/info = null diff --git a/code/game/atom_procs.dm b/code/game/atom_procs.dm index e710ce0e136..26a7c6a5132 100644 --- a/code/game/atom_procs.dm +++ b/code/game/atom_procs.dm @@ -104,13 +104,6 @@ if(isnull(M.key)) return if (!( src.flags ) & FPRINT) return - //Smudge up dem prints some - for(var/P in fingerprints) - var/test_print = stars(fingerprints[P], rand(85,95)) - if(stringpercent(test_print) == 32) //She's full of stars! (No actual print left) - fingerprints.Remove(P) - else - fingerprints[P] = test_print if (ishuman(M)) //Add the list if it does not exist. if(!fingerprintshidden) @@ -142,6 +135,15 @@ return 0 else if(H.gloves && !istype(H.gloves, /obj/item/clothing/gloves/latex) && !istype(H.gloves, /obj/item/clothing/gloves/fingerless)) return 0 + //Smudge up dem prints some + for(var/P in fingerprints) + if(P == md5(H.dna.uni_identity)) + continue + var/test_print = stars(fingerprints[P], rand(85,95)) + if(stringpercent(test_print) == 32) //She's full of stars! (No actual print left) + fingerprints.Remove(P) + else + fingerprints[P] = test_print //More adminstuffz if(fingerprintslast != H.key) fingerprintshidden += text("Real name: [], Key: []",H.real_name, H.key) @@ -160,6 +162,13 @@ fingerprints[full_print] = stringmerge(print, stars(full_print, (H.gloves ? rand(10,20) : rand(25,40)))) return 1 else + //Smudge up dem prints some + for(var/P in fingerprints) + var/test_print = stars(fingerprints[P], rand(85,95)) + if(stringpercent(test_print) == 32) //She's full of stars! (No actual print left) + fingerprints.Remove(P) + else + fingerprints[P] = test_print if(fingerprintslast != M.key) fingerprintshidden += text("Real name: [], Key: []",M.real_name, M.key) fingerprintslast = M.key diff --git a/code/game/machinery/kitchen/gibber.dm b/code/game/machinery/kitchen/gibber.dm index c00d181d9f7..146867ffda8 100644 --- a/code/game/machinery/kitchen/gibber.dm +++ b/code/game/machinery/kitchen/gibber.dm @@ -181,7 +181,7 @@ allmeat += newmeat for (var/mob/M in world) - if (M.client && M.client.holder && (M.client.holder.level != -3)) + if (M.client && M.client.holder && (M.client.holder.level != -3) && (M.client.holder.level != 0)) M << "\red [user.name]/[user.ckey] has gibbed [src.occupant.name]/[src.occupant.ckey]" src.occupant.death(1) src.occupant.ghostize() diff --git a/code/game/objects/devices/scanners.dm b/code/game/objects/devices/scanners.dm index 9e3775f3c6a..4d2a52722d3 100644 --- a/code/game/objects/devices/scanners.dm +++ b/code/game/objects/devices/scanners.dm @@ -61,167 +61,6 @@ MASS SPECTROMETER M.invisibility = 2 -/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 | USEDELAY - 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." - return 0 - if (( !( istype(M.dna, /datum/dna) ) || M.gloves) ) - user << "\blue No fingerprints found on [M]" - return 0 - else - if (src.amount < 1) - user << text("\blue Fingerprints scanned on [M]. Need more cards to print.") - 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) - 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) - user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.get_gender_form("it")] humming[prob(70) ? " gently." : "."]" ,\ - "\blue Unable to locate any fingerprints, materials, fibers, or blood on [A]!",\ - "You hear a faint hum of electrical equipment.") - return 0 - - if(add_data(A)) - user << "\blue Object already in internal memory. Consolidating data..." - return - - - //PRINTS - if(!A.fingerprints || !A.fingerprints.len) - if(A.fingerprints) - del(A.fingerprints) - else - user << "\blue Isolated [A.fingerprints.len] fingerprints: Data Stored: Scan with Hi-Res Forensic Scanner to retrieve." - - //FIBERS - if(A.suit_fibers) - user << "\blue Fibers/Materials Data Stored: Scan with Hi-Res Forensic Scanner to retrieve." - - //Blood - if (A.blood_DNA) - user << "\blue Blood found on [A]. Analysing..." - spawn(15) - for(var/blood in A.blood_DNA) - user << "Blood type: \red [A.blood_DNA[blood]] \t \black DNA: \red [blood]" - if(prob(5)) - user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.get_gender_form("it")] humming[prob(70) ? " gently." : "."]" ,\ - "You finish scanning \the [A].",\ - "You hear a faint hum of electrical equipment.") - return 0 - else - user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.get_gender_form("it")] humming[prob(70) ? " gently." : "."]\n[user.get_gender_form("It")] seems to perk up slightly at the readout." ,\ - "The results of the scan pique your interest.",\ - "You hear a faint hum of electrical equipment, and someone making a thoughtful noise.") - return 0 - return - - proc/add_data(atom/A as mob|obj|turf|area) - //I love hashtables. - var/list/data_entry = stored["\ref [A]"] - if(islist(data_entry)) //Yay, it was already stored! - //Merge the fingerprints. - var/list/data_prints = data_entry[1] - for(var/print in A.fingerprints) - var/merged_print = data_prints[print] - if(!merged_print) - data_prints[print] = A.fingerprints[print] - 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 - sum_list[2] = A.suit_fibers - sum_list[3] = A.blood_DNA - sum_list[4] = "\The [A] in \the [get_area(A)]" - stored["\ref [A]"] = sum_list - return 0 - - /obj/item/device/healthanalyzer name = "Health Analyzer" icon_state = "health" diff --git a/code/game/verbs/ooc.dm b/code/game/verbs/ooc.dm index 4b4d39d32b3..d138c6ece49 100644 --- a/code/game/verbs/ooc.dm +++ b/code/game/verbs/ooc.dm @@ -37,11 +37,13 @@ log_ooc("[src.name]/[src.key] : [msg]") for (var/client/C) - if (src.client.holder && (!src.client.stealth || C.holder)) + if (src.client.holder && (!src.client.stealth || ( C.holder && C.holder.level != 0))) if (src.client.holder.rank == "Admin Observer") C << "OOC: [src.key][src.client.stealth ? "/([src.client.fakekey])" : ""]: [msg]" else if (src.client.holder.rank == "Retired Admin") C << "OOC: [src.key][src.client.stealth ? "/([src.client.fakekey])" : ""]: [msg]" + else if (src.client.holder.rank == "Moderator") + C << "OOC: [src.key][src.client.stealth ? "/([src.client.fakekey])" : ""]: [msg]" else if (src.client.holder.level >= 5) C << "OOC: [src.key][src.client.stealth ? "/([src.client.fakekey])" : ""]: [msg]" else diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm index eb45379de53..26ac9307b61 100644 --- a/code/game/verbs/who.dm +++ b/code/game/verbs/who.dm @@ -30,7 +30,7 @@ for (var/mob/M in world) if(M && M.client && M.client.holder) - if(usr.client.holder) + if(usr.client.holder && (usr.client.holder.level != 0)) usr << "[M.key] is a [M.client.holder.rank][M.client.stealth ? " (as [M.client.fakekey])" : ""]" else if(!M.client.stealth && (M.client.holder.level != -3)) usr << "\t[pick(nobles)] [M.client] is a [M.client.holder.rank]" diff --git a/code/modules/DetectiveWork/detective_work.dm b/code/modules/DetectiveWork/detective_work.dm index 4c9b20b7281..37524d9c691 100644 --- a/code/modules/DetectiveWork/detective_work.dm +++ b/code/modules/DetectiveWork/detective_work.dm @@ -1,4 +1,4 @@ -//gloves w_uniform wear_suit shoes +//CONTAINS: Suit fibers and Detective's Scanning Computer atom/var/list/suit_fibers @@ -52,7 +52,7 @@ var/const/FINGERPRINT_COMPLETE = 6 //This is the output of the stringpercent(pri //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" + name = "\improper High-Res Forensic Scanning Computer" icon_state = "forensic" var obj/item/scanning @@ -136,9 +136,6 @@ obj/machinery/computer/forensic_scanning return if (allowed(M)) authenticated = 1 - //usr << "\green Access Granted" - //if(!authenticated) - //usr << "\red Access Denied" if("logout") authenticated = 0 if("clear") @@ -197,10 +194,9 @@ obj/machinery/computer/forensic_scanning if(files && files.len) temp = "Criminal Evidence Database

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


" else temp = "" @@ -213,22 +209,37 @@ obj/machinery/computer/forensic_scanning if("record") //Viewing a record from the "files" database. canclear = 0 if(files) - temp = "Criminal Evidence Database

" - temp += "Consolidated data points: Dossier [files.Find(href_list["identifier"])]
" 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]) + if(object == dossier[1] || object == dossier[2]) continue temp += "
" var/list/outputs = dossier[object] - var/list/prints_len = outputs[1] + var/list/prints = outputs[1] temp += "Object: [outputs[4]]
" temp += " Fingerprints:
" - temp += "    [prints_len.len] Unique fingerprints found.
" + 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:
" @@ -239,6 +250,7 @@ obj/machinery/computer/forensic_scanning temp += " Blood:
" for(var/named in blood) temp += "      Type: [blood[named]], DNA: [named]
" + temp += "
{Rename this Dossier}" temp += "
{Delete this Dossier}" temp += "
{Print}" else @@ -247,24 +259,33 @@ obj/machinery/computer/forensic_scanning if("databaseprint") //Printing from the "files" database. if(files) var/obj/item/weapon/paper/P = new(loc) - P.name = "Database File (Dossier [files.Find(href_list["identifier"])])" + P.name = "\improper Database File (Dossier [files.Find(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[href_list["identifier"]] + 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]) + if(object == dossier[1] || object == dossier[2]) continue P.info += "
" var/list/outputs = dossier[object] - var/list/prints_len = outputs[1] + var/list/prints = outputs[1] P.info += "Object: [outputs[4]]
" P.info += " Fingerprints:
" - P.info += "    [prints_len.len] Unique fingerprints found.
" + 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:
" @@ -283,11 +304,24 @@ obj/machinery/computer/forensic_scanning 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/j = 1, j <= fibers.len, j++) - temp += "      [fibers[j]]
" + for(var/fiber in fibers) + temp += "      [fiber]
" var/list/blood = outputs[2] if(blood && blood.len) temp += " Blood:
" @@ -302,15 +336,28 @@ obj/machinery/computer/forensic_scanning if(misc) var/obj/item/weapon/paper/P = new(loc) var/list/outputs = misc[href_list["identifier"]] - P.name = "Auxiliary Database File ([outputs[3]])" + 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/j = 1, j <= fibers.len, j++) - P.info += "      [fibers[j]]
" + for(var/fiber in fibers) + P.info += "      [fiber]
" var/list/blood = outputs[2] if(blood && blood.len) P.info += " Blood:
" @@ -361,36 +408,17 @@ obj/machinery/computer/forensic_scanning if(!scanning.fingerprints) scan_data += "No Fingerprints Found

" else - var/list/L = scanning.fingerprints - scan_data += "Isolated [L.len] Fingerprints. Loaded into database.
" + scan_data += "Isolated [scanning.fingerprints.len] Fingerprints. Loaded into database.
" add_data(scanning) if(!scanning.suit_fibers) - /*if(istype(scanning,/obj/item/device/detective_scanner)) - var/obj/item/device/detective_scanner/scanner = scanning - if(scanner.stored_name) - scan_data += "Fibers/Materials Data - [scanner.stored_name]:
" - for(var/data in scanner.stored_fibers) - scan_data += "- [data]
" - else - scan_data += "No Fibers/Materials Data
" - else*/ scan_data += "No Fibers/Materials Located
" else - /*if(istype(scanning,/obj/item/device/detective_scanner)) - var/obj/item/device/detective_scanner/scanner = scanning - if(scanner.stored_name) - scan_data += "Fibers/Materials Data - [scanner.stored_name]:
" - for(var/data in scanner.stored_fibers) - scan_data += "- [data]
" - else - scan_data += "No Fibers/Materials Data
"*/ - 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 Scanner to Database.
" + scan_data += "
Data transfered from \the [scanning] to Database.
" add_data_scanner(scanning) else if(!scanning.fingerprints) scan_data += "
Add to Database?
" @@ -402,7 +430,7 @@ obj/machinery/computer/forensic_scanning if(scan_data) temp = "Scan Data Printed." var/obj/item/weapon/paper/P = new(loc) - P.name = "Scan Data ([scan_name])" + P.name = "\improper Scan Data ([scan_name])" P.info = "[scan_data]" P.overlays += "paper_words" else @@ -416,6 +444,14 @@ obj/machinery/computer/forensic_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() @@ -439,7 +475,7 @@ obj/machinery/computer/forensic_scanning 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) + scanned_atom.suit_fibers, scanned_atom.blood_DNA, "[scanned_atom.name] (Direct Scan)") @@ -458,9 +494,9 @@ obj/machinery/computer/forensic_scanning if(!fibers) fibers = list() if(atom_suit_fibers) - for(var/j = 1, j <= atom_suit_fibers.len, j++) //Fibers~~~ - if(!fibers.Find(atom_suit_fibers[j])) //It isn't! Add! - fibers += atom_suit_fibers[j] + 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() @@ -468,11 +504,19 @@ obj/machinery/computer/forensic_scanning 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[3] + var/list/templist[4] templist[1] = atom_suit_fibers templist[2] = atom_blood_DNA templist[3] = atom_name + templist[4] = atom_fingerprints misc[atom_reference] = templist //Store it! //Has prints. if(atom_fingerprints) @@ -500,9 +544,9 @@ obj/machinery/computer/forensic_scanning if(!fibers) fibers = list() if(atom_suit_fibers) - for(var/j = 1, j < atom_suit_fibers.len, j++) //Fibers~~~ - if(!fibers.Find(atom_suit_fibers[j])) //It isn't! Add! - fibers += atom_suit_fibers[j] + 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) @@ -528,8 +572,9 @@ obj/machinery/computer/forensic_scanning data_point[2] = atom_suit_fibers data_point[3] = atom_blood_DNA data_point[4] = atom_name - var/list/new_file[1] + 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 @@ -580,209 +625,3 @@ obj/machinery/computer/forensic_scanning detective icon_state = "old" name = "PowerScan Mk.I" - -obj/item/clothing/shoes/var - track_blood = 0 - mob/living/carbon/human/track_blood_mob - track_blood_type -mob/var - bloody_hands = 0 - mob/living/carbon/human/bloody_hands_mob - track_blood - mob/living/carbon/human/track_blood_mob - track_blood_type -obj/item/clothing/gloves/var - transfer_blood = 0 - mob/living/carbon/human/bloody_hands_mob - - -obj/effect/decal/cleanable/var - track_amt = 3 - mob/blood_owner - -turf/Exited(mob/living/carbon/human/M) - if(istype(M,/mob/living) && !istype(M,/mob/living/carbon/metroid)) - if(!istype(src, /turf/space)) // Bloody tracks code starts here - var/dofoot = 1 - if(istype(M,/mob/living/simple_animal)) - if(!(istype(M,/mob/living/simple_animal/cat) || istype(M,/mob/living/simple_animal/corgi) || istype(M,/mob/living/simple_animal/constructwraith))) - dofoot = 0 - - if(dofoot) - - if(!istype(src, /turf/space)) // Bloody tracks code starts here - if(M.track_blood > 0) - M.track_blood-- - src.add_bloody_footprints(M.track_blood_mob,1,M.dir,get_tracks(M),M.track_blood_type) - else if(istype(M,/mob/living/carbon/human)) - if(M.shoes && istype(M.shoes,/obj/item/clothing/shoes)) - var/obj/item/clothing/shoes/S = M.shoes - if(S.track_blood > 0) - S.track_blood-- - src.add_bloody_footprints(S.track_blood_mob,1,M.dir,S.name,S.track_blood_type) // And bloody tracks end here - . = ..() -turf/Entered(mob/living/carbon/human/M) - if(istype(M,/mob/living) && !istype(M,/mob/living/carbon/metroid)) - var/dofoot = 1 - if(istype(M,/mob/living/simple_animal)) - if(!(istype(M,/mob/living/simple_animal/cat) || istype(M,/mob/living/simple_animal/corgi) || istype(M,/mob/living/simple_animal/constructwraith))) - dofoot = 0 - - if(dofoot) - - if(M.track_blood > 0) - M.track_blood-- - src.add_bloody_footprints(M.track_blood_mob,0,M.dir,get_tracks(M),M.track_blood_type) - else if(istype(M,/mob/living/carbon/human)) - if(M.shoes && istype(M.shoes,/obj/item/clothing/shoes) && !istype(src,/turf/space)) - var/obj/item/clothing/shoes/S = M.shoes - if(S.track_blood > 0) - S.track_blood-- - src.add_bloody_footprints(S.track_blood_mob,0,M.dir,S.name,S.track_blood_type) - - - for(var/obj/effect/decal/cleanable/B in src) - if(B:track_amt <= 0) continue - if(B.type != /obj/effect/decal/cleanable/blood/tracks) - if(istype(B, /obj/effect/decal/cleanable/xenoblood) || istype(B, /obj/effect/decal/cleanable/blood) || istype(B, /obj/effect/decal/cleanable/oil) || istype(B, /obj/effect/decal/cleanable/robot_debris)) - - var/track_type = "blood" - if(istype(B, /obj/effect/decal/cleanable/xenoblood)) - track_type = "xeno" - else if(istype(B, /obj/effect/decal/cleanable/oil) || istype(B, /obj/effect/decal/cleanable/robot_debris)) - track_type = "oil" - - if(istype(M,/mob/living/carbon/human)) - if(M.shoes && istype(M.shoes,/obj/item/clothing/shoes)) - var/obj/item/clothing/shoes/S = M.shoes - S.add_blood(B.blood_owner) - S.track_blood_mob = B.blood_owner - S.track_blood = max(S.track_blood,8) - S.track_blood_type = track_type - else - M.add_blood(B.blood_owner) - M.track_blood_mob = B.blood_owner - M.track_blood = max(M.track_blood,rand(4,8)) - M.track_blood_type = track_type - B.track_amt-- - break - . = ..() - -turf/proc/add_bloody_footprints(mob/living/carbon/human/M,leaving,d,info,bloodcolor) - for(var/obj/effect/decal/cleanable/blood/tracks/T in src) - if(T.dir == d && findtext(T.icon_state, bloodcolor)) - if((leaving && T.icon_state == "steps2") || (!leaving && T.icon_state == "steps1")) - T.desc = "These bloody footprints appear to have been made by [info]." - if(!T.blood_DNA) - T.blood_DNA = list() - if(istype(M,/mob/living/carbon/human)) - T.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - else if(istype(M,/mob/living/carbon/alien)) - T.blood_DNA["UNKNOWN DNA"] = "X*" - else if(istype(M,/mob/living/carbon/monkey)) - T.blood_DNA["Non-human DNA"] = "A+" - return - var/obj/effect/decal/cleanable/blood/tracks/this = new(src) - this.icon = 'footprints.dmi' - - var/preiconstate = "" - - if(info == "animal paws") - preiconstate = "paw" - else if(info == "alien claws") - preiconstate = "claw" - else if(info == "small alien feet") - preiconstate = "paw" - - if(leaving) - this.icon_state = "[bloodcolor][preiconstate]2" - else - this.icon_state = "[bloodcolor][preiconstate]1" - this.dir = d - - if(bloodcolor == "blood") - this.desc = "These bloody footprints appear to have been made by [info]." - else if(bloodcolor == "xeno") - this.desc = "These acidic bloody footprints appear to have been made by [info]." - else if(bloodcolor == "oil") - this.name = "oil" - this.desc = "These oil footprints appear to have been made by [info]." - - if(istype(M,/mob/living/carbon/human)) - if(!this.blood_DNA) - this.blood_DNA = list() - this.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - -proc/get_tracks(mob/M) - if(istype(M,/mob/living)) - if(istype(M,/mob/living/carbon/human)) - . = "human feet" - else if(istype(M,/mob/living/carbon/monkey) || istype(M,/mob/living/simple_animal/cat) || istype(M,/mob/living/simple_animal/corgi) || istype(M,/mob/living/simple_animal/crab)) - . = "animal paws" - else if(istype(M,/mob/living/silicon/robot)) - . = "robot feet" - else if(istype(M,/mob/living/carbon/alien/humanoid)) - . = "alien claws" - else if(istype(M,/mob/living/carbon/alien/larva)) - . = "small alien feet" - else - . = "an unknown creature" - - -proc/blood_incompatible(donor,receiver) - var - donor_antigen = copytext(donor,1,lentext(donor)) - receiver_antigen = copytext(receiver,1,lentext(receiver)) - donor_rh = findtext("+",donor) - receiver_rh = findtext("+",receiver) - if(donor_rh && !receiver_rh) return 1 - switch(receiver_antigen) - if("A") - if(donor_antigen != "A" && donor_antigen != "O") return 1 - if("B") - if(donor_antigen != "B" && donor_antigen != "O") return 1 - if("O") - if(donor_antigen != "O") return 1 - //AB is a universal receiver. - return 0 - -/obj/item/weapon/rag - New() // So I don't have to grab maplock - spawn(1) - new/obj/item/weapon/reagent_containers/glass/rag(loc) - del src - -/obj/item/weapon/reagent_containers/glass/rag - name = "damp rag" - desc = "For cleaning up messes, you suppose." - w_class = 1 - icon = 'toy.dmi' - icon_state = "rag" - amount_per_transfer_from_this = 5 - possible_transfer_amounts = list(5) - volume = 5 - can_be_placed_into = null - - attack(atom/target as obj|turf|area, mob/user as mob , flag) - if(ismob(target) && target.reagents && reagents.total_volume) - user.visible_message("\red \The [target] has been smothered with \the [src] by \the [user]!", "\red You smother \the [target] with \the [src]!", "You hear some struggling and muffled cries of surprise") - src.reagents.reaction(target, TOUCH) - spawn(5) src.reagents.clear_reagents() - return - else - ..() - - afterattack(atom/A as obj|turf|area, mob/user as mob) - if(istype(A) && src in user) - user.visible_message("[user] starts to wipe down [A] with [src]!") - if(do_after(user,30)) - user.visible_message("[user] finishes wiping off the [A]!") - A.clean_blood() - return - - examine() - if (!usr) - return - usr << "That's \a [src]." - usr << desc - return diff --git a/code/modules/DetectiveWork/evidence.dm b/code/modules/DetectiveWork/evidence.dm index a35a4982a2d..8853efb2be6 100644 --- a/code/modules/DetectiveWork/evidence.dm +++ b/code/modules/DetectiveWork/evidence.dm @@ -1,6 +1,5 @@ -//CONTAINS: -//Evidence bags and stuff -/////////// +//CONTAINS: Evidence bags + /obj/item/weapon/evidencebag name = "evidence bag" desc = "An empty evidence bag." diff --git a/code/modules/DetectiveWork/footprints_and_rag.dm b/code/modules/DetectiveWork/footprints_and_rag.dm new file mode 100644 index 00000000000..83e49347897 --- /dev/null +++ b/code/modules/DetectiveWork/footprints_and_rag.dm @@ -0,0 +1,207 @@ +//CONTAINS: Bloody footprints code, code for managing blood incompatability, and a rag to wipe away evidence. + +obj/item/clothing/shoes/var + track_blood = 0 + mob/living/carbon/human/track_blood_mob + track_blood_type +mob/var + bloody_hands = 0 + mob/living/carbon/human/bloody_hands_mob + track_blood + mob/living/carbon/human/track_blood_mob + track_blood_type +obj/item/clothing/gloves/var + transfer_blood = 0 + mob/living/carbon/human/bloody_hands_mob + + +obj/effect/decal/cleanable/var + track_amt = 3 + mob/blood_owner + +turf/Exited(mob/living/carbon/human/M) + if(istype(M,/mob/living) && !istype(M,/mob/living/carbon/metroid)) + if(!istype(src, /turf/space)) // Bloody tracks code starts here + var/dofoot = 1 + if(istype(M,/mob/living/simple_animal)) + if(!(istype(M,/mob/living/simple_animal/cat) || istype(M,/mob/living/simple_animal/corgi) || istype(M,/mob/living/simple_animal/constructwraith))) + dofoot = 0 + + if(dofoot) + + if(!istype(src, /turf/space)) // Bloody tracks code starts here + if(M.track_blood > 0) + M.track_blood-- + src.add_bloody_footprints(M.track_blood_mob,1,M.dir,get_tracks(M),M.track_blood_type) + else if(istype(M,/mob/living/carbon/human)) + if(M.shoes && istype(M.shoes,/obj/item/clothing/shoes)) + var/obj/item/clothing/shoes/S = M.shoes + if(S.track_blood > 0) + S.track_blood-- + src.add_bloody_footprints(S.track_blood_mob,1,M.dir,S.name,S.track_blood_type) // And bloody tracks end here + . = ..() +turf/Entered(mob/living/carbon/human/M) + if(istype(M,/mob/living) && !istype(M,/mob/living/carbon/metroid)) + var/dofoot = 1 + if(istype(M,/mob/living/simple_animal)) + if(!(istype(M,/mob/living/simple_animal/cat) || istype(M,/mob/living/simple_animal/corgi) || istype(M,/mob/living/simple_animal/constructwraith))) + dofoot = 0 + + if(dofoot) + + if(M.track_blood > 0) + M.track_blood-- + src.add_bloody_footprints(M.track_blood_mob,0,M.dir,get_tracks(M),M.track_blood_type) + else if(istype(M,/mob/living/carbon/human)) + if(M.shoes && istype(M.shoes,/obj/item/clothing/shoes) && !istype(src,/turf/space)) + var/obj/item/clothing/shoes/S = M.shoes + if(S.track_blood > 0) + S.track_blood-- + src.add_bloody_footprints(S.track_blood_mob,0,M.dir,S.name,S.track_blood_type) + + + for(var/obj/effect/decal/cleanable/B in src) + if(B:track_amt <= 0) continue + if(B.type != /obj/effect/decal/cleanable/blood/tracks) + if(istype(B, /obj/effect/decal/cleanable/xenoblood) || istype(B, /obj/effect/decal/cleanable/blood) || istype(B, /obj/effect/decal/cleanable/oil) || istype(B, /obj/effect/decal/cleanable/robot_debris)) + + var/track_type = "blood" + if(istype(B, /obj/effect/decal/cleanable/xenoblood)) + track_type = "xeno" + else if(istype(B, /obj/effect/decal/cleanable/oil) || istype(B, /obj/effect/decal/cleanable/robot_debris)) + track_type = "oil" + + if(istype(M,/mob/living/carbon/human)) + if(M.shoes && istype(M.shoes,/obj/item/clothing/shoes)) + var/obj/item/clothing/shoes/S = M.shoes + S.add_blood(B.blood_owner) + S.track_blood_mob = B.blood_owner + S.track_blood = max(S.track_blood,8) + S.track_blood_type = track_type + else + M.add_blood(B.blood_owner) + M.track_blood_mob = B.blood_owner + M.track_blood = max(M.track_blood,rand(4,8)) + M.track_blood_type = track_type + B.track_amt-- + break + . = ..() + +turf/proc/add_bloody_footprints(mob/living/carbon/human/M,leaving,d,info,bloodcolor) + for(var/obj/effect/decal/cleanable/blood/tracks/T in src) + if(T.dir == d && findtext(T.icon_state, bloodcolor)) + if((leaving && T.icon_state == "steps2") || (!leaving && T.icon_state == "steps1")) + T.desc = "These bloody footprints appear to have been made by [info]." + if(!T.blood_DNA) + T.blood_DNA = list() + if(istype(M,/mob/living/carbon/human)) + T.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type + else if(istype(M,/mob/living/carbon/alien)) + T.blood_DNA["UNKNOWN DNA"] = "X*" + else if(istype(M,/mob/living/carbon/monkey)) + T.blood_DNA["Non-human DNA"] = "A+" + return + var/obj/effect/decal/cleanable/blood/tracks/this = new(src) + this.icon = 'footprints.dmi' + + var/preiconstate = "" + + if(info == "animal paws") + preiconstate = "paw" + else if(info == "alien claws") + preiconstate = "claw" + else if(info == "small alien feet") + preiconstate = "paw" + + if(leaving) + this.icon_state = "[bloodcolor][preiconstate]2" + else + this.icon_state = "[bloodcolor][preiconstate]1" + this.dir = d + + if(bloodcolor == "blood") + this.desc = "These bloody footprints appear to have been made by [info]." + else if(bloodcolor == "xeno") + this.desc = "These acidic bloody footprints appear to have been made by [info]." + else if(bloodcolor == "oil") + this.name = "oil" + this.desc = "These oil footprints appear to have been made by [info]." + + if(istype(M,/mob/living/carbon/human)) + if(!this.blood_DNA) + this.blood_DNA = list() + this.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type + +proc/get_tracks(mob/M) + if(istype(M,/mob/living)) + if(istype(M,/mob/living/carbon/human)) + . = "human feet" + else if(istype(M,/mob/living/carbon/monkey) || istype(M,/mob/living/simple_animal/cat) || istype(M,/mob/living/simple_animal/corgi) || istype(M,/mob/living/simple_animal/crab)) + . = "animal paws" + else if(istype(M,/mob/living/silicon/robot)) + . = "robot feet" + else if(istype(M,/mob/living/carbon/alien/humanoid)) + . = "alien claws" + else if(istype(M,/mob/living/carbon/alien/larva)) + . = "small alien feet" + else + . = "an unknown creature" + + +proc/blood_incompatible(donor,receiver) + var + donor_antigen = copytext(donor,1,lentext(donor)) + receiver_antigen = copytext(receiver,1,lentext(receiver)) + donor_rh = findtext("+",donor) + receiver_rh = findtext("+",receiver) + if(donor_rh && !receiver_rh) return 1 + switch(receiver_antigen) + if("A") + if(donor_antigen != "A" && donor_antigen != "O") return 1 + if("B") + if(donor_antigen != "B" && donor_antigen != "O") return 1 + if("O") + if(donor_antigen != "O") return 1 + //AB is a universal receiver. + return 0 + +/obj/item/weapon/rag + New() // So I don't have to grab maplock + spawn(1) + new/obj/item/weapon/reagent_containers/glass/rag(loc) + del src + +/obj/item/weapon/reagent_containers/glass/rag + name = "damp rag" + desc = "For cleaning up messes, you suppose." + w_class = 1 + icon = 'toy.dmi' + icon_state = "rag" + amount_per_transfer_from_this = 5 + possible_transfer_amounts = list(5) + volume = 5 + can_be_placed_into = null + + attack(atom/target as obj|turf|area, mob/user as mob , flag) + if(ismob(target) && target.reagents && reagents.total_volume) + user.visible_message("\red \The [target] has been smothered with \the [src] by \the [user]!", "\red You smother \the [target] with \the [src]!", "You hear some struggling and muffled cries of surprise") + src.reagents.reaction(target, TOUCH) + spawn(5) src.reagents.clear_reagents() + return + else + ..() + + afterattack(atom/A as obj|turf|area, mob/user as mob) + if(istype(A) && src in user) + user.visible_message("\The [user] starts to wipe down \a [A] with \a [src]!", "You start to wipe down \the [A].", "You hear a damp rag being rubbed against something.") + if(do_after(user,30)) + user.visible_message("\The [user] finishes wiping off \a [A]!", "You finish wiping down \the [A].") + A.clean_blood() + return + + examine() + if (!usr) + return + usr << "That's \a [src]." + usr << desc + return \ No newline at end of file diff --git a/code/modules/DetectiveWork/scanner.dm b/code/modules/DetectiveWork/scanner.dm new file mode 100644 index 00000000000..65285684049 --- /dev/null +++ b/code/modules/DetectiveWork/scanner.dm @@ -0,0 +1,172 @@ +//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 | USEDELAY + 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." + return 0 + if (( !( istype(M.dna, /datum/dna) ) || M.gloves) ) + user << "\blue No fingerprints found on [M]" + return 0 + else + if (src.amount < 1) + user << text("\blue Fingerprints scanned on [M]. Need more cards to print.") + 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) + 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) + user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.get_gender_form("it")] humming[prob(70) ? " gently." : "."]" ,\ + "\blue Unable to locate any fingerprints, materials, fibers, or blood on [A]!",\ + "You hear a faint hum of electrical equipment.") + return 0 + + if(add_data(A)) + user << "\blue Object already in internal memory. Consolidating data..." + return + + + //PRINTS + if(!A.fingerprints || !A.fingerprints.len) + if(A.fingerprints) + del(A.fingerprints) + else + user << "\blue Isolated [A.fingerprints.len] fingerprints: Data Stored: Scan with Hi-Res Forensic Scanner to retrieve." + var/list/complete_prints = list() + for(var/i in A.fingerprints) + var/print = A.fingerprints[i] + if(stringpercent(print) <= FINGERPRINT_COMPLETE) + complete_prints += print + if(complete_prints.len < 1) + user << "\blue   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." + + //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.get_gender_form("it")] humming[prob(70) ? " gently." : "."]" ,\ + "You finish scanning \the [A].",\ + "You hear a faint hum of electrical equipment.") + return 0 + else + user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.get_gender_form("it")] humming[prob(70) ? " gently." : "."]\n[user.get_gender_form("It")] seems to perk up slightly at the readout." ,\ + "The results of the scan pique your interest.",\ + "You hear a faint hum of electrical equipment, and someone making a thoughtful noise.") + return 0 + return + + proc/add_data(atom/A as mob|obj|turf|area) + //I love hashtables. + var/list/data_entry = stored["\ref [A]"] + if(islist(data_entry)) //Yay, it was already stored! + //Merge the fingerprints. + var/list/data_prints = data_entry[1] + for(var/print in A.fingerprints) + var/merged_print = data_prints[print] + if(!merged_print) + data_prints[print] = A.fingerprints[print] + 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 + sum_list[2] = A.suit_fibers + sum_list[3] = A.blood_DNA + sum_list[4] = "\The [A] in \the [get_area(A)]" + stored["\ref [A]"] = sum_list + return 0 \ No newline at end of file diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index d0f0b72f56a..f0d7113b7d2 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -6,7 +6,7 @@ var/global/BSACooldown = 0 /proc/message_admins(var/text, var/admin_ref = 0) var/rendered = "ADMIN LOG: [text]" for (var/mob/M in world) - if (M && M.client && M.client.holder && M.client.holder.level > -3) //Lets not spam our retirees. + if (M && M.client && M.client.holder && M.client.holder.level > -3 && M.client.holder.level != 0) //Lets not spam our retirees. Or moderators! if (admin_ref) M << dd_replaceText(rendered, "%admin_ref%", "\ref[M]") else @@ -176,6 +176,7 @@ var/global/BSACooldown = 0 var/datum/player_info/P = new P.author = usr.key + P.rank = usr.client.holder.rank P.content = add var/modifyer = "th" switch(time2text(world.timeofday, "DD")) @@ -196,6 +197,9 @@ var/global/BSACooldown = 0 info << infos + message_admins("\blue [key_name_admin(usr)] has edited [key]'s notes.") + log_admin("[key_name(usr)] has edited [key]'s notes.") + del info var/savefile/note_list = new("data/player_notes.sav") @@ -221,6 +225,9 @@ var/global/BSACooldown = 0 infos.Remove(item) info << infos + message_admins("\blue [key_name_admin(usr)] deleted one of [key]'s notes.") + log_admin("[key_name(usr)] deleted one of [key]'s notes.") + del info show_player_info(key) @@ -612,13 +619,6 @@ var/global/BSACooldown = 0 var/datum/job/temp = job_master.GetJob(jobPos) if(!temp) continue joblist += temp.title - if("miscdept") - joblist += "pAI" - for(var/jobPos in nonhuman_positions) - if(!jobPos) continue - var/datum/job/temp = job_master.GetJob(jobPos) - if(!temp) continue - joblist += temp.title else joblist += href_list["jobban3"] @@ -800,7 +800,7 @@ var/global/BSACooldown = 0 usr << browse(dat, "window=jobban2;size=600x250") return if(href_list["newjobban2"]) - if ((src.rank in list("Moderator", "Administrator", "Badmin", "Tyrant" ))) + if ((src.rank in list(/*"Moderator", */"Administrator", "Badmin", "Tyrant" ))) var/mob/M = locate(href_list["jobban4"]) var/job = href_list["newjobban2"] if(!ismob(M)) return @@ -877,7 +877,7 @@ var/global/BSACooldown = 0 remove_goon(t) */ if (href_list["mute2"]) - if ((src.rank in list( "Moderator", "Temporary Admin", "Admin Candidate", "Trial Admin", "Badmin", "Game Admin", "Game Master" ))) + if ((src.rank in list(/* "Moderator", */"Temporary Admin", "Admin Candidate", "Trial Admin", "Badmin", "Game Admin", "Game Master" ))) var/mob/M = locate(href_list["mute2"]) if (ismob(M)) if ((M.client && M.client.holder && (M.client.holder.level >= src.level))) @@ -891,7 +891,7 @@ var/global/BSACooldown = 0 message_admins("\blue [key_name_admin(usr)] has [(M.client.muted ? "muted" : "voiced")] [key_name_admin(M)].", 1) M << "You have been [(M.client.muted ? "muted" : "voiced")]. Please resolve this in adminhelp." if (href_list["mute_complete"]) - if ((src.rank in list( "Moderator", "Temporary Admin", "Admin Candidate", "Trial Admin", "Badmin", "Game Admin", "Game Master" ))) + if ((src.rank in list(/* "Moderator", */"Temporary Admin", "Admin Candidate", "Trial Admin", "Badmin", "Game Admin", "Game Master" ))) var/mob/M = locate(href_list["mute_complete"]) if (ismob(M)) if ((M.client && M.client.holder && (M.client.holder.level >= src.level))) @@ -997,7 +997,7 @@ var/global/BSACooldown = 0 return if (href_list["sendtoprison"]) - if ((src.rank in list( "Moderator", "Admin Candidate", "Temporary Admin", "Trial Admin", "Badmin", "Game Admin", "Game Master" ))) + if ((src.rank in list(/* "Moderator", */"Admin Candidate", "Temporary Admin", "Trial Admin", "Badmin", "Game Admin", "Game Master" ))) var/confirm = alert(usr, "Send to admin prison for the round?", "Message", "Yes", "No") if(confirm != "Yes") @@ -1350,62 +1350,79 @@ var/global/BSACooldown = 0 // Now isn't that much better? IT IS NOW A PROC, i.e. kinda like a big panel like unstable if (href_list["adminplayeropts"]) - var/mob/M = locate(href_list["adminplayeropts"]) - show_player_panel(M) + if(rank in list("Admin Observer", "Temporary Admin", "Admin Candidate", "Trial Admin", "Badmin", "Game Admin", "Game Master")) + var/mob/M = locate(href_list["adminplayeropts"]) + show_player_panel(M) + else + alert("You cannot perform this action. You must be of a higher administrative rank!") if (href_list["player_info"]) var/key = href_list["player_info"] show_player_info(key) if (href_list["adminplayervars"]) - var/mob/M = locate(href_list["adminplayervars"]) - if(src && src.owner) - if(istype(src.owner,/client)) - var/client/cl = src.owner - cl.debug_variables(M) - else if(ismob(src.owner)) - var/mob/MO = src.owner - if(MO.client) - var/client/cl = MO.client + if(rank in list("Admin Observer", "Temporary Admin", "Admin Candidate", "Trial Admin", "Badmin", "Game Admin", "Game Master")) + var/mob/M = locate(href_list["adminplayervars"]) + if(src && src.owner) + if(istype(src.owner,/client)) + var/client/cl = src.owner cl.debug_variables(M) + else if(ismob(src.owner)) + var/mob/MO = src.owner + if(MO.client) + var/client/cl = MO.client + cl.debug_variables(M) + else + alert("You cannot perform this action. You must be of a higher administrative rank!") if (href_list["adminplayersubtlemessage"]) - var/mob/M = locate(href_list["adminplayersubtlemessage"]) - if(src && src.owner) - if(istype(src.owner,/client)) - var/client/cl = src.owner - cl.cmd_admin_subtle_message(M) - else if(ismob(src.owner)) - var/mob/MO = src.owner - if(MO.client) - var/client/cl = MO.client + if(rank in list("Admin Observer", "Temporary Admin", "Admin Candidate", "Trial Admin", "Badmin", "Game Admin", "Game Master")) + var/mob/M = locate(href_list["adminplayersubtlemessage"]) + if(src && src.owner) + if(istype(src.owner,/client)) + var/client/cl = src.owner cl.cmd_admin_subtle_message(M) + else if(ismob(src.owner)) + var/mob/MO = src.owner + if(MO.client) + var/client/cl = MO.client + cl.cmd_admin_subtle_message(M) + else + alert("You cannot perform this action. You must be of a higher administrative rank!") if (href_list["adminplayerobservejump"]) - var/mob/M = locate(href_list["adminplayerobservejump"]) - if(src && src.owner) - if(istype(src.owner,/client)) - var/client/cl = src.owner - cl.admin_observe() - sleep(2) - cl.jumptomob(M) - else if(ismob(src.owner)) - var/mob/MO = src.owner - if(MO.client) - var/client/cl = MO.client + if(rank in list("Admin Observer", "Temporary Admin", "Admin Candidate", "Trial Admin", "Badmin", "Game Admin", "Game Master")) + var/mob/M = locate(href_list["adminplayerobservejump"]) + if(src && src.owner) + if(istype(src.owner,/client)) + var/client/cl = src.owner cl.admin_observe() sleep(2) cl.jumptomob(M) + else if(ismob(src.owner)) + var/mob/MO = src.owner + if(MO.client) + var/client/cl = MO.client + cl.admin_observe() + sleep(2) + cl.jumptomob(M) + else + alert("You cannot perform this action. You must be of a higher administrative rank!") if (href_list["traitor_panel_pp"]) - var/mob/M = locate(href_list["traitor_panel_pp"]) - if(isnull(M)) - usr << "Mob doesn't seem to exist." - return - if(!ismob(M)) - usr << "This doen't seem to be a mob." - return - show_traitor_panel(M) + if(rank in list("Admin Observer", "Temporary Admin", "Admin Candidate", "Trial Admin", "Badmin", "Game Admin", "Game Master")) + var/mob/M = locate(href_list["traitor_panel_pp"]) + if(isnull(M)) + usr << "Mob doesn't seem to exist." + return + if(!ismob(M)) + usr << "This doen't seem to be a mob." + return + show_traitor_panel(M) + else + alert("You cannot perform this action. You must be of a higher administrative rank!") + + if (href_list["BlueSpaceArtillery"]) var/mob/M = locate(href_list["BlueSpaceArtillery"]) @@ -2239,7 +2256,7 @@ var/global/BSACooldown = 0 return if (href_list["secretsadmin"]) - if ((src.rank in list( "Moderator", "Temporary Admin", "Admin Candidate", "Trial Admin", "Badmin", "Game Admin", "Game Master" ))) + if ((src.rank in list(/* "Moderator", */"Temporary Admin", "Admin Candidate", "Trial Admin", "Badmin", "Game Admin", "Game Master" ))) var/ok = 0 switch(href_list["secretsadmin"]) if("clear_bombs") @@ -2380,7 +2397,7 @@ var/global/BSACooldown = 0 message_admins("\blue [user.ckey] warned [M.ckey].") else AddBan(M.ckey, M.computer_id, "Autobanning due to previous warn", user.ckey, 1, AUTOBANTIME) - M << "\redYou have been autobanned by [user.ckey]. This is what we in the biz like to call a \"second warning\"." + M << "\redYou have been autobanned by [user.ckey]." M << "\red This is a temporary ban; it will automatically be removed in [AUTOBANTIME] minutes." log_admin("[user.ckey] warned [M.ckey], resulting in a [AUTOBANTIME] minute autoban.") ban_unban_log_save("[user.ckey] warned [M.ckey], resulting in a [AUTOBANTIME] minute autoban.") @@ -2428,6 +2445,7 @@ var/global/BSACooldown = 0 body += "Mob type = [M.type]

" + body += "Warn | " body += "Kick | " body += "Ban | " body += "Jobban " @@ -2527,10 +2545,11 @@ var/global/BSACooldown = 0 //feedback_add_details("admin_verb","SPP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/datum/player_info/var - author // admin who authored the information - content // text content of the information - timestamp // Because this is bloody annoying + +/datum/player_info/var/author // admin who authored the information +/datum/player_info/var/rank //rank of admin who made the notes +/datum/player_info/var/content // text content of the information +/datum/player_info/var/timestamp // Because this is bloody annoying /obj/admins/proc/player_has_info(var/key as text) var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") @@ -2563,7 +2582,10 @@ var/global/BSACooldown = 0 if(!I.timestamp) I.timestamp = "Pre-4/3/2012" update_file = 1 - dat += "[I.content] by [I.author] on [I.timestamp] " + if(!I.rank) + I.rank = "N/A" + update_file = 1 + dat += "[I.content] by [I.author] ([I.rank]) on [I.timestamp] " if(I.author == usr.key) dat += "Remove" dat += "

" diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index f7eec938d0e..270a9bfe08c 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -107,52 +107,32 @@ if (holder.level >= -1) verbs += /client/proc/investigate_show verbs += /client/proc/cmd_admin_say + verbs += /client/proc/cmd_mod_say verbs += /client/proc/cmd_admin_gib_self verbs += /client/proc/deadmin_self else if (holder.level == -3) // Retired Admin verbs += /client/proc/cmd_admin_say + verbs += /client/proc/cmd_mod_say return else return //Moderator if (holder.level >= 0) - verbs += /obj/admins/proc/announce - verbs += /obj/admins/proc/startnow - verbs += /obj/admins/proc/toggleAI //Toggle the AI - verbs += /obj/admins/proc/toggleenter //Toggle enterting -// verbs += /obj/admins/proc/toggleguests //Toggle guests entering - verbs += /obj/admins/proc/toggleooc //toggle ooc - verbs += /obj/admins/proc/toggleoocdead //toggle ooc for dead/unc - verbs += /obj/admins/proc/voteres //toggle votes - verbs += /obj/admins/proc/vmode - verbs += /obj/admins/proc/votekill - verbs += /obj/admins/proc/show_player_panel - verbs += /client/proc/deadchat //toggles deadchat - //verbs += /client/proc/cmd_admin_mute --was never used (according to stats trackind) - use show player panel --erro verbs += /client/proc/cmd_admin_pm_context verbs += /client/proc/cmd_admin_pm_panel - verbs += /client/proc/cmd_admin_subtle_message - //verbs += /client/proc/warn - was never used - verbs += /client/proc/dsay verbs += /client/proc/admin_play verbs += /client/proc/admin_observe - verbs += /client/proc/game_panel -// verbs += /client/proc/player_panel - verbs += /client/proc/player_panel_new - verbs += /client/proc/unban_panel - verbs += /client/proc/jobbans - - verbs += /client/proc/voting verbs += /client/proc/hide_verbs - verbs += /client/proc/general_report - //verbs += /client/proc/air_report verbs += /client/proc/deadmin_self - //verbs += /client/proc/cmd_admin_prison --Merged with player panel - //verbs += /obj/admins/proc/unprison --Merged with player panel - verbs += /client/proc/playernotes verbs += /obj/admins/proc/show_skills else return + if(holder.level == 0) //Moderators don't get asay, only msay + verbs -= /client/proc/cmd_admin_say + verbs -= /client/proc/investigate_show + verbs -= /client/proc/cmd_admin_gib_self + verbs += /client/proc/mod_panel + //Temporary Admin if (holder.level >= 1) verbs += /obj/admins/proc/delay //game start delay @@ -165,6 +145,35 @@ verbs += /client/proc/deadmin_self //verbs += /client/proc/cmd_admin_attack_log --Merged with view variables verbs += /client/proc/cmd_admin_change_custom_event + // + //MOVED FROM MODERATOR + // + verbs += /client/proc/cmd_admin_subtle_message + verbs += /obj/admins/proc/announce + verbs += /obj/admins/proc/startnow + verbs += /obj/admins/proc/toggleAI //Toggle the AI + verbs += /obj/admins/proc/toggleenter //Toggle enterting +// verbs += /obj/admins/proc/toggleguests //Toggle guests entering + verbs += /obj/admins/proc/toggleooc //toggle ooc + verbs += /obj/admins/proc/toggleoocdead //toggle ooc for dead/unc + verbs += /obj/admins/proc/voteres //toggle votes + verbs += /obj/admins/proc/vmode + verbs += /obj/admins/proc/votekill + verbs += /client/proc/deadchat //toggles deadchat + //verbs += /client/proc/cmd_admin_mute --was never used (according to stats trackind) - use show player panel --erro + verbs += /client/proc/dsay + verbs += /client/proc/game_panel + verbs += /obj/admins/proc/show_player_panel +// verbs += /client/proc/player_panel + verbs += /client/proc/player_panel_new + verbs += /client/proc/unban_panel + verbs += /client/proc/jobbans + verbs += /client/proc/voting + verbs += /client/proc/general_report + //verbs += /client/proc/air_report + //verbs += /client/proc/cmd_admin_prison --Merged with player panel + //verbs += /obj/admins/proc/unprison --Merged with player panel + verbs += /client/proc/playernotes else return //Admin Candidate @@ -393,8 +402,8 @@ verbs -= /client/proc/cmd_admin_pm_context verbs -= /client/proc/cmd_admin_pm_panel verbs -= /client/proc/cmd_admin_say + verbs -= /client/proc/cmd_mod_say verbs -= /client/proc/cmd_admin_subtle_message - //verbs -= /client/proc/warn verbs -= /client/proc/dsay verbs -= /client/proc/admin_play verbs -= /client/proc/admin_observe @@ -418,6 +427,7 @@ verbs -= /client/proc/toggle_hear_radio verbs -= /client/proc/tension_report verbs -= /client/proc/player_panel_new + verbs -= /client/proc/mod_panel verbs -= /client/proc/toggle_gravity_on verbs -= /client/proc/toggle_gravity_off verbs -= /client/proc/toggle_random_events @@ -428,7 +438,7 @@ verbs -= /client/proc/getserverlog verbs -= /client/proc/cinematic //show a cinematic sequence verbs -= /client/proc/admin_memo - verbs -= /client/proc/investigate_show + verbs -= /client/proc/investigate_show verbs -= /client/proc/cmd_admin_change_custom_event verbs -= /client/proc/admin_invis verbs -= /client/proc/callprocgen @@ -538,6 +548,14 @@ // feedback_add_details("admin_verb","PPN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return +/client/proc/mod_panel() + set name = "Moderator Panel" + set category = "Admin" + if(holder) + holder.mod_panel() +// feedback_add_details("admin_verb","MP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + /client/proc/check_antagonists() set name = "Check Antagonists" set category = "Admin" @@ -836,6 +854,7 @@ verbs += /client/proc/deadchat //toggles deadchat verbs += /obj/admins/proc/toggleooc //toggle ooc verbs += /client/proc/cmd_admin_say//asay + verbs += /client/proc/cmd_mod_say verbs += /client/proc/toggleadminhelpsound // feedback_add_details("admin_verb","HMV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return @@ -856,6 +875,7 @@ verbs += /client/proc/deadchat //toggles deadchat verbs += /obj/admins/proc/toggleooc //toggle ooc verbs += /client/proc/cmd_admin_say//asay + verbs += /client/proc/cmd_mod_say//asay // feedback_add_details("admin_verb","TAVVH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 2c87cf9410a..408815774e9 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -113,6 +113,113 @@ usr << browse(dat, "window=players;size=905x600") + +/obj/admins/proc/mod_panel()//The new one + if (!usr.client.holder) + return + var/dat = "Player Menu" + dat += "" + //add to this if wanting to add back in IP checking + //add if you want to know their ip to the lists below + var/list/mobs = get_sorted_mobs() + var/i = 1 + + for(var/mob/M in mobs) + if(M.ckey) + var/color = "#e6e6e6" + i++ + if(i%2 == 0) + color = "#f2f2f2" + var/real = (M.real_name == M.original_name ? "[M.name]/[M.real_name]" : "[M.original_name] (as [M.name]/[M.real_name])") + var/turf/T = get_turf(M) + var/client_key = (M.key? M.key : "No key") + dat += "" // Adds current name +/* if(isobserver(M)) + dat += "" + else if(isalien(M)) + dat += "" + else if(islarva(M)) + dat += "" + else if(istajaran(M)) + dat += "" + else if(ishuman(M)) + dat += "" + else if(ismetroid(M)) + dat += "" + else if(ismonkey(M)) + dat += "" + else if(isAI(M)) + dat += "" + else if(ispAI(M)) + dat += "" + else if(isrobot(M)) + dat += "" + else if(isanimal(M)) + dat += "" + else if(iscorgi(M)) + dat += "" + else if(istype(M,/mob/new_player)) + dat += "" + else + dat += "\black" + + if(M.mind && M.mind.assigned_role && istype(M, /mob/living/carbon/human)) // Adds a column to Player Panel that shows their current job. + var/mob/living/carbon/human/H = M + + if (H.wear_id) + var/obj/item/weapon/card/id/id + + if(istype(H.wear_id, /obj/item/device/pda)) + var/obj/item/device/pda/PDA = H.wear_id + if(!isnull(PDA.id)) // The PDA may contain no ID + id = PDA.id // The ID is contained inside the PDA + + else + id = H.wear_id // The ID was on the ID slot + + if(!id) // Happens when there's no ID in the PDA located on the wear_id slot + dat += "" + + else if(isnull(id.assignment)) // Preventing runtime errors blocking the player panel + if(istype(id, /obj/item/weapon/card/id/syndicate)) + dat += "" + else + usr << "ERROR: Inform the coders that an [id.name] was checked for its assignment variable, and it was null." + dat += "" + + else + if(M.mind.assigned_role == id.assignment) // Polymorph + dat += "" + + else + dat += "" + + else + dat += "" +*/ + dat += {" + "} + + dat += {" + + "} + +/* switch(is_special_character(M)) + if(0) + dat += {""} + if(1) + dat += {""} + if(2) + dat += {""} +*/ + dat += "
Name/Real NameIP/CIDInfoOptions
IP:Type Assigned Job Traitor?(IP: [M.lastKnownIP])
[real]
[M.client ? M.client : "No client ([client_key])"] at ([T.x], [T.y], [T.z])
GhostAlienAlien larvaTajaran[M.job]MetroidMonkeyAIpAICyborgAnimalCorgiNew Player\red ERROR[M.mind.assigned_role] (No ID)AntagonistERROR[M.mind.assigned_role][M.mind.assigned_role] ([id.assignment])" + + else + dat += "[M.mind.assigned_role] (No ID)No Assigned RoleIP: [M.client.address]
+ CID: [M.client.computer_id]
[player_has_info(M.ckey) ? "Info" : "N/A"] PMTraitor?Traitor?Traitor?
" + + usr << browse(dat, "window=players;size=600x600") + //The old one /obj/admins/proc/player_panel_old() if (!usr.client.holder) diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index 94bd6098f51..2c0f9eba325 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -61,8 +61,12 @@ if(C.holder) if(holder) //both are admins - C << "Admin PM from-[key_name(src, C, 1)]: [msg]" - src << "Admin PM to-[key_name(C, src, 1)]: [msg]" + if(holder.rank == "Moderator") //If moderator + C << "Mod PM from-[key_name(src, C, 1)]: [msg]" + src << "Mod PM to-[key_name(C, src, 1)]: [msg]" + else + C << "Admin PM from-[key_name(src, C, 1)]: [msg]" + src << "Admin PM to-[key_name(C, src, 1)]: [msg]" else //recipient is an admin but sender is not C << "Reply PM from-[key_name(src, C, 1)]: [msg]" @@ -75,10 +79,14 @@ else if(holder) //sender is an admin but recipient is not. Do BIG RED TEXT // C << "-- Administrator private message --" - C << "Admin PM from-[key_name(src, C, 0)]: [msg]" - C << "Click on the administrator's name to reply." - src << "Admin PM to-[key_name(C, src, 1)]: [msg]" - + if(holder.rank == "Moderator") + C << "Mod PM from-[key_name(src, C, 0)]: [msg]" + C << "Click on the moderators's name to reply." + src << "Mod PM to-[key_name(C, src, 1)]: [msg]" + else + C << "Admin PM from-[key_name(src, C, 0)]: [msg]" + C << "Click on the administrator's name to reply." + src << "Admin PM to-[key_name(C, src, 1)]: [msg]" //always play non-admin recipients the adminhelp sound C << 'adminhelp.ogg' diff --git a/code/modules/admin/verbs/adminsay.dm b/code/modules/admin/verbs/adminsay.dm index 92165d06a2f..07ccbbbddd3 100644 --- a/code/modules/admin/verbs/adminsay.dm +++ b/code/modules/admin/verbs/adminsay.dm @@ -20,9 +20,39 @@ //feedback_add_details("admin_verb","M") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! for (var/mob/M in world) - if (M.client && M.client.holder) + if (M.client && M.client.holder && M.client.holder.level != 0) //Moderators cannot see it. if (src.holder.rank == "Admin Observer") M << "ADMIN: [key_name(usr, M)]: [msg]" else M << "ADMIN: [key_name(usr, M)] (JMP): [msg]" +/client/proc/cmd_mod_say(msg as text) + set category = "Special Verbs" + set name = "Msay" + set hidden = 1 + + if (!src.holder) + src << "Only administrators may use this command." + return + + if (src.muted || src.muted_complete) + src << "You are muted." + return + + msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN) + log_admin("MOD: [key_name(src)] : [msg]") + + + if (!msg) + return + //feedback_add_details("admin_verb","M") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + for (var/mob/M in world) + if (M.client && M.client.holder) + if (src.holder.rank == "Admin Observer") + M << "MOD: [key_name(usr, M)]: [msg]" + else if (src.holder.rank == "Moderator") + M << "MOD: [key_name(usr, M)] (JMP): [msg]" + else + M << "MOD: [key_name(usr, M)] (JMP): [msg]" + diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm index 47e61313879..a4eb0ed0582 100644 --- a/code/modules/admin/verbs/pray.dm +++ b/code/modules/admin/verbs/pray.dm @@ -28,7 +28,7 @@ // log_admin("[key_name(Sender)] sent a message to Centcomm! The message was [msg]") // Handled somewhere else for (var/mob/M in world) - if (M.client && M.client.holder) + if (M.client && M.client.holder && M.client.holder.level != 0) M << "\blue CENTCOMM:[key_name(Sender, M)] (PP) (VV) (SM) (JMP) (CA) (BSA) (RPLY): [msg]" // /proc/Syndicate_announce(var/text , var/mob/Sender) @@ -38,6 +38,6 @@ // log_admin("[key_name(Sender)] sent a message to the Syndicate! The message was [msg]") // Handled somewhere else for (var/mob/M in world) - if (M.client && M.client.holder) + if (M.client && M.client.holder && M.client.holder.level != 0) M << "\blue SYNDICATE:[key_name(Sender, M)] (PP) (VV) (SM) (JMP) (CA) (BSA) (RPLY): [msg]" // diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index ec9484a289e..270a8448c10 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -301,7 +301,7 @@ proc/ManifestLateSpawn(var/mob/living/carbon/human/H, icon/H_icon) // Attempted fix to add late joiners to various databases -- TLE - // This is basically ripped wholesale from the normal code for adding people to the databases during a fresh round //Erth Mark + // This is basically ripped wholesale from the normal code for adding people to the databases during a fresh round if (!isnull(H.mind) && (H.mind.assigned_role != "MODE")) var/datum/data/record/G = new() var/datum/data/record/M = new() diff --git a/code/stylesheet.dm b/code/stylesheet.dm index a3401ade9fd..bf2272ba291 100644 --- a/code/stylesheet.dm +++ b/code/stylesheet.dm @@ -20,6 +20,10 @@ em {font-style: normal; font-weight: bold;} .adminobserver {color: #996600; font-weight: bold;} .admin {color: #386aff; font-weight: bold;} +.mod {color: #735638; font-weight: bold;} +.modooc {color: #184880; font-weight: bold;} +.adminmod {color: #402A14; font-weight: bold;} + .name { font-weight: bold;} .say {} diff --git a/config/alienwhitelist.txt b/config/alienwhitelist.txt index 7bd575035fe..39be52e1117 100644 --- a/config/alienwhitelist.txt +++ b/config/alienwhitelist.txt @@ -3,4 +3,6 @@ searif - Soghun searif - Tajaran galenus - Soghun botanistpower - Tajaran -fenrisian - Tajaran \ No newline at end of file +fenrisian - Tajaran +forsamori - Tajaran +forsamori - Soghun \ No newline at end of file diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi index ceb1d3bd021..ce4098bcd85 100644 Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 4f966143387..91032dbec0a 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ