diff --git a/code/_helpers/maths.dm b/code/_helpers/maths.dm index 416fcaf1ac3..a873997afef 100644 --- a/code/_helpers/maths.dm +++ b/code/_helpers/maths.dm @@ -225,3 +225,19 @@ line += locate(current_x_step, current_y_step, starting_z) return line + + +/// Returns the distance between two points +#define DIST_BETWEEN_TWO_POINTS(ax, ay, bx, by) (sqrt((bx-ax)*(bx-ax))+((by-ay)*(by-ay))) + +/** + * Returns bearing of object relative to observer (0-360) + * a is the observer, b is the other object + * + * observer_x - Observer's X coordinate + * observer_y - Observer's Y coordinate + * target_x - Target's X coordinate + * target_y - Target's Y coordinate + */ +#define BEARING_RELATIVE(observer_x, observer_y, target_x, target_y) (90 - Atan2(target_x - observer_x, target_y - observer_y)) + diff --git a/code/modules/overmap/ships/computers/helm.dm b/code/modules/overmap/ships/computers/helm.dm index bd4be0a028d..63ffbab4144 100644 --- a/code/modules/overmap/ships/computers/helm.dm +++ b/code/modules/overmap/ships/computers/helm.dm @@ -175,22 +175,22 @@ /obj/machinery/computer/ship/helm/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return TOPIC_HANDLED + return TRUE if(!connected) - return TOPIC_HANDLED + return TRUE if(action == "add") var/datum/computer_file/data/waypoint/R = new() var/sec_name = input("Input naviation entry name", "New navigation entry", "Sector #[known_sectors.len]") as text if(!CanInteract(usr, physical_state)) - return TOPIC_NOACTION + return FALSE if(!sec_name) sec_name = "Sector #[known_sectors.len]" R.fields["name"] = sec_name if(sec_name in known_sectors) to_chat(usr, "Sector with that name already exists, please input a different name.") - return TOPIC_REFRESH + return TRUE switch(params["add"]) if("current") R.fields["x"] = connected.x @@ -198,10 +198,10 @@ if("new") var/newx = input("Input new entry x coordinate", "Coordinate input", connected.x) as num if(!CanInteract(usr, physical_state)) - return TOPIC_REFRESH + return TRUE var/newy = input("Input new entry y coordinate", "Coordinate input", connected.y) as num if(!CanInteract(usr, physical_state)) - return TOPIC_NOACTION + return FALSE R.fields["x"] = Clamp(newx, 1, world.maxx) R.fields["y"] = Clamp(newy, 1, world.maxy) known_sectors[sec_name] = R @@ -291,7 +291,7 @@ check_processing() else to_chat(usr, SPAN_WARNING("Your software does not allow you to interact with the piloting controls.")) - return TOPIC_HANDLED + return TRUE add_fingerprint(usr) updateUsrDialog() diff --git a/code/modules/overmap/ships/computers/sensors.dm b/code/modules/overmap/ships/computers/sensors.dm index f33968300ff..d7ae897fc12 100644 --- a/code/modules/overmap/ships/computers/sensors.dm +++ b/code/modules/overmap/ships/computers/sensors.dm @@ -68,10 +68,13 @@ else if(sound_token) QDEL_NULL(sound_token) -/obj/machinery/computer/ship/sensors/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - if(!linked) - display_reconnect_dialog(user, "sensors") - return +/obj/machinery/computer/ship/sensors/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Sensors", capitalize_first_letters(name)) + ui.open() + +/obj/machinery/computer/ship/sensors/ui_data(mob/user) simple_asset_ensure_is_sent(user, /datum/asset/simple/paper) @@ -79,6 +82,20 @@ data["viewing"] = viewing_overmap(user) data["muted"] = muted + + data["grid_x"] = linked.x + data["grid_y"] = linked.y + data["direction"] = dir2angle(linked.dir) + var/linked_x = linked.x + var/linked_y = linked.y + var/obj/effect/overmap/visitable/ship/linked_ship = linked + if(istype(linked_ship)) + linked_x += linked_ship.position[1] / 2.0 + linked_y += linked_ship.position[2] / 2.0 + data["is_ship"] = TRUE + data["x"] = linked_x + data["y"] = linked_y + if(sensors) data["on"] = sensors.use_power data["range"] = sensors.range @@ -128,17 +145,41 @@ for(var/obj/effect/overmap/visitable/identified_contact in contact_datums) potential_contacts |= identified_contact - for(var/obj/effect/overmap/O in potential_contacts) - if(linked == O) + for(var/obj/effect/overmap/contact in potential_contacts) + if(linked == contact) continue - if(!O.scannable) + if(!contact.scannable) continue - var/bearing = round(90 - Atan2(O.x - linked.x, O.y - linked.y),5) + + var/obj/effect/overmap/visitable/ship/landable/contact_landable = contact + var/landed = (istype(contact_landable) && contact_landable.status == SHIP_STATUS_LANDED) + + var/contact_x = contact.x + var/contact_y = contact.y + + var/obj/effect/overmap/visitable/ship/contact_ship = contact + if(istype(contact_ship)) + contact_x += contact_ship.position[1] / 2.0 + contact_y += contact_ship.position[2] / 2.0 + + var/bearing = round(BEARING_RELATIVE(linked_x, linked_y, contact_x, contact_y),5) if(bearing < 0) bearing += 360 - contacts.Add(list(list("name"=O.name, "ref"="\ref[O]", "bearing"=bearing, "can_datalink"=(!(O in connected.datalinked))))) - if(length(contacts)) - data["contacts"] = contacts + + var/distance = DIST_BETWEEN_TWO_POINTS(linked_x, linked_y, contact_x, contact_y) + + contacts.Add(list(list( + "name"=contact.name, + "ref"="\ref[contact]", + "bearing"=bearing, + "can_datalink"=(!(contact in connected.datalinked)), + "distance"=distance, + "landed"=landed, + "x"=contact_x, + "y"=contact_y + ))) + + data["contacts"] = contacts // Add datalink requests if(length(connected.datalink_requests)) @@ -176,58 +217,53 @@ else data["id_status"] = "NOBEACON" //Should not really happen. - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "shipsensors.tmpl", "[linked.get_real_name()] Sensors Control", 600, 530, src) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data -/obj/machinery/computer/ship/sensors/Topic(href, href_list) +/obj/machinery/computer/ship/sensors/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if (..()) - return TOPIC_HANDLED + return TRUE if (!linked) - return TOPIC_NOACTION + return FALSE - if (href_list["viewing"]) + if (action == "viewing") if(usr) viewing_overmap(usr) ? unlook(usr) : look(usr) - return TOPIC_REFRESH + return TRUE - if (href_list["link"]) + if (action == "link") find_sensors_and_iff() - return TOPIC_REFRESH + return TRUE if(sensors) - if (href_list["range"]) + if (action == "range") var/nrange = input("Set new sensors range", "Sensor range", sensors.range) as num|null if(!CanInteract(usr, default_state)) - return TOPIC_NOACTION + return FALSE if (nrange) sensors.set_desired_range(Clamp(nrange, 1, sensors.max_range)) - return TOPIC_REFRESH - if(href_list["range_choice"]) - var/nrange = text2num(href_list["range_choice"]) + return TRUE + if(action == "range_choice") + var/nrange = text2num(params["range_choice"]) if(!CanInteract(usr, default_state)) - return TOPIC_NOACTION + return FALSE if(nrange) sensors.set_desired_range(Clamp(nrange, 1, sensors.max_range)) - return TOPIC_REFRESH - if (href_list["toggle"]) + return TRUE + if (action == "toggle") sensors.toggle() - return TOPIC_REFRESH + return TRUE - if(href_list["deep_scan_toggle"]) + if(action == "deep_scan_toggle") sensors.deep_scan_toggled = !sensors.deep_scan_toggled - return TOPIC_REFRESH + return TRUE if(identification) - if(href_list["toggle_id"]) + if(action == "toggle_id") identification.toggle() - return TOPIC_REFRESH + return TRUE - if(href_list["change_ship_class"]) + if(action == "change_ship_class") if(!identification.use_power) to_chat(usr, SPAN_WARNING("You cannot do this while the IFF is off!")) return @@ -241,9 +277,9 @@ linked.set_new_class(new_class) playsound(src, 'sound/machines/twobeep.ogg', 50) visible_message(SPAN_NOTICE("\The [src] beeps, \"IFF change to ship class registered.\"")) - return TOPIC_REFRESH + return TRUE - if(href_list["change_ship_name"]) + if(action == "change_ship_name") if(!identification.use_power) to_chat(usr, SPAN_WARNING("You cannot do this while the IFF is off!")) return @@ -257,20 +293,20 @@ linked.set_new_designation(new_name) playsound(src, 'sound/machines/twobeep.ogg', 50) visible_message(SPAN_NOTICE("\The [src] beeps, \"IFF change to ship designation registered.\"")) - return TOPIC_REFRESH + return TRUE - if (href_list["scan-action"]) - switch(href_list["scan-action"]) + if (action == "scan_action") + switch(params["scan_action"]) if("clear") contact_details = null if("print") if(contact_details) playsound(loc, "sound/machines/dotprinter.ogg", 30, 1) new/obj/item/paper/(get_turf(src), contact_details, "paper (Sensor Scan - [contact_name])") - return TOPIC_HANDLED + return TRUE - if (href_list["scan"]) - var/obj/effect/overmap/O = locate(href_list["scan"]) + if (action == "scan") + var/obj/effect/overmap/O = locate(params["scan"]) if(istype(O) && !QDELETED(O)) if((O in view(7,linked))|| (O in contact_datums)) playsound(loc, "sound/machines/dotprinter.ogg", 30, 1) @@ -280,37 +316,37 @@ to_chat(usr, SPAN_NOTICE("Successfully scanned [O].")) contact_name = O.name contact_details = O.get_scan_data(usr) - return TOPIC_HANDLED + return TRUE - if (href_list["request_datalink"]) - var/obj/effect/overmap/visitable/O = locate(href_list["request_datalink"]) + if (action == "request_datalink") + var/obj/effect/overmap/visitable/O = locate(params["request_datalink"]) if(istype(O) && !QDELETED(O)) if((O in view(7,linked)) || (O in contact_datums)) for(var/obj/machinery/computer/ship/sensors/sensor_console in O.consoles) sensor_console.connected.datalink_requests |= src.connected - return TOPIC_HANDLED + return TRUE - if (href_list["accept_datalink_requests"]) - var/obj/effect/overmap/visitable/O = locate(href_list["accept_datalink_requests"]) + if (action == "accept_datalink_requests") + var/obj/effect/overmap/visitable/O = locate(params["accept_datalink_requests"]) for(var/obj/machinery/computer/ship/sensors/sensor_console in src.connected.consoles) sensor_console.datalink_add_ship_datalink(O) break src.connected.datalink_requests -= O // Remove the request - return TOPIC_HANDLED + return TRUE - if (href_list["decline_datalink_requests"]) - var/obj/effect/overmap/visitable/O = locate(href_list["decline_datalink_requests"]) + if (action == "decline_datalink_requests") + var/obj/effect/overmap/visitable/O = locate(params["decline_datalink_requests"]) src.connected.datalink_requests -= O // Remove the request - if (href_list["remove_datalink"]) - var/obj/effect/overmap/visitable/O = locate(href_list["remove_datalink"]) + if (action == "remove_datalink") + var/obj/effect/overmap/visitable/O = locate(params["remove_datalink"]) for(var/obj/machinery/computer/ship/sensors/rescinder_sensor_console in src.connected.consoles) // Get sensor console from the rescinder rescinder_sensor_console.datalink_remove_ship_datalink(O, TRUE) - return TOPIC_HANDLED + return TRUE - if (href_list["play_message"]) - var/caller = href_list["play_message"] + if (action == "play_message") + var/caller = params["play_message"] var/datum/distress_beacon/beacon = SSdistress.active_distress_beacons[caller] var/mob/living/carbon/human/sender = beacon.user var/user_name = beacon.user_name @@ -318,15 +354,15 @@ visible_message(SPAN_NOTICE("\The [src] beeps a few times as it replays the distress message.")) playsound(src, 'sound/machines/compbeep5.ogg') visible_message(SPAN_ITALIC("[accent_icon] [user_name] explains, \"[beacon.distress_message]\"")) - return TOPIC_HANDLED + return TRUE - if(href_list["inbound_fire"]) - var/direction = href_list["inbound_fire"] + if(action == "inbound_fire") + var/direction = params["inbound_fire"] if(direction != "clear") security_announcement.Announce("Enemy fire inbound, enemy fire inbound! [sanitizeSafe(direction)]!", "Brace for shock!", sound('sound/mecha/internaldmgalarm.ogg', volume = 90), 0) else security_announcement.Announce("No fire is incoming at the current moment, resume damage control.", "Space clear!", sound('sound/misc/announcements/security_level_old.ogg'), 0) - return TOPIC_HANDLED + return TRUE /obj/machinery/shipsensors name = "sensors suite" diff --git a/html/changelogs/DreamySkrell-sensors-tgui.yml b/html/changelogs/DreamySkrell-sensors-tgui.yml new file mode 100644 index 00000000000..3d96718bd62 --- /dev/null +++ b/html/changelogs/DreamySkrell-sensors-tgui.yml @@ -0,0 +1,42 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +# balance +# admin +# backend +# security +# refactor +################################# + +# Your name. +author: DreamySkrell + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - refactor: "Rewrites sensors from nanoui to tgui." + - rscadd: "Adds sensor contacts compass to sensors console." diff --git a/nano/templates/shipsensors.tmpl b/nano/templates/shipsensors.tmpl deleted file mode 100644 index bd080ab0e2e..00000000000 --- a/nano/templates/shipsensors.tmpl +++ /dev/null @@ -1,219 +0,0 @@ -

