mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 21:48:39 +01:00
[MODULAR] Handheld Blueshield Monitor (#20280)
Adds the blueshield's handheld monitor
This commit is contained in:
@@ -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 |
@@ -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>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user