From 91a3a29b27b47565c26c8dbe2bbea939c4746a8e Mon Sep 17 00:00:00 2001 From: vhbraz <54181477+Kaksisilma@users.noreply.github.com> Date: Sun, 20 Mar 2022 14:54:26 -0300 Subject: [PATCH] Complete virology addition CI fixes Ci Fixes 2 Map changes. CI fix? --- baystation12.dme | 14 + code/__defines/skills.dm | 1 + code/_global_vars/lists/objects.dm | 1 + code/_helpers/global_access.dm | 10 + code/_helpers/medical_scans.dm | 7 + code/controllers/subsystems/supply.dm | 13 + code/datums/supplypacks/science.dm | 8 + code/game/area/Space Station 13 areas.dm | 2 +- code/game/machinery/kitchen/smartfridge.dm | 6 +- .../effects/decals/Cleanable/humans.dm | 3 + .../objects/effects/decals/Cleanable/misc.dm | 1 + code/game/objects/effects/gibs.dm | 1 + .../objects/items/devices/scanners/health.dm | 7 + .../circuitboards/computer/computer.dm | 14 + code/game/turfs/simulated.dm | 1 + code/modules/admin/admin_verbs.dm | 30 + code/modules/admin/view_variables/helpers.dm | 4 +- code/modules/admin/view_variables/topic.dm | 11 + code/modules/events/event_container.dm | 1 + code/modules/events/space_cold.dm | 18 + code/modules/food/recipes_microwave.dm | 7 + code/modules/item_worth/worths_list.dm | 4 + code/modules/mob/living/bot/medibot.dm | 1 + code/modules/mob/living/carbon/carbon.dm | 2 + .../mob/living/carbon/carbon_defines.dm | 3 +- code/modules/mob/living/carbon/human/human.dm | 4 + .../living/carbon/human/human_attackhand.dm | 3 + code/modules/mob/living/carbon/human/life.dm | 16 + code/modules/mob/living/carbon/viruses.dm | 53 +- .../robot/flying/module_flying_ascent.dm | 1 + .../silicon/robot/modules/module_medical.dm | 4 +- .../living/simple_animal/hostile/vagrant.dm | 9 + code/modules/mob/skills/skill.dm | 9 + code/modules/organs/blood.dm | 26 +- .../Chemistry-Reagents-Core.dm | 45 + .../Chemistry-Reagents-Dispenser.dm | 13 + .../Chemistry-Reagents-Food-Drinks.dm | 9 + code/modules/reagents/Chemistry-Recipes.dm | 7 + .../reagents/reagent_containers/blood_pack.dm | 2 +- .../reagents/reagent_containers/glass.dm | 4 +- code/modules/reagents/reagent_dispenser.dm | 9 + .../research/designs/designs_circuits.dm | 14 + code/modules/species/mantid/mantid.dm | 2 + code/modules/species/species.dm | 1 + code/modules/species/species_getters.dm | 3 + code/modules/species/station/adherent.dm | 1 + code/modules/species/station/machine.dm | 1 + code/modules/species/station/prometheans.dm | 1 + code/modules/surgery/surgery.dm | 1 + code/modules/virus2/admin.dm | 215 +++ code/modules/virus2/analyser.dm | 78 + code/modules/virus2/antibodies.dm | 26 + code/modules/virus2/antibodyanalyser.dm | 72 + code/modules/virus2/centrifuge.dm | 215 +++ code/modules/virus2/curer.dm | 98 ++ code/modules/virus2/disease2.dm | 259 +++ code/modules/virus2/diseasesplicer.dm | 187 ++ code/modules/virus2/dishincubator.dm | 200 +++ code/modules/virus2/effect.dm | 406 +++++ code/modules/virus2/helpers.dm | 191 ++ code/modules/virus2/isolator.dm | 227 +++ code/modules/virus2/items_devices.dm | 108 ++ maps/away/lar_maria/lar_maria.dm | 78 + maps/torch/items/cards_ids.dm | 3 + maps/torch/job/command_jobs.dm | 3 +- maps/torch/job/medical_jobs.dm | 40 +- maps/torch/job/outfits/boh_outfits.dm | 5 + maps/torch/job/outfits/medical_outfits.dm | 15 + maps/torch/job/torch_jobs.dm | 2 +- maps/torch/job/torch_jobs_boh.dm | 14 + maps/torch/loadout/_defines.dm | 10 +- maps/torch/loadout/loadout_accessories.dm | 2 +- maps/torch/loadout/loadout_suit.dm | 2 +- maps/torch/structures/closets/medical.dm | 27 + maps/torch/torch4_deck2.dmm | 28 +- maps/torch/torch5_deck1.dmm | 1543 +++++++++++++---- maps/torch/torch_areas.dm | 2 +- maps/torch/torch_unit_testing.dm | 3 - nano/templates/disease_splicer.tmpl | 124 ++ nano/templates/dish_incubator.tmpl | 123 ++ nano/templates/isolation_centrifuge.tmpl | 81 + nano/templates/pathogenic_isolator.tmpl | 107 ++ test/check-paths.sh | 4 +- 83 files changed, 4544 insertions(+), 362 deletions(-) create mode 100644 code/modules/events/space_cold.dm create mode 100644 code/modules/virus2/admin.dm create mode 100644 code/modules/virus2/analyser.dm create mode 100644 code/modules/virus2/antibodies.dm create mode 100644 code/modules/virus2/antibodyanalyser.dm create mode 100644 code/modules/virus2/centrifuge.dm create mode 100644 code/modules/virus2/curer.dm create mode 100644 code/modules/virus2/disease2.dm create mode 100644 code/modules/virus2/diseasesplicer.dm create mode 100644 code/modules/virus2/dishincubator.dm create mode 100644 code/modules/virus2/effect.dm create mode 100644 code/modules/virus2/helpers.dm create mode 100644 code/modules/virus2/isolator.dm create mode 100644 code/modules/virus2/items_devices.dm create mode 100644 nano/templates/disease_splicer.tmpl create mode 100644 nano/templates/dish_incubator.tmpl create mode 100644 nano/templates/isolation_centrifuge.tmpl create mode 100644 nano/templates/pathogenic_isolator.tmpl diff --git a/baystation12.dme b/baystation12.dme index 158ec701a70..ced256d581f 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -1873,6 +1873,7 @@ #include "code\modules\events\sensor_suit_jamming.dm" #include "code\modules\events\shipping_error.dm" #include "code\modules\events\solar_storm.dm" +#include "code\modules\events\space_cold.dm" #include "code\modules\events\spacevine.dm" #include "code\modules\events\spider_infestation.dm" #include "code\modules\events\spontaneous_appendicitis.dm" @@ -3231,6 +3232,19 @@ #include "code\modules\ventcrawl\ventcrawl_atmospherics.dm" #include "code\modules\ventcrawl\ventcrawl_multiz.dm" #include "code\modules\ventcrawl\ventcrawl_verb.dm" +#include "code\modules\virus2\admin.dm" +#include "code\modules\virus2\analyser.dm" +#include "code\modules\virus2\antibodies.dm" +#include "code\modules\virus2\antibodyanalyser.dm" +#include "code\modules\virus2\centrifuge.dm" +#include "code\modules\virus2\curer.dm" +#include "code\modules\virus2\disease2.dm" +#include "code\modules\virus2\diseasesplicer.dm" +#include "code\modules\virus2\dishincubator.dm" +#include "code\modules\virus2\effect.dm" +#include "code\modules\virus2\helpers.dm" +#include "code\modules\virus2\isolator.dm" +#include "code\modules\virus2\items_devices.dm" #include "code\modules\Vox2\vox_machines.dm" #include "code\modules\vueui\external.dm" #include "code\modules\vueui\ui.dm" diff --git a/code/__defines/skills.dm b/code/__defines/skills.dm index c917500950f..2f9575d530e 100644 --- a/code/__defines/skills.dm +++ b/code/__defines/skills.dm @@ -33,4 +33,5 @@ #define SKILL_SCIENCE /decl/hierarchy/skill/research/science #define SKILL_MEDICAL /decl/hierarchy/skill/medical/medical #define SKILL_ANATOMY /decl/hierarchy/skill/medical/anatomy +#define SKILL_VIROLOGY /decl/hierarchy/skill/medical/medical/virology #define SKILL_CHEMISTRY /decl/hierarchy/skill/medical/chemistry \ No newline at end of file diff --git a/code/_global_vars/lists/objects.dm b/code/_global_vars/lists/objects.dm index 0b3e0d200c6..0a00c0af7c5 100644 --- a/code/_global_vars/lists/objects.dm +++ b/code/_global_vars/lists/objects.dm @@ -1,3 +1,4 @@ +GLOBAL_LIST_EMPTY(active_diseases) GLOBAL_LIST_EMPTY(med_hud_users) // List of all entities using a medical HUD. GLOBAL_LIST_EMPTY(sec_hud_users) // List of all entities using a security HUD. GLOBAL_LIST_EMPTY(jani_hud_users) diff --git a/code/_helpers/global_access.dm b/code/_helpers/global_access.dm index d31fb1f78c1..c89122cb157 100644 --- a/code/_helpers/global_access.dm +++ b/code/_helpers/global_access.dm @@ -1,6 +1,8 @@ // THIS FILE IS AUTOMATICALLY CREATED BY tools/gen_globals.py /proc/readglobal(which) switch(which) + if("ALL_ANTIGENS") + return global.ALL_ANTIGENS; if("ANTAG_FREQS") return global.ANTAG_FREQS; if("BSACooldown") @@ -909,6 +911,8 @@ return global.view_variables_dont_expand; if("view_variables_no_assoc") return global.view_variables_no_assoc; + if("virusDB") + return global.virusDB; if("visual_nets") return global.visual_nets; if("vsc") @@ -944,6 +948,8 @@ /proc/writeglobal(which, newval) switch(which) + if("ALL_ANTIGENS") + global.ALL_ANTIGENS=newval; if("ANTAG_FREQS") global.ANTAG_FREQS=newval; if("BSACooldown") @@ -1852,6 +1858,8 @@ global.view_variables_dont_expand=newval; if("view_variables_no_assoc") global.view_variables_no_assoc=newval; + if("virusDB") + global.virusDB=newval; if("visual_nets") global.visual_nets=newval; if("vsc") @@ -1886,6 +1894,7 @@ global.zone_blocked=newval; /var/list/_all_globals=list( + "ALL_ANTIGENS", "ANTAG_FREQS", "BSACooldown", "BUMP_TELEPORTERS", @@ -2342,6 +2351,7 @@ "ventcrawl_machinery", "view_variables_dont_expand", "view_variables_no_assoc", + "virusDB", "visual_nets", "vsc", "wax_recipes", diff --git a/code/_helpers/medical_scans.dm b/code/_helpers/medical_scans.dm index 85da3f3dd6b..8a4672ea390 100644 --- a/code/_helpers/medical_scans.dm +++ b/code/_helpers/medical_scans.dm @@ -46,6 +46,8 @@ scan["genetic"] = H.getCloneLoss() scan["paralysis"] = H.paralysis scan["immune_system"] = H.virus_immunity() + if (H.virus2.len) + scan["virus"] = TRUE scan["worms"] = H.has_brain_worms() scan["reagents"] = list() @@ -234,6 +236,11 @@
Large growth detected in frontal lobe, possibly cancerous.
*/ dat += "Antibody levels and immune system perfomance are at [scan["immune_system"]*100]% of baseline." + if (scan["virus"]) + if(skill_level >= SKILL_ADEPT) + dat += "
Viral pathogen detected in blood stream.
" + else + dat += "
Viral pathogen detected in blood stream.
" if(scan["worms"]) dat += "
Large growth detected in frontal lobe, possibly cancerous.
" diff --git a/code/controllers/subsystems/supply.dm b/code/controllers/subsystems/supply.dm index 4cf1c5f8989..16c7b7bc554 100644 --- a/code/controllers/subsystems/supply.dm +++ b/code/controllers/subsystems/supply.dm @@ -25,9 +25,13 @@ SUBSYSTEM_DEF(supply) "time" = "Base station supply", "manifest" = "From exported manifests", "crate" = "From exported crates", + "virology_antibodies" = "From uploaded antibody data", + "virology_dishes" = "From exported virus dishes", "gep" = "From uploaded good explorer points", "total" = "Total" // If you're adding additional point sources, add it here in a new line. Don't forget to put a comma after the old last line. ) + //virus dishes uniqueness + var/list/sold_virus_strains = list() /datum/controller/subsystem/supply/Initialize() . = ..() @@ -112,6 +116,15 @@ SUBSYSTEM_DEF(supply) var/obj/item/weapon/disk/survey/D = A add_points_from_source(round(D.Value() * 0.005), "gep") + // Sell virus dishes. + if(istype(A, /obj/item/weapon/virusdish)) + //Obviously the dish must be unique and never sold before. + var/obj/item/weapon/virusdish/dish = A + if(dish.analysed && istype(dish.virus2) && dish.virus2.uniqueID) + if(!(dish.virus2.uniqueID in sold_virus_strains)) + add_points_from_source(5, "virology_dishes") + sold_virus_strains += dish.virus2.uniqueID + qdel(AM) if(material_count.len) diff --git a/code/datums/supplypacks/science.dm b/code/datums/supplypacks/science.dm index 81df2f28cdc..ddf25d75c0f 100644 --- a/code/datums/supplypacks/science.dm +++ b/code/datums/supplypacks/science.dm @@ -10,6 +10,14 @@ containertype = /obj/structure/largecrate containername = "reagent dispenser crate" +/decl/hierarchy/supply_pack/science/virus + name = "Samples - Virus (BIOHAZARD)" + contains = list(/obj/item/weapon/virusdish/random = 4) + cost = 25 + containertype = /obj/structure/closet/crate/secure + containername = "virus sample crate" + access = access_cmo + /decl/hierarchy/supply_pack/science/coolanttank name = "Liquid - Coolant tank" contains = list(/obj/structure/reagent_dispensers/coolanttank) diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 55c4ba610ba..8e75dd3db61 100644 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -127,7 +127,7 @@ area/space/atmosalert() /area/medical/virology/access name = "\improper Virology Access" icon_state = "virology" - req_access = list() // This is like the lobby, needs low access to allow passing through in a different direction. + req_access = list(access_virology) /area/security req_access = list(access_sec_doors) diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm index 7c7bfd3c6d7..6223c6552b9 100644 --- a/code/game/machinery/kitchen/smartfridge.dm +++ b/code/game/machinery/kitchen/smartfridge.dm @@ -93,6 +93,8 @@ /obj/machinery/smartfridge/secure/virology/accept_check(var/obj/item/O as obj) if(istype(O,/obj/item/weapon/reagent_containers/glass/beaker/vial/)) return 1 + if(istype(O,/obj/item/weapon/virusdish/)) + return 1 return 0 /obj/machinery/smartfridge/chemistry @@ -177,7 +179,7 @@ var/remove_thing = FALSE if(istype(thing, /obj/item/weapon/reagent_containers/food/snacks)) var/obj/item/weapon/reagent_containers/food/snacks/S = thing - if(S.dry || !I.get_specific_product(get_turf(src), S)) + if(S.dry || !I.get_specific_product(get_turf(src), S)) continue if(S.dried_type == S.type) S.dry = 1 @@ -200,7 +202,7 @@ var/material/leather_mat = SSmaterials.get_material_by_name(skin_mat.tans_to) stock_item(new leather_mat.stack_type(get_turf(src), skin.amount, skin_mat.tans_to)) remove_thing = TRUE - + if(remove_thing) I.instances -= thing I.amount-- diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index 18f153a82cb..42fc3b0d01a 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -21,7 +21,9 @@ var/global/list/image/splatter_cache=list() scent_descriptor = SCENT_DESC_ODOR var/base_icon = 'icons/effects/blood.dmi' + var/list/viruses = list() var/basecolor=COLOR_BLOOD_HUMAN // Color when wet. + var/list/datum/disease2/disease/virus2 = list() var/amount = 5 var/drytime var/dryname = "dried blood" @@ -271,6 +273,7 @@ var/global/list/image/splatter_cache=list() icon_state = "mucus" generic_filth = TRUE persistent = TRUE + var/list/datum/disease2/disease/virus2 = list() var/dry=0 // Keeps the lag down /obj/effect/decal/cleanable/mucus/New() diff --git a/code/game/objects/effects/decals/Cleanable/misc.dm b/code/game/objects/effects/decals/Cleanable/misc.dm index 48fa277a547..b1938747eea 100644 --- a/code/game/objects/effects/decals/Cleanable/misc.dm +++ b/code/game/objects/effects/decals/Cleanable/misc.dm @@ -81,6 +81,7 @@ icon_state = "vomit_1" persistent = TRUE generic_filth = TRUE + var/list/viruses = list() /obj/effect/decal/cleanable/vomit/New() random_icon_states = icon_states(icon) diff --git a/code/game/objects/effects/gibs.dm b/code/game/objects/effects/gibs.dm index d9d0e731155..37e25f1ce92 100644 --- a/code/game/objects/effects/gibs.dm +++ b/code/game/objects/effects/gibs.dm @@ -5,6 +5,7 @@ icon = 'icons/mob/screen1.dmi' icon_state = "x3" var/sparks = 0 //whether sparks spread on Gib() + var/virusProb = 20 //the chance for viruses to spread on the gibs var/list/gibtypes = list() var/list/gibamounts = list() var/list/gibdirections = list() //of lists diff --git a/code/game/objects/items/devices/scanners/health.dm b/code/game/objects/items/devices/scanners/health.dm index 32907156b80..a61e0973ca4 100644 --- a/code/game/objects/items/devices/scanners/health.dm +++ b/code/game/objects/items/devices/scanners/health.dm @@ -289,6 +289,13 @@ if(chemtraces.len) . += "Metabolism products of [english_list(chemtraces)] found in subject's system." + if(H.virus2.len) + for (var/ID in H.virus2) + if (ID in virusDB) + print_reagent_default_message = FALSE + var/datum/computer_file/data/virus_record/V = virusDB[ID] + . += "Warning: Pathogen [V.fields["name"]] detected in subject's blood. Known antigen : [V.fields["antigen"]]" + if(print_reagent_default_message) . += "No results." diff --git a/code/game/objects/items/weapons/circuitboards/computer/computer.dm b/code/game/objects/items/weapons/circuitboards/computer/computer.dm index bb06a9100e3..15eba04022b 100644 --- a/code/game/objects/items/weapons/circuitboards/computer/computer.dm +++ b/code/game/objects/items/weapons/circuitboards/computer/computer.dm @@ -73,6 +73,20 @@ build_path = /obj/machinery/computer/operating origin_tech = list(TECH_DATA = 2, TECH_BIO = 2) +/obj/item/weapon/stock_parts/circuitboard/curefab + name = T_BOARD("cure fabricator") + build_path = /obj/machinery/computer/curer + +/obj/item/weapon/stock_parts/circuitboard/splicer + name = T_BOARD("disease splicer") + build_path = /obj/machinery/computer/diseasesplicer + origin_tech = list(TECH_DATA = 5, TECH_BIO = 5) + +/obj/item/weapon/stock_parts/circuitboard/centrifuge + name = T_BOARD("isolation centrifuge") + build_path = /obj/machinery/computer/centrifuge + origin_tech = list(TECH_DATA = 2, TECH_BIO = 3) + /obj/item/weapon/stock_parts/circuitboard/helm name = T_BOARD("helm control console") build_path = /obj/machinery/computer/ship/helm diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index 4eb86103109..615a06e2c73 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -143,6 +143,7 @@ B.blood_DNA = list() if(!B.blood_DNA[M.dna.unique_enzymes]) B.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type + B.virus2 = virus_copylist(M.virus2) return 1 //we bloodied the floor blood_splatter(src,M.get_blood(M.vessel),1) return 1 //we bloodied the floor diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 583efa616ab..4a9fb88cd83 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -669,6 +669,36 @@ var/list/admin_verbs_mod = list( log_and_message_admins("created an admin explosion at [epicenter.loc].") SSstatistics.add_field_details("admin_verb","DB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +/client/proc/give_disease2(mob/T as mob in SSmobs.mob_list) // -- Giacom + set category = "Fun" + set name = "Give Disease" + set desc = "Gives a Disease to a mob." + + var/datum/disease2/disease/D = new /datum/disease2/disease() + + var/severity = 1 + var/greater = input("Is this a lesser, greater, or badmin disease? (severity 1, 2, or 99)", "Give Disease") in list("Lesser", "Greater", "Badmin") + switch(greater) + if ("Lesser") severity = 1 + if ("Greater") severity = 2 + if ("Badmin") severity = 99 + + D.makerandom(severity) + D.infectionchance = input("How virulent is this disease? (1-100)", "Give Disease", D.infectionchance) as num + + if(istype(T,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = T + if (H.species) + D.affected_species = list(H.species.get_bodytype(H)) + if(H.species.primitive_form) + D.affected_species |= H.species.primitive_form + if(H.species.greater_form) + D.affected_species |= H.species.greater_form + infect_virus2(T,D,1) + + SSstatistics.add_field_details("admin_verb","GD2") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + log_and_message_admins("gave [key_name(T)] a [greater] disease2 with infection chance [D.infectionchance].") + /client/proc/togglebuildmodeself() set name = "Toggle Build Mode Self" set category = "Special Verbs" diff --git a/code/modules/admin/view_variables/helpers.dm b/code/modules/admin/view_variables/helpers.dm index 0988d95591d..f811c715526 100644 --- a/code/modules/admin/view_variables/helpers.dm +++ b/code/modules/admin/view_variables/helpers.dm @@ -39,6 +39,8 @@ + + @@ -154,7 +156,7 @@ // The following vars require R_DEBUG to edit /datum/proc/VV_locked() - return list("vars", "cuffed") + return list("vars", "viruses", "cuffed") /client/VV_locked() return list("vars", "mob") diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm index 4a54eed28af..1686f033800 100644 --- a/code/modules/admin/view_variables/topic.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -119,6 +119,17 @@ src.give_spell(M) href_list["datumrefresh"] = href_list["give_spell"] + else if(href_list["give_disease2"]) + if(!check_rights(R_ADMIN|R_FUN)) return + + var/mob/M = locate(href_list["give_disease2"]) + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + + src.give_disease2(M) + href_list["datumrefresh"] = href_list["give_spell"] + else if(href_list["godmode"]) if(!check_rights(R_REJUVINATE)) return diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index cdd87150f88..50919b4c035 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -144,6 +144,7 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Vermin Infestation", /datum/event/infestation, 100, list(ASSIGNMENT_JANITOR = 100)), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Wallrot", /datum/event/wallrot, 0, list(ASSIGNMENT_ENGINEER = 30, ASSIGNMENT_GARDENER = 50)), new /datum/event_meta/no_overmap(EVENT_LEVEL_MUNDANE, "Electrical Storm", /datum/event/electrical_storm, 20, list(ASSIGNMENT_ENGINEER = 20, ASSIGNMENT_JANITOR = 100)), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Space Cold Outbreak", /datum/event/space_cold, 100, list(ASSIGNMENT_MEDICAL = 20)), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Toilet Clog", /datum/event/toilet_clog, 50, list(ASSIGNMENT_JANITOR = 20)), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Drone Malfunction", /datum/event/rogue_maint_drones/, 10, list(ASSIGNMENT_ENGINEER = 30)), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Disposals Explosion", /datum/event/disposals_explosion/, 50, list(ASSIGNMENT_ENGINEER = 40)), diff --git a/code/modules/events/space_cold.dm b/code/modules/events/space_cold.dm new file mode 100644 index 00000000000..f1356278e94 --- /dev/null +++ b/code/modules/events/space_cold.dm @@ -0,0 +1,18 @@ +datum/event/space_cold/start() + var/list/candidates = list() //list of candidate keys + for(var/mob/living/carbon/human/G in GLOB.player_list) + if(G.client && G.stat != DEAD && !G.species.get_virus_immune(G)) + candidates += G + + if(!candidates.len) + return + + var/datum/disease2/disease/sniffle = new + sniffle.max_stage = 3 + sniffle.makerandom(1) + sniffle.spreadtype = "Airborne" + + var/victims = min(rand(1,3), candidates.len) + while(victims) + infect_virus2(pick_n_take(candidates),sniffle,1) + victims-- \ No newline at end of file diff --git a/code/modules/food/recipes_microwave.dm b/code/modules/food/recipes_microwave.dm index dd601c3aaec..787c6d217e5 100644 --- a/code/modules/food/recipes_microwave.dm +++ b/code/modules/food/recipes_microwave.dm @@ -921,6 +921,13 @@ I said no! ) result = /obj/item/weapon/reagent_containers/food/snacks/tofurkey +// Fuck Science! +/datum/recipe/ruinedvirusdish + items = list( + /obj/item/weapon/virusdish + ) + result = /obj/item/weapon/ruinedvirusdish + ////////////////////////////////////////// // bs12 food port stuff ////////////////////////////////////////// diff --git a/code/modules/item_worth/worths_list.dm b/code/modules/item_worth/worths_list.dm index 2ec284bb442..8d94ee0cdbd 100644 --- a/code/modules/item_worth/worths_list.dm +++ b/code/modules/item_worth/worths_list.dm @@ -163,6 +163,8 @@ var/list/worths = list( /obj/item/weapon/anodevice = 3300, /obj/item/weapon/scrying = 1000, /obj/item/weapon/magic_rock = 1500, + /obj/item/weapon/virusdish = 65, + /obj/item/weapon/diseasedisk = 100, /obj/item/weapon/cane/concealed = 150, /obj/item/weapon/cane = 40, /obj/item/weapon/caution = 15, @@ -648,6 +650,8 @@ var/list/worths = list( /obj/machinery/keycard_auth = -100, /obj/machinery/power/supermatter/shard = 100000, /obj/machinery/power/supermatter = 500000, + /obj/machinery/disease2/diseaseanalyser = -8000, + /obj/machinery/disease2/isolator/ = -9000, /obj/machinery/atmospherics/pipe/simple/heat_exchanging = -1000, /obj/machinery/atmospherics/pipe = -100, /obj/machinery/atmospherics/portables_connector = -500, diff --git a/code/modules/mob/living/bot/medibot.dm b/code/modules/mob/living/bot/medibot.dm index 50667988980..a60b7158fe6 100644 --- a/code/modules/mob/living/bot/medibot.dm +++ b/code/modules/mob/living/bot/medibot.dm @@ -20,6 +20,7 @@ var/treatment_oxy = /datum/reagent/tricordrazine var/treatment_fire = /datum/reagent/tricordrazine var/treatment_tox = /datum/reagent/tricordrazine + var/treatment_virus = /datum/reagent/spaceacillin var/treatment_emag = /datum/reagent/toxin var/declare_treatment = 0 //When attempting to treat a patient, should it notify everyone wearing medhuds? diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index f2c04adb7f0..36af2a1da40 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -365,6 +365,8 @@ if(now_pushing || !yes) return ..() + if(istype(AM, /mob/living/carbon) && prob(10)) + src.spread_disease_to(AM, "Contact") /mob/living/carbon/slip(slipped_on, stun_duration = 8) var/area/A = get_area(src) diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 05c28f4b24f..f024aa9ebf7 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -1,7 +1,8 @@ /mob/living/carbon/ gender = MALE var/datum/species/species //Contains icon generation and language information, set during New(). - + var/list/datum/disease2/disease/virus2 = list() + var/list/antibodies = list() var/life_tick = 0 // The amount of life ticks that have processed on this mob. var/obj/item/handcuffed = null //Whether or not the mob is handcuffed //Surgery info diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index fb6a08c8345..71035d56faf 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -923,6 +923,10 @@ H.brainmob.mind.transfer_to(src) qdel(H) + for (var/ID in virus2) + var/datum/disease2/disease/V = virus2[ID] + V.cure(src) + losebreath = 0 ..() diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index 469e3eff0aa..8e9dfaebc7b 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -64,6 +64,9 @@ return + if(istype(M,/mob/living/carbon)) + M.spread_disease_to(src, "Contact") + if(istype(H)) for (var/obj/item/grab/G in H) if (G.assailant == H && G.affecting == src) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 01f02bc4bed..71ddccddd2c 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -304,6 +304,13 @@ return ..() +/mob/living/carbon/human/handle_post_breath(datum/gas_mixture/breath) + ..() + //spread some viruses while we are at it + if(breath && !internal && virus2.len > 0 && prob(10)) + for(var/mob/living/carbon/M in view(1,src)) + src.spread_disease_to(M) + /mob/living/carbon/human/get_breath_from_internal(volume_needed=STD_BREATH_VOLUME) if(internal) @@ -975,9 +982,16 @@ hud_list[LIFE_HUD] = holder if (BITTEST(hud_updateflag, STATUS_HUD) && hud_list[STATUS_HUD] && hud_list[STATUS_HUD_OOC]) + var/foundVirus = 0 + for (var/ID in virus2) + if (ID in virusDB) + foundVirus = 1 + break var/image/holder = hud_list[STATUS_HUD] if(stat == DEAD) holder.icon_state = "huddead" + else if(foundVirus) + holder.icon_state = "hudill" else if(status_flags & XENO_HOST) holder.icon_state = "hudxeno" else if(has_brain_worms()) @@ -994,6 +1008,8 @@ holder2.icon_state = "huddead" else if(has_brain_worms()) holder2.icon_state = "hudbrainworm" + else if(virus2.len) + holder2.icon_state = "hudill" else holder2.icon_state = "hudhealthy" diff --git a/code/modules/mob/living/carbon/viruses.dm b/code/modules/mob/living/carbon/viruses.dm index 9f657c52aa5..f763656d365 100644 --- a/code/modules/mob/living/carbon/viruses.dm +++ b/code/modules/mob/living/carbon/viruses.dm @@ -1,13 +1,60 @@ -/mob/living/carbon - var/immunity = 100 //current immune system strength - var/immunity_norm = 100 //it will regenerate to this value +/mob/living/carbon/var/immunity = 100 //current immune system strength +/mob/living/carbon/var/immunity_norm = 100 //it will regenerate to this value /mob/living/carbon/proc/handle_viruses() if(status_flags & GODMODE) return 0 //godmode + if(bodytemperature > 406) + for (var/ID in virus2) + var/datum/disease2/disease/V = virus2[ID] + V.cure(src) + + if(life_tick % 3) //don't spam checks over all objects in view every tick. + for(var/obj/effect/decal/cleanable/O in view(1,src)) + if(istype(O,/obj/effect/decal/cleanable/blood)) + var/obj/effect/decal/cleanable/blood/B = O + if(isnull(B.virus2)) + B.virus2 = list() + if(B.virus2.len) + for (var/ID in B.virus2) + var/datum/disease2/disease/V = B.virus2[ID] + infect_virus2(src,V) + + else if(istype(O,/obj/effect/decal/cleanable/mucus)) + var/obj/effect/decal/cleanable/mucus/M = O + if(isnull(M.virus2)) + M.virus2 = list() + if(M.virus2.len) + for (var/ID in M.virus2) + var/datum/disease2/disease/V = M.virus2[ID] + infect_virus2(src,V) + + if(virus2.len) + for (var/ID in virus2) + var/datum/disease2/disease/V = virus2[ID] + if(isnull(V)) // Trying to figure out a runtime error that keeps repeating + CRASH("virus2 nulled before calling activate()") + else + V.process(src) + // activate may have deleted the virus + if(!V) continue + + // check if we're immune + var/list/common_antibodies = V.antigen & src.antibodies + if(common_antibodies.len) + V.dead = 1 + if(immunity > 0.2 * immunity_norm && immunity < immunity_norm) immunity = min(immunity + 0.25, immunity_norm) + if(life_tick % 5 && immunity < 15 && chem_effects[CE_ANTIVIRAL] < VIRUS_COMMON && !virus2.len) + var/infection_prob = 15 - immunity + var/turf/simulated/T = loc + if(istype(T)) + infection_prob += T.dirt + if(prob(infection_prob)) + infect_mob_random_lesser(src) + /mob/living/carbon/proc/virus_immunity() var/antibiotic_boost = reagents.get_reagent_amount(/datum/reagent/spaceacillin) / (REAGENTS_OVERDOSE/2) return max(immunity/100 * (1+antibiotic_boost), antibiotic_boost) diff --git a/code/modules/mob/living/silicon/robot/flying/module_flying_ascent.dm b/code/modules/mob/living/silicon/robot/flying/module_flying_ascent.dm index c88943ba59c..cf9d1056b03 100644 --- a/code/modules/mob/living/silicon/robot/flying/module_flying_ascent.dm +++ b/code/modules/mob/living/silicon/robot/flying/module_flying_ascent.dm @@ -81,6 +81,7 @@ SKILL_SCIENCE = SKILL_EXPERT, SKILL_MEDICAL = SKILL_EXPERT, SKILL_ANATOMY = SKILL_EXPERT, + SKILL_VIROLOGY = HAS_PERK, SKILL_CHEMISTRY = SKILL_EXPERT ) diff --git a/code/modules/mob/living/silicon/robot/modules/module_medical.dm b/code/modules/mob/living/silicon/robot/modules/module_medical.dm index 616a006c7c4..ec7d270add3 100644 --- a/code/modules/mob/living/silicon/robot/modules/module_medical.dm +++ b/code/modules/mob/living/silicon/robot/modules/module_medical.dm @@ -52,6 +52,7 @@ skills = list( SKILL_ANATOMY = SKILL_PROF, SKILL_MEDICAL = SKILL_PROF, + SKILL_VIROLOGY = HAS_PERK, SKILL_CHEMISTRY = SKILL_ADEPT, SKILL_BUREAUCRACY = SKILL_ADEPT, SKILL_DEVICES = SKILL_EXPERT @@ -74,7 +75,7 @@ /obj/item/weapon/robot_module/medical/surgeon/finalize_synths() . = ..() - var/datum/matter_synth/medicine/medicine = locate() in synths + var/datum/matter_synth/medicine/medicine = locate() in synths for(var/thing in list( /obj/item/stack/nanopaste, /obj/item/stack/medical/advanced/bruise_pack @@ -123,6 +124,7 @@ skills = list( SKILL_ANATOMY = SKILL_BASIC, SKILL_MEDICAL = SKILL_PROF, + SKILL_VIROLOGY = HAS_PERK, SKILL_CHEMISTRY = SKILL_PROF, SKILL_BUREAUCRACY = SKILL_ADEPT, SKILL_EVA = SKILL_EXPERT, diff --git a/code/modules/mob/living/simple_animal/hostile/vagrant.dm b/code/modules/mob/living/simple_animal/hostile/vagrant.dm index bbbef6c0d10..f1275f4e917 100644 --- a/code/modules/mob/living/simple_animal/hostile/vagrant.dm +++ b/code/modules/mob/living/simple_animal/hostile/vagrant.dm @@ -27,6 +27,7 @@ min_gas = null max_gas = null minbodytemp = 0 + var/datum/disease2/disease/carried var/cloaked = 0 var/mob/living/carbon/human/gripping = null var/blood_per_tick = 3 @@ -35,6 +36,12 @@ bleed_colour = "#aad9de" +/mob/living/simple_animal/hostile/vagrant/Initialize() + . = ..() + if(prob(25)) + carried = new/datum/disease2/disease() + carried.makerandom(rand(2, 4)) + /mob/living/simple_animal/hostile/vagrant/Allow_Spacemove(var/check_drift = 0) return 1 @@ -116,6 +123,8 @@ H.Weaken(1) H.Stun(1) H.visible_message("\the [src] latches onto \the [H], pulsating!") + if(carried && length(gripping.virus2) == 0) + infect_virus2(gripping, carried, 1) src.forceMove(gripping.loc) /mob/living/simple_animal/hostile/vagrant/swarm/Initialize() diff --git a/code/modules/mob/skills/skill.dm b/code/modules/mob/skills/skill.dm index 643974e78d5..9b2825d3ed9 100644 --- a/code/modules/mob/skills/skill.dm +++ b/code/modules/mob/skills/skill.dm @@ -322,6 +322,15 @@ GLOBAL_LIST_EMPTY(skills) "Experienced" = "You are a senior nurse or paramedic, or a practicing doctor. You know how to use all of the medical devices available to treat a patient. Your deep knowledge of the body and medications will let you diagnose and come up with a course of treatment for most ailments. You can perform a full-body scan thoroughly and find important information.
- You can fully operate Body Scanners. You can perform all surgery steps if you have Experienced Anatomy skill", "Master" = "You are an experienced doctor or an expert nurse or EMT. You've seen almost everything there is to see when it comes to injuries and illness and even when it comes to something you haven't seen, you can apply your wide knowledge base to put together a treatment. In a pinch, you can do just about any medicine-related task, but your specialty, whatever it may be, is where you really shine.") +/decl/hierarchy/skill/medical/medical/virology + ID = "virology" + name = "Virology" + desc = "This skill implies an understanding of microorganisms and their effects on humans." + levels = list( "Untrained" = "You know that diseases are contagious; you've probably heard you should wash your hands to stop their spread. You know that if you're sick, you can go to Medical and get treatment.
- You don't have laboratory training, and will probably cause a viral leak if you try to use machines there.", + "Trained" = "You have training in virology, and can operate the machinery in virology lab safely. You can isolate antibodies and modify viruses.
- Can use virology machinery without a risk of viral leak.") + prerequisites = list(SKILL_MEDICAL = SKILL_ADEPT) + default_max = SKILL_BASIC + /decl/hierarchy/skill/medical/anatomy ID = "anatomy" name = "Anatomy" diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm index 568a39e71e5..307975af311 100644 --- a/code/modules/organs/blood.dm +++ b/code/modules/organs/blood.dm @@ -28,7 +28,9 @@ "blood_DNA" = dna.unique_enzymes, "blood_colour" = species.get_blood_colour(src), "blood_type" = dna.b_type, - "trace_chem" = null + "trace_chem" = null, + "virus2" = list(), + "antibodies" = list() ) B.color = B.data["blood_colour"] @@ -134,6 +136,12 @@ /mob/living/carbon/proc/inject_blood(var/datum/reagent/blood/injected, var/amount) if (!injected || !istype(injected)) return + var/list/sniffles = virus_copylist(injected.data["virus2"]) + for(var/ID in sniffles) + var/datum/disease2/disease/sniffle = sniffles[ID] + infect_virus2(src,sniffle,1) + if (injected.data["antibodies"] && prob(5)) + antibodies |= injected.data["antibodies"] var/list/chems = list() chems = injected.data["trace_chem"] for(var/C in chems) @@ -198,6 +206,10 @@ /mob/living/carbon/proc/get_blood_data() var/data = list() data["donor"] = weakref(src) + if (!data["virus2"]) + data["virus2"] = list() + data["virus2"] |= virus_copylist(virus2) + data["antibodies"] = antibodies data["blood_DNA"] = dna.unique_enzymes data["blood_type"] = dna.b_type data["species"] = species.name @@ -264,6 +276,10 @@ proc/blood_splatter(var/target,var/datum/reagent/blood/source,var/large,var/spra else B.blood_DNA[source.data["blood_DNA"]] = "O+" + // Update virus information. + if(source.data["virus2"]) + B.virus2 = virus_copylist(source.data["virus2"]) + B.fluorescent = 0 B.set_invisibility(0) return B @@ -331,3 +347,11 @@ proc/blood_splatter(var/target,var/datum/reagent/blood/source,var/large,var/spra blood_volume_mod = blood_volume_mod + oxygenated_mult - (blood_volume_mod * oxygenated_mult) blood_volume = blood_volume * blood_volume_mod return min(blood_volume, 100) + +/mob/living/carbon/human/proc/cure_virus(var/virus_uuid) + if(vessel && virus_uuid) + for(var/datum/reagent/blood/B in vessel.reagent_list) + var/list/viruses = list() + viruses = B.data["virus2"] + viruses.Remove("[virus_uuid]") + B.data["virus2"] = viruses \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm index 124bce915db..2145688bd49 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm @@ -7,6 +7,8 @@ "blood_colour" = COLOR_BLOOD_HUMAN, "trace_chem" = null, "dose_chem" = null, + "virus2" = list(), + "antibodies" = list(), "has_oxy" = 1 ) name = "Blood" @@ -39,8 +41,21 @@ data = C.get_blood_data() color = data["blood_colour"] +/datum/reagent/blood/mix_data(var/newdata, var/newamount) + if(!islist(newdata)) + return + if(!data["virus2"]) + data["virus2"] = list() + data["virus2"] |= newdata["virus2"] + if(!data["antibodies"]) + data["antibodies"] = list() + data["antibodies"] |= newdata["antibodies"] + /datum/reagent/blood/get_data() // Just in case you have a reagent that handles data differently. var/t = data.Copy() + if(t["virus2"]) + var/list/v = t["virus2"] + t["virus2"] = v.Copy() return t /datum/reagent/blood/touch_turf(var/turf/simulated/T) @@ -64,17 +79,47 @@ M.adjustToxLoss(removed) if(M.chem_doses[type] > 15) M.adjustToxLoss(removed) + if(data && data["virus2"]) + var/list/vlist = data["virus2"] + if(vlist.len) + for(var/ID in vlist) + var/datum/disease2/disease/V = vlist[ID] + if(V && V.spreadtype == "Contact") + infect_virus2(M, V.getcopy()) /datum/reagent/blood/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) if(ishuman(M)) var/mob/living/carbon/human/H = M if(H.isSynthetic()) return + if(data && data["virus2"]) + var/list/vlist = data["virus2"] + if(vlist.len) + for(var/ID in vlist) + var/datum/disease2/disease/V = vlist[ID] + if(V.spreadtype == "Contact") + infect_virus2(M, V.getcopy()) + if(data && data["antibodies"]) + M.antibodies |= data["antibodies"] /datum/reagent/blood/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) M.inject_blood(src, volume) remove_self(volume) +// pure concentrated antibodies +/datum/reagent/antibodies + data = list("antibodies"=list()) + name = "Antibodies" + taste_description = "slime" + reagent_state = LIQUID + color = "#0050f0" + value = 6 + +/datum/reagent/antibodies/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(src.data) + M.antibodies |= src.data["antibodies"] + ..() + // Water! #define WATER_LATENT_HEAT 9500 // How much heat is removed when applied to a hot turf, in J/unit (9500 makes 120 u of water roughly equivalent to 2L /datum/reagent/water diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm index e9a60a3a3ad..2d874ae1fd5 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm @@ -312,6 +312,19 @@ /datum/reagent/radium/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) M.apply_damage(10 * removed, IRRADIATE, armor_pen = 100) // Radium may increase your chances to cure a disease + if(M.virus2.len) + for(var/ID in M.virus2) + var/datum/disease2/disease/V = M.virus2[ID] + if(prob(5)) + M.antibodies |= V.antigen + if(prob(50)) + M.apply_damage(50, IRRADIATE, armor_pen = 100) // curing it that way may kill you instead + var/absorbed = 0 + var/obj/item/organ/internal/diona/nutrients/rad_organ = locate() in M.internal_organs + if(rad_organ && !rad_organ.is_broken()) + absorbed = 1 + if(!absorbed) + M.adjustToxLoss(100) /datum/reagent/radium/touch_turf(var/turf/T) if(volume >= 3) diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm index 3ab156c7d0f..0bf172d447d 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm @@ -397,6 +397,15 @@ nutriment_factor = 1 color = "#801e28" +/datum/reagent/nutriment/virus_food + name = "Virus Food" + description = "A mixture of water, milk, and oxygen. Virus cells can use this mixture to reproduce." + taste_description = "vomit" + taste_mult = 2 + reagent_state = LIQUID + nutriment_factor = 2 + color = "#899613" + /datum/reagent/nutriment/sprinkles name = "Sprinkles" description = "Multi-colored little bits of sugar, commonly found on donuts. Loved by cops." diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index 7591a38c048..22a2e343e50 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -196,6 +196,13 @@ catalysts = list(/datum/reagent/toxin/phoron = 5) result_amount = 2 +/datum/chemical_reaction/virus_food + name = "Virus Food" + result = /datum/reagent/nutriment/virus_food + required_reagents = list(/datum/reagent/water = 1, /datum/reagent/drink/milk = 1) + result_amount = 5 + mix_message = "The water dilutes the milk into a thin white solution." + /datum/chemical_reaction/leporazine name = "Leporazine" result = /datum/reagent/leporazine diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index c7cc0a554ee..91b47589c90 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -89,7 +89,7 @@ if(blood_type) name = "blood pack [blood_type]" reagents_to_add = list(/datum/reagent/blood = volume) - reagent_data = list(/datum/reagent/blood = list("donor" = null, "blood_DNA" = null, "blood_type" = blood_type, "trace_chem" = null)) + reagent_data = list(/datum/reagent/blood = list("donor" = null, "blood_DNA" = null, "blood_type" = blood_type, "trace_chem" = null, "virus2" = list(), "antibodies" = list())) . = ..() /obj/item/weapon/reagent_containers/ivbag/blood/APlus diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm index 22cfd37eba2..bcfbc380305 100644 --- a/code/modules/reagents/reagent_containers/glass.dm +++ b/code/modules/reagents/reagent_containers/glass.dm @@ -31,9 +31,11 @@ /mob/living/bot/medbot, /obj/item/weapon/storage/secure/safe, /obj/structure/iv_drip, + /obj/machinery/disease2/incubator, /obj/machinery/disposal, /mob/living/simple_animal/cow, /mob/living/simple_animal/hostile/retaliate/goat, + /obj/machinery/computer/centrifuge, /obj/machinery/sleeper, /obj/machinery/smartfridge/, /obj/machinery/biogenerator, @@ -49,7 +51,7 @@ . = ..() if(distance > 2) return - + if(reagents && reagents.reagent_list.len) to_chat(user, "It contains [reagents.total_volume] units of liquid.") else diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 93a32d99ad3..6af306ee91a 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -327,6 +327,15 @@ initial_reagent_types = list(/datum/reagent/ethanol/beer = 1) atom_flags = ATOM_FLAG_CLIMBABLE +/obj/structure/reagent_dispensers/virusfood + name = "virus food dispenser" + desc = "A dispenser of virus food." + icon = 'icons/obj/objects.dmi' + icon_state = "virusfoodtank" + amount_per_transfer_from_this = 10 + anchored = 1 + initial_reagent_types = list(/datum/reagent/nutriment/virus_food = 1) + /obj/structure/reagent_dispensers/acid name = "sulphuric acid dispenser" desc = "A dispenser of acid for industrial processes." diff --git a/code/modules/research/designs/designs_circuits.dm b/code/modules/research/designs/designs_circuits.dm index 9c4e4d9204e..570c6e29b04 100644 --- a/code/modules/research/designs/designs_circuits.dm +++ b/code/modules/research/designs/designs_circuits.dm @@ -81,6 +81,20 @@ build_path = /obj/item/weapon/stock_parts/circuitboard/cryo_cell sort_string = "FACAF" +/datum/design/circuit/centrifuge + name = "isolation centrifuge console" + id = "iso_centrifuge" + req_tech = list(TECH_DATA = 2, TECH_BIO = 3) + build_path = /obj/item/weapon/stock_parts/circuitboard/centrifuge + sort_string = "FACAG" + +/datum/design/circuit/splicer + name = "disease splicer" + id = "isplicer" + req_tech = list(TECH_DATA = 5, TECH_BIO = 5) + build_path = /obj/item/weapon/stock_parts/circuitboard/splicer + sort_string = "FACAH" + /datum/design/circuit/clonecomputer name = "cloning control computer" id = "clooner" diff --git a/code/modules/species/mantid/mantid.dm b/code/modules/species/mantid/mantid.dm index 6b40f33012a..a46b27f4ac2 100644 --- a/code/modules/species/mantid/mantid.dm +++ b/code/modules/species/mantid/mantid.dm @@ -18,6 +18,7 @@ flesh_color = "#009999" hud_type = /datum/hud_data/mantid move_trail = /obj/effect/decal/cleanable/blood/tracks/snake + virus_immune = TRUE speech_chance = 100 speech_sounds = list( @@ -211,6 +212,7 @@ /datum/species/nabber/monarch name = SPECIES_MONARCH_WORKER name_plural = "Monarch Serpentid Workers" + virus_immune = TRUE spawn_flags = SPECIES_IS_RESTRICTED | SPECIES_NO_FBP_CONSTRUCTION | SPECIES_NO_FBP_CHARGEN has_organ = list( BP_BRAIN = /obj/item/organ/internal/brain/insectoid/nabber, diff --git a/code/modules/species/species.dm b/code/modules/species/species.dm index ba9b0f6b91b..1c8b3938286 100644 --- a/code/modules/species/species.dm +++ b/code/modules/species/species.dm @@ -54,6 +54,7 @@ var/mob_size = MOB_MEDIUM var/strength = STR_MEDIUM var/show_ssd = "fast asleep" + var/virus_immune var/short_sighted // Permanent weldervision. var/light_sensitive // Ditto, but requires sunglasses to fix var/blood_volume = SPECIES_BLOOD_DEFAULT // Initial blood volume. diff --git a/code/modules/species/species_getters.dm b/code/modules/species/species_getters.dm index 357a79384d5..6ac752ae701 100644 --- a/code/modules/species/species_getters.dm +++ b/code/modules/species/species_getters.dm @@ -49,6 +49,9 @@ /datum/species/proc/get_blood_colour(var/mob/living/carbon/human/H) return ((H && H.isSynthetic()) ? SYNTH_BLOOD_COLOUR : blood_color) +/datum/species/proc/get_virus_immune(var/mob/living/carbon/human/H) + return ((H && H.isSynthetic()) ? 1 : virus_immune) + /datum/species/proc/get_flesh_colour(var/mob/living/carbon/human/H) return ((H && H.isSynthetic()) ? SYNTH_FLESH_COLOUR : flesh_color) diff --git a/code/modules/species/station/adherent.dm b/code/modules/species/station/adherent.dm index 1ef48e576c4..16770cca41d 100644 --- a/code/modules/species/station/adherent.dm +++ b/code/modules/species/station/adherent.dm @@ -51,6 +51,7 @@ appearance_flags = HAS_EYE_COLOR | HAS_BASE_SKIN_COLOURS blood_color = "#2de00d" flesh_color = "#90edeb" + virus_immune = 1 slowdown = -1 hud_type = /datum/hud_data/adherent diff --git a/code/modules/species/station/machine.dm b/code/modules/species/station/machine.dm index 8ff331a0e45..edac01272df 100644 --- a/code/modules/species/station/machine.dm +++ b/code/modules/species/station/machine.dm @@ -38,6 +38,7 @@ blood_color = "#1f181f" flesh_color = "#575757" + virus_immune = 1 has_organ = list( BP_POSIBRAIN = /obj/item/organ/internal/posibrain, diff --git a/code/modules/species/station/prometheans.dm b/code/modules/species/station/prometheans.dm index beb730ca5bc..6acf7c215f6 100644 --- a/code/modules/species/station/prometheans.dm +++ b/code/modules/species/station/prometheans.dm @@ -31,6 +31,7 @@ var/datum/species/shapeshifter/promethean/prometheans poison_types = null gluttonous = GLUT_TINY | GLUT_SMALLER | GLUT_ITEM_ANYTHING | GLUT_PROJECTILE_VOMIT + virus_immune = 1 blood_volume = 600 min_age = 18 max_age = 125 diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index 66053c48002..3da3ca80408 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -6,6 +6,7 @@ GLOBAL_LIST_INIT(surgery_tool_exceptions, list( /obj/item/weapon/reagent_containers/hypospray, /obj/item/modular_computer, /obj/item/weapon/reagent_containers/syringe, + /obj/item/device/antibody_scanner, /obj/item/weapon/reagent_containers/borghypo )) GLOBAL_LIST_INIT(surgery_tool_exception_cache, new) diff --git a/code/modules/virus2/admin.dm b/code/modules/virus2/admin.dm new file mode 100644 index 00000000000..ba0cc4bf785 --- /dev/null +++ b/code/modules/virus2/admin.dm @@ -0,0 +1,215 @@ +/datum/disease2/disease/Topic(href, href_list) + . = ..() + if(.) return + + if(href_list["info"]) + // spawn or admin privileges to see info about viruses + if(!check_rights(R_ADMIN|R_SPAWN)) return + + to_chat(usr, "Infection chance: [infectionchance]; Speed: [speed]; Spread type: [spreadtype]") + to_chat(usr, "Affected species: [english_list(affected_species)]") + to_chat(usr, "Effects:") + for(var/datum/disease2/effect/E in effects) + to_chat(usr, "[E.stage]: [E.name]; chance=[E.chance]; multiplier=[E.multiplier]") + to_chat(usr, "Antigens: [antigens2string(antigen)]") + + return 1 + +/datum/disease2/disease/get_view_variables_header() + . = list() + for(var/datum/disease2/effect/E in effects) + . += "[E.stage]: [E.name]" + return {" + [name()]
+ [jointext(., "
")]
+ "} + +/datum/disease2/disease/get_view_variables_options() + return ..() + {" + + "} + +/datum/admins/var/datum/virus2_editor/virus2_editor_datum = new +/client/proc/virus2_editor() + set name = "Virus Editor" + set category = "Admin" + if(!holder || !check_rights(R_SPAWN)) return // spawn privileges to create viruses + + holder.virus2_editor_datum.show_ui(src) + +/datum/virus2_editor + var/list/s = list(/datum/disease2/effect/invisible,/datum/disease2/effect/invisible,/datum/disease2/effect/invisible,/datum/disease2/effect/invisible) + var/list/s_chance = list(1,1,1,1) + var/list/s_multiplier = list(1,1,1,1) + var/species = list() + var/infectionchance = 70 + var/spreadtype = "Contact" + var/list/antigens = list() + var/speed = 1 + var/mob/living/carbon/infectee = null + + // this holds spawned viruses so that the "Info" links work after the proc exits + var/list/spawned_viruses = list() + + proc/select(mob/user, stage) + if(stage < 1 || stage > 4) return + + var/list/L = list() + + for(var/e in (typesof(/datum/disease2/effect) - /datum/disease2/effect)) + var/datum/disease2/effect/f = e + if(initial(f.stage) <= stage) + L[initial(f.name)] = e + + var/datum/disease2/effect/Eff = s[stage] + + var/C = input("Select effect for stage [stage]:", "Stage [stage]", initial(Eff.name)) as null|anything in L + if(!C) return + return L[C] + + proc/show_ui(mob/user) + var/H = {" +

Virus2 Virus Editor


+ Effects:
+ "} + for(var/i = 1 to 4) + var/datum/disease2/effect/Eff = s[i] + H += {" + [initial(Eff.name)] + Chance: [s_chance[i]] + Multiplier: [s_multiplier[i]] +
+ "} + H += {" +
+ Infectable Species:
+ "} + var/f = 1 + for(var/k in all_species) + var/datum/species/S = all_species[k] + if(S.get_virus_immune()) + continue + if(!f) H += " | " + else f = 0 + H += "[k]" + H += {" + Reset +
+ Infection Chance: [infectionchance]
+ Spread Type: [spreadtype]
+ Speed: [speed]
+
+ "} + f = 1 + for(var/k in ALL_ANTIGENS) + if(!f) H += " | " + else f = 0 + H += "[k]" + H += {" + Reset +
+
+ Initial infectee: [infectee ? infectee : "(choose)"] + RELEASE + "} + + user << browse(H, "window=virus2edit") + + Topic(href, href_list) + switch(href_list["what"]) + if("effect") + var/stage = text2num(href_list["stage"]) + if(href_list["effect"]) + var/datum/disease2/effect/E = select(usr,stage) + if(!E) return + s[stage] = E + // set a default chance and multiplier of half the maximum (roughly average) + s_chance[stage] = max(1, round(initial(E.chance_max)/2)) + s_multiplier[stage] = max(1, round(initial(E.multiplier_max)/2)) + else if(href_list["chance"]) + var/datum/disease2/effect/Eff = s[stage] + var/I = input("Chance, per tick, of this effect happening (min 0, max [initial(Eff.chance_max)])", "Effect Chance", s_chance[stage]) as null|num + if(I == null || I < 0 || I > initial(Eff.chance_max)) return + s_chance[stage] = I + else if(href_list["multiplier"]) + var/datum/disease2/effect/Eff = s[stage] + var/I = input("Multiplier for this effect (min 1, max [initial(Eff.multiplier_max)])", "Effect Multiplier", s_multiplier[stage]) as null|num + if(I == null || I < 1 || I > initial(Eff.multiplier_max)) return + s_multiplier[stage] = I + if("species") + if(href_list["toggle"]) + var/T = href_list["toggle"] + if(T in species) + species -= T + else + species |= T + else if(href_list["reset"]) + species = list() + if(infectee) + if(!infectee.species || !(infectee.species.get_bodytype(infectee) in species)) + infectee = null + if("ichance") + var/I = input("Input infection chance", "Infection Chance", infectionchance) as null|num + if(!I) return + infectionchance = I + if("stype") + var/S = alert("Which spread type?", "Spread Type", "Cancel", "Contact", "Airborne") + if(!S || S == "Cancel") return + spreadtype = S + if("speed") + var/S = input("Input speed", "Speed", speed) as null|num + if(!S) return + speed = S + if("antigen") + if(href_list["toggle"]) + var/T = href_list["toggle"] + if(length(T) != 1) return + if(T in antigens) + antigens -= T + else + antigens |= T + else if(href_list["reset"]) + antigens = list() + if("infectee") + var/list/candidates = list() + for(var/mob/living/carbon/G in GLOB.living_mob_list_) + if(G.stat != DEAD && G.species) + if(G.species.get_bodytype(G) in species) + candidates["[G.name][G.client ? "" : " (no client)"]"] = G + else + candidates["[G.name] ([G.species.get_bodytype(G)])[G.client ? "" : " (no client)"]"] = G + if(!candidates.len) to_chat(usr, "No possible candidates found!") + + var/I = input("Choose initial infectee", "Infectee", infectee) as null|anything in candidates + if(!I || !candidates[I]) return + infectee = candidates[I] + species |= infectee.species.get_bodytype(infectee) + if("go") + if(!antigens.len) + var/a = alert("This disease has no antigens; it will be impossible to permanently immunise anyone without them.\ + It is strongly recommended to set at least one antigen. Do you want to go back and edit your virus?", "Antigens", "Yes", "Yes", "No") + if(a == "Yes") return + var/datum/disease2/disease/D = new + D.infectionchance = infectionchance + D.spreadtype = spreadtype + D.antigen = antigens + D.affected_species = species + D.speed = speed + for(var/i in 1 to 4) + var/datum/disease2/effect/E = new + var/Etype = s[i] + E = new Etype() + E.generate() + E.chance = s_chance[i] + E.multiplier = s_multiplier[i] + E.stage = i + + D.effects += E + + spawned_viruses += D + + message_admins("[key_name_admin(usr)] infected [key_name_admin(infectee)] with a virus (Info)") + log_admin("[key_name_admin(usr)] infected [key_name_admin(infectee)] with a virus!") + infect_virus2(infectee, D, forced=1) + + show_ui(usr) \ No newline at end of file diff --git a/code/modules/virus2/analyser.dm b/code/modules/virus2/analyser.dm new file mode 100644 index 00000000000..cd7257ab1b4 --- /dev/null +++ b/code/modules/virus2/analyser.dm @@ -0,0 +1,78 @@ +/obj/machinery/disease2/diseaseanalyser + name = "disease analyser" + icon = 'icons/obj/virology.dmi' + icon_state = "analyser" + anchored = 1 + density = 1 + + var/scanning = 0 + var/pause = 0 + + var/obj/item/weapon/virusdish/dish = null + +/obj/machinery/disease2/diseaseanalyser/attackby(var/obj/O as obj, var/mob/user as mob) + if(!istype(O,/obj/item/weapon/virusdish)) return + + if(dish) + to_chat(user, "\The [src] is already loaded.") + return + if(!user.unEquip(O, src)) + return + dish = O + operator_skill = user.get_skill_value(core_skill) + + user.visible_message("[user] adds \a [O] to \the [src]!", "You add \a [O] to \the [src]!") + +/obj/machinery/disease2/diseaseanalyser/Process() + if(stat & (NOPOWER|BROKEN)) + return + + if(scanning) + scanning -= 1 + if(scanning == 0) + if (dish.virus2.addToDB()) + ping("\The [src] pings, \"New pathogen added to data bank.\"") + + var/list/effects = get_fake_effects(dish.virus2) + var/r = dish.virus2.get_info(operator_skill, 1, effects) + var/title = "paper - [dish.virus2.name()]" + var/info = {" + [virology_letterhead("Post-Analysis Memo")] + [r] +
+ Additional Notes:  + "} + new /obj/item/weapon/paper(loc, info, title) + + dish.basic_info = dish.virus2.get_info(operator_skill, 0, effects) + dish.info = r + dish.SetName("[initial(dish.name)] ([dish.virus2.name()])") + dish.analysed = 1 + dish.forceMove(loc) + dish = null + operator_skill = null + + icon_state = "analyser" + src.state("\The [src] prints a sheet of paper.") + + else if(dish && !scanning && !pause) + if(dish.virus2 && dish.growth > 50) + dish.growth -= 10 + scanning = 5 + icon_state = "analyser_processing" + else + pause = 1 + spawn(25) + dish.forceMove(loc) + dish = null + + src.state("\The [src] buzzes, \"Insufficient growth density to complete analysis.\"") + pause = 0 + +/obj/machinery/disease2/diseaseanalyser/proc/get_fake_effects() + . = list() + for(var/datum/disease2/effect/E in dish.virus2.effects) + if(operator_skill >= HAS_PERK || prob(60)) + . += E //Passed skill check, use real effect + else + . += get_random_virus2_effect(E.stage, VIRUS_ENGINEERED) //Failed check, get a fake effect \ No newline at end of file diff --git a/code/modules/virus2/antibodies.dm b/code/modules/virus2/antibodies.dm new file mode 100644 index 00000000000..1e20ba4fbae --- /dev/null +++ b/code/modules/virus2/antibodies.dm @@ -0,0 +1,26 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +var/global/list/ALL_ANTIGENS = list( + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" + ) + +/hook/startup/proc/randomise_antigens_order() + ALL_ANTIGENS = shuffle(ALL_ANTIGENS) + return 1 + +// iterate over the list of antigens and see what matches +/proc/antigens2string(list/antigens, none="None") + if(!istype(antigens)) + CRASH("Illegal type!") + if(!antigens.len) + return none + + var/code = "" + for(var/V in ALL_ANTIGENS) + if(V in antigens) + code += V + + if(!code) + return none + + return code \ No newline at end of file diff --git a/code/modules/virus2/antibodyanalyser.dm b/code/modules/virus2/antibodyanalyser.dm new file mode 100644 index 00000000000..f99994f2459 --- /dev/null +++ b/code/modules/virus2/antibodyanalyser.dm @@ -0,0 +1,72 @@ +/obj/machinery/disease2/antibodyanalyser + name = "antibody analyser" + desc = "An advanced machine that analyses pure antibody samples and stores the structure of them on the ExoNet in exchange for cargo points." + icon = 'icons/obj/virology.dmi' + icon_state = "analyser" + anchored = 1 + density = 1 + + var/scanning = 0 + var/pause = 0 + var/list/known_antibodies = list() + + var/obj/item/weapon/reagent_containers/container = null + +/obj/machinery/disease2/antibodyanalyser/on_update_icon() + if(scanning) + icon_state = "analyser_processing" + else + icon_state = "analyser" + +/obj/machinery/disease2/antibodyanalyser/attackby(var/obj/I as obj, var/mob/user as mob) + if(istype(I,/obj/item/weapon/reagent_containers)) + if(!container && user.unEquip(I)) + container = I + I.forceMove(src) + user.visible_message("[user] adds a sample to \the [src]!", "You add a sample to \the [src]!") + return + +/obj/machinery/disease2/antibodyanalyser/Process() + if(stat & (NOPOWER|BROKEN)) + return + + if(scanning) + scanning -= 1 + if(scanning == 0) + if(!container.reagents.has_reagent(/datum/reagent/antibodies)) //if there are no antibody reagents, return false + return 0 + + else + var/list/data = container.reagents.get_data(/datum/reagent/antibodies) //now that we know there are antibody reagents, get the data + var/list/given_antibodies = data["antibodies"] //now check what specific antibodies it's holding + var/list/common_antibodies = known_antibodies & given_antibodies + var/list/unknown_antibodies = common_antibodies ^ given_antibodies + if(unknown_antibodies.len) + var/payout = unknown_antibodies.len * 45 + SSsupply.add_points_from_source(payout, "virology_antibodies") + ping("\The [src] pings, \"Successfully uploaded new antibodies to the ExoNet.\"") + known_antibodies |= unknown_antibodies //Add the new antibodies to list + else + src.state("\The [src] buzzes, \"Failed to identify any new antibodies.\"") + if(!given_antibodies.len) //return if no antibodies + return 0 + + container.dropInto(loc) + container = null + + update_icon() + + else if(container && !scanning && !pause) + if(container.reagents.has_reagent(/datum/reagent/antibodies)) + scanning = 5 + update_icon() + else + container.dropInto(loc) + container = null + + src.state("\The [src] buzzes, \"Failed to identify a pure sample of antibodies in the solution.\"") + return + +/obj/machinery/disease2/antibodyanalyser/Destroy() + QDEL_NULL(container) + . = ..() \ No newline at end of file diff --git a/code/modules/virus2/centrifuge.dm b/code/modules/virus2/centrifuge.dm new file mode 100644 index 00000000000..13c7c512248 --- /dev/null +++ b/code/modules/virus2/centrifuge.dm @@ -0,0 +1,215 @@ +/obj/machinery/computer/centrifuge + name = "isolation centrifuge" + desc = "Used to separate things with different weights. Spin 'em round, round, right round." + icon = 'icons/obj/virology.dmi' + icon_state = "centrifuge" + var/curing + var/isolating + + var/obj/item/weapon/reagent_containers/glass/beaker/vial/sample = null + var/datum/disease2/disease/virus2 = null + core_skill = SKILL_VIROLOGY + +/obj/machinery/computer/centrifuge/attackby(var/obj/O as obj, var/mob/user as mob) + if(isScrewdriver(O)) + return ..(O,user) + + if(istype(O,/obj/item/weapon/reagent_containers/glass/beaker/vial)) + if(sample) + to_chat(user, "\The [src] is already loaded.") + return + if(!user.unEquip(O, src)) + return + sample = O + + user.visible_message("[user] adds \a [O] to \the [src]!", "You add \a [O] to \the [src]!") + SSnano.update_uis(src) + + src.attack_hand(user) + +/obj/machinery/computer/centrifuge/on_update_icon() + ..() + if(! (stat & (BROKEN|NOPOWER))) + icon_state = (isolating || curing) ? "centrifuge_moving" : "centrifuge" + +/obj/machinery/computer/centrifuge/interface_interact(var/mob/user) + ui_interact(user) + return TRUE + +/obj/machinery/computer/centrifuge/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) + + var/data[0] + data["antibodies"] = null + data["pathogens"] = null + data["is_antibody_sample"] = null + + if (curing) + data["busy"] = "Isolating antibodies..." + else if (isolating) + data["busy"] = "Isolating pathogens..." + else + data["sample_inserted"] = !!sample + + if (sample) + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list + if (B) + data["antibodies"] = antigens2string(B.data["antibodies"], none=null) + + var/list/pathogens[0] + var/list/virus = B.data["virus2"] + for (var/ID in virus) + var/datum/disease2/disease/V = virus[ID] + pathogens.Add(list(list("name" = V.name(), "spread_type" = V.spreadtype, "reference" = "\ref[V]"))) + + if (pathogens.len > 0) + data["pathogens"] = pathogens + + else + var/datum/reagent/antibodies/A = locate(/datum/reagent/antibodies) in sample.reagents.reagent_list + if(A) + data["antibodies"] = antigens2string(A.data["antibodies"], none=null) + data["is_antibody_sample"] = 1 + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "isolation_centrifuge.tmpl", src.name, 400, 500) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/computer/centrifuge/Process() + if (stat & (NOPOWER|BROKEN)) return + + if (curing) + curing -= 1 + if (curing == 0) + cure() + + if (isolating) + isolating -= 1 + if(isolating == 0) + isolate() + + if(virus2) + infect_nearby(virus2) + +/obj/machinery/computer/centrifuge/OnTopic(mob/user, href_list) + if (href_list["close"]) + SSnano.close_user_uis(user, src, "main") + return TOPIC_HANDLED + + if (href_list["print"]) + print(user) + return TOPIC_HANDLED + + if(href_list["isolate"]) + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list + if (B) + var/datum/disease2/disease/virus = locate(href_list["isolate"]) + virus2 = virus.getcopy() + isolating = 40 + update_icon() + operator_skill = user.get_skill_value(core_skill) + return TOPIC_REFRESH + + switch(href_list["action"]) + if ("antibody") + var/delay = 20 + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list + if (!B) + state("\The [src] buzzes, \"No antibody carrier detected.\"", "blue") + return TOPIC_HANDLED + + var/list/viruses = B.data["virus2"] + if(length(viruses)) + var/ID = pick(viruses) + var/datum/disease2/disease/V = viruses[ID] + virus2 = V.getcopy() + operator_skill = user.get_skill_value(core_skill) + var/has_toxins = locate(/datum/reagent/toxin) in sample.reagents.reagent_list + var/has_radium = sample.reagents.has_reagent(/datum/reagent/radium) + if (has_toxins || has_radium) + state("\The [src] beeps, \"Pathogen purging speed above nominal.\"", "blue") + if (has_toxins) + delay = delay/2 + if (has_radium) + delay = delay/2 + + curing = round(delay) + playsound(src.loc, 'sound/machines/juicer_old.ogg', 50, 1) + update_icon() + return TOPIC_REFRESH + + if("sample") + if(sample) + sample.dropInto(loc) + sample = null + return TOPIC_REFRESH + +/obj/machinery/computer/centrifuge/proc/cure() + if (!sample) return + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list + if (!B) return + + var/list/data = list("antibodies" = B.data["antibodies"]) + var/amt= sample.reagents.get_reagent_amount(/datum/reagent/blood) + sample.reagents.remove_reagent(/datum/reagent/blood, amt) + sample.reagents.add_reagent(/datum/reagent/antibodies, amt, data) + operator_skill = null + + SSnano.update_uis(src) + update_icon() + ping("\The [src] pings, \"Antibody isolated.\"") + +/obj/machinery/computer/centrifuge/proc/isolate() + if (!sample) return + var/obj/item/weapon/virusdish/dish = new/obj/item/weapon/virusdish(loc) + dish.virus2 = virus2 + virus2 = null + operator_skill = null + + SSnano.update_uis(src) + update_icon() + ping("\The [src] pings, \"Pathogen isolated.\"") + +/obj/machinery/computer/centrifuge/proc/print(var/mob/user) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(loc) + P.SetName("paper - Pathology Report") + P.info = {" + [virology_letterhead("Pathology Report")] + Sample: [sample.name]
+"} + + if (user) + P.info += "Generated By: [user.name]
" + + P.info += "
" + + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list + if (B) + P.info += "Antibodies: " + P.info += antigens2string(B.data["antibodies"]) + P.info += "
" + + var/list/virus = B.data["virus2"] + P.info += "Pathogens:
" + if (virus.len > 0) + for (var/ID in virus) + var/datum/disease2/disease/V = virus[ID] + P.info += "[V.name()]
" + else + P.info += "None
" + + else + var/datum/reagent/antibodies/A = locate(/datum/reagent/antibodies) in sample.reagents.reagent_list + if (A) + P.info += "The following antibodies have been isolated from the blood sample: " + P.info += antigens2string(A.data["antibodies"]) + P.info += "
" + + P.info += {" +
+ Additional Notes: +"} + + state("The nearby computer prints out a pathology report.") \ No newline at end of file diff --git a/code/modules/virus2/curer.dm b/code/modules/virus2/curer.dm new file mode 100644 index 00000000000..1a7fba08b11 --- /dev/null +++ b/code/modules/virus2/curer.dm @@ -0,0 +1,98 @@ +/obj/machinery/computer/curer + name = "cure research machine" + icon = 'icons/obj/computer.dmi' + icon_keyboard = "med_key" + icon_screen = "dna" + idle_power_usage = 500 + var/curing + var/virusing + + var/obj/item/weapon/reagent_containers/container = null + +/obj/machinery/computer/curer/attackby(var/obj/I as obj, var/mob/user as mob) + if(istype(I,/obj/item/weapon/reagent_containers)) + if(!container) + if(!user.unEquip(I, src)) + return + container = I + return + if(istype(I,/obj/item/weapon/virusdish)) + if(virusing) + to_chat(user, "The pathogen materializer is still recharging..") + return + var/obj/item/weapon/reagent_containers/glass/beaker/product = new(src.loc) + + var/list/data = list("donor" = null, "blood_DNA" = null, "blood_type" = null, "trace_chem" = null, "virus2" = list(), "antibodies" = list()) + data["virus2"] |= I:virus2 + product.reagents.add_reagent(/datum/reagent/blood,30,data) + + virusing = 1 + spawn(1200) virusing = 0 + + state("The [src.name] Buzzes", "blue") + return + ..() + return + +/obj/machinery/computer/curer/interface_interact(var/mob/user) + interact(user) + return TRUE + +/obj/machinery/computer/curer/interact(var/mob/user) + user.machine = src + var/dat + if(curing) + dat = "Antibody production in progress" + else if(virusing) + dat = "Virus production in progress" + else if(container) + // see if there's any blood in the container + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in container.reagents.reagent_list + + if(B) + dat = "Blood sample inserted." + dat += "
Antibodies: [antigens2string(B.data["antibodies"])]" + dat += "
Begin antibody production" + else + dat += "
Please check container contents." + dat += "
Eject container" + else + dat = "Please insert a container." + + user << browse(dat, "window=computer;size=400x500") + onclose(user, "computer") + return + +/obj/machinery/computer/curer/Process() + if(stat & (NOPOWER|BROKEN)) + return + + if(curing) + curing -= 1 + if(curing == 0) + if(container) + createcure(container) + return + +/obj/machinery/computer/curer/OnTopic(user, href_list) + if (href_list["antibody"]) + curing = 10 + . = TOPIC_REFRESH + else if(href_list["eject"]) + container.dropInto(loc) + container = null + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + attack_hand(user) + +/obj/machinery/computer/curer/proc/createcure(var/obj/item/weapon/reagent_containers/container) + var/obj/item/weapon/reagent_containers/glass/beaker/product = new(src.loc) + + var/datum/reagent/blood/B = locate() in container.reagents.reagent_list + + var/list/data = list() + data["antibodies"] = B.data["antibodies"] + product.reagents.add_reagent(/datum/reagent/antibodies,30,data) + + state("\The [src.name] buzzes", "blue") \ No newline at end of file diff --git a/code/modules/virus2/disease2.dm b/code/modules/virus2/disease2.dm new file mode 100644 index 00000000000..1e6a97ec010 --- /dev/null +++ b/code/modules/virus2/disease2.dm @@ -0,0 +1,259 @@ +LEGACY_RECORD_STRUCTURE(virus_records, virus_record) + +/datum/disease2/disease + var/infectionchance = 70 + var/speed = 1 + var/spreadtype = "Contact" // Can also be "Airborne" + var/stage = 1 + var/dead = 0 + var/clicks = 0 + var/uniqueID = 0 + var/list/datum/disease2/effect/effects = list() + var/antigen = list() //A list of characters that represent antigens that cure this virus. + var/max_stage = 4 + var/list/affected_species = list(SPECIES_HUMAN,SPECIES_UNATHI,SPECIES_SKRELL) + +/datum/disease2/disease/New() + uniqueID = rand(0,10000) + ..() + +/datum/disease2/disease/proc/makerandom(var/severity=2) + var/list/excludetypes = list() + for(var/i=1 ; i <= max_stage ; i++ ) + var/datum/disease2/effect/E = get_random_virus2_effect(i, severity, excludetypes) + E.stage = i + if(!E.allow_multiple) + excludetypes += E.type + effects += E + uniqueID = rand(0,10000) + switch(severity) + if(1,2) + infectionchance = rand(10,20) + else + infectionchance = rand(60,90) + + antigen = list(pick(ALL_ANTIGENS)) + antigen |= pick(ALL_ANTIGENS) + spreadtype = prob(70) ? "Airborne" : "Contact" + + if(all_species.len) + affected_species = get_infectable_species() + +/proc/get_infectable_species() + var/list/meat = list() + var/list/res = list() + for (var/specie in all_species) + var/datum/species/S = all_species[specie] + if((S.spawn_flags & SPECIES_CAN_JOIN) && !S.get_virus_immune() && !S.greater_form) + meat += S + if(meat.len) + var/num = rand(1,meat.len) + for(var/i=0,i 50) + if((mob.species.name == SPECIES_DIONA) && prob(mob.radiation/25)) + cure(mob) + else if(prob(1)) + majormutate() + + if(prob(mob.virus_immunity()) && prob(stage)) // Increasing chance of curing as the virus progresses + cure(mob,1) + //Waiting out the disease the old way + if(stage == max_stage && clicks > max(stage*100, 300)) + if(prob(mob.virus_immunity() * 0.05 + 100-infectionchance)) + cure(mob, 1) + + var/top_badness = 1 + for(var/datum/disease2/effect/e in effects) + if(e.stage == stage) + top_badness = max(top_badness, e.badness) + + //Space antibiotics might stop disease completely + if(mob.chem_effects[CE_ANTIVIRAL] > top_badness) + if(stage == 1 && prob(20)) + cure(mob) + return + + clicks += speed + //Virus food speeds up disease progress + if(mob.reagents.has_reagent(/datum/reagent/nutriment/virus_food)) + mob.reagents.remove_reagent(/datum/reagent/nutriment/virus_food, REM) + clicks += 10 + + //Moving to the next stage + if(clicks > max(stage*100, 300)) + if(stage < max_stage && prob(10)) + stage++ + clicks = 0 + + //Do nasty effects + for(var/datum/disease2/effect/e in effects) + e.fire(mob,stage) + + //fever + if(!mob.chem_effects[CE_ANTIVIRAL]) + mob.bodytemperature = max(mob.bodytemperature, min(310+5*min(stage,max_stage) ,mob.bodytemperature+5*min(stage,max_stage))) + +/datum/disease2/disease/proc/cure(var/mob/living/carbon/mob, mob_gains_antigens) + for(var/datum/disease2/effect/e in effects) + e.deactivate(mob) + + mob.virus2.Remove("[uniqueID]") + + //Tries to remove the virus also from the bloodstream (only for human-like lifeforms). + if(istype(mob, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = mob + H.cure_virus(uniqueID) + + if (mob_gains_antigens) + mob.antibodies |= antigen + + BITSET(mob.hud_updateflag, STATUS_HUD) + +/datum/disease2/disease/proc/minormutate() + var/datum/disease2/effect/E = pick(effects) + E.minormutate() + +/datum/disease2/disease/proc/majormutate(badness = VIRUS_ENGINEERED) + uniqueID = rand(0,10000) + var/datum/disease2/effect/E = pick(effects) + var/list/exclude = list() + for(var/datum/disease2/effect/D in effects) + if(D != E) + exclude += D.type + + var/effect_stage = E.stage + E.deactivate() + effects -= E + qdel(E) + + effects += get_random_virus2_effect(effect_stage, badness, exclude) + + antigen = list(pick(ALL_ANTIGENS)) + antigen |= pick(ALL_ANTIGENS) + + if (prob(5) && all_species.len) + affected_species = get_infectable_species() + +/datum/disease2/disease/proc/getcopy() + var/datum/disease2/disease/disease = new /datum/disease2/disease + disease.infectionchance = infectionchance + disease.spreadtype = spreadtype + disease.speed = speed + disease.antigen = antigen + disease.uniqueID = uniqueID + disease.affected_species = affected_species.Copy() + for(var/datum/disease2/effect/effect in effects) + var/datum/disease2/effect/neweffect = new effect.type + neweffect.generate(effect.data) + neweffect.chance = effect.chance + neweffect.multiplier = effect.multiplier + neweffect.oneshot = effect.oneshot + neweffect.stage = effect.stage + disease.effects += neweffect + return disease + +/datum/disease2/disease/proc/issame(var/datum/disease2/disease/disease) + . = 1 + + var/list/types = list() + for(var/datum/disease2/effect/d in effects) + types += d.type + for(var/datum/disease2/effect/d in disease.effects) + if(!(d.type in types)) + return 0 + + if (antigen != disease.antigen) + return 0 + +/proc/virus_copylist(var/list/datum/disease2/disease/viruses) + var/list/res = list() + for (var/ID in viruses) + var/datum/disease2/disease/V = viruses[ID] + res["[V.uniqueID]"] = V.getcopy() + return res + + +var/global/list/virusDB = list() + +/datum/disease2/disease/proc/name() + .= "strain #[add_zero("[uniqueID]", 4)]" + if ("[uniqueID]" in virusDB) + var/datum/computer_file/data/virus_record/V = virusDB["[uniqueID]"] + .= V.fields["name"] + +/datum/disease2/disease/proc/get_info(skill = HAS_PERK, verbose = 1, given_effects) + if(!given_effects) + given_effects = effects + var/r = list() + if(verbose) + r += "Analysis determined the existence of a GNAv2-based viral lifeform.
" + r += "Designation: [name()]
" + r += "Antigen: [antigens2string(antigen)]
" + r += "Transmitted By: [spreadtype]
" + else + r = "[name()]" + + var/list/dat = list() + if(skill >= HAS_PERK) + if(verbose) + r += "Rate of Progression: [speed * 100]%
" + var/species = affected_species.Copy() + r += "Species Affected: [jointext(species, ", ")]
" + r += "Symptoms:
" + + for(var/datum/disease2/effect/E in given_effects) + dat += E.get_effect_info(verbose) + + . = verbose ? JOINTEXT(r + dat) : "[r] ([jointext(dat, ", ")])" + + +/datum/disease2/disease/proc/addToDB() + if ("[uniqueID]" in virusDB) + return 0 + var/datum/computer_file/data/virus_record/v = new() + v.fields["id"] = uniqueID + v.fields["name"] = name() + v.fields["description"] = get_info() + v.fields["antigen"] = antigens2string(antigen) + v.fields["spread type"] = spreadtype + virusDB["[uniqueID]"] = v + return 1 + + +proc/virology_letterhead(var/report_name) + return {" +

[report_name]

+
[station_name()] Virology Lab
+
+"} + +/datum/disease2/disease/proc/can_add_symptom(type) + for(var/datum/disease2/effect/H in effects) + if(H.type == type && !H.allow_multiple) + return 0 + + return 1 \ No newline at end of file diff --git a/code/modules/virus2/diseasesplicer.dm b/code/modules/virus2/diseasesplicer.dm new file mode 100644 index 00000000000..339e624782b --- /dev/null +++ b/code/modules/virus2/diseasesplicer.dm @@ -0,0 +1,187 @@ +/obj/machinery/computer/diseasesplicer + name = "disease splicer" + icon = 'icons/obj/computer.dmi' + icon_keyboard = "med_key" + icon_screen = "crew" + + var/datum/disease2/effect/memorybank = null + var/list/species_buffer = null + var/analysed = 0 + var/obj/item/weapon/virusdish/dish = null + var/burning = 0 + var/splicing = 0 + var/scanning = 0 + +/obj/machinery/computer/diseasesplicer/attackby(var/obj/I as obj, var/mob/user as mob) + if(isScrewdriver(I)) + return ..(I,user) + + if(istype(I,/obj/item/weapon/virusdish)) + if (dish) + to_chat(user, "\The [src] is already loaded.") + return + if(!user.unEquip(I, src)) + return + dish = I + + if(istype(I,/obj/item/weapon/diseasedisk)) + to_chat(user, "You upload the contents of the disk onto the buffer.") + var/obj/item/weapon/diseasedisk/disk = I + memorybank = disk.effect + species_buffer = disk.species + analysed = disk.analysed + + src.attack_hand(user) + +/obj/machinery/computer/diseasesplicer/interface_interact(var/mob/user) + ui_interact(user) + return TRUE + +/obj/machinery/computer/diseasesplicer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) + + var/data[0] + data["dish_inserted"] = !!dish + data["growth"] = 0 + data["affected_species"] = null + + if (memorybank) + data["buffer"] = list("name" = (analysed ? memorybank.name : "Unknown Symptom"), "stage" = memorybank.stage) + if (species_buffer) + data["species_buffer"] = analysed ? jointext(species_buffer, ", ") : "Unknown Species" + + if (splicing) + data["busy"] = "Splicing..." + else if (scanning) + data["busy"] = "Scanning..." + else if (burning) + data["busy"] = "Copying data to disk..." + else if (dish) + data["growth"] = min(dish.growth, 100) + + if (dish.virus2) + if (dish.virus2.affected_species) + data["affected_species"] = dish.analysed ? jointext(dish.virus2.affected_species, ", ") : "Unknown" + + if (dish.growth >= 50) + var/list/effects[0] + for (var/datum/disease2/effect/e in dish.virus2.effects) + effects.Add(list(list("name" = (dish.analysed ? e.name : "Unknown"), "stage" = (e.stage), "reference" = "\ref[e]"))) + data["effects"] = effects + else + data["info"] = "Insufficient cell growth for gene splicing." + else + data["info"] = "No virus detected." + else + data["info"] = "No dish loaded." + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "disease_splicer.tmpl", src.name, 400, 600) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/computer/diseasesplicer/Process() + if(stat & (NOPOWER|BROKEN)) + return + + if(scanning) + scanning -= 1 + if(!scanning) + ping("\The [src] pings, \"Analysis complete.\"") + SSnano.update_uis(src) + if(splicing) + splicing -= 1 + if(!splicing) + ping("\The [src] pings, \"Splicing operation complete.\"") + SSnano.update_uis(src) + if(burning) + burning -= 1 + if(!burning) + var/obj/item/weapon/diseasedisk/d = new /obj/item/weapon/diseasedisk(src.loc) + d.analysed = analysed + if(analysed) + if (memorybank) + d.SetName("[memorybank.name] GNA disk (Stage: [memorybank.stage])") + d.effect = memorybank + else if (species_buffer) + d.SetName("[jointext(species_buffer, ", ")] GNA disk") + d.species = species_buffer + else + if (memorybank) + d.SetName("Unknown GNA disk (Stage: [memorybank.stage])") + d.effect = memorybank + else if (species_buffer) + d.SetName("Unknown Species GNA disk") + d.species = species_buffer + + ping("\The [src] pings, \"Backup disk saved.\"") + SSnano.update_uis(src) + + if((scanning || splicing || burning) && dish && dish.virus2) + infect_nearby(dish.virus2, 80) + +/obj/machinery/computer/diseasesplicer/OnTopic(mob/user, href_list) + operator_skill = user.get_skill_value(core_skill) + if (href_list["close"]) + SSnano.close_user_uis(user, src, "main") + return TOPIC_HANDLED + + if (href_list["grab"]) + if (dish) + memorybank = locate(href_list["grab"]) + species_buffer = null + analysed = dish.analysed + dish = null + scanning = 10 + return TOPIC_REFRESH + + if (href_list["affected_species"]) + if (dish) + memorybank = null + species_buffer = dish.virus2.affected_species + analysed = dish.analysed + dish = null + scanning = 10 + return TOPIC_REFRESH + + if(href_list["eject"]) + if (dish) + dish.dropInto(loc) + dish = null + return TOPIC_REFRESH + + if(href_list["splice"]) + if(dish) + var/target = text2num(href_list["splice"]) // target = 1+ for effects, -1 for species + if(memorybank && target > 0) + if(target < memorybank.stage) + return // too powerful, catching this for href exploit prevention + + var/datum/disease2/effect/target_effect + var/list/illegal_types = list() + for(var/datum/disease2/effect/e in dish.virus2.effects) + if(e.stage == target) + target_effect = e + if(!e.allow_multiple) + illegal_types += e.type + if(memorybank.type in illegal_types) + to_chat(user, "Virus DNA can't hold more than one [memorybank]") + return 1 + dish.virus2.effects -= target_effect + dish.virus2.effects += memorybank + qdel(target_effect) + + else if(species_buffer && target == -1) + dish.virus2.affected_species = species_buffer + + else + return TOPIC_HANDLED + + splicing = 10 + dish.virus2.uniqueID = rand(0,10000) + return TOPIC_REFRESH + + if(href_list["disk"]) + burning = 10 + return TOPIC_REFRESH \ No newline at end of file diff --git a/code/modules/virus2/dishincubator.dm b/code/modules/virus2/dishincubator.dm new file mode 100644 index 00000000000..1a60c0d5ce1 --- /dev/null +++ b/code/modules/virus2/dishincubator.dm @@ -0,0 +1,200 @@ +/obj/machinery/disease2/incubator/ + name = "pathogenic incubator" + density = 1 + anchored = 1 + icon = 'icons/obj/virology.dmi' + icon_state = "incubator" + var/obj/item/weapon/virusdish/dish + var/obj/item/weapon/reagent_containers/glass/beaker = null + var/radiation = 0 + + var/on = 0 + var/power = 0 + + var/foodsupply = 0 + var/toxins = 0 + +/obj/machinery/disease2/incubator/attackby(var/obj/O as obj, var/mob/user as mob) + if(istype(O, /obj/item/weapon/reagent_containers/glass) || istype(O,/obj/item/weapon/reagent_containers/syringe)) + + if(beaker) + to_chat(user, "\The [src] is already loaded.") + return + if(!user.unEquip(O, src)) + return + beaker = O + + user.visible_message("[user] adds \a [O] to \the [src]!", "You add \a [O] to \the [src]!") + SSnano.update_uis(src) + + src.attack_hand(user) + return + + if(istype(O, /obj/item/weapon/virusdish)) + + if(dish) + to_chat(user, "The dish tray is already full!") + return + if(!user.unEquip(O, src)) + return + dish = O + + user.visible_message("[user] adds \a [O] to \the [src]!", "You add \a [O] to \the [src]!") + SSnano.update_uis(src) + + src.attack_hand(user) + +/obj/machinery/disease2/incubator/interface_interact(mob/user) + ui_interact(user) + return TRUE + +/obj/machinery/disease2/incubator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) + + var/data[0] + data["chemicals_inserted"] = !!beaker + data["dish_inserted"] = !!dish + data["food_supply"] = foodsupply + data["radiation"] = radiation + data["toxins"] = min(toxins, 100) + data["on"] = on + data["system_in_use"] = foodsupply > 0 || radiation > 0 || toxins > 0 + data["chemical_volume"] = beaker ? beaker.reagents.total_volume : 0 + data["max_chemical_volume"] = beaker ? beaker.volume : 1 + data["virus"] = dish ? dish.virus2 : null + data["growth"] = dish ? min(dish.growth, 100) : 0 + data["infection_rate"] = dish && dish.virus2 ? dish.virus2.infectionchance * 10 : 0 + data["analysed"] = dish && dish.analysed ? 1 : 0 + data["can_breed_virus"] = null + data["blood_already_infected"] = null + + if (beaker) + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in beaker.reagents.reagent_list + data["can_breed_virus"] = dish && dish.virus2 && B + + if (B) + if (!B.data["virus2"]) + B.data["virus2"] = list() + + var/list/virus = B.data["virus2"] + for (var/ID in virus) + data["blood_already_infected"] = virus[ID] + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "dish_incubator.tmpl", src.name, 400, 600) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/disease2/incubator/Process() + ..() + if(dish && on && dish.virus2) + use_power_oneoff(50,EQUIP) + if(!powered(EQUIP)) + on = 0 + icon_state = "incubator" + + var/threshold_mod = 0 + + if(foodsupply) + if(dish.growth + 3 >= 100 && dish.growth < 100) + ping("\The [src] pings, \"Sufficient viral growth density achieved.\"") + + foodsupply -= 1 + dish.growth += 3 + SSnano.update_uis(src) + + if(radiation) + threshold_mod++ + if(radiation > 50 & prob(5)) + dish.virus2.majormutate() + if(dish.info) + dish.info = "OUTDATED : [dish.info]" + dish.basic_info = "OUTDATED: [dish.basic_info]" + dish.analysed = 0 + ping("\The [src] pings, \"Mutant viral strain detected.\"") + else if(prob(5)) + dish.virus2.minormutate() + radiation -= 1 + SSnano.update_uis(src) + if(toxins && prob(5)) + dish.virus2.infectionchance -= 1 + SSnano.update_uis(src) + if(toxins > 50) + dish.growth = 0 + dish.virus2 = null + SSnano.update_uis(src) + infect_nearby(dish.virus2, 20 * 2**threshold_mod) + else if(!dish) + on = 0 + icon_state = "incubator" + SSnano.update_uis(src) + + if(beaker) + if (foodsupply < 100 && beaker.reagents.has_reagent(/datum/reagent/nutriment/virus_food)) + var/food_needed = min(10, 100 - foodsupply) / 2 + var/food_taken = min(food_needed, beaker.reagents.get_reagent_amount(/datum/reagent/nutriment/virus_food)) + + beaker.reagents.remove_reagent(/datum/reagent/nutriment/virus_food, food_taken) + foodsupply = min(100, foodsupply+(food_taken * 2)) + SSnano.update_uis(src) + + if ((locate(/datum/reagent/toxin) in beaker.reagents.reagent_list) && toxins < 100) + for(var/datum/reagent/toxin/T in beaker.reagents.reagent_list) + toxins += max(T.strength,1) + beaker.reagents.remove_reagent(T.type,1) + if(toxins > 100) + toxins = 100 + break + SSnano.update_uis(src) + +/obj/machinery/disease2/incubator/OnTopic(mob/user, href_list) + operator_skill = user.get_skill_value(core_skill) + if (href_list["close"]) + SSnano.close_user_uis(user, src, "main") + return TOPIC_HANDLED + + if (href_list["ejectchem"]) + if(beaker) + beaker.dropInto(loc) + beaker = null + return TOPIC_REFRESH + + if (href_list["power"]) + if (dish) + on = !on + icon_state = on ? "incubator_on" : "incubator" + return TOPIC_REFRESH + + if (href_list["ejectdish"]) + if(dish) + dish.dropInto(loc) + dish = null + return TOPIC_REFRESH + + if (href_list["rad"]) + radiation = min(100, radiation + 10) + return TOPIC_REFRESH + + if (href_list["flush"]) + radiation = 0 + toxins = 0 + foodsupply = 0 + return TOPIC_REFRESH + + if(href_list["virus"]) + if (!dish) + return TOPIC_HANDLED + + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in beaker.reagents.reagent_list + if (!B) + return TOPIC_HANDLED + + if (!B.data["virus2"]) + B.data["virus2"] = list() + + var/list/virus = list("[dish.virus2.uniqueID]" = dish.virus2.getcopy()) + B.data["virus2"] += virus + + ping("\The [src] pings, \"Injection complete.\"") + return TOPIC_REFRESH \ No newline at end of file diff --git a/code/modules/virus2/effect.dm b/code/modules/virus2/effect.dm new file mode 100644 index 00000000000..a891f134e19 --- /dev/null +++ b/code/modules/virus2/effect.dm @@ -0,0 +1,406 @@ +//////////////////////////////////////////////////////////////// +////////////////////////EFFECTS///////////////////////////////// +//////////////////////////////////////////////////////////////// +/proc/get_random_virus2_effect(stage, badness, exclude) + var/list/datum/disease2/effect/candidates = list() + for(var/T in subtypesof(/datum/disease2/effect)) + var/datum/disease2/effect/E = T + if(E in exclude) + continue + if(initial(E.badness) > badness) //we don't want such strong effects + continue + if(initial(E.stage) <= stage) + candidates += T + var/type = pick(candidates) + var/datum/disease2/effect/effect = new type + effect.generate() + effect.chance = rand(0,effect.chance_max) + effect.multiplier = rand(1,effect.multiplier_max) + return effect + +/datum/disease2/effect + var/name = "Blanking effect" + var/chance //probality to fire every tick + var/chance_max = 50 + var/multiplier = 1 //effect magnitude multiplier + var/multiplier_max = 1 + var/stage = 4 //minimal stage + var/badness = VIRUS_MILD //Used in random generation to limit how bad result should come out. + var/data = null //For semi-procedural effects; this should be generated in generate() if used + var/oneshot + var/delay = 5 SECONDS //minimal time between activations + var/hold_until //can only fire after this worldtime + var/allow_multiple //allow to have more than 1 effect of this type in the same virus + +/datum/disease2/effect/proc/get_effect_info(verbose = 1) + . = list() + if(verbose) + . += "([stage]) [name] " + . += "Strength: [multiplier >= 3 ? "Severe" : multiplier > 1 ? "Above Average" : "Average"] " + . += "Verosity: [chance * 15]
" + else + . += name + return JOINTEXT(.) + +/datum/disease2/effect/proc/fire(var/mob/living/carbon/human/mob,var/current_stage) + if(oneshot == -1) + return + if(hold_until > world.time) + return + if(mob.chem_effects[CE_ANTIVIRAL] >= badness) + return + if(stage <= current_stage && prob(chance)) + hold_until = world.time + delay + activate(mob) + if(oneshot == 1) + oneshot = -1 + +/datum/disease2/effect/proc/minormutate() + switch(pick(1,2,3,4,5)) + if(1) + chance = rand(0,chance_max) + if(2) + multiplier = rand(1,multiplier_max) + +/datum/disease2/effect/proc/activate(var/mob/living/carbon/human/mob) +/datum/disease2/effect/proc/deactivate(var/mob/living/carbon/human/mob) +/datum/disease2/effect/proc/generate(copy_data) // copy_data will be non-null if this is a copy; it should be used to initialise the data for this effect if present + +/datum/disease2/effect/invisible + name = "Waiting Syndrome" + stage = 1 + +////////////////////////STAGE 4///////////////////////////////// + +/datum/disease2/effect/gibbingtons + name = "Gibbingtons Syndrome" + stage = 4 + badness = VIRUS_EXOTIC + activate(var/mob/living/carbon/human/mob,var/multiplier) + // Probabilities have been tweaked to kill in ~2-3 minutes, giving 5-10 messages. + // Probably needs more balancing, but it's better than LOL U GIBBED NOW, especially now that viruses can potentially have no signs up until Gibbingtons. + mob.adjustBruteLoss(10*multiplier) + var/obj/item/organ/external/O = pick(mob.organs) + if(prob(25)) + to_chat(mob, "Your [O.name] feels as if it might burst!") + if(prob(10)) + spawn(50) + if(O) + O.droplimb(0,DROPLIMB_BLUNT) + +/datum/disease2/effect/radian + name = "Radian's Syndrome" + stage = 4 + multiplier_max = 3 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.apply_damage(2*multiplier, IRRADIATE, armor_pen = 100) + +/datum/disease2/effect/deaf + name = "Dead Ear Syndrome" + stage = 4 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.ear_deaf = min(mob.ear_deaf + 10, 50) + +/datum/disease2/effect/monkey + name = "Two Percent Syndrome" + stage = 4 + badness = VIRUS_EXOTIC + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.monkeyize() + +/datum/disease2/effect/killertoxins + name = "Toxification Syndrome" + stage = 4 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.adjustToxLoss(15*multiplier) + +/datum/disease2/effect/dna + name = "Reverse Pattern Syndrome" + stage = 4 + badness = VIRUS_ENGINEERED + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.bodytemperature = max(mob.bodytemperature, 350) + scramble(0,mob,10) + mob.apply_damage(10, CLONE) + +/datum/disease2/effect/organs + name = "Shutdown Syndrome" + stage = 4 + badness = VIRUS_ENGINEERED + activate(var/mob/living/carbon/human/mob,var/multiplier) + var/organ = pick(list(BP_R_ARM,BP_L_ARM,BP_R_LEG,BP_L_LEG)) + var/obj/item/organ/external/E = mob.organs_by_name[organ] + if (!(E.status & ORGAN_DEAD)) + E.status |= ORGAN_DEAD + to_chat(mob, "You can't feel your [E.name] anymore...") + for (var/obj/item/organ/external/C in E.children) + C.status |= ORGAN_DEAD + mob.update_body(1) + mob.adjustToxLoss(15*multiplier) + + deactivate(var/mob/living/carbon/human/mob,var/multiplier) + for (var/obj/item/organ/external/E in mob.organs) + E.status &= ~ORGAN_DEAD + for (var/obj/item/organ/external/C in E.children) + C.status &= ~ORGAN_DEAD + mob.update_body(1) + +/datum/disease2/effect/immortal + name = "Longevity Syndrome" + stage = 4 + badness = VIRUS_ENGINEERED + activate(var/mob/living/carbon/human/mob,var/multiplier) + for (var/external in mob.organs) + var/obj/item/organ/external/E = external + if (E.status & ORGAN_BROKEN && prob(30)) + to_chat(mob, "Your [E.name] suddenly feels much better!") + E.status ^= ORGAN_BROKEN + break + for (var/internal in mob.internal_organs) + var/obj/item/organ/internal/I = internal + if (I.damage && prob(30)) + to_chat(mob, "Your [mob.get_organ(I.parent_organ)] feels a bit warm...") + I.take_internal_damage(-2*multiplier) + break + var/heal_amt = -5*multiplier + mob.apply_damages(heal_amt,heal_amt,heal_amt,heal_amt) + + deactivate(var/mob/living/carbon/human/mob,var/multiplier) + to_chat(mob, "You suddenly feel hurt and old...") + mob.age += 8 + var/backlash_amt = 5*multiplier + mob.apply_damages(backlash_amt,backlash_amt,backlash_amt,backlash_amt) + +/datum/disease2/effect/bones + name = "Fragile Bones Syndrome" + stage = 4 + badness = VIRUS_ENGINEERED + activate(var/mob/living/carbon/human/mob,var/multiplier) + for (var/obj/item/organ/external/E in mob.organs) + E.min_broken_damage = max(5, E.min_broken_damage - 30) + + deactivate(var/mob/living/carbon/human/mob,var/multiplier) + for (var/obj/item/organ/external/E in mob.organs) + E.min_broken_damage = initial(E.min_broken_damage) + +////////////////////////STAGE 3///////////////////////////////// + +/datum/disease2/effect/toxins + name = "Hyperacidity" + stage = 3 + multiplier_max = 3 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.adjustToxLoss((2*multiplier)) + +/datum/disease2/effect/shakey + name = "World Shaking Syndrome" + stage = 3 + multiplier_max = 3 + activate(var/mob/living/carbon/human/mob,var/multiplier) + shake_camera(mob,5*multiplier) + +/datum/disease2/effect/telepathic + name = "Telepathy Syndrome" + stage = 3 + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.dna.SetSEState(GLOB.REMOTETALKBLOCK,1) + domutcheck(mob, null, MUTCHK_FORCED) + +/datum/disease2/effect/mind + name = "Lazy Mind Syndrome" + stage = 3 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + var/obj/item/organ/internal/brain/B = mob.internal_organs_by_name[BP_BRAIN] + if (B && B.damage < B.min_broken_damage) + B.take_internal_damage(5) + +/datum/disease2/effect/deaf + name = "Hard of Hearing Syndrome" + stage = 3 + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.ear_deaf = 5 + +/datum/disease2/effect/confusion + name = "Topographical Cretinism" + stage = 3 + activate(var/mob/living/carbon/human/mob,var/multiplier) + to_chat(mob, "You have trouble telling right and left apart all of a sudden.") + mob.confused = min(mob.confused + 10, 50) + +/datum/disease2/effect/mutation + name = "DNA Degradation" + stage = 3 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.apply_damage(2, CLONE) + +/datum/disease2/effect/chem_synthesis + name = "Chemical Synthesis" + stage = 3 + badness = VIRUS_COMMON + chance_max = 25 + + generate(c_data) + if(c_data) + data = c_data + else + data = pick(/datum/reagent/bicaridine, /datum/reagent/kelotane, /datum/reagent/dylovene, /datum/reagent/inaprovaline, /datum/reagent/space_drugs, /datum/reagent/sugar, + /datum/reagent/tramadol, /datum/reagent/dexalin, /datum/reagent/cryptobiolin, /datum/reagent/impedrezene, /datum/reagent/hyperzine, /datum/reagent/ethylredoxrazine, + /datum/reagent/mindbreaker, /datum/reagent/nutriment/glucose) + var/datum/reagent/R = data + name = "[initial(name)] ([initial(R.name)])" + + activate(var/mob/living/carbon/human/mob,var/multiplier) + if (mob.reagents.get_reagent_amount(data) < 5) + mob.reagents.add_reagent(data, 2) + +/datum/disease2/effect/nothing + name = "Nil Syndrome" + stage = 1 + badness = VIRUS_MILD + chance_max = 0 + allow_multiple = 1 + +////////////////////////STAGE 2///////////////////////////////// +/datum/disease2/effect/drowsness + name = "Automated Sleeping Syndrome" + stage = 2 + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.drowsyness = min(mob.drowsyness + 10, 50) + +/datum/disease2/effect/sleepy + name = "Resting Syndrome" + stage = 2 + chance_max = 15 + delay = 35 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.emote("collapse") + +/datum/disease2/effect/blind + name = "Blackout Syndrome" + stage = 2 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.eye_blind = max(mob.eye_blind, 4) + +/datum/disease2/effect/cough + name = "Anima Syndrome" + stage = 2 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.emote("cough") + if (mob.wear_mask) + return + for(var/mob/living/carbon/human/M in oview(2,mob)) + mob.spread_disease_to(M) + +/datum/disease2/effect/hungry + name = "Appetiser Effect" + stage = 2 + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.adjust_nutrition(-200) + +/datum/disease2/effect/fridge + name = "Refridgerator Syndrome" + stage = 2 + chance_max = 25 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.emote("shiver") + +/datum/disease2/effect/hair + name = "Hair Loss" + stage = 2 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + if(mob.species.name == SPECIES_HUMAN && !(mob.h_style == "Bald") && !(mob.h_style == "Balding Hair")) + to_chat(mob, "Your hair starts to fall out in clumps...") + spawn(50) + mob.h_style = "Balding Hair" + mob.update_hair() + +/datum/disease2/effect/stimulant + name = "Adrenaline Extra" + stage = 2 + badness = VIRUS_COMMON + activate(var/mob/living/carbon/human/mob,var/multiplier) + to_chat(mob, "You feel a rush of energy inside you!") + if (mob.reagents.get_reagent_amount(/datum/reagent/hyperzine) < 10) + mob.reagents.add_reagent(/datum/reagent/hyperzine, 4) + if (prob(30)) + mob.jitteriness = min(mob.jitteriness + 10, 500) + +////////////////////////STAGE 1///////////////////////////////// + +/datum/disease2/effect/sneeze + name = "Coldingtons Effect" + stage = 1 + delay = 15 SECONDS + + activate(var/mob/living/carbon/human/mob,var/multiplier) + if (prob(30)) + to_chat(mob, "You feel like you are about to sneeze!") + sleep(5) + mob.emote("sneeze") + for(var/mob/living/carbon/human/M in get_step(mob,mob.dir)) + mob.spread_disease_to(M) + if (prob(50) && !mob.wear_mask) + var/obj/effect/decal/cleanable/mucus/M = new(get_turf(mob)) + M.virus2 = virus_copylist(mob.virus2) + +/datum/disease2/effect/gunck + name = "Flemmingtons" + stage = 1 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + to_chat(mob, "Mucous runs down the back of your throat.") + +/datum/disease2/effect/drool + name = "Saliva Effect" + stage = 1 + chance_max = 25 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.emote("drool") + +/datum/disease2/effect/twitch + name = "Twitcher" + stage = 1 + chance_max = 25 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.emote("twitch") + +/datum/disease2/effect/headache + name = "Headache" + stage = 1 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + mob.custom_pain("Your head hurts a bit.", 20) + +/datum/disease2/effect/itch + name = "Itches" + stage = 1 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + var/obj/O = pick(mob.organs) + to_chat(mob, "Your [O.name] itches like hell.") + +/datum/disease2/effect/stomach + name = "Upset stomach" + stage = 1 + delay = 25 SECONDS + activate(var/mob/living/carbon/human/mob,var/multiplier) + to_chat(mob, "Your stomach feels heavy.") + +/datum/disease2/effect/stealth + name = "Silent Death Syndrome" + stage = 1 + badness = VIRUS_EXOTIC + chance_max = 0 + allow_multiple = 1 \ No newline at end of file diff --git a/code/modules/virus2/helpers.dm b/code/modules/virus2/helpers.dm new file mode 100644 index 00000000000..36740face50 --- /dev/null +++ b/code/modules/virus2/helpers.dm @@ -0,0 +1,191 @@ +/obj/machinery/disease2 + core_skill = SKILL_VIROLOGY + +/obj/machinery/proc/infect_nearby(datum/disease2/disease/disease, base_chance = 20, dist = 2) + if(istype(disease) && operator_skill <= HAS_PERK) + for(var/mob/living/carbon/victim in range(dist, src)) + if(prob(base_chance)) + infect_virus2(victim, disease) + +//Returns 1 if mob can be infected, 0 otherwise. +proc/infection_chance(var/mob/living/carbon/M, var/vector = "Airborne") + if (!istype(M)) + return 0 + + var/mob/living/carbon/human/H = M + if(istype(H) && H.species.get_virus_immune(H)) + return 0 + + var/protection = M.get_blocked_ratio(null, TOX, damage_flags = DAM_DISPERSED | DAM_BIO) //gets the full body bio armour value, weighted by body part coverage. + var/score = round(6 * protection) //scales 100% protection to 6. + + switch(vector) + if("Airborne") + if(M.internal) //not breathing infected air helps greatly + return 0 + var/obj/item/I = M.wear_mask + //masks provide a small bonus and can replace overall bio protection + if(I) + var/datum/extension/armor/armor_datum = get_extension(I, /datum/extension/armor) + if(armor_datum) + score = max(score, round(0.06*armor_datum.get_value("bio"))) + if (istype(I, /obj/item/clothing/mask)) + score += 1 //this should be added after + + if("Contact") + if(istype(H)) + //gloves provide a larger bonus + if (istype(H.gloves, /obj/item/clothing/gloves)) + score += 2 + + switch(score) + if (6 to INFINITY) + return 0 + if (5) + return 1 + if (4) + return 5 + if (3) + return 25 + if (2) + return 45 + if (1) + return 65 + else + return 100 + +//Similar to infection check, but used for when M is spreading the virus. +/proc/infection_spreading_check(var/mob/living/carbon/M, var/vector = "Airborne") + if (!istype(M)) + return 0 + + var/protection = M.get_blocked_ratio(null, TOX, damage_flags = DAM_DISPERSED | DAM_BIO) //gets the full body bio armour value, weighted by body part coverage. + + if (vector == "Airborne") //for airborne infections face-covering items give non-weighted protection value. + if(M.internal) + return 1 + protection = max(protection, M.get_blocked_ratio(BP_HEAD, TOX, damage_flags = DAM_BIO)) + + return prob(100 * protection + 15*M.chem_effects[CE_ANTIVIRAL]) + +/proc/airborne_can_reach(turf/simulated/source, turf/simulated/target) + //Can't ariborne without air + if(is_below_sound_pressure(source) || is_below_sound_pressure(target)) + return FALSE + //no infecting from other side of the hallway + if(get_dist(source,target) > 5) + return FALSE + if(istype(source) && istype(target)) + return source.zone == target.zone + +//Attemptes to infect mob M with virus. Set forced to 1 to ignore protective clothnig +/proc/infect_virus2(var/mob/living/carbon/M,var/datum/disease2/disease/disease,var/forced = 0) + if(!istype(disease)) +// log_debug("Bad virus") + return + if(!istype(M)) +// log_debug("Bad mob") + return + if ("[disease.uniqueID]" in M.virus2) + return + // if one of the antibodies in the mob's body matches one of the disease's antigens, don't infect + var/list/antibodies_in_common = M.antibodies & disease.antigen + if(antibodies_in_common.len) + return + if(prob(100 * M.reagents.get_reagent_amount(/datum/reagent/spaceacillin) / (REAGENTS_OVERDOSE/2))) + return + + if(!disease.affected_species.len) + return + + if (!(M.species.get_bodytype(M) in disease.affected_species)) + if (forced) + disease.affected_species[1] = M.species.get_bodytype(M) + else + return //not compatible with this species + +// log_debug("Infecting [M]") + var/mob_infection_prob = infection_chance(M, disease.spreadtype) * M.immunity_weakness() + if(forced || (prob(disease.infectionchance) && prob(mob_infection_prob))) + var/datum/disease2/disease/D = disease.getcopy() + D.minormutate() +// log_debug("Adding virus") + M.virus2["[D.uniqueID]"] = D + BITSET(M.hud_updateflag, STATUS_HUD) + +//Infects mob M with random lesser disease, if he doesn't have one +/proc/infect_mob_random_lesser(var/mob/living/carbon/M) + var/datum/disease2/disease/D = new /datum/disease2/disease + + D.makerandom(VIRUS_MILD) + infect_virus2(M, D, 1) + +//Infects mob M with random greated disease, if he doesn't have one +/proc/infect_mob_random_greater(var/mob/living/carbon/M) + var/datum/disease2/disease/D = new /datum/disease2/disease + + D.makerandom(VIRUS_COMMON) + infect_virus2(M, D, 1) + +//Fancy prob() function. +/proc/dprob(var/p) + return(prob(sqrt(p)) && prob(sqrt(p))) + +/mob/living/carbon/proc/spread_disease_to(var/mob/living/carbon/victim, var/vector = "Airborne") + if (src == victim) + return "retardation" + +// log_debug("Spreading [vector] diseases from [src] to [victim]") + if (virus2.len > 0) + for (var/ID in virus2) +// log_debug("Attempting virus [ID]") + var/datum/disease2/disease/V = virus2[ID] + if(V.spreadtype != vector) continue + + //It's hard to get other people sick if you're in an airtight suit. + if(!infection_spreading_check(src, V.spreadtype)) continue + + if (vector == "Airborne") + if(airborne_can_reach(get_turf(src), get_turf(victim))) +// log_debug("In range, infecting") + infect_virus2(victim,V) +// else +// log_debug("Could not reach target") + + if (vector == "Contact") + if (Adjacent(victim)) +// log_debug("In range, infecting") + infect_virus2(victim,V) + + //contact goes both ways + if (victim.virus2.len > 0 && vector == "Contact" && Adjacent(victim)) +// log_debug("Spreading [vector] diseases from [victim] to [src]") + var/nudity = 1 + + if (ishuman(victim)) + var/mob/living/carbon/human/H = victim + + //Allow for small chance of touching other zones. + //This is proc is also used for passive spreading so just because they are targeting + //that zone doesn't mean that's necessarily where they will touch. + var/touch_zone = zone_sel ? zone_sel.selecting : "chest" + touch_zone = ran_zone(touch_zone, 80) + var/obj/item/organ/external/select_area = H.get_organ(touch_zone) + if(!select_area) + //give it one more chance, since this is also called for passive spreading + select_area = H.get_organ(ran_zone()) + + if(!select_area) + nudity = 0 //cant contact a missing body part + else + var/list/clothes = list(H.head, H.wear_mask, H.wear_suit, H.w_uniform, H.gloves, H.shoes) + for(var/obj/item/clothing/C in clothes) + if(C && istype(C)) + if(C.body_parts_covered & select_area.body_part) + nudity = 0 + if (nudity) + for (var/ID in victim.virus2) + var/datum/disease2/disease/V = victim.virus2[ID] + if(V && V.spreadtype != vector) continue + if(!infection_spreading_check(victim, V.spreadtype)) continue + infect_virus2(src,V) \ No newline at end of file diff --git a/code/modules/virus2/isolator.dm b/code/modules/virus2/isolator.dm new file mode 100644 index 00000000000..44cbc248cc7 --- /dev/null +++ b/code/modules/virus2/isolator.dm @@ -0,0 +1,227 @@ +// UI menu navigation +#define HOME "home" +#define LIST "list" +#define ENTRY "entry" + +/obj/machinery/disease2/isolator/ + name = "pathogenic isolator" + density = 1 + anchored = 1 + icon = 'icons/obj/virology.dmi' + icon_state = "isolator" + var/isolating = 0 + var/state = HOME + var/datum/disease2/disease/virus2 = null + var/datum/computer_file/data/virus_record/entry = null + var/obj/item/weapon/reagent_containers/syringe/sample = null + +/obj/machinery/disease2/isolator/on_update_icon() + if (stat & (BROKEN|NOPOWER)) + icon_state = "isolator" + return + + if (isolating) + icon_state = "isolator_processing" + else if (sample) + icon_state = "isolator_in" + else + icon_state = "isolator" + +/obj/machinery/disease2/isolator/attackby(var/obj/O as obj, var/mob/user) + if(!istype(O,/obj/item/weapon/reagent_containers/syringe)) return + if(sample) + to_chat(user, "\The [src] is already loaded.") + return + if(!user.unEquip(O, src)) + return + sample = O + + user.visible_message("[user] adds \a [O] to \the [src]!", "You add \a [O] to \the [src]!") + SSnano.update_uis(src) + update_icon() + + src.attack_hand(user) + +/obj/machinery/disease2/isolator/interface_interact(mob/user) + ui_interact(user) + return TRUE + +/obj/machinery/disease2/isolator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) + + var/data[0] + data["syringe_inserted"] = !!sample + data["isolating"] = isolating + data["pathogen_pool"] = null + data["state"] = state + data["entry"] = entry + data["can_print"] = (state != HOME || sample) && !isolating + + switch (state) + if (HOME) + if (sample) + var/list/pathogen_pool[0] + for(var/datum/reagent/blood/B in sample.reagents.reagent_list) + var/list/virus = B.data["virus2"] + for (var/ID in virus) + var/datum/disease2/disease/V = virus[ID] + var/datum/computer_file/data/virus_record/R = null + if (ID in virusDB) + R = virusDB[ID] + + var/weakref/W = B.data["donor"] + var/mob/living/carbon/human/D = W.resolve() + pathogen_pool.Add(list(list(\ + "name" = "[D ? D.get_species() : "Unidentified"] [B.name]", \ + "dna" = B.data["blood_DNA"], \ + "unique_id" = V.uniqueID, \ + "reference" = "\ref[V]", \ + "is_in_database" = !!R, \ + "record" = "\ref[R]"))) + + if (pathogen_pool.len > 0) + data["pathogen_pool"] = pathogen_pool + + if (LIST) + var/list/db[0] + for (var/ID in virusDB) + var/datum/computer_file/data/virus_record/r = virusDB[ID] + db.Add(list(list("name" = r.fields["name"], "record" = "\ref[r]"))) + + if (db.len > 0) + data["database"] = db + + if (ENTRY) + if (entry) + var/desc = entry.fields["description"] + data["entry"] = list(\ + "name" = entry.fields["name"], \ + "description" = replacetext(desc, "\n", "")) + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "pathogenic_isolator.tmpl", src.name, 400, 500) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/disease2/isolator/Process() + if (isolating > 0) + isolating -= 1 + if(virus2) + infect_nearby(virus2) + if (isolating == 0) + if (virus2) + var/obj/item/weapon/virusdish/d = new /obj/item/weapon/virusdish(src.loc) + d.virus2 = virus2.getcopy() + virus2 = null + ping("\The [src] pings, \"Viral strain isolated.\"") + + SSnano.update_uis(src) + update_icon() + +/obj/machinery/disease2/isolator/OnTopic(mob/user, href_list) + if (href_list["close"]) + SSnano.close_user_uis(user, src, "main") + return TOPIC_HANDLED + + if (href_list[HOME]) + state = HOME + return TOPIC_REFRESH + + if (href_list[LIST]) + state = LIST + return TOPIC_REFRESH + + if (href_list[ENTRY]) + if (istype(locate(href_list["view"]), /datum/computer_file/data/virus_record)) + entry = locate(href_list["view"]) + + state = ENTRY + return TOPIC_REFRESH + + if (href_list["print"]) + print(user) + return TOPIC_REFRESH + + if(!sample) return TOPIC_HANDLED + + if (href_list["isolate"]) + operator_skill = user.get_skill_value(core_skill) + var/datum/disease2/disease/V = locate(href_list["isolate"]) + if (V) + virus2 = V + isolating = 20 + update_icon() + return TOPIC_REFRESH + + if (href_list["eject"]) + sample.dropInto(loc) + sample = null + update_icon() + return TOPIC_REFRESH + +/obj/machinery/disease2/isolator/proc/print(var/mob/user) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(loc) + + switch (state) + if (HOME) + if (!sample) return + P.SetName("paper - Patient Diagnostic Report") + P.info = {" + [virology_letterhead("Patient Diagnostic Report")] +
CONFIDENTIAL MEDICAL REPORT

+ Sample: [sample.name]
+"} + + if (user) + P.info += "Generated By: [user.name]
" + + P.info += "
" + + for(var/datum/reagent/blood/B in sample.reagents.reagent_list) + var/weakref/W = B.data["donor"] + var/mob/living/carbon/human/D = W.resolve() + P.info += "[D ? D.get_species() : "Unidentified"] [B.name]:
[B.data["blood_DNA"]]
" + + var/list/virus = B.data["virus2"] + P.info += "Pathogens:
" + if (virus.len > 0) + for (var/ID in virus) + var/datum/disease2/disease/V = virus[ID] + P.info += "[V.name()]
" + else + P.info += "None
" + + P.info += {" +
+ Additional Notes:  +"} + + if (LIST) + P.SetName("paper - Virus List") + P.info = {" + [virology_letterhead("Virus List")] +"} + + var/i = 0 + for (var/ID in virusDB) + i++ + var/datum/computer_file/data/virus_record/r = virusDB[ID] + P.info += "[i]. " + r.fields["name"] + P.info += "
" + + P.info += {" +
+ Additional Notes:  +"} + + if (ENTRY) + P.SetName("paper - Viral Profile") + P.info = {" + [virology_letterhead("Viral Profile")] + [entry.fields["description"]] +
+ Additional Notes:  +"} + + state("The nearby computer prints out a report.") \ No newline at end of file diff --git a/code/modules/virus2/items_devices.dm b/code/modules/virus2/items_devices.dm new file mode 100644 index 00000000000..49e1c1aea28 --- /dev/null +++ b/code/modules/virus2/items_devices.dm @@ -0,0 +1,108 @@ +///////////////ANTIBODY SCANNER/////////////// + +/obj/item/device/antibody_scanner + name = "antibody scanner" + desc = "Scans living beings for antibodies in their blood." + icon_state = "health" + w_class = ITEM_SIZE_SMALL + item_state = "electronic" + obj_flags = OBJ_FLAG_CONDUCTIBLE + +/obj/item/device/antibody_scanner/attack(mob/M as mob, mob/user as mob) + if(!istype(M,/mob/living/carbon/)) + report("Scan aborted: Incompatible target.", user) + return + + var/mob/living/carbon/C = M + if (istype(C,/mob/living/carbon/human/)) + var/mob/living/carbon/human/H = C + if(!H.should_have_organ(BP_HEART)) + report("Scan aborted: The target does not have blood.", user) + return + + if(!C.antibodies.len) + report("Scan Complete: No antibodies detected.", user) + return + + if (MUTATION_CLUMSY in user.mutations && prob(50)) + // I was tempted to be really evil and rot13 the output. + report("Antibodies detected: [reverse_text(antigens2string(C.antibodies))]", user) + else + report("Antibodies detected: [antigens2string(C.antibodies)]", user) + +/obj/item/device/antibody_scanner/proc/report(var/text, mob/user as mob) + to_chat(user, "\icon[src] \The [src] beeps, \"[text]\"") + +///////////////VIRUS DISH/////////////// + +/obj/item/weapon/virusdish + name = "virus dish" + icon = 'icons/obj/items.dmi' + icon_state = "implantcase-b" + var/datum/disease2/disease/virus2 = null + var/growth = 0 + var/basic_info = null + var/info = 0 + var/analysed = 0 + +/obj/item/weapon/virusdish/random + name = "virus sample" + +/obj/item/weapon/virusdish/random/New() + ..() + src.virus2 = new /datum/disease2/disease + src.virus2.makerandom() + growth = rand(5, 50) + +/obj/item/weapon/virusdish/attackby(var/obj/item/weapon/W as obj,var/mob/living/carbon/user as mob) + if(istype(W,/obj/item/weapon/hand_labeler) || istype(W,/obj/item/weapon/reagent_containers/syringe)) + return + ..() + if(prob(50)) + to_chat(user, "\The [src] shatters!") + if(virus2.infectionchance > 0) + for(var/mob/living/carbon/target in view(1, get_turf(src))) + if(airborne_can_reach(get_turf(src), get_turf(target))) + infect_virus2(target, src.virus2) + qdel(src) + +/obj/item/weapon/virusdish/examine(mob/user) + . = ..() + if(basic_info) + to_chat(user, "[basic_info] : More Information") + +/obj/item/weapon/virusdish/OnTopic(user, href_list) + if(href_list["info"]) + show_browser(user, info, "window=info_\ref[src]") + return TOPIC_HANDLED + +/obj/item/weapon/ruinedvirusdish + name = "ruined virus sample" + icon = 'icons/obj/items.dmi' + icon_state = "implantcase-b" + desc = "The bacteria in the dish are completely dead." + +/obj/item/weapon/ruinedvirusdish/attackby(var/obj/item/weapon/W as obj,var/mob/living/carbon/user as mob) + if(istype(W,/obj/item/weapon/hand_labeler) || istype(W,/obj/item/weapon/reagent_containers/syringe)) + return ..() + + if(prob(50)) + to_chat(user, "\The [src] shatters!") + qdel(src) + +///////////////GNA DISK/////////////// + +/obj/item/weapon/diseasedisk + name = "blank GNA disk" + icon = 'icons/obj/cloning.dmi' + icon_state = "datadisk0" + w_class = ITEM_SIZE_TINY + var/datum/disease2/effect/effect = null + var/list/species = null + var/stage = 1 + var/analysed = 1 + +/obj/item/weapon/diseasedisk/premade/New() + name = "blank GNA disk (stage: [stage])" + effect = new /datum/disease2/effect/invisible + effect.stage = stage \ No newline at end of file diff --git a/maps/away/lar_maria/lar_maria.dm b/maps/away/lar_maria/lar_maria.dm index 946fe02f399..552e5faed6b 100644 --- a/maps/away/lar_maria/lar_maria.dm +++ b/maps/away/lar_maria/lar_maria.dm @@ -14,6 +14,66 @@ cost = 2 area_usage_test_exempted_root_areas = list(/area/lar_maria) +///////////////////////////////////custom virus for prisoners to spread +/datum/disease2/disease/lar_maria + infectionchance = 90 //very aggressive + speed = 10 + spreadtype = "Airborne" + +/datum/disease2/disease/lar_maria/New() + ..() + var/datum/disease2/effect/sneeze/E1 = new() + E1.stage = 1 + effects += E1 + var/datum/disease2/effect/stimulant/E2 = new() + E2.stage = 2 + effects += E2 + var/datum/disease2/effect/stimulant/E3 = new() + E3.stage = 3 + effects += E3 + var/datum/disease2/effect/rage/E4 = new() + E4.stage = 4 + effects += E4 + +/datum/disease2/effect/rage //custom effect, fills PC with uncontrollable rage + name = "Rampage Syndrome" + stage = 4 + badness = VIRUS_EXOTIC + delay = 20 SECONDS + var/first_message_shown = FALSE + +/datum/disease2/effect/rage/activate(var/mob/living/carbon/human/mob,var/multiplier) + if (!first_message_shown) + first_message_shown = TRUE + to_chat(mob, "Your muscles start tensing up, and you can feel your pulse rising, throbbing at the back of your head. Your breathing increases, and you feel... angry. An urge wells up inside you. Everything is making you angry, and you want it to pay for it.") + return //nothing else happens first time giving chance to adjust RP + if(prob(50)) + to_chat(mob, "You feel uncontrollable rage filling you! You want to hurt and destroy!") + if (mob.reagents.get_reagent_amount(/datum/reagent/hyperzine) < 10) + mob.reagents.add_reagent(/datum/reagent/hyperzine, 4) + if(prob(50) && mob.check_has_mouth())//go crazy and bite someone + var/list/mouth_status = mob.can_eat_status() + if (mouth_status[1] == 1)//if no mouth HUMAN_EATING_NBP_MOUTH + to_chat(mob, "You angrily attempt to bite someone but you can't without a mouth!") + return + if (mouth_status[1] == 2)//if something covers mouth HUMAN_EATING_BLOCKED_MOUTH + to_chat(mob, "You angrily chew \the [mouth_status[2]] covering your mouth!") + return + var/list/mobs_to_bite = list() + for (var/mob/living/carbon/human/L in trange(1)) + if (L == mob) + continue + mobs_to_bite += L + if (mobs_to_bite.len < 1)//nobody to bite + return + var/mob/living/carbon/human/Target = pick(mobs_to_bite) + mob.visible_message("[mob] violently bites [Target]!") + Target.adjustBruteLoss(5) + if (prob(50)) + infect_virus2(Target, src, 1) + + + ///////////////////////////////////crew and prisoners /obj/effect/landmark/corpse/lar_maria eye_colors_per_species = list(SPECIES_HUMAN = list(COLOR_RED))//red eyes @@ -43,6 +103,11 @@ attacktext = "punched" var/obj/effect/landmark/corpse/lar_maria/corpse = null var/weapon = null + var/datum/disease2/disease/lar_maria/LMD = new() + +/mob/living/simple_animal/hostile/lar_maria/Destroy() + . = ..() + QDEL_NULL(LMD) /mob/living/simple_animal/hostile/lar_maria/death(gibbed, deathmessage, show_dead_message) ..(gibbed, deathmessage, show_dead_message) @@ -51,8 +116,21 @@ if (weapon) new weapon(src.loc) visible_message("Small shining spores float away from dying [src]!") + for (var/mob/living/carbon/human/L in orange(3))//infect those who are around + if (prob(infection_chance(L, "Airborne"))) + infect_virus2(L, LMD, 1) qdel(src) +/mob/living/simple_animal/hostile/lar_maria/AttackingTarget() + . = ..() + if (!.) + return + if(ishuman(target_mob) && Adjacent(target_mob))//if it's human who can be infected standing nearby + var/mob/living/L = target_mob + if (prob(50)) + visible_message("[src] violently bites [L]!") + infect_virus2(L, LMD, 1) + /mob/living/simple_animal/hostile/lar_maria/test_subject name = "\improper test subject" desc = "Sick, filthy, angry and probably crazy human in an orange robe." diff --git a/maps/torch/items/cards_ids.dm b/maps/torch/items/cards_ids.dm index 8f97405540c..629aef837c5 100644 --- a/maps/torch/items/cards_ids.dm +++ b/maps/torch/items/cards_ids.dm @@ -41,6 +41,9 @@ job_access_type = /datum/job/doctor detail_color = COLOR_PALE_BLUE_GRAY +/obj/item/weapon/card/id/torch/crew/medical/virology + job_access_type = /datum/job/doctor/virologist + /obj/item/weapon/card/id/torch/crew/medical/senior job_access_type = /datum/job/senior_doctor diff --git a/maps/torch/job/command_jobs.dm b/maps/torch/job/command_jobs.dm index 10af77400bf..b38b6c04f3f 100644 --- a/maps/torch/job/command_jobs.dm +++ b/maps/torch/job/command_jobs.dm @@ -158,7 +158,8 @@ SKILL_MEDICAL = SKILL_EXPERT, SKILL_ANATOMY = SKILL_EXPERT, SKILL_CHEMISTRY = SKILL_BASIC, - SKILL_DEVICES = SKILL_ADEPT) + SKILL_DEVICES = SKILL_ADEPT, + SKILL_VIROLOGY = HAS_PERK) max_skill = list( SKILL_MEDICAL = SKILL_MAX, SKILL_ANATOMY = SKILL_MAX, diff --git a/maps/torch/job/medical_jobs.dm b/maps/torch/job/medical_jobs.dm index 45b070edd88..d193e41e475 100644 --- a/maps/torch/job/medical_jobs.dm +++ b/maps/torch/job/medical_jobs.dm @@ -3,7 +3,7 @@ department = "Medical" department_flag = MED minimal_player_age = 0 - minimum_character_age = list(SPECIES_HUMAN = 25) //lowered to 25 because of Resident alt-title. if resident title is removed or someone changes age to somehow link to tile, raise back to 28 + minimum_character_age = list(SPECIES_HUMAN = 25) total_positions = 3 spawn_positions = 3 supervisors = "the Chief Medical Officer" @@ -86,6 +86,44 @@ /datum/computer_file/program/camera_monitor) skill_points = 22 +/datum/job/doctor/virologist + title = "Virologist" //Highly specialized role for handling viruses only. Not a physician. Not a medtech. + total_positions = 1 + spawn_positions = 1 + supervisors = "the Chief Medical Officer" + economic_power = 8 + minimum_character_age = list(SPECIES_HUMAN = 25) + minimal_player_age = 0 + alt_titles = list() + outfit_type = /decl/hierarchy/outfit/job/torch/crew/medical/virologist + allowed_branches = list( + /datum/mil_branch/expeditionary_corps, + /datum/mil_branch/fleet = /decl/hierarchy/outfit/job/torch/crew/medical/virologist/fleet, + /datum/mil_branch/civilian = /decl/hierarchy/outfit/job/torch/crew/medical/contractor/virologist + ) + allowed_ranks = list( + /datum/mil_rank/ec/o1, + /datum/mil_rank/fleet/o1, + /datum/mil_rank/fleet/o2, + /datum/mil_rank/civ/contractor + ) + min_skill = list( SKILL_EVA = SKILL_BASIC, + SKILL_MEDICAL = SKILL_BASIC, + SKILL_ANATOMY = SKILL_BASIC, + SKILL_VIROLOGY = HAS_PERK) + + max_skill = list( SKILL_MEDICAL = SKILL_MAX, + SKILL_CHEMISTRY = SKILL_MAX) + + access = list(access_medical, access_morgue, access_virology, access_maint_tunnels, access_emergency_storage, + access_crematorium, access_surgery, + access_medical_equip, access_solgov_crew, access_hangar) + minimal_access = list() + + software_on_spawn = list(/datum/computer_file/program/suit_sensors, + /datum/computer_file/program/camera_monitor) + skill_points = 22 + /datum/job/medical_trainee title = "Medical Trainee" department = "Medical" diff --git a/maps/torch/job/outfits/boh_outfits.dm b/maps/torch/job/outfits/boh_outfits.dm index e1e2675ecdf..9a415b225c8 100644 --- a/maps/torch/job/outfits/boh_outfits.dm +++ b/maps/torch/job/outfits/boh_outfits.dm @@ -73,6 +73,11 @@ uniform = /obj/item/clothing/under/solgov/utility/army/medical shoes = /obj/item/clothing/shoes/dutyboots +/decl/hierarchy/outfit/job/torch/crew/medical/virologist/marine + name = OUTFIT_JOB_NAME("Virologist - Marine Corps") + uniform = /obj/item/clothing/under/solgov/utility/army/medical + shoes = /obj/item/clothing/shoes/dutyboots + /decl/hierarchy/outfit/job/torch/crew/medical/doctor/marine name = OUTFIT_JOB_NAME("Medical Technician - Marine Corps") uniform = /obj/item/clothing/under/solgov/utility/army/medical diff --git a/maps/torch/job/outfits/medical_outfits.dm b/maps/torch/job/outfits/medical_outfits.dm index 7e812f64df0..989b8114cb3 100644 --- a/maps/torch/job/outfits/medical_outfits.dm +++ b/maps/torch/job/outfits/medical_outfits.dm @@ -14,15 +14,30 @@ shoes = /obj/item/clothing/shoes/dutyboots id_type = /obj/item/weapon/card/id/torch/crew/medical/senior +/decl/hierarchy/outfit/job/torch/crew/medical/virologist + name = OUTFIT_JOB_NAME("Virologist - Dagon") + uniform = /obj/item/clothing/under/solgov/utility/expeditionary/officer/medical + shoes = /obj/item/clothing/shoes/dutyboots + id_type =/obj/item/weapon/card/id/torch/crew/medical/virology + /decl/hierarchy/outfit/job/torch/crew/medical/senior/fleet name = OUTFIT_JOB_NAME("Physician - Fleet") uniform = /obj/item/clothing/under/solgov/utility/fleet/medical shoes = /obj/item/clothing/shoes/dutyboots +/decl/hierarchy/outfit/job/torch/crew/medical/virologist/fleet + name = OUTFIT_JOB_NAME("Virologist - Fleet") + uniform = /obj/item/clothing/under/solgov/utility/fleet/medical + shoes = /obj/item/clothing/shoes/dutyboots + /decl/hierarchy/outfit/job/torch/crew/medical/contractor/senior name = OUTFIT_JOB_NAME("Physician - Contractor") id_type = /obj/item/weapon/card/id/torch/contractor/medical/senior +/decl/hierarchy/outfit/job/torch/crew/medical/contractor/virologist + name = OUTFIT_JOB_NAME("Virologist - Contractor") + id_type =/obj/item/weapon/card/id/torch/crew/medical/virology + /decl/hierarchy/outfit/job/torch/crew/medical/doctor name = OUTFIT_JOB_NAME("Medical Technician") uniform = /obj/item/clothing/under/solgov/utility/expeditionary/medical diff --git a/maps/torch/job/torch_jobs.dm b/maps/torch/job/torch_jobs.dm index cbdcd011307..203234c9965 100644 --- a/maps/torch/job/torch_jobs.dm +++ b/maps/torch/job/torch_jobs.dm @@ -18,7 +18,7 @@ /datum/job/senior_engineer, /datum/job/engineer, /datum/job/roboticist, /datum/job/engineer_trainee, /datum/job/officer, /datum/job/warden, /datum/job/detective, /datum/job/seccadet, /datum/job/squad_lead, /datum/job/combat_tech, /datum/job/grunt, /datum/job/combat_medic, - /datum/job/senior_doctor, /datum/job/doctor, /datum/job/chemist, /datum/job/medical_trainee, + /datum/job/senior_doctor, /datum/job/doctor/virologist, /datum/job/doctor, /datum/job/chemist, /datum/job/medical_trainee, /datum/job/psychiatrist, /datum/job/chaplain, /datum/job/qm, /datum/job/cargo_tech, /datum/job/mining, /datum/job/janitor, /datum/job/chef, /datum/job/bartender, diff --git a/maps/torch/job/torch_jobs_boh.dm b/maps/torch/job/torch_jobs_boh.dm index 04a07de3698..1f1532f8b16 100644 --- a/maps/torch/job/torch_jobs_boh.dm +++ b/maps/torch/job/torch_jobs_boh.dm @@ -240,6 +240,20 @@ /datum/mil_rank/civ/contractor ) +/datum/job/doctor/virologist + allowed_branches = list( + /datum/mil_branch/fleet = /decl/hierarchy/outfit/job/torch/crew/medical/virologist/fleet, + /datum/mil_branch/civilian = /decl/hierarchy/outfit/job/torch/crew/medical/contractor/virologist, + /datum/mil_branch/marine_corps = /decl/hierarchy/outfit/job/torch/crew/medical/virologist/marine + ) + allowed_ranks = list( + /datum/mil_rank/fleet/o3, + /datum/mil_rank/fleet/o4, + /datum/mil_rank/marine_corps/o3, + /datum/mil_rank/marine_corps/o4, + /datum/mil_rank/civ/contractor + ) + /datum/job/medical_trainee allowed_branches = list( /datum/mil_branch/expeditionary_corps, diff --git a/maps/torch/loadout/_defines.dm b/maps/torch/loadout/_defines.dm index a890e4cc51a..4f3e674c2fd 100644 --- a/maps/torch/loadout/_defines.dm +++ b/maps/torch/loadout/_defines.dm @@ -14,13 +14,13 @@ #define CASUAL_ROLES list(/datum/job/assistant, /datum/job/janitor, /datum/job/chef, /datum/job/bartender, /datum/job/cargo_tech, /datum/job/roboticist, /datum/job/mining, /datum/job/chaplain, /datum/job/merchant, /datum/job/psiadvisor, /datum/job/submap/bearcat_captain, /datum/job/submap/bearcat_crewman, /datum/job/submap/unishi_crew, /datum/job/submap/unishi_researcher, /datum/job/submap/colonist, /datum/job/submap/pod) //For roles that would have a higher level of education, typically doctors and other scientists -#define DOCTOR_ROLES list(/datum/job/cmo, /datum/job/senior_doctor, /datum/job/chemist, /datum/job/psychiatrist, /datum/job/roboticist, /datum/job/rd, /datum/job/senior_scientist, /datum/job/scientist) +#define DOCTOR_ROLES list(/datum/job/cmo, /datum/job/senior_doctor, /datum/job/doctor/virologist, /datum/job/chemist, /datum/job/psychiatrist, /datum/job/roboticist, /datum/job/rd, /datum/job/senior_scientist, /datum/job/scientist) //For members of the medical department -#define MEDICAL_ROLES list(/datum/job/cmo, /datum/job/senior_doctor, /datum/job/doctor, /datum/job/psychiatrist, /datum/job/chemist, /datum/job/medical_trainee) +#define MEDICAL_ROLES list(/datum/job/cmo, /datum/job/senior_doctor, /datum/job/doctor, /datum/job/doctor/virologist, /datum/job/psychiatrist, /datum/job/chemist, /datum/job/medical_trainee) //For members of the medical department, roboticists, and some Research -#define STERILE_ROLES list(/datum/job/cmo, /datum/job/senior_doctor, /datum/job/doctor, /datum/job/chemist, /datum/job/psychiatrist, /datum/job/roboticist, /datum/job/rd, /datum/job/senior_scientist, /datum/job/scientist, /datum/job/scientist_assistant, /datum/job/medical_trainee) +#define STERILE_ROLES list(/datum/job/cmo, /datum/job/senior_doctor, /datum/job/doctor, /datum/job/doctor/virologist, /datum/job/chemist, /datum/job/psychiatrist, /datum/job/roboticist, /datum/job/rd, /datum/job/senior_scientist, /datum/job/scientist, /datum/job/scientist_assistant, /datum/job/medical_trainee) //For members of the engineering department #define ENGINEERING_ROLES list(/datum/job/chief_engineer, /datum/job/senior_engineer, /datum/job/engineer, /datum/job/roboticist, /datum/job/engineer_trainee) @@ -53,10 +53,10 @@ #define COMMAND_ROLES list(/datum/job/captain, /datum/job/hop, /datum/job/rd, /datum/job/cmo, /datum/job/chief_engineer, /datum/job/hos, /datum/job/sea, /datum/job/sea/marine, /datum/job/bridgeofficer, /datum/job/liaison, /datum/job/solrep, /datum/job/solguard /datum/job/bodyguard, /datum/job/bailiff, /datum/job/psiadvisor, /datum/jiaison, /datum/job/bodyguard, /datum/job/bailiff, ob/adjudicator) //For jobs that have at least O-1 in either SGF or SMC, but aren't considered Command or Command Support. -#define OFFICER_ROLES list(/datum/job/scientist, /datum/job/qm, /datum/job/chaplain, /datum/job/psychiatrist, /datum/job/senior_doctor, /datum/job/pathfinder) +#define OFFICER_ROLES list(/datum/job/scientist, /datum/job/qm, /datum/job/chaplain, /datum/job/psychiatrist, /datum/job/senior_doctor, /datum/job/doctor/virologist, /datum/job/pathfinder) //For members of Command, Command Support and all other officer roles. Basically COMMAND_ROLES and OFFICER_ROLES merged together as a last resort. -#define COMMANDANDOFFICER_ROLES list(/datum/job/captain, /datum/job/hop, /datum/job/rd, /datum/job/cmo, /datum/job/chief_engineer, /datum/job/hos, /datum/job/sea, /datum/job/sea/marine, /datum/job/bridgeofficer, /datum/job/liaison, /datum/job/bodyguard, /datum/job/bailiff, /datum/job/psiadvisor, /datum/job/adjudicator, /datum/job/scientist, /datum/job/qm, /datum/job/chaplain, /datum/job/psychiatrist, /datum/job/senior_doctor, /datum/job/pathfinder, /datum/job/solrep, /datum/job/solguard) +#define COMMANDANDOFFICER_ROLES list(/datum/job/captain, /datum/job/hop, /datum/job/rd, /datum/job/cmo, /datum/job/chief_engineer, /datum/job/hos, /datum/job/sea, /datum/job/sea/marine, /datum/job/bridgeofficer, /datum/job/liaison, /datum/job/bodyguard, /datum/job/bailiff, /datum/job/psiadvisor, /datum/job/adjudicator, /datum/job/scientist, /datum/job/qm, /datum/job/chaplain, /datum/job/psychiatrist, /datum/job/senior_doctor, /datum/job/doctor/virologist, /datum/job/pathfinder, /datum/job/solrep, /datum/job/solguard) #define UNIFORMED_BRANCHES list(/datum/mil_branch/expeditionary_corps, /datum/mil_branch/fleet, /datum/mil_branch/marine_corps) diff --git a/maps/torch/loadout/loadout_accessories.dm b/maps/torch/loadout/loadout_accessories.dm index e8375760184..00864056c0f 100644 --- a/maps/torch/loadout/loadout_accessories.dm +++ b/maps/torch/loadout/loadout_accessories.dm @@ -102,7 +102,7 @@ /datum/gear/accessory/armband_corpsman display_name = "medical armband" path = /obj/item/clothing/accessory/armband/medblue - allowed_roles = list(/datum/job/cmo, /datum/job/senior_doctor, /datum/job/doctor, /datum/job/medical_trainee) + allowed_roles = list(/datum/job/cmo, /datum/job/senior_doctor, /datum/job/doctor/virologist, /datum/job/doctor, /datum/job/medical_trainee) /datum/gear/accessory/armband_engineering allowed_roles = ENGINEERING_ROLES diff --git a/maps/torch/loadout/loadout_suit.dm b/maps/torch/loadout/loadout_suit.dm index 26864672d92..fdb7c494ead 100644 --- a/maps/torch/loadout/loadout_suit.dm +++ b/maps/torch/loadout/loadout_suit.dm @@ -15,7 +15,7 @@ allowed_roles = list(/datum/job/merchant, /datum/job/hos, /datum/job/warden, /datum/job/detective, /datum/job/officer, /datum/job/seccadet) /datum/gear/suit/medical_poncho - allowed_roles = list(/datum/job/senior_doctor, /datum/job/doctor, /datum/job/psychiatrist, /datum/job/merchant, /datum/job/chemist) + allowed_roles = list(/datum/job/senior_doctor, /datum/job/doctor/virologist, /datum/job/doctor, /datum/job/psychiatrist, /datum/job/merchant, /datum/job/chemist) /datum/gear/suit/engineering_poncho allowed_roles = list(/datum/job/engineer, /datum/job/roboticist, /datum/job/merchant) diff --git a/maps/torch/structures/closets/medical.dm b/maps/torch/structures/closets/medical.dm index d4305349200..cfd4ef28730 100644 --- a/maps/torch/structures/closets/medical.dm +++ b/maps/torch/structures/closets/medical.dm @@ -60,6 +60,33 @@ new /datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack/dufflebag/med, /obj/item/weapon/storage/backpack/messenger/med)), RANDOM_SCRUBS ) +/obj/structure/closet/secure_closet/medical_viro + name = "virologist's locker" + req_access = list(access_virology) + closet_appearance = /decl/closet_appearance/secure_closet/torch/medical/physician + +/obj/structure/closet/secure_closet/medical_viro/WillContain() + return list( + /obj/item/clothing/under/sterile, + /obj/item/clothing/suit/storage/toggle/labcoat/virologist, + /obj/item/clothing/shoes/white, + /obj/item/device/radio/headset/headset_med, + /obj/item/device/radio/headset/headset_med/alt, + /obj/item/taperoll/medical, + /obj/item/weapon/storage/belt/medical/full, + /obj/item/clothing/mask/surgical, + /obj/item/device/scanner/health, + /obj/item/clothing/accessory/stethoscope, + /obj/item/device/flashlight/pen, + /obj/item/clothing/glasses/hud/health, + /obj/item/device/flash, + /obj/item/device/megaphone, + /obj/item/weapon/storage/firstaid/adv, + /obj/item/weapon/material/knife/folding/swiss, + new /datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack/medic, /obj/item/weapon/storage/backpack/satchel/med)), + new /datum/atom_creator/weighted(list(/obj/item/weapon/storage/backpack/dufflebag/med, /obj/item/weapon/storage/backpack/messenger/med)), + RANDOM_SCRUBS = 2 + ) /obj/structure/closet/secure_closet/medical_torchsenior name = "physician's locker" diff --git a/maps/torch/torch4_deck2.dmm b/maps/torch/torch4_deck2.dmm index b0f086486da..d4845ea1366 100644 --- a/maps/torch/torch4_deck2.dmm +++ b/maps/torch/torch4_deck2.dmm @@ -1635,9 +1635,10 @@ /turf/simulated/floor/tiled/monotile, /area/engineering/locker_room) "da" = ( -/obj/effect/floor_decal/techfloor{ - dir = 8 - }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/table/rack, +/obj/random/firstaid, +/obj/random/firstaid, /turf/simulated/floor/tiled/techfloor/grid, /area/medical/storage) "db" = ( @@ -1654,6 +1655,9 @@ dir = 9 }, /obj/effect/floor_decal/techfloor/corner, +/obj/effect/floor_decal/techfloor/corner{ + dir = 8 + }, /turf/simulated/floor/tiled/techfloor, /area/medical/storage) "dc" = ( @@ -6945,10 +6949,8 @@ /turf/simulated/wall/r_wall/prepainted, /area/hallway/primary/seconddeck/elevator) "nb" = ( -/obj/structure/table/rack, /obj/effect/floor_decal/industrial/outline/yellow, -/obj/random/firstaid, -/obj/random/firstaid, +/obj/structure/closet/l3closet/virology, /turf/simulated/floor/tiled/techfloor/grid, /area/medical/storage) "nc" = ( @@ -8009,15 +8011,13 @@ dir = 8; icon_state = "corner_techfloor_grid" }, -/obj/effect/floor_decal/techfloor/corner{ - dir = 8 - }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, +/obj/effect/floor_decal/techfloor, /turf/simulated/floor/tiled/techfloor, /area/medical/storage) "pi" = ( @@ -10869,10 +10869,10 @@ /turf/simulated/floor/tiled/techfloor, /area/engineering/bluespace/containment) "up" = ( -/obj/effect/floor_decal/techfloor/corner{ +/obj/effect/floor_decal/techfloor, +/obj/effect/floor_decal/techfloor{ dir = 1 }, -/obj/effect/floor_decal/techfloor, /turf/simulated/floor/tiled/techfloor/grid, /area/medical/storage) "uq" = ( @@ -11010,6 +11010,9 @@ /obj/machinery/light/small{ dir = 4 }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 1 + }, /turf/simulated/floor/tiled/techfloor/grid, /area/medical/storage) "uC" = ( @@ -18138,6 +18141,9 @@ /obj/effect/floor_decal/techfloor{ dir = 4 }, +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, /turf/simulated/floor/tiled/techfloor/grid, /area/medical/storage) "PE" = ( diff --git a/maps/torch/torch5_deck1.dmm b/maps/torch/torch5_deck1.dmm index bc29ad5d3e7..e602ca46c83 100644 --- a/maps/torch/torch5_deck1.dmm +++ b/maps/torch/torch5_deck1.dmm @@ -3,8 +3,13 @@ /turf/space, /area/space) "aac" = ( -/obj/structure/inflatable, -/turf/simulated/floor/plating, +/obj/machinery/washing_machine, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "aad" = ( /obj/structure/disposalpipe/segment, @@ -177,14 +182,16 @@ /turf/simulated/floor/tiled/dark, /area/command/armoury) "aav" = ( -/obj/effect/decal/cleanable/dirt, -/obj/random/junk, -/turf/simulated/floor/plating, +/obj/machinery/disease2/isolator, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "aaw" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/smartfridge/secure/virology, -/turf/simulated/floor/plating, +/obj/machinery/computer/centrifuge, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "aay" = ( /obj/effect/floor_decal/corner_techfloor_grid{ @@ -230,14 +237,13 @@ /turf/space, /area/space) "aaH" = ( -/obj/effect/decal/cleanable/dirt, -/obj/random/junk, -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 }, -/turf/simulated/floor/plating, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/simulated/floor/tiled/white, /area/medical/virology) "aaI" = ( /obj/structure/table/steel, @@ -838,8 +844,24 @@ /turf/simulated/floor/tiled/freezer, /area/crew_quarters/head/aux) "abT" = ( -/obj/random/junk, -/turf/simulated/floor/plating, +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/obj/machinery/embedded_controller/radio/airlock/access_controller{ + id_tag = "virology_airlock_control"; + name = "Virology Access Console"; + pixel_x = -24; + pixel_y = -24; + req_access = list("ACCESS_VIRO"); + tag_exterior_door = "virology_airlock_exterior"; + tag_interior_door = "virology_airlock_interior" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/simulated/floor/tiled/white, /area/medical/virology) "abU" = ( /obj/structure/lattice, @@ -1191,29 +1213,51 @@ /turf/simulated/floor/tiled/monotile, /area/rnd/development) "acI" = ( -/obj/machinery/door/firedoor, -/obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, -/area/medical/virology) -"acJ" = ( -/obj/effect/decal/cleanable/filth, /obj/structure/cable/green{ - d1 = 4; + d2 = 2; + icon_state = "0-2" + }, +/obj/structure/cable/green{ + d1 = 2; d2 = 8; - icon_state = "4-8" + icon_state = "2-8" }, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/simulated/floor/tiled/white, +/area/medical/virology) +"acJ" = ( +/obj/structure/table/glass, +/obj/effect/floor_decal/corner/paleblue/mono, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "acL" = ( /turf/simulated/wall/prepainted, /area/maintenance/firstdeck/aftstarboard) "acM" = ( -/turf/simulated/wall/r_wall/prepainted, -/area/maintenance/firstdeck/centralstarboard) +/obj/machinery/disease2/incubator, +/obj/item/weapon/storage/secure/safe{ + pixel_x = 5; + pixel_y = 29 + }, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, +/area/medical/virology) "acN" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/table, -/turf/simulated/floor/plating, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/item/device/radio/intercom{ + dir = 1; + pixel_y = -28 + }, +/turf/simulated/floor/tiled/white, /area/medical/virology) "acO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1538,9 +1582,15 @@ /turf/simulated/floor/tiled, /area/hallway/primary/firstdeck/center) "ads" = ( -/obj/effect/decal/cleanable/cobweb, -/turf/simulated/wall/r_wall/prepainted, -/area/maintenance/firstdeck/aftstarboard) +/obj/structure/reagent_dispensers/virusfood{ + density = 0; + pixel_y = 32 + }, +/obj/machinery/disease2/antibodyanalyser, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, +/area/medical/virology) "adt" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -2735,9 +2785,15 @@ /turf/simulated/floor/tiled/techfloor, /area/crew_quarters/safe_room/firstdeck) "afD" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/bed/padded, -/turf/simulated/floor/plating, +/obj/structure/cable/green{ + d2 = 4; + icon_state = "0-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/simulated/floor/tiled/white, /area/medical/virology) "afE" = ( /obj/machinery/hologram/holopad, @@ -2984,6 +3040,10 @@ d2 = 2; icon_state = "1-2" }, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, /turf/simulated/floor/tiled/white, /area/medical/sleeper) "agc" = ( @@ -4337,22 +4397,35 @@ /turf/simulated/floor/tiled, /area/security/wing) "aik" = ( -/obj/structure/catwalk, -/obj/effect/decal/cleanable/dirt, -/obj/structure/barricade, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/simulated/floor/tiled/white, /area/medical/virology/access) "ail" = ( -/obj/structure/catwalk, -/obj/effect/decal/cleanable/dirt, -/obj/random/junk, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, /obj/structure/cable/green{ d1 = 1; d2 = 2; icon_state = "1-2" }, -/obj/structure/barricade, -/turf/simulated/floor/plating, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/simulated/floor/tiled/white, /area/medical/virology/access) "aim" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -4400,17 +4473,38 @@ /obj/effect/floor_decal/corner/paleblue{ dir = 6 }, +/obj/machinery/embedded_controller/radio/airlock/access_controller{ + id_tag = "virology_airlock_control"; + name = "Virology Access Console"; + pixel_x = -24; + pixel_y = 22; + req_access = list("ACCESS_VIRO"); + tag_exterior_door = "virology_airlock_exterior"; + tag_interior_door = "virology_airlock_interior" + }, /turf/simulated/floor/tiled/white, /area/medical/sleeper) "aiq" = ( -/obj/structure/catwalk, -/obj/effect/decal/cleanable/dirt, +/obj/structure/cable/green{ + d1 = 2; + d2 = 4; + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, /obj/structure/cable/green{ d1 = 1; d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/simulated/floor/tiled/white, /area/medical/virology/access) "air" = ( /obj/structure/hygiene/sink{ @@ -4434,23 +4528,32 @@ /area/security/wing) "ais" = ( /obj/machinery/door/firedoor, +/obj/machinery/door/airlock/virology{ + frequency = 1379; + id_tag = "virology_airlock_exterior"; + locked = 1; + name = "Virology External Airlock" + }, /obj/effect/floor_decal/industrial/hatch/yellow, -/obj/structure/barricade, -/obj/structure/door_assembly, /turf/simulated/floor/tiled/white/monotile, /area/medical/virology/access) "ait" = ( /obj/machinery/door/firedoor, -/obj/effect/floor_decal/industrial/hatch/yellow, -/obj/machinery/door/airlock/medical{ - name = "Decomissioned Virology" - }, /obj/structure/cable/green{ d1 = 1; d2 = 2; icon_state = "1-2" }, -/obj/structure/barricade, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/airlock/virology{ + frequency = 1379; + id_tag = "virology_airlock_exterior"; + locked = 1; + name = "Virology External Airlock" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, /turf/simulated/floor/tiled/white/monotile, /area/medical/virology/access) "aiu" = ( @@ -4462,12 +4565,8 @@ d2 = 8; icon_state = "4-8" }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/effect/floor_decal/corner/paleblue{ dir = 9 }, @@ -4481,6 +4580,7 @@ d2 = 8; icon_state = "1-8" }, +/obj/structure/disposalpipe/segment, /turf/simulated/floor/tiled/white, /area/medical/sleeper) "aiy" = ( @@ -4933,9 +5033,19 @@ /turf/simulated/floor/tiled, /area/security/wing) "ajz" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/door/airlock/virology, -/turf/simulated/floor/plating, +/obj/structure/cable/green{ + d1 = 1; + d2 = 2; + icon_state = "1-2" + }, +/obj/machinery/door/window/southright{ + dir = 8; + name = "Virology Isolation Room One" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/turf/simulated/floor/tiled/white, /area/medical/virology) "ajC" = ( /obj/effect/floor_decal/floordetail/edgedrain{ @@ -5033,13 +5143,15 @@ /turf/simulated/floor/airless, /area/thruster/d1starboard) "ajN" = ( -/obj/structure/inflatable, +/obj/structure/closet/secure_closet/virology, /obj/structure/cable/green{ d1 = 1; d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "ajO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -5226,17 +5338,29 @@ /turf/simulated/floor/plating, /area/shuttle/escape_pod7/station) "akc" = ( +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, /obj/structure/cable/green{ d1 = 1; - d2 = 2; - icon_state = "1-2" + d2 = 8; + icon_state = "1-8" }, -/turf/simulated/floor/plating, +/obj/effect/floor_decal/corner/paleblue{ + dir = 8 + }, +/turf/simulated/floor/tiled/white, /area/medical/virology) "akd" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/closet/wardrobe/virology_white, -/turf/simulated/floor/plating, +/obj/structure/bed/padded, +/obj/item/weapon/bedsheet, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/paleblue/mono, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "ake" = ( /obj/machinery/power/breakerbox/activated{ @@ -5458,25 +5582,48 @@ /turf/simulated/floor/tiled, /area/security/brig/perma) "akv" = ( -/obj/machinery/requests_console{ - announcementConsole = 1; - department = "Medbay"; - departmentType = 1; - name = "Medbay RC"; - pixel_x = -31 +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/virology{ + frequency = 1379; + id_tag = "virology_airlock_interior"; + locked = 1; + name = "Virology Internal Airlock" }, -/obj/structure/door_assembly, -/obj/structure/firedoor_assembly, -/turf/simulated/floor/plating, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/blast/regular{ + density = 0; + dir = 1; + icon_state = "pdoor0"; + id_tag = "virologyquar"; + name = "Virology Emergency Quarantine Blast Doors"; + opacity = 0 + }, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology/access) "aky" = ( -/obj/effect/decal/cleanable/dirt, +/obj/machinery/smartfridge/secure/virology{ + req_access = list(list("ACCESS_VIRO","ACCESS_SURGERY")) + }, +/obj/machinery/requests_console{ + department = "Virology"; + name = "Virology Requests Console"; + pixel_x = -32 + }, /obj/structure/cable/green{ d1 = 1; d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for shutters."; + id_tag = "viro2_shutters"; + name = "Virology Window Shutters"; + pixel_x = -22; + pixel_y = 24 + }, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "akz" = ( /obj/machinery/washing_machine, @@ -5485,16 +5632,6 @@ }, /turf/simulated/floor/tiled, /area/security/brig/perma) -"akA" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/table, -/obj/structure/cable/green{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/turf/simulated/floor/plating, -/area/medical/virology) "akC" = ( /turf/simulated/wall/prepainted, /area/security/brig/psionic) @@ -5603,12 +5740,11 @@ /turf/simulated/floor/tiled/techfloor/grid, /area/crew_quarters/safe_room/firstdeck) "akO" = ( -/obj/structure/cable/green{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/turf/simulated/floor/plating, +/obj/structure/closet/secure_closet/personal/patient, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "akQ" = ( /obj/structure/cable/green{ @@ -5637,22 +5773,9 @@ }, /turf/simulated/floor/plating, /area/security/wing) -"akR" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/plating, -/area/medical/virology) "akS" = ( -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/simulated/floor/tiled/white, /area/medical/virology) "akU" = ( /obj/machinery/door/airlock/civilian{ @@ -5724,9 +5847,21 @@ /turf/simulated/floor/tiled, /area/security/brig/perma) "alb" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/plating, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/landmark{ + name = "xeno_spawn"; + pixel_x = -1 + }, +/obj/item/device/radio/intercom{ + dir = 1; + pixel_y = -28 + }, +/turf/simulated/floor/tiled/white, /area/medical/virology) "alc" = ( /obj/structure/table/reinforced, @@ -5754,24 +5889,18 @@ /turf/simulated/floor/tiled, /area/security/brig/perma) "alf" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/filth, -/obj/structure/cable/green{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, /obj/structure/cable/green{ - d1 = 2; - d2 = 8; - icon_state = "2-8" + d1 = 1; + d2 = 2; + icon_state = "1-2" }, -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 }, -/turf/simulated/floor/plating, +/turf/simulated/floor/tiled/white, /area/medical/virology) "alh" = ( /obj/structure/cable{ @@ -5895,18 +6024,43 @@ /turf/simulated/floor/plating, /area/maintenance/firstdeck/centralstarboard) "als" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, /obj/structure/cable/green{ d1 = 1; d2 = 2; icon_state = "1-2" }, -/obj/structure/door_assembly, -/obj/structure/firedoor_assembly, -/turf/simulated/floor/plating, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/virology{ + frequency = 1379; + id_tag = "virology_airlock_interior"; + locked = 1; + name = "Virology Internal Airlock" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/blast/regular{ + density = 0; + dir = 1; + icon_state = "pdoor0"; + id_tag = "virologyquar"; + name = "Virology Emergency Quarantine Blast Doors"; + opacity = 0 + }, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology/access) "alu" = ( -/obj/effect/decal/cleanable/filth, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/simulated/floor/tiled/white, /area/medical/virology) "alw" = ( /obj/structure/table/reinforced, @@ -7213,6 +7367,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 9 }, +/obj/structure/disposalpipe/segment, /turf/simulated/floor/tiled/white, /area/medical/sleeper) "anN" = ( @@ -10266,8 +10421,20 @@ /turf/simulated/floor/tiled, /area/security/wing) "asZ" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/wall/r_wall/hull, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Virology - Fore" + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -23; + pixel_y = 0 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/simulated/floor/tiled/white, /area/medical/virology) "ata" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, @@ -10292,7 +10459,19 @@ /turf/simulated/floor/tiled, /area/security/wing) "atb" = ( -/turf/simulated/floor/plating, +/obj/machinery/firealarm{ + dir = 2; + pixel_y = 24 + }, +/obj/structure/closet/crate/freezer, +/obj/item/weapon/virusdish/random, +/obj/item/weapon/virusdish/random, +/obj/item/weapon/virusdish/random, +/obj/item/weapon/virusdish/random, +/obj/item/weapon/virusdish/random, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "atc" = ( /obj/structure/cable/green{ @@ -13233,6 +13412,7 @@ dir = 4; pixel_x = 24 }, +/obj/structure/disposalpipe/segment, /turf/simulated/floor/tiled/white, /area/medical/sleeper) "aDE" = ( @@ -13596,6 +13776,7 @@ dir = 4; icon_state = "tube1" }, +/obj/structure/disposalpipe/segment, /turf/simulated/floor/tiled/white, /area/medical/sleeper) "aFB" = ( @@ -13782,6 +13963,17 @@ /obj/effect/wallframe_spawn/reinforced/no_grille, /turf/simulated/floor/plating, /area/rnd/development) +"aGF" = ( +/obj/structure/cable/green{ + d2 = 8; + icon_state = "0-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "aGG" = ( /turf/simulated/wall/prepainted, /area/rnd/breakroom) @@ -14199,6 +14391,22 @@ }, /turf/simulated/floor/tiled/dark, /area/medical/morgue) +"aKy" = ( +/obj/structure/cable/green{ + d2 = 2; + icon_state = "0-2" + }, +/obj/structure/cable/green{ + d1 = 2; + d2 = 4; + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "aKz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 @@ -15363,11 +15571,18 @@ /turf/simulated/floor/plating, /area/maintenance/firstdeck/centralport) "aSF" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/table/standard, -/obj/item/clothing/suit/bio_suit/virology, -/obj/effect/decal/cleanable/filth, -/turf/simulated/floor/plating, +/obj/structure/table/glass, +/obj/item/weapon/paper_bin{ + pixel_x = 1; + pixel_y = 8 + }, +/obj/item/weapon/reagent_containers/spray/cleaner, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "aSK" = ( /turf/simulated/wall/r_wall/prepainted, @@ -16877,6 +17092,7 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, +/obj/structure/disposalpipe/segment, /turf/simulated/floor/tiled/white, /area/medical/sleeper) "bex" = ( @@ -17043,6 +17259,10 @@ dir = 6 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, /turf/simulated/floor/tiled/white, /area/medical/sleeper) "bpt" = ( @@ -17355,15 +17575,32 @@ /turf/simulated/floor/reinforced, /area/rnd/xenobiology) "bCf" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/filth, -/obj/structure/barricade, +/obj/structure/cable/green{ + d1 = 2; + d2 = 4; + icon_state = "2-4" + }, +/obj/structure/cable/green{ + d1 = 2; + d2 = 8; + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, /obj/structure/cable/green{ d1 = 1; d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/obj/machinery/light_switch{ + pixel_x = 24; + pixel_y = -21 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/turf/simulated/floor/tiled/white, /area/medical/virology) "bCX" = ( /obj/structure/table/steel, @@ -17387,7 +17624,8 @@ /turf/simulated/floor/reinforced, /area/rnd/xenobiology) "bDc" = ( -/turf/simulated/wall/r_wall/prepainted, +/obj/structure/sign/warning/biohazard, +/turf/simulated/wall/r_wall/hull, /area/medical/virology/access) "bDK" = ( /turf/simulated/wall/r_wall/hull, @@ -17481,6 +17719,7 @@ /obj/machinery/door/airlock/medical{ name = "Emergency Treatment Center" }, +/obj/structure/disposalpipe/segment, /turf/simulated/floor/tiled/white/monotile, /area/medical/sleeper) "bGD" = ( @@ -17824,9 +18063,9 @@ /turf/simulated/floor/tiled/white/monotile, /area/medical/sleeper) "bSY" = ( -/obj/machinery/status_display, +/obj/structure/sign/warning/deathsposal, /turf/simulated/wall/r_wall/hull, -/area/maintenance/firstdeck/aftstarboard) +/area/medical/virology) "bTb" = ( /obj/item/device/radio/intercom{ dir = 4; @@ -17856,6 +18095,9 @@ pixel_x = 2; pixel_y = -34 }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /turf/simulated/floor/tiled/white, /area/medical/sleeper) "bUe" = ( @@ -17940,6 +18182,11 @@ /obj/effect/shuttle_landmark/escape_pod/start/pod10, /turf/simulated/floor/plating, /area/shuttle/escape_pod10/station) +"bWf" = ( +/obj/structure/cable/green, +/obj/effect/wallframe_spawn/reinforced, +/turf/simulated/floor/plating, +/area/medical/virology) "bWw" = ( /obj/machinery/power/apc{ dir = 4; @@ -18066,6 +18313,21 @@ }, /turf/simulated/floor/tiled/white, /area/medical/infirmreception) +"ccM" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "cdD" = ( /obj/effect/wallframe_spawn/reinforced/polarized/no_grille/regular{ id = "medbaylockers" @@ -18204,6 +18466,12 @@ }, /turf/simulated/floor/tiled, /area/hallway/primary/firstdeck/fore) +"cjy" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/simulated/wall/r_wall/hull, +/area/medical/virology) "cjG" = ( /obj/structure/disposalpipe/segment, /turf/simulated/wall/prepainted, @@ -18874,13 +19142,13 @@ /turf/simulated/floor/tiled/white, /area/medical/locker) "cVb" = ( -/obj/random/junk, -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 }, -/turf/simulated/floor/plating, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/turf/simulated/floor/tiled/white, /area/medical/virology) "cVP" = ( /obj/structure/disposalpipe/segment{ @@ -19100,6 +19368,7 @@ pixel_x = 6; pixel_y = -20 }, +/obj/structure/disposalpipe/segment, /turf/simulated/floor/tiled/white, /area/medical/infirmreception) "dci" = ( @@ -19607,6 +19876,7 @@ /obj/effect/floor_decal/corner/paleblue{ dir = 1 }, +/obj/structure/disposalpipe/segment, /turf/simulated/floor/tiled, /area/hallway/primary/firstdeck/aft) "dPA" = ( @@ -20173,10 +20443,17 @@ /turf/simulated/floor/tiled/monotile, /area/teleporter/firstdeck) "fac" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/table/standard, -/obj/item/weapon/zipgunframe, -/turf/simulated/floor/plating, +/obj/structure/table/glass, +/obj/item/weapon/storage/fancy/vials, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "fcb" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ @@ -20207,6 +20484,16 @@ }, /turf/simulated/floor/tiled/white, /area/medical/sleeper) +"fdr" = ( +/obj/structure/closet/secure_closet/personal/patient, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, +/area/medical/virology) "fdQ" = ( /obj/structure/skele_stand, /turf/simulated/floor/tiled/techfloor, @@ -20400,6 +20687,10 @@ /obj/effect/floor_decal/corner/paleblue{ dir = 4 }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, /turf/simulated/floor/tiled/white, /area/medical/sleeper) "fub" = ( @@ -20420,6 +20711,10 @@ name = "Infirmary Entry Lockdown Shutters"; opacity = 0 }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, /turf/simulated/floor/tiled/white/monotile, /area/medical/sleeper) "fuV" = ( @@ -20434,6 +20729,24 @@ "fvw" = ( /turf/simulated/wall/prepainted, /area/medical/triage) +"fya" = ( +/obj/structure/cable/green, +/obj/structure/cable/green{ + d1 = 1; + d2 = 8; + icon_state = "1-8" + }, +/obj/structure/cable/green{ + d1 = 2; + d2 = 8; + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "fyf" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ dir = 4 @@ -20613,6 +20926,13 @@ }, /turf/simulated/floor/tiled/white, /area/medical/triage) +"fQQ" = ( +/obj/machinery/hologram/holopad, +/obj/effect/floor_decal/corner/paleblue/three_quarters{ + dir = 1 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "fRN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/disposalpipe/segment, @@ -20939,6 +21259,24 @@ }, /turf/simulated/floor/tiled/white, /area/medical/sleeper) +"gub" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/obj/structure/hygiene/sink{ + dir = 4; + icon_state = "sink"; + pixel_x = 11; + pixel_y = 0 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "guP" = ( /obj/structure/filingcabinet/chestdrawer, /obj/effect/floor_decal/corner/paleblue{ @@ -21037,6 +21375,18 @@ }, /turf/simulated/floor/tiled, /area/hallway/primary/firstdeck/aft) +"gAV" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "gBb" = ( /obj/effect/floor_decal/corner/paleblue{ dir = 9 @@ -21110,6 +21460,7 @@ /obj/effect/floor_decal/corner/paleblue/three_quarters{ dir = 1 }, +/obj/structure/disposalpipe/segment, /turf/simulated/floor/tiled/white, /area/medical/sleeper) "gQb" = ( @@ -21247,6 +21598,13 @@ }, /turf/simulated/floor/plating, /area/hallway/primary/firstdeck/center) +"hes" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/structure/disposalpipe/segment, +/turf/simulated/floor/tiled/white, +/area/medical/sleeper) "hgb" = ( /obj/structure/cable/green{ d1 = 4; @@ -21773,13 +22131,29 @@ /turf/simulated/floor/tiled/white, /area/medical/sleeper) "hEK" = ( +/obj/structure/hygiene/shower{ + dir = 4; + icon_state = "shower" + }, +/obj/machinery/embedded_controller/radio/airlock/access_controller{ + id_tag = "virology_airlock_control"; + name = "Virology Access Console"; + pixel_x = 8; + pixel_y = 24; + req_access = list("ACCESS_VIRO"); + tag_exterior_door = "virology_airlock_exterior"; + tag_interior_door = "virology_airlock_interior" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, /obj/machinery/alarm{ - alarm_id = "xenobio2_alarm"; dir = 4; - pixel_x = -24 + icon_state = "alarm0"; + pixel_x = -22; + pixel_y = 0 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/turf/simulated/floor/tiled/white, /area/medical/virology/access) "hFb" = ( /obj/structure/disposalpipe/segment, @@ -22003,6 +22377,13 @@ /obj/machinery/ai_status_display, /turf/simulated/wall/r_wall/prepainted, /area/hallway/primary/firstdeck/center) +"hWW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/paleblue{ + dir = 4 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "hYb" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ dir = 4 @@ -22252,10 +22633,27 @@ /turf/simulated/floor/tiled/white, /area/medical/washroom) "iop" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/filth, -/obj/structure/table, -/turf/simulated/floor/plating, +/obj/structure/table/glass, +/obj/item/weapon/storage/box/gloves{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/weapon/storage/box/masks, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + d1 = 1; + d2 = 2; + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "iqb" = ( /obj/structure/bed/chair/office/light, @@ -22443,10 +22841,19 @@ /turf/simulated/wall/prepainted, /area/medical/reslab) "iAd" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/table/standard, -/obj/item/clothing/head/bio_hood/virology, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/table/glass, +/obj/item/weapon/storage/box/syringes{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/weapon/storage/box/beakers, +/obj/item/weapon/reagent_containers/dropper, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "iAS" = ( /obj/structure/table/rack, @@ -22633,6 +23040,7 @@ d2 = 8; icon_state = "2-8" }, +/obj/structure/disposalpipe/segment, /turf/simulated/floor/tiled/white, /area/medical/sleeper) "iSb" = ( @@ -22722,6 +23130,23 @@ "jbE" = ( /turf/simulated/wall/r_wall/hull, /area/medical/virology) +"jbL" = ( +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/obj/machinery/door/window/southright{ + name = "Virology Isolation Room Three" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "jbR" = ( /obj/machinery/atmospherics/unary/vent_pump{ dir = 8; @@ -22845,7 +23270,8 @@ /area/thruster/d1starboard) "jib" = ( /obj/machinery/porta_turret/exterior/dagon, -/turf/simulated/floor/airless, +/obj/structure/lattice, +/turf/space, /area/space) "jiq" = ( /obj/structure/railing/mapped, @@ -23047,6 +23473,21 @@ }, /turf/simulated/floor/tiled/white, /area/rnd/locker) +"jus" = ( +/obj/structure/cable/green{ + d1 = 1; + d2 = 2; + icon_state = "1-2" + }, +/obj/machinery/door/window/southright{ + dir = 4; + name = "Animal Pen" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "jvb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -23699,6 +24140,9 @@ /obj/machinery/door/firedoor, /turf/simulated/floor/tiled/techfloor/grid, /area/command/armoury/tactical) +"ktq" = ( +/turf/simulated/floor/tiled/white, +/area/medical/virology) "kub" = ( /obj/effect/floor_decal/corner_techfloor_grid{ dir = 1 @@ -23828,6 +24272,24 @@ /obj/effect/wallframe_spawn/reinforced/no_grille, /turf/simulated/floor/plating, /area/assembly/chargebay) +"kEF" = ( +/obj/structure/cable/green, +/obj/structure/cable/green{ + d1 = 1; + d2 = 4; + icon_state = "1-4" + }, +/obj/structure/cable/green{ + d1 = 2; + d2 = 4; + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "kHb" = ( /obj/machinery/door/airlock/engineering{ autoset_access = 0; @@ -23841,8 +24303,22 @@ /turf/simulated/floor/tiled/steel_ridged, /area/assembly/robotics) "kIu" = ( -/obj/structure/table/standard, -/turf/simulated/floor/plating, +/obj/structure/table/glass, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/item/weapon/reagent_containers/syringe/antiviral, +/obj/item/weapon/reagent_containers/syringe/antiviral, +/obj/item/weapon/reagent_containers/syringe/antiviral, +/obj/item/weapon/reagent_containers/syringe/antiviral, +/obj/item/weapon/storage/lockbox/vials, +/obj/item/device/antibody_scanner, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "kLb" = ( /obj/effect/floor_decal/corner/paleblue{ @@ -24704,6 +25180,7 @@ d2 = 8; icon_state = "4-8" }, +/obj/structure/disposalpipe/segment, /turf/simulated/floor/tiled/white, /area/medical/sleeper) "lYS" = ( @@ -24811,14 +25288,14 @@ /turf/simulated/floor/plating, /area/security/storage) "mfH" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/filth, +/obj/structure/cable/green, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" + d1 = 1; + d2 = 2; + icon_state = "1-2" }, -/turf/simulated/floor/plating, +/obj/effect/wallframe_spawn/reinforced, +/turf/simulated/floor/tiled/white, /area/medical/virology) "mgb" = ( /obj/structure/table/steel, @@ -25128,6 +25605,31 @@ }, /turf/simulated/floor/tiled/white/monotile, /area/medical/chemistry) +"mxx" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + d1 = 2; + d2 = 4; + icon_state = "2-4" + }, +/obj/structure/cable/green{ + d1 = 2; + d2 = 8; + icon_state = "2-8" + }, +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "myb" = ( /obj/effect/floor_decal/corner/paleblue{ dir = 9 @@ -25250,8 +25752,13 @@ /turf/simulated/floor/tiled/techfloor/grid, /area/command/armoury) "mJY" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/computer/diseasesplicer, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "mKb" = ( /obj/machinery/light_switch{ @@ -25443,6 +25950,14 @@ /obj/structure/disposalpipe/segment, /turf/simulated/floor/tiled/steel_grid, /area/hallway/primary/firstdeck/fore) +"ncs" = ( +/obj/structure/table/glass, +/obj/item/modular_computer/laptop/preset/records, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, +/area/medical/virology) "ncI" = ( /obj/effect/floor_decal/industrial/outline/grey, /turf/simulated/floor/tiled/techfloor, @@ -25577,6 +26092,14 @@ }, /turf/simulated/floor/tiled, /area/hallway/primary/firstdeck/fore) +"njY" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/turf/simulated/floor/tiled/white, +/area/medical/sleeper) "nkb" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/glass/security{ @@ -25729,6 +26252,7 @@ "nyk" = ( /obj/effect/wallframe_spawn/reinforced/no_grille, /obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, /turf/simulated/floor/plating, /area/medical/infirmreception) "nys" = ( @@ -26069,6 +26593,23 @@ }, /turf/simulated/floor/plating, /area/hallway/primary/firstdeck/fore) +"nWe" = ( +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/obj/machinery/door/window/southright{ + name = "Virology Isolation Room Two" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "nWl" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 @@ -26279,8 +26820,30 @@ }, /turf/simulated/floor/tiled/white, /area/rnd/research) +"oeo" = ( +/obj/structure/bed/padded, +/obj/item/weapon/bedsheet, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue/mono, +/turf/simulated/floor/tiled/white/monotile, +/area/medical/virology) +"oeT" = ( +/obj/effect/landmark{ + name = "lightsout" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "ofb" = ( /obj/effect/floor_decal/industrial/outline/blue, +/obj/structure/disposalpipe/segment, /turf/simulated/floor/tiled/white, /area/medical/infirmreception) "ogb" = ( @@ -26712,6 +27275,22 @@ }, /turf/simulated/floor/tiled/white, /area/rnd/locker) +"oTa" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/obj/structure/cable/green{ + d2 = 4; + icon_state = "0-4" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "oTb" = ( /obj/structure/cable/green{ d1 = 4; @@ -26881,6 +27460,13 @@ }, /turf/simulated/floor/tiled/white, /area/rnd/research) +"peA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/paleblue{ + dir = 1 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "pfb" = ( /obj/machinery/door/firedoor, /obj/structure/cable/green{ @@ -26982,14 +27568,16 @@ /turf/simulated/floor/tiled/dark, /area/medical/reslab) "plV" = ( -/obj/machinery/door/firedoor, -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - dir = 4; - id_tag = "viroblast"; - name = "Virology Blast Door" +/obj/structure/disposalpipe/segment{ + dir = 4 }, -/turf/simulated/floor/plating, +/obj/structure/cable/green{ + d1 = 1; + d2 = 4; + icon_state = "1-4" + }, +/obj/effect/floor_decal/corner/paleblue, +/turf/simulated/floor/tiled/white, /area/medical/virology) "pmb" = ( /obj/structure/cable/green{ @@ -27029,13 +27617,25 @@ /turf/simulated/floor/tiled/white, /area/rnd/locker) "psJ" = ( +/obj/effect/wallframe_spawn/reinforced/hull, /obj/machinery/door/firedoor, -/obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/blast/regular{ - id_tag = "viroblast"; - name = "Virology Blast Door" + density = 0; + dir = 1; + icon_state = "pdoor0"; + id_tag = "virologyquar"; + name = "Virology Emergency Quarantine Blast Doors"; + opacity = 0 }, -/turf/simulated/floor/plating, +/obj/machinery/door/blast/shutters{ + density = 0; + dir = 2; + icon_state = "shutter0"; + id_tag = "viro2_shutters"; + name = "Window Shutters"; + opacity = 0 + }, +/turf/simulated/floor/airless, /area/medical/virology) "ptb" = ( /obj/structure/closet/emcloset, @@ -27131,6 +27731,30 @@ /obj/structure/catwalk, /turf/simulated/floor/plating, /area/maintenance/firstdeck/aftport) +"pxh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + d1 = 1; + d2 = 2; + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/paleblue/three_quarters{ + dir = 8 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) +"pxt" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/item/device/radio/intercom{ + dir = 4; + pixel_x = -21 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "pyb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 9 @@ -27308,20 +27932,6 @@ "pIA" = ( /turf/simulated/floor/tiled, /area/hallway/primary/firstdeck/fore) -"pID" = ( -/obj/machinery/door/firedoor, -/obj/effect/wallframe_spawn/reinforced, -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/door/blast/regular{ - id_tag = "viroblast"; - name = "Virology Blast Door" - }, -/turf/simulated/floor/plating, -/area/medical/virology) "pIW" = ( /obj/structure/lattice, /obj/machinery/atmospherics/pipe/simple/visible/blue, @@ -27785,6 +28395,15 @@ }, /turf/simulated/floor/tiled/dark, /area/medical/surgery) +"qoW" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "qqb" = ( /obj/machinery/photocopier, /obj/machinery/power/apc{ @@ -28043,6 +28662,17 @@ }, /turf/simulated/floor/tiled/white, /area/rnd/xenobiology/xenoflora) +"qJy" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/obj/item/weapon/stool, +/obj/machinery/light, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "qKb" = ( /obj/machinery/atmospherics/pipe/manifold/visible{ dir = 4 @@ -28425,6 +29055,20 @@ /obj/effect/floor_decal/industrial/outline/yellow, /turf/simulated/floor/tiled/white, /area/rnd/xenobiology/xenoflora) +"rgw" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "rhb" = ( /obj/machinery/atmospherics/pipe/simple/visible, /obj/effect/floor_decal/industrial/warning{ @@ -28432,6 +29076,15 @@ }, /turf/simulated/floor/tiled/white/monotile, /area/rnd/xenobiology/xenoflora) +"rhJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "rhO" = ( /turf/simulated/floor/tiled/techfloor, /area/maintenance/firstdeck/centralstarboard) @@ -28499,9 +29152,13 @@ /turf/simulated/floor/tiled/white/monotile, /area/rnd/misc_lab) "rmC" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/constructable_frame, -/turf/simulated/floor/plating, +/obj/item/device/radio/intercom{ + pixel_y = 23 + }, +/obj/machinery/disease2/diseaseanalyser, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, /area/medical/virology) "rnb" = ( /obj/machinery/portable_atmospherics/canister, @@ -28540,6 +29197,26 @@ /obj/effect/floor_decal/corner/research/mono, /turf/simulated/floor/tiled/white/monotile, /area/rnd/misc_lab) +"roy" = ( +/obj/machinery/camera/network/medbay{ + c_tag = "Virology - Aft" + }, +/obj/structure/cable/green{ + d2 = 8; + icon_state = "0-8" + }, +/obj/machinery/power/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "roA" = ( /obj/structure/railing/mapped{ dir = 4; @@ -28560,6 +29237,17 @@ }, /turf/simulated/floor/tiled/monotile, /area/security/detectives_office) +"rqU" = ( +/obj/structure/table/glass, +/obj/item/weapon/folder/white, +/obj/item/weapon/hand_labeler, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, +/area/medical/virology) "rrV" = ( /obj/effect/floor_decal/industrial/outline/grey, /obj/machinery/power/apc{ @@ -28579,6 +29267,23 @@ }, /turf/simulated/floor/tiled/white, /area/rnd/research) +"rss" = ( +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/obj/structure/cable/green{ + d2 = 4; + icon_state = "0-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "rsu" = ( /obj/effect/floor_decal/corner/red{ dir = 8 @@ -28716,19 +29421,17 @@ /turf/simulated/floor/reinforced, /area/rnd/misc_lab) "ryc" = ( -/obj/item/device/radio/intercom/department/medbay{ - dir = 8; - pixel_x = 21 +/obj/structure/closet/wardrobe/virology_white, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 }, -/obj/machinery/camera/network/medbay{ - c_tag = "Infirmary - Virology Access"; - dir = 8 +/obj/structure/sign/warning/internals_required{ + pixel_x = 32 }, -/obj/machinery/light{ - dir = 1 +/obj/machinery/camera/network/medbay{ + c_tag = "Virology - Access" }, -/obj/random/obstruction, -/turf/simulated/floor/plating, +/turf/simulated/floor/tiled/white, /area/medical/virology/access) "rzb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -28798,6 +29501,20 @@ }, /turf/simulated/floor/tiled/white, /area/rnd/xenobiology/xenoflora) +"rDW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + d1 = 1; + d2 = 2; + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "rEb" = ( /obj/machinery/atmospherics/pipe/simple/visible/red, /obj/machinery/honey_extractor, @@ -28931,6 +29648,17 @@ }, /turf/simulated/floor/tiled/white, /area/rnd/research) +"rMN" = ( +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "rNb" = ( /obj/machinery/atmospherics/portables_connector{ dir = 1 @@ -30566,6 +31294,29 @@ "tJO" = ( /turf/simulated/floor/tiled/white, /area/security/detectives_office) +"tLF" = ( +/obj/structure/cable/green{ + d2 = 4; + icon_state = "0-4" + }, +/obj/structure/cable/green{ + d1 = 1; + d2 = 4; + icon_state = "1-4" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/simulated/floor/tiled/white, +/area/medical/virology) +"tMD" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/obj/item/device/radio/intercom{ + dir = 8; + pixel_x = 21 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "tTY" = ( /obj/structure/railing/mapped{ dir = 1 @@ -30587,12 +31338,22 @@ }, /turf/simulated/wall/r_wall/prepainted, /area/maintenance/firstdeck/aftstarboard) +"tWu" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "tWZ" = ( /obj/effect/floor_decal/techfloor{ dir = 1 }, /turf/simulated/floor/tiled/techfloor, /area/crew_quarters/safe_room/firstdeck) +"tXa" = ( +/obj/structure/disposalpipe/segment, +/turf/simulated/wall/prepainted, +/area/medical/infirmreception) "tYV" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 4 @@ -30651,6 +31412,12 @@ }, /turf/simulated/floor/tiled/steel_ridged, /area/medical/counselor) +"ujw" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "ujx" = ( /obj/machinery/light{ dir = 1 @@ -30775,9 +31542,21 @@ /turf/simulated/open, /area/maintenance/firstdeck/aftport) "uHJ" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/filth, -/turf/simulated/floor/plating, +/obj/structure/bed/chair/office/light{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/simulated/floor/tiled/white, /area/medical/virology) "uJn" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -30937,6 +31716,22 @@ /obj/machinery/light, /turf/simulated/floor/tiled/techfloor/grid, /area/command/armoury) +"vdb" = ( +/obj/structure/cable/green{ + d1 = 2; + d2 = 8; + icon_state = "2-8" + }, +/obj/structure/cable/green{ + d2 = 2; + icon_state = "0-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "veT" = ( /obj/effect/floor_decal/techfloor{ dir = 4 @@ -30989,6 +31784,19 @@ /obj/structure/catwalk, /turf/simulated/floor/plating, /area/maintenance/firstdeck/aftstarboard) +"vgz" = ( +/obj/structure/cable/green{ + d1 = 1; + d2 = 8; + icon_state = "1-8" + }, +/obj/structure/cable/green{ + d2 = 8; + icon_state = "0-8" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "vhs" = ( /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/hologram/holopad, @@ -31026,6 +31834,12 @@ }, /turf/simulated/floor/tiled/techfloor/grid, /area/command/armoury) +"vmw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "vnz" = ( /obj/effect/floor_decal/industrial/outline/grey, /obj/machinery/light, @@ -31129,6 +31943,22 @@ }, /turf/simulated/floor/tiled/white, /area/security/detectives_office) +"vEx" = ( +/obj/structure/table/glass, +/obj/item/weapon/storage/box/monkeycubes, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/item/weapon/storage/box/monkeycubes/farwacubes, +/obj/item/weapon/storage/box/monkeycubes/neaeracubes, +/obj/item/weapon/storage/box/monkeycubes/stokcubes, +/obj/effect/floor_decal/corner/paleblue/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled/white/monotile, +/area/medical/virology) "vFj" = ( /obj/structure/table/glass, /obj/item/device/scanner/reagent, @@ -31173,9 +32003,25 @@ /turf/simulated/floor/tiled, /area/security/wing) "vJX" = ( -/obj/structure/barricade, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/structure/closet/l3closet/virology, +/obj/item/clothing/mask/gas, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/obj/machinery/power/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + d2 = 8; + icon_state = "0-8" + }, +/obj/item/device/radio/intercom{ + dir = 1; + pixel_y = -28 + }, +/turf/simulated/floor/tiled/white, /area/medical/virology/access) "vMw" = ( /turf/simulated/wall/r_wall/prepainted, @@ -31184,9 +32030,14 @@ /turf/simulated/wall/r_wall/prepainted, /area/security/locker) "vMO" = ( -/obj/structure/catwalk, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/simulated/floor/tiled/white, /area/medical/virology/access) "vSe" = ( /obj/effect/floor_decal/corner/paleblue/mono, @@ -31387,11 +32238,29 @@ /turf/simulated/floor/plating, /area/hallway/primary/firstdeck/fore) "wna" = ( -/obj/structure/extinguisher_cabinet{ - pixel_x = -32 +/obj/structure/hygiene/sink{ + dir = 8; + icon_state = "sink"; + pixel_x = -12; + pixel_y = 2 }, -/obj/random/obstruction, -/turf/simulated/floor/plating, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for shutters."; + id_tag = "virologyquar"; + name = "Virology Emergency Quarantine Control"; + pixel_x = 8; + pixel_y = -24 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24; + pixel_y = 0 + }, +/obj/machinery/light, +/turf/simulated/floor/tiled/white, /area/medical/virology/access) "wro" = ( /obj/item/weapon/stool/padded, @@ -31463,18 +32332,30 @@ /turf/simulated/floor/tiled, /area/security/wing) "wyf" = ( -/obj/machinery/door/firedoor, /obj/structure/cable/green{ d1 = 1; d2 = 2; icon_state = "1-2" }, -/obj/effect/wallframe_spawn/reinforced, +/obj/effect/wallframe_spawn/reinforced/hull, +/obj/machinery/door/firedoor, /obj/machinery/door/blast/regular{ - id_tag = "viroblast"; - name = "Virology Blast Door" + density = 0; + dir = 1; + icon_state = "pdoor0"; + id_tag = "virologyquar"; + name = "Virology Emergency Quarantine Blast Doors"; + opacity = 0 }, -/turf/simulated/floor/plating, +/obj/machinery/door/blast/shutters{ + density = 0; + dir = 2; + icon_state = "shutter0"; + id_tag = "viro2_shutters"; + name = "Window Shutters"; + opacity = 0 + }, +/turf/simulated/floor/airless, /area/medical/virology) "wyA" = ( /turf/simulated/wall/prepainted, @@ -31546,6 +32427,22 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /turf/simulated/floor/tiled/dark, /area/command/armoury/access) +"wVv" = ( +/obj/structure/cable/green{ + d1 = 2; + d2 = 4; + icon_state = "2-4" + }, +/obj/structure/cable/green{ + d2 = 2; + icon_state = "0-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/simulated/floor/tiled/white, +/area/medical/virology) "wWc" = ( /obj/structure/sign/warning/secure_area{ dir = 4 @@ -50923,7 +51820,7 @@ aaa aaa aaa czU -adA +aaa aaa aaa aaa @@ -51128,9 +52025,9 @@ fSy adA jib jbE -plV jbE -plV +jbE +jbE jbE aaa aaa @@ -51330,9 +52227,9 @@ fSy adA adA jbE -atb -atb -atb +fdr +pxt +oeo jbE aaa aaa @@ -51533,7 +52430,7 @@ adA jbE jbE afD -mJY +ktq alu jbE jbE @@ -51736,8 +52633,8 @@ jbE asZ acI ajz -acI -asZ +kEF +bWf jbE jbE aaa @@ -51933,12 +52830,12 @@ aaa aaa aaa qxz -pID -aky +wyf aky +plV aaH -aky -aky +hWW +rss akO akd jbE @@ -52137,10 +53034,10 @@ aaa aaa psJ mJY -atb -mJY -mJY -atb +ccM +ncs +ujw +nWe akS alb jbE @@ -52339,16 +53236,16 @@ aaa aaa jbE rmC -mJY -aSF uHJ -alu +aSF +ujw +oTa acJ -uHJ +qJy jbE abP abP -acM +abP acC aeo ssh @@ -52540,17 +53437,17 @@ aaa aaa aaa jbE -rmC +acM uHJ iAd -uHJ -mJY -akR -aac +ujw +vdb +mfH +tLF meG hEK wna -bDc +meG ahk aeo aeo @@ -52741,13 +53638,13 @@ aaa aaa aaa aaa -jbE +psJ aav -uHJ -mJY -uHJ -mJY -akR +rgw +rqU +fQQ +rhJ +tWu abT akv aik @@ -52763,7 +53660,7 @@ gnb aaZ bnN bdW -bnN +njY anM gOb fsb @@ -52943,12 +53840,12 @@ aaa aaa aaa aaa -jbE +psJ aaw -mJY +mxx iop -uHJ -alu +pxh +rDW alf bCf als @@ -52956,9 +53853,9 @@ ail aiq ait aiv -fob +hes bGj -fob +hes lYJ aDD aFx @@ -53146,14 +54043,14 @@ aaa aaa aaa jbE -rmC -mJY +ads +rMN kIu -uHJ -uHJ +oeT +wVv mfH -mJY -meG +vgz +bDc ryc vJX bDc @@ -53176,9 +54073,9 @@ ofb ofb ofb dbH -arK +tXa dMe -hwY +hlh mpq amO ljb @@ -53349,16 +54246,16 @@ aaa aaa jbE atb -mJY +rMN fac -mJY -mJY -akR -akd +ujw +oTa +acJ +qJy jbE mpy -bSY -ads +mpy +mpy adt sfx ebt @@ -53551,10 +54448,10 @@ aaa aaa psJ aac -atb -mJY -mJY -mJY +gAV +vEx +ujw +jbL akS acN jbE @@ -53755,10 +54652,10 @@ wyf ajN akc cVb -aky -aky -akA -acN +peA +rss +akO +akd jbE aaa mpy @@ -53954,12 +54851,12 @@ aaa aaa dDC jbE -jbE -jbE -acI -ajz -acI -jbE +bSY +roy +aKy +jus +fya +bWf jbE jbE aaa @@ -54157,10 +55054,10 @@ aaa dDC adA jbE -jbE -mJY -mJY -atb +cjy +aGF +ktq +vmw jbE jbE aaa @@ -54359,10 +55256,10 @@ aaa dDC adA adA -jbE -aac -mJY -atb +cjy +qoW +tMD +gub jbE aaa aaa @@ -54561,10 +55458,10 @@ aaa dDC adA jib +cjy +jbE jbE -plV jbE -plV jbE aaa aaa @@ -54761,9 +55658,9 @@ aaa aaa aaa tdB -adA aaa aaa +aaB aaa aaa aaa diff --git a/maps/torch/torch_areas.dm b/maps/torch/torch_areas.dm index f8e1897861a..961e3de6172 100644 --- a/maps/torch/torch_areas.dm +++ b/maps/torch/torch_areas.dm @@ -1121,7 +1121,7 @@ req_access = list(access_surgery) /area/medical/virology - name = "\improper Virology (decomissioned)" + name = "\improper Virology" /area/crew_quarters/safe_room/medical name = "\improper Medical Safe Room" diff --git a/maps/torch/torch_unit_testing.dm b/maps/torch/torch_unit_testing.dm index b44d615bf87..7007def44b2 100644 --- a/maps/torch/torch_unit_testing.dm +++ b/maps/torch/torch_unit_testing.dm @@ -42,7 +42,6 @@ /area/maintenance/aux_med = NO_SCRUBBER|NO_VENT|NO_APC, /area/solar = NO_SCRUBBER|NO_VENT|NO_APC, /area/storage = NO_SCRUBBER|NO_VENT, - /area/medical/virology = NO_SCRUBBER|NO_VENT|NO_APC, /area/storage/auxillary/port = 0, /area/storage/auxillary/starboard = 0, /area/storage/primary = 0, @@ -82,8 +81,6 @@ /area/shuttle/syndicate_elite/station, /area/shuttle/escape/centcom, /area/rnd/xenobiology/xenoflora_storage, - /area/medical/virology, - /area/medical/virology/access, /area/turbolift, /area/turbolift/start, /area/turbolift/bridge, diff --git a/nano/templates/disease_splicer.tmpl b/nano/templates/disease_splicer.tmpl new file mode 100644 index 00000000000..a41ab323a4e --- /dev/null +++ b/nano/templates/disease_splicer.tmpl @@ -0,0 +1,124 @@ +
+
+ {{:helper.link('Close', 'gear', {'close' : 1}, null, 'fixedLeft')}} +
+
+ +{{if data.busy}} +
The Splicer is currently busy.
+
+
{{:data.busy}}
+
+

