TGUI Overmap Shuttle Controls

This commit is contained in:
ShadowLarkens
2020-08-17 17:46:56 -07:00
parent 2cb854cb1b
commit 48b630891e
27 changed files with 1287 additions and 997 deletions

View File

@@ -189,6 +189,8 @@
/datum/computer_file/program/proc/check_eye(var/mob/user) /datum/computer_file/program/proc/check_eye(var/mob/user)
if(NM) if(NM)
return NM.check_eye(user) return NM.check_eye(user)
if(TM)
return TM.check_eye(user)
else else
return -1 return -1

View File

@@ -1,7 +1,7 @@
/datum/computer_file/program/ship_nav /datum/computer_file/program/ship_nav
filename = "navviewer" filename = "navviewer"
filedesc = "Ship Navigational Screen" filedesc = "Ship Navigational Screen"
nanomodule_path = /datum/nano_module/program/ship/nav tguimodule_path = /datum/tgui_module/ship/nav/ntos
program_icon_state = "helm" program_icon_state = "helm"
program_key_state = "generic_key" program_key_state = "generic_key"
program_menu_icon = "pin-s" program_menu_icon = "pin-s"
@@ -10,54 +10,3 @@
requires_ntnet = 1 requires_ntnet = 1
network_destination = "ship position sensors" network_destination = "ship position sensors"
size = 4 size = 4
/datum/nano_module/program/ship/nav
name = "Navigation Display"
/datum/nano_module/program/ship/nav/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
if(!linked)
to_chat(user, "<span class='warning'>You don't appear to be on a spaceship...</span>")
if(program)
program.kill_program()
else if(ui)
ui.close()
return
var/list/data = list()
if(program)
data = program.get_header_data()
var/turf/T = get_turf(linked)
var/obj/effect/overmap/visitable/sector/current_sector = locate() in T
data["sector"] = current_sector ? current_sector.name : "Deep Space"
data["sector_info"] = current_sector ? current_sector.desc : "Not Available"
data["s_x"] = linked.x
data["s_y"] = linked.y
data["speed"] = round(linked.get_speed()*1000, 0.01)
data["accel"] = round(linked.get_acceleration()*1000, 0.01)
data["heading"] = linked.get_heading_degrees()
data["viewing"] = viewing_overmap(user)
if(linked.get_speed())
data["ETAnext"] = "[round(linked.ETA()/10)] seconds"
else
data["ETAnext"] = "N/A"
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "nav.tmpl", "[linked.name] Navigation Screen", 380, 530, state = state)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/datum/nano_module/program/ship/nav/OnTopic(var/mob/user, var/list/href_list)
if(..())
return TOPIC_HANDLED
if (!linked)
return TOPIC_NOACTION
if (href_list["viewing"])
viewing_overmap(user) ? unlook(user) : look(user)
return TOPIC_REFRESH

View File

@@ -1,87 +0,0 @@
/datum/nano_module/program/ship
var/obj/effect/overmap/visitable/ship/linked
var/list/viewers
var/extra_view = 0
/datum/nano_module/program/ship/New()
..()
sync_linked()
if(linked)
name = "[linked.name] [name]"
/datum/nano_module/program/ship/Destroy()
if(LAZYLEN(viewers))
for(var/weakref/W in viewers)
var/M = W.resolve()
if(M)
unlook(M)
. = ..()
/datum/nano_module/program/ship/proc/sync_linked()
var/obj/effect/overmap/visitable/ship/sector = get_overmap_sector(get_z(nano_host()))
if(!sector)
return
return attempt_hook_up_recursive(sector)
/datum/nano_module/program/ship/proc/attempt_hook_up_recursive(obj/effect/overmap/visitable/ship/sector)
if(attempt_hook_up(sector))
return sector
for(var/obj/effect/overmap/visitable/ship/candidate in sector)
if((. = .(candidate)))
return
/datum/nano_module/program/ship/proc/attempt_hook_up(obj/effect/overmap/visitable/ship/sector)
if(!istype(sector))
return
if(sector.check_ownership(nano_host()))
linked = sector
return 1
/datum/nano_module/program/ship/proc/look(var/mob/user)
if(linked)
user.machine = nano_host()
user.reset_view(linked)
user.set_viewsize(world.view + extra_view)
GLOB.moved_event.register(user, src, /datum/nano_module/program/ship/proc/unlook)
LAZYDISTINCTADD(viewers, weakref(user))
/datum/nano_module/program/ship/proc/unlook(var/mob/user)
user.reset_view()
user.set_viewsize() // reset to default
GLOB.moved_event.unregister(user, src, /datum/nano_module/program/ship/proc/unlook)
LAZYREMOVE(viewers, weakref(user))
/datum/nano_module/program/ship/proc/viewing_overmap(mob/user)
return (weakref(user) in viewers)
/datum/nano_module/program/ship/proc/DefaultTopicState()
return global.default_state
/datum/nano_module/program/ship/Topic(var/href, var/href_list = list(), var/datum/topic_state/state)
if((. = ..()))
return
state = state || DefaultTopicState() || global.default_state
if(CanUseTopic(usr, state, href_list) == STATUS_INTERACTIVE)
CouldUseTopic(usr)
return OnTopic(usr, href_list, state)
CouldNotUseTopic(usr)
return TRUE
/datum/nano_module/program/ship/proc/OnTopic(var/mob/user, var/href_list, var/datum/topic_state/state)
return TOPIC_NOACTION
/datum/nano_module/program/ship/proc/CouldNotUseTopic(mob/user)
. = ..()
unlook(user)
/datum/nano_module/program/ship/proc/CouldUseTopic(mob/user)
. = ..()
if(viewing_overmap(user))
look(user)
/datum/nano_module/program/ship/check_eye(var/mob/user)
if (!get_dist(user, nano_host()) > 1 || user.blinded || !linked )
unlook(user)
return -1
else
return 0

View File

@@ -118,14 +118,30 @@ obj/machinery/computer/ship/disperser/proc/is_valid_setup()
if(B) if(B)
return B return B
/obj/machinery/computer/ship/disperser/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = TRUE) /obj/machinery/computer/ship/disperser/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
if(!linked) if(!linked)
display_reconnect_dialog(user, "disperser synchronization") display_reconnect_dialog(user, "disperser synchronization")
return return
var/data[0] ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "OvermapDisperser", "[linked.name] ORB control") // 400, 550
ui.open()
if (!link_parts()) /obj/machinery/computer/ship/disperser/tgui_data(mob/user)
var/list/data = list()
data["faillink"] = FALSE
data["calibration"] = null
data["overmapdir"] = null
data["cal_accuracy"] = 0
data["strength"] = 0
data["range"] = 0
data["next_shot"] = -1
data["nopower"] = TRUE
data["skill"] = FALSE
data["chargeload"] = null
if(!link_parts())
data["faillink"] = TRUE data["faillink"] = TRUE
else else
data["calibration"] = calibration data["calibration"] = calibration
@@ -137,56 +153,58 @@ obj/machinery/computer/ship/disperser/proc/is_valid_setup()
data["nopower"] = !data["faillink"] && (!front.powered() || !middle.powered() || !back.powered()) data["nopower"] = !data["faillink"] && (!front.powered() || !middle.powered() || !back.powered())
data["skill"] = user.get_skill_value(core_skill) > skill_offset data["skill"] = user.get_skill_value(core_skill) > skill_offset
var/charge = "<b>UNKNOWN ERROR</b>" var/charge = "UNKNOWN ERROR"
if(get_charge_type() == OVERMAP_WEAKNESS_NONE) if(get_charge_type() == OVERMAP_WEAKNESS_NONE)
charge = "<b>ERROR</b>: No valid charge detected." charge = "ERROR: No valid charge detected."
else else
var/obj/structure/ship_munition/disperser_charge/B = get_charge() var/obj/structure/ship_munition/disperser_charge/B = get_charge()
charge = B.chargedesc charge = B.chargedesc
data["chargeload"] = charge data["chargeload"] = charge
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) return data
if (!ui)
ui = new(user, src, ui_key, "disperser.tmpl", "[linked.name] ORB control", 400, 550)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/ship/disperser/OnTopic(mob/user, list/href_list, state) /obj/machinery/computer/ship/disperser/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..() if(..())
if(.) return TRUE
return
if(!linked) if(!linked)
return TOPIC_HANDLED return FALSE
if (href_list["choose"]) switch(action)
overmapdir = sanitize_integer(text2num(href_list["choose"]), 0, 9, 0) if("choose")
reset_calibration() overmapdir = sanitize_integer(text2num(params["dir"]), 0, 9, 0)
reset_calibration()
. = TRUE
if(href_list["calibration"]) if("calibration")
var/input = input("0-9", "disperser calibration", 0) as num|null var/input = input("0-9", "disperser calibration", 0) as num|null
if(!isnull(input)) //can be zero so we explicitly check for null if(!isnull(input)) //can be zero so we explicitly check for null
var/calnum = sanitize_integer(text2num(href_list["calibration"]), 0, caldigit)//sanitiiiiize var/calnum = sanitize_integer(text2num(params["calibration"]), 0, caldigit)//sanitiiiiize
calibration[calnum + 1] = sanitize_integer(input, 0, 9, 0)//must add 1 because nanoui indexes from 0 calibration[calnum + 1] = sanitize_integer(input, 0, 9, 0)//must add 1 because js indexes from 0
. = TRUE
if(href_list["skill_calibration"]) if("skill_calibration")
for(var/i = 1 to min(caldigit, user.get_skill_value(core_skill) - skill_offset)) for(var/i = 1 to min(caldigit, usr.get_skill_value(core_skill) - skill_offset))
calibration[i] = calexpected[i] calibration[i] = calexpected[i]
. = TRUE
if(href_list["strength"]) if("strength")
var/input = input("1-5", "disperser strength", 1) as num|null var/input = input("1-5", "disperser strength", 1) as num|null
if(input && CanInteract(user, state)) if(input && tgui_status(usr, state) == STATUS_INTERACTIVE)
strength = sanitize_integer(input, 1, 5, 1) strength = sanitize_integer(input, 1, 5, 1)
middle.update_idle_power_usage(strength * range * 100) middle.update_idle_power_usage(strength * range * 100)
. = TRUE
if(href_list["range"]) if("range")
var/input = input("1-5", "disperser radius", 1) as num|null var/input = input("1-5", "disperser radius", 1) as num|null
if(input && CanInteract(user, state)) if(input && tgui_status(usr, state) == STATUS_INTERACTIVE)
range = sanitize_integer(input, 1, 5, 1) range = sanitize_integer(input, 1, 5, 1)
middle.update_idle_power_usage(strength * range * 100) middle.update_idle_power_usage(strength * range * 100)
. = TRUE
if(href_list["fire"]) if("fire")
fire(user) fire(usr)
. = TRUE
return TOPIC_REFRESH if(. && !issilicon(usr))
playsound(src, "terminal_type", 50, 1)

View File