Sensor Array Control Console

-
- {{:helper.link(data.on ? 'Switch Off' : 'Switch On', 'gear', { 'toggle' : 1 }, data.status != 'MISSING' ? null : 'disabled', data.on ? 'selected' : null)}} -
-
- Status: -
-
- {{:data.status}} -
-
-
-
- Range: -
-
- {{for data.range_choices}} - {{:helper.link(value, null, { 'range_choice' : value }, null, ( value==data.range ? 'selected' : ( value==data.desired_range ? 'disabled' : null ) ) )}} - {{/for}} -
-
- {{if data.deep_scan_range > 0}} -
-
- {{:data.deep_scan_name}} -
-
- Effective Range: {{:data.deep_scan_range}} - {{:helper.link(data.deep_scan_toggled ? 'Deactivate' : 'Activate', 'gear', {'deep_scan_toggle' : 1}, data.status != 'MISSING' ? null : 'disabled', data.deep_scan_toggled ? 'selected' : null)}} -
-
- {{/if}} -
-
-
-
- Integrity: -
-
- {{if data.health < (data.max_health * 0.25)}} - {{:helper.displayBar(data.health, 0, data.max_health, 'bad')}} -
{{:data.health}}/{{:data.max_health}} - {{else data.health < data.max_health *.75}} - {{:helper.displayBar(data.health, 0, data.max_health, 'average')}} -
{{:data.health}}/{{:data.max_health}} - {{else}} - {{:helper.displayBar(data.health, 0, data.max_health, 'good')}} -
{{:data.health}}/{{:data.max_health}} - {{/if}} -
-
-
-
- Temperature: -
-
- {{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}} -
-
- {{if data.heat < (data.critical_heat * 0.5)}} - Temperature low. - {{else data.heat < (data.critical_heat * 0.75)}} - Sensor temperature high! - {{else}} - TEMPERATURE CRITICAL: Disable or reduce power immediately! - {{/if}} -
-
-
-
-
-
- Sector map view - {{:helper.link(data.viewing ? 'Engaged' : 'Disengaged', 'shuffle', { 'viewing' : 1 }, null, data.viewing ? 'selected' : null)}} -
-
-
-