+ Thank you for your patience! +

+{{else}} +
+

Virus Dish

+
+
+ {{:helper.link('Eject Dish', 'eject', { 'eject' : 1 }, data.dish_inserted ? null : 'disabled')}} +
+ +
+
+ Growth Density: +
+
+ {{:helper.displayBar(data.growth, 0, 100, (data.growth >= 50) ? 'good' : data.growth >= 25 ? 'average' : 'bad', data.growth + '%' )}} +
+
+ +
+
+ {{if !data.info}} +
+ Symptoms: +
+ {{/if}} +
+ {{if data.info}} + {{:data.info}} + {{else}} + {{for data.effects}} +
+
+ ({{:value.stage}}) {{:value.name}} + {{if value.badness > 1}} + Dangerous + {{/if}} +
+
+ {{/for}} + {{/if}} +
+
+ {{if data.affected_species && !data.info}} +
+
+ Affected Species: +
+
+ {{:data.affected_species}} +
+
+ {{/if}} +
+ {{if data.effects}} +
+ CAUTION: Reverse engineering will destroy the viral sample. +
+
+
+ Reverse Engineering: +
+
+ {{for data.effects}} + {{:helper.link(value.stage, 'transferthick-e-w', { 'grab' : value.reference })}} + {{/for}} +
+
+ {{:helper.link('Species', 'transferthick-e-w', { 'affected_species' : 1 })}} +
+
+ {{/if}} + +
+