@@ -54,22 +54,8 @@
// //
// Topic // Topic
// //
/obj/machinery/computer/ship/tgui_state()
/obj/machinery/computer/ship/proc/DefaultTopicState() return GLOB.tgui_default_state
return global.default_state
/obj/machinery/computer/ship/Topic(var/href, var/href_list = list(), var/datum/topic_state/state)
if((. = ..()))
return
state = state || DefaultTopicState() || global.default_state
if(CanUseTopic(usr, state, href_list) == STATUS_INTERACTIVE)
CouldUseTopic(usr)
return OnTopic(usr, href_list, state)
CouldNotUseTopic(usr)
return TRUE
/obj/machinery/computer/ship/proc/OnTopic(var/mob/user, var/href_list, var/datum/topic_state/state)
return TOPIC_NOACTION
// //
// Interaction // Interaction
@@ -80,11 +66,11 @@
// If you perform direct interactions in here, you are responsible for ensuring that full interactivity checks have been made (i.e CanInteract). // If you perform direct interactions in here, you are responsible for ensuring that full interactivity checks have been made (i.e CanInteract).
// The checks leading in to here only guarantee that the user should be able to view a UI. // The checks leading in to here only guarantee that the user should be able to view a UI.
/obj/machinery/computer/ship/proc/interface_interact(var/mob/user) /obj/machinery/computer/ship/proc/interface_interact(var/mob/user)
ui_interact(user) tgui_interact(user)
return TRUE return TRUE
/obj/machinery/computer/ship/attack_ai(mob/user) /obj/machinery/computer/ship/attack_ai(mob/user)
if(CanUseTopic(user, DefaultTopicState()) > STATUS_CLOSE) if(tgui_status(user, tgui_state()) > STATUS_CLOSE)
return interface_interact(user) return interface_interact(user)
// After a recent rework this should mostly be safe. // After a recent rework this should mostly be safe.
@@ -98,6 +84,6 @@
return return
if(!allowed(user)) if(!allowed(user))
to_chat(user, "<span class='warning'>Access Denied.</span>") to_chat(user, "<span class='warning'>Access Denied.</span>")
return 1 return TRUE
if(CanUseTopic(user, DefaultTopicState()) > STATUS_CLOSE) if(tgui_status(user, tgui_state()) > STATUS_CLOSE)
return interface_interact(user) return interface_interact(user)

View File

@@ -5,92 +5,92 @@
icon_keyboard = "tech_key" icon_keyboard = "tech_key"
icon_screen = "engines" icon_screen = "engines"
circuit = /obj/item/weapon/circuitboard/engine circuit = /obj/item/weapon/circuitboard/engine
var/display_state = "status"
/obj/machinery/computer/ship/engines/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) /obj/machinery/computer/ship/engines/tgui_interact(mob/user, datum/tgui/ui)
if(!linked) if(!linked)
display_reconnect_dialog(user, "ship control systems") display_reconnect_dialog(user, "ship control systems")
return return
var/data[0] ui = SStgui.try_update_ui(user, src, ui)
data["state"] = display_state if(!ui)
ui = new(user, src, "OvermapEngines", "[linked.name] Engines Control") // 390, 530
ui.open()
/obj/machinery/computer/ship/engines/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = list()
data["global_state"] = linked.engines_state data["global_state"] = linked.engines_state
data["global_limit"] = round(linked.thrust_limit*100) data["global_limit"] = round(linked.thrust_limit*100)
var/total_thrust = 0 var/total_thrust = 0
var/list/enginfo[0] var/list/enginfo = list()
for(var/datum/ship_engine/E in linked.engines) for(var/datum/ship_engine/E in linked.engines)
var/list/rdata[0] var/list/rdata = list()
rdata["eng_type"] = E.name rdata["eng_type"] = E.name
rdata["eng_on"] = E.is_on() rdata["eng_on"] = E.is_on()
rdata["eng_thrust"] = E.get_thrust() rdata["eng_thrust"] = E.get_thrust()
rdata["eng_thrust_limiter"] = round(E.get_thrust_limit()*100) rdata["eng_thrust_limiter"] = round(E.get_thrust_limit()*100)
rdata["eng_status"] = E.get_status() var/list/status = E.get_status()
if(!islist(status))
log_runtime(EXCEPTION("Warning, ship [E.name] (\ref[E]) for [linked.name] returned a non-list status!"))
status = list("Error")
rdata["eng_status"] = status
rdata["eng_reference"] = "\ref[E]" rdata["eng_reference"] = "\ref[E]"
total_thrust += E.get_thrust() total_thrust += E.get_thrust()
enginfo.Add(list(rdata)) enginfo.Add(list(rdata))
data["engines_info"] = enginfo data["engines_info"] = enginfo
data["total_thrust"] = total_thrust data["total_thrust"] = total_thrust
return data
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) /obj/machinery/computer/ship/engines/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if (!ui)
ui = new(user, src, ui_key, "engines_control.tmpl", "[linked.name] Engines Control", 390, 530)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/ship/engines/OnTopic(var/mob/user, var/list/href_list, state)
if(..()) if(..())
return ..() return TRUE
if(href_list["state"]) switch(action)
display_state = href_list["state"] if("global_toggle")
return TOPIC_REFRESH linked.engines_state = !linked.engines_state
for(var/datum/ship_engine/E in linked.engines)
if(linked.engines_state == !E.is_on())
E.toggle()
. = TRUE
if(href_list["global_toggle"]) if("set_global_limit")
linked.engines_state = !linked.engines_state var/newlim = input("Input new thrust limit (0..100%)", "Thrust limit", linked.thrust_limit*100) as num
for(var/datum/ship_engine/E in linked.engines) if(tgui_status(usr, state) != STATUS_INTERACTIVE)
if(linked.engines_state == !E.is_on()) return FALSE
E.toggle() linked.thrust_limit = clamp(newlim/100, 0, 1)
return TOPIC_REFRESH for(var/datum/ship_engine/E in linked.engines)
E.set_thrust_limit(linked.thrust_limit)
. = TRUE
if(href_list["set_global_limit"]) if("global_limit")
var/newlim = input("Input new thrust limit (0..100%)", "Thrust limit", linked.thrust_limit*100) as num linked.thrust_limit = clamp(linked.thrust_limit + text2num(params["global_limit"]), 0, 1)
if(!CanInteract(user, state)) for(var/datum/ship_engine/E in linked.engines)
return TOPIC_NOACTION E.set_thrust_limit(linked.thrust_limit)
linked.thrust_limit = CLAMP(newlim/100, 0, 1) . = TRUE
for(var/datum/ship_engine/E in linked.engines)
E.set_thrust_limit(linked.thrust_limit)
return TOPIC_REFRESH
if(href_list["global_limit"]) if("set_limit")
linked.thrust_limit = CLAMP(linked.thrust_limit + text2num(href_list["global_limit"]), 0, 1) var/datum/ship_engine/E = locate(params["engine"])
for(var/datum/ship_engine/E in linked.engines)
E.set_thrust_limit(linked.thrust_limit)
return TOPIC_REFRESH
if(href_list["engine"])
if(href_list["set_limit"])
var/datum/ship_engine/E = locate(href_list["engine"])
var/newlim = input("Input new thrust limit (0..100)", "Thrust limit", E.get_thrust_limit()) as num var/newlim = input("Input new thrust limit (0..100)", "Thrust limit", E.get_thrust_limit()) as num
if(!CanInteract(user, state)) if(tgui_status(usr, state) != STATUS_INTERACTIVE)
return return FALSE
var/limit = CLAMP(newlim/100, 0, 1) var/limit = clamp(newlim/100, 0, 1)
if(istype(E)) if(istype(E))
E.set_thrust_limit(limit) E.set_thrust_limit(limit)
return TOPIC_REFRESH . = TRUE
if(href_list["limit"])
var/datum/ship_engine/E = locate(href_list["engine"])
var/limit = CLAMP(E.get_thrust_limit() + text2num(href_list["limit"]), 0, 1)
if(istype(E))
E.set_thrust_limit(limit)
return TOPIC_REFRESH
if(href_list["toggle"]) if("limit")
var/datum/ship_engine/E = locate(href_list["engine"]) var/datum/ship_engine/E = locate(params["engine"])
var/limit = clamp(E.get_thrust_limit() + text2num(params["limit"]), 0, 1)
if(istype(E))
E.set_thrust_limit(limit)
. = TRUE
if("toggle")
var/datum/ship_engine/E = locate(params["engine"])
if(istype(E)) if(istype(E))
E.toggle() E.toggle()
return TOPIC_REFRESH . = TRUE
return TOPIC_REFRESH
return TOPIC_NOACTION if(. && !issilicon(usr))
playsound(src, "terminal_type", 50, 1)

View File

