[MODULAR] Handheld Blueshield Monitor (#20280)

Adds the blueshield's handheld monitor
This commit is contained in:
Gyran
2023-04-03 02:04:04 +01:00
committed by GitHub
parent e9f130f818
commit 3faaf783c5
6 changed files with 344 additions and 1 deletions
@@ -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
@@ -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)
@@ -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)
Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

+2
View File
@@ -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"
@@ -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 (
<Box inline width={2} color={COLORS.damageType[type]} textAlign="center">
{value}
</Box>
);
};
// all of this just to change the name
export const CrewConsoleSkyratBlueshield = () => {
return (
<Window title="Blueshield Monitor" width={600} height={300}>
<Window.Content scrollable>
<Section minHeight="540px">
<CrewTable />
</Section>
</Window.Content>
</Window>
);
};
const CrewTable = (props, context) => {
const { act, data } = useBackend(context);
const sensors = sortBy((s) => s.ijob)(data.sensors ?? []);
return (
<Table cellpadding="3">
<Table.Row>
<Table.Cell bold colspan="2">
Name
</Table.Cell>
<Table.Cell bold collapsing textAlign="center">
Status
</Table.Cell>
<Table.Cell bold collapsing textAlign="center">
Vitals
</Table.Cell>
<Table.Cell bold width="180px" collapsing textAlign="center">
Position
</Table.Cell>
</Table.Row>
{sensors.map((sensor) => (
<CrewTableEntry sensor_data={sensor} key={sensor.ref} />
))}
</Table>
);
};
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 (
<Table.Row>
<Table.Cell bold={jobIsHead(ijob)} color={jobToColor(ijob)}>
{name}
{assignment !== undefined ? ` (${assignment})` : ''}
</Table.Cell>
<Table.Cell collapsing textAlign="center">
{is_robot ? <Icon name="wrench" color="#B7410E" size={1} /> : ''}
</Table.Cell>
<Table.Cell collapsing textAlign="center">
{oxydam !== undefined && life_status ? (
<Icon
name={healthToAttribute(
oxydam,
toxdam,
burndam,
brutedam,
HEALTH_ICON_BY_LEVEL
)}
color={healthToAttribute(
oxydam,
toxdam,
burndam,
brutedam,
HEALTH_COLOR_BY_LEVEL
)}
size={1}
/>
) : life_status ? (
<Icon name="heart" color="#17d568" size={1} />
) : (
<Icon name="skull" color="#801308" size={1} />
)}
</Table.Cell>
<Table.Cell collapsing textAlign="center">
{oxydam !== undefined ? (
<Box inline>
<HealthStat type="oxy" value={oxydam} />
{'/'}
<HealthStat type="toxin" value={toxdam} />
{'/'}
<HealthStat type="burn" value={burndam} />
{'/'}
<HealthStat type="brute" value={brutedam} />
</Box>
) : life_status ? (
'Alive'
) : (
'Dead'
)}
</Table.Cell>
<Table.Cell>
{area !== undefined ? (
area
) : (
<Icon name="question" color="#ffffff" size={1} />
)}
</Table.Cell>
{!!link_allowed && (
<Table.Cell collapsing>
<Button
content="Track"
disabled={!can_track}
onClick={() =>
act('select_person', {
name: name,
})
}
/>
</Table.Cell>
)}
</Table.Row>
);
};