Storage

+
+ +
+
+ Memory Buffer: +
+
+ {{if data.buffer}} + {{:data.buffer.name}} ({{:data.buffer.stage}}) + {{else}} + {{if data.species_buffer}} + {{:data.species_buffer}} + {{else}} + Empty + {{/if}} + {{/if}} +
+
+ {{:helper.link('Save To Disk', 'disk', { 'disk' : 1 }, (data.buffer || data.species_buffer) ? null : 'disabled')}} + {{if data.species_buffer}} + {{:helper.link('Splice Species', 'pencil', { 'splice' : -1 }, (data.species_buffer && !data.info) ? null : 'disabled')}} + {{else data.buffer}} + {{:helper.link('Splice #1', 'pencil', { 'splice' : 1 }, data.buffer.stage > 1 ? 'disabled' : null)}} + {{:helper.link('Splice #2', 'pencil', { 'splice' : 2 }, data.buffer.stage > 2 ? 'disabled' : null)}} + {{:helper.link('Splice #3', 'pencil', { 'splice' : 3 }, data.buffer.stage > 3 ? 'disabled' : null)}} + {{:helper.link('Splice #4', 'pencil', { 'splice' : 4 }, data.buffer.stage > 4 ? 'disabled' : null)}} + {{/if}} +{{/if}} + + + + + + + + + diff --git a/nano/templates/dish_incubator.tmpl b/nano/templates/dish_incubator.tmpl new file mode 100644 index 00000000000..e1e916828a4 --- /dev/null +++ b/nano/templates/dish_incubator.tmpl @@ -0,0 +1,123 @@ +
+
+ {{:helper.link('Close', 'gear', {'close' : '1'}, null, 'fixedLeft')}} +
+
+ +
+