@@ -22,6 +22,7 @@ GLOBAL_LIST_EMPTY(all_waypoints)
circuit = /obj/item/weapon/circuitboard/helm circuit = /obj/item/weapon/circuitboard/helm
core_skill = /datum/skill/pilot core_skill = /datum/skill/pilot
var/autopilot = 0 var/autopilot = 0
var/autopilot_disabled = TRUE
var/list/known_sectors = list() var/list/known_sectors = list()
var/dx //desitnation var/dx //desitnation
var/dy //coordinates var/dy //coordinates
@@ -36,7 +37,7 @@ GLOBAL_LIST_EMPTY(all_waypoints)
/obj/machinery/computer/ship/helm/proc/get_known_sectors() /obj/machinery/computer/ship/helm/proc/get_known_sectors()
var/area/overmap/map = locate() in world var/area/overmap/map = locate() in world
for(var/obj/effect/overmap/visitable/sector/S in map) for(var/obj/effect/overmap/visitable/sector/S in map)
if (S.known) if(S.known)
var/datum/computer_file/data/waypoint/R = new() var/datum/computer_file/data/waypoint/R = new()
R.fields["name"] = S.name R.fields["name"] = S.name
R.fields["x"] = S.x R.fields["x"] = S.x
@@ -45,7 +46,7 @@ GLOBAL_LIST_EMPTY(all_waypoints)
/obj/machinery/computer/ship/helm/process() /obj/machinery/computer/ship/helm/process()
..() ..()
if (autopilot && dx && dy) if(autopilot && dx && dy && !autopilot_disabled)
var/turf/T = locate(dx,dy,global.using_map.overmap_z) var/turf/T = locate(dx,dy,global.using_map.overmap_z)
if(linked.loc == T) if(linked.loc == T)
if(linked.is_still()) if(linked.is_still())
@@ -60,13 +61,13 @@ GLOBAL_LIST_EMPTY(all_waypoints)
var/heading = linked.get_heading() var/heading = linked.get_heading()
// Destination is current grid or speedlimit is exceeded // Destination is current grid or speedlimit is exceeded
if ((get_dist(linked.loc, T) <= brake_path) || speed > speedlimit) if((get_dist(linked.loc, T) <= brake_path) || speed > speedlimit)
linked.decelerate() linked.decelerate()
// Heading does not match direction // Heading does not match direction
else if (heading & ~direction) else if(heading & ~direction)
linked.accelerate(turn(heading & ~direction, 180), accellimit) linked.accelerate(turn(heading & ~direction, 180), accellimit)
// All other cases, move toward direction // All other cases, move toward direction
else if (speed + acceleration <= speedlimit) else if(speed + acceleration <= speedlimit)
linked.accelerate(direction, accellimit) linked.accelerate(direction, accellimit)
linked.operator_skill = null//if this is on you can't dodge meteors linked.operator_skill = null//if this is on you can't dodge meteors
return return
@@ -78,149 +79,176 @@ GLOBAL_LIST_EMPTY(all_waypoints)
linked.relaymove(user, direction, accellimit) linked.relaymove(user, direction, accellimit)
return 1 return 1
/obj/machinery/computer/ship/helm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) /obj/machinery/computer/ship/helm/tgui_interact(mob/user, datum/tgui/ui)
var/data[0]
if(!linked) if(!linked)
display_reconnect_dialog(user, "helm") display_reconnect_dialog(user, "helm")
return
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "OvermapHelm", "[linked.name] Helm Control") // 565, 545
ui.open()
/obj/machinery/computer/ship/helm/tgui_data(mob/user)
var/list/data = ..()
var/turf/T = get_turf(linked)
var/obj/effect/overmap/visitable/sector/current_sector = locate() in T
data["sector"] = current_sector ? current_sector.name : "Deep Space"
data["sector_info"] = current_sector ? current_sector.desc : "Not Available"
data["landed"] = linked.get_landed_info()
data["s_x"] = linked.x
data["s_y"] = linked.y
data["dest"] = dy && dx
data["d_x"] = dx
data["d_y"] = dy
data["speedlimit"] = speedlimit ? speedlimit*1000 : "Halted"
data["accel"] = min(round(linked.get_acceleration()*1000, 0.01),accellimit*1000)
data["heading"] = linked.get_heading_degrees()
data["autopilot_disabled"] = autopilot_disabled
data["autopilot"] = autopilot
data["manual_control"] = viewing_overmap(user)
data["canburn"] = linked.can_burn()
data["accellimit"] = accellimit*1000
var/speed = round(linked.get_speed()*1000, 0.01)
var/speed_color = null
if(linked.get_speed() < SHIP_SPEED_SLOW)
speed_color = "good"
if(linked.get_speed() > SHIP_SPEED_FAST)
speed_color = "average"
data["speed"] = speed
data["speed_color"] = speed_color
if(linked.get_speed())
data["ETAnext"] = "[round(linked.ETA()/10)] seconds"
else else
var/turf/T = get_turf(linked) data["ETAnext"] = "N/A"
var/obj/effect/overmap/visitable/sector/current_sector = locate() in T
data["sector"] = current_sector ? current_sector.name : "Deep Space" var/list/locations[0]
data["sector_info"] = current_sector ? current_sector.desc : "Not Available" for (var/key in known_sectors)
data["landed"] = linked.get_landed_info() var/datum/computer_file/data/waypoint/R = known_sectors[key]
data["s_x"] = linked.x var/list/rdata[0]
data["s_y"] = linked.y rdata["name"] = R.fields["name"]
data["dest"] = dy && dx rdata["x"] = R.fields["x"]
data["d_x"] = dx rdata["y"] = R.fields["y"]
data["d_y"] = dy rdata["reference"] = "\ref[R]"
data["speedlimit"] = speedlimit ? speedlimit*1000 : "Halted" locations.Add(list(rdata))
data["accel"] = min(round(linked.get_acceleration()*1000, 0.01),accellimit*1000)
data["heading"] = linked.get_heading_degrees()
data["autopilot"] = autopilot
data["manual_control"] = viewing_overmap(user)
data["canburn"] = linked.can_burn()
data["accellimit"] = accellimit*1000
var/speed = round(linked.get_speed()*1000, 0.01) data["locations"] = locations
if(linked.get_speed() < SHIP_SPEED_SLOW) return data
speed = "<span class='good'>[speed]</span>"
if(linked.get_speed() > SHIP_SPEED_FAST)
speed = "<span class='average'>[speed]</span>"
data["speed"] = speed
if(linked.get_speed()) /obj/machinery/computer/ship/helm/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
data["ETAnext"] = "[round(linked.ETA()/10)] seconds"
else
data["ETAnext"] = "N/A"
var/list/locations[0]
for (var/key in known_sectors)
var/datum/computer_file/data/waypoint/R = known_sectors[key]
var/list/rdata[0]
rdata["name"] = R.fields["name"]
rdata["x"] = R.fields["x"]
rdata["y"] = R.fields["y"]
rdata["reference"] = "\ref[R]"
locations.Add(list(rdata))
data["locations"] = locations
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "helm.tmpl", "[linked.name] Helm Control", 565, 545)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/ship/helm/OnTopic(var/mob/user, var/list/href_list, state)
if(..()) if(..())
return TOPIC_HANDLED return TRUE
if(!linked) if(!linked)
return TOPIC_HANDLED return FALSE
if (href_list["add"]) switch(action)
var/datum/computer_file/data/waypoint/R = new() if("add")
var/sec_name = input("Input naviation entry name", "New navigation entry", "Sector #[known_sectors.len]") as text var/datum/computer_file/data/waypoint/R = new()
if(!CanInteract(user,state)) var/sec_name = input("Input navigation entry name", "New navigation entry", "Sector #[known_sectors.len]") as text
return TOPIC_NOACTION if(tgui_status(usr, state) != STATUS_INTERACTIVE)
if(!sec_name) return FALSE
sec_name = "Sector #[known_sectors.len]" if(!sec_name)
R.fields["name"] = sec_name sec_name = "Sector #[known_sectors.len]"
if(sec_name in known_sectors) R.fields["name"] = sec_name
to_chat(user, "<span class='warning'>Sector with that name already exists, please input a different name.</span>") if(sec_name in known_sectors)
return TOPIC_REFRESH to_chat(usr, "<span class='warning'>Sector with that name already exists, please input a different name.</span>")
switch(href_list["add"]) return TRUE
if("current") switch(params["add"])
R.fields["x"] = linked.x if("current")
R.fields["y"] = linked.y R.fields["x"] = linked.x
if("new") R.fields["y"] = linked.y
var/newx = input("Input new entry x coordinate", "Coordinate input", linked.x) as num if("new")
if(!CanInteract(user,state)) var/newx = input("Input new entry x coordinate", "Coordinate input", linked.x) as num
return TOPIC_REFRESH if(tgui_status(usr, state) != STATUS_INTERACTIVE)
var/newy = input("Input new entry y coordinate", "Coordinate input", linked.y) as num return TRUE
if(!CanInteract(user,state)) var/newy = input("Input new entry y coordinate", "Coordinate input", linked.y) as num
return TOPIC_NOACTION if(tgui_status(usr, state) != STATUS_INTERACTIVE)
R.fields["x"] = CLAMP(newx, 1, world.maxx) return FALSE
R.fields["y"] = CLAMP(newy, 1, world.maxy) R.fields["x"] = CLAMP(newx, 1, world.maxx)
known_sectors[sec_name] = R R.fields["y"] = CLAMP(newy, 1, world.maxy)
known_sectors[sec_name] = R
. = TRUE
if (href_list["remove"]) if("remove")
var/datum/computer_file/data/waypoint/R = locate(href_list["remove"]) var/datum/computer_file/data/waypoint/R = locate(params["remove"])
if(R) if(R)
known_sectors.Remove(R.fields["name"]) known_sectors.Remove(R.fields["name"])
qdel(R) qdel(R)
. = TRUE
if (href_list["setx"]) if("setcoord")
var/newx = input("Input new destiniation x coordinate", "Coordinate input", dx) as num|null if(params["setx"])
if(!CanInteract(user,state)) var/newx = input("Input new destiniation x coordinate", "Coordinate input", dx) as num|null
return if(tgui_status(usr, state) != STATUS_INTERACTIVE)
if (newx) return
dx = CLAMP(newx, 1, world.maxx) if(newx)
dx = CLAMP(newx, 1, world.maxx)
if (href_list["sety"]) if(params["sety"])
var/newy = input("Input new destiniation y coordinate", "Coordinate input", dy) as num|null var/newy = input("Input new destiniation y coordinate", "Coordinate input", dy) as num|null
if(!CanInteract(user,state)) if(tgui_status(usr, state) != STATUS_INTERACTIVE)
return return
if (newy) if(newy)
dy = CLAMP(newy, 1, world.maxy) dy = CLAMP(newy, 1, world.maxy)
. = TRUE
if (href_list["x"] && href_list["y"]) if("setds")
dx = text2num(href_list["x"]) dx = text2num(params["x"])
dy = text2num(href_list["y"]) dy = text2num(params["y"])
. = TRUE
if (href_list["reset"]) if("reset")
dx = 0 dx = 0
dy = 0 dy = 0
. = TRUE
if (href_list["speedlimit"]) if("speedlimit")
var/newlimit = input("Input new speed limit for autopilot (0 to brake)", "Autopilot speed limit", speedlimit*1000) as num|null var/newlimit = input("Input new speed limit for autopilot (0 to brake)", "Autopilot speed limit", speedlimit*1000) as num|null
if(newlimit) if(newlimit)
speedlimit = CLAMP(newlimit/1000, 0, 100) speedlimit = CLAMP(newlimit/1000, 0, 100)
if (href_list["accellimit"]) . = TRUE
var/newlimit = input("Input new acceleration limit", "Acceleration limit", accellimit*1000) as num|null
if(newlimit)
accellimit = max(newlimit/1000, 0)
if (href_list["move"]) if("accellimit")
var/ndir = text2num(href_list["move"]) var/newlimit = input("Input new acceleration limit", "Acceleration limit", accellimit*1000) as num|null
if(prob(user.skill_fail_chance(/datum/skill/pilot, 50, linked.skill_needed, factor = 1))) if(newlimit)
ndir = turn(ndir,pick(90,-90)) accellimit = max(newlimit/1000, 0)
linked.relaymove(user, ndir, accellimit) . = TRUE
if (href_list["brake"]) if("move")
linked.decelerate() var/ndir = text2num(params["dir"])
if(prob(usr.skill_fail_chance(/datum/skill/pilot, 50, linked.skill_needed, factor = 1)))
ndir = turn(ndir,pick(90,-90))
linked.relaymove(usr, ndir, accellimit)
. = TRUE
if (href_list["apilot"]) if("brake")
autopilot = !autopilot linked.decelerate()
. = TRUE
if (href_list["manual"]) if("apilot")
viewing_overmap(user) ? unlook(user) : look(user) if(autopilot_disabled)
autopilot = FALSE
else
autopilot = !autopilot
. = TRUE
if("apilot_lock")
autopilot_disabled = !autopilot_disabled
autopilot = FALSE
. = TRUE
add_fingerprint(user) if("manual")
updateUsrDialog() viewing_overmap(usr) ? unlook(usr) : look(usr)
. = TRUE
add_fingerprint(usr)
if(. && !issilicon(usr))
playsound(src, "terminal_type", 50, 1)
/obj/machinery/computer/ship/navigation /obj/machinery/computer/ship/navigation
@@ -228,49 +256,21 @@ GLOBAL_LIST_EMPTY(all_waypoints)
icon_keyboard = "generic_key" icon_keyboard = "generic_key"
icon_screen = "helm" icon_screen = "helm"
circuit = /obj/item/weapon/circuitboard/nav circuit = /obj/item/weapon/circuitboard/nav
var/datum/tgui_module/ship/nav/nav_tgui
/obj/machinery/computer/ship/navigation/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) /obj/machinery/computer/ship/navigation/Initialize()
if(!linked) . = ..()
display_reconnect_dialog(user, "Navigation") nav_tgui = new(src)
return
var/data[0] /obj/machinery/computer/ship/navigation/Destroy()
QDEL_NULL(nav_tgui)
. = ..()
/obj/machinery/computer/ship/navigation/sync_linked(user)
return nav_tgui?.sync_linked()
var/turf/T = get_turf(linked) /obj/machinery/computer/ship/navigation/tgui_interact(mob/user, datum/tgui/ui)
var/obj/effect/overmap/visitable/sector/current_sector = locate() in T return nav_tgui?.tgui_interact(user, ui)
data["sector"] = current_sector ? current_sector.name : "Deep Space"
data["sector_info"] = current_sector ? current_sector.desc : "Not Available"
data["s_x"] = linked.x
data["s_y"] = linked.y
data["speed"] = round(linked.get_speed()*1000, 0.01)
data["accel"] = round(linked.get_acceleration()*1000, 0.01)
data["heading"] = linked.get_heading_degrees()
data["viewing"] = viewing_overmap(user)
if(linked.get_speed())
data["ETAnext"] = "[round(linked.ETA()/10)] seconds"
else
data["ETAnext"] = "N/A"
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "nav.tmpl", "[linked.name] Navigation Screen", 380, 530)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/ship/navigation/OnTopic(var/mob/user, var/list/href_list)
if(..())
return TOPIC_HANDLED
if (!linked)
return TOPIC_NOACTION
if (href_list["viewing"])
viewing_overmap(user) ? unlook(user) : look(user)
return TOPIC_REFRESH
/obj/machinery/computer/ship/navigation/telescreen //little hacky but it's only used on one ship so it should be okay /obj/machinery/computer/ship/navigation/telescreen //little hacky but it's only used on one ship so it should be okay
icon_state = "tele_nav" icon_state = "tele_nav"

