Adds docking controllers

Squashed 10 commits:

Adds simple docking controllers

Adds docking_controllers.dm

Moves docking handshake code into its own type
Keeps docking code separate from the code for messing with airlocks and
doors.

Improves handling of invalid states

Adds docking controller to research shuttle dock

Also adds the start of a nano-ui template.

Resetting the dock controller resets the override

Adds debug verbs

Adds support for overriding docking checks

Less confusing name for the docking program
This commit is contained in:
mwerezak
2014-06-09 23:14:53 -04:00
parent 3bc6f4c9b6
commit ad7a1c5d59
8 changed files with 1511 additions and 1167 deletions
@@ -4,109 +4,246 @@
#define STATE_UNDOCKING 2
#define STATE_DOCKED 3
#define MODE_NONE 0
#define MODE_SERVER 1
#define MODE_CLIENT 2 //The one who initiated the docking, and who can initiate the undocking. The server cannot initiate undocking. (Think server == station, client == shuttle)
/datum/computer/file/embedded_program/airlock/docking
/*
*** STATE TABLE ***
MODE_CLIENT|STATE_UNDOCKED sent a request for docking and now waiting for a reply.
MODE_CLIENT|STATE_DOCKING server told us they are OK to dock, waiting for our docking port to be ready.
MODE_CLIENT|STATE_DOCKED idle - docked as client.
MODE_CLIENT|STATE_UNDOCKING we are either waiting for our docking port to be ready or for the server to give us the OK to undock.
MODE_SERVER|STATE_UNDOCKED should never happen.
MODE_SERVER|STATE_DOCKING someone requested docking, we are waiting for our docking port to be ready.
MODE_SERVER|STATE_DOCKED idle - docked as server
MODE_SERVER|STATE_UNDOCKING client requested undocking, we are waiting for our docking port to be ready.
MODE_NONE|STATE_UNDOCKED idle - not docked.
MODE_NONE|anything else should never happen.
*/
/datum/computer/file/embedded_program/docking
var/tag_target //the tag of the docking controller that we are trying to dock with
var/airlock_override = 0 //allows use of the docking port as a normal airlock (normally this is only allowed in STATE_UNDOCKED)
var/dock_state = STATE_UNDOCKED
var/dock_master = 0 //are we the initiator of the dock?
var/control_mode = MODE_NONE
var/response_sent = 0 //so we don't spam confirmation messages
var/override_enabled = 0 //skips checks for the docking port being ready
/datum/computer/file/embedded_program/airlock/docking/receive_signal(datum/signal/signal, receive_method, receive_param)
var/receive_tag = signal.data["tag"] //for docking signals, this is the sender id
/datum/computer/file/embedded_program/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"]
var/recipient = signal.data["recipient"] //the intended recipient of the docking signal
if (recipient == id_tag)
switch (command)
if ("request_dock")
if (state == STATE_UNDOCKED)
tag_target = receive_tag
begin_dock()
if ("request_undock")
if(receive_tag == tag_target)
begin_undock()
if ("confirm_dock")
if(receive_tag == tag_target)
dock_master = 1
begin_dock()
else
send_docking_command(receive_tag, "docking_error") //send an error message
if ("confirm_undock")
if(receive_tag == tag_target)
begin_undock()
if ("docking_error")
if(receive_tag==tag_target)
//try to return to a good state
stop_cycling()
//close the doors
toggleDoor(memory["interior_status"], tag_interior_door, memory["secure"], "close")
toggleDoor(memory["exterior_status"], tag_exterior_door, memory["secure"], "close")
state = STATE_UNDOCKED
tag_target = null
dock_master = 0
if (recipient != id_tag)
return //this signal is not for us
..()
switch (command)
if ("confirm_dock")
if (control_mode == MODE_CLIENT && dock_state == STATE_UNDOCKED && receive_tag == tag_target)
dock_state = STATE_DOCKING
prepare_for_docking()
else if (control_mode == MODE_SERVER && dock_state == STATE_DOCKING && receive_tag == tag_target) //client just sent us the confirmation back, we're done with the docking process
dock_state = STATE_DOCKED
finish_docking() //server done docking!
response_sent = 0
else
send_docking_command(tag_target, "abort_dock") //not expecting confirmation for anything - tell the other guy.
if ("request_dock")
if (control_mode == MODE_NONE && dock_state == STATE_UNDOCKED)
control_mode = MODE_SERVER
dock_state = STATE_DOCKING
tag_target = receive_tag
prepare_for_docking()
if ("confirm_undock")
if (control_mode == MODE_CLIENT && dock_state == STATE_UNDOCKING && receive_tag == tag_target)
send_docking_command(tag_target, "confirm_undock")
reset() //client is done undocking!
if ("request_undock")
if (control_mode == MODE_SERVER && dock_state == STATE_DOCKED && receive_tag == tag_target)
dock_state = STATE_UNDOCKING
prepare_for_undocking()
if ("abort_dock")
if (dock_state == STATE_DOCKING && receive_tag == tag_target)
reset()
if ("abort_undock")
if (dock_state == STATE_UNDOCKING && receive_tag == tag_target)
dock_state = STATE_DOCKING //redock
prepare_for_docking()
if ("dock_error")
if (receive_tag == tag_target)
reset() //something really bad happened
if ("enable_override")
if (receive_tag == tag_target)
override_enabled = 1
/datum/computer/file/embedded_program/airlock/docking/receive_user_command(command)
if (state == STATE_UNDOCKED || airlock_override)
..(command)
if ("disable_override")
if (receive_tag == tag_target)
override_enabled = 0
/datum/computer/file/embedded_program/airlock/docking/process()
..() //process regular airlock stuff first
/datum/computer/file/embedded_program/docking/process()
switch(dock_state)
if(STATE_DOCKING)
if(done_cycling() || airlock_override)
state = STATE_DOCKED
if (STATE_DOCKING) //waiting for our docking port to be ready for docking
if (ready_for_docking() || override_enabled)
if (!response_sent)
send_docking_command(tag_target, "confirm_dock") //tell the other guy we're ready
response_sent = 1
if (!dock_master)
send_docking_command(tag_target, "confirm_dock") //send confirmation
//open doors
toggleDoor(memory["interior_status"], tag_interior_door, memory["secure"], "open")
toggleDoor(memory["exterior_status"], tag_exterior_door, memory["secure"], "open")
if(STATE_UNDOCKING)
if(check_doors_closed() || airlock_override) //check doors are closed or override
state = STATE_UNDOCKED
if (!dock_master)
send_docking_command(tag_target, "confirm_undock") //send confirmation
dock_master = 0
tag_target = null
/datum/computer/file/embedded_program/airlock/docking/cycleDoors(var/target)
if (state == STATE_UNDOCKED || airlock_override)
..(target)
//get the docking port into a good state for docking.
/datum/computer/file/embedded_program/airlock/docking/proc/begin_dock()
dock_state = STATE_DOCKING
begin_cycle_in()
//get the docking port into a good state for undocking.
/datum/computer/file/embedded_program/airlock/docking/proc/begin_undock()
dock_state = STATE_UNDOCKING
stop_cycling()
if (control_mode == MODE_CLIENT) //client doesn't need to do anything further
dock_state = STATE_DOCKED
finish_docking() //client done docking!
response_sent = 0
if (STATE_UNDOCKING)
if (ready_for_undocking() || override_enabled)
if (control_mode == MODE_CLIENT)
if (!response_sent)
send_docking_command(tag_target, "request_undock") //tell the server we want to undock now.
response_sent = 1
else if (control_mode == MODE_SERVER)
send_docking_command(tag_target, "confirm_undock") //tell the client we are OK to undock.
reset() //server is done undocking!
//close the doors
toggleDoor(memory["interior_status"], tag_interior_door, memory["secure"], "close")
toggleDoor(memory["exterior_status"], tag_exterior_door, memory["secure"], "close")
if (dock_state != STATE_DOCKING && dock_state != STATE_UNDOCKING)
response_sent = 0
//handle invalid states
if (control_mode == MODE_NONE && dock_state != STATE_UNDOCKED)
if (tag_target)
send_docking_command(tag_target, "dock_error")
reset()
if (control_mode == MODE_SERVER && dock_state == STATE_UNDOCKED)
control_mode = MODE_NONE
/datum/computer/file/embedded_program/airlock/docking/proc/send_docking_command(var/recipient, var/command)
/datum/computer/file/embedded_program/docking/proc/initiate_docking(var/target)
if (dock_state != STATE_UNDOCKED || control_mode == MODE_SERVER) //must be undocked and not serving another request to begin a new docking handshake
return
tag_target = target
control_mode = MODE_CLIENT
send_docking_command(tag_target, "request_dock")
/datum/computer/file/embedded_program/docking/proc/initiate_undocking()
if (dock_state != STATE_DOCKED || control_mode != MODE_CLIENT) //must be docked and must be client to start undocking
return
dock_state = STATE_UNDOCKING
prepare_for_undocking()
send_docking_command(tag_target, "request_undock")
//tell the docking port to start getting ready for docking - e.g. pressurize
/datum/computer/file/embedded_program/docking/proc/prepare_for_docking()
return
//are we ready for docking?
/datum/computer/file/embedded_program/docking/proc/ready_for_docking()
return 1
//we are docked, open the doors or whatever.
/datum/computer/file/embedded_program/docking/proc/finish_docking()
return
//tell the docking port to start getting ready for undocking - e.g. close those doors.
/datum/computer/file/embedded_program/docking/proc/prepare_for_undocking()
return
//are we ready for undocking?
/datum/computer/file/embedded_program/docking/proc/ready_for_undocking()
return 1
/datum/computer/file/embedded_program/docking/proc/initiate_abort()
switch(dock_state)
if (STATE_DOCKING)
send_docking_command(tag_target, "abort_dock")
reset()
if (STATE_UNDOCKING)
send_docking_command(tag_target, "abort_undock")
dock_state = STATE_DOCKING //redock
prepare_for_docking()
/datum/computer/file/embedded_program/docking/proc/enable_override()
override_enabled = 1
if (tag_target)
send_docking_command(tag_target, "enable_override")
/datum/computer/file/embedded_program/docking/proc/disable_override()
override_enabled = 0
if (tag_target)
send_docking_command(tag_target, "disable_override")
/datum/computer/file/embedded_program/docking/proc/reset()
dock_state = STATE_UNDOCKED
control_mode = MODE_NONE
tag_target = null
response_sent = 0
override_enabled = 0
//returns 1 if we are saftely undocked (and the shuttle can leave)
/datum/computer/file/embedded_program/docking/proc/undocked()
return (dock_state == STATE_UNDOCKED)
/datum/computer/file/embedded_program/docking/proc/send_docking_command(var/recipient, var/command)
var/datum/signal/signal = new
signal.data["tag"] = id_tag
signal.data["command"] = command
signal.data["recipient"] = recipient
post_signal(signal)
//for debugging
/datum/computer/file/embedded_program/docking/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/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"]]\""
/obj/machinery/embedded_controller/radio/airlock/airlock_controller/docking_port/verb/view_state()
set src in view(1)
src.program:print_state()
/obj/machinery/embedded_controller/radio/airlock/airlock_controller/docking_port/verb/spoof_signal(var/command as text, var/sender as text)
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/airlock/airlock_controller/docking_port/verb/debug_init_dock(var/target as text)
set src in view(1)
src.program:initiate_docking(target)
/obj/machinery/embedded_controller/radio/airlock/airlock_controller/docking_port/verb/debug_init_undock(var/target as text)
set src in view(1)
src.program:initiate_undocking()
#undef STATE_UNDOCKED
#undef STATE_DOCKING
#undef STATE_UNDOCKING
#undef STATE_DOCKED
#undef STATE_DOCKED
#undef MODE_NONE
#undef MODE_SERVER
#undef MODE_CLIENT