Environmental Conditions

+
+
+
+ Power: +
+
+ {{:helper.link('On', 'power', { 'power' : 1 }, !data.dish_inserted ? 'disabled' : data.on ? 'selected' : null)}}{{:helper.link('Off', 'close', { 'power' : 1 }, data.on ? null : 'selected')}} +
+
+
+ {{:helper.link('Add Radiation', 'radiation', {'rad' : 1})}} + {{:helper.link('Flush System', 'trash', {'flush' : 1}, data.system_in_use ? null : 'disabled')}} +
+ +
+
+
+ Virus Food: +
+
+ {{:helper.displayBar(data.food_supply, 0, 100, 'good', data.food_supply)}} +
+
+
+
+ Radiation Level: +
+
+ {{:helper.displayBar(data.radiation, 0, 100, (data.radiation >= 50) ? 'bad' : (data.growth >= 25) ? 'average' : 'good')}} +
+ {{:helper.formatNumber(data.radiation * 10000)}} µSv +
+
+
+
+ Toxicity: +
+
+ {{:helper.displayBar(data.toxins, 0, 100, (data.toxins >= 50) ? 'bad' : (data.toxins >= 25) ? 'average' : 'good', data.toxins + '%')}} +
+
+
+ +
+

Chemicals

+
+
+ {{:helper.link('Eject Chemicals', 'eject', { 'ejectchem' : 1 }, data.chemicals_inserted ? null : 'disabled')}} + {{:helper.link('Breed Virus', 'circle-arrow-s', { 'virus' : 1 }, data.can_breed_virus ? null : 'disabled')}} +
+ +{{if data.chemicals_inserted}} +
+
+ Volume: +
+
+ {{:helper.displayBar(data.chemical_volume, 0, data.max_chemical_volume, 'good', data.chemical_volume + ' / ' + data.max_chemical_volume)}} +
+
+
+
+ Breeding Environment: +
+
+ + {{:!data.dish_inserted ? 'N/A' : data.can_breed_virus ? 'Suitable' : 'No hemolytic samples detected'}} + + {{if data.blood_already_infected}} +
+ CAUTION: Viral infection detected in blood sample. + {{/if}} +
+
+{{else}} +
+ No chemicals inserted. +
+{{/if}} + +
+

