From 3faaf783c5c2de0d044ff5a52053d70ee3883ea0 Mon Sep 17 00:00:00 2001 From: Gyran <62253058+Gyrandola@users.noreply.github.com> Date: Mon, 3 Apr 2023 03:04:04 +0200 Subject: [PATCH] [MODULAR] Handheld Blueshield Monitor (#20280) Adds the blueshield's handheld monitor --- .../modules/blueshield/code/devices/crew.dm | 133 ++++++++++++ .../blueshield/code/devices/sensor_device.dm | 8 + .../modules/blueshield/code/medkit.dm | 3 +- .../modules/blueshield/icons/device.dmi | Bin 0 -> 499 bytes tgstation.dme | 2 + .../interfaces/CrewConsoleSkyratBlueshield.js | 199 ++++++++++++++++++ 6 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 modular_skyrat/modules/blueshield/code/devices/crew.dm create mode 100644 modular_skyrat/modules/blueshield/code/devices/sensor_device.dm create mode 100644 modular_skyrat/modules/blueshield/icons/device.dmi create mode 100644 tgui/packages/tgui/interfaces/CrewConsoleSkyratBlueshield.js diff --git a/modular_skyrat/modules/blueshield/code/devices/crew.dm b/modular_skyrat/modules/blueshield/code/devices/crew.dm new file mode 100644 index 00000000000..fe15297f8f2 --- /dev/null +++ b/modular_skyrat/modules/blueshield/code/devices/crew.dm @@ -0,0 +1,133 @@ +/* +* Trimmed and modified copy of ".../machinery/computer/crew.dm" +* for the sake of modularity. (Blueshield Monitor Console soon?) +*/ + +#define SENSORS_UPDATE_PERIOD (10 SECONDS) + +GLOBAL_DATUM_INIT(blueshield_crewmonitor, /datum/crewmonitor/blueshield, new) + +//list of all Command/CC jobs +/datum/crewmonitor/blueshield + var/list/jobs_command = list( + JOB_CAPTAIN = 00, + JOB_HEAD_OF_SECURITY = 10, + JOB_CHIEF_MEDICAL_OFFICER = 20, + JOB_RESEARCH_DIRECTOR = 30, + JOB_CHIEF_ENGINEER = 40, + JOB_QUARTERMASTER = 50, + JOB_HEAD_OF_PERSONNEL = 60, + JOB_CENTCOM_ADMIRAL = 200, + JOB_CENTCOM = 201, + JOB_CENTCOM_OFFICIAL = 210, + JOB_CENTCOM_COMMANDER = 211, + JOB_CENTCOM_BARTENDER = 212, + JOB_CENTCOM_CUSTODIAN = 213, + JOB_CENTCOM_MEDICAL_DOCTOR = 214, + JOB_CENTCOM_RESEARCH_OFFICER = 215, + JOB_ERT_COMMANDER = 220, + JOB_ERT_OFFICER = 221, + JOB_ERT_ENGINEER = 222, + JOB_ERT_MEDICAL_DOCTOR = 223, + JOB_ERT_CLOWN = 224, + JOB_ERT_CHAPLAIN = 225, + JOB_ERT_JANITOR = 226, + JOB_ERT_DEATHSQUAD = 227, + JOB_NT_REP = 230, + JOB_BLUESHIELD = 231, + ) + +/datum/crewmonitor/blueshield/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if (!ui) + ui = new(user, src, "CrewConsoleSkyratBlueshield") + ui.open() + +/* +* Override of crewmonitor/update_data(z) +* - "trim_assignment" is now iterated for command-only jobs +* - "if (id_card)" now encapsulates all the remaining checks to avoid showing unknowns +*/ +/datum/crewmonitor/blueshield/update_data(z) + if(data_by_z["[z]"] && last_update["[z]"] && world.time <= last_update["[z]"] + SENSORS_UPDATE_PERIOD) + return data_by_z["[z]"] + + var/list/results = list() + for(var/tracked_mob in GLOB.suit_sensors_list) + if(!tracked_mob) + stack_trace("Null entry in suit sensors list.") + continue + + var/mob/living/tracked_living_mob = tracked_mob + + var/turf/pos = get_turf(tracked_living_mob) + + if(!pos) + stack_trace("Tracked mob has no loc and is likely in nullspace: [tracked_living_mob] ([tracked_living_mob.type])") + continue + + if(pos.z != z && (!is_station_level(pos.z) || !is_station_level(z)) && !HAS_TRAIT(tracked_living_mob, TRAIT_MULTIZ_SUIT_SENSORS)) + continue + + var/mob/living/carbon/human/tracked_human = tracked_living_mob + + if(!ishuman(tracked_human)) + stack_trace("Non-human mob is in suit_sensors_list: [tracked_living_mob] ([tracked_living_mob.type])") + continue + + var/obj/item/clothing/under/uniform = tracked_human.w_uniform + if (!istype(uniform)) + stack_trace("Human without a suit sensors compatible uniform is in suit_sensors_list: [tracked_human] ([tracked_human.type]) ([uniform?.type])") + continue + + if((uniform.has_sensor <= NO_SENSORS) || !uniform.sensor_mode) + stack_trace("Human without active suit sensors is in suit_sensors_list: [tracked_human] ([tracked_human.type]) ([uniform.type])") + continue + + var/sensor_mode = uniform.sensor_mode + var/list/entry = list() + + var/obj/item/card/id/id_card = tracked_living_mob.get_idcard(hand_first = FALSE) + if (id_card) + + entry["name"] = id_card.registered_name + entry["assignment"] = id_card.assignment + var/trim_assignment = id_card.get_trim_assignment() + + //Check if they are command + if (jobs_command[trim_assignment] != null) + entry["ijob"] = jobs_command[trim_assignment] + else + continue + + if (issynthetic(tracked_human)) + entry["is_robot"] = TRUE + + if (sensor_mode >= SENSOR_LIVING) + entry["life_status"] = (tracked_living_mob.stat != DEAD) + + if (sensor_mode >= SENSOR_VITALS) + entry += list( + "oxydam" = round(tracked_living_mob.getOxyLoss(), 1), + "toxdam" = round(tracked_living_mob.getToxLoss(), 1), + "burndam" = round(tracked_living_mob.getFireLoss(), 1), + "brutedam" = round(tracked_living_mob.getBruteLoss(), 1), + "health" = round(tracked_living_mob.health, 1), + ) + + if (sensor_mode >= SENSOR_COORDS) + entry["area"] = get_area_name(tracked_living_mob, format_text = TRUE) + + entry["can_track"] = tracked_living_mob.can_track() + + else + continue + + results[++results.len] = entry + + data_by_z["[z]"] = results + last_update["[z]"] = world.time + + return results + +#undef SENSORS_UPDATE_PERIOD diff --git a/modular_skyrat/modules/blueshield/code/devices/sensor_device.dm b/modular_skyrat/modules/blueshield/code/devices/sensor_device.dm new file mode 100644 index 00000000000..f9fffbc1d5b --- /dev/null +++ b/modular_skyrat/modules/blueshield/code/devices/sensor_device.dm @@ -0,0 +1,8 @@ +/obj/item/sensor_device/blueshield + name = "blueshield's handheld monitor" + desc = "A unique model of handheld crew monitor that seems to have been customized for Executive Protection purposes." + icon = 'modular_skyrat/modules/blueshield/icons/device.dmi' + icon_state = "blueshield_scanner" + +/obj/item/sensor_device/blueshield/attack_self(mob/user) + GLOB.blueshield_crewmonitor.show(user,src) diff --git a/modular_skyrat/modules/blueshield/code/medkit.dm b/modular_skyrat/modules/blueshield/code/medkit.dm index bf50bdbf8c4..3939188f699 100644 --- a/modular_skyrat/modules/blueshield/code/medkit.dm +++ b/modular_skyrat/modules/blueshield/code/medkit.dm @@ -2,6 +2,7 @@ name = "blueshield combat medical kit" desc = "Blue boy to the rescue!" color = "#AAAAFF" + /obj/item/storage/medkit/tactical/blueshield/PopulateContents() if(empty) return @@ -9,4 +10,4 @@ new /obj/item/stack/medical/bruise_pack(src) new /obj/item/stack/medical/ointment(src) new /obj/item/healthanalyzer(src) - new /obj/item/pinpointer/crew(src) + new /obj/item/sensor_device/blueshield(src) diff --git a/modular_skyrat/modules/blueshield/icons/device.dmi b/modular_skyrat/modules/blueshield/icons/device.dmi new file mode 100644 index 0000000000000000000000000000000000000000..e079de6c16092a10d4b7dae4361018e7a99b65bc GIT binary patch literal 499 zcmVjc2DN>ZZy}iZ7#a(=^va+(;+S*lYpGjPS0000&bLTNywNixV($dlZ{{Y_S z|Ns90d!_H|LUKU>0004WQchCV=-0C=2JR&a84 z_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5DJiEk zwKyX)H76y$I5{ydFSSUCi!&v&s2C_|$ip&P)S|V}f!M6`l?6yWW!lA}@yhwJ`w_ phvDPBQ+uHB^FNX~{U=^JtS87b6E_0Ati=ET002ovPDHLkV1l=X&kFzm literal 0 HcmV?d00001 diff --git a/tgstation.dme b/tgstation.dme index 4c1b5dd2387..f7d96d9b48d 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5698,6 +5698,8 @@ #include "modular_skyrat\modules\blueshield\code\landmarks.dm" #include "modular_skyrat\modules\blueshield\code\medkit.dm" #include "modular_skyrat\modules\blueshield\code\weapons.dm" +#include "modular_skyrat\modules\blueshield\code\devices\crew.dm" +#include "modular_skyrat\modules\blueshield\code\devices\sensor_device.dm" #include "modular_skyrat\modules\bluespace_miner\code\bluespace_miner.dm" #include "modular_skyrat\modules\bodyparts\code\_mutant_bodyparts.dm" #include "modular_skyrat\modules\bodyparts\code\akula_bodyparts.dm" diff --git a/tgui/packages/tgui/interfaces/CrewConsoleSkyratBlueshield.js b/tgui/packages/tgui/interfaces/CrewConsoleSkyratBlueshield.js new file mode 100644 index 00000000000..2d13e59d150 --- /dev/null +++ b/tgui/packages/tgui/interfaces/CrewConsoleSkyratBlueshield.js @@ -0,0 +1,199 @@ +import { sortBy } from 'common/collections'; +import { useBackend } from '../backend'; +import { Box, Button, Section, Table, Icon } from '../components'; +import { COLORS } from '../constants'; +import { Window } from '../layouts'; + +const HEALTH_COLOR_BY_LEVEL = [ + '#17d568', + '#c4cf2d', + '#e67e22', + '#ed5100', + '#e74c3c', + '#801308', +]; +const HEALTH_ICON_BY_LEVEL = [ + 'heart', + 'heart', + 'heart', + 'heart', + 'heartbeat', + 'skull', +]; +const jobIsHead = (jobId) => jobId % 10 === 0; + +const jobToColor = (jobId) => { + if (jobId === 0) { + return COLORS.department.captain; + } + if (jobId >= 10 && jobId < 20) { + return COLORS.department.security; + } + if (jobId >= 20 && jobId < 30) { + return COLORS.department.medbay; + } + if (jobId >= 30 && jobId < 40) { + return COLORS.department.science; + } + if (jobId >= 40 && jobId < 50) { + return COLORS.department.engineering; + } + if (jobId >= 50 && jobId < 60) { + return COLORS.department.cargo; + } + if (jobId >= 60 && jobId < 80) { + return COLORS.department.service; + } + if (jobId >= 200 && jobId < 240) { + return COLORS.department.centcom; + } + return COLORS.department.other; +}; + +const healthToAttribute = (oxy, tox, burn, brute, attributeList) => { + const healthSum = oxy + tox + burn + brute; + const level = Math.min(Math.max(Math.ceil(healthSum / 50), 0), 5); + // 200 Default Health, Sum Divided by 50, 6 Health States + return attributeList[level]; +}; + +const HealthStat = (props) => { + const { type, value } = props; + return ( + + {value} + + ); +}; + +// all of this just to change the name +export const CrewConsoleSkyratBlueshield = () => { + return ( + + +
+ +
+
+
+ ); +}; + +const CrewTable = (props, context) => { + const { act, data } = useBackend(context); + const sensors = sortBy((s) => s.ijob)(data.sensors ?? []); + return ( + + + + Name + + + Status + + + Vitals + + + Position + + + {sensors.map((sensor) => ( + + ))} +
+ ); +}; + +const CrewTableEntry = (props, context) => { + const { act, data } = useBackend(context); + const { link_allowed } = data; + const { sensor_data } = props; + const { + name, + assignment, + ijob, + is_robot, + life_status, + oxydam, + toxdam, + burndam, + brutedam, + area, + can_track, + } = sensor_data; + + return ( + + + {name} + {assignment !== undefined ? ` (${assignment})` : ''} + + + {is_robot ? : ''} + + + {oxydam !== undefined && life_status ? ( + + ) : life_status ? ( + + ) : ( + + )} + + + {oxydam !== undefined ? ( + + + {'/'} + + {'/'} + + {'/'} + + + ) : life_status ? ( + 'Alive' + ) : ( + 'Dead' + )} + + + {area !== undefined ? ( + area + ) : ( + + )} + + {!!link_allowed && ( + +