From 3cfc2c6e763d4946a54bff0d3b610b33f4bbf365 Mon Sep 17 00:00:00 2001 From: Will <7099514+Willburd@users.noreply.github.com> Date: Thu, 19 Jun 2025 09:46:02 -0400 Subject: [PATCH] Bingle them viruses (#17881) * viruspage creation * virus unit testing * oop * tweaks * as check * use glob list * new data * scan data proper * counting * constructing lists * fix * wikicomp side * basictgui * list fix * tweaks * virus tgui page * . * . * . * unused * . * . * stack item it * genes * show gene conflicts * no static tags * fixed conflict gene report * tgui foundation for genes * handle gene conflicts once * .bingle page * . * . * import order fix * traits names must be unique --------- Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com> --- code/controllers/subsystems/internal_wiki.dm | 215 +++++++++++++++++- code/game/dna/genes/gene.dm | 6 +- code/modules/admin/admin.dm | 31 +-- code/modules/library/wikicomp.dm | 18 +- code/unit_tests/disease_tests.dm | 32 +++ .../{authohiss_tests.dm => trait_tests.dm} | 22 ++ .../tgui-panel/settings/settingsImExport.ts | 5 +- .../WikiCommon/WikiQuickElements.tsx | 10 +- .../WikiPages/WIkiDonationbanner.tsx | 2 +- .../WikiPages/WikiSearchPage.tsx | 6 + .../WikiPages/WikiSubPages/WikiGenePage.tsx | 52 +++++ .../WikiSubPages/WikiMaterialPage.tsx | 7 +- .../WikiPages/WikiSubPages/WikiVirusPage.tsx | 154 +++++++++++++ .../interfaces/PublicLibraryWiki/constants.ts | 63 +++++ .../interfaces/PublicLibraryWiki/index.tsx | 4 + .../interfaces/PublicLibraryWiki/types.ts | 33 +++ .../tgui/interfaces/common/RankIcon.tsx | 16 +- vorestation.dme | 3 +- 18 files changed, 642 insertions(+), 37 deletions(-) create mode 100644 code/unit_tests/disease_tests.dm rename code/unit_tests/{authohiss_tests.dm => trait_tests.dm} (65%) create mode 100644 tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSubPages/WikiGenePage.tsx create mode 100644 tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSubPages/WikiVirusPage.tsx diff --git a/code/controllers/subsystems/internal_wiki.dm b/code/controllers/subsystems/internal_wiki.dm index 69f3fa83433..cb9716da6df 100644 --- a/code/controllers/subsystems/internal_wiki.dm +++ b/code/controllers/subsystems/internal_wiki.dm @@ -20,6 +20,8 @@ SUBSYSTEM_DEF(internal_wiki) VAR_PRIVATE/list/drinkreact = list() VAR_PRIVATE/list/chemreact = list() VAR_PRIVATE/list/botseeds = list() + VAR_PRIVATE/list/viruses = list() + VAR_PRIVATE/list/genes = list() VAR_PRIVATE/list/foodrecipe = list() @@ -33,6 +35,8 @@ SUBSYSTEM_DEF(internal_wiki) VAR_PRIVATE/list/searchcache_chemreact = list() VAR_PRIVATE/list/searchcache_catalogs = list() VAR_PRIVATE/list/searchcache_botseeds = list() + VAR_PRIVATE/list/searchcache_viruses = list() + VAR_PRIVATE/list/searchcache_genes = list() VAR_PRIVATE/list/spoiler_entries = list() @@ -44,7 +48,7 @@ SUBSYSTEM_DEF(internal_wiki) VAR_PRIVATE/highest_cached_donator = null /datum/controller/subsystem/internal_wiki/stat_entry(msg) - msg = "P: [pages.len] | O: [ores.len] | M: [materials.len] | S: [smashers.len] | F: [foodrecipe.len] | D: [drinkreact.len] | C: [chemreact.len] | B: [botseeds.len] " + msg = "P: [pages.len] | O: [ores.len] | M: [materials.len] | S: [smashers.len] | F: [foodrecipe.len] | D: [drinkreact.len] | C: [chemreact.len] | B: [botseeds.len] | V: [viruses.len] | G: [genes.len] " return ..() /datum/controller/subsystem/internal_wiki/Initialize() @@ -53,8 +57,10 @@ SUBSYSTEM_DEF(internal_wiki) init_particle_smasher_data() init_reagent_data() init_seed_data() + init_virus_data() init_kitchen_data() init_lore_data() + init_gene_data() // Donation gag donation_goal = rand(min_donation,max_donation) donation_goal = round(donation_goal,1) @@ -126,6 +132,14 @@ SUBSYSTEM_DEF(internal_wiki) RETURN_TYPE(/datum/internal_wiki/page/seed) SHOULD_NOT_OVERRIDE(TRUE) return botseeds[search] +/datum/controller/subsystem/internal_wiki/proc/get_page_virus(var/search) + RETURN_TYPE(/datum/internal_wiki/page/virus) + SHOULD_NOT_OVERRIDE(TRUE) + return viruses[search] +/datum/controller/subsystem/internal_wiki/proc/get_page_gene(var/search) + RETURN_TYPE(/datum/internal_wiki/page/gene) + SHOULD_NOT_OVERRIDE(TRUE) + return genes[search] /datum/controller/subsystem/internal_wiki/proc/get_page_catalog(var/search) RETURN_TYPE(/datum/internal_wiki/page/catalog) SHOULD_NOT_OVERRIDE(TRUE) @@ -163,6 +177,14 @@ SUBSYSTEM_DEF(internal_wiki) RETURN_TYPE(/list) SHOULD_NOT_OVERRIDE(TRUE) return searchcache_botseeds +/datum/controller/subsystem/internal_wiki/proc/get_searchcache_viruses() + RETURN_TYPE(/list) + SHOULD_NOT_OVERRIDE(TRUE) + return searchcache_viruses +/datum/controller/subsystem/internal_wiki/proc/get_searchcache_genes() + RETURN_TYPE(/list) + SHOULD_NOT_OVERRIDE(TRUE) + return searchcache_genes /datum/controller/subsystem/internal_wiki/proc/get_catalogs() RETURN_TYPE(/list) SHOULD_NOT_OVERRIDE(TRUE) @@ -511,6 +533,37 @@ SUBSYSTEM_DEF(internal_wiki) botseeds["[S.display_name]"] = P pages.Add(P) +/datum/controller/subsystem/internal_wiki/proc/init_virus_data() + SHOULD_NOT_OVERRIDE(TRUE) + PRIVATE_PROC(TRUE) + // viruses or diseases + for(var/datum/disease/D as anything in subtypesof(/datum/disease)) + if(initial(D.name) == DEVELOPER_WARNING_NAME) + continue + if(initial(D.visibility_flags) & HIDDEN_PANDEMIC) + spoiler_entries.Add(D) + continue + var/datum/internal_wiki/page/virus/P = new() + P.assemble(D) + searchcache_viruses.Add("[initial(D.medical_name)]") + viruses["[initial(D.medical_name)]"] = P + pages.Add(P) + +/datum/controller/subsystem/internal_wiki/proc/init_gene_data() + SHOULD_NOT_OVERRIDE(TRUE) + PRIVATE_PROC(TRUE) + // viruses or diseases + for(var/datum/gene/G in GLOB.dna_genes) + var/N = G.name + if(istype(G,/datum/gene/trait)) + var/datum/gene/trait/T = G + N = T.get_name() + var/datum/internal_wiki/page/gene/P = new() + P.assemble(G) + searchcache_genes.Add("[N]") + genes["[N]"] = P + pages.Add(P) + /datum/controller/subsystem/internal_wiki/proc/init_kitchen_data() SHOULD_NOT_OVERRIDE(TRUE) PRIVATE_PROC(TRUE) @@ -1311,6 +1364,166 @@ SUBSYSTEM_DEF(internal_wiki) data["name"] = catalog_record.name data["desc"] = catalog_record.desc +// VIRUSES +///////////////////////////////////////////// +/datum/internal_wiki/page/virus/assemble(var/datum/disease/D) + title = initial(D.name) + data["title"] = title + data["description"] = initial(D.desc) + data["form"] = initial(D.form) + data["agent"] = initial(D.agent) + data["danger"] = initial(D.danger) + data["max_stages"] = initial(D.max_stages) + + var/infectivity = "" + switch(initial(D.infectivity)) + if(0) + infectivity = "NA" + if(1 to 3) + infectivity = "Low" + if(4 to 7) + infectivity = "Medium" + if(8 to INFINITY) + infectivity = "High" + data["infectivity"] = infectivity + + var/resiliance = "" + switch(initial(D.cure_chance)) + if(0 to 8) + resiliance = "Extreme" + if(9 to 12) + resiliance = "High" + if(13 to 16) + resiliance = "Medium" + if(17 to INFINITY) + resiliance = "Low" + data["resiliance"] = resiliance + + var/discovery = "" + switch(initial(D.discovery_threshold)) + if(0 to 0.24) + discovery = "Extremely Elusive" + if(0.25 to 0.49) + discovery = "Difficult" + if(0.5 to 0.74) + discovery = "Moderate" + if(0.75 to 0.89) + discovery = "Easy" + if(0.9 to INFINITY) + discovery = "Trivial" + data["discovery"] = discovery + + var/spread_flags = initial(D.spread_flags) + var/spread_type = "NA" + if(spread_flags & DISEASE_SPREAD_CONTACT) + spread_type = "Contact" + else if(spread_flags & DISEASE_SPREAD_FLUIDS) + spread_type = "Fluids" + else if(spread_flags & DISEASE_SPREAD_BLOOD) + spread_type = "Blood" + else if(spread_flags & DISEASE_SPREAD_AIRBORNE) + spread_type = "Airborne" + else if(spread_flags & DISEASE_SPREAD_FALTERED) + spread_type = "Faltered" + data["spread"] = spread_type + + var/mod_flags = initial(D.virus_modifiers) + data["all_cures"] = mod_flags & NEEDS_ALL_CURES + data["aggressive"] = mod_flags & BYPASSES_IMMUNITY + var/flags = initial(D.disease_flags) + data["curable"] = flags & CURABLE + data["resistable"] = flags & CAN_RESIST + data["carriable"] = flags & CAN_CARRY + data["spread_dead"] = flags & SPREAD_DEAD + data["infect_synth"] = flags & INFECT_SYNTHETICS + +/datum/internal_wiki/page/virus/get_print() + var/body = "" + body += "Description: [data["description"]]
" + body += "
" + body += "Type: [data["form"]] - [data["agent"]]
" + body += "Hazard Level: [data["danger"]]
" + body += "Growth Stages: [data["max_stages"]]
" + body += "Curable: [(data["curable"]) ? "Yes" : "No"][!(data["all_cures"]) ? " - single treatment" : ""]
" + body += "Resistable: [(data["resistable"]) ? "Yes" : "No"]
" + body += "
" + // Transmission type + body += "Transmission: [data["spread"]] [(data["aggressive"]) ? "Aggressive" : ""]
" + if(data["carriable"]) + body += "Transmissable without symptoms
" + if(data["spread_dead"]) + body += "Transmissable from dead tissue
" + if(data["infect_synth"]) + body += "Inorganic pathogen
" + // Difficulty of discovery + body += "Discoverability: [data["discovery"]]
" + // Probability of spreading + body += "Infectivity: [data["infectivity"]]
" + // Probability of cure, 10 to 20 regularly + body += "Resiliance: [data["resiliance"]]
" + return body + +// GENES +///////////////////////////////////////////// +/datum/internal_wiki/page/gene/assemble(var/datum/gene/G) + if(istype(G,/datum/gene/trait)) + // Trait genetics + var/datum/gene/trait/T = G + title = T.get_name() + data["title"] = title + data["description"] = T.get_desc() + if(istype(T.linked_trait,/datum/trait/positive)) + if(!T.linked_trait.hidden) + data["trait_type"] = "Positive" + else + data["trait_type"] = "Super Power" // Likely eye lasers + else if(istype(T.linked_trait,/datum/trait/negative)) + if(!T.linked_trait.hidden) + data["trait_type"] = "Negative" + else + data["trait_type"] = "Disability" // Likely gibbings or such + else + if(!T.linked_trait.hidden) + data["trait_type"] = "Neutral" + else + data["trait_type"] = "Strange" // Not sure what neutrals are hidden, but just incase + // Conflicts + data["blockers"] = null + var/list/output_blockers = list() + var/list/blockers = T.conflict_traits + for(var/path in blockers) + var/datum/trait/TG = GLOB.all_traits[path] + output_blockers.Add(TG.name) + if(output_blockers.len) + data["blockers"] = output_blockers + else + // Old style gene + title = G.name + data["title"] = title + data["description"] = G.desc + data["trait_type"] = "Neutral" + data["blockers"] = null + var/list/bounds = GetDNABounds(G.block) + data["bounds_off_min"] = EncodeDNABlock(bounds[1]) // Minimum hex where gene is off + data["bounds_off_max"] = EncodeDNABlock(bounds[2]) // Maximum hex where gene is off + data["bounds_on_min"] = EncodeDNABlock(bounds[3]) // Minimum hex where gene is on + data["bounds_on_max"] = EncodeDNABlock(bounds[4]) // Maximum hex where gene is on + +/datum/internal_wiki/page/gene/get_print() + var/body = "" + body += "Description: [data["description"]]
" + body += "
" + body += "Type: [data["trait_type"]]
" + body += "Active Range: [data["bounds_on_min"]] - [data["bounds_on_max"]]
" + body += "Inactive Range: [data["bounds_off_min"]] - [data["bounds_off_max"]]
" + body += "
" + var/list/blockers = data["blockers"] + if(blockers) + body += "Suppressed By:
" + for(var/trait_name in blockers) + body += "-[trait_name]
" + return body + // MISC HELPERS //////////////////////////////////////////// /datum/internal_wiki/page/proc/print_allergens(var/list/allergens) diff --git a/code/game/dna/genes/gene.dm b/code/game/dna/genes/gene.dm index 0ccf1172253..7f61e5b7ef4 100644 --- a/code/game/dna/genes/gene.dm +++ b/code/game/dna/genes/gene.dm @@ -103,19 +103,19 @@ // check trait if not. CONFLICT-O-TRON ENGAGE var/datum/trait/instance_test = GLOB.all_traits[P] if(path in instance_test.excludes) - conflict_traits.Add(P) + conflict_traits |= P has_conflict = TRUE continue for(var/V in linked_trait.var_changes) if(V == "flags") continue if(V in instance_test.var_changes) - conflict_traits.Add(P) + conflict_traits |= P has_conflict = TRUE continue for(var/V in linked_trait.var_changes_pref) if(V in instance_test.var_changes_pref) - conflict_traits.Add(P) + conflict_traits |= P has_conflict = TRUE continue return has_conflict diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index c7b857595e9..58cf269dca1 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -89,13 +89,13 @@ GLOBAL_VAR_INIT(floorIsLava, 0) body += "\ Send back to Lobby | " var/muted = M.client.prefs.muted body += {"
"} + span_bold("Mute: ") + {" - \[IC | - OOC | - LOOC | - PRAY | - ADMINHELP | - DEADCHAT\] - (toggle all) + \[[(muted & MUTE_IC) ? span_red("IC") : span_blue("IC")] | + [(muted & MUTE_OOC) ? span_red("OOC") : span_blue("OOC")] | + [(muted & MUTE_LOOC) ? span_red("LOOC") : span_blue("LOOC")] | + [(muted & MUTE_PRAY) ? span_red("PRAY") : span_blue("PRAY")] | + [(muted & MUTE_ADMINHELP) ? span_red("ADMINHELP") : span_blue("ADMINHELP")] | + [(muted & MUTE_DEADCHAT) ? span_red("DEADCHAT") : span_blue("DEADCHAT")]\] + ([(muted & MUTE_ALL) ? span_red("toggle all") : span_blue("toggle all")]) "} body += {"

@@ -171,10 +171,13 @@ GLOBAL_VAR_INIT(floorIsLava, 0) if(istype(gene,/datum/gene/trait)) var/datum/gene/trait/T = gene tname = T.get_name() - var/bcolor="[(bstate)?"#006600":"#ff0000"]" - if(!bstate && M.dna.GetSEState(block)) // Gene isn't active, but the dna says it is... Was blocked by another gene! - bcolor="#d88d00" - body += "[bname][block]" // Traitgenes edit - show trait linked names on mouseover + if(bstate) + bname = span_green(bname) + else if(!bstate && M.dna.GetSEState(block)) // Gene isn't active, but the dna says it is... Was blocked by another gene! + bname = span_orange(bname) + else + bname = span_red(bname) + body += "[bname][block]" // Traitgenes edit - show trait linked names on mouseover else body += "[block]" body+="" @@ -231,9 +234,11 @@ GLOBAL_VAR_INIT(floorIsLava, 0) if(!f) body += " | " else f = 0 if(L in M.languages) - body += "[k]" + k = span_green(k) + body += "[k]" else - body += "[k]" + k = span_red(k) + body += "[k]" body += {"
"} diff --git a/code/modules/library/wikicomp.dm b/code/modules/library/wikicomp.dm index a74302e5c74..bd975632eaf 100644 --- a/code/modules/library/wikicomp.dm +++ b/code/modules/library/wikicomp.dm @@ -56,6 +56,8 @@ data["particle_data"] = null data["catalog_data"] = null data["ore_data"] = null + data["virus_data"] = null + data["gene_data"] = null data["sub_categories"] = null data["donated"] = SSinternal_wiki.get_donation_current() data["goal"] = SSinternal_wiki.get_donation_goal() @@ -112,6 +114,16 @@ if(P) data["ore_data"] = P.get_data() + if("Viruses") + data["search"] = SSinternal_wiki.get_searchcache_viruses() + if(P) + data["virus_data"] = P.get_data() + + if("Genes") + data["search"] = SSinternal_wiki.get_searchcache_genes() + if(P) + data["gene_data"] = P.get_data() + else data["search"] = list() @@ -203,6 +215,10 @@ new_page = SSinternal_wiki.get_page_particle(search) if(searchmode == "Ores") new_page = SSinternal_wiki.get_page_ore(search) + if(searchmode == "Viruses") + new_page = SSinternal_wiki.get_page_virus(search) + if(searchmode == "Genes") + new_page = SSinternal_wiki.get_page_gene(search) if(new_page == P) return FALSE @@ -211,7 +227,7 @@ if(P) doc_title = P.title - doc_body = P.get_print() // TODO - pass get_data() instead, as only printing should use get_print() + doc_body = P.get_print() else doc_title = "Error" doc_body = "Invalid data." diff --git a/code/unit_tests/disease_tests.dm b/code/unit_tests/disease_tests.dm new file mode 100644 index 00000000000..5327b5fdcc9 --- /dev/null +++ b/code/unit_tests/disease_tests.dm @@ -0,0 +1,32 @@ +/datum/unit_test/disease_must_be_valid + name = "DISEASE: All diseases must have valid data" + +/datum/unit_test/disease_must_be_valid/start_test() + var/failed = FALSE + var/list/used_ids = list() + + var/count = 0 + for(var/datum/disease/D as anything in subtypesof(/datum/disease)) + if(initial(D.name) == DEVELOPER_WARNING_NAME) + continue + + count++ + if(initial(D.medical_name) in used_ids) + log_unit_test("[D]: Disease - Had a reused medical name, this is used as an ID and must be unique.") + failed = TRUE + else + used_ids.Add(initial(D.medical_name)) + + if(!initial(D.name) || initial(D.name) == "") + log_unit_test("[D]: Disease - Lacks a name.") + failed = TRUE + + if(!initial(D.desc) || initial(D.desc) == "") + log_unit_test("[D]: Disease - Lacks a description.") + failed = TRUE + + if(failed) + fail("All diseases must have valid data.") + else + pass("All [count] diseases have proper data.") + return failed diff --git a/code/unit_tests/authohiss_tests.dm b/code/unit_tests/trait_tests.dm similarity index 65% rename from code/unit_tests/authohiss_tests.dm rename to code/unit_tests/trait_tests.dm index 0abc49fea67..411e61a4f59 100644 --- a/code/unit_tests/authohiss_tests.dm +++ b/code/unit_tests/trait_tests.dm @@ -1,3 +1,25 @@ +/datum/unit_test/all_traits_unique_names + name = "TRAITS: All traits shall have unique names" + +/datum/unit_test/all_traits_unique_names/start_test() + var/failed = FALSE + + var/list/used_named = list() + for(var/traitpath in GLOB.all_traits) + var/datum/trait/T = GLOB.all_traits[traitpath] + if(T.name in used_named) + log_unit_test("[T.type]: Trait - The name \"[T.name]\" is already in use.") + failed = TRUE + else + used_named.Add(T.name) + + if(failed) + fail("One or more traits shared a name.") + else + pass("All [GLOB.all_traits.len] have unique names.") + return failed + + /datum/unit_test/autohiss_shall_be_exclusive name = "TRAITS: Autohiss traits shall be exclusive" diff --git a/tgui/packages/tgui-panel/settings/settingsImExport.ts b/tgui/packages/tgui-panel/settings/settingsImExport.ts index 70771ef2fa1..5cd8f169dd9 100644 --- a/tgui/packages/tgui-panel/settings/settingsImExport.ts +++ b/tgui/packages/tgui-panel/settings/settingsImExport.ts @@ -5,7 +5,7 @@ import { importSettings } from './actions'; export function exportChatSettings( settings: Record, - pages: Record[], + pages: Record, ) { const opts: SaveFilePickerOptions = { id: `ss13-chatprefs-${Date.now()}`, @@ -18,8 +18,7 @@ export function exportChatSettings( ], }; - const pagesEntry: Record[] = []; - pagesEntry['chatPages'] = pages; + const pagesEntry = { chatPages: pages }; const exportObject = Object.assign(settings, pagesEntry); diff --git a/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiCommon/WikiQuickElements.tsx b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiCommon/WikiQuickElements.tsx index d73cd69fa22..2a3eba9494a 100644 --- a/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiCommon/WikiQuickElements.tsx +++ b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiCommon/WikiQuickElements.tsx @@ -2,11 +2,17 @@ import { Box, LabeledList } from 'tgui-core/components'; import { zeroC } from '../constants'; -export const YesBox = (props) => { +export const YesNoBox = (props: { value: boolean }) => { + const { value } = props; + + return value ? : ; +}; + +const YesBox = (props) => { return Yes; }; -export const NoBox = (props) => { +const NoBox = (props) => { return No; }; diff --git a/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WIkiDonationbanner.tsx b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WIkiDonationbanner.tsx index 58b6ddf9ae1..c4561885888 100644 --- a/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WIkiDonationbanner.tsx +++ b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WIkiDonationbanner.tsx @@ -107,7 +107,7 @@ const WikiDonationContent = (props: { - {donated} / {goal}₮ + {donated}₮ / {goal}₮ {!hideButtons && donated < goal && ( diff --git a/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSearchPage.tsx b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSearchPage.tsx index 70bebef56b8..edf98f6dbef 100644 --- a/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSearchPage.tsx +++ b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSearchPage.tsx @@ -9,10 +9,12 @@ import { WikiBotanyPage } from './WikiSubPages/WikiBotanyPage'; import { WikiCatalogPage } from './WikiSubPages/WIkiCatalogPage'; import { WikiChemistryPage } from './WikiSubPages/WikiChemistryPage'; import { WikiFoodPage } from './WikiSubPages/WikiFoodPage'; +import { WikiGenePage } from './WikiSubPages/WikiGenePage'; import { WikiMaterialPage } from './WikiSubPages/WikiMaterialPage'; import { WikiNoDataPage } from './WikiSubPages/WikiNoDataPage'; import { WikiOrePage } from './WikiSubPages/WikiOrePage'; import { WikiParticlePage } from './WikiSubPages/WikiParticlePage'; +import { WikiVirusPage } from './WikiSubPages/WikiVirusPage'; export const WikiSearchPage = ( props: { @@ -37,6 +39,8 @@ export const WikiSearchPage = ( searchmode, botany_data, ore_data, + virus_data, + gene_data, food_data, drink_data, chemistry_data, @@ -81,6 +85,8 @@ export const WikiSearchPage = ( ); tabs['Botany'] = !!botany_data && ; tabs['Ores'] = !!ore_data && ; + tabs['Viruses'] = !!virus_data && ; + tabs['Genes'] = !!gene_data && ; tabs['Materials'] = !!material_data && ( ); diff --git a/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSubPages/WikiGenePage.tsx b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSubPages/WikiGenePage.tsx new file mode 100644 index 00000000000..b3ba07ab9bf --- /dev/null +++ b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSubPages/WikiGenePage.tsx @@ -0,0 +1,52 @@ +import { Box, LabeledList, Section, Stack } from 'tgui-core/components'; +import { capitalize } from 'tgui-core/string'; + +import { geneTypeToColor } from '../../constants'; +import type { GeneData } from '../../types'; +import { WikiList } from '../../WikiCommon/WikiListElements'; + +export const WikiGenePage = (props: { gene: GeneData }) => { + const { + title, + description, + trait_type, + bounds_off_min, + bounds_off_max, + bounds_on_min, + bounds_on_max, + blockers, + } = props.gene; + + return ( +
+ + + + + + {description ? description : 'No information available!'} + + + + + {trait_type} + + + + {bounds_on_min} - {bounds_on_max} + + + + + {bounds_off_min} - {bounds_off_max} + + + {!!blockers && ( + + )} + + + +
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSubPages/WikiMaterialPage.tsx b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSubPages/WikiMaterialPage.tsx index b706bd4616e..d91b86b4055 100644 --- a/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSubPages/WikiMaterialPage.tsx +++ b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSubPages/WikiMaterialPage.tsx @@ -5,11 +5,10 @@ import type { MaterialData } from '../../types'; import { ColorizedImage } from '../../WikiCommon/WikiColorIcon'; import { WikiSpoileredList } from '../../WikiCommon/WikiListElements'; import { - NoBox, NotAvilableBox, SupplyEntry, TemperatureBox, - YesBox, + YesNoBox, } from '../../WikiCommon/WikiQuickElements'; export const WikiMaterialPage = (props: { materials: MaterialData }) => { @@ -58,10 +57,10 @@ export const WikiMaterialPage = (props: { materials: MaterialData }) => { /> - {opacity > 0.5 ? : } + 0.5} /> - {conductive ? : } + diff --git a/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSubPages/WikiVirusPage.tsx b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSubPages/WikiVirusPage.tsx new file mode 100644 index 00000000000..6e01b8f2fba --- /dev/null +++ b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiPages/WikiSubPages/WikiVirusPage.tsx @@ -0,0 +1,154 @@ +import { Box, Icon, LabeledList, Section, Stack } from 'tgui-core/components'; +import { capitalize } from 'tgui-core/string'; + +import { + virusDiscoveryToColor, + virusInfectivityToColor, + virusResilienceToColor, + virusSpreadToColor, + virusSpreadToIcon, + viursThreatToColor, +} from '../../constants'; +import type { VirusData } from '../../types'; +import { YesNoBox } from '../../WikiCommon/WikiQuickElements'; + +export const WikiVirusPage = (props: { virus: VirusData }) => { + const { + title, + description, + form, + agent, + danger, + infectivity, + resiliance, + max_stages, + discovery, + spread, + all_cures, + aggressive, + curable, + resistable, + carriable, + spread_dead, + infect_synth, + } = props.virus; + + return ( +
+ + + + + {description} + + + + {form} - {agent} + + + {danger} + + + {max_stages} + + + + + + + + {!all_cures ? ' - single treatment' : ''} + + + + + + + + + + + + + {spread} + + + + + {aggressive ? ( + <> + {' - Agressive '} + + + + + ) : ( + '' + )} + + + {!!carriable && ( + + + + {'>'} + + + + {'Transmissable without symptoms'} + + + + + )} + {!!spread_dead && ( + + + + {'>'} + + + + {'Transmissable from dead tissue'} + + + + + )} + {!!infect_synth && ( + + + + {'>'} + + + + {'Inorganic pathogen'} + + + + + )} + + + + + {discovery} + + + + {infectivity} + + + + {resiliance} + + + + +
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/PublicLibraryWiki/constants.ts b/tgui/packages/tgui/interfaces/PublicLibraryWiki/constants.ts index 1fecef5b169..854ac32f83f 100644 --- a/tgui/packages/tgui/interfaces/PublicLibraryWiki/constants.ts +++ b/tgui/packages/tgui/interfaces/PublicLibraryWiki/constants.ts @@ -7,6 +7,8 @@ export const WikiPages = [ 'Materials', 'Ores', 'Particle Physics', + 'Viruses', + 'Genes', ]; export const wikiAds = [ @@ -157,3 +159,64 @@ export const WikiTippOfTheDay = [ 'Your kitchen is a chemistry set too!', 'With Bingle, no sin will remain hidden from sight!', ]; + +export const viursThreatToColor = { + Beneficial: 'green', + Positive: 'olive', + 'No threat': undefined, + Minor: 'yellow', + Medium: '#f5ad42', + Harmful: 'orange', + Dangerous: 'red', + BIOHAZARD: '#b80000', + PANDEMIC: '#990202', +}; + +export const virusSpreadToColor = { + NA: 'label', + Contact: undefined, + Fluids: 'blue', + Blood: 'red', + Airborne: 'teal', + Faltered: 'grey', +}; + +export const virusSpreadToIcon = { + NA: undefined, + Contact: 'handshake', + Fluids: 'water', + Blood: 'droplet', + Airborne: 'wind', + Faltered: 'syringe', +}; + +export const virusDiscoveryToColor = { + 'Extremely Elusive': 'red', + Difficult: 'orange', + Moderate: 'yellow', + Easy: 'olive', + Trivial: undefined, +}; + +export const virusInfectivityToColor = { + High: 'red', + Medium: 'orange', + Low: 'yellow', + NA: undefined, +}; + +export const virusResilienceToColor = { + Extreme: 'red', + High: 'orange', + Medium: 'yellow', + Low: 'olive', +}; + +export const geneTypeToColor = { + Positive: 'green', + 'Super Power': 'teal', + Negative: 'red', + Disability: 'orange', + Neutral: undefined, + Strange: 'purple', +}; diff --git a/tgui/packages/tgui/interfaces/PublicLibraryWiki/index.tsx b/tgui/packages/tgui/interfaces/PublicLibraryWiki/index.tsx index e87367dc17c..9975148d552 100644 --- a/tgui/packages/tgui/interfaces/PublicLibraryWiki/index.tsx +++ b/tgui/packages/tgui/interfaces/PublicLibraryWiki/index.tsx @@ -34,6 +34,8 @@ export const PublicLibraryWiki = (props) => { particle_data, catalog_data, ore_data, + virus_data, + gene_data, has_donated, donated, goal, @@ -148,6 +150,8 @@ export const PublicLibraryWiki = (props) => { chemistry_data={chemistry_data} botany_data={botany_data} ore_data={ore_data} + virus_data={virus_data} + gene_data={gene_data} material_data={material_data} particle_data={particle_data} catalog_data={catalog_data} diff --git a/tgui/packages/tgui/interfaces/PublicLibraryWiki/types.ts b/tgui/packages/tgui/interfaces/PublicLibraryWiki/types.ts index 3c99f720f01..2012ed00f27 100644 --- a/tgui/packages/tgui/interfaces/PublicLibraryWiki/types.ts +++ b/tgui/packages/tgui/interfaces/PublicLibraryWiki/types.ts @@ -22,6 +22,8 @@ export type PageData = { chemistry_data: ReagentData | null; drink_data: DrinkData | null; food_data: FoodData | null; + virus_data: VirusData | null; + gene_data: GeneData | null; }; export type FoodData = DrinkData & Partial<{ recipe: RedipeData }>; @@ -84,6 +86,37 @@ export type OreData = { grind_reagents: Record; } & Icon; +export type VirusData = { + title: string; + description: string | null; + form: string; + agent: string; + danger: string; + infectivity: string; + resiliance: string; + max_stages: number; + discovery: string; + spread: string; + all_cures: BooleanLike; + aggressive: BooleanLike; + curable: BooleanLike; + resistable: BooleanLike; + carriable: BooleanLike; + spread_dead: BooleanLike; + infect_synth: BooleanLike; +}; + +export type GeneData = { + title: string; + description: string | null; + trait_type: string; + blockers: string[] | null; + bounds_off_min: string; + bounds_off_max: string; + bounds_on_min: string; + bounds_on_max: string; +}; + export type ParticleData = { title: string; req_mat: string | null; diff --git a/tgui/packages/tgui/interfaces/common/RankIcon.tsx b/tgui/packages/tgui/interfaces/common/RankIcon.tsx index ae08f32484d..35e1c9a73d9 100644 --- a/tgui/packages/tgui/interfaces/common/RankIcon.tsx +++ b/tgui/packages/tgui/interfaces/common/RankIcon.tsx @@ -591,10 +591,10 @@ const rank2color = { 'Off-duty Explorer': 'white', 'Off-duty Worker': 'white', // AI / Robot - AI: 'maroon', - Cyborg: 'maroon', - Robot: 'maroon', - Drone: 'maroon', + AI: '#800000', + Cyborg: '#800000', + Robot: '#800000', + Drone: '#800000', // Clown / Mime Clown: 'green', Jester: 'green', @@ -627,11 +627,11 @@ const rank2color = { Security: 'red', Combat: 'yellow', Engineering: 'orange', - Gravekeeper: 'maroon', + Gravekeeper: '#800000', Lost: 'grey', - Protector: 'maroon', - Mechanist: 'maroon', - 'Combat Medic': 'maroon', + Protector: '#800000', + Mechanist: '#800000', + 'Combat Medic': '#800000', }; type rank_icon = { rank: string; color: string }; diff --git a/vorestation.dme b/vorestation.dme index 304bc31fd33..7d1e537e02a 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -4548,10 +4548,10 @@ #include "code\modules\xenobio\machinery\processor.dm" #include "code\modules\xgm\xgm_gas_data.dm" #include "code\modules\xgm\xgm_gas_mixture.dm" -#include "code\unit_tests\authohiss_tests.dm" #include "code\unit_tests\clothing_tests.dm" #include "code\unit_tests\cosmetic_tests.dm" #include "code\unit_tests\decl_tests.dm" +#include "code\unit_tests\disease_tests.dm" #include "code\unit_tests\genetics_tests.dm" #include "code\unit_tests\language_tests.dm" #include "code\unit_tests\loadout_tests.dm" @@ -4566,6 +4566,7 @@ #include "code\unit_tests\robot_tests.dm" #include "code\unit_tests\sqlite_tests.dm" #include "code\unit_tests\subsystem_tests.dm" +#include "code\unit_tests\trait_tests.dm" #include "code\unit_tests\unit_test.dm" #include "code\unit_tests\unit_test_vr.dm" #include "code\unit_tests\vore_tests_vr.dm"