Virus Dish

+
+
+ {{:helper.link('Eject Dish', 'eject', {'ejectdish' : 1}, data.dish_inserted ? null : 'disabled')}} +
+ +{{if data.dish_inserted}} + {{if data.virus}} +
+
+ Growth Density: +
+
+ {{:helper.displayBar(data.growth, 0, 100, (data.growth >= 50) ? 'good' : (data.growth >= 25) ? 'average' : 'bad', data.growth + '%' )}} +
+
+
+
+ Infection Rate: +
+
+ {{:data.analysed ? data.infection_rate : "Unknown"}} +
+
+ {{else}} +
+ No virus detected. +
+ {{/if}} +{{else}} +
+ No dish loaded. +
+{{/if}} \ No newline at end of file diff --git a/nano/templates/isolation_centrifuge.tmpl b/nano/templates/isolation_centrifuge.tmpl new file mode 100644 index 00000000000..6a4fd0fe1ab --- /dev/null +++ b/nano/templates/isolation_centrifuge.tmpl @@ -0,0 +1,81 @@ +
+ {{:helper.link('Close', 'gear', {'close' : 1}, null, 'fixedLeft')}} + {{:helper.link('Print', 'print', { 'print' : 1 }, data.antibodies || data.pathogens ? null : 'disabled', 'fixedLeft')}} +
+ +{{if data.busy}} +
The Centrifuge is currently busy.
+
+
{{:data.busy}}
+
+

