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-05 03:04:35 -04:00
parent 3bc6f4c9b6
commit ad7a1c5d59
8 changed files with 1511 additions and 1167 deletions

View File

@@ -387,8 +387,11 @@
#include "code\game\machinery\doors\unpowered.dm"
#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_program.dm"
#include "code\game\machinery\embedded_controller\docking_program.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\kitchen\gibber.dm"
#include "code\game\machinery\kitchen\juicer.dm"
#include "code\game\machinery\kitchen\microwave.dm"

View File

@@ -12,23 +12,21 @@
/obj/machinery/embedded_controller/radio/airlock/initialize()
..()
var/datum/computer/file/embedded_program/airlock/new_prog = new
var/datum/computer/file/embedded_program/airlock/new_program = new/datum/computer/file/embedded_program/airlock(src)
new_prog.id_tag = id_tag
new_prog.tag_exterior_door = tag_exterior_door
new_prog.tag_interior_door = tag_interior_door
new_prog.tag_airpump = tag_airpump
new_prog.tag_chamber_sensor = tag_chamber_sensor
new_prog.tag_exterior_sensor = tag_exterior_sensor
new_prog.tag_interior_sensor = tag_interior_sensor
new_prog.memory["secure"] = tag_secure
new_program.tag_exterior_door = tag_exterior_door
new_program.tag_interior_door = tag_interior_door
new_program.tag_airpump = tag_airpump
new_program.tag_chamber_sensor = tag_chamber_sensor
new_program.tag_exterior_sensor = tag_exterior_sensor
new_program.tag_interior_sensor = tag_interior_sensor
new_program.memory["secure"] = tag_secure
new_prog.master = src
program = new_prog
program = new_program
spawn(10)
program.signalDoor(tag_exterior_door, "update") //signals connected doors to update their status
program.signalDoor(tag_interior_door, "update")
new_program.signalDoor(tag_exterior_door, "update") //signals connected doors to update their status
new_program.signalDoor(tag_interior_door, "update")
//Advanced airlock controller for when you want a more versatile airlock controller - useful for turning simple access control rooms into airlocks

View File

