mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-28 22:47:59 +01:00
/tg/ui Virology PanD.E.M.I.C 2200 (PanDEMIC) (#24533)
* /tg/ui PanDEMIC * Fix types on booleans * [ci skip] * Fix oversights [ci skip] * Fix styling * Apply suggestions from code review Co-authored-by: Aylong <69762909+AyIong@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Aylong <69762909+AyIong@users.noreply.github.com> * Remove unused field * Optimize ui_data * Make clone cooldown spin * Change unit [ci skip] * Remove use of !! * Fix Flex style prop accidental override * Rewrite Stack to Flex * Revert changes to Stack * [ci skip] * Build and update tgui * Move force update code * Build and update tgui * trigger ci * Fix style --------- Co-authored-by: Arthri <41360489+a@users.noreply.github.com> Co-authored-by: Aylong <69762909+AyIong@users.noreply.github.com> Co-authored-by: /tg/ui Builder <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
This commit is contained in:
co-authored by
Aylong
Arthri
/tg/ui Builder <41898282+github-actions[bot]@users.noreply.github.com>
Burzah
parent
38d16c4698
commit
4e036c77e3
@@ -187,7 +187,7 @@ SUBSYSTEM_DEF(tgui)
|
||||
*
|
||||
* return int The number of UIs updated.
|
||||
*/
|
||||
/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object)
|
||||
/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object, full_update = FALSE)
|
||||
var/count = 0
|
||||
var/key = "[src_object.UID()]"
|
||||
// No UIs opened for this src_object
|
||||
@@ -196,7 +196,10 @@ SUBSYSTEM_DEF(tgui)
|
||||
for(var/datum/tgui/ui in open_uis_by_src[key])
|
||||
// Check if UI is valid.
|
||||
if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user))
|
||||
ui.process(force = TRUE)
|
||||
if(full_update)
|
||||
ui.send_full_update(null, TRUE)
|
||||
else
|
||||
ui.process(force = TRUE)
|
||||
count++
|
||||
return count
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
var/temp_html = ""
|
||||
var/printing = null
|
||||
var/wait = null
|
||||
var/selected_strain_index = 1
|
||||
var/obj/item/reagent_containers/beaker = null
|
||||
|
||||
/obj/machinery/computer/pandemic/Initialize(mapload)
|
||||
@@ -26,23 +27,33 @@
|
||||
stat |= BROKEN
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/computer/pandemic/proc/GetVirusByIndex(index)
|
||||
/obj/machinery/computer/pandemic/proc/GetViruses()
|
||||
if(beaker && beaker.reagents)
|
||||
if(length(beaker.reagents.reagent_list))
|
||||
var/datum/reagent/blood/BL = locate() in beaker.reagents.reagent_list
|
||||
if(BL)
|
||||
if(BL.data && BL.data["viruses"])
|
||||
var/list/viruses = BL.data["viruses"]
|
||||
return viruses[index]
|
||||
return viruses
|
||||
|
||||
/obj/machinery/computer/pandemic/proc/GetResistancesByIndex(index)
|
||||
/obj/machinery/computer/pandemic/proc/GetVirusByIndex(index)
|
||||
var/list/viruses = GetViruses()
|
||||
if(viruses && index > 0 && index <= length(viruses))
|
||||
return viruses[index]
|
||||
|
||||
/obj/machinery/computer/pandemic/proc/GetResistances()
|
||||
if(beaker && beaker.reagents)
|
||||
if(length(beaker.reagents.reagent_list))
|
||||
var/datum/reagent/blood/BL = locate() in beaker.reagents.reagent_list
|
||||
if(BL)
|
||||
if(BL.data && BL.data["resistances"])
|
||||
var/list/resistances = BL.data["resistances"]
|
||||
return resistances[index]
|
||||
return resistances
|
||||
|
||||
/obj/machinery/computer/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)
|
||||
var/datum/disease/D = GetVirusByIndex(index)
|
||||
@@ -68,117 +79,233 @@
|
||||
if(!wait)
|
||||
. += "waitlight"
|
||||
|
||||
/obj/machinery/computer/pandemic/Topic(href, href_list)
|
||||
/obj/machinery/computer/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 = "round_bottle"
|
||||
B.pixel_x = rand(-3, 3)
|
||||
B.pixel_y = rand(-3, 3)
|
||||
replicator_cooldown(cooldown)
|
||||
B.name = "[name] [bottle_type] bottle"
|
||||
return B
|
||||
|
||||
/obj/machinery/computer/pandemic/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
if(..())
|
||||
return
|
||||
|
||||
usr.set_machine(src)
|
||||
if(!beaker) return
|
||||
|
||||
if(href_list["create_vaccine"])
|
||||
if(!wait)
|
||||
var/obj/item/reagent_containers/glass/bottle/B = new/obj/item/reagent_containers/glass/bottle(loc)
|
||||
if(B)
|
||||
B.pixel_x = rand(-3, 3)
|
||||
B.pixel_y = rand(-3, 3)
|
||||
var/path = GetResistancesByIndex(text2num(href_list["create_vaccine"]))
|
||||
var/vaccine_type = path
|
||||
var/vaccine_name = "Unknown"
|
||||
|
||||
if(!ispath(vaccine_type))
|
||||
if(GLOB.archive_diseases[path])
|
||||
var/datum/disease/D = GLOB.archive_diseases[path]
|
||||
if(D)
|
||||
vaccine_name = D.name
|
||||
vaccine_type = path
|
||||
else if(vaccine_type)
|
||||
var/datum/disease/D = new vaccine_type(0, null)
|
||||
if(D)
|
||||
vaccine_name = D.name
|
||||
|
||||
if(vaccine_type)
|
||||
|
||||
B.name = "[vaccine_name] vaccine bottle"
|
||||
B.reagents.add_reagent("vaccine", 15, list(vaccine_type))
|
||||
replicator_cooldown(200)
|
||||
else
|
||||
temp_html = "The replicator is not ready yet."
|
||||
updateUsrDialog()
|
||||
if(inoperable())
|
||||
return
|
||||
else if(href_list["create_virus_culture"])
|
||||
if(!wait)
|
||||
var/type = GetVirusTypeByIndex(text2num(href_list["create_virus_culture"]))//the path is received as string - converting
|
||||
|
||||
|
||||
. = TRUE
|
||||
|
||||
switch(action)
|
||||
if("clone_strain")
|
||||
if(wait)
|
||||
atom_say("The replicator is not ready yet.")
|
||||
return
|
||||
|
||||
var/strain_index = text2num(params["strain_index"])
|
||||
if(isnull(strain_index))
|
||||
atom_say("Unable to respond to command.")
|
||||
return
|
||||
var/datum/disease/virus = GetVirusByIndex(strain_index)
|
||||
var/datum/disease/D = null
|
||||
if(!virus)
|
||||
atom_say("Unable to find requested strain.")
|
||||
return
|
||||
var/type = virus.GetDiseaseID()
|
||||
if(!ispath(type))
|
||||
D = GetVirusByIndex(text2num(href_list["create_virus_culture"]))
|
||||
var/datum/disease/advance/A = GLOB.archive_diseases[D.GetDiseaseID()]
|
||||
var/datum/disease/advance/A = GLOB.archive_diseases[type]
|
||||
if(A)
|
||||
D = new A.type(0, A)
|
||||
else if(type)
|
||||
if(type in GLOB.diseases) // Make sure this is a disease
|
||||
D = new type(0, null)
|
||||
if(!D)
|
||||
atom_say("Unable to synthesize requested strain.")
|
||||
return
|
||||
var/name = tgui_input_text(usr, "Name:", "Name the culture", D.name, MAX_NAME_LEN)
|
||||
var/default_name = ""
|
||||
if(D.name == "Unknown" || D.name == "")
|
||||
default_name = replacetext(beaker.name, new/regex(" culture bottle\\Z", "g"), "")
|
||||
else
|
||||
default_name = D.name
|
||||
var/name = tgui_input_text(usr, "Name:", "Name the culture", default_name, MAX_NAME_LEN)
|
||||
if(name == null || wait)
|
||||
return
|
||||
var/obj/item/reagent_containers/glass/bottle/B = new/obj/item/reagent_containers/glass/bottle(loc)
|
||||
B.icon_state = "round_bottle"
|
||||
B.pixel_x = rand(-3, 3)
|
||||
B.pixel_y = rand(-3, 3)
|
||||
replicator_cooldown(50)
|
||||
var/list/data = list("viruses"=list(D))
|
||||
B.name = "[name] culture bottle"
|
||||
var/obj/item/reagent_containers/glass/bottle/B = create_culture(name)
|
||||
B.desc = "A small bottle. Contains [D.agent] culture in synthblood medium."
|
||||
B.reagents.add_reagent("blood",20,data)
|
||||
updateUsrDialog()
|
||||
else
|
||||
temp_html = "The replicator is not ready yet."
|
||||
updateUsrDialog()
|
||||
return
|
||||
else if(href_list["empty_beaker"])
|
||||
beaker.reagents.clear_reagents()
|
||||
eject_beaker()
|
||||
updateUsrDialog()
|
||||
return
|
||||
else if(href_list["eject"])
|
||||
eject_beaker()
|
||||
updateUsrDialog()
|
||||
return
|
||||
else if(href_list["clear"])
|
||||
temp_html = ""
|
||||
updateUsrDialog()
|
||||
return
|
||||
else if(href_list["name_disease"])
|
||||
var/new_name = tgui_input_text(usr, "Name the Disease", "New Name", max_length = MAX_NAME_LEN)
|
||||
if(!new_name)
|
||||
return
|
||||
if(..())
|
||||
return
|
||||
var/id = GetVirusTypeByIndex(text2num(href_list["name_disease"]))
|
||||
if(GLOB.archive_diseases[id])
|
||||
var/datum/disease/advance/A = GLOB.archive_diseases[id]
|
||||
B.reagents.add_reagent("blood", 20, list("viruses" = list(D)))
|
||||
if("clone_vaccine")
|
||||
if(wait)
|
||||
atom_say("The replicator is not ready yet.")
|
||||
return
|
||||
|
||||
var/resistance_index = text2num(params["resistance_index"])
|
||||
if(isnull(resistance_index))
|
||||
atom_say("Unable to find requested antibody.")
|
||||
return
|
||||
var/vaccine_type = GetResistancesByIndex(resistance_index)
|
||||
var/vaccine_name = "Unknown"
|
||||
if(!ispath(vaccine_type))
|
||||
if(GLOB.archive_diseases[vaccine_type])
|
||||
var/datum/disease/D = GLOB.archive_diseases[vaccine_type]
|
||||
if(D)
|
||||
vaccine_name = D.name
|
||||
else if(vaccine_type)
|
||||
var/datum/disease/D = new vaccine_type(0, null)
|
||||
if(D)
|
||||
vaccine_name = D.name
|
||||
|
||||
if(!vaccine_type)
|
||||
atom_say("Unable to synthesize requested antibody.")
|
||||
return
|
||||
|
||||
var/obj/item/reagent_containers/glass/bottle/B = create_culture(vaccine_name, "vaccine", 200)
|
||||
B.reagents.add_reagent("vaccine", 15, list(vaccine_type))
|
||||
if("eject_beaker")
|
||||
eject_beaker()
|
||||
if("destroy_eject_beaker")
|
||||
beaker.reagents.clear_reagents()
|
||||
eject_beaker()
|
||||
if("print_release_forms")
|
||||
var/strain_index = text2num(params["strain_index"])
|
||||
if(isnull(strain_index))
|
||||
atom_say("Unable to respond to command.")
|
||||
return
|
||||
var/type = GetVirusTypeByIndex(strain_index)
|
||||
if(!type)
|
||||
atom_say("Unable to find requested strain.")
|
||||
return
|
||||
var/datum/disease/advance/A = GLOB.archive_diseases[type]
|
||||
if(!A)
|
||||
atom_say("Unable to find requested strain.")
|
||||
return
|
||||
print_form(A, usr)
|
||||
if("name_strain")
|
||||
var/strain_index = text2num(params["strain_index"])
|
||||
if(isnull(strain_index))
|
||||
atom_say("Unable to respond to command.")
|
||||
return
|
||||
var/type = GetVirusTypeByIndex(strain_index)
|
||||
if(!type)
|
||||
atom_say("Unable to find requested strain.")
|
||||
return
|
||||
var/datum/disease/advance/A = GLOB.archive_diseases[type]
|
||||
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()
|
||||
updateUsrDialog()
|
||||
else if(href_list["print_form"])
|
||||
var/datum/disease/D = GetVirusByIndex(text2num(href_list["print_form"]))
|
||||
D = GLOB.archive_diseases[D.GetDiseaseID()]//We know it's advanced no need to check
|
||||
print_form(D, usr)
|
||||
if("switch_strain")
|
||||
var/strain_index = text2num(params["strain_index"])
|
||||
if(isnull(strain_index) || strain_index < 1)
|
||||
atom_say("Unable to respond to command.")
|
||||
return
|
||||
var/list/viruses = GetViruses()
|
||||
if(strain_index > length(viruses))
|
||||
atom_say("Unable to find requested strain.")
|
||||
return
|
||||
selected_strain_index = strain_index;
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/computer/pandemic/ui_state(mob/user)
|
||||
return GLOB.default_state
|
||||
|
||||
else
|
||||
usr << browse(null, "window=pandemic")
|
||||
updateUsrDialog()
|
||||
return
|
||||
/obj/machinery/computer/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()
|
||||
|
||||
add_fingerprint(usr)
|
||||
/obj/machinery/computer/pandemic/ui_data(mob/user)
|
||||
var/datum/reagent/blood/Blood = null
|
||||
if(beaker)
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
for(var/datum/reagent/blood/B in R.reagent_list)
|
||||
if(B)
|
||||
Blood = B
|
||||
break
|
||||
|
||||
var/list/data = list(
|
||||
"synthesisCooldown" = wait ? TRUE : FALSE,
|
||||
"beakerLoaded" = beaker ? TRUE : FALSE,
|
||||
"beakerContainsBlood" = Blood ? TRUE : FALSE,
|
||||
"beakerContainsVirus" = length(Blood?.data["viruses"]) != 0,
|
||||
"selectedStrainIndex" = selected_strain_index,
|
||||
)
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/pandemic/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
. = data
|
||||
|
||||
var/datum/reagent/blood/Blood = null
|
||||
if(beaker)
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
for(var/datum/reagent/blood/B in R.reagent_list)
|
||||
if(B)
|
||||
Blood = B
|
||||
break
|
||||
|
||||
var/list/strains = list()
|
||||
for(var/datum/disease/D in GetViruses())
|
||||
if(D.visibility_flags & 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,
|
||||
))
|
||||
|
||||
strains += list(list(
|
||||
"commonName" = D.name,
|
||||
"description" = D.desc,
|
||||
"bloodDNA" = Blood.data["blood_DNA"],
|
||||
"bloodType" = Blood.data["blood_type"],
|
||||
"diseaseAgent" = D.agent,
|
||||
"possibleTreatments" = D.cure_text,
|
||||
"transmissionRoute" = D.spread_text,
|
||||
"symptoms" = symptoms,
|
||||
"isAdvanced" = istype(D, /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)
|
||||
else if(resistance)
|
||||
var/datum/disease/D = new resistance(0, null)
|
||||
if(D)
|
||||
resistances += list(D.name)
|
||||
data["resistances"] = resistances
|
||||
|
||||
/obj/machinery/computer/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)
|
||||
@@ -241,108 +368,16 @@
|
||||
P.info = info_text.Join("")
|
||||
P.update_icon()
|
||||
|
||||
/obj/machinery/computer/pandemic/attack_ai(mob/user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/computer/pandemic/attack_hand(mob/user)
|
||||
if(..())
|
||||
return
|
||||
user.set_machine(src)
|
||||
var/dat = ""
|
||||
if(temp_html)
|
||||
dat = "[temp_html]<BR><BR><A href='byond://?src=[UID()];clear=1'>Main Menu</A>"
|
||||
else if(!beaker)
|
||||
dat += "Please insert beaker.<BR>"
|
||||
dat += "<A href='byond://?src=[user.UID()];mach_close=pandemic'>Close</A>"
|
||||
else
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/datum/reagent/blood/Blood = null
|
||||
for(var/datum/reagent/blood/B in R.reagent_list)
|
||||
if(B)
|
||||
Blood = B
|
||||
break
|
||||
if(!R.total_volume||!length(R.reagent_list))
|
||||
dat += "The beaker is empty<BR>"
|
||||
else if(!Blood)
|
||||
dat += "No blood sample found in beaker."
|
||||
else if(!Blood.data)
|
||||
dat += "No blood data found in beaker."
|
||||
else
|
||||
dat += "<h3>Blood sample data:</h3>"
|
||||
dat += "<b>Blood DNA:</b> [(Blood.data["blood_DNA"]||"none")]<BR>"
|
||||
dat += "<b>Blood Type:</b> [(Blood.data["blood_type"]||"none")]<BR>"
|
||||
|
||||
|
||||
if(Blood.data["viruses"])
|
||||
var/list/vir = Blood.data["viruses"]
|
||||
if(length(vir))
|
||||
var/i = 0
|
||||
for(var/thing in Blood.data["viruses"])
|
||||
var/datum/disease/D = thing
|
||||
i++
|
||||
if(!(D.visibility_flags & HIDDEN_PANDEMIC))
|
||||
|
||||
if(istype(D, /datum/disease/advance))
|
||||
|
||||
var/datum/disease/advance/A = D
|
||||
D = GLOB.archive_diseases[A.GetDiseaseID()]
|
||||
if(D)
|
||||
if(D.name == "Unknown")
|
||||
dat += "<b><a href='byond://?src=[UID()];name_disease=[i]'>Name Disease</a></b><BR>"
|
||||
else
|
||||
dat += "<b><a href='byond://?src=[UID()];print_form=[i]'>Print release form</a></b><BR>"
|
||||
|
||||
if(!D)
|
||||
CRASH("We weren't able to get the advance disease from the archive.")
|
||||
|
||||
dat += "<b>Disease Agent:</b> [D?"[D.agent] - <A href='byond://?src=[UID()];create_virus_culture=[i]'>Create virus culture bottle</A>":"none"]<BR>"
|
||||
dat += "<b>Common name:</b> [(D.name||"none")]<BR>"
|
||||
dat += "<b>Description: </b> [(D.desc||"none")]<BR>"
|
||||
dat += "<b>Spread:</b> [(D.spread_text||"none")]<BR>"
|
||||
dat += "<b>Possible cure:</b> [(D.cure_text||"none")]<BR><BR>"
|
||||
|
||||
if(istype(D, /datum/disease/advance))
|
||||
var/datum/disease/advance/A = D
|
||||
dat += "<b>Symptoms:</b> "
|
||||
var/english_symptoms = list()
|
||||
for(var/datum/symptom/S in A.symptoms)
|
||||
english_symptoms += S.name
|
||||
dat += english_list(english_symptoms)
|
||||
|
||||
else
|
||||
dat += "No detectable virus in the sample."
|
||||
else
|
||||
dat += "No detectable virus in the sample."
|
||||
|
||||
dat += "<BR><b>Contains antibodies to:</b> "
|
||||
if(Blood.data["resistances"])
|
||||
var/list/res = Blood.data["resistances"]
|
||||
if(length(res))
|
||||
dat += "<ul>"
|
||||
var/i = 0
|
||||
for(var/type in Blood.data["resistances"])
|
||||
i++
|
||||
var/disease_name = "Unknown"
|
||||
|
||||
if(!ispath(type))
|
||||
var/datum/disease/advance/A = GLOB.archive_diseases[type]
|
||||
if(A)
|
||||
disease_name = A.name
|
||||
else
|
||||
var/datum/disease/D = new type(0, null)
|
||||
disease_name = D.name
|
||||
|
||||
dat += "<li>[disease_name] - <A href='byond://?src=[UID()];create_vaccine=[i]'>Create vaccine bottle</A></li>"
|
||||
dat += "</ul><BR>"
|
||||
else
|
||||
dat += "nothing<BR>"
|
||||
else
|
||||
dat += "nothing<BR>"
|
||||
dat += "<BR><A href='byond://?src=[UID()];eject=1'>Eject beaker</A>[((R.total_volume&&length(R.reagent_list)) ? "-- <A href='byond://?src=[UID()];empty_beaker=1'>Empty and eject beaker</A>":"")]<BR>"
|
||||
dat += "<A href='byond://?src=[user.UID()];mach_close=pandemic'>Close</A>"
|
||||
|
||||
var/datum/browser/popup = new(user, "pandemic", name, 575, 400)
|
||||
popup.set_content(dat)
|
||||
popup.open(0)
|
||||
onclose(user, "pandemic")
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/computer/pandemic/attack_ghost(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/computer/pandemic/attackby(obj/item/I, mob/user, params)
|
||||
if(default_unfasten_wrench(user, I, time = 4 SECONDS))
|
||||
@@ -361,6 +396,7 @@
|
||||
beaker.loc = src
|
||||
to_chat(user, "<span class='notice'>You add the beaker to the machine.</span>")
|
||||
updateUsrDialog()
|
||||
SStgui.update_uis(src, TRUE)
|
||||
icon_state = "pandemic1"
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -24,10 +24,11 @@ export const computeFlexClassName = (props: FlexProps) => {
|
||||
};
|
||||
|
||||
export const computeFlexProps = (props: FlexProps) => {
|
||||
const { className, direction, wrap, align, justify, inline, ...rest } = props;
|
||||
const { className, direction, wrap, align, justify, inline, style, ...rest } =
|
||||
props;
|
||||
return computeBoxProps({
|
||||
style: {
|
||||
...rest.style,
|
||||
...style,
|
||||
'flex-direction': direction,
|
||||
'flex-wrap': wrap === true ? 'wrap' : wrap,
|
||||
'align-items': align,
|
||||
|
||||
@@ -0,0 +1,374 @@
|
||||
import { BooleanLike } from '../../common/react';
|
||||
import { InfernoNode } from 'inferno';
|
||||
import { useBackend } from '../backend';
|
||||
import {
|
||||
Button,
|
||||
Flex,
|
||||
LabeledList,
|
||||
Section,
|
||||
Stack,
|
||||
Table,
|
||||
Tabs,
|
||||
} from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
interface PathogenSymptom {
|
||||
name: string;
|
||||
stealth: number;
|
||||
resistance: number;
|
||||
stageSpeed: number;
|
||||
transmissibility: number;
|
||||
}
|
||||
|
||||
interface PathogenStrain {
|
||||
commonName?: string;
|
||||
description?: string;
|
||||
bloodDNA?: string;
|
||||
bloodType?: string;
|
||||
diseaseAgent: string;
|
||||
possibleTreatments?: string;
|
||||
transmissionRoute?: string;
|
||||
symptoms?: PathogenSymptom[];
|
||||
isAdvanced: BooleanLike;
|
||||
}
|
||||
|
||||
interface PanDEMICData {
|
||||
synthesisCooldown: BooleanLike;
|
||||
beakerLoaded: BooleanLike;
|
||||
beakerContainsBlood: BooleanLike;
|
||||
beakerContainsVirus: BooleanLike;
|
||||
selectedStrainIndex: number;
|
||||
strains?: PathogenStrain[];
|
||||
resistances?: string[];
|
||||
}
|
||||
|
||||
export const PanDEMIC = (props, context) => {
|
||||
const { data } = useBackend<PanDEMICData>(context);
|
||||
const {
|
||||
beakerLoaded,
|
||||
beakerContainsBlood,
|
||||
beakerContainsVirus,
|
||||
resistances = [],
|
||||
} = data;
|
||||
|
||||
let emptyPlaceholder;
|
||||
if (!beakerLoaded) {
|
||||
emptyPlaceholder = <>No container loaded.</>;
|
||||
} else if (!beakerContainsBlood) {
|
||||
emptyPlaceholder = <>No blood sample found in the loaded container.</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Window width={575} height={510}>
|
||||
<Window.Content>
|
||||
<Stack fill vertical>
|
||||
{emptyPlaceholder && (
|
||||
<Section
|
||||
title="Container Information"
|
||||
buttons={<CommonCultureActions />}
|
||||
>
|
||||
{emptyPlaceholder}
|
||||
</Section>
|
||||
)}
|
||||
{!!beakerContainsVirus && <CultureInformationSection />}
|
||||
{resistances?.length > 0 && <ResistancesSection />}
|
||||
</Stack>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const CommonCultureActions = (props, context) => {
|
||||
const { act, data } = useBackend<PanDEMICData>(context);
|
||||
const { beakerLoaded } = data;
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
icon="eject"
|
||||
content="Eject"
|
||||
disabled={!beakerLoaded}
|
||||
onClick={() => act('eject_beaker')}
|
||||
/>
|
||||
<Button.Confirm
|
||||
icon="trash-alt"
|
||||
confirmIcon="eraser"
|
||||
content="Destroy"
|
||||
confirmContent="Destroy"
|
||||
disabled={!beakerLoaded}
|
||||
onClick={() => act('destroy_eject_beaker')}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const StrainInformation = (
|
||||
props: { strain: PathogenStrain; strainIndex: number },
|
||||
context
|
||||
) => {
|
||||
const { act, data } = useBackend<PanDEMICData>(context);
|
||||
const { beakerContainsVirus } = data;
|
||||
const {
|
||||
commonName,
|
||||
description,
|
||||
diseaseAgent,
|
||||
bloodDNA,
|
||||
bloodType,
|
||||
possibleTreatments,
|
||||
transmissionRoute,
|
||||
isAdvanced,
|
||||
} = props.strain;
|
||||
|
||||
const bloodInformation = (
|
||||
<>
|
||||
<LabeledList.Item label="Blood DNA">
|
||||
{!bloodDNA ? (
|
||||
'Undetectable'
|
||||
) : (
|
||||
<span style={{ 'font-family': "'Courier New', monospace" }}>
|
||||
{bloodDNA}
|
||||
</span>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Blood Type">
|
||||
{
|
||||
<div
|
||||
// blood type can sometimes contain a span
|
||||
// eslint-disable-next-line react/no-danger
|
||||
dangerouslySetInnerHTML={{ __html: bloodType ?? 'Undetectable' }}
|
||||
/>
|
||||
}
|
||||
</LabeledList.Item>
|
||||
</>
|
||||
);
|
||||
|
||||
if (!beakerContainsVirus) {
|
||||
return <LabeledList>{bloodInformation}</LabeledList>;
|
||||
}
|
||||
|
||||
let nameButtons;
|
||||
if (isAdvanced) {
|
||||
if (
|
||||
commonName !== undefined &&
|
||||
commonName !== null &&
|
||||
commonName !== 'Unknown'
|
||||
) {
|
||||
nameButtons = (
|
||||
<Button
|
||||
icon="print"
|
||||
content="Print Release Forms"
|
||||
onClick={() =>
|
||||
act('print_release_forms', {
|
||||
strain_index: props.strainIndex,
|
||||
})
|
||||
}
|
||||
style={{ 'margin-left': 'auto' }}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
nameButtons = (
|
||||
<Button
|
||||
icon="pen"
|
||||
content="Name Disease"
|
||||
onClick={() =>
|
||||
act('name_strain', { strain_index: props.strainIndex })
|
||||
}
|
||||
style={{ 'margin-left': 'auto' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Common Name" className="common-name-label">
|
||||
<Stack horizontal align="center">
|
||||
{commonName ?? 'Unknown'}
|
||||
{nameButtons}
|
||||
</Stack>
|
||||
</LabeledList.Item>
|
||||
{description && (
|
||||
<LabeledList.Item label="Description">{description}</LabeledList.Item>
|
||||
)}
|
||||
<LabeledList.Item label="Disease Agent">{diseaseAgent}</LabeledList.Item>
|
||||
{bloodInformation}
|
||||
<LabeledList.Item label="Spread Vector">
|
||||
{transmissionRoute ?? 'None'}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Possible Cures">
|
||||
{possibleTreatments ?? 'None'}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
);
|
||||
};
|
||||
|
||||
const StrainInformationSection = (
|
||||
props: {
|
||||
strain: PathogenStrain;
|
||||
strainIndex: number;
|
||||
sectionTitle?: string;
|
||||
sectionButtons?: InfernoNode | InfernoNode[];
|
||||
},
|
||||
context
|
||||
) => {
|
||||
const { act, data } = useBackend<PanDEMICData>(context);
|
||||
let synthesisCooldown = !!data.synthesisCooldown;
|
||||
const appliedSectionButtons = (
|
||||
<>
|
||||
<Button
|
||||
icon={synthesisCooldown ? 'spinner' : 'clone'}
|
||||
iconSpin={synthesisCooldown}
|
||||
content="Clone"
|
||||
disabled={synthesisCooldown}
|
||||
onClick={() => act('clone_strain', { strain_index: props.strainIndex })}
|
||||
/>
|
||||
{props.sectionButtons}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<Flex.Item>
|
||||
<Section
|
||||
title={props.sectionTitle ?? 'Strain Information'}
|
||||
buttons={appliedSectionButtons}
|
||||
>
|
||||
<StrainInformation
|
||||
strain={props.strain}
|
||||
strainIndex={props.strainIndex}
|
||||
/>
|
||||
</Section>
|
||||
</Flex.Item>
|
||||
);
|
||||
};
|
||||
|
||||
const CultureInformationSection = (props, context) => {
|
||||
const { act, data } = useBackend<PanDEMICData>(context);
|
||||
const { selectedStrainIndex, strains } = data;
|
||||
const selectedStrain = strains[selectedStrainIndex - 1];
|
||||
|
||||
if (strains.length === 1) {
|
||||
return (
|
||||
<>
|
||||
<StrainInformationSection
|
||||
strain={strains[0]}
|
||||
strainIndex={1}
|
||||
sectionButtons={<CommonCultureActions />}
|
||||
/>
|
||||
{strains[0].symptoms?.length > 0 && (
|
||||
<StrainSymptomsSection strain={strains[0]} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const sectionButtons = <CommonCultureActions />;
|
||||
|
||||
return (
|
||||
<Stack.Item grow>
|
||||
<Section title="Culture Information" fill buttons={sectionButtons}>
|
||||
<Flex direction="column" style={{ 'height': '100%' }}>
|
||||
<Flex.Item>
|
||||
<Tabs>
|
||||
{strains.map((strain, i) => (
|
||||
<Tabs.Tab
|
||||
key={i}
|
||||
icon="virus"
|
||||
selected={selectedStrainIndex - 1 === i}
|
||||
onClick={() => act('switch_strain', { strain_index: i + 1 })}
|
||||
>
|
||||
{strain.commonName ?? 'Unknown'}
|
||||
</Tabs.Tab>
|
||||
))}
|
||||
</Tabs>
|
||||
</Flex.Item>
|
||||
<StrainInformationSection
|
||||
strain={selectedStrain}
|
||||
strainIndex={selectedStrainIndex}
|
||||
/>
|
||||
{selectedStrain.symptoms?.length > 0 && (
|
||||
<StrainSymptomsSection
|
||||
className="remove-section-bottom-padding"
|
||||
strain={selectedStrain}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
);
|
||||
};
|
||||
|
||||
const sum = (values: number[]) => {
|
||||
return values.reduce((r, value) => r + value, 0);
|
||||
};
|
||||
|
||||
const StrainSymptomsSection = (props: {
|
||||
className?: string;
|
||||
strain: PathogenStrain;
|
||||
}) => {
|
||||
const { symptoms } = props.strain;
|
||||
return (
|
||||
<Flex.Item grow>
|
||||
<Section title="Infection Symptoms" fill className={props.className}>
|
||||
<Table className="symptoms-table">
|
||||
<Table.Row>
|
||||
<Table.Cell>Name</Table.Cell>
|
||||
<Table.Cell>Stealth</Table.Cell>
|
||||
<Table.Cell>Resistance</Table.Cell>
|
||||
<Table.Cell>Stage Speed</Table.Cell>
|
||||
<Table.Cell>Transmissibility</Table.Cell>
|
||||
</Table.Row>
|
||||
{symptoms.map((symptom, index) => (
|
||||
<Table.Row key={index}>
|
||||
<Table.Cell>{symptom.name}</Table.Cell>
|
||||
<Table.Cell>{symptom.stealth}</Table.Cell>
|
||||
<Table.Cell>{symptom.resistance}</Table.Cell>
|
||||
<Table.Cell>{symptom.stageSpeed}</Table.Cell>
|
||||
<Table.Cell>{symptom.transmissibility}</Table.Cell>
|
||||
</Table.Row>
|
||||
))}
|
||||
<Table.Row className="table-spacer" />
|
||||
<Table.Row>
|
||||
<Table.Cell style={{ 'font-weight': 'bold' }}>Total</Table.Cell>
|
||||
<Table.Cell>{sum(symptoms.map((s) => s.stealth))}</Table.Cell>
|
||||
<Table.Cell>{sum(symptoms.map((s) => s.resistance))}</Table.Cell>
|
||||
<Table.Cell>{sum(symptoms.map((s) => s.stageSpeed))}</Table.Cell>
|
||||
<Table.Cell>
|
||||
{sum(symptoms.map((s) => s.transmissibility))}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table>
|
||||
</Section>
|
||||
</Flex.Item>
|
||||
);
|
||||
};
|
||||
|
||||
const VaccineSynthesisIcons = ['flask', 'vial', 'eye-dropper'];
|
||||
|
||||
const ResistancesSection = (props, context) => {
|
||||
const { act, data } = useBackend<PanDEMICData>(context);
|
||||
const { synthesisCooldown, beakerContainsVirus, resistances } = data;
|
||||
return (
|
||||
<Stack.Item>
|
||||
<Section
|
||||
title="Antibodies"
|
||||
fill
|
||||
buttons={!beakerContainsVirus && <CommonCultureActions />}
|
||||
>
|
||||
<Stack horizontal wrap>
|
||||
{resistances.map((r, i) => (
|
||||
<Stack.Item key={i}>
|
||||
<Button
|
||||
icon={VaccineSynthesisIcons[i % VaccineSynthesisIcons.length]}
|
||||
disabled={!!synthesisCooldown}
|
||||
onClick={() =>
|
||||
act('clone_vaccine', { resistance_index: i + 1 })
|
||||
}
|
||||
mr="0.5em"
|
||||
/>
|
||||
{r}
|
||||
</Stack.Item>
|
||||
))}
|
||||
</Stack>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
.symptoms-table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 0 0.5ex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.symptoms-table > tbody > tr:first-child {
|
||||
width: 100%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.symptoms-table > tbody > tr:nth-child(2) > td:first-child {
|
||||
padding-top: 0.5ex;
|
||||
}
|
||||
|
||||
.symptoms-table > tbody > tr > td:nth-child(n + 2) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.common-name-label > .LabeledList__cell {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.table-spacer {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.remove-section-bottom-padding .Section__content {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
@@ -57,6 +57,7 @@
|
||||
@include meta.load-css('./interfaces/Newscaster.scss');
|
||||
@include meta.load-css('./interfaces/NuclearBomb.scss');
|
||||
@include meta.load-css('./interfaces/OreRedemption.scss');
|
||||
@include meta.load-css('./interfaces/PanDEMIC.scss');
|
||||
@include meta.load-css('./interfaces/PDA.scss');
|
||||
@include meta.load-css('./interfaces/PdaPainter.scss');
|
||||
@include meta.load-css('./interfaces/PoolController.scss');
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+76
-76
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user