Shuttle control panel (rebundled)

This commit is contained in:
Chompstation Bot
2021-02-11 12:40:30 +00:00
committed by Darlantan
parent 83b3f7aef3
commit 37031c2c9b
16 changed files with 823 additions and 239 deletions

View File

@@ -4,9 +4,6 @@
// Also handles initialization and processing of overmap sectors. // Also handles initialization and processing of overmap sectors.
// //
// This global variable exists for legacy support so we don't have to rename every shuttle_controller to SSshuttles yet.
var/global/datum/controller/subsystem/shuttles/shuttle_controller
SUBSYSTEM_DEF(shuttles) SUBSYSTEM_DEF(shuttles)
name = "Shuttles" name = "Shuttles"
wait = 2 SECONDS wait = 2 SECONDS
@@ -35,9 +32,6 @@ SUBSYSTEM_DEF(shuttles)
var/tmp/list/current_run // Shuttles remaining to process this fire() tick var/tmp/list/current_run // Shuttles remaining to process this fire() tick
/datum/controller/subsystem/shuttles/PreInit()
global.shuttle_controller = src // TODO - Remove this! Change everything to point at SSshuttles intead
/datum/controller/subsystem/shuttles/Initialize(timeofday) /datum/controller/subsystem/shuttles/Initialize(timeofday)
last_landmark_registration_time = world.time last_landmark_registration_time = world.time
// Find all declared shuttle datums and initailize them. (Okay, queue them for initialization a few lines further down) // Find all declared shuttle datums and initailize them. (Okay, queue them for initialization a few lines further down)

View File