@@ -0,0 +1,137 @@
//a docking port based on an airlock
/obj/machinery/embedded_controller/radio/airlock/airlock_controller/docking_port
name = "docking port controller"
var/datum/computer/file/embedded_program/airlock/docking/airlock_prog
var/datum/computer/file/embedded_program/docking/airlock/docking_prog
/obj/machinery/embedded_controller/radio/airlock/airlock_controller/docking_port/initialize()
airlock_prog = new/datum/computer/file/embedded_program/airlock/docking(src)
airlock_prog.tag_exterior_door = tag_exterior_door
airlock_prog.tag_interior_door = tag_interior_door
airlock_prog.tag_airpump = tag_airpump
airlock_prog.tag_chamber_sensor = tag_chamber_sensor
airlock_prog.tag_exterior_sensor = tag_exterior_sensor
airlock_prog.tag_interior_sensor = tag_interior_sensor
airlock_prog.memory["secure"] = 1
docking_prog = new/datum/computer/file/embedded_program/docking/airlock/(src, airlock_prog)
program = docking_prog
spawn(10)
airlock_prog.signalDoor(tag_exterior_door, "update") //signals connected doors to update their status
airlock_prog.signalDoor(tag_interior_door, "update")
/obj/machinery/embedded_controller/radio/airlock/airlock_controller/docking_port/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
var/data[0]
data = list(
"chamber_pressure" = round(airlock_prog.memory["chamber_sensor_pressure"]),
"exterior_status" = airlock_prog.memory["exterior_status"],
"interior_status" = airlock_prog.memory["interior_status"],
"processing" = airlock_prog.memory["processing"],
)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
if (!ui)
ui = new(user, src, ui_key, "simple_airlock_console.tmpl", name, 470, 290)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/obj/machinery/embedded_controller/radio/airlock/airlock_controller/docking_port/Topic(href, href_list)
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(clean)
program.receive_user_command(href_list["command"])
return 1
//A docking controller for an airlock based docking port
/datum/computer/file/embedded_program/docking/airlock
var/datum/computer/file/embedded_program/airlock/docking/airlock_prog
/datum/computer/file/embedded_program/docking/airlock/New(var/obj/machinery/embedded_controller/M, var/datum/computer/file/embedded_program/airlock/docking/A)
..(M)
airlock_prog = A
airlock_prog.master_prog = src
/datum/computer/file/embedded_program/docking/airlock/receive_user_command(command)
..(command)
airlock_prog.receive_user_command(command) //pass along to subprograms
/datum/computer/file/embedded_program/docking/airlock/process()
airlock_prog.process()
..()
/datum/computer/file/embedded_program/docking/airlock/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 (recipient == id_tag && command == "enable_override" && receive_tag == tag_target)
..(signal, receive_method, receive_param)
airlock_prog.receive_signal(signal, receive_method, receive_param) //pass along to subprograms
//tell the docking port to start getting ready for docking - e.g. pressurize
/datum/computer/file/embedded_program/docking/airlock/prepare_for_docking()
airlock_prog.begin_cycle_in()
//are we ready for docking?
/datum/computer/file/embedded_program/docking/airlock/ready_for_docking()
return airlock_prog.done_cycling()
//we are docked, open the doors or whatever.
/datum/computer/file/embedded_program/docking/airlock/finish_docking()
airlock_prog.open_doors()
//tell the docking port to start getting ready for undocking - e.g. close those doors.
/datum/computer/file/embedded_program/docking/airlock/prepare_for_undocking()
airlock_prog.stop_cycling()
airlock_prog.close_doors()
//are we ready for undocking?
/datum/computer/file/embedded_program/docking/airlock/ready_for_undocking()
return airlock_prog.check_doors_secured()
/datum/computer/file/embedded_program/docking/airlock/reset()
airlock_prog.stop_cycling()
airlock_prog.close_doors()
..()
//An airlock controller to be used by the airlock-based docking port controller.
//Same as a regular airlock controller but allows disabling of the regular airlock functions when docking
/datum/computer/file/embedded_program/airlock/docking
var/datum/computer/file/embedded_program/docking/airlock/master_prog
/datum/computer/file/embedded_program/airlock/docking/receive_user_command(command)
if (master_prog.undocked() || master_prog.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/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/docking/cycleDoors(var/target)
if (master_prog.undocked() || master_prog.override_enabled) //only allow the port to be used as an airlock if nothing is docked here or the override is enabled
..(target)

View File

@@ -8,19 +8,6 @@
#define TARGET_INOPEN -1
#define TARGET_OUTOPEN -2
/datum/computer/file/embedded_program
var/list/memory = list()
var/obj/machinery/embedded_controller/master
var/id_tag
/datum/computer/file/embedded_program/proc/receive_user_command(command)
return
/datum/computer/file/embedded_program/proc/receive_signal(datum/signal/signal, receive_method, receive_param)
return
/datum/computer/file/embedded_program/airlock
var/tag_exterior_door
@@ -74,7 +61,7 @@
memory["pump_status"] = "off"
else if(receive_tag==id_tag)
if(istype(master, /obj/machinery/embedded_controller/radio/access_controller))
if(istype(master, /obj/machinery/embedded_controller/radio/airlock/access_controller))
switch(signal.data["command"])
if("cycle_exterior")
receive_user_command("cycle_ext_door")
@@ -148,7 +135,7 @@
signalPump(tag_airpump, 0) //send a signal to stop pressurizing
/datum/computer/file/embedded_program/airlock/proc/process()
/datum/computer/file/embedded_program/airlock/process()
if(!state)
if(target_state)
switch(target_state)
@@ -158,8 +145,7 @@
memory["target_pressure"] = memory["external_sensor_pressure"]
//lock down the airlock before activating pumps
toggleDoor(memory["exterior_status"], tag_exterior_door, 1, "close")
toggleDoor(memory["interior_status"], tag_interior_door, 1, "close")
close_doors()
var/chamber_pressure = memory["chamber_sensor_pressure"]
var/target_pressure = memory["target_pressure"]
@@ -184,7 +170,7 @@
signalPump(tag_airpump, 0)
//the airlock will not allow itself to continue to cycle when any of the doors are forced open.
if (state && !check_doors_closed())
if (state && !check_doors_secured())
stop_cycling()
switch(state)
@@ -221,7 +207,7 @@
return 1
//these are here so that subtypes don't have to make so many assuptions about our implementation
//these are here so that other types don't have to make so many assuptions about our implementation
/datum/computer/file/embedded_program/airlock/proc/begin_cycle_in()
state = STATE_WAIT
@@ -231,6 +217,10 @@
state = STATE_WAIT
target_state = TARGET_OUTOPEN
/datum/computer/file/embedded_program/airlock/proc/close_doors()
toggleDoor(memory["interior_status"], tag_interior_door, 1, "close")
toggleDoor(memory["exterior_status"], tag_exterior_door, 1, "close")
/datum/computer/file/embedded_program/airlock/proc/stop_cycling()
state = STATE_WAIT
target_state = TARGET_NONE
@@ -238,14 +228,11 @@
/datum/computer/file/embedded_program/airlock/proc/done_cycling()
return (state == STATE_WAIT && target_state == TARGET_NONE)
/datum/computer/file/embedded_program/airlock/proc/post_signal(datum/signal/signal, comm_line)
if(master)
master.post_signal(signal, comm_line)
else
del(signal)
/datum/computer/file/embedded_program/airlock/proc/check_doors_closed()
return (memory["interior_status"]["state"] == "closed" && memory["exterior_status"["state"] == "closed")
//are the doors closed and locked?
/datum/computer/file/embedded_program/airlock/proc/check_doors_secured()
var/ext_closed = (memory["exterior_status"]["state"] == "closed" && memory["exterior_status"]["lock"] == "locked")
var/int_closed = (memory["interior_status"]["state"] == "closed" && memory["interior_status"]["lock"] == "locked")
return (ext_closed && int_closed)
/datum/computer/file/embedded_program/airlock/proc/signalDoor(var/tag, var/command)
var/datum/signal/signal = new
@@ -253,7 +240,6 @@
signal.data["command"] = command
post_signal(signal)
/datum/computer/file/embedded_program/airlock/proc/signalPump(var/tag, var/power, var/direction, var/pressure)
var/datum/signal/signal = new
signal.data = list(

View File

@@ -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
/datum/computer/file/embedded_program/airlock/docking/receive_signal(datum/signal/signal, receive_method, receive_param)
var/override_enabled = 0 //skips checks for the docking port being ready
/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)
return //this signal is not for us
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()
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(receive_tag, "docking_error") //send an error message
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(receive_tag == tag_target)
begin_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 ("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
..()
/datum/computer/file/embedded_program/airlock/docking/receive_user_command(command)
if (state == STATE_UNDOCKED || airlock_override)
..(command)
/datum/computer/file/embedded_program/airlock/docking/process()
..() //process regular airlock stuff first
switch(dock_state)
if(STATE_DOCKING)
if(done_cycling() || airlock_override)
state = STATE_DOCKED
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()
if ("request_undock")
if (control_mode == MODE_SERVER && dock_state == STATE_DOCKED && receive_tag == tag_target)
dock_state = STATE_UNDOCKING
stop_cycling()
prepare_for_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 ("abort_dock")
if (dock_state == STATE_DOCKING && receive_tag == tag_target)
reset()
/datum/computer/file/embedded_program/airlock/docking/proc/send_docking_command(var/recipient, var/command)
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
if ("disable_override")
if (receive_tag == tag_target)
override_enabled = 0
/datum/computer/file/embedded_program/docking/process()
switch(dock_state)
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 (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!
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/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 MODE_NONE
#undef MODE_SERVER
#undef MODE_CLIENT

View File

@@ -0,0 +1,26 @@
/datum/computer/file/embedded_program
var/list/memory = list()
var/obj/machinery/embedded_controller/master
var/id_tag
/datum/computer/file/embedded_program/New(var/obj/machinery/embedded_controller/M)
master = M
if (istype(M, /obj/machinery/embedded_controller/radio))
id_tag = M:id_tag
/datum/computer/file/embedded_program/proc/receive_user_command(command)
return
/datum/computer/file/embedded_program/proc/receive_signal(datum/signal/signal, receive_method, receive_param)
return
/datum/computer/file/embedded_program/proc/process()
return
/datum/computer/file/embedded_program/proc/post_signal(datum/signal/signal, comm_line)
if(master)
master.post_signal(signal, comm_line)
else
del(signal)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
<div class="item" style="padding-top: 10px">
<div class="item">
<div class="itemLabel">
Docking Port Status:
</div>
<div class="itemContent">
{{if docking_status.state == "docked"}}
DOCKED
{{else docking_status.state == "docking"}}
UNDOCKING
{{else docking_status.state == "undocking"}}
DOCKING
{{else docking_status.state == "undocked"}}
UNDOCKED
{{else}}
ERROR
{{/if}}
</div>
</div>
</div>
<div class="item" style="padding-top: 10px">
<div class="item">
<div class="itemLabel">
Chamber Pressure:
</div>
<div class="itemContent">
{{:~displayBar(chamber_pressure, 0, 200, chamber_pressure < 80 || chamber_pressure > 120 ? 'bad' : chamber_pressure < 95 || chamber_pressure > 110 ? 'average' : 'good')}}
<div class="statusValue">
{{:chamber_pressure}} kPa
</div>
</div>
</div>
</div>
<div class="item" style="padding-top: 10px">
<div class="item">
<div class="itemContent" style="width: 100%">
{{:~link('Cycle to Exterior', 'arrowthickstop-1-w', {'command' : 'cycle_ext'}, processing ? 'disabled' : null)}}
{{:~link('Cycle to Interior', 'arrowthickstop-1-e', {'command' : 'cycle_int'}, processing ? 'disabled' : null)}}
</div>
<div class="itemContent" style="padding-top: 2px; width: 100%">
{{if interior_status.state == "open"}}
{{:~link('Force exterior door', 'alert', {'command' : 'force_ext'}, null, 'redBackground')}}
{{else}}
{{:~link('Force exterior door', 'alert', {'command' : 'force_ext'}, null, processing ? 'yellowBackground' : null)}}
{{/if}}
{{if exterior_status.state == "open"}}
{{:~link('Force interior door', 'alert', {'command' : 'force_int'}, null, 'redBackground')}}
{{else}}
{{:~link('Force interior door', 'alert', {'command' : 'force_int'}, null, processing ? 'yellowBackground' : null)}}
{{/if}}
</div>
</div>
<div class="item" style="padding-top: 10px; width: 100%">
{{:~link('Abort', 'cancel', {'command' : 'abort'}, processing ? null : 'disabled', processing ? 'redBackground' : null)}}
</div>
</div>