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"