IFF Management

-
- {{:helper.link(data.id_on ? 'Switch off' : 'Switch on', 'gear', { 'toggle_id' : 1 }, data.id_status != 'NOBEACON' ? null : 'disabled', data.id_on ? 'selected' : null)}} -
-
- Status: -
-
- {{:data.id_status}} -
-
-
-
- Class: -
-
- {{if data.can_change_class}} - {{:helper.link(data.id_class, 'gear', { 'change_ship_class' : 1 })}} - {{else}} - {{:data.id_class}} - {{/if}} -
-
-
- Designation: -
-
- {{if data.can_change_name}} - {{:helper.link(data.id_name, 'gear', { 'change_ship_name' : 1 })}} - {{else}} - {{:data.id_name}} - {{/if}} -
-
-
-

Sensor Contacts

-
-{{if data.contacts}} - - {{for data.contacts}} - - - - - - {{/for}} -
{{:helper.link('Scan', 'search' ,{ 'scan' : value.ref }, null, null)}} - {{if value.can_datalink}} - {{:helper.link('Datalink', 'search' ,{ 'request_datalink' : value.ref }, null, null)}} - {{/if}} - {{:value.name}}, bearing {{:value.bearing}}
- {{if data.contact_details}} - - {{:data.contact_details}} -
-
- - {{:helper.link('Print', 'search', { 'scan-action' : 'print' })}} - {{:helper.link('Clear', 'refresh', { 'scan-action' : 'clear' })}} - -{{/if}} -{{/if}} - - -

