Files
nevimer 6e9f2ccfc0 Merge remote-tracking branch 'tgstation/master' into upstream-12-15
# Conflicts:
#	.github/workflows/compile_all_maps.yml
#	.github/workflows/run_integration_tests.yml
#	_maps/map_files/CatwalkStation/CatwalkStation_2023.dmm
#	code/_onclick/hud/credits.dm
#	code/controllers/subsystem/networks/id_access.dm
#	code/datums/diseases/advance/advance.dm
#	code/datums/diseases/advance/symptoms/heal.dm
#	code/game/machinery/doors/door.dm
#	code/game/objects/structures/crates_lockers/closets/secure/medical.dm
#	code/game/objects/structures/crates_lockers/closets/secure/security.dm
#	code/modules/antagonists/malf_ai/malf_ai_modules.dm
#	code/modules/jobs/job_types/_job.dm
#	code/modules/loadout/categories/accessories.dm
#	code/modules/loadout/loadout_helpers.dm
#	code/modules/loadout/loadout_items.dm
#	code/modules/loadout/loadout_preference.dm
#	code/modules/mob/living/silicon/robot/robot_defense.dm
#	code/modules/mod/mod_theme.dm
#	code/modules/projectiles/ammunition/energy/laser.dm
#	code/modules/reagents/reagent_containers/cups/drinks.dm
#	code/modules/shuttle/mobile_port/variants/supply.dm
#	code/modules/surgery/organs/internal/eyes/_eyes.dm
#	code/modules/unit_tests/screenshots/screenshot_antag_icons_heretic.png
#	icons/hud/screen_full.dmi
2025-12-15 18:12:29 -05:00

346 lines
12 KiB
Plaintext