@@ -60,6 +60,7 @@ var/list/admin_verbs_admin = list(
/client/proc/check_ai_laws, //shows AI and borg laws, /client/proc/check_ai_laws, //shows AI and borg laws,
/client/proc/rename_silicon, //properly renames silicons, /client/proc/rename_silicon, //properly renames silicons,
/client/proc/manage_silicon_laws, // Allows viewing and editing silicon laws. , /client/proc/manage_silicon_laws, // Allows viewing and editing silicon laws. ,
/client/proc/shuttle_panel, // Allows controlling all shuttles remotely.
/client/proc/check_antagonists, /client/proc/check_antagonists,
/client/proc/admin_memo, //admin memo system. show/delete/write. +SERVER needed to delete admin memos of others, /client/proc/admin_memo, //admin memo system. show/delete/write. +SERVER needed to delete admin memos of others,
/client/proc/dsay, //talk in deadchat using our ckey/fakekey, /client/proc/dsay, //talk in deadchat using our ckey/fakekey,
@@ -452,6 +453,7 @@ var/list/admin_verbs_event_manager = list(
/client/proc/check_ai_laws, //shows AI and borg laws, /client/proc/check_ai_laws, //shows AI and borg laws,
/client/proc/rename_silicon, //properly renames silicons, /client/proc/rename_silicon, //properly renames silicons,
/client/proc/manage_silicon_laws, // Allows viewing and editing silicon laws. , /client/proc/manage_silicon_laws, // Allows viewing and editing silicon laws. ,
/client/proc/shuttle_panel, // Allows controlling all shuttles remotely.
/client/proc/check_antagonists, /client/proc/check_antagonists,
/client/proc/admin_memo, //admin memo system. show/delete/write. +SERVER needed to delete admin memos of others, /client/proc/admin_memo, //admin memo system. show/delete/write. +SERVER needed to delete admin memos of others,
/client/proc/dsay, //talk in deadchat using our ckey/fakekey, /client/proc/dsay, //talk in deadchat using our ckey/fakekey,

View File

@@ -437,6 +437,17 @@
set_security_level(sec_level) set_security_level(sec_level)
log_admin("[key_name(usr)] changed the security level to code [sec_level].") log_admin("[key_name(usr)] changed the security level to code [sec_level].")
/client/proc/shuttle_panel()
set name = "Shuttle Control Panel"
set category = "Admin"
if(!check_rights(R_ADMIN | R_EVENT))
return
var/datum/tgui_module/admin_shuttle_controller/A = new(src)
A.tgui_interact(usr)
log_and_message_admins("has opened the shuttle panel.")
feedback_add_details("admin_verb","SHCP")
//---- bs12 verbs ---- //---- bs12 verbs ----
@@ -525,4 +536,4 @@
T.spell_list += new S T.spell_list += new S
feedback_add_details("admin_verb","GS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! feedback_add_details("admin_verb","GS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
log_admin("[key_name(usr)] gave [key_name(T)] the spell [S].") log_admin("[key_name(usr)] gave [key_name(T)] the spell [S].")
message_admins("<font color='blue'>[key_name_admin(usr)] gave [key_name(T)] the spell [S].</font>", 1) message_admins("<font color='blue'>[key_name_admin(usr)] gave [key_name(T)] the spell [S].</font>", 1)

View File

@@ -86,7 +86,7 @@
E.set_thrust_limit(limit) E.set_thrust_limit(limit)
. = TRUE . = TRUE
if("toggle") if("toggle_engine")
var/datum/ship_engine/E = locate(params["engine"]) var/datum/ship_engine/E = locate(params["engine"])
if(istype(E)) if(istype(E))
E.toggle() E.toggle()

View File

@@ -105,7 +105,7 @@
if(nrange) if(nrange)
sensors.set_range(CLAMP(nrange, 1, world.view)) sensors.set_range(CLAMP(nrange, 1, world.view))
. = TRUE . = TRUE
if("toggle") if("toggle_sensor")
sensors.toggle() sensors.toggle()
. = TRUE . = TRUE

View File

@@ -131,14 +131,14 @@
return return
autopilot = TRUE autopilot = TRUE
autopilot_delay = initial(autopilot_delay) autopilot_delay = initial(autopilot_delay)
shuttle_controller.process_shuttles |= src SSshuttles.process_shuttles |= src
if(process_state == IDLE_STATE) if(process_state == IDLE_STATE)
process_state = DO_AUTOPILOT process_state = DO_AUTOPILOT
else else
if(!autopilot) if(!autopilot)
return return
autopilot = FALSE autopilot = FALSE
shuttle_controller.process_shuttles -= src SSshuttles.process_shuttles -= src
if (process_state == DO_AUTOPILOT) if (process_state == DO_AUTOPILOT)
process_state = initial(process_state) process_state = initial(process_state)
@@ -196,7 +196,7 @@
log_shuttle("[my_area] shuttle computer couldn't find [lost] sensor!") log_shuttle("[my_area] shuttle computer couldn't find [lost] sensor!")
/obj/machinery/computer/shuttle_control/web/attackby(obj/I, mob/user) /obj/machinery/computer/shuttle_control/web/attackby(obj/I, mob/user)
var/datum/shuttle/autodock/web_shuttle/shuttle = shuttle_controller.shuttles[shuttle_tag] var/datum/shuttle/autodock/web_shuttle/shuttle = SSshuttles.shuttles[shuttle_tag]
if(shuttle && istype(I,/obj/item/clothing/head/pilot)) if(shuttle && istype(I,/obj/item/clothing/head/pilot))
var/obj/item/clothing/head/pilot/H = I var/obj/item/clothing/head/pilot/H = I
H.shuttle_comp = src H.shuttle_comp = src
@@ -418,7 +418,7 @@
// This is called whenever a shuttle is initialized. If its our shuttle, do our thing! // This is called whenever a shuttle is initialized. If its our shuttle, do our thing!
/obj/shuttle_connector/proc/setup_routes(var/new_shuttle) /obj/shuttle_connector/proc/setup_routes(var/new_shuttle)
var/datum/shuttle/autodock/web_shuttle/ES = shuttle_controller.shuttles[shuttle_name] var/datum/shuttle/autodock/web_shuttle/ES = SSshuttles.shuttles[shuttle_name]
if(ES != new_shuttle) if(ES != new_shuttle)
return // Its not our shuttle! Ignore! return // Its not our shuttle! Ignore!
if(destinations && istype(ES)) if(destinations && istype(ES))

View File

@@ -78,10 +78,10 @@ Code is pretty much ripped verbatim from nano modules, but with un-needed stuff
return TRUE return TRUE
// Just a nice little default interact in case the subtypes don't need any special behavior here // Just a nice little default interact in case the subtypes don't need any special behavior here
/datum/tgui_module/tgui_interact(mob/user, datum/tgui/ui = null) /datum/tgui_module/tgui_interact(mob/user, datum/tgui/ui = null, datum/tgui/parent_ui = null)
ui = SStgui.try_update_ui(user, src, ui) ui = SStgui.try_update_ui(user, src, ui)
if(!ui) if(!ui)
ui = new(user, src, tgui_id, name) ui = new(user, src, tgui_id, name, parent_ui)
ui.open() ui.open()
// This is a helper for anything that wants to render the map. // This is a helper for anything that wants to render the map.

View File

@@ -0,0 +1,102 @@
/* This is an admin tool to control all shuttles, including overmap & classic. */
/datum/tgui_module/admin_shuttle_controller
name = "Admin Shuttle Controller"
tgui_id = "AdminShuttleController"
/datum/tgui_module/admin_shuttle_controller/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = ..()
var/list/shuttles = list()
for(var/shuttle_name in SSshuttles.shuttles)
var/datum/shuttle/S = SSshuttles.shuttles[shuttle_name]
shuttles.Add(list(list(
"name" = shuttle_name,
"ref" = REF(S),
"current_location" = S.get_location_name(),
"status" = S.moving_status,
)))
data["shuttles"] = shuttles
var/list/overmap_ships = list()
for(var/ship in SSshuttles.ships)
var/obj/effect/overmap/visitable/ship/S = ship
overmap_ships.Add(list(list(
"name" = S.scanner_name || S.name,
"ref" = REF(S),
)))
data["overmap_ships"] = overmap_ships
return data
/datum/tgui_module/admin_shuttle_controller/tgui_state(mob/user)
return GLOB.tgui_admin_state
/datum/tgui_module/admin_shuttle_controller/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return
switch(action)
if("adminobserve")
var/datum/shuttle/S = locate(params["ref"])
if(istype(S))
var/client/C = usr.client
if(!isobserver(usr))
C.admin_ghost()
spawn(2)
C.jumptoturf(get_turf(S.current_location))
else if(istype(S, /obj/effect/overmap/visitable))
var/obj/effect/overmap/visitable/V = S
var/client/C = usr.client
if(!isobserver(usr))
C.admin_ghost()
spawn(2)
var/atom/target
if(LAZYLEN(V.generic_waypoints))
target = V.generic_waypoints[1]
else if(LAZYLEN(V.restricted_waypoints))
target = V.restricted_waypoints[1]
else
to_chat(C, "<span class='warning'>Unable to jump to [V].</span>")
return FALSE
var/turf/T = get_turf(target)
if(!istype(T))
to_chat(C, "<span class='warning'>Unable to jump to [V].</span>")
return FALSE
C.jumptoturf(T)
return TRUE
if("classicmove")
var/datum/shuttle/S = locate(params["ref"])
if(istype(S, /datum/shuttle/autodock/multi))
var/datum/shuttle/autodock/multi/shuttle = S
var/dest_key = input("Choose shuttle destination", "Shuttle Destination") as null|anything in shuttle.get_destinations()
if(dest_key)
shuttle.set_destination(dest_key, usr)
shuttle.launch(src)
else if(istype(S, /datum/shuttle/autodock/overmap))
var/datum/shuttle/autodock/overmap/shuttle = S
var/list/possible_d = shuttle.get_possible_destinations()
var/D
if(!LAZYLEN(possible_d))
to_chat(usr, "<span class='warning'>There are no possible destinations for [shuttle] ([shuttle.type])</span>")
return FALSE
D = input("Choose shuttle destination", "Shuttle Destination") as null|anything in possible_d
if(D)
shuttle.set_destination(possible_d[D])
shuttle.launch()
else if(istype(S, /datum/shuttle/autodock))
var/datum/shuttle/autodock/shuttle = S
if(alert(usr, "Are you sure you want to launch [shuttle]?", "Launching Shuttle", "Yes", "No") == "Yes")
shuttle.launch(src)
else
to_chat(usr, "<span class='notice'>The shuttle control panel isn't quite sure how to move [S] ([S?.type]).</span>")
return FALSE
to_chat(usr, "<span class='notice'>Launching shuttle [S].</span>")
return TRUE
if("overmap_control")
var/obj/effect/overmap/visitable/ship/V = locate(params["ref"])
if(istype(V))
var/datum/tgui_module/ship/fullmonty/F = new(src, V)
F.tgui_interact(usr, null, ui)
return TRUE

View File

@@ -52,7 +52,7 @@
/datum/tgui_module/ship/proc/look(var/mob/user) /datum/tgui_module/ship/proc/look(var/mob/user)
if(linked) if(linked)
user.set_machine(tgui_host()) user.set_machine(src)
user.reset_view(linked) user.reset_view(linked)
user.set_viewsize(world.view + extra_view) user.set_viewsize(world.view + extra_view)
GLOB.moved_event.register(user, src, /datum/tgui_module/ship/proc/unlook) GLOB.moved_event.register(user, src, /datum/tgui_module/ship/proc/unlook)
@@ -134,4 +134,327 @@
return TRUE return TRUE
/datum/tgui_module/ship/nav/ntos /datum/tgui_module/ship/nav/ntos
ntos = TRUE ntos = TRUE
// Full monty control computer
/datum/tgui_module/ship/fullmonty
name = "Full Monty Overmap Control"
tgui_id = "OvermapFull"
// HELM
var/autopilot = 0
var/autopilot_disabled = TRUE
var/list/known_sectors = list()
var/dx //desitnation
var/dy //coordinates
var/speedlimit = 1/(20 SECONDS) //top speed for autopilot, 5
var/accellimit = 0.001 //manual limiter for acceleration
// SENSORS
var/obj/machinery/shipsensors/sensors
/datum/tgui_module/ship/fullmonty/tgui_state(mob/user)
return GLOB.tgui_admin_state
/datum/tgui_module/ship/fullmonty/New(host, obj/effect/overmap/visitable/ship/new_linked)
. = ..()
if(!istype(new_linked))
CRASH("Warning, [new_linked] is not an overmap ship! Something went horribly wrong for [usr]!")
return
linked = new_linked
name = initial(name) + " ([linked.name])"
// HELM
var/area/overmap/map = locate() in world
for(var/obj/effect/overmap/visitable/sector/S in map)
if(S.known)
var/datum/computer_file/data/waypoint/R = new()
R.fields["name"] = S.name
R.fields["x"] = S.x
R.fields["y"] = S.y
known_sectors[S.name] = R
// SENSORS
for(var/obj/machinery/shipsensors/S in global.machines)
if(linked.check_ownership(S))
sensors = S
break
/datum/tgui_module/ship/fullmonty/relaymove(var/mob/user, direction)
if(viewing_overmap(user) && linked)
direction = turn(direction,pick(90,-90))
linked.relaymove(user, direction, accellimit)
return 1
return ..()
// Beware ye eyes. This holds all of the data from helm, engine, and sensor control all at once.
/datum/tgui_module/ship/fullmonty/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = ..()
// HELM
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
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
// ENGINES
data["global_state"] = linked.engines_state
data["global_limit"] = round(linked.thrust_limit*100)
var/total_thrust = 0
var/list/enginfo = list()
for(var/datum/ship_engine/E in linked.engines)
var/list/rdata = list()
rdata["eng_type"] = E.name
rdata["eng_on"] = E.is_on()
rdata["eng_thrust"] = E.get_thrust()
rdata["eng_thrust_limiter"] = round(E.get_thrust_limit()*100)
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]"
total_thrust += E.get_thrust()
enginfo.Add(list(rdata))
data["engines_info"] = enginfo
data["total_thrust"] = total_thrust
// SENSORS
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)
data["on"] = sensors.use_power
data["range"] = sensors.range
data["health"] = sensors.health
data["max_health"] = sensors.max_health
data["heat"] = sensors.heat
data["critical_heat"] = sensors.critical_heat
if(sensors.health == 0)
data["status"] = "DESTROYED"
else if(!sensors.powered())
data["status"] = "NO POWER"
else if(!sensors.in_vacuum())
data["status"] = "VACUUM SEAL BROKEN"
else
data["status"] = "OK"
var/list/contacts = list()
for(var/obj/effect/overmap/O in view(7,linked))
if(linked == O)
continue
if(!O.scannable)
continue
var/bearing = round(90 - ATAN2(O.x - linked.x, O.y - linked.y),5)
if(bearing < 0)
bearing += 360
contacts.Add(list(list("name"=O.name, "ref"="\ref[O]", "bearing"=bearing)))
data["contacts"] = contacts
return data
// Beware ye eyes. This holds all of the ACTIONS from helm, engine, and sensor control all at once.
/datum/tgui_module/ship/fullmonty/tgui_act(action, params)
if(..())
return TRUE
switch(action)
/* HELM */
if("add")
var/datum/computer_file/data/waypoint/R = new()
var/sec_name = input("Input navigation entry name", "New navigation entry", "Sector #[known_sectors.len]") as text
if(!sec_name)
sec_name = "Sector #[known_sectors.len]"
R.fields["name"] = sec_name
if(sec_name in known_sectors)
to_chat(usr, "<span class='warning'>Sector with that name already exists, please input a different name.</span>")
return TRUE
switch(params["add"])
if("current")
R.fields["x"] = linked.x
R.fields["y"] = linked.y
if("new")
var/newx = input("Input new entry x coordinate", "Coordinate input", linked.x) as num
var/newy = input("Input new entry y coordinate", "Coordinate input", linked.y) as num
R.fields["x"] = CLAMP(newx, 1, world.maxx)
R.fields["y"] = CLAMP(newy, 1, world.maxy)
known_sectors[sec_name] = R
. = TRUE
if("remove")
var/datum/computer_file/data/waypoint/R = locate(params["remove"])
if(R)
known_sectors.Remove(R.fields["name"])
qdel(R)
. = TRUE
if("setcoord")
if(params["setx"])
var/newx = input("Input new destiniation x coordinate", "Coordinate input", dx) as num|null
if(newx)
dx = CLAMP(newx, 1, world.maxx)
if(params["sety"])
var/newy = input("Input new destiniation y coordinate", "Coordinate input", dy) as num|null
if(newy)
dy = CLAMP(newy, 1, world.maxy)
. = TRUE
if("setds")
dx = text2num(params["x"])
dy = text2num(params["y"])
. = TRUE
if("reset")
dx = 0
dy = 0
. = TRUE
if("speedlimit")
var/newlimit = input("Input new speed limit for autopilot (0 to brake)", "Autopilot speed limit", speedlimit*1000) as num|null
if(newlimit)
speedlimit = CLAMP(newlimit/1000, 0, 100)
. = TRUE
if("accellimit")
var/newlimit = input("Input new acceleration limit", "Acceleration limit", accellimit*1000) as num|null
if(newlimit)
accellimit = max(newlimit/1000, 0)
. = TRUE
if("move")
var/ndir = text2num(params["dir"])
ndir = turn(ndir,pick(90,-90))
linked.relaymove(usr, ndir, accellimit)
. = TRUE
if("brake")
linked.decelerate()
. = TRUE
if("apilot")
if(autopilot_disabled)
autopilot = FALSE
else
autopilot = !autopilot
. = TRUE
if("apilot_lock")
autopilot_disabled = !autopilot_disabled
autopilot = FALSE
. = TRUE
if("manual")
viewing_overmap(usr) ? unlook(usr) : look(usr)
. = TRUE
/* END HELM */
/* ENGINES */
if("global_toggle")
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("set_global_limit")
var/newlim = input("Input new thrust limit (0..100%)", "Thrust limit", linked.thrust_limit*100) as num
linked.thrust_limit = clamp(newlim/100, 0, 1)
for(var/datum/ship_engine/E in linked.engines)
E.set_thrust_limit(linked.thrust_limit)
. = TRUE
if("global_limit")
linked.thrust_limit = clamp(linked.thrust_limit + text2num(params["global_limit"]), 0, 1)
for(var/datum/ship_engine/E in linked.engines)
E.set_thrust_limit(linked.thrust_limit)
. = TRUE
if("set_limit")
var/datum/ship_engine/E = locate(params["engine"])
var/newlim = input("Input new thrust limit (0..100)", "Thrust limit", E.get_thrust_limit()) as num
var/limit = clamp(newlim/100, 0, 1)
if(istype(E))
E.set_thrust_limit(limit)
. = TRUE
if("limit")
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_engine")
var/datum/ship_engine/E = locate(params["engine"])
if(istype(E))
E.toggle()
. = TRUE
/* END ENGINES */
/* SENSORS */
if("range")
var/nrange = input("Set new sensors range", "Sensor range", sensors.range) as num|null
if(nrange)
sensors.set_range(CLAMP(nrange, 1, world.view))
. = TRUE
if("toggle_sensor")
sensors.toggle()
. = TRUE
if("viewing")
if(usr && !isAI(usr))
viewing_overmap(usr) ? unlook(usr) : look(usr)
. = TRUE
/* END SENSORS */
// We don't want these to do anything.
/datum/tgui_module/ship/fullmonty/sync_linked()
return
/datum/tgui_module/ship/fullmonty/attempt_hook_up_recursive()
return
/datum/tgui_module/ship/fullmonty/attempt_hook_up()
return

View File

@@ -0,0 +1,89 @@
import { sortBy } from 'common/collections';
import { Fragment } from 'inferno';
import { useBackend } from "../backend";
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section, Table } from "../components";
import { Window } from "../layouts";
export const AdminShuttleController = (props, context) => {
const { act, data } = useBackend(context);
return (
<Window width={600} height={600} resizable>
<Window.Content scrollable>
<ShuttleList />
</Window.Content>
</Window>
);
};
export const ShuttleList = (props, context) => {
const { act, data } = useBackend(context);
const {
shuttles,
overmap_ships,
} = data;
return (
<Section noTopPadding>
<Section title="Classic Shuttles" level={2}>
<Table>
{sortBy(f => f.name)(shuttles).map(shuttle => (
<Table.Row key={shuttle.ref}>
<Table.Cell collapsing>
<Button
m={0}
content="JMP"
onClick={() => act("adminobserve", { ref: shuttle.ref })} />
</Table.Cell>
<Table.Cell collapsing>
<Button
m={0}
content="Fly"
onClick={() => act("classicmove", { ref: shuttle.ref })} />
</Table.Cell>
<Table.Cell>{shuttle.name}</Table.Cell>
<Table.Cell>{shuttle.current_location}</Table.Cell>
<Table.Cell>{shuttleStatusToWords(shuttle.status)}</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
<Section title="Overmap Ships" level={2}>
<Table>
{sortBy(f => f.name?.toLowerCase() || f.name || f.ref)(overmap_ships).map(ship => (
<Table.Row key={ship.ref}>
<Table.Cell collapsing>
<Button
content="JMP"
onClick={() => act("adminobserve", { ref: ship.ref })} />
</Table.Cell>
<Table.Cell collapsing>
<Button
content="Control"
onClick={() => act("overmap_control", { ref: ship.ref })} />
</Table.Cell>
<Table.Cell>
{ship.name}
</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
</Section>
);
};
/* Helpers */
const shuttleStatusToWords = status => {
switch (status) {
case 0:
return "Idle";
case 1:
return "Warmup";
case 2:
return "Transit";
default:
return "UNK";
}
};

View File

@@ -5,6 +5,16 @@ import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section, AnimatedNum
import { Window } from "../layouts"; import { Window } from "../layouts";
export const OvermapEngines = (props, context) => { export const OvermapEngines = (props, context) => {
return (
<Window width={390} height={530}>
<Window.Content>
<OvermapEnginesContent />
</Window.Content>
</Window>
);
};
export const OvermapEnginesContent = (props, context) => {
const { act, data } = useBackend(context); const { act, data } = useBackend(context);
const { const {
global_state, // This indicates all engines being powered up or not global_state, // This indicates all engines being powered up or not
@@ -13,98 +23,96 @@ export const OvermapEngines = (props, context) => {
total_thrust, // Total thrust of all engines together total_thrust, // Total thrust of all engines together
} = data; } = data;
return ( return (
<Window width={390} height={530}> <Fragment>
<Window.Content> <Section title="Status">
<Section title="Status"> <LabeledList>
<LabeledList> <LabeledList.Item label="Engines">
<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 <Button
fluid
iconSpin={engine.eng_on === -1}
color={engine.eng_on === -1 ? "purple" : null}
selected={engine.eng_on === 1}
icon="power-off" icon="power-off"
selected={global_state} onClick={() => act("toggle_engine", { engine: engine.eng_reference })}>
onClick={() => act("global_toggle")}> {engine.eng_on ? (engine.eng_on === 1 ? "Shutoff" : "Booting") : "Startup"}
{global_state ? "Shut All Engines Down" : "Start All Engines"}
</Button> </Button>
</LabeledList.Item> </Flex.Item>
<LabeledList.Item label="Volume Limit"> </Flex>
<Button ))}
onClick={() => act("global_limit", { global_limit: -0.1 })} </Section>
icon="minus" /> </Fragment>
<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,39 @@
import { round } from 'common/math';
import { Fragment } from 'inferno';
import { useBackend, useLocalState } from "../backend";
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section, Table, AnimatedNumber, Tabs } from "../components";
import { Window } from "../layouts";
import { OvermapEnginesContent } from './OvermapEngines';
import { OvermapHelmContent } from './OvermapHelm';
import { OvermapShipSensorsContent } from './OvermapShipSensors';
export const OvermapFull = (props, context) => {
const [tab, setTab] = useLocalState(context, 'overmapFullState', 0);
return (
<Window width={800} height={800} resizable>
<Window.Content scrollable>
<Tabs>
<Tabs.Tab
selected={tab === 0}
onClick={() => setTab(0)}>
Engines
</Tabs.Tab>
<Tabs.Tab
selected={tab === 1}
onClick={() => setTab(1)}>
Helm
</Tabs.Tab>
<Tabs.Tab
selected={tab === 2}
onClick={() => setTab(2)}>
Sensors
</Tabs.Tab>
</Tabs>
{tab === 0 && <OvermapEnginesContent />}
{tab === 1 && <OvermapHelmContent />}
{tab === 2 && <OvermapShipSensorsContent />}
</Window.Content>
</Window>
);
};

View File

@@ -6,27 +6,34 @@ import { Window } from "../layouts";
import { OvermapFlightData, OvermapPanControls } from './common/Overmap'; import { OvermapFlightData, OvermapPanControls } from './common/Overmap';
export const OvermapHelm = (props, context) => { export const OvermapHelm = (props, context) => {
const { act, data } = useBackend(context);
return ( return (
<Window width={565} height={545} resizable> <Window width={565} height={545} resizable>
<Window.Content> <Window.Content>
<Flex> <OvermapHelmContent />
<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.Content>
</Window> </Window>
); );
}; };
export const OvermapHelmContent = (props, context) => {
return (
<Fragment>
<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 />
</Fragment>
);
};
export const OvermapFlightDataWrap = (props, context) => { export const OvermapFlightDataWrap = (props, context) => {
const { act, data } = useBackend(context); const { act, data } = useBackend(context);

View File

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

File diff suppressed because one or more lines are too long

View File

@@ -3871,6 +3871,7 @@
#include "code\modules\tgui\tgui.dm" #include "code\modules\tgui\tgui.dm"
#include "code\modules\tgui\tgui_window.dm" #include "code\modules\tgui\tgui_window.dm"
#include "code\modules\tgui\modules\_base.dm" #include "code\modules\tgui\modules\_base.dm"
#include "code\modules\tgui\modules\admin_shuttle_controller.dm"
#include "code\modules\tgui\modules\agentcard.dm" #include "code\modules\tgui\modules\agentcard.dm"
#include "code\modules\tgui\modules\alarm.dm" #include "code\modules\tgui\modules\alarm.dm"
#include "code\modules\tgui\modules\appearance_changer.dm" #include "code\modules\tgui\modules\appearance_changer.dm"