mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 20:48:56 +01:00
## About The Pull Request
Makes more machinery using MAP_SWITCHes so their fancy preview icons
could be displayed in SDMM. MAP_SWITCH takes original icon+icon_state of
machinery as first argument and icon+icon_state (basically a machinery
part because the naming system, like `MAP_SWITCH("computer",
"/obj/machinery/computer/slot_machine")` ) from
icons/obj/fluff/map_previews.dmi
Adds a tool (subsystem) for that need that generates preview icons for
stuff that has overlays. To include them in preview generating you have
to set specific variable to TRUE.
## Why It's Good For The Game
Lets us do this instead of black boring consoles:
(before)
<img width="641" height="575" alt="image"
src="https://github.com/user-attachments/assets/35fc5a19-bc24-4c02-957a-43ddef86e684"
/>
(after)
<img width="641" height="575" alt="image"
src="https://github.com/user-attachments/assets/99310823-747f-4e0a-acf8-60abcc8f2ed1"
/>
## Changelog
🆑
qol: Made machinery with overlays actually be properly displayed in SDMM
editor.
/🆑
292 lines
11 KiB
Plaintext
292 lines
11 KiB
Plaintext
#define MENU_OPERATION 1
|
|
#define MENU_SURGERIES 2
|
|
|
|
/obj/machinery/computer/operating
|
|
name = "operating computer"
|
|
desc = "Monitors patient vitals and displays surgery steps. Can be loaded with surgery disks to perform experimental procedures. Automatically syncs to operating tables within its line of sight for surgical tech advancement."
|
|
icon_state = MAP_SWITCH("computer", "/obj/machinery/computer/crew")
|
|
icon_screen = "crew"
|
|
icon_keyboard = "med_key"
|
|
circuit = /obj/item/circuitboard/computer/operating
|
|
interaction_flags_machine = parent_type::interaction_flags_machine | INTERACT_MACHINE_REQUIRES_STANDING
|
|
|
|
light_color = LIGHT_COLOR_GREEN
|
|
|
|
/// Linked operating table, if any
|
|
var/obj/structure/table/optable/table
|
|
/// List if surgery typepaths available on this computer
|
|
var/list/advanced_surgeries = list()
|
|
/// Techweb linked to this operating computer
|
|
var/datum/techweb/linked_techweb
|
|
/// Currently selected body zone for surgery
|
|
var/target_zone = BODY_ZONE_CHEST
|
|
/// Experiment handler component reference
|
|
var/datum/component/experiment_handler/experiment_handler
|
|
/// Lazyassoclist of mob weakrefs to the zone they had selected when opening the UI
|
|
/// When closing the UI we try to revert their zone selector to that zone
|
|
var/list/datum/weakref/zone_on_open
|
|
|
|
/obj/machinery/computer/operating/Initialize(mapload)
|
|
. = ..()
|
|
find_table()
|
|
return INITIALIZE_HINT_LATELOAD
|
|
|
|
/obj/machinery/computer/operating/post_machine_initialize()
|
|
. = ..()
|
|
if(!CONFIG_GET(flag/no_default_techweb_link) && !linked_techweb)
|
|
CONNECT_TO_RND_SERVER_ROUNDSTART(linked_techweb, src)
|
|
|
|
if(linked_techweb)
|
|
RegisterSignal(linked_techweb, COMSIG_TECHWEB_ADD_DESIGN, PROC_REF(on_techweb_research))
|
|
RegisterSignal(linked_techweb, COMSIG_TECHWEB_REMOVE_DESIGN, PROC_REF(on_techweb_unresearch))
|
|
RegisterSignal(linked_techweb, COMSIG_TECHWEB_EXPERIMENT_COMPLETED, PROC_REF(update_static_data_batched))
|
|
|
|
for(var/datum/design/surgery/design in linked_techweb.get_researched_design_datums())
|
|
advanced_surgeries |= design.surgery
|
|
|
|
var/list/operating_signals = list(
|
|
COMSIG_OPERATING_COMPUTER_AUTOPSY_COMPLETE = TYPE_PROC_REF(/datum/component/experiment_handler, try_run_autopsy_experiment),
|
|
)
|
|
experiment_handler = AddComponent(
|
|
/datum/component/experiment_handler, \
|
|
allowed_experiments = list(/datum/experiment/autopsy), \
|
|
config_flags = EXPERIMENT_CONFIG_ALWAYS_ACTIVE, \
|
|
config_mode = EXPERIMENT_CONFIG_ALTCLICK, \
|
|
experiment_signals = operating_signals, \
|
|
)
|
|
|
|
/obj/machinery/computer/operating/Destroy()
|
|
for(var/direction in GLOB.alldirs)
|
|
table = locate(/obj/structure/table/optable) in get_step(src, direction)
|
|
if(table && table.computer == src)
|
|
table.computer = null
|
|
QDEL_NULL(experiment_handler)
|
|
return ..()
|
|
|
|
/obj/machinery/computer/operating/multitool_act(mob/living/user, obj/item/multitool/tool)
|
|
if(!QDELETED(tool.buffer) && istype(tool.buffer, /datum/techweb))
|
|
linked_techweb = tool.buffer
|
|
return TRUE
|
|
|
|
/obj/machinery/computer/operating/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
|
|
if(istype(tool, /obj/item/disk/surgery))
|
|
user.visible_message(
|
|
span_notice("[user] begins to load [tool] in [src]..."),
|
|
span_notice("You begin to load a surgery protocol from [tool]..."),
|
|
span_hear("You hear the chatter of a floppy drive."),
|
|
)
|
|
var/obj/item/disk/surgery/disky = tool
|
|
if(!do_after(user, 1 SECONDS, src))
|
|
return ITEM_INTERACT_BLOCKING
|
|
advanced_surgeries |= disky.surgeries
|
|
update_static_data_for_all_viewers()
|
|
playsound(src, 'sound/machines/compiler/compiler-stage2.ogg', 50, FALSE, SILENCED_SOUND_EXTRARANGE)
|
|
balloon_alert(user, "surgeries loaded")
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
if((tool.item_flags & SURGICAL_TOOL) && !user.combat_mode)
|
|
ui_interact(user)
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
return NONE
|
|
|
|
/obj/machinery/computer/operating/on_set_is_operational(old_value)
|
|
update_static_data_for_all_viewers()
|
|
|
|
/obj/machinery/computer/operating/proc/find_table()
|
|
for(var/direction in GLOB.alldirs)
|
|
table = locate(/obj/structure/table/optable) in get_step(src, direction)
|
|
if(table)
|
|
table.computer = src
|
|
break
|
|
|
|
/obj/machinery/computer/operating/ui_status(mob/user, datum/ui_state/state)
|
|
. = ..()
|
|
if(isliving(user) && !issilicon(user))
|
|
. = min(., ui_check(user))
|
|
|
|
/// Checks for special ui state conditions
|
|
/obj/machinery/computer/operating/proc/ui_check(mob/living/user)
|
|
// lower states should be checked first
|
|
|
|
// normally machines revert to "disabled" when non-operational,
|
|
// but here we outright close it so people can't gleam extra info
|
|
if(!is_operational)
|
|
return UI_CLOSE
|
|
// if you're knocked out, ie anesthetic... definitely a no-go
|
|
if(user.stat >= UNCONSCIOUS || HAS_TRAIT(user, TRAIT_KNOCKEDOUT))
|
|
return UI_CLOSE
|
|
// the patient itself should be blocked from viewing the computer
|
|
if(user.body_position == LYING_DOWN)
|
|
return (user.loc == table?.loc) ? UI_CLOSE : UI_DISABLED
|
|
// we have a tight range check so people can't spy on surgeries from across the room
|
|
// likewise it'd be pretty lame if you could see what was going on while incapacitated
|
|
if(get_dist(user, src) > 2 || user.incapacitated)
|
|
return UI_DISABLED
|
|
|
|
return UI_INTERACTIVE
|
|
|
|
/obj/machinery/computer/operating/ui_interact(mob/user, datum/tgui/ui)
|
|
. = ..()
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(ui)
|
|
return
|
|
|
|
if(ishuman(user))
|
|
// if you are the first human to open the ui, it changes to your active zone
|
|
if(!LAZYLEN(zone_on_open))
|
|
target_zone = user.zone_selected
|
|
// then we record what you were looking at for when you close it
|
|
LAZYSET(zone_on_open, WEAKREF(user), user.zone_selected)
|
|
|
|
ui = new(user, src, "OperatingComputer", name)
|
|
ui.open()
|
|
|
|
/obj/machinery/computer/operating/ui_close(mob/user)
|
|
. = ..()
|
|
// reverts zone to whatever you had going into it, typically chest, so you don't have to mess around with it
|
|
var/zone_found = LAZYACCESS(zone_on_open, WEAKREF(user))
|
|
if(!zone_found)
|
|
return
|
|
|
|
var/atom/movable/screen/zone_sel/selector = user.hud_used?.screen_objects[HUD_MOB_ZONE_SELECTOR]
|
|
selector?.set_selected_zone(zone_found, user, FALSE)
|
|
LAZYREMOVE(zone_on_open, WEAKREF(user))
|
|
if(!LAZYLEN(zone_on_open))
|
|
zone_on_open = initial(zone_on_open)
|
|
|
|
/obj/machinery/computer/operating/ui_assets(mob/user)
|
|
. = ..()
|
|
. += get_asset_datum(/datum/asset/simple/body_zones)
|
|
|
|
/obj/machinery/computer/operating/ui_data(mob/user)
|
|
var/list/data = list()
|
|
|
|
data["has_table"] = !!table
|
|
data["target_zone"] = target_zone
|
|
if(isnull(table?.patient))
|
|
return data
|
|
|
|
data["patient"] = list()
|
|
var/mob/living/patient = table.patient
|
|
|
|
switch(patient.stat)
|
|
if(CONSCIOUS)
|
|
data["patient"]["stat"] = "Conscious"
|
|
data["patient"]["statstate"] = "good"
|
|
if(SOFT_CRIT)
|
|
data["patient"]["stat"] = "Critical Condition"
|
|
data["patient"]["statstate"] = "average"
|
|
if(UNCONSCIOUS, HARD_CRIT)
|
|
data["patient"]["stat"] = "Unconscious"
|
|
data["patient"]["statstate"] = "average"
|
|
if(DEAD)
|
|
data["patient"]["stat"] = "Dead"
|
|
data["patient"]["statstate"] = "bad"
|
|
data["patient"]["health"] = patient.health
|
|
data["patient"]["blood_type"] = patient.get_bloodtype()?.name || "UNKNOWN"
|
|
data["patient"]["maxHealth"] = patient.maxHealth
|
|
data["patient"]["minHealth"] = HEALTH_THRESHOLD_DEAD
|
|
data["patient"]["bruteLoss"] = patient.get_brute_loss()
|
|
data["patient"]["fireLoss"] = patient.get_fire_loss()
|
|
data["patient"]["toxLoss"] = patient.get_tox_loss()
|
|
data["patient"]["oxyLoss"] = patient.get_oxy_loss()
|
|
data["patient"]["blood_level"] = patient.blood_volume
|
|
data["patient"]["standard_blood_level"] = BLOOD_VOLUME_NORMAL
|
|
data["patient"]["surgery_state"] = patient.get_surgery_state_as_list(deprecise_zone(target_zone))
|
|
return data
|
|
|
|
/obj/machinery/computer/operating/ui_static_data(mob/user)
|
|
var/list/data = list()
|
|
|
|
data["experiments"] = list()
|
|
data["techwebs"] = list()
|
|
data["surgeries"] = list()
|
|
if(!is_operational)
|
|
return data
|
|
|
|
if(linked_techweb)
|
|
data["techwebs"] += list(list(
|
|
"web_id" = linked_techweb.id,
|
|
"web_org" = linked_techweb.organization,
|
|
"selected" = TRUE,
|
|
"ref" = REF(linked_techweb),
|
|
"all_servers" = linked_techweb.techweb_servers,
|
|
))
|
|
|
|
for(var/datum/experiment/experiment as anything in linked_techweb.available_experiments)
|
|
if(istype(experiment, /datum/experiment/autopsy))
|
|
data["experiments"] += list(experiment.to_ui_data())
|
|
|
|
var/list/operations = GLOB.operations.get_instances_from(GLOB.operations.unlocked | advanced_surgeries)
|
|
var/any_recommended = FALSE
|
|
for(var/datum/surgery_operation/operation as anything in operations)
|
|
var/recommend = FALSE
|
|
if(table?.patient && operation.show_as_next_step(table.patient, target_zone))
|
|
recommend = TRUE
|
|
any_recommended = TRUE
|
|
|
|
data["surgeries"] += list(list(
|
|
"name" = operation.rnd_name || operation.name,
|
|
"desc" = operation.rnd_desc || operation.desc,
|
|
"tool_rec" = operation.get_recommended_tool() || "error",
|
|
"requirements" = operation.get_requirements(),
|
|
"show_as_next" = recommend,
|
|
"show_in_list" = TRUE,
|
|
"priority" = operation.operation_flags & OPERATION_PRIORITY_NEXT_STEP,
|
|
"mechanic" = operation.operation_flags & OPERATION_MECHANIC,
|
|
))
|
|
|
|
if(!any_recommended && table?.patient && !HAS_TRAIT(table.patient, TRAIT_READY_TO_OPERATE))
|
|
data["surgeries"] += list(list(
|
|
"name" = "Prepare for surgery",
|
|
"desc" = "Begin surgery by applying surgical drapes to the patient or by buckling the patient to the surgical table.",
|
|
"tool_rec" = /obj/item/surgical_drapes::name,
|
|
"show_as_next" = TRUE,
|
|
"show_in_list" = FALSE,
|
|
))
|
|
|
|
return data
|
|
|
|
/obj/machinery/computer/operating/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
switch(action)
|
|
if("open_experiments")
|
|
experiment_handler.ui_interact(usr)
|
|
if("change_zone")
|
|
if(params["new_zone"] in (GLOB.all_body_zones + GLOB.all_precise_body_zones))
|
|
target_zone = params["new_zone"]
|
|
var/atom/movable/screen/zone_sel/selector = ui.user.hud_used?.screen_objects[HUD_MOB_ZONE_SELECTOR]
|
|
selector?.set_selected_zone(params["new_zone"], ui.user, FALSE)
|
|
update_static_data_for_all_viewers()
|
|
return TRUE
|
|
|
|
/obj/machinery/computer/operating/proc/on_techweb_research(datum/source, datum/design/surgery/design)
|
|
SIGNAL_HANDLER
|
|
|
|
if(!istype(design))
|
|
return
|
|
|
|
advanced_surgeries |= design.surgery
|
|
update_static_data_batched()
|
|
|
|
/obj/machinery/computer/operating/proc/on_techweb_unresearch(datum/source, datum/design/surgery/design)
|
|
SIGNAL_HANDLER
|
|
|
|
if(!istype(design))
|
|
return
|
|
|
|
advanced_surgeries -= design.surgery
|
|
update_static_data_batched()
|
|
|
|
/// Updates static data for all viewers after a miniscule delay (to batch multiple updates together)
|
|
/obj/machinery/computer/operating/proc/update_static_data_batched(...)
|
|
SIGNAL_HANDLER
|
|
|
|
addtimer(CALLBACK(src, TYPE_PROC_REF(/datum, update_static_data_for_all_viewers)), 0.1 SECONDS, TIMER_UNIQUE)
|
|
|
|
#undef MENU_OPERATION
|
|
#undef MENU_SURGERIES
|