Advanced Disease Rework (#28451)

* Reworks cures, adds strains, adds treatment chems to symptoms

* Enables coexistence of different samples of the same strain at different stages within the same container

* Adds symptom guessing. Correct guesses reduce analysis time and wrong ones increase it.

* Adds a chance for a virus to evolve into a new strain. changing the cure and adding/subtracting symptoms

* Revert "Adds a chance for a virus to evolve into a new strain. changing the cure and adding/subtracting symptoms"

This reverts commit 124dd485c7.

* Adds spontaneous virus mutations, strain tracking. Removes antibody metabolism

* change the amount of time added/reduced by each factor

* Creates a disease outbreak event that allows admins to cause an outbreak of a virus of their choosing. Allows virus creation when choosing virus to give someone or for an outbreak.

* The normal base property values are now the defaults for disease creation

* Rebuild TGUI

* Rebuild TGUI

* Rebuild TGUI

* Update tgui.bundle.js

* remove redundant lines

* improves ui some and moves to using world time for analysis time

* fixes a bug with the analysis time and updates the initial known advanced disease list

* Buffs the disease outbreak event and adds a base stat row to the PANDEMIC

* Update tgui.bundle.js

* Implements calibration

* Adds a remove from database button

* Moves the known disease global list to work per z level

* Removes treatments from most chems and makes each instance of a symptom not acting purge some of the reagent that treated it

* Update symptoms.dm

* Adds stage to unknown diseases

* Moves accumulated error to work per z level and change the location of the delete strain data button

* Adds confirmation to the delete data button and moves the disease text out of the loop in the copy constructor

* fix indentation

* Replaces pent with hydrocodone in the advanced cure list

* gives more buffs to event disease based on severity. removes longevity from possible symptoms an event disease can get.  Fixes a bug with determining analysis time

* Update tgui.bundle.js

* Update pandemic.dm

* Update pandemic.dm

* Update tgui.bundle.js

* review changes

* Update tgui.bundle.js

* Update tgui.bundle.js

* Update tgui.bundle.js

* Update tgui.bundle.js

* Update tgui.bundle.js

* Update tgui.bundle.js

* Update tgui.bundle.js

* Update tgui.bundle.js

* review changes

* Update tgui.bundle.js

* Makes vaccines only add resistances and no longer cure

* improves pandemic ui and fixes calibration button not being properly disabled

* Update tgui.bundle.js

* Add the new agars to the virologist's fridge

* lowered evolution chance of viruses a bit

* further lowers evolution chance

* Update advance.dm

* Changes the scaling of analysis time and fixes stage speed presentation in the pandemic

* Scanners can now see virus strains that have been inserted in the pandemic

* Allows a mob to be infected by both an event and non event disease

* Fixes the +1 syringe of translocation stabbing your feet

* Update tgui.bundle.js

* Changes spontanous mutation to be per spread and makes disease events less likely.

* Diseases less common, mutations happen only on spread now, symptom list ordered alphabetically in the dropdown, fixed some bugs

* Update tgui.bundle.js

* changes virus alerts

* Removes numbers from the virus alert text and fixes a bug that caused excessive virus mutations

* Update tgui.bundle.js

* refactor disease spread

* Changes disease spread logic to give players options to protect themselves and others

* Blackbox things

* Increases announcement timer and fixes the infection talley

* Update disease_outbreak.dm

* Adds an incubation period to advanced viruses. bumps sneeze back to 5 range

* Adds failsafe to disease outbreaks that will infect a random crew member if none have arrived in 10 minutes

* Only record advanced disease infections

* Properly handle recording of disease infection events

* Changed resistance effect on cure

* another adjustment to res effect on cure

* Small resist buff, spontanous combustion buff and some calculation fixes

* changes spontanous combustion stat bonuses and maluses

* Update flesh_eating.dm

* Update flesh_eating.dm

* Update flesh_eating.dm

* Big trait changes and rebalance

* adds treatments to fire and necro

* Introduces viral contamination of food and reagent containers, as well as disinfection

* Fix runtime in reagent transfers

* Revert the prefs and config changes

* Slowed down diseases and made symptoms more gradual, improved disease alerts to both crew and dchat

* Sterilizine now sterilizes things contaminated with viruses. Heat reactions now take place alongside chemical reactions when adding reagents to a beaker

* Adds option to order sterile masks, goggles and biosuits in packs of 4. Makes sterile masks as good as internals for viruses

* adds logging to pandemic

* Changes symptom stats and increased disease varaiety

* Fixes some disease bugs

* Fixes some bugs and makes it behave better

* Adds shiver emote to shiver symptom

* Adds admin message/log to contracting an event disease and fixes copy behaviour when infecting

* Prefix spread defines

* Change the rest of the macros

* correct the disinfection temp macro

* Moves disease signals to their own file

* move disnifection temp back

* fix a type

* viral contaminations component review changes

* var name changes

* more style fixes

* Update tgui.bundle.js

* fixes pandemic

* Fixes disease outbreak having two carriers sometimes and changes the virus alert to the new one

* Update disease_defines.dm

* fixes samples not passing stages on properly

* actually fixes the bug

* Fixes stabilization being lost on cloning

* Finally completely and absolutely fixes the sample stages bug(please)

* Makes the pandemic a machine

* Update pandemic.dm

* removed drinks from cure requirements

* lowers chance of major viral outbreak

* fixes pandemic not processing properly

* Changes the cure system to have more options

* Makes mixing event viruses more random

* Fixes hardsuits having a 1% chance to be infected

* Increases virus protection of most clothing. medical scrubs and surgical hat buffed sunstantially

* Slow down progress of diseases

* makes spread less likely

* envirosuit is now slightly more protective from viruses, while the medical one is as good as scrubs

* Adds further protection to helmets

* Increases the number of possible cures and the scaling of required cures

* Pandemic ui improvements

* Update _disease.dm

* fix a bug with spread target in the disease outbreak event

* changes some clothing permeability

* Adds the ability to make viral DNA extracts by injecting a sample into a black slime core. It's equivalent to 2 stages

* Adds age to health analyzer, makes viral evolution toggle minor disabilities, confusion symptom now confuses more often

* Update pandemic.dm

* replace lazarus with acetic acid in the cures

* Changes the relation of the amount of cure options to required cures and the scaling of required cures with resistance

* Fixes virus renaming

* changes description and permeability of some medical jumpsuits

* Adds a list of all diseases infecting client mobs to the disease outbreak event

* uses event UID instead of ref in the disease

* Adds advanced disease carriers to admin antag menu

* Adds viral eraser which removes tracking and stabilizing. Admin spawn only for now

* Update tgui.bundle.js

* Adds the ability to create viral genetic material using radiation. it can be used in addition to that produced in xenobio

* changes alert logic, disease generation logic, adds treatments to weakness, cough and sneeze now more gradual and cough spreads at range 3

* makes disease advance a bit faster

* reduce time to announcement to 6 minutes after 3 people are infected

* Changes medibot disease detection to be the same as analyzers. Treatment chems now put the symptom on a cooldown that persists after they leave the body.

* Make sure the disease outbreak event only selects crew

* Fix abductor virus gland virus generation

* Adds sterilizine to viro locker

* Fixes null viruses appearing when merging virusless blood

* Adds oculine to hyphema treatments

* Rebalances weight loss and flesh eating

* Improvements to advanced disease carrier tab on the TGUI antag menu

* change the flag on away missions

* Update mob_spawn.dm

* Update tgui.bundle.js

* adds sterilizine recipe back

* Adds viral contamination to surgery tools and surgery steps

* small changes

* fixes pandemic ui. should work properly now(I hope)

* CI compliance

* Update flesh_eating.dm

* Update vomit.dm

* Update tgui.bundle.js

* Initial revision of analysis and fixes the UI issue with multiple stage samples

* refactors treatment and makes treatment chems more adjustable

* var correction

* symptoms and their contribution now show up on the pandemic

* Update tgui.bundle.js

* Update code/datums/diseases/advance/symptoms/cough.dm

Signed-off-by: Burzah <116982774+Burzah@users.noreply.github.com>

* change wizard disease and zombie disease macros to new ones

* Update tgui.bundle.js

* changes the part requirements on the pandemic boards to fit the actual parts

* fix misbehaviour when inserting samples without symptoms

* Some changes to difficulty scaling, reverts the level of projectile vomiting back to 4, and disallows germaphobes to avoid infection by injection

* Adds viral contamination to IV bags

---------

Signed-off-by: Burzah <116982774+Burzah@users.noreply.github.com>
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
This commit is contained in:
Migratingcocofruit
2025-08-08 04:54:36 +03:00
committed by GitHub
parent 4f77a856f0
commit a5260456ae
133 changed files with 2484 additions and 1117 deletions
@@ -1,31 +1,106 @@
/obj/machinery/computer/pandemic
#define ANALYSIS_DIFFICULTY_BASE 100
#define ANALYSIS_DIFFICULTY_INCREMENT 40
#define ANALYSIS_DURATION_BASE (0.5 MINUTES)
#define STAGE_CONTRIBUTION 40
#define GENE_CONTRIBUTION 60
/// list of known advanced disease ids. If an advanced disease isn't here it will display as unknown disease on scanners
/// Initialized with the id of the flu and cold samples from the virologist's fridge in the pandemic's init
GLOBAL_LIST_EMPTY(known_advanced_diseases)
GLOBAL_LIST_EMPTY(detected_advanced_diseases)
/obj/machinery/pandemic
name = "PanD.E.M.I.C 2200"
desc = "Used to work with viruses."
icon = 'icons/obj/chemical.dmi'
icon_state = "pandemic0"
circuit = /obj/item/circuitboard/pandemic
idle_power_consumption = 20
resistance_flags = ACID_PROOF
density = TRUE
anchored = TRUE
/// The base analysis time which is later modified by samples of uniqute stages and symptom prediction
var/analysis_difficulty_base = ANALYSIS_DIFFICULTY_BASE
/// How difficult the disease is to analyze. This sets the requirements for how much you need to contribute with things like stages and symptom predictions
var/analysis_difficulty = 0
/// The contribution of various factors towards analysis. The "max" values are only for the UI
var/analysis_contributions = list(
"Stage Data" = list("amount" = 0, "max" = 5 * STAGE_CONTRIBUTION),
"Viral Gene Data" = list("amount" = 0, "max" = 2 * GENE_CONTRIBUTION),
"Symptom Data" = list("amount" = 0, "max" = 0.5 * ANALYSIS_DIFFICULTY_BASE)
)
/// The time at which the analysis of a disease will be done. Calculated at the begnining of analysis using analysis_difficulty and symptoms symptom_guesses.
var/analysis_time
/// How much time analysis will take. Depends on components
var/analysis_duration
/// Whether the PANDEMIC is currently analyzing an advanced disease
var/analyzing = FALSE
/// Whether to keep the report screen up. This is so it can stay persistent while the UI is closed
var/reporting = FALSE
/// Can our sample be analyzed
var/valid_sample = FALSE
/// ID of the disease being analyzed
var/analyzed_ID = ""
/// Index of the disease being analyzed
var/analyzed_index
/// List of all symptoms. Gets filled in Initialize().
var/symptom_list = list()
var/temp_html = ""
var/printing = null
var/wait = null
var/selected_strain_index = 1
var/obj/item/reagent_containers/beaker = null
/// The current symptom predictions
var/list/predictions = list(
"No Prediction",
"No Prediction",
"No Prediction",
"No Prediction",
"No Prediction",
"No Prediction"
)
/obj/machinery/computer/pandemic/Initialize(mapload)
/obj/machinery/pandemic/Initialize(mapload)
. = ..()
component_parts = list()
component_parts += new /obj/item/circuitboard/pandemic(null)
component_parts += new /obj/item/stock_parts/manipulator(null)
component_parts += new /obj/item/stock_parts/micro_laser(null)
RefreshParts()
GLOB.pandemics |= src
var/datum/symptom/S
symptom_list += list("No Prediction")
for(var/symptom_path in GLOB.list_symptoms)
// I don't know a way to access the name of something with only the path without creating an instance.
S = new symptom_path()
symptom_list += list(S.name)
qdel(S)
// We init the list for the Z level here so that we can know it is loaded when we do.
if(!(z in GLOB.known_advanced_diseases))
GLOB.known_advanced_diseases += list("[z]" = list("4:origin", "24:origin"))
update_icon()
/obj/machinery/computer/pandemic/Destroy()
/obj/machinery/pandemic/RefreshParts()
var/manip_rating = 0
var/laser_rating = 0
for(var/obj/item/stock_parts/manipulator/manip in component_parts)
manip_rating += manip.rating
for(var/obj/item/stock_parts/micro_laser/laser in component_parts)
laser_rating += laser.rating
analysis_difficulty_base = ANALYSIS_DIFFICULTY_BASE * (9 / (manip_rating + 8))
analysis_duration = ANALYSIS_DURATION_BASE * (1 / laser_rating)
find_analysis_requirements()
/obj/machinery/pandemic/Destroy()
GLOB.pandemics -= src
return ..()
/obj/machinery/computer/pandemic/set_broken()
/obj/machinery/pandemic/proc/set_broken()
stat |= BROKEN
update_icon()
/obj/machinery/computer/pandemic/proc/GetViruses()
/obj/machinery/pandemic/proc/GetViruses()
if(beaker && beaker.reagents)
if(length(beaker.reagents.reagent_list))
var/datum/reagent/blood/BL = locate() in beaker.reagents.reagent_list
@@ -34,12 +109,12 @@
var/list/viruses = BL.data["viruses"]
return viruses
/obj/machinery/computer/pandemic/proc/GetVirusByIndex(index)
/obj/machinery/pandemic/proc/GetVirusByIndex(index)
var/list/viruses = GetViruses()
if(viruses && index > 0 && index <= length(viruses))
return viruses[index]
/obj/machinery/computer/pandemic/proc/GetResistances()
/obj/machinery/pandemic/proc/GetResistances()
if(beaker && beaker.reagents)
if(length(beaker.reagents.reagent_list))
var/datum/reagent/blood/BL = locate() in beaker.reagents.reagent_list
@@ -48,17 +123,17 @@
var/list/resistances = BL.data["resistances"]
return resistances
/obj/machinery/computer/pandemic/proc/GetResistancesByIndex(index)
/obj/machinery/pandemic/proc/GetResistancesByIndex(index)
var/list/resistances = GetResistances()
if(resistances && index > 0 && index <= length(resistances))
return resistances[index]
/obj/machinery/computer/pandemic/proc/GetVirusTypeByIndex(index)
/obj/machinery/pandemic/proc/GetVirusTypeByIndex(index)
var/datum/disease/D = GetVirusByIndex(index)
if(D)
return D.GetDiseaseID()
/obj/machinery/computer/pandemic/proc/replicator_cooldown(waittime)
/obj/machinery/pandemic/proc/replicator_cooldown(waittime)
wait = 1
update_icon()
spawn(waittime)
@@ -66,18 +141,18 @@
update_icon()
playsound(loc, 'sound/machines/ping.ogg', 30, 1)
/obj/machinery/computer/pandemic/update_icon_state()
/obj/machinery/pandemic/update_icon_state()
if(stat & BROKEN)
icon_state = (beaker ? "pandemic1_b" : "pandemic0_b")
return
icon_state = "pandemic[(beaker)?"1":"0"][(has_power()) ? "" : "_nopower"]"
/obj/machinery/computer/pandemic/update_overlays()
/obj/machinery/pandemic/update_overlays()
. = list()
if(!wait)
. += "waitlight"
/obj/machinery/computer/pandemic/proc/create_culture(name, bottle_type = "culture", cooldown = 50)
/obj/machinery/pandemic/proc/create_culture(name, bottle_type = "culture", cooldown = 50)
var/obj/item/reagent_containers/glass/bottle/B = new/obj/item/reagent_containers/glass/bottle(loc)
B.icon_state = "bottle"
B.scatter_atom()
@@ -85,7 +160,118 @@
B.name = "[name] [bottle_type] bottle"
return B
/obj/machinery/computer/pandemic/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
/// Find the time it would take to analyze the current disease before any symptom predictions are made
/obj/machinery/pandemic/proc/find_analysis_requirements()
if(!beaker)
return
analysis_contributions["Stage Data"]["amount"] = 0
analysis_contributions["Viral Gene Data"]["amount"] = 0
analysis_contributions["Symptom Data"]["amount"] = 0
analysis_contributions["Symptom Data"]["max"] = 1
valid_sample = TRUE
var/strains = 0
var/list/stages = list()
var/current_strain = ""
var/stealth_init = FALSE
var/stealth = 0
var/resistance = 0
var/max_stages = 0
var/known_symptoms = 0
var/num_symptoms = 0
var/datum/reagent/blood/blood_sample = locate() in beaker.reagents.reagent_list
var/datum/reagent/virus_genes/gene_sample = locate() in beaker.reagents.reagent_list
if(blood_sample && blood_sample.data && blood_sample.data["viruses"])
for(var/datum/disease/advance/to_analyze in blood_sample.data["viruses"])
// Note down number of symptoms and number of known symptoms.
// We only use these values if we find one strain, so no need to worry about overwriting
known_symptoms = length(GLOB.detected_advanced_diseases["[z]"][to_analyze.GetDiseaseID()]["known_symptoms"])
num_symptoms = length(to_analyze.symptoms)
// Automatically analyze if the tracker stores the ID of an analyzed disease
if(to_analyze.tracker && (to_analyze.tracker in GLOB.known_advanced_diseases["[z]"]))
if(!(to_analyze.GetDiseaseID() in GLOB.known_advanced_diseases["[z]"]))
GLOB.known_advanced_diseases["[z]"] += list(to_analyze.GetDiseaseID())
// If we know this disease there's no need to keep going.
if(to_analyze.GetDiseaseID() in GLOB.known_advanced_diseases["[z]"])
return
// If we somehow got multiple strains we can't do analysis.
if(to_analyze.strain != current_strain || current_strain == "")
strains++
if(strains > 1)
valid_sample = FALSE
SStgui.update_uis(src, TRUE)
return
current_strain = to_analyze.strain
// Calculate the stealth and resistance values. We only need to do this once
if(!stealth_init)
for(var/datum/symptom/S in to_analyze.symptoms)
stealth += S.stealth
resistance += S.resistance
stealth += to_analyze.base_properties["stealth"]
resistance += to_analyze.base_properties["resistance"]
max_stages = to_analyze.max_stages
stealth_init = TRUE
// If we found a unique stage count it
if(!(to_analyze.stage in stages))
analysis_contributions["Stage Data"]["amount"] += STAGE_CONTRIBUTION
stages += to_analyze.stage
if(gene_sample && gene_sample.data)
for(var/key in gene_sample.data)
for(var/strain_id in gene_sample.data[key])
if(strain_id == current_strain)
analysis_contributions["Viral Gene Data"]["amount"] += GENE_CONTRIBUTION
break
var/power_level = (stealth + resistance)
// Make sure we don't runtime if empty
if(max_stages)
analysis_difficulty = analysis_difficulty_base + ANALYSIS_DIFFICULTY_INCREMENT * (1.17 ** power_level)
else
analysis_difficulty = analysis_difficulty_base
analysis_contributions["Symptom Data"]["amount"] = num_symptoms ? analysis_difficulty * known_symptoms / (2 * num_symptoms) : 0
analysis_contributions["Symptom Data"]["max"] = max(analysis_difficulty / 2, 1)
SStgui.update_uis(src, TRUE)
/obj/machinery/pandemic/proc/start_analysis(strain_index)
var/datum/disease/advance/virus = GetVirusByIndex(strain_index)
analyzing = TRUE
analysis_time = world.time + analysis_duration
analyzed_ID = virus.GetDiseaseID()
analyzed_index = strain_index
/obj/machinery/pandemic/proc/analyze(strain_index)
reporting = TRUE
var/datum/disease/advance/virus = GetVirusByIndex(analyzed_index)
var/symptom_names = list()
for(var/datum/symptom/current_symptom in virus.symptoms)
symptom_names += list(current_symptom.name)
for(var/name in predictions)
if(!name || name == "No Prediction")
continue
if(name in symptom_names)
GLOB.detected_advanced_diseases["[z]"][analyzed_ID]["known_symptoms"] |= list(name)
var/found_symptoms = length(GLOB.detected_advanced_diseases["[z]"][analyzed_ID]["known_symptoms"])
// Correct symptom symptom_guesses reduce the final analysis time by up to half of the base time.
analysis_contributions["Symptom Data"]["max"] = analysis_difficulty / 2
analysis_contributions["Symptom Data"]["amount"] = analysis_difficulty * found_symptoms / (2 * length(virus.symptoms))
var/total_contribution = 0
for(var/factor in analysis_contributions)
total_contribution += analysis_contributions[factor]["amount"]
return (analysis_difficulty - total_contribution) <= 0
/obj/machinery/pandemic/process()
if(analyzing && analysis_time < world.time)
if(analyze(analyzed_index))
GLOB.known_advanced_diseases["[z]"] += analyzed_ID
analyzing = FALSE
SStgui.update_uis(src, TRUE)
/obj/machinery/pandemic/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
if(..())
return
if(inoperable())
@@ -111,9 +297,9 @@
return
var/type = virus.GetDiseaseID()
if(!ispath(type))
var/datum/disease/advance/A = GLOB.archive_diseases[type]
if(A)
D = new A.type(0, A)
var/datum/disease/advance/A = virus
if(istype(A))
D = A.Copy()
else if(type)
if(type in GLOB.diseases) // Make sure this is a disease
D = new type(0, null)
@@ -158,6 +344,10 @@
var/obj/item/reagent_containers/glass/bottle/B = create_culture(vaccine_name, "vaccine", 200)
B.reagents.add_reagent("vaccine", 15, list(vaccine_type))
if("remove_from_database")
if(params["strain_id"] in GLOB.known_advanced_diseases["[z]"])
GLOB.known_advanced_diseases["[z]"] -= params["strain_id"]
SStgui.update_uis(src, TRUE)
if("eject_beaker")
eject_beaker()
update_static_data(ui.user)
@@ -192,15 +382,16 @@
if(!A)
atom_say("Unable to find requested strain.")
return
if(A.name != "Unknown")
atom_say("Request rejected. Strain already has a name.")
return
var/new_name = tgui_input_text(usr, "Name the Strain", "New Name", max_length = MAX_NAME_LEN)
if(!new_name)
return
A.AssignName(new_name)
for(var/datum/disease/advance/AD in GLOB.active_diseases)
AD.Refresh()
AD.Refresh(TRUE, FALSE, FALSE, FALSE)
var/datum/reagent/blood = locate() in beaker.reagents.reagent_list
if(blood.data && blood.data["viruses"])
for(var/datum/disease/advance/virus in blood.data["viruses"])
virus.AssignName(new_name)
update_static_data(ui.user)
if("switch_strain")
var/strain_index = text2num(params["strain_index"])
@@ -212,26 +403,52 @@
atom_say("Unable to find requested strain.")
return
selected_strain_index = strain_index;
if("analyze_strain")
start_analysis(params["strain_index"])
if("set_prediction")
set_predictions(text2num(params["pred_index"]), params["pred_value"])
SStgui.update_uis(src)
if("close_report")
reporting = FALSE
else
return FALSE
/obj/machinery/computer/pandemic/ui_state(mob/user)
/obj/machinery/pandemic/proc/set_predictions(index, value)
predictions[index] = value
/obj/machinery/pandemic/ui_state(mob/user)
return GLOB.default_state
/obj/machinery/computer/pandemic/ui_interact(mob/user, datum/tgui/ui = null)
/obj/machinery/pandemic/ui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "PanDEMIC", name)
ui.open()
/obj/machinery/computer/pandemic/ui_data(mob/user)
/obj/machinery/pandemic/ui_data(mob/user)
var/datum/reagent/blood/Blood = null
var/can_analyze = valid_sample
var/contribution_list = list()
var/contribution_sum = 0
if(beaker)
var/datum/reagents/R = beaker.reagents
for(var/datum/reagent/blood/B in R.reagent_list)
if(B)
Blood = B
break
if(Blood)
if(Blood.data && Blood.data["viruses"])
for(var/datum/disease/advance/virus in Blood.data["viruses"])
if((virus.GetDiseaseID() in GLOB.known_advanced_diseases["[z]"]))
can_analyze = FALSE
break
for(var/factor in analysis_contributions)
contribution_list += list(list(
"factor" = factor,
"amount" = analysis_contributions[factor]["amount"],
"maxAmount" = analysis_contributions[factor]["max"],
))
contribution_sum += analysis_contributions[factor]["amount"]
var/list/data = list(
"synthesisCooldown" = wait ? TRUE : FALSE,
@@ -239,11 +456,21 @@
"beakerContainsBlood" = Blood ? TRUE : FALSE,
"beakerContainsVirus" = length(Blood?.data["viruses"]) != 0,
"selectedStrainIndex" = selected_strain_index,
"analysisTime" = analysis_time > world.time ? analysis_time - world.time : 0,
"analysisDuration" = analysis_duration,
"analysisDifficulty" = analysis_difficulty,
"analysisContributions" = contribution_list,
"totalContribution" = contribution_sum,
"canAnalyze" = can_analyze,
"analyzing" = analyzing,
"reporting" = reporting,
"symptom_names" = symptom_list,
"predictions" = predictions,
)
return data
/obj/machinery/computer/pandemic/ui_static_data(mob/user)
/obj/machinery/pandemic/ui_static_data(mob/user)
var/list/data = list()
. = data
@@ -256,59 +483,58 @@
break
var/list/strains = list()
for(var/datum/disease/D in GetViruses())
if(D.visibility_flags & HIDDEN_PANDEMIC)
for(var/datum/disease/blood_disease in GetViruses())
if(!(blood_disease.GetDiseaseID() in GLOB.detected_advanced_diseases["[z]"]))
GLOB.detected_advanced_diseases["[z]"] += list(blood_disease.GetDiseaseID() = list("known_symptoms" = list()))
if(blood_disease.visibility_flags & VIRUS_HIDDEN_PANDEMIC)
continue
var/list/symptoms = list()
if(istype(D, /datum/disease/advance))
var/datum/disease/advance/A = D
D = GLOB.archive_diseases[A.GetDiseaseID()]
if(!D)
CRASH("We weren't able to get the advance disease from the archive.")
for(var/datum/symptom/S in A.symptoms)
symptoms += list(list(
"name" = S.name,
"stealth" = S.stealth,
"resistance" = S.resistance,
"stageSpeed" = S.stage_speed,
"transmissibility" = S.transmittable,
"complexity" = S.level,
))
var/list/symptoms = blood_disease.get_pandemic_symptoms(z)
var/list/base_stats = blood_disease.get_pandemic_base_stats()
var/known = blood_disease.is_known(z)
strains += list(list(
"commonName" = D.name,
"description" = D.desc,
"commonName" = known ? blood_disease.name : "Unknown strain",
"description" = known ? blood_disease.desc : "Unknown strain",
"strainID" = blood_disease.get_strain_id(),
"strainFullID" = blood_disease.get_full_strain_id(),
"diseaseID" = blood_disease.get_ui_id(),
"sample_stage" = blood_disease.get_stage(),
"known" = known,
"bloodDNA" = Blood.data["blood_DNA"],
"bloodType" = Blood.data["blood_type"],
"diseaseAgent" = D.agent,
"possibleTreatments" = D.cure_text,
"transmissionRoute" = D.spread_text,
"diseaseAgent" = blood_disease.agent,
"possibleCures" = known ? blood_disease.cure_text : "Unknown strain",
"RequiredCures" = "[blood_disease.get_required_cures()]",
"Stabilized" = blood_disease.is_stabilized(),
"StrainTracker" = blood_disease.get_tracker(),
"transmissionRoute" = known ? blood_disease.spread_text : "Unknown strain",
"symptoms" = symptoms,
"isAdvanced" = istype(D, /datum/disease/advance),
"baseStats" = base_stats,
"isAdvanced" = istype(blood_disease, /datum/disease/advance),
))
data["strains"] = strains
var/list/resistances = list()
for(var/resistance in GetResistances())
if(!ispath(resistance))
var/datum/disease/D = GLOB.archive_diseases[resistance]
if(D)
resistances += list(D.name)
var/datum/disease/resisted_disease = GLOB.archive_diseases[resistance]
if(resisted_disease)
resistances += list(resisted_disease.name)
else if(resistance)
var/datum/disease/D = new resistance(0, null)
if(D)
resistances += list(D.name)
var/datum/disease/resistance_disease = new resistance(0, null)
if(resistance_disease)
resistances += list(resistance_disease.name)
data["resistances"] = resistances
data["analysis_difficulty"] = analysis_difficulty
/obj/machinery/computer/pandemic/proc/eject_beaker()
/obj/machinery/pandemic/proc/eject_beaker()
beaker.forceMove(loc)
beaker = null
icon_state = "pandemic0"
selected_strain_index = 1
//Prints a nice virus release form. Props to Urbanliner for the layout
/obj/machinery/computer/pandemic/proc/print_form(datum/disease/advance/D, mob/living/user)
/obj/machinery/pandemic/proc/print_form(datum/disease/advance/D, mob/living/user)
D = GLOB.archive_diseases[D.GetDiseaseID()]
if(!(printing) && D)
var/reason = tgui_input_text(user,"Enter a reason for the release", "Write", multiline = TRUE)
@@ -350,7 +576,7 @@
P.name = "Releasing Virus - [D.name]"
printing = null
/obj/machinery/computer/pandemic/proc/print_goal_orders()
/obj/machinery/pandemic/proc/print_goal_orders()
if(stat & (BROKEN|NOPOWER))
return
@@ -370,18 +596,18 @@
P.info = info_text.Join("")
P.update_icon()
/obj/machinery/computer/pandemic/attack_ai(mob/user)
/obj/machinery/pandemic/attack_ai(mob/user)
return attack_hand(user)
/obj/machinery/computer/pandemic/attack_hand(mob/user)
/obj/machinery/pandemic/attack_hand(mob/user)
if(..())
return
ui_interact(user)
/obj/machinery/computer/pandemic/attack_ghost(mob/user)
/obj/machinery/pandemic/attack_ghost(mob/user)
ui_interact(user)
/obj/machinery/computer/pandemic/item_interaction(mob/living/user, obj/item/used, list/modifiers)
/obj/machinery/pandemic/item_interaction(mob/living/user, obj/item/used, list/modifiers)
if(default_unfasten_wrench(user, used, time = 4 SECONDS))
power_change()
return
@@ -395,17 +621,33 @@
return ITEM_INTERACT_COMPLETE
beaker = used
beaker.loc = src
beaker.forceMove(src)
to_chat(user, "<span class='notice'>You add the beaker to the machine.</span>")
SStgui.update_uis(src, TRUE)
icon_state = "pandemic1"
var/datum/reagent/blood/inserted = locate() in beaker.reagents.reagent_list
if(inserted && inserted.data && inserted.data["viruses"])
for(var/datum/disease/advance/virus in inserted.data["viruses"])
if(!(virus.GetDiseaseID() in GLOB.detected_advanced_diseases["[z]"]))
GLOB.detected_advanced_diseases["[z]"] += list(virus.GetDiseaseID() = list("known_symptoms" = list()))
log_admin("[key_name(user)] inserted disease [virus] of strain [virus.strain] with the following symptoms: [english_list(virus.symptoms)] into [src] at these coords x: [x] y: [y] z: [z]")
find_analysis_requirements()
SStgui.update_uis(src, TRUE)
return ITEM_INTERACT_COMPLETE
else
return ..()
/obj/machinery/computer/pandemic/screwdriver_act(mob/user, obj/item/I)
/obj/machinery/pandemic/screwdriver_act(mob/living/user, obj/item/I)
if(!default_deconstruction_screwdriver(user, icon_state, icon_state, I))
return FALSE
if(beaker)
eject_beaker()
return TRUE
return ..()
return TRUE
/obj/machinery/pandemic/crowbar_act(mob/living/user, obj/item/I)
return default_deconstruction_crowbar(user, I)
#undef ANALYSIS_DIFFICULTY_BASE
#undef ANALYSIS_DIFFICULTY_INCREMENT
#undef ANALYSIS_DURATION_BASE
#undef STAGE_CONTRIBUTION
#undef GENE_CONTRIBUTION
@@ -52,7 +52,7 @@
M.SetJitter(0)
for(var/thing in M.viruses)
var/datum/disease/D = thing
if(D.severity == NONTHREAT)
if(D.severity == VIRUS_NONTHREAT)
continue
D.cure(0)
..()
@@ -155,6 +155,12 @@
color = "#899613" // rgb: 137, 150, 19
taste_description = "watery milk"
/datum/reagent/consumable/virus_food/on_mob_life(mob/living/M)
. = ..()
for(var/datum/disease/advance/virus in M.viruses)
if(prob(3))
virus.progress += 20
/datum/reagent/mutagen/mutagenvirusfood
name = "Mutagenic agar"
id = "mutagenvirusfood"
@@ -183,3 +189,32 @@
name = "Weakened virus plasma"
id = "weakplasmavirusfood"
color = "#CEC3C6" // rgb: 206,195,198
/datum/reagent/consumable/stable_agar
name = "Stable agar"
id = "stable_agar"
color = "#50BDB0" // rgb: 80,206,192
/datum/reagent/consumable/tracking_agar
name = "Tracking agar"
id = "tracking_agar"
color = "#2c8852" // rgb: 45,136,82
/datum/reagent/virus_genes
name = "Viral Genetic Material"
id = "virus_genes"
color = "#e0717a"
/// Depth 1 copy of the lists
/datum/reagent/virus_genes/on_merge(list/_data)
var/list/result = list()
for(var/key in (data + _data))
result[key] = data[key]
if(_data[key])
result[key] += _data[key]
data = result
/datum/reagent/viral_eraser
name = "Viral Eraser"
id = "viral_eraser"
color = "#ffe600" // rgb: 45,136,82
@@ -29,6 +29,35 @@
var/update_flags = STATUS_UPDATE_HEALTH
return ..() | update_flags
/datum/reagent/medicine/sterilizine
name = "Sterilizine"
id = "sterilizine"
description = "Sterilizes wounds in preparation for surgery."
reagent_state = LIQUID
color = "#C8A5DC" // rgb: 200, 165, 220
taste_description = "antiseptic"
goal_difficulty = REAGENT_GOAL_EASY
//makes you squeaky clean
/datum/reagent/medicine/sterilizine/reaction_mob(mob/living/M, method=REAGENT_TOUCH, volume)
if(method == REAGENT_TOUCH)
M.germ_level -= min(volume*20, M.germ_level)
/datum/reagent/medicine/sterilizine/reaction_obj(obj/O, volume)
O.germ_level -= min(volume*20, O.germ_level)
SEND_SIGNAL(O, COMSIG_ATOM_DISINFECTED)
/datum/reagent/medicine/sterilizine/reaction_turf(turf/T, volume)
T.germ_level -= min(volume*20, T.germ_level)
/datum/reagent/medicine/sterilizine/reaction_temperature(exposed_temperature, exposed_volume)
// Sterilize the container
for(var/datum/reagent/to_disinfect in holder.reagent_list)
if(to_disinfect.data && to_disinfect.data["viruses"])
to_disinfect?.data["viruses"] = list()
if(isobj(holder.my_atom))
SEND_SIGNAL(holder.my_atom, COMSIG_ATOM_DISINFECTED)
/datum/reagent/medicine/synaptizine
name = "Synaptizine"
id = "synaptizine"
@@ -106,7 +106,7 @@
for(var/thing in data["viruses"])
var/datum/disease/D = thing
if(D.spread_flags & SPECIAL || D.spread_flags & NON_CONTAGIOUS)
if(D.spread_flags & SPREAD_SPECIAL || D.spread_flags & SPREAD_NON_CONTAGIOUS)
continue
if(method == REAGENT_TOUCH)
@@ -121,6 +121,13 @@
C.blood_volume = min(C.blood_volume + round(volume, 0.1), BLOOD_VOLUME_NORMAL)
..()
/datum/reagent/blood/reaction_temperature(exposed_temperature, exposed_volume)
// If the blood goes above 60C kill all viruses
if(exposed_temperature > VIRUS_DISINFECTION_TEMP)
data["viruses"] = list()
..()
/datum/reagent/blood/on_new(list/data)
if(istype(data))
SetViruses(src, data)
@@ -151,15 +158,38 @@
// Stop issues with the list changing during mixing.
var/list/to_mix = list()
var/list/disease_ids = list()
var/list/stages = list()
for(var/datum/disease/advance/AD in mix1)
to_mix += AD
for(var/datum/disease/advance/AD in mix2)
to_mix += AD
if(!(AD.GetDiseaseID() in disease_ids))
disease_ids += AD.GetDiseaseID()
stages[AD.GetDiseaseID()] = list(AD.stage)
to_mix += AD
if(!(AD.stage in stages[AD.GetDiseaseID()]))
stages[AD.GetDiseaseID()] += list(AD.stage)
to_mix += AD
var/datum/disease/advance/AD = Advance_Mix(to_mix)
if(AD)
var/list/preserve = list(AD)
for(var/datum/disease/advance/AD in mix2)
if(!(AD.GetDiseaseID() in disease_ids))
disease_ids += AD.GetDiseaseID()
stages[AD.GetDiseaseID()] = list(AD.stage)
to_mix += AD
if(!(AD.stage in stages[AD.GetDiseaseID()]))
stages[AD.GetDiseaseID()] += list(AD.stage)
to_mix += AD
var/list/result_diseases = list()
if(length(disease_ids) == 1)
for(var/datum/disease/advance/AD in to_mix)
result_diseases += AD.Copy()
else
var/datum/disease/advance/result_virus = Advance_Mix(to_mix)
if(istype(result_virus))
result_diseases = list(result_virus)
if(length(result_diseases))
var/list/preserve = result_diseases
for(var/D in data["viruses"])
if(!istype(D, /datum/disease/advance))
preserve += D
@@ -187,6 +217,19 @@
blood_prop = new(T)
blood_prop.blood_DNA["UNKNOWN DNA STRUCTURE"] = "X*"
/// If irradiated by gamma radiation and there are advanced viruses in the blood become a sample of viral genetic data
/datum/reagent/blood/reaction_radiation(amount, emission_type)
if(emission_type == GAMMA_RAD && amount > 100)
if(data && data["viruses"])
var/list/strains = list("radiation" = list())
for(var/datum/disease/advance/virus in data["viruses"])
strains["radiation"] += virus.strain
if(length(strains["radiation"]))
var/blood_volume = volume
holder.remove_reagent(id, blood_volume)
holder.add_reagent("virus_genes", blood_volume, strains)
/datum/reagent/vaccine
//data must contain virus type
name = "Vaccine"
@@ -199,7 +242,7 @@
for(var/thing in M.viruses)
var/datum/disease/D = thing
if(D.GetDiseaseID() in data)
D.cure()
D.make_resistant(M)
M.resistances |= data
/datum/reagent/vaccine/on_merge(list/incoming_data)
@@ -62,7 +62,12 @@
data.Cut()
data = null
/datum/reagent/proc/reaction_temperature(exposed_temperature, exposed_volume) //By default we do nothing.
/// By default do nothing
/datum/reagent/proc/reaction_temperature(exposed_temperature, exposed_volume)
return
/// By default do nothing
/datum/reagent/proc/reaction_radiation(amount, emission_type)
return
/**
@@ -35,7 +35,8 @@
var/list/addiction_threshold_accumulated = list()
var/flags
/datum/reagents/New(maximum = 100, temperature_minimum, temperature_maximum)
/datum/reagents/New(maximum = 100, temperature_minimum, temperature_maximum, atom/_my_atom = null)
my_atom = _my_atom
maximum_volume = maximum
if(temperature_minimum)
temperature_min = temperature_minimum
@@ -63,9 +64,10 @@
var/datum/chemical_reaction/D = new path()
var/list/reaction_ids = list()
if(D && length(D.required_reagents))
for(var/reaction in D.required_reagents)
reaction_ids += reaction
if(D && (length(D.required_reagents) || length(D.required_catalysts)))
var/list/all_requirements = D.required_reagents + D.required_catalysts
for(var/reagent_id in all_requirements)
reaction_ids += reagent_id
// Create filters based on each reagent id in the required reagents list
for(var/id in reaction_ids)
@@ -73,6 +75,9 @@
GLOB.chemical_reactions_list[id] = list()
GLOB.chemical_reactions_list[id] += D
break // Don't bother adding ourselves to other reagent ids, it is redundant.
if(my_atom)
RegisterSignal(my_atom, COMSIG_ATOM_RAD_ACT, PROC_REF(radiation_react))
ADD_TRAIT(my_atom, TRAIT_ABSORB_RADS, "reagents_holder_[UID()]")
/**
* Removes reagents from the holder until the passed amount is matched.
@@ -171,11 +176,16 @@
if(!O.reagents)
return
R = O.reagents
if(isliving(my_atom))
var/atom/thing = target
SEND_SIGNAL(thing, COMSIG_MOB_REAGENT_EXCHANGE, my_atom)
else if(isliving(target))
var/mob/living/M = target
if(!M.reagents)
return
R = M.reagents
if(isobj(my_atom))
SEND_SIGNAL(my_atom, COMSIG_MOB_REAGENT_EXCHANGE, target)
else if(istype(target, /datum/reagents))
R = target
else
@@ -186,7 +196,6 @@
var/trans_data = null
for(var/A in reagent_list)
var/datum/reagent/current_reagent = A
var/current_reagent_transfer = current_reagent.volume * part
if(preserve_data)
trans_data = copy_data(current_reagent)
@@ -199,6 +208,8 @@
if(!no_react)
R.handle_reactions()
handle_reactions()
R.temperature_react()
temperature_react()
return amount
/datum/reagents/proc/copy_to(obj/target, amount = 1, multiplier = 1, preserve_data = TRUE, safety = FALSE)
@@ -215,12 +226,15 @@
var/current_reagent_transfer = current_reagent.volume * part
if(preserve_data)
trans_data = copy_data(current_reagent)
R.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data)
update_total()
R.update_total()
R.handle_reactions()
handle_reactions()
R.temperature_react()
temperature_react()
return amount
/datum/reagents/proc/set_reagent_temp(new_temp = T0C, react = TRUE)
@@ -230,10 +244,17 @@
handle_reactions()
/datum/reagents/proc/temperature_react() //Calls the temperature reaction procs without changing the temp.
if(chem_temp > VIRUS_DISINFECTION_TEMP && isobj(my_atom))
SEND_SIGNAL(my_atom, COMSIG_ATOM_DISINFECTED)
for(var/A in reagent_list)
var/datum/reagent/current_reagent = A
current_reagent.reaction_temperature(chem_temp, 100)
/datum/reagents/proc/radiation_react(atom/source, amount, emission_type)
SIGNAL_HANDLER // COMSIG_ATOM_RAD_ACT
for(var/datum/reagent/current_reagent in reagent_list)
current_reagent.reaction_radiation(amount, emission_type)
/datum/reagents/proc/temperature_reagents(exposed_temperature, divisor = 35, change_cap = 15) //This is what you use to change the temp of a reagent holder.
//Do not manually change the reagent unless you know what youre doing.
var/difference = abs(chem_temp - exposed_temperature)
@@ -275,6 +296,8 @@
if(get_reagent_amount(reagent) < amount)
amount = get_reagent_amount(reagent)
amount = min(amount, R.maximum_volume - R.total_volume)
if(isliving(my_atom))
SEND_SIGNAL(target,COMSIG_MOB_REAGENT_EXCHANGE , my_atom)
var/trans_data = null
for(var/A in reagent_list)
var/datum/reagent/current_reagent = A
@@ -288,6 +311,7 @@
update_total()
R.update_total()
R.handle_reactions()
R.temperature_react()
return amount
@@ -492,7 +516,7 @@
var/preserved_data = null
for(var/B in C.required_reagents)
if(!preserved_data)
preserved_data = get_data(B)
preserved_data = copy_data_by_id(B)
remove_reagent(B, (multiplier * C.required_reagents[B]), safety = TRUE)
var/created_volume = C.result_amount*multiplier
@@ -690,6 +714,9 @@
if(total_volume + amount > maximum_volume) amount = (maximum_volume - total_volume) //Doesnt fit in. Make it disappear. Shouldnt happen. Will happen.
if(amount <= 0)
return FALSE
// Contaminate the container with viruses if the reagent has any. We do this here rather than a reaction because it only depends on the data, and not necessarily the reagent.
if(data && length(data["viruses"]) && isobj(my_atom))
my_atom.AddComponent(/datum/component/viral_contamination, data["viruses"])
chem_temp = clamp((chem_temp * total_volume + reagtemp * amount) / (total_volume + amount), temperature_min, temperature_max) //equalize with new chems
var/list/cached_reagents = reagent_list
@@ -888,6 +915,11 @@
if(R.id == reagent_id)
R.data = new_data
/datum/reagents/proc/copy_data_by_id(reagent_id)
for(var/datum/reagent/candidate in reagent_list)
if(candidate.id == reagent_id)
return(copy_data(candidate))
/datum/reagents/proc/copy_data(datum/reagent/current_reagent)
if(!current_reagent || !current_reagent.data)
return null
@@ -966,8 +998,7 @@
// Convenience proc to create a reagents holder for an atom
// Max vol is maximum volume of holder
/atom/proc/create_reagents(max_vol, temperature_minimum, temperature_maximum)
reagents = new /datum/reagents(max_vol, temperature_minimum, temperature_maximum)
reagents.my_atom = src
reagents = new /datum/reagents(max_vol, temperature_minimum, temperature_maximum, src)
/proc/get_random_reagent_id() // Returns a random reagent ID minus blacklisted reagents
var/static/list/random_reagents
@@ -1012,8 +1043,11 @@
reagent_list = null
QDEL_LIST_CONTENTS(addiction_list)
addiction_list = null
if(my_atom && my_atom.reagents == src)
my_atom.reagents = null
if(my_atom)
UnregisterSignal(my_atom, COMSIG_ATOM_RAD_ACT)
REMOVE_TRAIT(my_atom, TRAIT_ABSORB_RADS, "reagents_holder_[UID()]")
if(my_atom.reagents == src)
my_atom.reagents = null
my_atom = null
#undef ADDICTION_TIME
@@ -36,6 +36,13 @@
required_reagents = list("carpotoxin" = 1, "spaceacillin" = 1, "copper" = 1)
result_amount = 3
/datum/chemical_reaction/sterilizine
name = "Sterilizine"
id = "sterilizine"
result = "sterilizine"
required_reagents = list("antihol" = 2, "chlorine" = 1)
result_amount = 3
/datum/chemical_reaction/charcoal
name = "Charcoal"
id = "charcoal"
@@ -414,6 +414,20 @@
required_reagents = list("salglu_solution" = 1, "mutagenvirusfood" = 1)
result_amount = 2
/datum/chemical_reaction/virus_food_mutadone
name = "stable agar"
id = "stable_agar"
result = "stable_agar"
required_reagents = list("mutadone" = 1, "virusfood" = 1)
result_amount = 2
/datum/chemical_reaction/virus_food_tracker
name = "Tracking agar"
id = "tracking_agar"
result = "tracking_agar"
required_reagents = list("fluorosurfactant" = 1, "virusfood" = 1)
result_amount = 2
/datum/chemical_reaction/mix_virus
name = "Mix Virus"
id = "mixvirus"
@@ -499,6 +513,43 @@
if(D)
D.Devolve()
/datum/chemical_reaction/mix_virus/stabilize_virus
name = "Stabilize Virus"
id = "stabilize_virus"
required_reagents = list("stable_agar" = 1)
/datum/chemical_reaction/mix_virus/stabilize_virus/on_reaction(datum/reagents/holder, created_volume)
var/datum/reagent/blood/B = locate(/datum/reagent/blood) in holder.reagent_list
if(B && B.data)
var/datum/disease/advance/D = locate(/datum/disease/advance) in B.data["viruses"]
if(istype(D))
D.evolution_chance = 0
/datum/chemical_reaction/mix_virus/track_virus
name = "Track Virus"
id = "track_virus"
required_reagents = list("tracking_agar" = 1)
/datum/chemical_reaction/mix_virus/track_virus/on_reaction(datum/reagents/holder, created_volume)
var/datum/reagent/blood/B = locate(/datum/reagent/blood) in holder.reagent_list
if(B && B.data)
var/datum/disease/advance/D = locate(/datum/disease/advance) in B.data["viruses"]
if(istype(D))
D.tracker = D.GetDiseaseID()
/datum/chemical_reaction/mix_virus/clear_virus
name = "Clear Virus"
id = "clear_virus"
required_reagents = list("viral_eraser" = 10)
/datum/chemical_reaction/mix_virus/clear_virus/on_reaction(datum/reagents/holder, created_volume)
var/datum/reagent/blood/B = locate(/datum/reagent/blood) in holder.reagent_list
if(B && B.data)
var/datum/disease/advance/D = locate(/datum/disease/advance) in B.data["viruses"]
if(istype(D))
D.tracker = ""
D.evolution_chance = VIRUS_EVOLUTION_CHANCE
// Someday, maybe add some version of doing science on patient zero to discover the recipees.
/datum/chemical_reaction/zombie
name = "Anti-Plague Sequence Alpha"
@@ -575,7 +626,7 @@
result = "zombiecure4"
cure_level = 4
amt_req_cures = 2
required_symptom = /datum/symptom/heal/metabolism
required_symptom = /datum/symptom/heal
/datum/chemical_reaction/zombie/four/get_possible_cures()
return list("colorful_reagent", "bacchus_blessing", "pen_acid", "glyphosate", "lazarus_reagent", "omnizine", "sarin", "ants", "clf3", "sorium", "????", "aranesp")
@@ -512,6 +512,28 @@
/datum/chemical_reaction/slimemutate2/on_reaction(datum/reagents/holder)
SSblackbox.record_feedback("tally", "slime_cores_used", 1, type)
/datum/chemical_reaction/viral_gene_extraction
name = "Virus Gene Extraction"
id = "virus_gene_extraction"
result = "virus_genes"
required_reagents = list("blood" = 1)
result_amount = 1
required_other = TRUE
required_container = /obj/item/slime_extract/black
/datum/chemical_reaction/viral_gene_extraction/on_reaction(datum/reagents/holder)
SSblackbox.record_feedback("tally", "slime_cores_used", 1, type)
var/obj/item/reagent_containers/glass/bottle/result_bottle = new(get_turf(holder.my_atom))
holder.trans_to(result_bottle, holder.total_volume)
var/datum/reagent/virus_genes/result_genes = locate() in result_bottle.reagents.reagent_list
var/list/strains = list("slime" = list())
if(result_genes.data && result_genes.data["viruses"])
for(var/datum/disease/advance/advanced_virus in result_genes.data["viruses"])
strains["slime"] += list(advanced_virus.strain)
result_bottle.name = "[advanced_virus.strain] Strain Viral Genetic Matter"
break
result_genes.data = strains
//Oil
/datum/chemical_reaction/slime_explosion
name = "Slime Explosion"
@@ -302,6 +302,26 @@
desc = "A small bottle. Contains H0NI<42 virion culture in synthblood medium."
spawned_disease = /datum/disease/pierrot_throat
/obj/item/reagent_containers/glass/bottle/tracking_agar
name = "Tracking agar bottle"
desc = "A small bottle. Contains tracking agar which allows modifying a virus without needing to reanalyze it"
list_reagents = list("tracking_agar" = 50)
/obj/item/reagent_containers/glass/bottle/stable_agar
name = "Stable agar bottle"
desc = "A small bottle. Contains stable agar which stop a virus from being able to mutate on its own"
list_reagents = list("stable_agar" = 50)
/obj/item/reagent_containers/glass/bottle/sterilizine
name = "Sterilizine bottle"
desc = "A small bottle. Contains sterilizine, which is used to sterilize beakers and syringes"
list_reagents = list("sterilizine" = 50)
/obj/item/reagent_containers/glass/bottle/viral_eraser
name = "Viral eraser bottle"
desc = "A small bottle. Contains a small amount of viral eraser which removes all tracking and stabilizing from a virus"
list_reagents = list("viral_eraser" = 10)
/obj/item/reagent_containers/glass/bottle/cold
name = "Rhinovirus culture bottle"
desc = "A small bottle. Contains XY-rhinovirus culture in synthblood medium."
@@ -63,11 +63,20 @@
add_attack_logs(user, target, "Fed with [name] containing [contained]", !!target.ckey ? null : ATKLOG_ALL)
else
to_chat(user, "<span class='notice'>You swallow a gulp of [src].</span>")
var/fraction = min(5 / reagents.total_volume, 1)
reagents.reaction(target, REAGENT_INGEST, fraction)
addtimer(CALLBACK(reagents, TYPE_PROC_REF(/datum/reagents, trans_to), target, 5), 5)
playsound(target.loc,'sound/items/drink.ogg', rand(10,50), TRUE)
// Add viruses where needed
if(length(target.viruses))
AddComponent(/datum/component/viral_contamination, target.viruses)
// Infect contained blood as well for splash reactions
var/datum/reagent/blood/blood_contained = locate() in reagents.reagent_list
if(blood_contained?.data["viruses"])
var/list/blood_viruses = blood_contained.data["viruses"]
blood_viruses |= target.viruses.Copy()
blood_contained.data["viruses"] = blood_viruses
SEND_SIGNAL(src, COMSIG_MOB_REAGENT_EXCHANGE, target)
/obj/item/reagent_containers/glass/normal_act(atom/target, mob/living/user)
if(!check_allowed_items(target, target_self = TRUE) || !is_open_container() || !reagents)
@@ -54,6 +54,8 @@
/obj/item/reagent_containers/iv_bag/proc/begin_processing(mob/target)
injection_target = target
if(target.viruses)
AddComponent(/datum/component/viral_contamination, target.viruses)
RegisterSignal(injection_target, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine))
START_PROCESSING(SSobj, src)
update_iv_type()
@@ -188,6 +188,10 @@
var/fraction = min(amount_per_transfer_from_this / reagents.total_volume, 1)
reagents.reaction(target, REAGENT_INGEST, fraction)
reagents.trans_to(target, amount_per_transfer_from_this)
if(iscarbon(target))
var/mob/living/carbon/carbon_target = target
if(length(carbon_target.viruses))
AddComponent(/datum/component/viral_contamination, carbon_target.viruses)
to_chat(user, "<span class='notice'>You inject [amount_per_transfer_from_this] units of the solution. The syringe now contains [reagents.total_volume] units.</span>")
if(reagents.total_volume <= 0 && mode == SYRINGE_INJECT)
mode = SYRINGE_DRAW