mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 20:48:56 +01:00
Disease Outbreak: Advanced v3 (#73092)
## About The Pull Request PR to replace https://github.com/tgstation/tgstation/pull/73001 Revamps the Disease Outbreak: Advanced random event to be more consistent in actually generating random diseases. This generates random viruses based on rolling severity, symptoms, and transmissibility separately and ensures the virus created through RNG is valid and transmissible. Revamps menu for admin spawned DO:A events. Custom outbreak with manual symptom selection is available in the Secrets panel. Parameters for generating the viruses can be tweaked using the defines in the event file. ## Why It's Good For The Game Current DO:A code has a tendency to generate viruses that aren't actually transmissible, be it through choosing too many symptoms or having a transmissibility that's too low to allow spread. ## Changelog 🆑 LT3 refactor: Rewrite of random event Disease Outbreak: Advanced. Listen to those level 7 biohazard warnings! admin: Fully customizable build-your-own virus is available in the admin Secrets panel, for those people you really hate /🆑 --------- Co-authored-by: san7890 <the@san7890.com>
This commit is contained in:
@@ -499,3 +499,16 @@
|
||||
|
||||
/datum/disease/advance/proc/totalTransmittable()
|
||||
return properties["transmittable"]
|
||||
|
||||
/**
|
||||
* Make virus visible to heath scanners
|
||||
*/
|
||||
/datum/disease/advance/proc/MakeVisible()
|
||||
visibility_flags &= ~HIDDEN_SCANNER
|
||||
for(var/datum/disease/advance/virus in SSdisease.active_diseases)
|
||||
if(!virus.id)
|
||||
stack_trace("Advanced virus ID is empty or null!")
|
||||
return
|
||||
|
||||
if(virus.id == id)
|
||||
virus.visibility_flags &= ~HIDDEN_SCANNER
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
/// Advanced virus lower limit for symptoms
|
||||
#define ADV_MIN_SYMPTOMS 3
|
||||
/// Advanced virus upper limit for symptoms
|
||||
#define ADV_MAX_SYMPTOMS 4
|
||||
/// How long the virus stays hidden before announcement
|
||||
#define ADV_ANNOUNCE_DELAY 75
|
||||
/// Numerical define for medium severity advanced virus
|
||||
#define ADV_DISEASE_MEDIUM 4
|
||||
/// Numerical define for harmful severity advanced virus
|
||||
#define ADV_DISEASE_HARMFUL 5
|
||||
/// Numerical define for dangerous severity advanced virus
|
||||
#define ADV_DISEASE_DANGEROUS 7
|
||||
/// Percentile for low severity advanced virus
|
||||
#define ADV_RNG_LOW 30
|
||||
/// Percentile for mid severity advanced virus
|
||||
#define ADV_RNG_MID 85
|
||||
/// Percentile for low transmissibility advanced virus
|
||||
#define ADV_SPREAD_LOW 30
|
||||
/// Percentile for mid transmissibility advanced virus
|
||||
#define ADV_SPREAD_MID 90
|
||||
|
||||
/datum/round_event_control/disease_outbreak
|
||||
name = "Disease Outbreak: Classic"
|
||||
typepath = /datum/round_event/disease_outbreak
|
||||
@@ -5,7 +26,7 @@
|
||||
min_players = 10
|
||||
weight = 5
|
||||
category = EVENT_CATEGORY_HEALTH
|
||||
description = "A 'classic' virus will infect some members of the crew." //These are the ones with PERSONALITY
|
||||
description = "A 'classic' virus will infect some members of the crew."
|
||||
admin_setup = /datum/event_admin_setup/disease_outbreak
|
||||
///Disease recipient candidates
|
||||
var/list/disease_candidates = list()
|
||||
@@ -35,8 +56,31 @@
|
||||
continue
|
||||
disease_candidates += candidate
|
||||
|
||||
/datum/event_admin_setup/disease_outbreak
|
||||
///Admin selected disease, to be passed down to the round_event
|
||||
var/virus_type
|
||||
|
||||
/// Checks for candidates. Returns false if there isn't enough
|
||||
/datum/event_admin_setup/disease_outbreak/proc/candidate_check()
|
||||
var/datum/round_event_control/disease_outbreak/disease_control = event_control
|
||||
disease_control.generate_candidates() //can_spawn_event() is bypassed by admin_setup, so this makes sure that the candidates are still generated
|
||||
return length(disease_control.disease_candidates)
|
||||
|
||||
/datum/event_admin_setup/disease_outbreak/prompt_admins()
|
||||
var/candidate_count = candidate_check()
|
||||
if(!candidate_count)
|
||||
tgui_alert(usr, "There are no candidates eligible to recieve a disease!", "Error")
|
||||
return ADMIN_CANCEL_EVENT
|
||||
tgui_alert(usr, "[candidate_count] candidates found!", "Disease Outbreak")
|
||||
|
||||
if(tgui_alert(usr, "Select a specific disease?", "Sickening behavior", list("Yes", "No")) == "Yes")
|
||||
virus_type = tgui_input_list(usr, "Warning: Some of these are EXTREMELY dangerous.","Bacteria Hysteria", subtypesof(/datum/disease))
|
||||
|
||||
/datum/event_admin_setup/disease_outbreak/apply_to_event(datum/round_event/disease_outbreak/event)
|
||||
event.virus_type = virus_type
|
||||
|
||||
/datum/round_event/disease_outbreak
|
||||
announce_when = 120
|
||||
announce_when = ADV_ANNOUNCE_DELAY
|
||||
///The disease type we will be spawning
|
||||
var/datum/disease/virus_type
|
||||
///Disease recipient candidates, passed from the round_event_control object
|
||||
@@ -46,7 +90,7 @@
|
||||
priority_announce("Confirmed outbreak of level 7 viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", ANNOUNCER_OUTBREAK7)
|
||||
|
||||
/datum/round_event/disease_outbreak/setup()
|
||||
announce_when = rand(60, 180)
|
||||
announce_when = ADV_ANNOUNCE_DELAY
|
||||
|
||||
/datum/round_event/disease_outbreak/start()
|
||||
var/datum/round_event_control/disease_outbreak/disease_event = control
|
||||
@@ -83,81 +127,247 @@
|
||||
name = "Disease Outbreak: Advanced"
|
||||
typepath = /datum/round_event/disease_outbreak/advanced
|
||||
category = EVENT_CATEGORY_HEALTH
|
||||
description = "An 'advanced' disease will infect some members of the crew." //These are the ones that get viro lynched!
|
||||
weight = 10
|
||||
description = "An 'advanced' disease will infect some members of the crew."
|
||||
admin_setup = /datum/event_admin_setup/disease_outbreak/advanced
|
||||
|
||||
/datum/event_admin_setup/disease_outbreak/advanced
|
||||
///Admin selected custom severity rating for the event
|
||||
var/chosen_severity
|
||||
///Admin selected custom value for the maximum symptoms this virus should have
|
||||
var/chosen_max_symptoms
|
||||
|
||||
/**
|
||||
* Admin virus customization
|
||||
*
|
||||
* If the admin wishes, give them the opportunity to select the severity and number of symptoms.
|
||||
*/
|
||||
/datum/event_admin_setup/disease_outbreak/advanced/prompt_admins()
|
||||
var/candidate_count = candidate_check()
|
||||
if(!candidate_count)
|
||||
tgui_alert(usr, "There are no candidates eligible to recieve a disease!", "Error")
|
||||
return ADMIN_CANCEL_EVENT
|
||||
tgui_alert(usr, "[candidate_count] candidates found!", "Disease Outbreak")
|
||||
|
||||
if(tgui_alert(usr,"Customize your virus?", "Glorified Debug Tool", list("Yes", "No")) == "Yes")
|
||||
chosen_severity = tgui_alert(usr, "Pick a severity!", "In the event of an airborne virus, try not to breathe.", list("Medium", "Harmful", "Dangerous"))
|
||||
switch(chosen_severity)
|
||||
if("Medium")
|
||||
chosen_severity = ADV_DISEASE_MEDIUM
|
||||
if("Harmful")
|
||||
chosen_severity = ADV_DISEASE_HARMFUL
|
||||
if("Dangerous")
|
||||
chosen_severity = ADV_DISEASE_DANGEROUS
|
||||
else
|
||||
return ADMIN_CANCEL_EVENT
|
||||
|
||||
chosen_max_symptoms = tgui_input_number(usr, "How many symptoms do you want your virus to have?", "A pox upon ye!", 4, 15)
|
||||
|
||||
else
|
||||
chosen_severity = null
|
||||
chosen_max_symptoms = null
|
||||
|
||||
if(tgui_alert(usr,"Are you happy with your selections?", "Epidemic warning, Standby!", list("Yes", "Cancel")) != "Yes")
|
||||
return ADMIN_CANCEL_EVENT
|
||||
|
||||
/datum/event_admin_setup/disease_outbreak/advanced/apply_to_event(datum/round_event/disease_outbreak/advanced/event)
|
||||
event.max_severity = chosen_severity
|
||||
event.max_symptoms = chosen_max_symptoms
|
||||
|
||||
/datum/round_event/disease_outbreak/advanced
|
||||
///Number of symptoms for our virus
|
||||
var/max_severity
|
||||
//Maximum symptoms for our virus
|
||||
var/max_symptoms
|
||||
|
||||
/**
|
||||
* Generate virus base values
|
||||
*
|
||||
* Generates a virus with either the admin selected parameters for severity and symptoms
|
||||
* or if it was not selected, randomly pick between the MIX and MAX configured in the defines.
|
||||
*/
|
||||
/datum/round_event/disease_outbreak/advanced/start()
|
||||
var/datum/round_event_control/disease_outbreak/advanced/disease_event = control
|
||||
afflicted += disease_event.disease_candidates
|
||||
disease_event.disease_candidates.Cut() //Clean the list after use
|
||||
disease_event.disease_candidates.Cut()
|
||||
|
||||
if(!max_symptoms)
|
||||
max_symptoms = 3 + max(FLOOR((world.time - control.earliest_start)/6000, 1),0) //3 symptoms at 20 minutes, plus 1 per 10 minutes.
|
||||
max_symptoms = clamp(max_symptoms, 3, 8) //Capping the virus symptoms prevents the event from becoming "smite one poor player with an -12 transmission hell virus" after a certain round length.
|
||||
max_symptoms = rand(ADV_MIN_SYMPTOMS, ADV_MAX_SYMPTOMS)
|
||||
|
||||
if(!max_severity)
|
||||
max_severity = 3 + max(FLOOR((world.time - control.earliest_start)/6000, 1),0) //Max severity doesn't need clamping
|
||||
var/rng_severity = rand(1, 100)
|
||||
if(rng_severity < ADV_RNG_LOW)
|
||||
max_severity = ADV_DISEASE_MEDIUM
|
||||
|
||||
var/datum/disease/advance/advanced_disease = new /datum/disease/advance/random(max_symptoms, max_severity)
|
||||
else if(rng_severity < ADV_RNG_MID)
|
||||
max_severity = ADV_DISEASE_HARMFUL
|
||||
|
||||
var/list/name_symptoms = list() //for feedback
|
||||
for(var/datum/symptom/new_symptom in advanced_disease.symptoms)
|
||||
else
|
||||
max_severity = ADV_DISEASE_DANGEROUS
|
||||
|
||||
var/datum/disease/advance/advanced_disease = new /datum/disease/advance/random/event(max_symptoms, max_severity)
|
||||
|
||||
var/list/name_symptoms = list()
|
||||
for(var/datum/symptom/new_symptom as anything in advanced_disease.symptoms)
|
||||
name_symptoms += new_symptom.name
|
||||
|
||||
var/mob/living/carbon/human/victim = pick_n_take(afflicted)
|
||||
if(victim.ForceContractDisease(advanced_disease, FALSE))
|
||||
message_admins("An event has triggered a random advanced virus outbreak on [ADMIN_LOOKUPFLW(victim)]! It has these symptoms: [english_list(name_symptoms)]")
|
||||
log_game("An event has triggered a random advanced virus outbreak on [key_name(victim)]! It has these symptoms: [english_list(name_symptoms)].")
|
||||
message_admins("An event has triggered a random advanced virus outbreak on [ADMIN_LOOKUPFLW(victim)]! It has these symptoms: [english_list(name_symptoms)]. It is transmissable via [advanced_disease.spread_text].")
|
||||
log_game("An event has triggered a random advanced virus outbreak on [key_name(victim)]! It has these symptoms: [english_list(name_symptoms)]. It is transmissable via [advanced_disease.spread_text].")
|
||||
announce_to_ghosts(victim)
|
||||
else
|
||||
log_game("An event attempted to trigger a random advanced virus outbreak on [key_name(victim)], but failed.")
|
||||
|
||||
/datum/event_admin_setup/disease_outbreak
|
||||
///Admin selected disease, to be passed down to the round_event
|
||||
var/virus_type
|
||||
/datum/disease/advance/random/event
|
||||
name = "Experimental Disease"
|
||||
copy_type = /datum/disease/advance
|
||||
|
||||
/// Checks for candidates. Returns false if there isn't enough
|
||||
/datum/event_admin_setup/disease_outbreak/proc/candidate_check()
|
||||
var/datum/round_event_control/disease_outbreak/disease_control = event_control
|
||||
disease_control.generate_candidates() //can_spawn_event() is bypassed by admin_setup, so this makes sure that the candidates are still generated
|
||||
return length(disease_control.disease_candidates)
|
||||
/datum/round_event/disease_outbreak/advance/setup()
|
||||
announce_when = ADV_ANNOUNCE_DELAY
|
||||
|
||||
/datum/event_admin_setup/disease_outbreak/prompt_admins()
|
||||
var/candidate_count = candidate_check()
|
||||
if(!candidate_check())
|
||||
tgui_alert(usr, "There are no candidates eligible to recieve a disease!", "Error")
|
||||
return ADMIN_CANCEL_EVENT
|
||||
tgui_alert(usr, "[candidate_count] candidates found!", "Disease Outbreak")
|
||||
/**
|
||||
* Generate advanced virus
|
||||
*
|
||||
* Uses the parameters to create a list of symptoms, picking from various severities
|
||||
* Viral Evolution and Eternal Youth are special modifiers, so we roll separately.
|
||||
*/
|
||||
|
||||
if(tgui_alert(usr, "Select a specific disease?", "Sickening behavior", list("Yes", "No")) == "Yes")
|
||||
virus_type = tgui_input_list(usr, "Warning: Some of these are EXTREMELY dangerous.","Bacteria Hysteria", subtypesof(/datum/disease))
|
||||
/datum/disease/advance/random/event/New(max_symptoms, max_severity)
|
||||
var/list/datum/symptom/possible_symptoms = list(
|
||||
/datum/symptom/beard,
|
||||
/datum/symptom/chills,
|
||||
/datum/symptom/choking,
|
||||
/datum/symptom/confusion,
|
||||
/datum/symptom/cough,
|
||||
/datum/symptom/deafness,
|
||||
/datum/symptom/dizzy,
|
||||
/datum/symptom/fever,
|
||||
/datum/symptom/headache,
|
||||
/datum/symptom/itching,
|
||||
/datum/symptom/shedding,
|
||||
/datum/symptom/sneeze,
|
||||
/datum/symptom/vomit,
|
||||
/datum/symptom/weight_loss,
|
||||
)
|
||||
|
||||
/datum/event_admin_setup/disease_outbreak/apply_to_event(datum/round_event/disease_outbreak/event)
|
||||
event.virus_type = virus_type
|
||||
switch(max_severity)
|
||||
if(ADV_DISEASE_HARMFUL)
|
||||
possible_symptoms += list(
|
||||
/datum/symptom/disfiguration,
|
||||
/datum/symptom/hallucigen,
|
||||
/datum/symptom/polyvitiligo,
|
||||
/datum/symptom/visionloss,
|
||||
)
|
||||
|
||||
/datum/event_admin_setup/disease_outbreak/advanced
|
||||
///Admin selected custom severity rating for the event
|
||||
var/max_severity
|
||||
///Admin selected custom value for the maximum symptoms this virus should have
|
||||
var/max_symptoms
|
||||
if(ADV_DISEASE_DANGEROUS)
|
||||
possible_symptoms += list(
|
||||
/datum/symptom/alkali,
|
||||
/datum/symptom/asphyxiation,
|
||||
/datum/symptom/fire,
|
||||
/datum/symptom/flesh_death,
|
||||
/datum/symptom/flesh_eating,
|
||||
/datum/symptom/narcolepsy,
|
||||
/datum/symptom/voice_change,
|
||||
)
|
||||
|
||||
/datum/event_admin_setup/disease_outbreak/advanced/prompt_admins()
|
||||
var/candidate_count = candidate_check()
|
||||
if(!candidate_check())
|
||||
tgui_alert(usr, "There are no candidates eligible to recieve a disease!", "Error")
|
||||
return ADMIN_CANCEL_EVENT
|
||||
tgui_alert(usr, "[candidate_count] candidates found!", "Disease Outbreak")
|
||||
for(var/i in 1 to max_symptoms)
|
||||
var/datum/symptom/chosen_symptom = pick_n_take(possible_symptoms)
|
||||
if(chosen_symptom)
|
||||
var/datum/symptom/new_symptom = new chosen_symptom
|
||||
symptoms += new_symptom
|
||||
|
||||
if(tgui_alert(usr,"Customize your virus?", "Glorified Debug Tool", list("Yes", "No")) == "Yes")
|
||||
max_severity = tgui_input_number(usr, "Select a custom severity for your virus!", "Plague Incorporation!", 3, 8)
|
||||
max_symptoms = tgui_input_number(usr, "How many symptoms do you want your virus to have?", "A pox upon ye!", 3, 15)
|
||||
if(prob(50))
|
||||
symptoms += new /datum/symptom/viralevolution
|
||||
|
||||
/datum/event_admin_setup/disease_outbreak/advanced/apply_to_event(datum/round_event/disease_outbreak/advanced/event)
|
||||
event.max_severity = max_severity
|
||||
event.max_symptoms = max_symptoms
|
||||
if(prob(50))
|
||||
symptoms += new /datum/symptom/youth
|
||||
|
||||
Refresh()
|
||||
|
||||
name = "Sample #[rand(1, 9999)]"
|
||||
|
||||
/**
|
||||
* Assign virus properties
|
||||
*
|
||||
* Now that we've picked our symptoms and severity, we determine the other stats
|
||||
* (Stage Speed, Resistance, Transmissibility)
|
||||
* The LOW/MID percentiles can be adjusted in the defines.
|
||||
* If the virus is severity DANGEROUS we do not hide it from health scanners at event start.
|
||||
* If the virus is airborne, also don't hide it.
|
||||
*/
|
||||
/datum/disease/advance/random/event/AssignProperties()
|
||||
var/transmissibility = rand(1, 100)
|
||||
|
||||
addtimer(CALLBACK(src, PROC_REF(MakeVisible)), ((ADV_ANNOUNCE_DELAY * 2) - 10) SECONDS)
|
||||
|
||||
if(length(properties))
|
||||
spreading_modifier = max(CEILING(0.4 * properties["transmittable"], 1), 1)
|
||||
cure_chance = clamp(7.5 - (0.5 * properties["resistance"]), 5, 10) // Can be between 5 and 10
|
||||
stage_prob = max(0.5 * properties["stage_rate"], 1)
|
||||
SetSeverity(properties["severity"])
|
||||
visibility_flags |= HIDDEN_SCANNER
|
||||
switch(severity)
|
||||
if("Dangerous", "BIOHAZARD")
|
||||
visibility_flags &= ~HIDDEN_SCANNER
|
||||
|
||||
GenerateCure(properties)
|
||||
|
||||
if(transmissibility < ADV_SPREAD_LOW)
|
||||
SetSpread(DISEASE_SPREAD_CONTACT_FLUIDS)
|
||||
|
||||
else if(transmissibility < ADV_SPREAD_MID)
|
||||
SetSpread(DISEASE_SPREAD_CONTACT_SKIN)
|
||||
|
||||
else
|
||||
SetSpread(DISEASE_SPREAD_AIRBORNE)
|
||||
visibility_flags &= ~HIDDEN_SCANNER
|
||||
|
||||
else
|
||||
CRASH("Advanced virus properties were empty or null!")
|
||||
|
||||
/**
|
||||
* Set the transmission methods on the generated virus
|
||||
*
|
||||
* Apply the transmission methods we rolled in the AssignProperties proc
|
||||
*/
|
||||
/datum/disease/advance/random/event/SetSpread(spread_id)
|
||||
switch(spread_id)
|
||||
if(DISEASE_SPREAD_CONTACT_FLUIDS)
|
||||
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_FLUIDS
|
||||
spread_text = "fluids"
|
||||
if(DISEASE_SPREAD_CONTACT_SKIN)
|
||||
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_FLUIDS | DISEASE_SPREAD_CONTACT_SKIN
|
||||
spread_text = "skin contact"
|
||||
if(DISEASE_SPREAD_AIRBORNE)
|
||||
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_FLUIDS | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_AIRBORNE
|
||||
spread_text = "respiration"
|
||||
|
||||
/**
|
||||
* Determine the cure
|
||||
*
|
||||
* Rolls one of six possible cure groups, then selects a cure from it and applies it to the virus.
|
||||
*/
|
||||
/datum/disease/advance/random/event/GenerateCure()
|
||||
if(!length(properties))
|
||||
stack_trace("Advanced virus properties were empty or null!")
|
||||
return
|
||||
var/res = rand(1, 6)
|
||||
if(res == oldres)
|
||||
return
|
||||
cures = list(pick(advance_cures[res]))
|
||||
oldres = res
|
||||
// Get the cure name from the cure_id
|
||||
var/datum/reagent/cure = GLOB.chemical_reagents_list[cures[1]]
|
||||
cure_text = cure.name
|
||||
|
||||
#undef ADV_MIN_SYMPTOMS
|
||||
#undef ADV_MAX_SYMPTOMS
|
||||
#undef ADV_ANNOUNCE_DELAY
|
||||
#undef ADV_DISEASE_MEDIUM
|
||||
#undef ADV_DISEASE_HARMFUL
|
||||
#undef ADV_DISEASE_DANGEROUS
|
||||
#undef ADV_RNG_LOW
|
||||
#undef ADV_RNG_MID
|
||||
#undef ADV_SPREAD_LOW
|
||||
#undef ADV_SPREAD_MID
|
||||
|
||||
Reference in New Issue
Block a user