From 03f2f3e2b0cd0066955f7201b33fa09998a5a661 Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Wed, 19 Oct 2022 19:23:13 -0700 Subject: [PATCH] Orbit refactor + features part dos: Icons, health bars. (#70580) * orbit refactor + features * Via suggestion Co-Authored-By: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Co-Authored-By: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> * cleanup * readds heatmap optional + bug fix * fixes bugs * naming conventions * what * indeed * modular via suggestion Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> * nice * pai fix * misc searching Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> --- code/datums/id_trim/_id_trim.dm | 2 + code/datums/id_trim/jobs.dm | 33 +++ code/modules/mob/dead/observer/orbit.dm | 19 +- .../tgui/interfaces/Orbit/constants.ts | 43 ++++ .../packages/tgui/interfaces/Orbit/helpers.ts | 106 ++++++++ .../interfaces/{Orbit.tsx => Orbit/index.tsx} | 237 +++++------------- tgui/packages/tgui/interfaces/Orbit/types.ts | 23 ++ 7 files changed, 278 insertions(+), 185 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/Orbit/constants.ts create mode 100644 tgui/packages/tgui/interfaces/Orbit/helpers.ts rename tgui/packages/tgui/interfaces/{Orbit.tsx => Orbit/index.tsx} (53%) create mode 100644 tgui/packages/tgui/interfaces/Orbit/types.ts diff --git a/code/datums/id_trim/_id_trim.dm b/code/datums/id_trim/_id_trim.dm index 7000e2d6b1d..0322d56839e 100644 --- a/code/datums/id_trim/_id_trim.dm +++ b/code/datums/id_trim/_id_trim.dm @@ -16,6 +16,8 @@ var/intern_alt_name = null /// The icon_state associated with this trim, as it will show on the security HUD. var/sechud_icon_state = SECHUD_UNKNOWN + /// Icons to be displayed in the orbit ui. Source: FontAwesome v5. + var/orbit_icon /// Accesses that this trim unlocks on a card it is imprinted on. These accesses never take wildcard slots and can be added and removed at will. var/list/access = list() diff --git a/code/datums/id_trim/jobs.dm b/code/datums/id_trim/jobs.dm index a61c2adf99b..12db61ce654 100644 --- a/code/datums/id_trim/jobs.dm +++ b/code/datums/id_trim/jobs.dm @@ -79,6 +79,7 @@ /datum/id_trim/job/assistant assignment = "Assistant" trim_state = "trim_assistant" + orbit_icon = "toolbox" sechud_icon_state = SECHUD_ASSISTANT minimal_access = list() extra_access = list( @@ -105,6 +106,7 @@ /datum/id_trim/job/atmospheric_technician assignment = "Atmospheric Technician" trim_state = "trim_atmospherictechnician" + orbit_icon = "fan" department_color = COLOR_ENGINEERING_ORANGE subdepartment_color = COLOR_ENGINEERING_ORANGE sechud_icon_state = SECHUD_ATMOSPHERIC_TECHNICIAN @@ -134,6 +136,7 @@ /datum/id_trim/job/bartender assignment = "Bartender" trim_state = "trim_bartender" + orbit_icon = "cocktail" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_BARTENDER @@ -158,6 +161,7 @@ /datum/id_trim/job/botanist assignment = "Botanist" trim_state = "trim_botanist" + orbit_icon = "seedling" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_BOTANIST @@ -182,6 +186,7 @@ assignment = "Captain" intern_alt_name = "Captain-in-Training" trim_state = "trim_captain" + orbit_icon = "crown" department_color = COLOR_COMMAND_BLUE subdepartment_color = COLOR_COMMAND_BLUE department_state = "departmenthead" @@ -204,6 +209,7 @@ /datum/id_trim/job/cargo_technician assignment = "Cargo Technician" trim_state = "trim_cargotechnician" + orbit_icon = "box" department_color = COLOR_CARGO_BROWN subdepartment_color = COLOR_CARGO_BROWN sechud_icon_state = SECHUD_CARGO_TECHNICIAN @@ -228,6 +234,7 @@ /datum/id_trim/job/chaplain assignment = "Chaplain" trim_state = "trim_chaplain" + orbit_icon = "cross" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_CHAPLAIN @@ -249,6 +256,7 @@ /datum/id_trim/job/chemist assignment = "Chemist" trim_state = "trim_chemist" + orbit_icon = "prescription-bottle" department_color = COLOR_MEDICAL_BLUE subdepartment_color = COLOR_MEDICAL_BLUE sechud_icon_state = SECHUD_CHEMIST @@ -275,6 +283,7 @@ assignment = "Chief Engineer" intern_alt_name = "Chief Engineer-in-Training" trim_state = "trim_stationengineer" + orbit_icon = "user-astronaut" department_color = COLOR_COMMAND_BLUE subdepartment_color = COLOR_ENGINEERING_ORANGE department_state = "departmenthead" @@ -316,6 +325,7 @@ assignment = "Chief Medical Officer" intern_alt_name = "Chief Medical Officer-in-Training" trim_state = "trim_medicaldoctor" + orbit_icon = "user-md" department_color = COLOR_COMMAND_BLUE subdepartment_color = COLOR_MEDICAL_BLUE department_state = "departmenthead" @@ -353,6 +363,7 @@ /datum/id_trim/job/clown assignment = "Clown" trim_state = "trim_clown" + orbit_icon = "face-grin-tears" department_color = COLOR_MAGENTA subdepartment_color = COLOR_MAGENTA sechud_icon_state = SECHUD_CLOWN @@ -371,6 +382,7 @@ /datum/id_trim/job/cook assignment = "Cook" trim_state = "trim_cook" + orbit_icon = "utensils" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_COOK @@ -398,6 +410,7 @@ /datum/id_trim/job/curator assignment = "Curator" trim_state = "trim_curator" + orbit_icon = "book" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_CURATOR @@ -418,6 +431,7 @@ /datum/id_trim/job/detective assignment = "Detective" trim_state = "trim_detective" + orbit_icon = "user-secret" department_color = COLOR_SECURITY_RED subdepartment_color = COLOR_SECURITY_RED sechud_icon_state = SECHUD_DETECTIVE @@ -455,6 +469,7 @@ /datum/id_trim/job/geneticist assignment = "Geneticist" trim_state = "trim_geneticist" + orbit_icon = "dna" department_color = COLOR_SCIENCE_PINK subdepartment_color = COLOR_SCIENCE_PINK sechud_icon_state = SECHUD_GENETICIST @@ -482,6 +497,7 @@ assignment = "Head of Personnel" intern_alt_name = "Head of Personnel-in-Training" trim_state = "trim_headofpersonnel" + orbit_icon = "dog" department_color = COLOR_COMMAND_BLUE subdepartment_color = COLOR_SERVICE_LIME department_state = "departmenthead" @@ -532,6 +548,7 @@ assignment = "Head of Security" intern_alt_name = "Head of Security-in-Training" trim_state = "trim_securityofficer" + orbit_icon = "user-shield" department_color = COLOR_COMMAND_BLUE subdepartment_color = COLOR_SECURITY_RED department_state = "departmenthead" @@ -588,6 +605,7 @@ /datum/id_trim/job/janitor assignment = "Janitor" trim_state = "trim_janitor" + orbit_icon = "broom" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_JANITOR @@ -608,6 +626,7 @@ /datum/id_trim/job/lawyer assignment = "Lawyer" trim_state = "trim_lawyer" + orbit_icon = "gavel" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_SECURITY_RED sechud_icon_state = SECHUD_LAWYER @@ -628,6 +647,7 @@ /datum/id_trim/job/medical_doctor assignment = "Medical Doctor" trim_state = "trim_medicaldoctor" + orbit_icon = "staff-snake" department_color = COLOR_MEDICAL_BLUE subdepartment_color = COLOR_MEDICAL_BLUE sechud_icon_state = SECHUD_MEDICAL_DOCTOR @@ -653,6 +673,7 @@ /datum/id_trim/job/mime assignment = "Mime" trim_state = "trim_mime" + orbit_icon = "comment-slash" department_color = COLOR_SILVER subdepartment_color = COLOR_WHITE sechud_icon_state = SECHUD_MIME @@ -671,6 +692,7 @@ /datum/id_trim/job/paramedic assignment = "Paramedic" trim_state = "trim_paramedic" + orbit_icon = "truck-medical" department_color = COLOR_MEDICAL_BLUE subdepartment_color = COLOR_MEDICAL_BLUE sechud_icon_state = SECHUD_PARAMEDIC @@ -700,6 +722,7 @@ /datum/id_trim/job/prisoner assignment = "Prisoner" trim_state = "trim_warden" + orbit_icon = "lock-keyhole" department_color = COLOR_PRISONER_BLACK subdepartment_color = COLOR_PRISONER_ORANGE sechud_icon_state = SECHUD_PRISONER @@ -742,6 +765,7 @@ /datum/id_trim/job/psychologist assignment = "Psychologist" trim_state = "trim_psychologist" + orbit_icon = "brain" department_color = COLOR_SERVICE_LIME subdepartment_color = COLOR_MEDICAL_BLUE sechud_icon_state = SECHUD_PSYCHOLOGIST @@ -762,6 +786,7 @@ /datum/id_trim/job/quartermaster assignment = "Quartermaster" trim_state = "trim_quartermaster" + orbit_icon = "sack-dollar" department_color = COLOR_COMMAND_BLUE subdepartment_color = COLOR_CARGO_BROWN department_state = "departmenthead" @@ -797,6 +822,7 @@ assignment = "Research Director" intern_alt_name = "Research Director-in-Training" trim_state = "trim_scientist" + orbit_icon = "user-graduate" department_color = COLOR_COMMAND_BLUE subdepartment_color = COLOR_SCIENCE_PINK department_state = "departmenthead" @@ -844,6 +870,7 @@ /datum/id_trim/job/roboticist assignment = "Roboticist" trim_state = "trim_roboticist" + orbit_icon = "battery-half" department_color = COLOR_SCIENCE_PINK subdepartment_color = COLOR_SCIENCE_PINK sechud_icon_state = SECHUD_ROBOTICIST @@ -871,6 +898,7 @@ /datum/id_trim/job/scientist assignment = "Scientist" trim_state = "trim_scientist" + orbit_icon = "flask" department_color = COLOR_SCIENCE_PINK subdepartment_color = COLOR_SCIENCE_PINK sechud_icon_state = SECHUD_SCIENTIST @@ -899,6 +927,7 @@ /datum/id_trim/job/security_officer assignment = "Security Officer" trim_state = "trim_securityofficer" + orbit_icon = "shield-halved" department_color = COLOR_SECURITY_RED subdepartment_color = COLOR_SECURITY_RED sechud_icon_state = SECHUD_SECURITY_OFFICER @@ -1019,6 +1048,7 @@ /datum/id_trim/job/shaft_miner assignment = "Shaft Miner" trim_state = "trim_shaftminer" + orbit_icon = "digging" department_color = COLOR_CARGO_BROWN subdepartment_color = COLOR_SCIENCE_PINK sechud_icon_state = SECHUD_SHAFT_MINER @@ -1055,6 +1085,7 @@ /datum/id_trim/job/station_engineer assignment = "Station Engineer" trim_state = "trim_stationengineer" + orbit_icon = "gears" department_color = COLOR_ENGINEERING_ORANGE subdepartment_color = COLOR_ENGINEERING_ORANGE sechud_icon_state = SECHUD_STATION_ENGINEER @@ -1084,6 +1115,7 @@ /datum/id_trim/job/virologist assignment = "Virologist" trim_state = "trim_virologist" + orbit_icon = "virus" department_color = COLOR_MEDICAL_BLUE subdepartment_color = COLOR_MEDICAL_BLUE sechud_icon_state = SECHUD_VIROLOGIST @@ -1108,6 +1140,7 @@ /datum/id_trim/job/warden assignment = "Warden" trim_state = "trim_warden" + orbit_icon = "handcuffs" department_color = COLOR_SECURITY_RED subdepartment_color = COLOR_SECURITY_RED sechud_icon_state = SECHUD_WARDEN diff --git a/code/modules/mob/dead/observer/orbit.dm b/code/modules/mob/dead/observer/orbit.dm index dd2efeb58b4..dd31f6c085d 100644 --- a/code/modules/mob/dead/observer/orbit.dm +++ b/code/modules/mob/dead/observer/orbit.dm @@ -81,14 +81,18 @@ GLOBAL_DATUM_INIT(orbit_menu, /datum/orbit_menu, new) var/datum/mind/mind = mob_poi.mind var/was_antagonist = FALSE - serialized["job"] = mind?.assigned_role?.title serialized["name"] = mob_poi.real_name - serialized["health"] = null - // Cast the mob so we can get health - var/mob/living/player - if(isliving(mob_poi)) // Kind of silly here since we've already checked for dead mobs - player = mob_poi + + if(isliving(mob_poi)) // handles edge cases like blob + var/mob/living/player = mob_poi serialized["health"] = FLOOR((player.health / player.maxHealth * 100), 1) + if(issilicon(player)) + serialized["job"] = player.job + else + var/obj/item/card/id/id_card = player.get_idcard(hand_first = FALSE) + serialized["job"] = id_card?.get_trim_assignment() + var/datum/id_trim/trim = id_card?.trim + serialized["job_icon"] = trim?.orbit_icon for(var/datum/antagonist/antag_datum as anything in mind.antag_datums) if (antag_datum.show_to_ghosts) @@ -105,8 +109,7 @@ GLOBAL_DATUM_INIT(orbit_menu, /datum/orbit_menu, new) misc += list(list( "ref" = REF(atom_poi), - "name" = name, - "extra" = null, // Just in case you want to add anything + "full_name" = name, )) // Display the supermatter crystal integrity diff --git a/tgui/packages/tgui/interfaces/Orbit/constants.ts b/tgui/packages/tgui/interfaces/Orbit/constants.ts new file mode 100644 index 00000000000..55b06984cb4 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/constants.ts @@ -0,0 +1,43 @@ +export const ANTAG2COLOR = { + 'Abductors': 'pink', + 'Ash Walkers': 'olive', + 'Biohazards': 'brown', + 'CentCom': 'teal', +} as const; + +export const ANTAG2GROUP = { + 'Abductor Agent': 'Abductors', + 'Abductor Scientist': 'Abductors', + 'Ash Walker': 'Ash Walkers', + 'Blob': 'Biohazards', + 'Sentient Disease': 'Biohazards', + 'CentCom Commander': 'CentCom', + 'CentCom Head Intern': 'CentCom', + 'CentCom Intern': 'CentCom', + 'CentCom Official': 'CentCom', + 'Central Command': 'CentCom', + 'Clown Operative': 'Clown Operatives', + 'Clown Operative Leader': 'Clown Operatives', + 'Nuclear Operative': 'Nuclear Operatives', + 'Nuclear Operative Leader': 'Nuclear Operatives', + 'Space Wizard': 'Wizard Federation', + 'Wizard Apprentice': 'Wizard Federation', + 'Wizard Minion': 'Wizard Federation', +} as const; + +export const JOB2ICON = { + 'AI': 'eye', + 'Cyborg': 'robot', + 'Personal AI': 'mobile-alt', +} as const; + +export enum THREAT { + Low = 2, + Medium = 5, + High = 8, +} + +export enum HEALTH { + Good = 69, + Average = 19, +} diff --git a/tgui/packages/tgui/interfaces/Orbit/helpers.ts b/tgui/packages/tgui/interfaces/Orbit/helpers.ts new file mode 100644 index 00000000000..f99d35ab5a4 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/helpers.ts @@ -0,0 +1,106 @@ +import { sortBy } from 'common/collections'; +import { ANTAG2GROUP, HEALTH, THREAT } from './constants'; +import type { AntagGroup, Antags, Observable } from './types'; + +/** + * Collates antagonist groups into their own separate sections. + * Some antags are grouped together lest they be listed separately, + * ie: Nuclear Operatives. See: ANTAG_GROUPS. + */ +export const collateAntagonists = (antagonists: Antags) => { + const collatedAntagonists = {}; // Hate that I cant use a map here + antagonists.map((player) => { + const { antag } = player; + const resolvedName: string = ANTAG2GROUP[antag] || antag; + if (!collatedAntagonists[resolvedName]) { + collatedAntagonists[resolvedName] = []; + } + collatedAntagonists[resolvedName].push(player); + }); + const sortedAntagonists = sortBy(([key]) => key)( + Object.entries(collatedAntagonists) + ); + + return sortedAntagonists; +}; + +/** Returns a disguised name in case the person is wearing someone else's ID */ +export const getDisplayName = (full_name: string, name?: string) => { + if (!name) { + return full_name; + } + if ( + !full_name?.includes('[') || + full_name.match(/\(as /) || + full_name.match(/^Unknown/) + ) { + return name; + } + // return only the name before the first ' [' or ' (' + return `"${full_name.split(/ \[| \(/)[0]}"`; +}; + +/** Returns the display color for certain health percentages */ +const getHealthColor = (health: number) => { + switch (true) { + case health > HEALTH.Good: + return 'good'; + case health > HEALTH.Average: + return 'average'; + default: + return 'bad'; + } +}; + +/** Returns the display color based on orbiter numbers */ +const getThreatColor = (orbiters: number) => { + switch (true) { + case orbiters > THREAT.High: + return 'violet'; + case orbiters > THREAT.Medium: + return 'blue'; + case orbiters > THREAT.Low: + return 'teal'; + default: + return 'good'; + } +}; + +/** + * ### getDisplayColor + * Displays color for buttons based on the health or orbiter count. Toggleable. + * @param {Observable} item - The point of interest. + * @param {boolean} heatMap - Whether the user has heat map toggled. + * @param {string} color - OPTIONAL: The color to default to. + */ +export const getDisplayColor = ( + item: Observable, + heatMap: boolean, + color?: string +) => { + const { health, orbiters = 0 } = item; + if (typeof health !== 'number') { + return color ? 'good' : 'grey'; + } + if (heatMap) { + return getThreatColor(orbiters); + } + return getHealthColor(health); +}; + +/** Checks if a full name or job title matches the search. */ +export const isJobOrNameMatch = ( + observable: Observable, + searchQuery: string +) => { + if (!searchQuery) { + return true; + } + const { full_name, job } = observable; + + return ( + full_name?.toLowerCase().includes(searchQuery?.toLowerCase()) || + job?.toLowerCase().includes(searchQuery?.toLowerCase()) || + false + ); +}; diff --git a/tgui/packages/tgui/interfaces/Orbit.tsx b/tgui/packages/tgui/interfaces/Orbit/index.tsx similarity index 53% rename from tgui/packages/tgui/interfaces/Orbit.tsx rename to tgui/packages/tgui/interfaces/Orbit/index.tsx index 69211ee824a..c2b3644f403 100644 --- a/tgui/packages/tgui/interfaces/Orbit.tsx +++ b/tgui/packages/tgui/interfaces/Orbit/index.tsx @@ -1,73 +1,19 @@ -import { useBackend, useLocalState } from '../backend'; import { filter, sortBy } from 'common/collections'; -import { capitalizeFirst, multiline } from 'common/string'; -import { Box, Button, Collapsible, Icon, Input, LabeledList, NoticeBox, Section, Stack } from '../components'; -import { Window } from '../layouts'; import { flow } from 'common/fp'; - -type AntagGroup = [string, Antags]; - -type Antags = Array; - -type Data = { - alive: Array; - antagonists: Antags; - dead: Array; - ghosts: Array; - misc: Array; - npcs: Array; -}; - -type Observable = { - extra?: string; - full_name: string; - health?: number; - job?: string; - name?: string; - orbiters?: number; - ref: string; -}; - -const ANTAG2COLOR = { - 'Abductors': 'pink', - 'Ash Walkers': 'olive', - 'Biohazards': 'brown', - 'CentCom': 'teal', -} as const; - -const ANTAG2GROUP = { - 'Abductor Agent': 'Abductors', - 'Abductor Scientist': 'Abductors', - 'Ash Walker': 'Ash Walkers', - 'Blob': 'Biohazards', - 'Sentient Disease': 'Biohazards', - 'CentCom Commander': 'CentCom', - 'CentCom Head Intern': 'CentCom', - 'CentCom Intern': 'CentCom', - 'CentCom Official': 'CentCom', - 'Central Command': 'CentCom', - 'Clown Operative': 'Clown Operatives', - 'Clown Operative Leader': 'Clown Operatives', - 'Nuclear Operative': 'Nuclear Operatives', - 'Nuclear Operative Leader': 'Nuclear Operatives', - 'Space Wizard': 'Wizard Federation', - 'Wizard Apprentice': 'Wizard Federation', - 'Wizard Minion': 'Wizard Federation', -} as const; - -enum THREAT { - None, - Small = 'teal', - Medium = 'blue', - Large = 'violet', -} +import { capitalizeFirst, multiline } from 'common/string'; +import { useBackend, useLocalState } from 'tgui/backend'; +import { Button, Collapsible, Icon, Input, LabeledList, NoticeBox, Section, Stack } from 'tgui/components'; +import { Window } from 'tgui/layouts'; +import { collateAntagonists, getDisplayColor, getDisplayName, isJobOrNameMatch } from './helpers'; +import { ANTAG2COLOR, JOB2ICON } from './constants'; +import type { AntagGroup, Observable, OrbitData } from './types'; export const Orbit = (props, context) => { return ( - + @@ -83,7 +29,7 @@ export const Orbit = (props, context) => { /** Controls filtering out the list of observables via search */ const ObservableSearch = (props, context) => { - const { act, data } = useBackend(context); + const { act, data } = useBackend(context); const { alive = [], antagonists = [], @@ -97,13 +43,18 @@ const ObservableSearch = (props, context) => { 'autoObserve', false ); + const [heatMap, setHeatMap] = useLocalState( + context, + 'heatMap', + false + ); const [searchQuery, setSearchQuery] = useLocalState( context, 'searchQuery', '' ); /** Gets a list of Observables, then filters the most relevant to orbit */ - const orbitMostRelevant = (searchQuery: string): void => { + const orbitMostRelevant = (searchQuery: string) => { /** Returns the most orbited observable that matches the search. */ const mostRelevant: Observable = flow([ // Filters out anything that doesn't match search @@ -139,6 +90,16 @@ const ObservableSearch = (props, context) => { /> + + @@ -283,6 +247,7 @@ const ObservableTooltip = (props: { item: Observable }) => { item: { extra, full_name, job, health }, } = props; const extraInfo = extra?.split(':'); + const displayHealth = !!health && health >= 0 ? `${health}%` : 'Critical'; return ( <> @@ -290,106 +255,24 @@ const ObservableTooltip = (props: { item: Observable }) => { Last Known Data - {!!extraInfo && ( + {extraInfo ? ( {extraInfo[1]} - )} - {!!full_name && ( - {full_name} - )} - {!!job && {job}} - {!!health && ( - - {getHealthLabel(health!)} - + ) : ( + <> + {!!full_name && ( + {full_name} + )} + {!!job && {job}} + {!!health && ( + + {displayHealth} + + )} + )} ); }; - -/** - * Collates antagonist groups into their own separate sections. - * Some antags are grouped together lest they be listed separately, - * ie: Nuclear Operatives. See: ANTAG_GROUPS. - */ -const collateAntagonists = (antagonists: Antags) => { - const collatedAntagonists = {}; // Hate that I cant use a map here - antagonists.map((player) => { - const { antag } = player; - const resolvedName: string = ANTAG2GROUP[antag] || antag; - if (!collatedAntagonists[resolvedName]) { - collatedAntagonists[resolvedName] = []; - } - collatedAntagonists[resolvedName].push(player); - }); - const sortedAntagonists = sortBy(([key]) => key)( - Object.entries(collatedAntagonists) - ); - - return sortedAntagonists; -}; - -/** Returns a disguised name in case the person is wearing someone else's ID */ -const getDisplayName = (name: string | undefined, full_name: string) => { - if (!name) { - return full_name; - } - if ( - !full_name?.includes('[') || - full_name.match(/\(as /) || - full_name.match(/^Unknown/) - ) { - return name; - } - // return only the name before the first ' [' or ' (' - return `"${full_name.split(/ \[| \(/)[0]}"`; -}; - -/** Returns some labels for a player's health */ -const getHealthLabel = (health: number) => { - if (health >= 100) { - return Great; - } - if (health >= 75) { - return Good; - } - if (health >= 50) { - return Fair; - } - if (health >= 25) { - return Poor; - } - if (health > 0) { - return Bad; - } - if (health <= 0) { - return Critical; - } -}; - -/** Takes the amount of orbiters and returns some style options */ -const getThreat = (orbiters: number) => { - if (!orbiters || orbiters <= 2) { - return THREAT.None; - } else if (orbiters === 3) { - return THREAT.Small; - } else if (orbiters <= 6) { - return THREAT.Medium; - } else { - return THREAT.Large; - } -}; - -/** Checks if a full name or job title matches the search. */ -const isJobOrNameMatch = (observable: Observable, searchQuery: string) => { - const { full_name, name, job } = observable; - const displayName = full_name ?? name; - - return ( - displayName?.toLowerCase().includes(searchQuery?.toLowerCase()) || - job?.toLowerCase().includes(searchQuery?.toLowerCase()) || - false - ); -}; diff --git a/tgui/packages/tgui/interfaces/Orbit/types.ts b/tgui/packages/tgui/interfaces/Orbit/types.ts new file mode 100644 index 00000000000..1d49a5178ac --- /dev/null +++ b/tgui/packages/tgui/interfaces/Orbit/types.ts @@ -0,0 +1,23 @@ +export type AntagGroup = [string, Antags]; + +export type Antags = Array; + +export type OrbitData = { + alive: Array; + antagonists: Antags; + dead: Array; + ghosts: Array; + misc: Array; + npcs: Array; +}; + +export type Observable = { + extra?: string; + full_name: string; + health?: number; + job?: string; + job_icon?: string; + name?: string; + orbiters?: number; + ref: string; +};