+ Thank you for your patience! +

+{{else}} +
+

{{:data.is_antibody_sample ? 'Antibody Sample' : 'Blood Sample'}}

+
+
+ {{:helper.link('Eject Vial', 'eject', { 'action' : 'sample' }, data.sample_inserted ? null : 'disabled')}} +
+ {{if data.sample_inserted}} + {{if data.antibodies || data.pathogens}} +
+ {{if data.antibodies}} +
+
+ Antibodies: +
+
+ {{:data.antibodies}} +
+
+ {{/if}} + {{if data.pathogens}} +
+
+ Pathogens: +
+
+ {{for data.pathogens}} +
+ {{:value.name}} ({{:value.spread_type}}) +
+ {{/for}} +
+
+ {{/if}} +
+ {{else}} +
+ No antibodies or viral strains detected. +
+ {{/if}} + {{else}} +
+ No vial detected. +
+ {{/if}} + {{if data.antibodies && !data.is_antibody_sample}} +
+
+ Isolate Antibodies: +
+
+ {{:helper.link(data.antibodies, 'pencil', { 'action' : 'antibody' })}} +
+
+ {{/if}} + {{if data.pathogens}} +
+
+ Isolate Strain: +
+
+ {{for data.pathogens}} + {{:helper.link(value.name, 'pencil', { 'isolate' : value.reference })}} + {{/for}} +
+
+ {{/if}} +{{/if}} \ No newline at end of file diff --git a/nano/templates/pathogenic_isolator.tmpl b/nano/templates/pathogenic_isolator.tmpl new file mode 100644 index 00000000000..958201d2c05 --- /dev/null +++ b/nano/templates/pathogenic_isolator.tmpl @@ -0,0 +1,107 @@ +
+