Datalinks

-
-{{if data.datalink_requests}} - - {{for data.datalink_requests}} - -
-
- - - - - {{/for}} -
{{:helper.link('Accept', 'search' ,{ 'accept_datalink_requests' : value.ref }, null, null)}}{{:helper.link('Decline', 'search' ,{ 'decline_datalink_requests' : value.ref }, null, null)}}{{:value.name}}
-{{/if}} -{{if data.datalinked}} -

Connected Datalinks

- - {{for data.datalinked}} - -
-
- - - - {{/for}} -
{{:helper.link('Rescind', 'search' ,{ 'remove_datalink' : value.ref }, null, null)}}{{:value.name}}
-{{/if}} -
- -{{if data.id_name == 'Horizon'}} -

Announce Inbound fire

-
-
- {{:helper.link('', 'triangle-1-nw', { 'inbound_fire' : 'Fore-Port' }, null, null)}} - {{:helper.link('', 'triangle-1-n', { 'inbound_fire' : 'Fore' }, null, null)}} - {{:helper.link('', 'triangle-1-ne', { 'inbound_fire' : 'Fore-Starboard' }, null, null)}} -
-
- {{:helper.link('', 'triangle-1-w', { 'inbound_fire' : 'Port' }, null, null)}} - {{:helper.link('', 'circle-close', { 'inbound_fire' : 'clear' }, null, null)}} - {{:helper.link('', 'triangle-1-e', { 'inbound_fire' : 'Starboard' }, null, null)}} -
-
- {{:helper.link('', 'triangle-1-sw', { 'inbound_fire' : 'Bow-Port' }, null, null)}} - {{:helper.link('', 'triangle-1-s', { 'inbound_fire' : 'Bow' }, null, null)}} - {{:helper.link('', 'triangle-1-se', { 'inbound_fire' : 'Bow-Starboard' }, null, null)}} -
-
-{{/if}} - -