/// How often the sensor data is updated // BUBBER EDIT REMOVAL - Defined in code/__DEFINES/~~bubber_defines/misc.dm
// #define SENSORS_UPDATE_PERIOD (10 SECONDS) //How often the sensor data updates.
/// The job sorting ID associated with otherwise unknown jobs
#define UNKNOWN_JOB_ID 998
/obj/machinery/computer/crew
name = "crew monitoring console"
desc = "Used to monitor active health sensors built into most of the crew's uniforms."
icon_screen = "crew"
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/crew
light_color = LIGHT_COLOR_BLUE
/obj/machinery/computer/crew/Initialize(mapload, obj/item/circuitboard/C)
. = ..()
AddComponent(/datum/component/usb_port, typecacheof(list(/obj/item/circuit_component/medical_console_data), only_root_path = TRUE))
/obj/item/circuit_component/medical_console_data
display_name = "Crew Monitoring Data"
desc = "Outputs the medical statuses of people on the crew monitoring computer, where it can then be filtered with a Select Query component."
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL
/// The records retrieved
var/datum/port/output/records
var/obj/machinery/computer/crew/attached_console
/obj/item/circuit_component/medical_console_data/populate_ports()
records = add_output_port("Crew Monitoring Data", PORT_TYPE_TABLE)
/obj/item/circuit_component/medical_console_data/register_usb_parent(atom/movable/shell)
. = ..()
if(istype(shell, /obj/machinery/computer/crew))
attached_console = shell
/obj/item/circuit_component/medical_console_data/unregister_usb_parent(atom/movable/shell)
attached_console = null
return ..()
/obj/item/circuit_component/medical_console_data/get_ui_notices()
. = ..()
. += create_table_notices(list(
"name",
"job",
"is_robot", //SKYRAT EDIT ADDITION - Displaying robotic species Icon
"is_dnr", //BUBBERSTATION EDIT ADDITION - Displays DNR status
"life_status",
"suffocation",
"toxin",
"burn",
"brute",
"location",
"health",
))
/obj/item/circuit_component/medical_console_data/input_received(datum/port/input/port)
if(!attached_console || !GLOB.crewmonitor)
return
var/list/new_table = list()
for(var/list/player_record as anything in GLOB.crewmonitor.update_data(attached_console.z))
var/list/entry = list()
entry["name"] = player_record["name"]
entry["job"] = player_record["assignment"]
entry["is_robot"] = player_record["is_robot"] //SKYRAT EDIT ADDITION - Displaying robotic species Icon
entry["life_status"] = player_record["life_status"]
entry["suffocation"] = player_record["oxydam"]
entry["toxin"] = player_record["toxdam"]
entry["burn"] = player_record["burndam"]
entry["brute"] = player_record["brutedam"]
entry["location"] = player_record["area"]
entry["health"] = player_record["health"]
new_table += list(entry)
records.set_output(new_table)
/obj/machinery/computer/crew/syndie
icon_keyboard = "syndie_key"
/obj/machinery/computer/crew/ui_interact(mob/user)
. = ..()
GLOB.crewmonitor.show(user,src)
GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new)
/datum/crewmonitor
/// List of user -> UI source
var/list/ui_sources = list()
/// Cache of data generated by z-level, used for serving the data within SENSOR_UPDATE_PERIOD of the last update
var/list/data_by_z = list()
/// Cache of last update time for each z-level
var/list/last_update = list()
/// Map of job to ID for sorting purposes
var/list/jobs = list(
// Note that jobs divisible by 10 are considered heads of staff, and bolded
// 00: Captain
JOB_CAPTAIN = 0,
JOB_HUMAN_AI = 1,
// 10-19: Security
JOB_HEAD_OF_SECURITY = 10,
JOB_WARDEN = 11,
JOB_SECURITY_OFFICER = 12,
/* SKYRAT EDIT REMOVAL - We need those slots for our own jobs, these jobs aren't on Skyrat anymore anyway.
JOB_SECURITY_OFFICER_MEDICAL = 13,
JOB_SECURITY_OFFICER_ENGINEERING = 14,
JOB_SECURITY_OFFICER_SCIENCE = 15,
JOB_SECURITY_OFFICER_SUPPLY = 16,
*/
JOB_SECURITY_MEDIC = 13, // BUBBER EDIT ADDITION
JOB_CORRECTIONS_OFFICER = 14, // SKYRAT EDIT ADDITION
JOB_DETECTIVE = 15,
// 20-29: Medbay
JOB_CHIEF_MEDICAL_OFFICER = 20,
JOB_CHEMIST = 21,
JOB_MEDICAL_DOCTOR = 22,
JOB_PARAMEDIC = 23,
JOB_CORONER = 24,
JOB_ORDERLY = 25, // SKYRAT EDIT ADDITION
JOB_PSYCHOLOGIST = 26, // SKYRAT EDIT - ORIGINAL: JOB_PSYCHOLOGIST = 71,
// 30-39: Science
JOB_RESEARCH_DIRECTOR = 30,
JOB_SCIENTIST = 31,
JOB_ROBOTICIST = 32,
JOB_GENETICIST = 33,
JOB_SCIENCE_GUARD = 34, // SKYRAT EDIT ADDITION
// 40-49: Engineering
JOB_CHIEF_ENGINEER = 40,
JOB_STATION_ENGINEER = 41,
JOB_ATMOSPHERIC_TECHNICIAN = 42,
JOB_ENGINEERING_GUARD = 43, // SKYRAT EDIT ADDITION
JOB_TELECOMMS_SPECIALIST = 44, // SKYRAT EDIT ADDITION
// 50-59: Cargo
JOB_QUARTERMASTER = 50,
JOB_SHAFT_MINER = 51,
JOB_CARGO_TECHNICIAN = 52,
JOB_BITRUNNER = 53,
JOB_CUSTOMS_AGENT = 54, // SKYRAT EDIT ADDITION
JOB_BLACKSMITH = 55, // Bubber edit Addition!
// 60+: Service
JOB_HEAD_OF_PERSONNEL = 60,
JOB_BARTENDER = 61,
JOB_CHEF = 62,
JOB_COOK = 63,
JOB_BOTANIST = 64,
JOB_CURATOR = 65,
JOB_CHAPLAIN = 66,
JOB_CLOWN = 67,
JOB_MIME = 68,
JOB_JANITOR = 69,
JOB_LAWYER = 71,
JOB_BARBER = 74, // SKYRAT EDIT ADDITION
JOB_BOUNCER = 73, // SKYRAT EDIT ADDITION
JOB_PSYCHOLOGIST = 72,
// 200-229: Centcom
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, // SKYRAT EDIT ADDITION
JOB_BLUESHIELD = 231, // SKYRAT EDIT ADDITION
// ANYTHING ELSE = UNKNOWN_JOB_ID, Unknowns/custom jobs will appear after civilians, and before assistants
JOB_ASSISTANT = 999,
)
/datum/crewmonitor/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if (!ui)
ui = new(user, src, "CrewConsoleBubbers") // BUBBER EDIT CHANGE - Crew Console
ui.open()
/datum/crewmonitor/proc/show(mob/M, source)
ui_sources[WEAKREF(M)] = WEAKREF(source)
ui_interact(M)
/datum/crewmonitor/ui_host(mob/user)
var/datum/weakref/host_ref = ui_sources[WEAKREF(user)]
return host_ref?.resolve()
/datum/crewmonitor/ui_data(mob/user)
var/z = user.z
if(!z)
var/turf/T = get_turf(user)
z = T.z
. = list(
"sensors" = update_data(z),
"link_allowed" = HAS_AI_ACCESS(user),
)
/datum/crewmonitor/proc/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 | GLOB.nanite_sensors_list) // BUBBER CHANGE - NANITES
if(!tracked_mob)
stack_trace("Null entry in suit sensors or nanite sensors list.") // BUBBER CHANGE - NANITES
continue
var/mob/living/tracked_living_mob = tracked_mob
// Check if z-level is correct
var/turf/pos = get_turf(tracked_living_mob)
// Is our target in nullspace for some reason?
if(!pos)
stack_trace("Tracked mob has no loc and is likely in nullspace: [tracked_living_mob] ([tracked_living_mob.type])")
continue
// Machinery and the target should be on the same level or different levels of the same station
if(pos.z != z && (!is_station_level(pos.z) || !is_station_level(z)) && !HAS_TRAIT(tracked_living_mob, TRAIT_MULTIZ_SUIT_SENSORS))
continue
var/sensor_mode // BUBBER ADDITION - NANITES
var/has_monitoring_nanites = FALSE // BUBBER ADDITION - NANITES
var/mob/living/carbon/human/tracked_human = tracked_living_mob
// Set sensor level based on whether we're in the nanites list or the suit sensor list.
if(tracked_living_mob in GLOB.nanite_sensors_list) // BUBBER CHANGE - NANITES
sensor_mode = SENSOR_COORDS
has_monitoring_nanites = TRUE
if(!ishuman(tracked_human))
stack_trace("Non-human mob is in suit_sensors_list: [tracked_living_mob] ([tracked_living_mob.type])")
continue
// BUBBER CHANGE START - NANITES
// Check they have a uniform
var/obj/item/clothing/under/uniform = tracked_human.w_uniform
if(!has_monitoring_nanites)
// they don't have nanites, lets check uniform
if(!istype(uniform))
// no uniform, somethings fucked
stack_trace("Human without a uniform or nanites is in suit_sensors_list: [tracked_human] ([tracked_human.type])")
continue
else
// they have a uniform, lets check sensor status
if(uniform.has_sensor == NO_SENSORS)
// no sensors in the uniform, somethings fucked
stack_trace("Human without a suit sensors compatible uniform or nanites is in suit_sensors_list: [tracked_human] ([tracked_human.type]) ([uniform.type])")
continue
if(!uniform.sensor_mode)
// sensors are disabled, somethings fucked
stack_trace("Human without active suit sensors or nanites is in suit_sensors_list: [tracked_human] ([tracked_human.type]) ([uniform.type])")
continue
sensor_mode = uniform.sensor_mode
// BUBBER CHANGE END - NANITES
// The entry for this human
var/list/entry = list(
"ref" = REF(tracked_living_mob),
"name" = "Unknown",
"ijob" = UNKNOWN_JOB_ID,
)
// ID and id-related data
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()
if (jobs[trim_assignment] != null)
entry["ijob"] = jobs[trim_assignment]
// BUBBER EDIT BEGIN: Checking for robotic race/Proteans
if (issynthetic(tracked_human) || isprotean(tracked_human))
entry["is_robot"] = TRUE
// BUBBER EDIT END
// Broken sensors show garbage data
if (uniform?.has_sensor == BROKEN_SENSORS) // BUBBER EDIT CHANGE - NANITES - Original: if (uniform.has_sensor == BROKEN_SENSORS)
entry["life_status"] = 1 // BUBBER EDIT CHANGE - Original: rand(0,1) - Mob stays in consistent list position when sensors are broken
entry["area"] = pick_list (ION_FILE, "ionarea")
entry["oxydam"] = rand(0,175)
entry["toxdam"] = rand(0,175)
entry["burndam"] = rand(0,175)
entry["brutedam"] = rand(0,175)
entry["health"] = -50
results[++results.len] = entry
continue
// BUBBERSTATION EDIT BEGIN: Add DNR status, proteans death state.
// If sensors are above living tracking, set DNR state
if (sensor_mode >= SENSOR_LIVING)
entry["is_dnr"] = tracked_human.get_dnr()
// Current status
var/obj/item/organ/brain/protean/protean_brain = tracked_human.get_organ_slot(ORGAN_SLOT_BRAIN)
if(istype(protean_brain))
if(!isprotean(tracked_human))
stack_trace("[tracked_human] brain-species mismatch! Species is [tracked_human.dna.species] but brain is Protean")
entry["life_status"] = protean_brain?.dead ? DEAD : tracked_living_mob.stat // If brain not dead/no brain then handling as usual
else
entry["life_status"] = tracked_living_mob.stat
// BUBBERSTATION EDIT END
// Damage
if (sensor_mode >= SENSOR_VITALS)
entry += list(
"oxydam" = round(tracked_living_mob.get_oxy_loss(), 1),
"toxdam" = round(tracked_living_mob.get_tox_loss(), 1),
"burndam" = round(tracked_living_mob.get_fire_loss(), 1),
"brutedam" = round(tracked_living_mob.get_brute_loss(), 1),
"health" = round(tracked_living_mob.health, 1),
)
// Location
if (sensor_mode >= SENSOR_COORDS)
entry["area"] = get_area_name(tracked_living_mob, format_text = TRUE)
results[++results.len] = entry
// Cache result
data_by_z["[z]"] = results
last_update["[z]"] = world.time
return results
/datum/crewmonitor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
switch (action)
if ("select_person")
var/mob/living/silicon/ai/AI = usr
if(!istype(AI))
return
AI.ai_tracking_tool.track_name(AI, params["name"])
// #undef SENSORS_UPDATE_PERIOD // BUBBER EDIT REMOVAL - Defined in code/__DEFINES/~~bubber_defines/misc.dm
#undef UNKNOWN_JOB_ID