View File

@@ -20,14 +20,29 @@
sensors = S sensors = S
break break
/obj/machinery/computer/ship/sensors/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) /obj/machinery/computer/ship/sensors/tgui_interact(mob/user, datum/tgui/ui)
if(!linked) if(!linked)
display_reconnect_dialog(user, "sensors") display_reconnect_dialog(user, "sensors")
return return
var/data[0] ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "OvermapShipSensors", "[linked.name] Sensors Control") // 420, 530
ui.open()
/obj/machinery/computer/ship/sensors/tgui_data(mob/user)
var/list/data = list()
data["viewing"] = viewing_overmap(user) data["viewing"] = viewing_overmap(user)
data["on"] = 0
data["range"] = "N/A"
data["health"] = 0
data["max_health"] = 0
data["heat"] = 0
data["critical_heat"] = 0
data["status"] = "MISSING"
data["contacts"] = list()
if(sensors) if(sensors)
data["on"] = sensors.use_power data["on"] = sensors.use_power
data["range"] = sensors.range data["range"] = sensors.range
@@ -53,54 +68,48 @@
if(bearing < 0) if(bearing < 0)
bearing += 360 bearing += 360
contacts.Add(list(list("name"=O.name, "ref"="\ref[O]", "bearing"=bearing))) contacts.Add(list(list("name"=O.name, "ref"="\ref[O]", "bearing"=bearing)))
if(contacts.len) data["contacts"] = contacts
data["contacts"] = contacts
else
data["status"] = "MISSING"
data["range"] = "N/A"
data["on"] = 0
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) return data
if (!ui)
ui = new(user, src, ui_key, "shipsensors.tmpl", "[linked.name] Sensors Control", 420, 530, src)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/ship/sensors/OnTopic(var/mob/user, var/list/href_list, state) /obj/machinery/computer/ship/sensors/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..()) if(..())
return TOPIC_HANDLED return TRUE
if (!linked) if(!linked)
return TOPIC_NOACTION return FALSE
if (href_list["viewing"]) switch(action)
if(user && !isAI(user)) if("viewing")
viewing_overmap(user) ? unlook(user) : look(user) if(usr && !isAI(usr))
return TOPIC_REFRESH viewing_overmap(usr) ? unlook(usr) : look(usr)
. = TRUE
if (href_list["link"]) if("link")
find_sensors() find_sensors()
return TOPIC_REFRESH . = TRUE
if("scan")
var/obj/effect/overmap/O = locate(params["scan"])
if(istype(O) && !QDELETED(O) && (O in view(7,linked)))
new/obj/item/weapon/paper/(get_turf(src), O.get_scan_data(usr), "paper (Sensor Scan - [O])")
. = TRUE
if(sensors) if(sensors)
if (href_list["range"]) switch(action)
var/nrange = input("Set new sensors range", "Sensor range", sensors.range) as num|null if("range")
if(!CanInteract(user,state)) var/nrange = input("Set new sensors range", "Sensor range", sensors.range) as num|null
return TOPIC_NOACTION if(tgui_status(usr, state) != STATUS_INTERACTIVE)
if (nrange) return FALSE
sensors.set_range(CLAMP(nrange, 1, world.view)) if(nrange)
return TOPIC_REFRESH sensors.set_range(CLAMP(nrange, 1, world.view))
if (href_list["toggle"]) . = TRUE
sensors.toggle() if("toggle")
return TOPIC_REFRESH sensors.toggle()
. = TRUE
if (href_list["scan"]) if(. && !issilicon(usr))
var/obj/effect/overmap/O = locate(href_list["scan"]) playsound(src, "terminal_type", 50, 1)
if(istype(O) && !QDELETED(O) && (O in view(7,linked)))
playsound(src, "sound/machines/dotprinter.ogg", 30, 1)
new/obj/item/weapon/paper/(get_turf(src), O.get_scan_data(user), "paper (Sensor Scan - [O])")
return TOPIC_HANDLED
/obj/machinery/computer/ship/sensors/process() /obj/machinery/computer/ship/sensors/process()
..() ..()

View File

@@ -37,22 +37,31 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
popup.set_content("<center><strong><font color = 'red'>Error</strong></font><br>Unable to connect to [flavor].<br><a href='?src=\ref[src];sync=1'>Reconnect</a></center>") popup.set_content("<center><strong><font color = 'red'>Error</strong></font><br>Unable to connect to [flavor].<br><a href='?src=\ref[src];sync=1'>Reconnect</a></center>")
popup.open() popup.open()
/obj/machinery/computer/ship/Topic(href, href_list)
if(..())
return TRUE
if(href_list["sync"])
if(sync_linked(usr))
interface_interact(usr)
return TRUE
// In computer_shims for now - we had to define it. // In computer_shims for now - we had to define it.
// /obj/machinery/computer/ship/interface_interact(var/mob/user) // /obj/machinery/computer/ship/interface_interact(var/mob/user)
// ui_interact(user) // ui_interact(user)
// return TRUE // return TRUE
/obj/machinery/computer/ship/OnTopic(var/mob/user, var/list/href_list) /obj/machinery/computer/ship/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..()) if(..())
return TOPIC_HANDLED return TRUE
if(href_list["sync"]) switch(action)
sync_linked(user) if("sync")
return TOPIC_REFRESH sync_linked(usr)
if(href_list["close"]) return TRUE
unlook(user) if("close")
user.unset_machine() unlook(usr)
return TOPIC_HANDLED usr.unset_machine()
return TOPIC_NOACTION return TRUE
return FALSE
// Management of mob view displacement. look to shift view to the ship on the overmap; unlook to shift back. // Management of mob view displacement. look to shift view to the ship on the overmap; unlook to shift back.
@@ -60,6 +69,7 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
if(linked) if(linked)
apply_visual(user) apply_visual(user)
user.reset_view(linked) user.reset_view(linked)
user.set_machine(src)
user.set_viewsize(world.view + extra_view) user.set_viewsize(world.view + extra_view)
GLOB.moved_event.register(user, src, /obj/machinery/computer/ship/proc/unlook) GLOB.moved_event.register(user, src, /obj/machinery/computer/ship/proc/unlook)
// TODO GLOB.stat_set_event.register(user, src, /obj/machinery/computer/ship/proc/unlook) // TODO GLOB.stat_set_event.register(user, src, /obj/machinery/computer/ship/proc/unlook)
@@ -75,17 +85,21 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
/obj/machinery/computer/ship/proc/viewing_overmap(mob/user) /obj/machinery/computer/ship/proc/viewing_overmap(mob/user)
return (weakref(user) in viewers) return (weakref(user) in viewers)
/obj/machinery/computer/ship/CouldNotUseTopic(mob/user) /obj/machinery/computer/ship/tgui_status(mob/user)
. = ..() . = ..()
if(. > STATUS_DISABLED)
if(viewing_overmap(user))
look(user)
return
unlook(user) unlook(user)
/obj/machinery/computer/ship/CouldUseTopic(mob/user) /obj/machinery/computer/ship/tgui_close(mob/user)
. = ..() . = ..()
if(viewing_overmap(user)) user.unset_machine()
look(user) unlook(user)
/obj/machinery/computer/ship/check_eye(var/mob/user) /obj/machinery/computer/ship/check_eye(var/mob/user)
if (!get_dist(user, src) > 1 || user.blinded || !linked ) if(!get_dist(user, src) > 1 || user.blinded || !linked)
unlook(user) unlook(user)
return -1 return -1
else else

View File

@@ -19,7 +19,7 @@ var/list/ship_engines = list()
//Returns status string for this engine //Returns status string for this engine
/datum/ship_engine/proc/get_status() /datum/ship_engine/proc/get_status()
return "All systems nominal" return list("All systems nominal")
/datum/ship_engine/proc/get_thrust() /datum/ship_engine/proc/get_thrust()
return 1 return 1

View File

@@ -103,18 +103,17 @@
. = list() . = list()
.+= "Location: [get_area(src)]." .+= "Location: [get_area(src)]."
if(stat & NOPOWER) if(stat & NOPOWER)
.+= "<span class='average'>Insufficient power to operate.</span>" .+= list(list("Insufficient power to operate.", "bad"))
if(!check_fuel()) if(!check_fuel())
.+= "<span class='average'>Insufficient fuel for a burn.</span>" .+= list(list("Insufficient fuel for a burn.", "bad"))
if(stat & BROKEN) if(stat & BROKEN)
.+= "<span class='average'>Inoperable engine configuration.</span>" .+= list(list("Inoperable engine configuration.", "bad"))
if(blockage) if(blockage)
.+= "<span class='average'>Obstruction of airflow detected.</span>" .+= list(list("Obstruction of airflow detected.", "bad"))
.+= "Propellant total mass: [round(air_contents.get_mass(),0.01)] kg." .+= "Propellant total mass: [round(air_contents.get_mass(),0.01)] kg."
.+= "Propellant used per burn: [round(air_contents.get_mass() * volume_per_burn * thrust_limit / air_contents.volume,0.01)] kg." .+= "Propellant used per burn: [round(air_contents.get_mass() * volume_per_burn * thrust_limit / air_contents.volume,0.01)] kg."
.+= "Propellant pressure: [round(air_contents.return_pressure()/1000,0.1)] MPa." .+= "Propellant pressure: [round(air_contents.return_pressure()/1000,0.1)] MPa."
. = jointext(.,"<br>")
/obj/machinery/atmospherics/unary/engine/power_change() /obj/machinery/atmospherics/unary/engine/power_change()
. = ..() . = ..()