Menu

+
+
+ {{if !data.isolating}} + {{:helper.link('Home', 'home', {'home' : 1}, data.state == 'home' ? 'disabled' : null, 'fixedLeft')}} + {{:helper.link('List', 'note', {'list' : 1}, data.state == 'list' ? 'disabled' : null, 'fixedLeft')}} + {{:helper.link('Pathogen', 'folder-open', {'entry' : 1}, data.state == 'entry' ? 'disabled' : null, 'fixedLeft')}} + {{/if}} +
+ {{:helper.link('Close', 'gear', {'close' : 1}, null, 'fixedLeft')}} + {{:helper.link('Print', 'print', { 'print' : 1 }, data.can_print ? null : 'disabled', 'fixedLeft')}} +
+ +{{if data.isolating}} +
The Isolator is currently busy.
+
+
Isolating pathogens...
+
+

+ Thank you for your patience! +

+{{else}} + {{if data.state =="home"}} +
+

Blood Sample

+
+
+ {{:helper.link('Eject Syringe', 'eject', { 'eject' : 1 }, data.syringe_inserted ? null : 'disabled')}} +
+ + {{if data.syringe_inserted}} +
+ Pathogens: + {{if data.pathogen_pool}} + {{for data.pathogen_pool}} +
+ {{:index + 1}}. #{{:value.unique_id}} {{:value.is_in_database ? "(Analysed)" : ""}}
+ {{:value.name}}: {{:value.dna}} +
+ {{/for}} + {{else}} + No pathogens detected. + {{/if}} +
+ {{else}} +
+ No syringe loaded. +
+ {{/if}} + {{if data.pathogen_pool}} +
+
+ Isolate Pathogens: +
+
+ {{for data.pathogen_pool}} + {{:helper.link('#' + value.unique_id, 'pencil', { 'isolate' : value.reference }, null, 'fixedLeft')}} + {{/for}} +
+
+
+
+ Database Lookup: +
+
+ {{for data.pathogen_pool}} + {{if value.is_in_database}} + {{:helper.link('#' + value.unique_id, 'info', { 'entry' : 1, 'view' : value.record }, null, 'fixedLeft')}} + {{/if}} + {{/for}} +
+
+ {{/if}} + {{else}} + {{if data.state == "list"}} +
+

View Database

+
+
+ {{if data.database}} + {{for data.database}} +
+
{{:value.name}}
+ {{:helper.link('Details', 'circle-arrow-s', { 'entry' : 1, 'view' : value.record }, null, 'fixedLeft')}} +
+ {{/for}} + {{else}} + The viral database is empty. + {{/if}} +
+ {{else}} + {{if data.state == "entry"}} + {{if data.entry}} +
+

{{:data.entry.name}}

+
+
+ {{:data.entry.description}} +
+ {{else}} + No virus selected. + {{/if}} + {{/if}} + {{/if}} + {{/if}} +{{/if}} \ No newline at end of file diff --git a/test/check-paths.sh b/test/check-paths.sh index 514576e18ff..b259c17d1a7 100755 --- a/test/check-paths.sh +++ b/test/check-paths.sh @@ -31,12 +31,12 @@ exactly 10 "/obj text paths" '"/obj' exactly 8 "/turf text paths" '"/turf' exactly 0 "world<< uses" 'world<<|world[[:space:]]<<' exactly 43 "world.log<< uses" 'world.log<<|world.log[[:space:]]<<' -exactly 478 "<< uses" '(?