diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm index f59e2e69223..27f6d7c7fe8 100644 --- a/code/controllers/subsystem/chat.dm +++ b/code/controllers/subsystem/chat.dm @@ -18,7 +18,7 @@ SUBSYSTEM_DEF(chat) return -/datum/controller/subsystem/chat/proc/queue(target, message, handle_whitespace = TRUE) +/datum/controller/subsystem/chat/proc/queue(target, message, handle_whitespace = TRUE, trailing_newline = TRUE) if(!target || !message) return @@ -36,7 +36,8 @@ SUBSYSTEM_DEF(chat) if(handle_whitespace) message = replacetext(message, "\n", "
") message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]") - message += "
" + if (trailing_newline) + message += "
" //url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript. diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index f496d5cd57d..48ce5016c20 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -10,6 +10,13 @@ NANITE SCANNER GENE SCANNER */ + +// Describes the two modes of scanning available for health analyzers +#define SCANMODE_HEALTH 0 +#define SCANMODE_CHEMICAL 1 +#define SCANNER_CONDENSED 0 +#define SCANNER_VERBOSE 1 + /obj/item/t_scanner name = "\improper T-ray scanner" desc = "A terahertz-ray emitter and scanner used to detect underfloor objects such as cables and pipes." @@ -78,7 +85,7 @@ GENE SCANNER item_state = "healthanalyzer" lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - desc = "A hand-held body scanner able to distinguish vital signs of the subject." + desc = "A hand-held body scanner capable of distinguishing vital signs of the subject." flags_1 = CONDUCT_1 item_flags = NOBLUDGEON slot_flags = ITEM_SLOT_BELT @@ -87,8 +94,8 @@ GENE SCANNER throw_speed = 3 throw_range = 7 custom_materials = list(/datum/material/iron=200) - var/mode = 1 - var/scanmode = 0 + var/mode = SCANNER_VERBOSE + var/scanmode = SCANMODE_HEALTH var/advanced = FALSE custom_price = 300 @@ -97,48 +104,47 @@ GENE SCANNER return BRUTELOSS /obj/item/healthanalyzer/attack_self(mob/user) - if(!scanmode) - to_chat(user, "You switch the health analyzer to scan chemical contents.") - scanmode = 1 - else - to_chat(user, "You switch the health analyzer to check physical health.") - scanmode = 0 + scanmode = !scanmode + to_chat(user, "You switch the health analyzer to [scanmode ? "scan chemical contents" : "check physical health"].") /obj/item/healthanalyzer/attack(mob/living/M, mob/living/carbon/human/user) flick("[icon_state]-scan", src) //makes it so that it plays the scan animation upon scanning, including clumsy scanning // Clumsiness/brain damage check - if ((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50)) user.visible_message("[user] analyzes the floor's vitals!", \ "You stupidly try to analyze the floor's vitals!") - to_chat(user, "Analyzing results for The floor:\n\tOverall status: Healthy") - to_chat(user, "Key: Suffocation/Toxin/Burn/Brute") - to_chat(user, "\tDamage specifics: 0-0-0-0") - to_chat(user, "Body temperature: ???") + to_chat(user, "Analyzing results for The floor:\n\tOverall status: Healthy\ + \nKey: Suffocation/Toxin/Burn/Brute\ + \n\tDamage specifics: 0-0-0-0\ + \nBody temperature: ???") return user.visible_message("[user] analyzes [M]'s vitals.", \ "You analyze [M]'s vitals.") - if(scanmode == 0) + if(scanmode == SCANMODE_HEALTH) healthscan(user, M, mode, advanced) - else if(scanmode == 1) + else chemscan(user, M) add_fingerprint(user) // Used by the PDA medical scanner too -/proc/healthscan(mob/user, mob/living/M, mode = 1, advanced = FALSE) +/proc/healthscan(mob/user, mob/living/M, mode = SCANNER_VERBOSE, advanced = FALSE) if(isliving(user) && (user.incapacitated() || user.eye_blind)) return - //Damage specifics + + // the final list of strings to render + var/render_list = list() + + // Damage specifics var/oxy_loss = M.getOxyLoss() var/tox_loss = M.getToxLoss() var/fire_loss = M.getFireLoss() var/brute_loss = M.getBruteLoss() - var/mob_status = (M.stat == DEAD ? "Deceased" : "[round(M.health/M.maxHealth,0.01)*100] % healthy") + var/mob_status = (M.stat == DEAD ? "Deceased" : "[round(M.health/M.maxHealth,0.01)*100]% healthy") if(HAS_TRAIT(M, TRAIT_FAKEDEATH) && !advanced) mob_status = "Deceased" @@ -147,29 +153,29 @@ GENE SCANNER if(ishuman(M)) var/mob/living/carbon/human/H = M if(H.undergoing_cardiac_arrest() && H.stat != DEAD) - to_chat(user, "Subject suffering from heart attack: Apply defibrillation or other electric shock immediately!") + render_list += "Subject suffering from heart attack: Apply defibrillation or other electric shock immediately!\n" - to_chat(user, "Analyzing results for [M]:\n\tOverall status: [mob_status]") + render_list += "Analyzing results for [M]:\nOverall status: [mob_status]\n" // Damage descriptions if(brute_loss > 10) - to_chat(user, "\t[brute_loss > 50 ? "Severe" : "Minor"] tissue damage detected.") + render_list += "[brute_loss > 50 ? "Severe" : "Minor"] tissue damage detected.\n" if(fire_loss > 10) - to_chat(user, "\t[fire_loss > 50 ? "Severe" : "Minor"] burn damage detected.") + render_list += "[fire_loss > 50 ? "Severe" : "Minor"] burn damage detected.\n" if(oxy_loss > 10) - to_chat(user, "\t[oxy_loss > 50 ? "Severe" : "Minor"] oxygen deprivation detected.") + render_list += "[oxy_loss > 50 ? "Severe" : "Minor"] oxygen deprivation detected.\n" if(tox_loss > 10) - to_chat(user, "\t[tox_loss > 50 ? "Severe" : "Minor"] amount of toxin damage detected.") + render_list += "[tox_loss > 50 ? "Severe" : "Minor"] amount of toxin damage detected.\n" if(M.getStaminaLoss()) - to_chat(user, "\tSubject appears to be suffering from fatigue.") + render_list += "Subject appears to be suffering from fatigue.\n" if(advanced) - to_chat(user, "\tFatigue Level: [M.getStaminaLoss()]%.") + render_list += "Fatigue Level: [M.getStaminaLoss()]%.\n" if (M.getCloneLoss()) - to_chat(user, "\tSubject appears to have [M.getCloneLoss() > 30 ? "Severe" : "Minor"] cellular damage.") + render_list += "Subject appears to have [M.getCloneLoss() > 30 ? "Severe" : "Minor"] cellular damage.\n" if(advanced) - to_chat(user, "\tCellular Damage Level: [M.getCloneLoss()].") + render_list += "Cellular Damage Level: [M.getCloneLoss()].\n" if (!M.getorgan(/obj/item/organ/brain)) - to_chat(user, "\tSubject lacks a brain.") + render_list += "Subject lacks a brain.\n" if(iscarbon(M)) var/mob/living/carbon/C = M if(LAZYLEN(C.get_traumas())) @@ -185,83 +191,32 @@ GENE SCANNER trauma_desc += "permanent " trauma_desc += B.scan_desc trauma_text += trauma_desc - to_chat(user, "\tCerebral traumas detected: subject appears to be suffering from [english_list(trauma_text)].") + render_list += "Cerebral traumas detected: subject appears to be suffering from [english_list(trauma_text)].\n" if(C.roundstart_quirks.len) - to_chat(user, "\tSubject has the following physiological traits: [C.get_trait_string()].") + render_list += "Subject has the following physiological traits: [C.get_trait_string()].\n" if(advanced) - to_chat(user, "\tBrain Activity Level: [(200 - M.getOrganLoss(ORGAN_SLOT_BRAIN))/2]%.") + render_list += "Brain Activity Level: [(200 - M.getOrganLoss(ORGAN_SLOT_BRAIN))/2]%.\n" if (M.radiation) - to_chat(user, "\tSubject is irradiated.") + render_list += "Subject is irradiated.\n" if(advanced) - to_chat(user, "\tRadiation Level: [M.radiation]%.") + render_list += "Radiation Level: [M.radiation]%.\n" if(advanced && M.hallucinating()) - to_chat(user, "\tSubject is hallucinating.") - - //Eyes and ears - if(advanced) - if(iscarbon(M)) - var/mob/living/carbon/C = M - var/obj/item/organ/ears/ears = C.getorganslot(ORGAN_SLOT_EARS) - to_chat(user, "\t==EAR STATUS==") - if(istype(ears)) - var/healthy = TRUE - if(HAS_TRAIT_FROM(C, TRAIT_DEAF, GENETIC_MUTATION)) - healthy = FALSE - to_chat(user, "\tSubject is genetically deaf.") - else if(HAS_TRAIT(C, TRAIT_DEAF)) - healthy = FALSE - to_chat(user, "\tSubject is deaf.") - else - if(ears.damage) - to_chat(user, "\tSubject has [ears.damage > ears.maxHealth ? "permanent ": "temporary "]hearing damage.") - healthy = FALSE - if(ears.deaf) - to_chat(user, "\tSubject is [ears.damage > ears.maxHealth ? "permanently ": "temporarily "] deaf.") - healthy = FALSE - if(healthy) - to_chat(user, "\tHealthy.") - else - to_chat(user, "\tSubject does not have ears.") - var/obj/item/organ/eyes/eyes = C.getorganslot(ORGAN_SLOT_EYES) - to_chat(user, "\t==EYE STATUS==") - if(istype(eyes)) - var/healthy = TRUE - if(HAS_TRAIT(C, TRAIT_BLIND)) - to_chat(user, "\tSubject is blind.") - healthy = FALSE - if(HAS_TRAIT(C, TRAIT_NEARSIGHT)) - to_chat(user, "\tSubject is nearsighted.") - healthy = FALSE - if(eyes.damage > 30) - to_chat(user, "\tSubject has severe eye damage.") - healthy = FALSE - else if(eyes.damage > 20) - to_chat(user, "\tSubject has significant eye damage.") - healthy = FALSE - else if(eyes.damage) - to_chat(user, "\tSubject has minor eye damage.") - healthy = FALSE - if(healthy) - to_chat(user, "\tHealthy.") - else - to_chat(user, "\tSubject does not have eyes.") - + render_list += "Subject is hallucinating.\n" // Body part damage report - if(iscarbon(M) && mode == 1) + if(iscarbon(M) && mode == SCANNER_VERBOSE) var/mob/living/carbon/C = M var/list/damaged = C.get_damaged_bodyparts(1,1) if(length(damaged)>0 || oxy_loss>0 || tox_loss>0 || fire_loss>0) - var/list/dmgreport = list() - dmgreport += "\ + var/dmgreport = "General status:\ +
\ \ \ \ \ \ - \ \ \ @@ -274,109 +229,106 @@ GENE SCANNER \ " dmgreport += "
Damage:BruteBurnToxinSuffocation
Overall:[CEILING(brute_loss,1)][CEILING(fire_loss,1)][(org.brute_dam > 0) ? "[CEILING(org.brute_dam,1)]" : "0"][(org.burn_dam > 0) ? "[CEILING(org.burn_dam,1)]" : "0"]
" - to_chat(user, dmgreport.Join()) + render_list += dmgreport // tables do not need extra linebreak + //Eyes and ears + if(advanced && iscarbon(M)) + var/mob/living/carbon/C = M + + // Ear status + var/obj/item/organ/ears/ears = C.getorganslot(ORGAN_SLOT_EARS) + var/message = "\nSubject does not have ears." + if(istype(ears)) + message = "" + if(HAS_TRAIT_FROM(C, TRAIT_DEAF, GENETIC_MUTATION)) + message = "\nSubject is genetically deaf." + else if(HAS_TRAIT(C, TRAIT_DEAF)) + message = "\nSubject is deaf." + else + if(ears.damage) + message += "\nSubject has [ears.damage > ears.maxHealth ? "permanent ": "temporary "]hearing damage." + if(ears.deaf) + message += "\nSubject is [ears.damage > ears.maxHealth ? "permanently ": "temporarily "] deaf." + render_list += "Ear status:[message == "" ? "\nHealthy." : message]\n" + + // Eye status + var/obj/item/organ/eyes/eyes = C.getorganslot(ORGAN_SLOT_EYES) + message = "\nSubject does not have eyes." + if(istype(eyes)) + message = "" + if(HAS_TRAIT(C, TRAIT_BLIND)) + message += "\nSubject is blind." + if(HAS_TRAIT(C, TRAIT_NEARSIGHT)) + message += "\nSubject is nearsighted." + if(eyes.damage > 30) + message += "\nSubject has severe eye damage." + else if(eyes.damage > 20) + message += "\nSubject has significant eye damage." + else if(eyes.damage) + message += "\nSubject has minor eye damage." + render_list += "Eye status:[message == "" ? "\nHealthy." : message]\n" - //Organ damages report if(ishuman(M)) var/mob/living/carbon/human/H = M - var/minor_damage - var/major_damage - var/max_damage - var/report_organs = FALSE - //Piece together the lists to be reported - for(var/O in H.internal_organs) - var/obj/item/organ/organ = O - if(organ.organ_flags & ORGAN_FAILING) - report_organs = TRUE //if we report one organ, we report all organs, even if the lists are empty, just for consistency - if(max_damage) - max_damage += ", " //prelude the organ if we've already reported an organ - max_damage += organ.name //this just slaps the organ name into the string of text - else - max_damage = "\tNon-Functional Organs: " //our initial statement - max_damage += organ.name - else if(organ.damage > organ.high_threshold) - report_organs = TRUE - if(major_damage) - major_damage += ", " - major_damage += organ.name - else - major_damage = "\tSeverely Damaged Organs: " - major_damage += organ.name - else if(organ.damage > organ.low_threshold) - report_organs = TRUE - if(minor_damage) - minor_damage += ", " - minor_damage += organ.name - else - minor_damage = "\tMildly Damaged Organs: " - minor_damage += organ.name + // Organ damage + if (H.internal_organs && H.internal_organs.len) + var/render = FALSE + var/toReport = "Organs:\ + \ + \ + [advanced ? "" : ""]\ + " + + for(var/obj/item/organ/organ in H.internal_organs) + var/status = "" + if (organ.organ_flags & ORGAN_FAILING) status = "Non-Functional" + else if (organ.damage > organ.high_threshold) status = "Severely Damaged" + else if (organ.damage > organ.low_threshold) status = "Mildly Damaged" + if (status != "") + render = TRUE + toReport += "\ + [advanced ? "" : ""]\ + " + + if (render) + render_list += toReport + "
OrganDmgStatus
[organ.name][CEILING(organ.damage,1)][status]
" // tables do not need extra linebreak - if(report_organs) //we either finish the list, or set it to be empty if no organs were reported in that category - if(!max_damage) - max_damage = "\tNon-Functional Organs: " - else - max_damage += "
" - if(!major_damage) - major_damage = "\tSeverely Damaged Organs: " - else - major_damage += "
" - if(!minor_damage) - minor_damage = "\tMildly Damaged Organs: " - else - minor_damage += "
" - to_chat(user, minor_damage) - to_chat(user, major_damage) - to_chat(user, max_damage) //Genetic damage if(advanced && H.has_dna()) - to_chat(user, "\tGenetic Stability: [H.dna.stability]%.") + render_list += "Genetic Stability: [H.dna.stability]%.\n" - // Species and body temperature - if(ishuman(M)) - var/mob/living/carbon/human/H = M + // Species and body temperature var/datum/species/S = H.dna.species - var/mutant = FALSE - if (H.dna.check_mutation(HULK)) - mutant = TRUE - else if (S.mutantlungs != initial(S.mutantlungs)) - mutant = TRUE - else if (S.mutant_brain != initial(S.mutant_brain)) - mutant = TRUE - else if (S.mutant_heart != initial(S.mutant_heart)) - mutant = TRUE - else if (S.mutanteyes != initial(S.mutanteyes)) - mutant = TRUE - else if (S.mutantears != initial(S.mutantears)) - mutant = TRUE - else if (S.mutanthands != initial(S.mutanthands)) - mutant = TRUE - else if (S.mutanttongue != initial(S.mutanttongue)) - mutant = TRUE - else if (S.mutanttail != initial(S.mutanttail)) - mutant = TRUE - else if (S.mutantliver != initial(S.mutantliver)) - mutant = TRUE - else if (S.mutantstomach != initial(S.mutantstomach)) - mutant = TRUE - else if (S.flying_species != initial(S.flying_species)) - mutant = TRUE + var/mutant = H.dna.check_mutation(HULK) \ + || S.mutantlungs != initial(S.mutantlungs) \ + || S.mutant_brain != initial(S.mutant_brain) \ + || S.mutant_heart != initial(S.mutant_heart) \ + || S.mutanteyes != initial(S.mutanteyes) \ + || S.mutantears != initial(S.mutantears) \ + || S.mutanthands != initial(S.mutanthands) \ + || S.mutanttongue != initial(S.mutanttongue) \ + || S.mutanttail != initial(S.mutanttail) \ + || S.mutantliver != initial(S.mutantliver) \ + || S.mutantstomach != initial(S.mutantstomach) \ + || S.flying_species != initial(S.flying_species) - to_chat(user, "Species: [S.name][mutant ? "-derived mutant" : ""]") - to_chat(user, "Body temperature: [round(M.bodytemperature-T0C,0.1)] °C ([round(M.bodytemperature*1.8-459.67,0.1)] °F)") + render_list += "Species: [S.name][mutant ? "-derived mutant" : ""]\n" + render_list += "Body temperature: [round(M.bodytemperature-T0C,0.1)] °C ([round(M.bodytemperature*1.8-459.67,0.1)] °F)\n" // Time of death if(M.tod && (M.stat == DEAD || ((HAS_TRAIT(M, TRAIT_FAKEDEATH)) && !advanced))) - to_chat(user, "Time of Death: [M.tod]") + render_list += "Time of Death: [M.tod]\n" var/tdelta = round(world.time - M.timeofdeath) if(tdelta < (DEFIB_TIME_LIMIT * 10)) - to_chat(user, "Subject died [DisplayTimeText(tdelta)] ago, defibrillation may be possible!") + render_list += "Subject died [DisplayTimeText(tdelta)] ago, defibrillation may be possible!\n" for(var/thing in M.diseases) var/datum/disease/D = thing if(!(D.visibility_flags & HIDDEN_SCANNER)) - to_chat(user, "Warning: [D.form] detected\nName: [D.name].\nType: [D.spread_text].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure_text]") + render_list += "Warning: [D.form] detected\n\ +
Name: [D.name].\nType: [D.spread_text].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure_text]
\ +
" // divs do not need extra linebreak // Blood Level if(M.has_dna()) @@ -386,46 +338,46 @@ GENE SCANNER if(ishuman(C)) var/mob/living/carbon/human/H = C if(H.bleed_rate) - to_chat(user, "Subject is bleeding!") + render_list += "Subject is bleeding!\n" var/blood_percent = round((C.blood_volume / BLOOD_VOLUME_NORMAL)*100) var/blood_type = C.dna.blood_type - if(blood_id != /datum/reagent/blood)//special blood substance + if(blood_id != /datum/reagent/blood) // special blood substance var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id] - if(R) - blood_type = R.name - else - blood_type = blood_id + blood_type = R ? R.name : blood_id if(C.blood_volume <= BLOOD_VOLUME_SAFE && C.blood_volume > BLOOD_VOLUME_OKAY) - to_chat(user, "Blood level: LOW [blood_percent] %, [C.blood_volume] cl, type: [blood_type]") + render_list += "Blood level: LOW [blood_percent] %, [C.blood_volume] cl, type: [blood_type]\n" else if(C.blood_volume <= BLOOD_VOLUME_OKAY) - to_chat(user, "Blood level: CRITICAL [blood_percent] %, [C.blood_volume] cl, type: [blood_type]") + render_list += "Blood level: CRITICAL [blood_percent] %, [C.blood_volume] cl, type: [blood_type]\n" else - to_chat(user, "Blood level: [blood_percent] %, [C.blood_volume] cl, type: [blood_type]") + render_list += "Blood level: [blood_percent] %, [C.blood_volume] cl, type: [blood_type]\n" - var/cyberimp_detect + var/cyberimp_detect = "" for(var/obj/item/organ/cyberimp/CI in C.internal_organs) if(CI.status == ORGAN_ROBOTIC && !CI.syndicate_implant) - cyberimp_detect += "[C.name] is modified with a [CI.name].
" - if(cyberimp_detect) - to_chat(user, "Detected cybernetic modifications:") - to_chat(user, "[cyberimp_detect]") + cyberimp_detect += "[C.name] is modified with a [CI.name].\n" + if(cyberimp_detect != "") + render_list += "Detected cybernetic modifications:\n[cyberimp_detect]\n" + SEND_SIGNAL(M, COMSIG_NANITE_SCAN, user, FALSE) + to_chat(user, jointext(render_list, ""), trailing_newline = FALSE) // we handled the last
so we don't need handholding /proc/chemscan(mob/living/user, mob/living/M) - if(istype(M)) - if(M.reagents) - if(M.reagents.reagent_list.len) - to_chat(user, "Subject contains the following reagents:") - for(var/datum/reagent/R in M.reagents.reagent_list) - to_chat(user, "[round(R.volume, 0.001)] units of [R.name][R.overdosed == 1 ? " - OVERDOSING" : "."]") - else - to_chat(user, "Subject contains no reagents.") - if(M.reagents.addiction_list.len) - to_chat(user, "Subject is addicted to the following reagents:") - for(var/datum/reagent/R in M.reagents.addiction_list) - to_chat(user, "[R.name]") - else - to_chat(user, "Subject is not addicted to any reagents.") + if(istype(M) && M.reagents) + var/render_list = list() + if(M.reagents.reagent_list.len) + render_list += "Subject contains the following reagents:\n" + for(var/datum/reagent/R in M.reagents.reagent_list) + render_list += "[round(R.volume, 0.001)] units of [R.name][R.overdosed == 1 ? " - OVERDOSING" : "."]\n" + else + render_list += "Subject contains no reagents.\n" + if(M.reagents.addiction_list.len) + render_list += "Subject is addicted to the following reagents:\n" + for(var/datum/reagent/R in M.reagents.addiction_list) + render_list += "[R.name]\n" + else + render_list += "Subject is not addicted to any reagents.\n" + + to_chat(user, jointext(render_list, ""), trailing_newline = FALSE) // we handled the last
so we don't need handholding /obj/item/healthanalyzer/verb/toggle_mode() set name = "Switch Verbosity" @@ -435,11 +387,7 @@ GENE SCANNER return mode = !mode - switch (mode) - if(1) - to_chat(usr, "The scanner now shows specific limb damage.") - if(0) - to_chat(usr, "The scanner no longer shows limb damage.") + to_chat(usr, mode == SCANNER_VERBOSE ? "The scanner now shows specific limb damage." : "The scanner no longer shows limb damage.") /obj/item/healthanalyzer/advanced name = "advanced health analyzer" @@ -488,16 +436,13 @@ GENE SCANNER if(!istype(location)) return + var/render_list = list() var/datum/gas_mixture/environment = location.return_air() - var/pressure = environment.return_pressure() var/total_moles = environment.total_moles() - to_chat(user, "Results:") - if(abs(pressure - ONE_ATMOSPHERE) < 10) - to_chat(user, "Pressure: [round(pressure, 0.01)] kPa") - else - to_chat(user, "Pressure: [round(pressure, 0.01)] kPa") + render_list += "Results:\ + \nPressure: [round(pressure, 0.01)] kPa\n" if(total_moles) var/list/env_gases = environment.gases @@ -507,25 +452,10 @@ GENE SCANNER var/co2_concentration = env_gases[/datum/gas/carbon_dioxide][MOLES]/total_moles var/plasma_concentration = env_gases[/datum/gas/plasma][MOLES]/total_moles - if(abs(n2_concentration - N2STANDARD) < 20) - to_chat(user, "Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/nitrogen][MOLES], 0.01)] mol)") - else - to_chat(user, "Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/nitrogen][MOLES], 0.01)] mol)") - - if(abs(o2_concentration - O2STANDARD) < 2) - to_chat(user, "Oxygen: [round(o2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/oxygen][MOLES], 0.01)] mol)") - else - to_chat(user, "Oxygen: [round(o2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/oxygen][MOLES], 0.01)] mol)") - - if(co2_concentration > 0.01) - to_chat(user, "CO2: [round(co2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/carbon_dioxide][MOLES], 0.01)] mol)") - else - to_chat(user, "CO2: [round(co2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/carbon_dioxide][MOLES], 0.01)] mol)") - - if(plasma_concentration > 0.005) - to_chat(user, "Plasma: [round(plasma_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/plasma][MOLES], 0.01)] mol)") - else - to_chat(user, "Plasma: [round(plasma_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/plasma][MOLES], 0.01)] mol)") + render_list += "Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/nitrogen][MOLES], 0.01)] mol)\ + \nOxygen: [round(o2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/oxygen][MOLES], 0.01)] mol)\ + \nCO2: [round(co2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/carbon_dioxide][MOLES], 0.01)] mol)\ + \nPlasma: [round(plasma_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/plasma][MOLES], 0.01)] mol)\n" environment.garbage_collect() @@ -533,14 +463,14 @@ GENE SCANNER if(id in GLOB.hardcoded_gases) continue var/gas_concentration = env_gases[id][MOLES]/total_moles - to_chat(user, "[env_gases[id][GAS_META][META_GAS_NAME]]: [round(gas_concentration*100, 0.01)] % ([round(env_gases[id][MOLES], 0.01)] mol)") - to_chat(user, "Temperature: [round(environment.temperature-T0C, 0.01)] °C ([round(environment.temperature, 0.01)] K)") + render_list += "[env_gases[id][GAS_META][META_GAS_NAME]]: [round(gas_concentration*100, 0.01)] % ([round(env_gases[id][MOLES], 0.01)] mol)\n" + render_list += "Temperature: [round(environment.temperature-T0C, 0.01)] °C ([round(environment.temperature, 0.01)] K)\n" + to_chat(user, jointext(render_list, ""), trailing_newline = FALSE) // we handled the last
so we don't need handholding /obj/item/analyzer/AltClick(mob/user) //Barometer output for measuring when the next storm happens ..() if(user.canUseTopic(src, BE_CLOSE)) - if(cooldown) to_chat(user, "[src]'s barometer function is preparing itself.") return @@ -605,14 +535,15 @@ GENE SCANNER return FALSE var/icon = target + var/render_list = list() if(!silent && isliving(user)) user.visible_message("[user] has used the analyzer on [icon2html(icon, viewers(user))] [target].", "You use the analyzer on [icon2html(icon, user)] [target].") - to_chat(user, "Results of analysis of [icon2html(icon, user)] [target].") + render_list += "Results of analysis of [icon2html(icon, user)] [target]." var/list/airs = islist(mixture) ? mixture : list(mixture) for(var/g in airs) if(airs.len > 1) //not a unary gas mixture - to_chat(user, "Node [airs.Find(g)]") + render_list += "Node [airs.Find(g)]" var/datum/gas_mixture/air_contents = g var/total_moles = air_contents.total_moles() @@ -622,26 +553,23 @@ GENE SCANNER var/cached_scan_results = air_contents.analyzer_results if(total_moles > 0) - to_chat(user, "Moles: [round(total_moles, 0.01)] mol") - to_chat(user, "Volume: [volume] L") - to_chat(user, "Pressure: [round(pressure,0.01)] kPa") + render_list += "Moles: [round(total_moles, 0.01)] mol\ + \nVolume: [volume] L\ + \nPressure: [round(pressure,0.01)] kPa" var/list/cached_gases = air_contents.gases for(var/id in cached_gases) var/gas_concentration = cached_gases[id][MOLES]/total_moles - to_chat(user, "[cached_gases[id][GAS_META][META_GAS_NAME]]: [round(gas_concentration*100, 0.01)] % ([round(cached_gases[id][MOLES], 0.01)] mol)") - to_chat(user, "Temperature: [round(temperature - T0C,0.01)] °C ([round(temperature, 0.01)] K)") - + render_list += "[cached_gases[id][GAS_META][META_GAS_NAME]]: [round(gas_concentration*100, 0.01)] % ([round(cached_gases[id][MOLES], 0.01)] mol)" + render_list += "Temperature: [round(temperature - T0C,0.01)] °C ([round(temperature, 0.01)] K)" else - if(airs.len > 1) - to_chat(user, "This node is empty!") - else - to_chat(user, "[target] is empty!") + render_list += airs.len > 1 ? "This node is empty!" : "[target] is empty!" if(cached_scan_results && cached_scan_results["fusion"]) //notify the user if a fusion reaction was detected - var/instability = round(cached_scan_results["fusion"], 0.01) - to_chat(user, "Large amounts of free neutrons detected in the air indicate that a fusion reaction took place.") - to_chat(user, "Instability of the last fusion reaction: [instability].") + render_list += "Large amounts of free neutrons detected in the air indicate that a fusion reaction took place.\ + \nInstability of the last fusion reaction: [round(cached_scan_results["fusion"], 0.01)]." + + to_chat(user, jointext(render_list, "\n")) // we let the join apply newlines so we do need handholding return TRUE //slime scanner @@ -671,36 +599,35 @@ GENE SCANNER slime_scan(T, user) /proc/slime_scan(mob/living/simple_animal/slime/T, mob/living/user) - to_chat(user, "========================") - to_chat(user, "Slime scan results:") - to_chat(user, "[T.colour] [T.is_adult ? "adult" : "baby"] slime") - to_chat(user, "Nutrition: [T.nutrition]/[T.get_max_nutrition()]") + var/to_render = "========================\ + \nSlime scan results:\ + \n[T.colour] [T.is_adult ? "adult" : "baby"] slime\ + \nNutrition: [T.nutrition]/[T.get_max_nutrition()]" if (T.nutrition < T.get_starve_nutrition()) - to_chat(user, "Warning: slime is starving!") + to_render += "\nWarning: slime is starving!" else if (T.nutrition < T.get_hunger_nutrition()) - to_chat(user, "Warning: slime is hungry") - to_chat(user, "Electric change strength: [T.powerlevel]") - to_chat(user, "Health: [round(T.health/T.maxHealth,0.01)*100]%") + to_render += "\nWarning: slime is hungry" + to_render += "\nElectric change strength: [T.powerlevel]\nHealth: [round(T.health/T.maxHealth,0.01)*100]%" if (T.slime_mutation[4] == T.colour) - to_chat(user, "This slime does not evolve any further.") + to_render += "\nThis slime does not evolve any further." else if (T.slime_mutation[3] == T.slime_mutation[4]) if (T.slime_mutation[2] == T.slime_mutation[1]) - to_chat(user, "Possible mutation: [T.slime_mutation[3]]") - to_chat(user, "Genetic destability: [T.mutation_chance/2] % chance of mutation on splitting") + to_render += "\nPossible mutation: [T.slime_mutation[3]]\ + \nGenetic destability: [T.mutation_chance/2] % chance of mutation on splitting" else - to_chat(user, "Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]] (x2)") - to_chat(user, "Genetic destability: [T.mutation_chance] % chance of mutation on splitting") + to_render += "\nPossible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]] (x2)\ + \nGenetic destability: [T.mutation_chance] % chance of mutation on splitting" else - to_chat(user, "Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]], [T.slime_mutation[4]]") - to_chat(user, "Genetic destability: [T.mutation_chance] % chance of mutation on splitting") + to_render += "\nPossible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]], [T.slime_mutation[4]]\ + \nGenetic destability: [T.mutation_chance] % chance of mutation on splitting" if (T.cores > 1) - to_chat(user, "Multiple cores detected") - to_chat(user, "Growth progress: [T.amount_grown]/[SLIME_EVOLUTION_THRESHOLD]") + to_render += "\nMultiple cores detected" + to_render += "\nGrowth progress: [T.amount_grown]/[SLIME_EVOLUTION_THRESHOLD]" if(T.effectmod) - to_chat(user, "Core mutation in progress: [T.effectmod]") - to_chat(user, "Progress in core mutation: [T.applied] / [SLIME_EXTRACT_CROSSING_REQUIRED]") - to_chat(user, "========================") + to_render += "\nCore mutation in progress: [T.effectmod]\ + \nProgress in core mutation: [T.applied] / [SLIME_EXTRACT_CROSSING_REQUIRED]" + to_chat(user, to_render + "\n========================") /obj/item/nanite_scanner @@ -870,3 +797,8 @@ GENE SCANNER /obj/item/scanner_wand/proc/return_patient() var/returned_target = selected_target return returned_target + +#undef SCANMODE_HEALTH +#undef SCANMODE_CHEMICAL +#undef SCANNER_CONDENSED +#undef SCANNER_VERBOSE diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index ebe15c5e7c9..21ffdf66624 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -233,7 +233,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico log_world("\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: [(src.owner.key ? src.owner.key : src.owner)] triggered JS error: [error]") //Global chat procs -/proc/to_chat_immediate(target, message, handle_whitespace = TRUE) +/proc/to_chat_immediate(target, message, handle_whitespace = TRUE, trailing_newline = TRUE) if(!target || !message) return @@ -244,6 +244,8 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico if(handle_whitespace) message = replacetext(message, "\n", "
") message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]") //EIGHT SPACES IN TOTAL!! + if(trailing_newline) + message += "
" if(islist(target)) // Do the double-encoding outside the loop to save nanoseconds @@ -286,11 +288,11 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico // url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript. C << output(url_encode(url_encode(message)), "browseroutput:output") -/proc/to_chat(target, message, handle_whitespace = TRUE) +/proc/to_chat(target, message, handle_whitespace = TRUE, trailing_newline = TRUE) if(Master.current_runlevel == RUNLEVEL_INIT || !SSchat?.initialized) - to_chat_immediate(target, message, handle_whitespace) + to_chat_immediate(target, message, handle_whitespace, trailing_newline) return - SSchat.queue(target, message, handle_whitespace) + SSchat.queue(target, message, handle_whitespace, trailing_newline) /datum/chatOutput/proc/swaptolightmode() //Dark mode light mode stuff. Yell at KMC if this breaks! (See darkmode.dm for documentation) owner.force_white_theme() diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css index 830ebae79e0..bbd7ddc83d2 100644 --- a/code/modules/goonchat/browserassets/css/browserOutput.css +++ b/code/modules/goonchat/browserassets/css/browserOutput.css @@ -405,3 +405,6 @@ em {font-style: normal; font-weight: bold;} /* HELPER CLASSES */ .text-normal {font-weight: normal; font-style: normal;} .hidden {display: none; visibility: hidden;} +.ml-1 {margin-left: 1em;} +.ml-2 {margin-left: 2em;} +.ml-3 {margin-left: 3em;} diff --git a/code/modules/goonchat/browserassets/css/browserOutput_white.css b/code/modules/goonchat/browserassets/css/browserOutput_white.css index 9839b284c65..a1f8fc1dbaf 100644 --- a/code/modules/goonchat/browserassets/css/browserOutput_white.css +++ b/code/modules/goonchat/browserassets/css/browserOutput_white.css @@ -403,3 +403,6 @@ h1.alert, h2.alert {color: #000000;} /* HELPER CLASSES */ .text-normal {font-weight: normal; font-style: normal;} .hidden {display: none; visibility: hidden;} +.ml-1 {margin-left: 1em;} +.ml-2 {margin-left: 2em;} +.ml-3 {margin-left: 3em;}