View File

@@ -61,9 +61,7 @@
. = list() . = list()
.+= "Location: [get_area(src)]." .+= "Location: [get_area(src)]."
if(!powered()) if(!powered())
.+= "Insufficient power to operate." .+= list(list("Insufficient power to operate.", "bad"))
. = jointext(.,"<br>")
/obj/machinery/ion_engine/proc/burn() /obj/machinery/ion_engine/proc/burn()
if(!on && !powered()) if(!on && !powered())

View File

@@ -26,6 +26,9 @@ Code is pretty much ripped verbatim from nano modules, but with un-needed stuff
if(host) if(host)
host.tgui_close(user) host.tgui_close(user)
/datum/tgui_module/proc/check_eye(mob/user)
return -1
/datum/tgui_module/proc/can_still_topic(mob/user, datum/tgui_state/state) /datum/tgui_module/proc/can_still_topic(mob/user, datum/tgui_state/state)
return (tgui_status(user, state) == STATUS_INTERACTIVE) return (tgui_status(user, state) == STATUS_INTERACTIVE)

View File

@@ -0,0 +1,137 @@
/datum/tgui_module/ship
var/obj/effect/overmap/visitable/ship/linked
var/list/viewers
var/extra_view = 0
/datum/tgui_module/ship/New()
. = ..()
sync_linked()
if(linked)
name = "[linked.name] [name]"
/datum/tgui_module/ship/Destroy()
if(LAZYLEN(viewers))
for(var/weakref/W in viewers)
var/M = W.resolve()
if(M)
unlook(M)
. = ..()
/datum/tgui_module/ship/tgui_status(mob/user)
. = ..()
if(. > STATUS_DISABLED)
if(viewing_overmap(user))
look(user)
return
unlook(user)
/datum/tgui_module/ship/tgui_close(mob/user)
. = ..()
user.unset_machine()
unlook(user)
/datum/tgui_module/ship/proc/sync_linked()
var/obj/effect/overmap/visitable/ship/sector = get_overmap_sector(get_z(tgui_host()))
if(!sector)
return
return attempt_hook_up_recursive(sector)
/datum/tgui_module/ship/proc/attempt_hook_up_recursive(obj/effect/overmap/visitable/ship/sector)
if(attempt_hook_up(sector))
return sector
for(var/obj/effect/overmap/visitable/ship/candidate in sector)
if((. = .(candidate)))
return
/datum/tgui_module/ship/proc/attempt_hook_up(obj/effect/overmap/visitable/ship/sector)
if(!istype(sector))
return
if(sector.check_ownership(tgui_host()))
linked = sector
return 1
/datum/tgui_module/ship/proc/look(var/mob/user)
if(linked)
user.set_machine(tgui_host())
user.reset_view(linked)
user.set_viewsize(world.view + extra_view)
GLOB.moved_event.register(user, src, /datum/tgui_module/ship/proc/unlook)
LAZYDISTINCTADD(viewers, weakref(user))
/datum/tgui_module/ship/proc/unlook(var/mob/user)
user.reset_view()
user.set_viewsize() // reset to default
GLOB.moved_event.unregister(user, src, /datum/tgui_module/ship/proc/unlook)
LAZYREMOVE(viewers, weakref(user))
/datum/tgui_module/ship/proc/viewing_overmap(mob/user)
return (weakref(user) in viewers)
/datum/tgui_module/ship/check_eye(var/mob/user)
if(!get_dist(user, tgui_host()) > 1 || user.blinded || !linked)
unlook(user)
return -1
else
return 0
// Navigation
/datum/tgui_module/ship/nav
name = "Navigation Display"
tgui_id = "OvermapNavigation"
/datum/tgui_module/ship/nav/tgui_interact(mob/user, datum/tgui/ui)
if(!linked)
var/obj/machinery/computer/ship/navigation/host = tgui_host()
if(istype(host))
// Real Computer path
host.display_reconnect_dialog(user, "Navigation")
return
// NTOS Path
if(!sync_linked())
to_chat(user, "<span class='warning'>You don't appear to be on a spaceship...</span>")
if(ui)
ui.close(can_be_suspended = FALSE)
if(ntos)
var/obj/item/modular_computer/M = tgui_host()
if(istype(M))
M.kill_program()
return
. = ..()
/datum/tgui_module/ship/nav/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = ..()
var/turf/T = get_turf(linked)
var/obj/effect/overmap/visitable/sector/current_sector = locate() in T
data["sector"] = current_sector ? current_sector.name : "Deep Space"
data["sector_info"] = current_sector ? current_sector.desc : "Not Available"
data["s_x"] = linked.x
data["s_y"] = linked.y
data["speed"] = round(linked.get_speed()*1000, 0.01)
data["accel"] = round(linked.get_acceleration()*1000, 0.01)
data["heading"] = linked.get_heading_degrees()
data["viewing"] = viewing_overmap(user)
if(linked.get_speed())
data["ETAnext"] = "[round(linked.ETA()/10)] seconds"
else
data["ETAnext"] = "N/A"
return data
/datum/tgui_module/ship/nav/tgui_act(action, params)
if(..())
return TRUE
if(!linked)
return FALSE
if(action == "viewing")
viewing_overmap(usr) ? unlook(usr) : look(usr)
return TRUE
/datum/tgui_module/ship/nav/ntos
ntos = TRUE

View File

@@ -1,91 +0,0 @@
{{if data.faillink}}
<div class='notice'>
ERROR: Machine is incomplete, out of range, or misaligned!
</div>
{{else}}
<div style="float:left;width:50%">
<h3>Targeting</h3>
<div class='block'>
<div class='item'>
<div class='item'>
{{:helper.link('', 'triangle-1-nw', { 'choose' : 9 }, data.overmapdir == 9 ? 'selected' : null, null)}}
{{:helper.link('', 'triangle-1-n', { 'choose' : 1 }, data.overmapdir == 1 ? 'selected' : null, null)}}
{{:helper.link('', 'triangle-1-ne', { 'choose' : 5 }, data.overmapdir == 5 ? 'selected' : null, null)}}
</div>
<div class='item'>
{{:helper.link('', 'triangle-1-w', { 'choose' : 8 }, data.overmapdir == 8 ? 'selected' : null, null)}}
{{:helper.link('', 'circle-close', { 'choose' : 0 }, data.overmapdir == 0 ? 'selected' : null, null)}}
{{:helper.link('', 'triangle-1-e', { 'choose' : 4 }, data.overmapdir == 4 ? 'selected' : null, null)}}
</div>
<div class='item'>
{{:helper.link('', 'triangle-1-sw', { 'choose' : 10 }, data.overmapdir == 10 ? 'selected' : null, null)}}
{{:helper.link('', 'triangle-1-s', { 'choose' : 2 }, data.overmapdir == 2 ? 'selected' : null, null)}}
{{:helper.link('', 'triangle-1-se', { 'choose' : 6 }, data.overmapdir == 6 ? 'selected' : null, null)}}
</div>
</div>
</div>
</div>
<div style="float:right;width:50%">
<h3>Charge</h3>
<div class='block'>
{{if data.nopower}}
<b>At least one part of the machine is unpowered.</b>
{{/if}}
<div class='itemLabelWidest'>
Charge Load Type
</div>
<div class='item'>
{{:data.chargeload}}
</div>
<div class='itemLabelWidest'>
Cooldown
</div>
<div class='item'>
{{if data.next_shot == 0}}
Ready
{{else}}
{{:data.next_shot}} seconds
<br><i>Warning: Do not fire during cooldown.</i>
{{/if}}
</div>
</div>
</div>
<hr>
<div style="float:left;width:50%">
<h3>Calibration</h3>
<div class='block'>
<div class='itemLabelWidest'>
{{:data.cal_accuracy}}%
</div>
<div class='itemLabelWidest'>
{{:helper.link('Pre-Calibration', 'transfer-e-w', { 'skill_calibration' : 1 }, data.skill ? null : 'disabled', null)}}
</div><br>
{{for data.calibration}}
<div class='item'>
{{:helper.link(value, 'shuffle', { 'calibration' : index }, null, null)}}
<br>
</div>
{{/for}}
</div>
</div>
<div style="float:right;width:50%">
<h3>Setup</h3>
<div class='block'>
<div class='itemLabelWidest'>
Strength
</div>
<div class='item'>
{{:helper.link(data.strength, 'lightbulb', { 'strength' : 1 }, null, null)}}
</div>
<div class='itemLabelWidest'>
Radius
</div>
<div class='item'>
{{:helper.link(data.range, 'arrow-4-diag', { 'range' : 1 }, null, null)}}
</div>
</div>
</div>
<div class='item'>
{{:helper.link("Fire", 'alert', { 'fire' : 1 }, null, null)}}
</div>
{{/if}}

View File

