[MIRROR] Bingle them viruses (#11094)

Co-authored-by: Will <7099514+Willburd@users.noreply.github.com>
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
CHOMPStation2StaffMirrorBot
2025-06-20 02:30:14 -07:00
committed by GitHub
parent 91f4f951ad
commit 5886b748bf
18 changed files with 642 additions and 37 deletions

View File

@@ -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 += "<b>Description: </b>[data["description"]]<br>"
body += "<br>"
body += "<b>Type: [data["form"]] - [data["agent"]]</b><br>"
body += "<b>Hazard Level: [data["danger"]]</b><br>"
body += "<b>Growth Stages: [data["max_stages"]]</b><br>"
body += "<b>Curable: [(data["curable"]) ? "Yes" : "No"][!(data["all_cures"]) ? " - single treatment" : ""]</b><br>"
body += "<b>Resistable: [(data["resistable"]) ? "Yes" : "No"]</b><br>"
body += "<br>"
// Transmission type
body += "<b>Transmission: [data["spread"]] [(data["aggressive"]) ? "Aggressive" : ""]</b><br>"
if(data["carriable"])
body += "<b>Transmissable without symptoms</b><br>"
if(data["spread_dead"])
body += "<b>Transmissable from dead tissue</b><br>"
if(data["infect_synth"])
body += "<b>Inorganic pathogen</b><br>"
// Difficulty of discovery
body += "<b>Discoverability: [data["discovery"]]</b><br>"
// Probability of spreading
body += "<b>Infectivity: [data["infectivity"]]</b><br>"
// Probability of cure, 10 to 20 regularly
body += "<b>Resiliance: [data["resiliance"]]</b><br>"
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 += "<b>Description: </b>[data["description"]]<br>"
body += "<br>"
body += "<b>Type: [data["trait_type"]]</b><br>"
body += "<b>Active Range: [data["bounds_on_min"]] - [data["bounds_on_max"]]</b><br>"
body += "<b>Inactive Range: [data["bounds_off_min"]] - [data["bounds_off_max"]]</b><br>"
body += "<br>"
var/list/blockers = data["blockers"]
if(blockers)
body += "<b>Suppressed By:</b><br>"
for(var/trait_name in blockers)
body += "-[trait_name]<br>"
return body
// MISC HELPERS
////////////////////////////////////////////
/datum/internal_wiki/page/proc/print_allergens(var/list/allergens)

View File

@@ -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

View File

@@ -89,13 +89,13 @@ GLOBAL_VAR_INIT(floorIsLava, 0)
body += "\ <A href='byond://?src=\ref[src];[HrefToken()];sendbacktolobby=\ref[M]'>Send back to Lobby</A> | "
var/muted = M.client.prefs.muted
body += {"<br>"} + span_bold("Mute: ") + {"
\[<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_IC]'><font color='[(muted & MUTE_IC)?"red":"blue"]'>IC</font></a> |
<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_OOC]'><font color='[(muted & MUTE_OOC)?"red":"blue"]'>OOC</font></a> |
<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_LOOC]'><font color='[(muted & MUTE_LOOC)?"red":"blue"]'>LOOC</font></a> |
<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_PRAY]'><font color='[(muted & MUTE_PRAY)?"red":"blue"]'>PRAY</font></a> |
<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_ADMINHELP]'><font color='[(muted & MUTE_ADMINHELP)?"red":"blue"]'>ADMINHELP</font></a> |
<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_DEADCHAT]'><font color='[(muted & MUTE_DEADCHAT)?"red":"blue"]'>DEADCHAT</font></a>\]
(<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_ALL]'><font color='[(muted & MUTE_ALL)?"red":"blue"]'>toggle all</font></a>)
\[<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_IC]'>[(muted & MUTE_IC) ? span_red("IC") : span_blue("IC")]</a> |
<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_OOC]'>[(muted & MUTE_OOC) ? span_red("OOC") : span_blue("OOC")]</a> |
<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_LOOC]'>[(muted & MUTE_LOOC) ? span_red("LOOC") : span_blue("LOOC")]</a> |
<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_PRAY]'>[(muted & MUTE_PRAY) ? span_red("PRAY") : span_blue("PRAY")]</a> |
<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_ADMINHELP]'>[(muted & MUTE_ADMINHELP) ? span_red("ADMINHELP") : span_blue("ADMINHELP")]</a> |
<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_DEADCHAT]'>[(muted & MUTE_DEADCHAT) ? span_red("DEADCHAT") : span_blue("DEADCHAT")]</a>\]
(<A href='byond://?src=\ref[src];[HrefToken()];mute=\ref[M];mute_type=[MUTE_ALL]'>[(muted & MUTE_ALL) ? span_red("toggle all") : span_blue("toggle all")]</a>)
"}
body += {"<br><br>
@@ -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 += "<A href='byond://?src=\ref[src];[HrefToken()];togmutate=\ref[M];block=[block]' style='color:[bcolor];' title='[tname]'>[bname]</A><sub>[block]</sub>" // 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 += "<A href='byond://?src=\ref[src];[HrefToken()];togmutate=\ref[M];block=[block]' title='[tname]'>[bname]</A><sub>[block]</sub>" // Traitgenes edit - show trait linked names on mouseover
else
body += "[block]"
body+="</td>"
@@ -231,9 +234,11 @@ GLOBAL_VAR_INIT(floorIsLava, 0)
if(!f) body += " | "
else f = 0
if(L in M.languages)
body += "<a href='byond://?src=\ref[src];[HrefToken()];toglang=\ref[M];lang=[html_encode(k)]' style='color:#006600'>[k]</a>"
k = span_green(k)
body += "<a href='byond://?src=\ref[src];[HrefToken()];toglang=\ref[M];lang=[html_encode(k)]'>[k]</a>"
else
body += "<a href='byond://?src=\ref[src];[HrefToken()];toglang=\ref[M];lang=[html_encode(k)]' style='color:#ff0000'>[k]</a>"
k = span_red(k)
body += "<a href='byond://?src=\ref[src];[HrefToken()];toglang=\ref[M];lang=[html_encode(k)]'>[k]</a>"
body += {"<br>"}

View File

@@ -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."

View File

@@ -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

View File

@@ -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"

View File

@@ -5,7 +5,7 @@ import { importSettings } from './actions';
export function exportChatSettings(
settings: Record<string, any>,
pages: Record<string, Page>[],
pages: Record<string, Page>,
) {
const opts: SaveFilePickerOptions = {
id: `ss13-chatprefs-${Date.now()}`,
@@ -18,8 +18,7 @@ export function exportChatSettings(
],
};
const pagesEntry: Record<string, Page>[] = [];
pagesEntry['chatPages'] = pages;
const pagesEntry = { chatPages: pages };
const exportObject = Object.assign(settings, pagesEntry);

View File

@@ -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 ? <YesBox /> : <NoBox />;
};
const YesBox = (props) => {
return <Box textColor="green">Yes</Box>;
};
export const NoBox = (props) => {
const NoBox = (props) => {
return <Box textColor="red">No</Box>;
};

View File

@@ -107,7 +107,7 @@ const WikiDonationContent = (props: {
</Stack.Item>
<Stack.Item>
<Box>
{donated} / {goal}
{donated} / {goal}
</Box>
</Stack.Item>
{!hideButtons && donated < goal && (

View File

@@ -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 && <WikiBotanyPage seeds={botany_data} />;
tabs['Ores'] = !!ore_data && <WikiOrePage ores={ore_data} />;
tabs['Viruses'] = !!virus_data && <WikiVirusPage virus={virus_data} />;
tabs['Genes'] = !!gene_data && <WikiGenePage gene={gene_data} />;
tabs['Materials'] = !!material_data && (
<WikiMaterialPage materials={material_data} />
);

View File

@@ -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 (
<Section fill scrollable title={capitalize(title)}>
<Stack vertical fill>
<Stack.Item grow>
<LabeledList>
<LabeledList.Item label="Description">
<Box color={description ? undefined : 'label'}>
{description ? description : 'No information available!'}
</Box>
</LabeledList.Item>
<LabeledList.Divider />
<LabeledList.Item label="Type">
<Box color={geneTypeToColor[trait_type]}>{trait_type}</Box>
</LabeledList.Item>
<LabeledList.Item label="Active Range">
<Box color="green">
{bounds_on_min} - {bounds_on_max}
</Box>
</LabeledList.Item>
<LabeledList.Item label="Inactive Range">
<Box color="red">
{bounds_off_min} - {bounds_off_max}
</Box>
</LabeledList.Item>
{!!blockers && (
<WikiList entries={blockers} title="Suppressed By" />
)}
</LabeledList>
</Stack.Item>
</Stack>
</Section>
);
};

View File

@@ -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 }) => {
/>
<LabeledList.Divider />
<LabeledList.Item label="Transparent">
{opacity > 0.5 ? <YesBox /> : <NoBox />}
<YesNoBox value={opacity > 0.5} />
</LabeledList.Item>
<LabeledList.Item label="Conductive">
{conductive ? <YesBox /> : <NoBox />}
<YesNoBox value={!!conductive} />
</LabeledList.Item>
<LabeledList.Divider />
<LabeledList.Item label="Stability">

View File

@@ -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 (
<Section fill scrollable title={capitalize(title)}>
<Stack vertical fill>
<Stack.Item grow>
<LabeledList>
<LabeledList.Item label="Description">
{description}
</LabeledList.Item>
<LabeledList.Divider />
<LabeledList.Item label="Type">
{form} - {agent}
</LabeledList.Item>
<LabeledList.Item label="Hazard Level">
<Box color={viursThreatToColor[danger]}>{danger}</Box>
</LabeledList.Item>
<LabeledList.Item label="Growth Stages">
<Box>{max_stages}</Box>
</LabeledList.Item>
<LabeledList.Item label="Curable">
<Stack>
<Stack.Item>
<YesNoBox value={!!curable} />
</Stack.Item>
<Stack.Item>
{!all_cures ? ' - single treatment' : ''}
</Stack.Item>
</Stack>
</LabeledList.Item>
<LabeledList.Item label="Resistable">
<YesNoBox value={!!resistable} />
</LabeledList.Item>
<LabeledList.Divider />
<LabeledList.Item label="Transmission">
<Stack vertical>
<Stack.Item>
<Stack>
<Stack.Item>
<Box>{spread}</Box>
</Stack.Item>
<Stack.Item>
<Icon
color={virusSpreadToColor[spread]}
name={virusSpreadToIcon[spread]}
/>
</Stack.Item>
{aggressive ? (
<>
<Stack.Item>{' - Agressive '}</Stack.Item>
<Stack.Item>
<Icon name={'triangle-exclamation'} />
</Stack.Item>
</>
) : (
''
)}
</Stack>
</Stack.Item>
{!!carriable && (
<Stack.Item>
<Stack>
<Stack.Item>
<Box inline>{'>'}</Box>
</Stack.Item>
<Stack.Item>
<Box inline color="yellow">
{'Transmissable without symptoms'}
</Box>
</Stack.Item>
</Stack>
</Stack.Item>
)}
{!!spread_dead && (
<Stack.Item>
<Stack>
<Stack.Item>
<Box inline>{'>'}</Box>
</Stack.Item>
<Stack.Item>
<Box inline color="yellow">
{'Transmissable from dead tissue'}
</Box>
</Stack.Item>
</Stack>
</Stack.Item>
)}
{!!infect_synth && (
<Stack.Item>
<Stack>
<Stack.Item>
<Box inline>{'>'}</Box>
</Stack.Item>
<Stack.Item>
<Box inline color="yellow">
{'Inorganic pathogen'}
</Box>
</Stack.Item>
</Stack>
</Stack.Item>
)}
</Stack>
</LabeledList.Item>
<LabeledList.Divider />
<LabeledList.Item label="Discoverability">
<Box color={virusDiscoveryToColor[discovery]}>{discovery}</Box>
</LabeledList.Item>
<LabeledList.Item label="Infectivity">
<Box color={virusInfectivityToColor[infectivity]}>
{infectivity}
</Box>
</LabeledList.Item>
<LabeledList.Item label="Resiliance">
<Box color={virusResilienceToColor[resiliance]}>{resiliance}</Box>
</LabeledList.Item>
</LabeledList>
</Stack.Item>
</Stack>
</Section>
);
};

View File

@@ -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',
};

View File

@@ -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}

View File

@@ -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<string, string>;
} & 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;

View File

@@ -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 };

View File

@@ -4801,10 +4801,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"
@@ -4819,6 +4819,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"