From 3033668671450505756f6e024e12b6ebdd1b49f7 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Tue, 24 Jun 2014 23:28:33 -0400 Subject: [PATCH] Adds multi-airlock docking controller Conflicts: code/game/machinery/embedded_controller/docking_program.dm --- baystation12.dme | 2 + .../airlock_docking_controller_multi.dm | 157 +++++++++++++ .../embedded_controller/docking_program.dm | 22 +- .../docking_program_multi.dm | 221 ++++++++++++++++++ .../embedded_controller_base.dm | 2 +- 5 files changed, 401 insertions(+), 3 deletions(-) create mode 100644 code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm create mode 100644 code/game/machinery/embedded_controller/docking_program_multi.dm diff --git a/baystation12.dme b/baystation12.dme index 755ac2a5d59..26734717624 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -462,8 +462,10 @@ #include "code\game\machinery\doors\windowdoor.dm" #include "code\game\machinery\embedded_controller\airlock_controllers.dm" #include "code\game\machinery\embedded_controller\airlock_docking_controller.dm" +#include "code\game\machinery\embedded_controller\airlock_docking_controller_multi.dm" #include "code\game\machinery\embedded_controller\airlock_program.dm" #include "code\game\machinery\embedded_controller\docking_program.dm" +#include "code\game\machinery\embedded_controller\docking_program_multi.dm" #include "code\game\machinery\embedded_controller\embedded_controller_base.dm" #include "code\game\machinery\embedded_controller\embedded_program_base.dm" #include "code\game\machinery\embedded_controller\simple_docking_controller.dm" diff --git a/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm b/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm new file mode 100644 index 00000000000..b5aa7f101e5 --- /dev/null +++ b/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm @@ -0,0 +1,157 @@ +//a controller for a docking port with multiple independent airlocks +//this is the master controller, that things will try to dock with. +/obj/machinery/embedded_controller/radio/docking_port_multi + name = "docking port controller" + var/child_tags_txt //for mapping + var/datum/computer/file/embedded_program/docking/multi/docking_program + +/obj/machinery/embedded_controller/radio/docking_port_multi/initialize() + ..() + docking_program = new/datum/computer/file/embedded_program/docking/multi(src) + program = docking_program + + +/obj/machinery/embedded_controller/radio/docking_port_multi/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null) + var/data[0] + + data = list( + "docking_status" = docking_program.get_docking_status(), + //child override status + ) + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data) + + if (!ui) + ui = new(user, src, ui_key, "simple_docking_console.tmpl", name, 470, 290) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/embedded_controller/radio/docking_port_multi/Topic(href, href_list) + if(..()) + return + + /* + usr.set_machine(src) + src.add_fingerprint(usr) + + var/clean = 0 + switch(href_list["command"]) //anti-HTML-hacking checks + if("force_door") + clean = 1 + if("toggle_override") + clean = 1 + + + if(clean) + program.receive_user_command(href_list["command"]) + + return 1 + */ + return + + + +//a docking port based on an airlock +/obj/machinery/embedded_controller/radio/airlock/docking_port_multi + name = "docking port controller" + var/master_tag //for mapping + var/datum/computer/file/embedded_program/airlock/multi_docking/airlock_program + tag_secure = 1 + +/obj/machinery/embedded_controller/radio/airlock/docking_port_multi/initialize() + ..() + airlock_program = new/datum/computer/file/embedded_program/airlock/multi_docking(src) + program = airlock_program + +/obj/machinery/embedded_controller/radio/airlock/docking_port_multi/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null) + var/data[0] + + data = list( + "chamber_pressure" = round(airlock_program.memory["chamber_sensor_pressure"]), + "exterior_status" = airlock_program.memory["exterior_status"], + "interior_status" = airlock_program.memory["interior_status"], + "processing" = airlock_program.memory["processing"], + "docking_status" = airlock_program.master_status, + "airlock_disabled" = (airlock_program.docking_enabled && !airlock_program.override_enabled), + "override_enabled" = airlock_program.override_enabled, + ) + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data) + + if (!ui) + ui = new(user, src, ui_key, "docking_airlock_console.tmpl", name, 470, 290) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/embedded_controller/radio/airlock/docking_port_multi/Topic(href, href_list) + if(..()) + return + + usr.set_machine(src) + src.add_fingerprint(usr) + + var/clean = 0 + switch(href_list["command"]) //anti-HTML-hacking checks + if("cycle_ext") + clean = 1 + if("cycle_int") + clean = 1 + if("force_ext") + clean = 1 + if("force_int") + clean = 1 + if("abort") + clean = 1 + if("toggle_override") + clean = 1 + + if(clean) + program.receive_user_command(href_list["command"]) + + return 1 + + + +/*** DEBUG VERBS ***/ + +/datum/computer/file/embedded_program/docking/multi/proc/print_state() + world << "id_tag: [id_tag]" + world << "dock_state: [dock_state]" + world << "control_mode: [control_mode]" + world << "tag_target: [tag_target]" + world << "response_sent: [response_sent]" + +/datum/computer/file/embedded_program/docking/multi/post_signal(datum/signal/signal, comm_line) + world << "Program [id_tag] sent a message!" + print_state() + world << "[id_tag] sent command \"[signal.data["command"]]\" to \"[signal.data["recipient"]]\"" + ..(signal) + +/obj/machinery/embedded_controller/radio/docking_port_multi/verb/view_state() + set category = "Debug" + set src in view(1) + src.program:print_state() + +/obj/machinery/embedded_controller/radio/docking_port_multi/verb/spoof_signal(var/command as text, var/sender as text) + set category = "Debug" + set src in view(1) + var/datum/signal/signal = new + signal.data["tag"] = sender + signal.data["command"] = command + signal.data["recipient"] = id_tag + + src.program:receive_signal(signal) + +/obj/machinery/embedded_controller/radio/docking_port_multi/verb/debug_init_dock(var/target as text) + set category = "Debug" + set src in view(1) + src.program:initiate_docking(target) + +/obj/machinery/embedded_controller/radio/docking_port_multi/verb/debug_init_undock() + set category = "Debug" + set src in view(1) + src.program:initiate_undocking() + +/**/ diff --git a/code/game/machinery/embedded_controller/docking_program.dm b/code/game/machinery/embedded_controller/docking_program.dm index b85a9376843..dc6a642d169 100644 --- a/code/game/machinery/embedded_controller/docking_program.dm +++ b/code/game/machinery/embedded_controller/docking_program.dm @@ -115,11 +115,13 @@ if ("confirm_dock") if (control_mode == MODE_CLIENT && dock_state == STATE_UNDOCKED && receive_tag == tag_target) dock_state = STATE_DOCKING + broadcast_docking_status() if (!override_enabled) prepare_for_docking() else if (control_mode == MODE_CLIENT && dock_state == STATE_DOCKING && receive_tag == tag_target) dock_state = STATE_DOCKED + broadcast_docking_status() if (!override_enabled) finish_docking() //client done docking! response_sent = 0 @@ -129,7 +131,10 @@ if ("request_dock") if (control_mode == MODE_NONE && dock_state == STATE_UNDOCKED) control_mode = MODE_SERVER + dock_state = STATE_DOCKING + broadcast_docking_status() + tag_target = receive_tag if (!override_enabled) prepare_for_docking() @@ -146,6 +151,8 @@ if ("request_undock") if (control_mode == MODE_SERVER && dock_state == STATE_DOCKED && receive_tag == tag_target) dock_state = STATE_UNDOCKING + broadcast_docking_status() + if (!override_enabled) prepare_for_undocking() @@ -164,7 +171,10 @@ else if (control_mode == MODE_SERVER && received_confirm) send_docking_command(tag_target, "confirm_dock") //tell the client we are done docking. + dock_state = STATE_DOCKED + broadcast_docking_status() + if (!override_enabled) finish_docking() //server done docking! response_sent = 0 @@ -212,6 +222,8 @@ return dock_state = STATE_UNDOCKING + broadcast_docking_status() + if (!override_enabled) prepare_for_undocking() @@ -249,6 +261,8 @@ /datum/computer/file/embedded_program/docking/proc/reset() dock_state = STATE_UNDOCKED + broadcast_docking_status() + control_mode = MODE_NONE tag_target = null response_sent = 0 @@ -277,6 +291,12 @@ signal.data["recipient"] = recipient post_signal(signal) +/datum/computer/file/embedded_program/docking/proc/broadcast_docking_status() + var/datum/signal/signal = new + signal.data["tag"] = id_tag + signal.data["dock_status"] = get_docking_status() + post_signal(signal) + //this is mostly for NanoUI /datum/computer/file/embedded_program/docking/proc/get_docking_status() switch (dock_state) @@ -286,8 +306,6 @@ if (STATE_DOCKED) return "docked" - - #undef STATE_UNDOCKED #undef STATE_DOCKING #undef STATE_UNDOCKING diff --git a/code/game/machinery/embedded_controller/docking_program_multi.dm b/code/game/machinery/embedded_controller/docking_program_multi.dm new file mode 100644 index 00000000000..43906f9d5ff --- /dev/null +++ b/code/game/machinery/embedded_controller/docking_program_multi.dm @@ -0,0 +1,221 @@ +/* + These programs are for docking controllers that consist of multiple independent airlocks + Each airlock has an airlock controller running the child program, and there is one docking controller running the master program +*/ + +/* + the master program +*/ +/datum/computer/file/embedded_program/docking/multi + var/list/children_tags + var/list/children_ready + var/list/children_override + +/datum/computer/file/embedded_program/docking/multi/New(var/obj/machinery/embedded_controller/M) + ..(M) + + if (istype(M,/obj/machinery/embedded_controller/radio/docking_port_multi)) //if our parent controller is the right type, then we can auto-init stuff at construction + var/obj/machinery/embedded_controller/radio/docking_port_multi/controller = M + //parse child_tags_txt and create child tags + children_tags = text2list(controller.child_tags_txt, ";") + + children_ready = list() + children_override = list() + for (var/child_tag in children_tags) + children_ready[child_tag] = 0 + children_override[child_tag] = "disabled" + +/datum/computer/file/embedded_program/docking/multi/proc/clear_children_ready_status() + for (var/child_tag in children_tags) + children_ready[child_tag] = 0 + +/datum/computer/file/embedded_program/docking/multi/receive_signal(datum/signal/signal, receive_method, receive_param) + var/receive_tag = signal.data["tag"] //for docking signals, this is the sender id + var/command = signal.data["command"] + var/recipient = signal.data["recipient"] //the intended recipient of the docking signal + + if (receive_tag in children_tags) + + //track children status + if (signal.data["override_status"]) + children_override[receive_tag] = signal.data["override_status"] + + if (recipient == id_tag) + switch (command) + if ("ready_for_docking") + children_ready[receive_tag] = 1 + if ("ready_for_undocking") + children_ready[receive_tag] = 1 + if ("status_override_enabled") + children_override[receive_tag] = 1 + if ("status_override_disabled") + children_override[receive_tag] = 0 + + ..(signal, receive_method, receive_param) + +/datum/computer/file/embedded_program/docking/multi/prepare_for_docking() + //clear children ready status + clear_children_ready_status() + + //tell children to prepare for docking + for (var/child_tag in children_tags) + send_docking_command(child_tag, "prepare_for_docking") + +/datum/computer/file/embedded_program/docking/multi/ready_for_docking() + //check children ready status + for (var/child_tag in children_tags) + if (!children_ready[child_tag]) + return 0 + return 1 + +/datum/computer/file/embedded_program/docking/multi/finish_docking() + //tell children to finish docking + for (var/child_tag in children_tags) + send_docking_command(child_tag, "finish_docking") + + //clear ready flags + clear_children_ready_status() + +/datum/computer/file/embedded_program/docking/multi/prepare_for_undocking() + //clear children ready status + clear_children_ready_status() + + //tell children to prepare for undocking + for (var/child_tag in children_tags) + send_docking_command(child_tag, "prepare_for_undocking") + +/datum/computer/file/embedded_program/docking/multi/ready_for_undocking() + //check children ready status + for (var/child_tag in children_tags) + if (!children_ready[child_tag]) + return 0 + return 1 + +/datum/computer/file/embedded_program/docking/multi/finish_undocking() + //tell children to finish undocking + for (var/child_tag in children_tags) + send_docking_command(child_tag, "finish_undocking") + + //clear ready flags + clear_children_ready_status() + + + + +/* + the child program + technically should be "slave" but eh... I'm too politically correct. +*/ +/datum/computer/file/embedded_program/airlock/multi_docking + var/master_tag + + var/master_status = "undocked" + var/override_enabled = 0 + var/docking_enabled = 0 + var/docking_mode = 0 //0 = docking, 1 = undocking + var/response_sent = 0 + +/datum/computer/file/embedded_program/airlock/multi_docking/New(var/obj/machinery/embedded_controller/M) + ..(M) + + if (istype(M, /obj/machinery/embedded_controller/radio/airlock/docking_port_multi)) //if our parent controller is the right type, then we can auto-init stuff at construction + var/obj/machinery/embedded_controller/radio/airlock/docking_port_multi/controller = M + src.master_tag = controller.master_tag + +/datum/computer/file/embedded_program/airlock/multi_docking/receive_user_command(command) + if (command == "toggle_override") + if (override_enabled) + override_enabled = 0 + broadcast_override_status() + else + override_enabled = 1 + broadcast_override_status() + return + + if (!docking_enabled|| override_enabled) //only allow the port to be used as an airlock if nothing is docked here or the override is enabled + ..(command) + +/datum/computer/file/embedded_program/airlock/multi_docking/receive_signal(datum/signal/signal, receive_method, receive_param) + ..() + + var/receive_tag = signal.data["tag"] //for docking signals, this is the sender id + var/command = signal.data["command"] + var/recipient = signal.data["recipient"] //the intended recipient of the docking signal + + if (receive_tag != master_tag) + return //only respond to master + + //track master's status + if (signal.data["dock_status"]) + master_status = signal.data["dock_status"] + + if (recipient != id_tag) + return //this signal is not for us + + switch (command) + if ("prepare_for_docking") + docking_enabled = 1 + docking_mode = 0 + response_sent = 0 + + if (!override_enabled) + begin_cycle_in() + + if ("prepare_for_undocking") + docking_mode = 1 + response_sent = 0 + + if (!override_enabled) + stop_cycling() + close_doors() + + if ("finish_docking") + if (!override_enabled) + open_doors() + + if ("finish_undocking") + docking_enabled = 0 + +/datum/computer/file/embedded_program/airlock/multi_docking/process() + ..() + + if (docking_enabled && !response_sent) + + switch (docking_mode) + if (0) //docking + if (ready_for_docking()) + send_signal_to_master("ready_for_docking") + response_sent = 1 + if (1) //undocking + if (ready_for_undocking()) + send_signal_to_master("ready_for_undocking") + response_sent = 1 + +//checks if we are ready for docking +/datum/computer/file/embedded_program/airlock/multi_docking/proc/ready_for_docking() + return done_cycling() + +//checks if we are ready for undocking +/datum/computer/file/embedded_program/airlock/multi_docking/proc/ready_for_undocking() + return check_doors_secured() + +/datum/computer/file/embedded_program/airlock/multi_docking/proc/open_doors() + toggleDoor(memory["interior_status"], tag_interior_door, memory["secure"], "open") + toggleDoor(memory["exterior_status"], tag_exterior_door, memory["secure"], "open") + +/datum/computer/file/embedded_program/airlock/multi_docking/cycleDoors(var/target) + if (!docking_enabled|| override_enabled) //only allow the port to be used as an airlock if nothing is docked here or the override is enabled + ..(target) + +/datum/computer/file/embedded_program/airlock/multi_docking/proc/send_signal_to_master(var/command) + var/datum/signal/signal = new + signal.data["tag"] = id_tag + signal.data["command"] = command + signal.data["recipient"] = master_tag + post_signal(signal) + +/datum/computer/file/embedded_program/airlock/multi_docking/proc/broadcast_override_status() + var/datum/signal/signal = new + signal.data["tag"] = id_tag + signal.data["override_status"] = override_enabled? "enabled" : "disabled" + post_signal(signal) diff --git a/code/game/machinery/embedded_controller/embedded_controller_base.dm b/code/game/machinery/embedded_controller/embedded_controller_base.dm index 0d6241211e5..a9a8b40ed58 100644 --- a/code/game/machinery/embedded_controller/embedded_controller_base.dm +++ b/code/game/machinery/embedded_controller/embedded_controller_base.dm @@ -1,5 +1,5 @@ /obj/machinery/embedded_controller - var/datum/computer/file/embedded_program/program + var/datum/computer/file/embedded_program/program //the currently executing program name = "Embedded Controller" anchored = 1