@@ -1,110 +0,0 @@
<div class="item">
{{:helper.link('Overall info', 'note', {'state' :'status'}, null, data.state == 'status' ? 'selected' : null)}}
{{:helper.link('Details', 'note', {'state' : 'engines'}, null, data.state == 'engines' ? 'selected' : null)}}
</div>
<div class="item">
<div class='item'>
<div class="itemLabel">
<span class='average'>Global controls:</span>
</div>
<div class="itemContent">
{{:helper.link(data.global_state ? 'Shut all down' : 'Power all up', 'power', {'global_toggle' : 1}, null, data.global_state ? 'selected' : null)}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Volume limit:</span>
</div>
<div class="itemContent">
{{:helper.link('', 'circle-plus', { 'global_limit' : 0.1}, null, null)}}
{{:helper.link(data.global_limit+'%', null, { 'set_global_limit' : 1 }, null, null)}}
{{:helper.link('', 'circle-minus', { 'global_limit' : -0.1}, null, null)}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Total thrust:</span>
</div>
<div class="itemContent">
<span class='white'>{{:data.total_thrust}}</span>
</div>
</div>
</div>
{{if data.state == "engines"}}
{{if data.engines_info}}
{{for data.engines_info}}
<div class='item'>
<div class="itemLabel">
<span class='white'>Engine #{{:(index + 1)}}:</span>
</div>
<div class="itemContent">
{{:helper.link(value.eng_on ? 'Shutdown' : 'Power up', 'power', { 'toggle' : 1, 'engine' : value.eng_reference }, null, value.eng_on ? value.eng_on == 1 ? 'linkOn' : 'yellowButton' : null)}}
</div>
<div class='statusDisplay'>
<div class='item'>
<div class="itemLabel">
<span class='average'>Type:</span>
</div>
<div class="itemContent">
<span class='white'>{{:value.eng_type}}</span>
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Status:</span>
</div>
<div class="itemContent">
<span class='{{:value.eng_on ? value.eng_on == 1 ? 'good' : 'average' : 'bad'}}'>{{:value.eng_on ? value.eng_on == 1 ? 'Online' : 'Booting' : 'Offline'}}</span><br>
<span class='white'>{{:value.eng_status}}</span>
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Current thrust:</span>
</div>
<div class="itemContent">
<span class='white'>{{:value.eng_thrust}}</span>
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Volume limit:</span>
</div>
<div class="itemContent">
{{:helper.link('', 'circle-plus', { 'limit' : 0.1, 'engine' : value.eng_reference }, null, null)}}
{{:helper.link(value.eng_thrust_limiter+'%', null, { 'set_limit' : 1, 'engine' : value.eng_reference }, null, null)}}
{{:helper.link('', 'circle-minus', { 'limit' : -0.1, 'engine' : value.eng_reference }, null, null)}}
</div>
</div>
</div>
{{/for}}
{{/if}}
{{/if}}
{{if data.state == "status"}}
{{if data.engines_info}}
{{for data.engines_info}}
<div class='block'>
<div class='item'>
<div class="itemLabel">
<span class='white'>Engine #{{:(index + 1)}}:</span>
</div>
<div class="itemContent">
{{:helper.link(value.eng_on ? 'Shutdown' : 'Power up', 'power', { 'toggle' : 1, 'engine' : value.eng_reference }, null, value.eng_on ? value.eng_on == 1 ? 'linkOn' : 'yellowButton' : null)}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Thrust:</span>
<br>
<span class='average'>Volume limit:</span>
</div>
<div class="itemContent">
<span class='white'>{{:value.eng_thrust}}</span>
<br>
<span class='white'>{{:value.eng_thrust_limiter}}%</span>
</div>
</div>
</div>
{{/for}}
{{/if}}
{{/if}}

View File

@@ -1,159 +0,0 @@
<div style="float:left;width:45%;">
<fieldset style="min-height:180px;background-color: #202020;">
<legend style="text-align:center">Flight data</legend>
<div class='item'>
<div class="itemLabelWider">
ETA to next grid:
</div>
<div style="float:right">
{{:data.ETAnext}}
</div>
</div>
<div class='item'>
<div class="itemLabelWider">
Speed:
</div>
<div style="float:right">
{{:data.speed}} Gm/h
</div>
</div>
<div class='item'>
<div class="itemLabelWider">
Acceleration:
</div>
<div style="float:right">
{{:data.accel}} Gm/h
</div>
</div>
<div class='item'>
<div class="itemLabelWider">
Heading:
</div>
<div style="float:right">
{{:data.heading}}&deg;
</div>
</div>
<div class='item'>
<div class="itemLabelWider">
Acceleration limiter:
</div>
<div style="float:right">
{{:helper.link(data.accellimit, null, { 'accellimit' : 1}, null, null)}} Gm/h
</div>
</div>
</fieldset>
</div>
<div style="float:left;width:25%">
<fieldset style="min-height:180px;background-color: #202020;">
<legend style="text-align:center">Manual control</legend>
<div class='item'>
<div class='item'>
{{:helper.link('', 'triangle-1-nw', { 'move' : 9 }, data.canburn ? null : 'disabled', null)}}
{{:helper.link('', 'triangle-1-n', { 'move' : 1 }, data.canburn ? null : 'disabled', null)}}
{{:helper.link('', 'triangle-1-ne', { 'move' : 5 }, data.canburn ? null : 'disabled', null)}}
</div>
<div class='item'>
{{:helper.link('', 'triangle-1-w', { 'move' : 8 }, data.canburn ? null : 'disabled', null)}}
{{:helper.link('', 'circle-close', { 'brake' : 1 }, data.canburn ? null : 'disabled', null)}}
{{:helper.link('', 'triangle-1-e', { 'move' : 4 }, data.canburn ? null : 'disabled', null)}}
</div>
<div class='item'>
{{:helper.link('', 'triangle-1-sw', { 'move' : 10 }, data.canburn ? null : 'disabled', null)}}
{{:helper.link('', 'triangle-1-s', { 'move' : 2 }, data.canburn ? null : 'disabled', null)}}
{{:helper.link('', 'triangle-1-se', { 'move' : 6 }, data.canburn ? null : 'disabled', null)}}
</div>
<div class='item'>
<span class='white'>Direct control</span>
<br>
{{:helper.link(data.manual_control ? 'Engaged' : 'Disengaged', 'shuffle', { 'manual' : 1 }, null, data.manual_control ? 'selected' : null)}}
</div>
</div>
</fieldset>
</div>
<div style="float:left;width:30%">
<fieldset style="min-height:180px;background-color: #202020;">
<legend style="text-align:center">Autopilot</legend>
<div class='item'>
<div class="itemLabelWide">
Target:
</div>
<div class="itemContent">
{{if data.dest}}
{{:helper.link(data.d_x, null, { 'setx' : 1 }, null, null)}} {{:helper.link(data.d_y, null, { 'sety' : 1 }, null, null)}}
{{else}}
{{:helper.link('None', null, { 'sety' : 1, 'setx' : 1 }, null, null)}}
{{/if}}
</div>
</div>
<div class='item'>
<div class="itemLabelWide">
Speed limit:
</div>
<div class="itemContent">
{{:helper.link(data.speedlimit, null, { 'speedlimit' : 1 }, null, null)}} Gm/h
</div>
</div>
<div class="item">
{{:helper.link(data.autopilot ? 'Engaged' : 'Disengaged', 'gear', { 'apilot' : 1 }, data.dest ? null : 'disabled', data.autopilot ? 'selected' : null)}}
</div>
</fieldset>
</div>
<div class='block' style='clear: both;'>
<h3>Navigation data</h3>
<div class='item'>
<div class="itemLabel">
Location:
</div>
<div class="itemContent">
{{:data.sector}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
Coordinates:
</div>
<div class="itemContent">
{{:data.s_x}} : {{:data.s_y}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
Scan data:
</div>
<div class="itemContent">
{{:data.sector_info}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
Status:
</div>
<div class="itemContent">
{{:data.landed}}
</div>
</div>
<div class='item'>
{{:helper.link('Save current position', 'disk', { 'add' : 'current' }, null)}}
{{:helper.link('Add new entry', 'document', { 'add' : 'new' }, null)}}
</div>
<div class='statusDisplay'>
<table style="width:100%">
<tr><th style="width:40%">Name<th>Coordinates<th>Actions
{{for data.locations}}
<tr class="candystripe"><td>{{:value.name}}
<td>{{:value.x}} : {{:value.y}}
<td>{{:helper.link('Plot course', 'arrowreturnthick-1-e', { 'x' : value.x, 'y' : value.y }, null, null)}}
{{:helper.link('Remove', 'close', { 'remove' : value.reference }, null, null)}}
{{/for}}
</table>
</div>
</div>

View File

@@ -1,59 +0,0 @@
<h3>Navigation</h3>
<div class='block'>
<div class='item'>
<div class="itemContent">
<div class='item'>
<span class='white'>Map view</span>
{{:helper.link(data.viewing ? 'Engaged' : 'Disengaged', 'shuffle', { 'viewing' : 1 }, null, data.viewing ? 'selected' : null)}}
</div>
</div>
</div>
</div>
<div style="float:left;width:50%">
<h3>Sector information</h3>
<div class='block'>
{{:data.sector}}
<br>
<span class='average'>Coordinates:</span> {{:data.s_x}} : {{:data.s_y}}
<br>
<span class='average'>Additional information:</span> {{:data.sector_info}}
</div>
</div>
<div style="float:right;width:50%">
<h3>Flight data</h3>
<div class='block'>
<div class='item'>
<div class="itemLabel">
<span class='average'>ETA to next grid:</span>
</div>
<div style="float:right">
{{:data.ETAnext}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Speed:</span>
</div>
<div style="float:right">
{{:data.speed}} Gm/h
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Acceleration:</span>
</div>
<div style="float:right">
{{:data.accel}} Gm/h
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Heading:</span>
</div>
<div style="float:right">
{{:data.heading}}&deg;
</div>
</div>
</div>
</div>

View File

@@ -1,90 +0,0 @@
<h3>Sensors control console</h3>
<div class='block'>
{{:helper.link(data.on ? 'Switch off' : 'Switch on', 'gear', { 'toggle' : 1 }, data.status != 'MISSING' ? null : 'disabled', data.on ? 'selected' : null)}}
<div class='item'>
<div class="itemLabel">
<span class='white'>Status:</span>
</div>
<div class="itemContent">
{{:data.status}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='white'>Range:</span>
</div>
<div class="itemContent">
{{:helper.link(data.range, null, { 'range' : 1 }, null, null)}}
</div>
</div>
</div>
<div class='block'>
<div class='item'>
<div class="itemLabel">
Integrity:
</div>
<div class="itemContent">
{{if data.health < (data.max_health * 0.25)}}
{{:helper.displayBar(data.health, 0, data.max_health, 'bad')}}
<br><span class="bad">{{:data.health}}/{{:data.max_health}}</span>
{{else data.health < data.max_health *.75}}
{{:helper.displayBar(data.health, 0, data.max_health, 'average')}}
<br><span class="average">{{:data.health}}/{{:data.max_health}}</span>
{{else}}
{{:helper.displayBar(data.health, 0, data.max_health, 'good')}}
<br><span class="good">{{:data.health}}/{{:data.max_health}}</span>
{{/if}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
Temperature:
</div>
<div class="itemContent">
{{if data.heat < (data.critical_heat * 0.5)}}
{{:helper.displayBar(data.heat, 0, data.critical_heat, 'good')}}
{{else data.heat < (data.critical_heat * 0.75)}}
{{:helper.displayBar(data.heat, 0, data.critical_heat, 'average')}}
{{else}}
{{:helper.displayBar(data.heat, 0, data.critical_heat, 'bad')}}
{{/if}}
</div>
<div class="itemContent">
{{if data.heat < (data.critical_heat * 0.5)}}
<span class="good">Temperature low.</span>
{{else data.heat < (data.critical_heat * 0.75)}}
<span class="average">Sensor temperature high!</span>
{{else}}
<span class="bad">TEMPERATURE CRITICAL: Disable or reduce power immediately!</span>
{{/if}}
</div>
</div>
</div>
<div class='item'>
<div class="itemContent">
<div class='item'>
<span class='white'>Sector map view</span>
{{:helper.link(data.viewing ? 'Engaged' : 'Disengaged', 'shuffle', { 'viewing' : 1 }, null, data.viewing ? 'selected' : null)}}
</div>
</div>
</div>
<h4>Sensor contacts</h4>
<div class='block'>
{{if data.contacts}}
<table>
{{for data.contacts}}
<tr>
<div class='item'>
<td>{{:helper.link('Scan', 'search' ,{ 'scan' : value.ref }, null, null)}}</td>
<td><span class='white'>{{:value.name}}</span>, bearing {{:value.bearing}}</td>
</div>
</tr>
{{/for}}
</table>
{{/if}}
</div>
{{if data.status == 'MISSING'}}
<div class='item'>
{{:helper.link('Link up with the sensor suite', 'gear', { 'link' : 1 }, data.status == 'MISSING' ? null : 'disabled', null)}}
</div>
{{/if}}

View File

@@ -0,0 +1,15 @@
import { NtosWindow } from '../layouts';
import { OvermapNavigationContent } from './OvermapNavigation';
export const NtosOvermapNavigation = () => {
return (
<NtosWindow
width={380}
height={530}
resizable>
<NtosWindow.Content scrollable>
<OvermapNavigationContent />
</NtosWindow.Content>
</NtosWindow>
);
};

View File

@@ -0,0 +1,129 @@
import { round } from 'common/math';
import { Fragment } from 'inferno';
import { useBackend, useLocalState } from "../backend";
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section, Table, AnimatedNumber } from "../components";
import { Window } from "../layouts";
import { OvermapPanControls } from './common/Overmap';
export const OvermapDisperser = (props, context) => {
return (
<Window width={400} height={550} resizable>
<Window.Content>
<OvermapDisperserContent />
</Window.Content>
</Window>
);
};
const OvermapDisperserContent = (props, context) => {
const { act, data } = useBackend(context);
const {
faillink,
calibration,
overmapdir,
cal_accuracy,
strength,
range,
next_shot,
nopower,
skill,
chargeload,
} = data;
if (faillink) {
return (
<Section title="Error">
Machine is incomplete, out of range, or misaligned!
</Section>
);
}
return (
<Flex wrap="wrap" spacing={1}>
<Flex.Item basis="22%">
<Section title="Targeting" textAlign="center">
<OvermapPanControls actToDo="choose" selected={val => val === overmapdir} />
</Section>
</Flex.Item>
<Flex.Item basis="74%" grow={1}>
<Section title="Charge">
<LabeledList>
{nopower && (
<LabeledList.Item label="Error">
At least one part of the machine is unpowered.
</LabeledList.Item>
) || null}
<LabeledList.Item label="Charge Load Type">
{chargeload}
</LabeledList.Item>
<LabeledList.Item label="Cooldown">
{next_shot === 0 && (
<Box color="good">Ready</Box>
) || next_shot > 1 && (
<Box color="average">
<AnimatedNumber value={next_shot} /> Seconds
<Box color="bad">Warning: Do not fire during cooldown.</Box>
</Box>
) || null}
</LabeledList.Item>
</LabeledList>
</Section>
</Flex.Item>
<Flex.Item basis="50%" mt={1}>
<Section title="Calibration">
<AnimatedNumber value={cal_accuracy} />%
<Button
ml={1}
icon="exchange-alt"
onClick={() => act("skill_calibration")}>
Pre-Calibration
</Button>
<Box mt={1}>
{calibration.map((cal, i) => (
<Box key={i}>
Cal #{i}:
<Button
ml={1}
icon="random"
onClick={() => act("calibration", { calibration: i })}>
{cal.toString() /* We do this to make the button size correctly at 0 */}
</Button>
</Box>
))}
</Box>
</Section>
</Flex.Item>
<Flex.Item basis="45%" grow={1} mt={1}>
<Section title="Setup">
<LabeledList>
<LabeledList.Item label="Strength">
<Button
fluid
icon="fist-raised"
onClick={() => act("strength")}>
{strength}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Radius">
<Button
fluid
icon="expand-arrows-alt"
onClick={() => act("range")}>
{range}
</Button>
</LabeledList.Item>
</LabeledList>
</Section>
</Flex.Item>
<Flex.Item grow={1} mt={1}>
<Button
fluid
color="red"
icon="bomb"
onClick={() => act("fire")}>
Fire ORB
</Button>
</Flex.Item>
</Flex>
);
};

View File

@@ -0,0 +1,110 @@
import { round } from 'common/math';
import { Fragment } from 'inferno';
import { useBackend } from "../backend";
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section, AnimatedNumber, Collapsible } from "../components";
import { Window } from "../layouts";
export const OvermapEngines = (props, context) => {
const { act, data } = useBackend(context);
const {
global_state, // This indicates all engines being powered up or not
global_limit, // Global Thrust limit
engines_info, // Array of engines
total_thrust, // Total thrust of all engines together
} = data;
return (
<Window width={390} height={530}>
<Window.Content>
<Section title="Status">
<LabeledList>
<LabeledList.Item label="Engines">
<Button
icon="power-off"
selected={global_state}
onClick={() => act("global_toggle")}>
{global_state ? "Shut All Engines Down" : "Start All Engines"}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Volume Limit">
<Button
onClick={() => act("global_limit", { global_limit: -0.1 })}
icon="minus" />
<Button onClick={() => act("set_global_limit")}>
{global_limit}%
</Button>
<Button
onClick={() => act("global_limit", { global_limit: 0.1 })}
icon="plus" />
</LabeledList.Item>
<LabeledList.Item label="Total Thrust">
<AnimatedNumber value={total_thrust} />
</LabeledList.Item>
</LabeledList>
</Section>
<Section title="Engines" height="340px" style={{ "overflow-y": "auto" }}>
{engines_info.map((engine, i) => (
<Flex spacing={1} mt={i !== 0 && -1} key={i}>
<Flex.Item basis="80%">
<Collapsible title={(
<Box inline>
Engine #{i + 1} |
Thrust: <AnimatedNumber value={engine.eng_thrust} /> |
Limit: <AnimatedNumber value={engine.eng_thrust_limiter} format={val => val + "%"} />
</Box>
// "Engine " + (i + 1)
// + " | Thrust: " + engine.eng_thrust
// + " | Limit: " + engine.eng_thrust_limiter + "%"
)}>
<Section width="127%">
<LabeledList>
<LabeledList.Item label="Type">
{engine.eng_type}
</LabeledList.Item>
<LabeledList.Item label="Status">
<Box color={engine.eng_on ? (engine.eng_on === 1 ? "good" : "average") : "bad"}>
{engine.eng_on ? (engine.eng_on === 1 ? "Online" : "Booting") : "Offline"}
</Box>
{engine.eng_status.map(status => {
if (Array.isArray(status)) {
return <Box color={status[1]}>{status[0]}</Box>;
} else {
return <Box>{status}</Box>;
}
})}
</LabeledList.Item>
<LabeledList.Item label="Current Thrust">
{engine.eng_thrust}
</LabeledList.Item>
<LabeledList.Item label="Volume Limit">
<Button
onClick={() => act("limit", { limit: -0.1, engine: engine.eng_reference })}
icon="minus" />
<Button onClick={() => act("set_limit", { engine: engine.eng_reference })}>
{engine.eng_thrust_limiter}%
</Button>
<Button
onClick={() => act("limit", { limit: 0.1, engine: engine.eng_reference })}
icon="plus" />
</LabeledList.Item>
</LabeledList>
</Section>
</Collapsible>
</Flex.Item>
<Flex.Item basis="20%">
<Button
fluid
iconSpin={engine.eng_on === -1}
color={engine.eng_on === -1 ? "purple" : null}
selected={engine.eng_on === 1}
icon="power-off"
onClick={() => act("toggle", { engine: engine.eng_reference })}>
{engine.eng_on ? (engine.eng_on === 1 ? "Shutoff" : "Booting") : "Startup"}
</Button>
</Flex.Item>
</Flex>
))}
</Section>
</Window.Content>
</Window>
);
};

View File

@@ -0,0 +1,235 @@
import { round } from 'common/math';
import { Fragment } from 'inferno';
import { useBackend, useLocalState } from "../backend";
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section, Table } from "../components";
import { Window } from "../layouts";
import { OvermapFlightData, OvermapPanControls } from './common/Overmap';
export const OvermapHelm = (props, context) => {
const { act, data } = useBackend(context);
return (
<Window width={565} height={545} resizable>
<Window.Content>
<Flex>
<Flex.Item basis="40%" height="180px">
<OvermapFlightDataWrap />
</Flex.Item>
<Flex.Item basis="25%" height="180px">
<OvermapManualControl />
</Flex.Item>
<Flex.Item basis="35%" height="180px">
<OvermapAutopilot />
</Flex.Item>
</Flex>
<OvermapNavComputer />
</Window.Content>
</Window>
);
};
export const OvermapFlightDataWrap = (props, context) => {
const { act, data } = useBackend(context);
// While, yes, this is a strange choice to use fieldset over Section
// just look at how pretty the legend is, sticking partially through the border ;///;
return (
<fieldset style={{ height: "100%", border: "1px solid #4972a1", margin: 'none' }} className="Section">
<legend>Flight Data</legend>
<OvermapFlightData />
</fieldset>
);
};
const OvermapManualControl = (props, context) => {
const { act, data } = useBackend(context);
const {
canburn,
manual_control,
} = data;
return (
<fieldset style={{ height: "100%", border: "1px solid #4972a1" }} className="Section">
<legend>Manual Control</legend>
<Flex align="center" justify="center">
<Flex.Item>
<OvermapPanControls disabled={!canburn} actToDo="move" />
</Flex.Item>
</Flex>
<Box textAlign="center" mt={1}>
<Box bold underline>
Direct Control
</Box>
<Button
selected={manual_control}
onClick={() => act("manual")}
icon="compass">
{manual_control ? "Enabled" : "Disabled"}
</Button>
</Box>
</fieldset>
);
};
const OvermapAutopilot = (props, context) => {
const { act, data } = useBackend(context);
const {
dest,
d_x,
d_y,
speedlimit,
autopilot,
autopilot_disabled,
} = data;
if (autopilot_disabled) {
return (
<fieldset style={{ height: "100%", border: "1px solid #4972a1" }} className="Section">
<legend>Autopilot</legend>
<Box textAlign="center" color="bad" fontSize={1.2}>
AUTOPILOT DISABLED
</Box>
<Box textAlign="center" color="average">
Warning: This vessel is equipped with a class I autopilot.
Class I autopilots are unable to do anything but fly in a
straight line directly towards the target, and may result in
collisions.
</Box>
<Box textAlign="center">
<Button.Confirm
mt={1}
color="bad"
content="Unlock Autopilot"
confirmContent="ACCEPT RISKS?"
icon="exclamation-triangle"
confirmIcon="exclamation-triangle"
onClick={() => act("apilot_lock")} />
</Box>
</fieldset>
);
}
return (
<fieldset style={{ height: "100%", border: "1px solid #4972a1" }} className="Section">
<legend>Autopilot</legend>
<LabeledList>
<LabeledList.Item label="Target">
{dest && (
<Fragment>
<Button onClick={() => act("setcoord", { setx: true })}>
{d_x}
</Button>
<Button onClick={() => act("setcoord", { sety: true })}>
{d_y}
</Button>
</Fragment>
) || (
<Button icon="pen" onClick={() => act("setcoord", { setx: true, sety: true })}>
None
</Button>
)}
</LabeledList.Item>
<LabeledList.Item label="Speed Limit">
<Button
icon="tachometer-alt"
onClick={() => act("speedlimit")}>
{speedlimit} Gm/h
</Button>
</LabeledList.Item>
</LabeledList>
<Button
mt={1}
fluid
selected={autopilot}
disabled={!dest}
icon="robot"
onClick={() => act("apilot")}>
{autopilot ? "Engaged" : "Disengaged"}
</Button>
<Button
fluid
color="good"
icon="exclamation-triangle"
onClick={() => act("apilot_lock")}>
Lock Autopilot
</Button>
</fieldset>
);
};
const OvermapNavComputer = (props, context) => {
const { act, data } = useBackend(context);
const {
sector,
s_x,
s_y,
sector_info,
landed,
locations,
} = data;
return (
<Section title="Navigation Data" m={0.3} mt={1}>
<LabeledList>
<LabeledList.Item label="Location">
{sector}
</LabeledList.Item>
<LabeledList.Item label="Coordinates">
{s_x} : {s_y}
</LabeledList.Item>
<LabeledList.Item label="Scan Data">
{sector_info}
</LabeledList.Item>
<LabeledList.Item label="Status">
{landed}
</LabeledList.Item>
</LabeledList>
<Flex mt={1} align="center" justify="center" spacing={1}>
<Flex.Item basis="50%">
<Button
fluid
icon="save"
onClick={() => act("add", { add: "current" })}>
Save Current Position
</Button>
</Flex.Item>
<Flex.Item basis="50%">
<Button
fluid
icon="sticky-note"
onClick={() => act("add", { add: "new" })}>
Add New Entry
</Button>
</Flex.Item>
</Flex>
<Section mt={1} scrollable height="130px">
<Table>
<Table.Row header>
<Table.Cell>Name</Table.Cell>
<Table.Cell>Coordinates</Table.Cell>
<Table.Cell>Actions</Table.Cell>
</Table.Row>
{locations.map(loc => (
<Table.Row key={loc.name}>
<Table.Cell>{loc.name}</Table.Cell>
<Table.Cell>{loc.x} : {loc.y}</Table.Cell>
<Table.Cell collapsing>
<Button
icon="rocket"
onClick={() => act("setds", { x: loc.x, y: loc.y })}>
Plot Course
</Button>
<Button
icon="trash"
onClick={() => act("remove", { remove: loc.reference })}>
Remove
</Button>
</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
</Section>
);
};

View File

@@ -0,0 +1,54 @@
import { round } from 'common/math';
import { Fragment } from 'inferno';
import { useBackend } from "../backend";
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../components";
import { Window } from "../layouts";
import { OvermapFlightData } from "./common/Overmap";
export const OvermapNavigation = (props, context) => {
return (
<Window width={380} height={530} resizable>
<Window.Content>
<OvermapNavigationContent />
</Window.Content>
</Window>
);
};
export const OvermapNavigationContent = (props, context) => {
const { act, data } = useBackend(context);
const {
sector,
s_x,
s_y,
sector_info,
viewing,
} = data;
return (
<Fragment>
<Section title="Current Location" buttons={
<Button
icon="eye"
selected={viewing}
onClick={() => act("viewing")}>
Map View
</Button>
}>
<LabeledList>
<LabeledList.Item label="Current Location">
{sector}
</LabeledList.Item>
<LabeledList.Item label="Coordiantes">
{s_x} : {s_y}
</LabeledList.Item>
<LabeledList.Item label="Additional Information">
{sector_info}
</LabeledList.Item>
</LabeledList>
</Section>
<Section title="Flight Data">
<OvermapFlightData disableLimiterControls />
</Section>
</Fragment>
);
};

View File

@@ -0,0 +1,111 @@
import { round } from 'common/math';
import { Fragment } from 'inferno';
import { useBackend } from "../backend";
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../components";
import { Window } from "../layouts";
export const OvermapShipSensors = (props, context) => {
const { act, data } = useBackend(context);
const {
viewing,
on,
range,
health,
max_health,
heat,
critical_heat,
status,
contacts,
} = data;
return (
<Window width={375} height={545} resizable>
<Window.Content>
<Section title="Status" buttons={(
<Fragment>
<Button
icon="eye"
selected={viewing}
onClick={() => act("viewing")}>
Map View
</Button>
<Button
icon="power-off"
selected={on}
onClick={() => act("toggle")}>
{on ? "Sensors Enabled" : "Sensors Disabled"}
</Button>
</Fragment>
)}>
<LabeledList>
<LabeledList.Item label="Status">
{status}
</LabeledList.Item>
<LabeledList.Item label="Range">
<Button
icon="signal"
onClick={() => act("range")}>
{range}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Integrity">
<ProgressBar
ranges={{
good: [max_health * 0.75, Infinity],
average: [max_health * 0.25, max_health * 0.75],
bad: [-Infinity, max_health * 0.25],
}}
value={health}
maxValue={max_health}>
{health} / {max_health}
</ProgressBar>
</LabeledList.Item>
<LabeledList.Item label="Temperature">
<ProgressBar
ranges={{
bad: [critical_heat * 0.75, Infinity],
average: [critical_heat * 0.5, critical_heat * 0.75],
good: [-Infinity, critical_heat * 0.5],
}}
value={heat}
maxValue={critical_heat}>
{heat < critical_heat * 0.5 && (
<Box>Temperature low.</Box>
) || heat < critical_heat * 0.75 && (
<Box>Sensor temperature high!</Box>
) || (
<Box>TEMPERATURE CRITICAL: Disable or reduce power immediately!</Box>
)}
</ProgressBar>
</LabeledList.Item>
</LabeledList>
</Section>
<Section title="Contacts">
{contacts.length && contacts.map(alien => (
<Button
key={alien.ref}
fluid
icon="search"
onClick={() => act("scan", { scan: alien.ref })}>
<Box bold inline>Scan: {alien.name}</Box>
<Box inline>, bearing: {alien.bearing}&deg;</Box>
</Button>
)) || (
<Box color="average">
No contacts on sensors.
</Box>
)}
</Section>
{data.status === "MISSING" && (
<Section title="Error">
<Button
icon="wifi"
onClick={() => act("link")}>
Link up with sensor suite?
</Button>
</Section>
) || null}
</Window.Content>
</Window>
);
};

View File

@@ -0,0 +1,117 @@
import { round } from 'common/math';
import { Fragment } from 'inferno';
import { useBackend, useLocalState } from "../../backend";
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section, Table } from "../../components";
export const OvermapFlightData = (props, context) => {
const { act, data } = useBackend(context);
const {
disableLimiterControls,
} = props;
const {
ETAnext,
speed,
speed_color,
accel,
heading,
accellimit,
} = data;
// While, yes, this is a strange choice to use fieldset over Section
// just look at how pretty the legend is, sticking partially through the border ;///;
return (
<LabeledList>
<LabeledList.Item label="ETA To Next Grid">
{ETAnext}
</LabeledList.Item>
<LabeledList.Item label="Speed" color={speed_color}>
{speed} Gm/h
</LabeledList.Item>
<LabeledList.Item label="Acceleration">
{accel} Gm/h
</LabeledList.Item>
<LabeledList.Item label="Heading">
{heading}&deg;
</LabeledList.Item>
{!disableLimiterControls && (
<LabeledList.Item label="Acceleration Limiter">
<Button onClick={() => act("accellimit")}>
{accellimit} Gm/h
</Button>
</LabeledList.Item>
) || null}
</LabeledList>
);
};
export const OvermapPanControls = (props, context) => {
const { act } = useBackend(context);
const {
disabled,
actToDo,
selected = val => false,
} = props;
return (
<Fragment>
<Box>
<Button
disabled={disabled}
selected={selected(9)}
onClick={() => act(actToDo, { dir: 9 })}
icon="arrow-up"
iconRotation={-45} />
<Button
disabled={disabled}
selected={selected(1)}
onClick={() => act(actToDo, { dir: 1 })}
icon="arrow-up" />
<Button
disabled={disabled}
selected={selected(5)}
onClick={() => act(actToDo, { dir: 5 })}
icon="arrow-up"
iconRotation={45} />
</Box>
<Box>
<Button
disabled={disabled}
selected={selected(8)}
onClick={() => act(actToDo, { dir: 8 })}
icon="arrow-left" />
<Button
disabled={disabled}
selected={selected(0)}
onClick={() => act("brake")}
icon="ban" />
<Button
disabled={disabled}
selected={selected(4)}
onClick={() => act(actToDo, { dir: 4 })}
icon="arrow-right" />
</Box>
<Box>
<Button
disabled={disabled}
selected={selected(1)}
onClick={() => act(actToDo, { dir: 10 })}
icon="arrow-down"
iconRotation={45} />
<Button
disabled={disabled}
selected={selected(2)}
onClick={() => act(actToDo, { dir: 2 })}
icon="arrow-down" />
<Button
disabled={disabled}
selected={selected(6)}
onClick={() => act(actToDo, { dir: 6 })}
icon="arrow-down"
iconRotation={-45} />
</Box>
</Fragment>
);
};

View File

@@ -2901,7 +2901,6 @@
#include "code\modules\modular_computers\file_system\programs\security\alarm_monitor.dm" #include "code\modules\modular_computers\file_system\programs\security\alarm_monitor.dm"
#include "code\modules\modular_computers\file_system\programs\security\digitalwarrant.dm" #include "code\modules\modular_computers\file_system\programs\security\digitalwarrant.dm"
#include "code\modules\modular_computers\file_system\programs\ships\navigation.dm" #include "code\modules\modular_computers\file_system\programs\ships\navigation.dm"
#include "code\modules\modular_computers\file_system\programs\ships\ship.dm"
#include "code\modules\modular_computers\hardware\_hardware.dm" #include "code\modules\modular_computers\hardware\_hardware.dm"
#include "code\modules\modular_computers\hardware\battery_module.dm" #include "code\modules\modular_computers\hardware\battery_module.dm"
#include "code\modules\modular_computers\hardware\card_slot.dm" #include "code\modules\modular_computers\hardware\card_slot.dm"
@@ -3497,6 +3496,7 @@
#include "code\modules\tgui\modules\atmos_control.dm" #include "code\modules\tgui\modules\atmos_control.dm"
#include "code\modules\tgui\modules\camera.dm" #include "code\modules\tgui\modules\camera.dm"
#include "code\modules\tgui\modules\crew_monitor.dm" #include "code\modules\tgui\modules\crew_monitor.dm"
#include "code\modules\tgui\modules\overmap.dm"
#include "code\modules\tgui\modules\power_monitor.dm" #include "code\modules\tgui\modules\power_monitor.dm"
#include "code\modules\tgui\modules\rcon.dm" #include "code\modules\tgui\modules\rcon.dm"
#include "code\modules\tgui\modules\shutoff_monitor.dm" #include "code\modules\tgui\modules\shutoff_monitor.dm"