Distress Beacons

-
-Press the 'Listen' button to listen to the distress message. -{{if data.distress_beacons}} - - {{for data.distress_beacons}} - -
-
- - - - {{/for}} -
{{:helper.link('Listen', 'info' ,{ 'play_message' : value.caller }, null, null)}}{{:value.caller}}, bearing {{:value.bearing}}, sent by {{:value.sender}}
-{{/if}} -
-{{if data.status == 'MISSING'}} -
- {{:helper.link('Link up with the sensor suite', 'gear', { 'link' : 1 }, data.status == 'MISSING' ? null : 'disabled', null)}} -
-{{/if}} diff --git a/tgui/packages/common/math.ts b/tgui/packages/common/math.ts index 9dc1d655693..b9f7bfda9d5 100644 --- a/tgui/packages/common/math.ts +++ b/tgui/packages/common/math.ts @@ -4,6 +4,8 @@ * @license MIT */ +// Further modified for Aurora + /** * Limits a number to the range between 'min' and 'max'. */ @@ -96,3 +98,10 @@ export const numberOfDecimalDigits = (value) => { } return 0; }; + +// Linear interpolation between two values. +export const lerp = (value1: number, value2: number, amount: number) => { + amount = amount < 0 ? 0 : amount; + amount = amount > 1 ? 1 : amount; + return value1 + (value2 - value1) * amount; +}; diff --git a/tgui/packages/tgui/interfaces/Sensors.tsx b/tgui/packages/tgui/interfaces/Sensors.tsx new file mode 100644 index 00000000000..e891d9b2b8f --- /dev/null +++ b/tgui/packages/tgui/interfaces/Sensors.tsx @@ -0,0 +1,621 @@ +import { BooleanLike } from '../../common/react'; +import { useBackend } from '../backend'; +import { Box, Button, Section, Table, ProgressBar, Slider } from '../components'; +import { NtosWindow } from '../layouts'; +import { round, clamp } from 'common/math'; +import { Color } from 'common/color'; +import { capitalizeAll } from 'common/string'; + +export type SensorsData = { + viewing: BooleanLike; + muted: BooleanLike; + grid_x: number; + grid_y: number; + x: number; + y: number; + direction: number; + is_ship: BooleanLike; + on: BooleanLike; + range: number; + health: number; + max_health: number; + deep_scan_name: string; + deep_scan_range: number; + deep_scan_toggled: BooleanLike; + heat: number; + critical_heat: number; + status: string; + desired_range: number; + range_choices: number[]; + contacts: ContactData[]; + + id_on: BooleanLike; + id_status: string; + id_class: string; + id_name: string; + can_change_class: BooleanLike; + can_change_name: BooleanLike; + contact_details: string; + + distress_beacons: DistressBeaconData[]; + distress_range: number; + + datalink_requests: { name: string; ref: string }[]; + datalinked: { name: string; ref: string }[]; +}; + +type ContactData = { + name: string; + ref: string; + bearing: number; + can_datalink: BooleanLike; + landed: BooleanLike; + distance: number; + x: number; + y: number; + color: string; // assigned in ts +}; + +type DistressBeaconData = { + caller: string; + sender: string; + bearing: number; +}; + +const SensorSection = function (act, data: SensorsData) { + const range_choice_max = data.range_choices[data.range_choices.length - 1]; + + return ( +
act('viewing')} + /> + }> + + + State: + +
+
+ ); +}; + +const ContactsSection = function (act, data: SensorsData) { + return ( +
+ {data.contacts && data.contacts.length ? ( + + + + Designation + B + X + Y + D + C + + {data.contacts.map((contact: ContactData, i) => ( + + +
+ ) : ( + '' + )} +
+ ); +}; + +const ContactDetailsSection = function (act, data: SensorsData) { + if (data.contact_details && data.contact_details !== '') { + /* eslint-disable react/no-danger */ + const contact_details = ( +
+ ); + /* eslint-enable */ + return ( +
+ + {contact_details} +
+ ); + } else { + return ''; + } +}; + +const CompassSection = function (context, act, data: SensorsData) { + return ( +
+ + + + + {[8, 16, 24, 32, 40, 48].map((r) => ( + + ))} + + {[0, 45, 90, 135, 180, 225, 270, 315].map((b) => ( + + ))} + {data.contacts + ?.filter((c) => !c.landed) + .map((contact: ContactData, i) => ( + + ))} + {data.contacts + ?.filter((c) => !c.landed) + .map((contact: ContactData, i) => ( + <> + + + {contact.bearing} + + + ))} + {[0, 45, 90, 135, 180, 225, 270, 315].map((b) => ( + + {b} + + ))} + + + +
+ ); +}; + +const DatalinksSection = function (act, data: SensorsData) { + return ( +
+ {data.datalink_requests && data.datalink_requests.length ? ( + + + Datalink Requests: + + {data.datalink_requests.map((request) => ( + + +
+ ) : ( + '' + )} + {data.datalinked && data.datalinked.length ? ( + + + Active Datalinks: + + {data.datalinked.map((datalinked) => ( + + {capitalizeAll(datalinked.name)} + +
+ ) : ( + '' + )} + {data.contacts && + data.contacts.length && + data.contacts.some((contact) => contact.can_datalink) ? ( + + + Potential Datalinks: + + {data.contacts + .filter((contact) => contact.can_datalink) + .map((contact) => ( + + {capitalizeAll(contact.name)} + +
+ ) : ( + '' + )} +
+ ); +}; + +const IFFSection = function (act, data: SensorsData) { + return ( +
+ + + State: + +
+
+ ); +}; + +const DistressSection = function (act, data: SensorsData) { + return ( +
+ {data.distress_beacons && data.distress_beacons.length ? ( + + + + Vessel + Bearing + Sender + + {data.distress_beacons.map((beacon: DistressBeaconData) => ( + + +
+ ) : ( + 'None received.' + )} +
+ ); +}; + +export const Sensors = (props, context) => { + const { act, data } = useBackend(context); + + { + let color_i = 0; + const colors = [ + 'red', + 'green', + 'purple', + 'orange', + 'cyan', + 'yellow', + 'maroon', + 'olive', + 'white', + ]; + + let bearing_color_map: Map = new Map(); + + data.contacts?.forEach((contact, i) => { + if (!bearing_color_map[contact.bearing]) { + bearing_color_map[contact.bearing] = colors[color_i]; + color_i++; + if (color_i >= colors.length) { + color_i = 0; + } + } + contact.color = bearing_color_map[contact.bearing]; + }); + } + + return ( + + + {data.status === 'MISSING' ? ( +