NTNet Extensibility (#22908)

Fixes https://github.com/Aurorastation/Aurora.3/issues/21944

Spiritual successor of
https://github.com/Aurorastation/Aurora.3/pull/22352
Cherrypicked changes from the C3 Crew Management branch, this PR
contains all NTNet extensibility features, including Field Relay
construction, off-site camera usage (contingent on standing up remote
hardware and being out of jamming), etc. This also fixes a handful of
outstanding telecomms and view/mobeye-related bugs adjacent to where I
was working.

changes:
- rscadd: "Adds NTNet extensibility, requires new machinery constructed
on away-site z-levels."
- rscadd: "Breaks NTNet Relay machinery into Quantum Relay ('core' obj
on Horizon) and Field Relay (deployable off-site constructions)."
- qol: "Embedded cameras (basically every video camera EXCEPT those
which are installed on walls) can now be viewed from NTNet-connected
z-level, not just connected ones."
- rscadd: "Adds several public camera monitor consoles to the Horizon
(near where public sensor grid feed consoles already exist)."
- rscadd: "Adds some spare camera console boards to Horizon technical
storage."
- qol: "Adds action button for 'cancel-camera-view' verb while viewing
cameras or looking up/down z-level."
- bugfix: "Fixes Jockey comms (frequency was missing from ANTAG_FREQS)."
- bugfix: "Fixes look-up/look-down actions intermittently failing
without first using cancel-camera-view."
This commit is contained in:
Batrachophreno
2026-08-02 01:24:45 +00:00
committed by GitHub
parent 886ca9237f
commit 7172d3dbe3
48 changed files with 4864 additions and 4153 deletions
+92 -28
View File
@@ -1,7 +1,7 @@
GLOBAL_DATUM_INIT(ntnet_global, /datum/ntnet, new)
// This is the NTNet datum. There can be only one NTNet datum in game at once. Modular computers read data from this.
/// This is the NTNet datum. There can be only one NTNet datum in game at once. Modular computers read data from this.
/datum/ntnet
var/list/relays = list()
var/list/logs = list()
@@ -13,22 +13,24 @@ GLOBAL_DATUM_INIT(ntnet_global, /datum/ntnet, new)
var/list/available_news = list()
var/list/fileservers = list()
var/list/datum/ntnet_account/users = list()
// Amount of logs the system tries to keep in memory. Keep below 999 to prevent byond from acting weirdly.
// High values make displaying logs much laggier.
/// Amount of logs the system tries to keep in memory. Keep below 999 to prevent byond from acting weirdly.
/// High values make displaying logs much laggier.
var/setting_maxlogcount = 100
// These only affect wireless. LAN (consoles) are unaffected since it would be possible to create scenario where someone turns off NTNet, and is unable to turn it back on since it refuses connections
/// These only affect wireless. LAN (consoles) are unaffected since it would be possible to create scenario where someone turns off NTNet, and is unable to turn it back on since it refuses connections
var/setting_softwaredownload = TRUE
var/setting_peertopeer = TRUE
var/setting_communication = TRUE
var/setting_systemcontrol = TRUE
var/setting_disabled = FALSE // Setting to 1 will disable all wireless, independently on relays status.
var/intrusion_detection_enabled = TRUE // Whether the IDS warning system is enabled
var/intrusion_detection_alarm = FALSE // Set when there is an IDS warning due to malicious (antag) software.
/// Setting to 1 will disable all wireless, independently on relays status.
var/setting_disabled = FALSE
/// Whether the IDS warning system is enabled
var/intrusion_detection_enabled = TRUE
/// Set when there is an IDS warning due to malicious (antag) software.
var/intrusion_detection_alarm = FALSE
// If new NTNet datum is spawned, it replaces the old one.
/// If new NTNet datum is spawned, it replaces the old one.
/datum/ntnet/New()
if(GLOB.ntnet_global && (GLOB.ntnet_global != src))
GLOB.ntnet_global = src // There can be only one.
@@ -41,7 +43,7 @@ GLOBAL_DATUM_INIT(ntnet_global, /datum/ntnet, new)
//add some default channels
new /datum/ntnet_conversation("NTNet Relay", TRUE)
// Simplified logging: Adds a log. log_string is mandatory parameter, source is optional.
/// Simplified logging: Adds a log. log_string is mandatory parameter, source is optional.
/datum/ntnet/proc/add_log(var/log_string, var/obj/item/computer_hardware/network_card/source = null, var/messaging=FALSE)
var/log_text = "[worldtime2text()] - "
if(source)
@@ -62,18 +64,9 @@ GLOBAL_DATUM_INIT(ntnet_global, /datum/ntnet, new)
else
break
// Checks whether NTNet operates. If parameter is passed checks whether specific function is enabled.
/// Checks whether NTNet's core service operates. If parameter is passed checks whether specific function is enabled.
/datum/ntnet/proc/check_function(var/specific_action = 0)
if(!relays || !relays.len) // No relays found. NTNet is down
return FALSE
var/operating = FALSE
// Check all relays. If we have at least one working relay, network is up.
for(var/obj/structure/machinery/ntnet_relay/R in relays)
if(R.operable())
operating = TRUE
break
var/operating = has_operable_core()
if(setting_disabled)
return FALSE
@@ -88,7 +81,79 @@ GLOBAL_DATUM_INIT(ntnet_global, /datum/ntnet, new)
return (operating && setting_systemcontrol)
return operating
// Builds lists that contain downloadable software.
/datum/ntnet/proc/check_endpoint_function(var/specific_action = 0, var/ethernet = FALSE)
// Wireless firewall toggles do not affect wired endpoints, but wired endpoints still need a live core service
if(ethernet)
return has_operable_core()
return check_function(specific_action)
/datum/ntnet/proc/has_operable_core()
if(!relays || !relays.len)
return FALSE
for(var/obj/structure/machinery/ntnet_relay/R in relays)
if(R.provides_core_service())
return TRUE
return FALSE
/// 'For endpoint' signifies that sometimes we will abstract a device as being a modular computer when really all we care about is whether it is networked.
/// This will likely need to be simplified in future.
/datum/ntnet/proc/get_signal_for_endpoint(var/atom/endpoint, var/specific_action = 0, var/ethernet = FALSE, var/long_range = FALSE)
if(!istype(endpoint))
return 0
var/turf/endpoint_turf = get_turf(endpoint)
if(SSatlas.current_map.is_always_available_network_level(endpoint_turf?.z))
if(ethernet)
return 3
if(long_range)
return 2
return 1
if(!check_endpoint_function(specific_action, ethernet))
return 0
var/area/A = get_area(endpoint)
if(A?.centcomm_area && ethernet)
return 3
var/signal = 0
for(var/obj/structure/machinery/ntnet_relay/R in relays)
signal = max(signal, R.get_signal_for_endpoint(endpoint, ethernet, long_range))
return signal
/datum/ntnet/proc/get_signal(var/obj/item/computer_hardware/network_card/card, var/specific_action = 0)
if(!istype(card) || !card.parent_computer)
return 0
return get_signal_for_endpoint(card.parent_computer, specific_action, card.ethernet, card.long_range)
/datum/ntnet/proc/get_reachable_z_levels_for_endpoint(var/atom/endpoint, var/specific_action = 0, var/ethernet = FALSE, var/long_range = FALSE)
. = list()
var/turf/endpoint_turf = get_turf(endpoint)
if(SSatlas.current_map.is_always_available_network_level(endpoint_turf?.z))
. |= endpoint_turf.z
return
if(get_signal_for_endpoint(endpoint, specific_action, ethernet, long_range) <= 0)
return
for(var/obj/structure/machinery/ntnet_relay/R in relays)
if(R.can_route_to_core())
. |= R.get_covered_z_levels()
/datum/ntnet/proc/get_reachable_z_levels(var/obj/item/computer_hardware/network_card/card, var/specific_action = 0)
. = list()
var/turf/endpoint_turf = get_turf(card?.parent_computer)
if(SSatlas.current_map.is_always_available_network_level(endpoint_turf?.z))
. |= endpoint_turf.z
return
if(get_signal(card, specific_action) <= 0)
return
for(var/obj/structure/machinery/ntnet_relay/R in relays)
if(R.can_route_to_core())
. |= R.get_covered_z_levels()
/// Builds lists that contain downloadable software.
/datum/ntnet/proc/build_software_lists()
available_station_software = list()
available_antag_software = list()
@@ -109,7 +174,7 @@ GLOBAL_DATUM_INIT(ntnet_global, /datum/ntnet, new)
var/datum/modular_computer_app_presets/prs = new path()
available_software_presets.Add(prs)
// Builds lists that contain downloadable software.
/// Builds lists that contain downloadable software.
/datum/ntnet/proc/build_news_list()
available_news = list()
for(var/F in typesof(/datum/computer_file/data/news_article/))
@@ -117,14 +182,13 @@ GLOBAL_DATUM_INIT(ntnet_global, /datum/ntnet, new)
if(news.stored_data)
available_news.Add(news)
// Attempts to find a downloadable file according to filename var
/// Attempts to find a downloadable file according to filename var
/datum/ntnet/proc/find_ntnet_file_by_name(var/filename)
for(var/datum/computer_file/program/P in available_software)
if(filename == P.filename)
return P
// Resets the IDS alarm
/// Resets the IDS alarm
/datum/ntnet/proc/resetIDS()
intrusion_detection_alarm = FALSE
@@ -132,13 +196,13 @@ GLOBAL_DATUM_INIT(ntnet_global, /datum/ntnet, new)
resetIDS()
intrusion_detection_enabled = !intrusion_detection_enabled
// Removes all logs
/// Removes all logs
/datum/ntnet/proc/purge_logs()
logs = list()
messages = list()
add_log("-!- LOGS DELETED BY SYSTEM OPERATOR -!-")
// Updates maximal amount of stored logs. Use this instead of setting the number, it performs required checks.
/// Updates maximal amount of stored logs. Use this instead of setting the number, it performs required checks.
/datum/ntnet/proc/update_max_log_count(var/lognumber)
if(!lognumber)
return FALSE
@@ -1,7 +1,6 @@
// Relays don't handle any actual communication. Global NTNet datum does that, relays only tell the datum if it should or shouldn't work.
/obj/structure/machinery/ntnet_relay
name = "NTNet Quantum Relay"
desc = "A very complex router and transmitter capable of connecting electronic devices together. Looks fragile."
desc = "A very complex core router and transmitter capable of connecting electronic devices together. Looks fragile."
use_power = POWER_USE_ACTIVE
active_power_usage = 20000 //20kW, appropriate for machine that keeps massive cross-Zlevel wireless network operational.
idle_power_usage = 100
@@ -9,22 +8,34 @@
icon = 'icons/obj/machinery/telecomms.dmi'
anchored = TRUE
density = TRUE
var/datum/ntnet/NTNet // This is mostly for backwards reference and to allow varedit modifications from ingame.
var/enabled = TRUE // Set to FALSE if the relay was turned off
var/dos_failure = FALSE // Set to TRUE if the relay failed due to (D)DoS attack
var/list/dos_sources = list() // Backwards reference for qdel() stuff
/// This is mostly for backwards reference and to allow varedit modifications from ingame.
var/datum/ntnet/NTNet
/// Set to FALSE if the relay was turned off
var/enabled = TRUE
/// Set to TRUE if the relay failed due to (D)DoS attack
var/dos_failure = FALSE
/// Backwards reference for qdel() stuff
var/list/dos_sources = list()
/// Core relays are the NTNet source of truth. Field relays only extend a live core.
var/core_service = TRUE
/// Overmap tile range from this relay's sector to an operable core.
var/backhaul_range = 0
// Denial of Service attack variables
var/dos_overload = 0 // Amount of DoS "packets" in this relay's buffer
var/dos_capacity = 500 // Amount of DoS "packets" in buffer required to crash the relay
var/dos_dissipate = 1 // Amount of DoS "packets" dissipated over time.
/// Amount of DoS "packets" in this relay's buffer
var/dos_overload = 0
/// Amount of DoS "packets" in buffer required to crash the relay
var/dos_capacity = 500
/// Amount of DoS "packets" dissipated over time.
var/dos_dissipate = 1
component_types = list(
/obj/item/stack/cable_coil{amount = 15},
/obj/item/circuitboard/ntnet_relay
/obj/item/circuitboard/ntnet_relay,
/obj/item/stack/cable_coil = 15,
/obj/item/stock_parts/micro_laser/high = 2,
/obj/item/stock_parts/subspace/filter,
/obj/item/stock_parts/subspace/crystal
)
// TODO: Implement more logic here. For now it's only a placeholder.
/obj/structure/machinery/ntnet_relay/operable()
if(!..(EMPED))
return FALSE
@@ -34,6 +45,90 @@
return FALSE
return TRUE
/obj/structure/machinery/ntnet_relay/proc/provides_core_service()
return core_service && operable() && is_valid_core_location()
/obj/structure/machinery/ntnet_relay/proc/ensure_linked()
if(!SSatlas.current_map.use_overmap)
return linked
if(istype(linked) && (z in linked.map_z))
return linked
linked = null
return sync_linked()
/obj/structure/machinery/ntnet_relay/proc/is_valid_core_location()
if(!SSatlas.current_map.use_overmap)
return TRUE
var/obj/effect/overmap/visitable/sector = ensure_linked()
if(istype(sector))
return sector.base
var/obj/effect/overmap/visitable/known_sector = GLOB.map_sectors["[z]"]
if(istype(known_sector))
return FALSE
return is_station_level(z)
/obj/structure/machinery/ntnet_relay/proc/can_route_to_core()
if(!operable())
return FALSE
if(core_service)
return provides_core_service()
if(!GLOB.ntnet_global)
return FALSE
return !!get_backhaul_core()
/obj/structure/machinery/ntnet_relay/proc/get_backhaul_core()
if(!GLOB.ntnet_global)
return
ensure_linked()
for(var/obj/structure/machinery/ntnet_relay/R in GLOB.ntnet_global.relays)
if(R == src || !R.provides_core_service())
continue
if(can_backhaul_to(R))
return R
/obj/structure/machinery/ntnet_relay/proc/can_backhaul_to(var/obj/structure/machinery/ntnet_relay/core)
if(!istype(core) || !core.provides_core_service())
return FALSE
if(SSatlas.current_map.use_overmap)
var/obj/effect/overmap/visitable/source_sector = ensure_linked()
var/obj/effect/overmap/visitable/core_sector = core.ensure_linked()
if(!istype(source_sector) || !istype(core_sector))
return FALSE
return get_dist(source_sector, core_sector) <= backhaul_range
return AreConnectedZLevels(z, core.z)
/obj/structure/machinery/ntnet_relay/proc/get_covered_z_levels()
if(SSatlas.current_map.use_overmap)
var/obj/effect/overmap/visitable/sector = ensure_linked()
if(istype(sector))
return sector.map_z.Copy()
return list()
return GetConnectedZlevels(z)
/obj/structure/machinery/ntnet_relay/proc/covers_z(var/z_level)
if(!z_level || !can_route_to_core())
return FALSE
return z_level in get_covered_z_levels()
/// 'For endpoint' signifies that sometimes we will abstract a device as being a modular computer when really all we care about is whether it is networked.
/// This will likely need to be simplified in future.
/obj/structure/machinery/ntnet_relay/proc/get_signal_for_endpoint(var/atom/endpoint, var/ethernet = FALSE, var/long_range = FALSE)
if(!istype(endpoint))
return 0
var/turf/T = get_turf(endpoint)
if(!istype(T) || !covers_z(T.z))
return 0
if(ethernet)
return 3
if(long_range)
return 2
return 1
/obj/structure/machinery/ntnet_relay/proc/get_signal(var/obj/item/computer_hardware/network_card/card)
if(!istype(card) || !card.parent_computer)
return 0
return get_signal_for_endpoint(card.parent_computer, card.ethernet, card.long_range)
/obj/structure/machinery/ntnet_relay/update_icon()
ClearOverlays()
if(operable())
@@ -76,11 +171,18 @@
ui.open()
/obj/structure/machinery/ntnet_relay/ui_data(mob/user)
var/obj/structure/machinery/ntnet_relay/backhaul_core = core_service ? null : get_backhaul_core()
var/backhaul_online = core_service ? can_route_to_core() : !!backhaul_core
var/list/data = list()
data["enabled"] = enabled
data["dos_capacity"] = dos_capacity
data["dos_overload"] = dos_overload
data["dos_crashed"] = dos_failure
data["relay_class"] = core_service ? "Core" : "Field"
data["linked_sector"] = linked ? linked.name : "Unlinked"
data["backhaul_range"] = backhaul_range
data["backhaul_online"] = backhaul_online
data["backhaul_core"] = core_service ? "Self" : (backhaul_core?.linked ? backhaul_core.linked.name : "None")
return data
@@ -113,8 +215,13 @@
if(GLOB.ntnet_global)
GLOB.ntnet_global.relays.Add(src)
NTNet = GLOB.ntnet_global
sync_linked()
GLOB.ntnet_global.add_log("New quantum relay activated. Current amount of linked relays: [NTNet.relays.len]")
/obj/structure/machinery/ntnet_relay/LateInitialize()
. = ..()
sync_linked()
/obj/structure/machinery/ntnet_relay/Destroy()
if(GLOB.ntnet_global)
GLOB.ntnet_global.relays.Remove(src)
@@ -140,3 +247,18 @@
qdel(src)
return
..()
/obj/structure/machinery/ntnet_relay/field
name = "NTNet Field Relay"
desc = "A deployable NTNet relay that extends local network coverage while it has short-range backhaul to an operational core relay."
active_power_usage = 5000
enabled = FALSE
core_service = FALSE
backhaul_range = 1
component_types = list(
/obj/item/circuitboard/ntnet_relay/field,
/obj/item/stack/cable_coil = 15,
/obj/item/stock_parts/micro_laser/high = 2,
/obj/item/stock_parts/subspace/filter,
/obj/item/stock_parts/subspace/crystal
)
@@ -100,6 +100,8 @@
/obj/item/modular_computer/Destroy()
STOP_PROCESSING(SSprocessing, src)
reset_remote_viewers(TRUE)
SStgui.close_uis(src)
enabled = FALSE
@@ -289,6 +291,7 @@
active_program = null
else
return FALSE
reset_remote_viewers()
var/mob/user = usr
if(user && istype(user) && !forced && !QDELETED(src))
INVOKE_ASYNC(src, TYPE_PROC_REF(/datum, ui_interact), user) // Re-open the UI on this computer. It should show the main screen now.
@@ -304,6 +307,14 @@
active_program = null
else
return FALSE
reset_remote_viewers()
/obj/item/modular_computer/proc/reset_remote_viewers(var/unset_viewers_machine = FALSE)
for(var/mob/M in GLOB.player_list)
if(M.machine == src && M.is_viewing_remote_view())
if(unset_viewers_machine)
M.unset_machine()
M.reset_view(null)
// Returns 0 for No Signal, 1 for Low Signal and 2 for Good Signal. 3 is for wired connection (always-on)
/obj/item/modular_computer/proc/get_ntnet_status(var/specific_action = 0)
@@ -26,7 +26,7 @@
data["isAI"] = isAI(user)
data["crewmembers"] = list()
if(SSradio.telecomms_ping(computer))
for(var/z_level in SSatlas.current_map.map_levels)
for(var/z_level in GLOB.ntnet_global.get_reachable_z_levels(computer.network_card))
data["crewmembers"] += GLOB.crew_repository.health_data(z_level)
data["security_level"] = seclevel2num(get_security_level())
@@ -21,6 +21,16 @@
data["ntnetstatus"] = GLOB.ntnet_global.check_function()
data["ntnetrelays"] = GLOB.ntnet_global.relays.len
data["ntnetcores"] = 0
data["ntnetfieldrelays"] = 0
data["ntnetroutedrelays"] = 0
for(var/obj/structure/machinery/ntnet_relay/R in GLOB.ntnet_global.relays)
if(R.core_service)
data["ntnetcores"]++
else
data["ntnetfieldrelays"]++
if(R.can_route_to_core())
data["ntnetroutedrelays"]++
data["idsstatus"] = GLOB.ntnet_global.intrusion_detection_enabled
data["idsalarm"] = GLOB.ntnet_global.intrusion_detection_alarm
@@ -8,7 +8,7 @@
return
switch(network)
if(NETWORK_THUNDER, NETWORK_NEWS)
if(NETWORK_THUNDER, NETWORK_NEWS, NETWORK_EXPEDITION)
return FALSE
if(NETWORK_REACTOR,NETWORK_ENGINEERING,NETWORK_ENGINEERING_OUTPOST,NETWORK_ALARM_ATMOS,NETWORK_ALARM_FIRE,NETWORK_ALARM_POWER)
return ACCESS_ENGINE
@@ -46,6 +46,15 @@
var/current_network
/// Used for camera monitor consoles from which this interface can be launched. If it exists, only provide that console's "console_networks" networks.
var/list/monitored_networks = list()
/// Used by non-modular camera consoles that run this program - abstracts as modular comp w/ network card.
var/atom/ntnet_endpoint
var/ntnet_endpoint_ethernet = FALSE
var/ntnet_endpoint_long_range = FALSE
/datum/computer_file/program/camera_monitor/ui_host()
if(ntnet_endpoint)
return ntnet_endpoint
return ..()
/datum/computer_file/program/camera_monitor/ui_data(mob/user)
var/list/data = initial_data()
@@ -108,6 +117,7 @@
return 0
/// If no network_access is passed, or if 0 is returned, we treat this as no camera access required. Allowed it.
/datum/computer_file/program/camera_monitor/proc/can_access_network(var/mob/user, var/network_access)
// No access passed, or 0 which is considered no access requirement. Allow it.
if(!network_access)
@@ -115,6 +125,19 @@
return (check_network_access(user, ACCESS_SECURITY) && GLOB.security_level >= SEC_LEVEL_BLUE) || check_network_access(user, network_access)
/datum/computer_file/program/camera_monitor/proc/can_reach_camera(var/obj/structure/machinery/camera/C)
if(!C?.can_use())
return FALSE
var/turf/camera_turf = get_turf(C)
if(!camera_turf || !GLOB.ntnet_global)
return FALSE
if(computer?.network_card)
return (camera_turf.z in GLOB.ntnet_global.get_reachable_z_levels(computer.network_card, requires_ntnet_feature))
return (camera_turf.z in GLOB.ntnet_global.get_reachable_z_levels_for_endpoint(ntnet_endpoint, requires_ntnet_feature, ntnet_endpoint_ethernet, ntnet_endpoint_long_range))
/datum/computer_file/program/camera_monitor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
@@ -152,6 +175,10 @@
usr.reset_view(current_camera)
return TRUE
/datum/computer_file/program/camera_monitor/kill_program(forced)
reset_current()
return ..()
/datum/computer_file/program/camera_monitor/proc/switch_to_camera(var/mob/user, var/obj/structure/machinery/camera/C)
//don't need to check if the camera works for AI because the AI jumps to the camera location and doesn't actually look through cameras.
if(isAI(user))
@@ -164,7 +191,7 @@
A.client.eye = A.eyeobj
return TRUE
if(!is_contact_area(get_area(C)))
if(!can_reach_camera(C))
to_chat(user, SPAN_NOTICE("This camera is too far away to connect to!"))
return FALSE
@@ -186,6 +213,10 @@
if(!current_camera)
return 0
if(!can_reach_camera(current_camera))
reset_current()
return -1
var/viewflag = current_camera.check_eye(user)
if(viewflag < 0)
reset_current()
@@ -194,6 +225,8 @@
/datum/computer_file/program/camera_monitor/grants_equipment_vision(mob/user)
if(user.stat || user.blinded || !current_camera)
return FALSE
if(!can_reach_camera(current_camera))
return FALSE
return current_camera.grants_equipment_vision(user)
/datum/computer_file/program/camera_monitor/proc/set_current(var/obj/structure/machinery/camera/C)
@@ -233,8 +266,8 @@
/datum/computer_file/program/camera_monitor/news
filename = "idcammon"
filedesc = "Journalism Camera Monitoring"
extended_desc = "This program allows remote access to station's camera system. Some camera networks may have additional access requirements. This version has has a connection to news networks."
filedesc = "Public Camera Monitoring"
extended_desc = "This program allows remote access to station's camera system. Some camera networks may have additional access requirements. This version has has a connection to news and expeditionary networks."
size = 2
required_access_download = null
usage_flags = PROGRAM_ALL
@@ -242,5 +275,5 @@
/datum/computer_file/program/camera_monitor/news/modify_networks_list(var/list/networks)
networks = list()
networks.Add(list(list("tag" = NETWORK_NEWS, "has_access" = 1)))
networks.Add(list(list("tag" = NETWORK_THUNDER, "has_access" = 1)))
networks.Add(list(list("tag" = NETWORK_EXPEDITION, "has_access" = 1)))
return networks
@@ -40,7 +40,7 @@
var/turf/mech_turf = get_turf(M)
mechData["location"] = "[mech_turf.x], [mech_turf.y], [mech_turf.z]"
mechData["camera_status"] = M.camera.status
mechData["camera_status"] = M.camera.can_use()
mechData["lockdown"] = M.lockdown
mechs += list(mechData)
@@ -121,7 +121,7 @@
A.client.eye = A.eyeobj
return TRUE
if(!is_contact_area(get_area(C)))
if(!can_reach_camera(C))
to_chat(user, SPAN_NOTICE("This camera is too far away to connect to!"))
return FALSE
@@ -130,6 +130,16 @@
user.reset_view(current_camera)
return TRUE
/datum/computer_file/program/penal_mechs/proc/can_reach_camera(var/obj/structure/machinery/camera/C)
if(!C?.can_use())
return FALSE
var/turf/camera_turf = get_turf(C)
if(!camera_turf || !computer?.network_card || !GLOB.ntnet_global)
return FALSE
return (camera_turf.z in GLOB.ntnet_global.get_reachable_z_levels(computer.network_card, requires_ntnet_feature))
/datum/computer_file/program/penal_mechs/proc/set_current(var/obj/structure/machinery/camera/C)
if(current_camera == C)
return
@@ -26,7 +26,7 @@
/datum/computer_file/program/clientmanager/ui_data(mob/user)
var/list/data = list()
data["ntnet_status"] = GLOB.ntnet_global.check_function(NTNET_SOFTWAREDOWNLOAD)
data["ntnet_status"] = computer.get_ntnet_status(NTNET_SOFTWAREDOWNLOAD)
return data
/datum/computer_file/program/clientmanager/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
@@ -35,7 +35,7 @@
if(action == "enroll")
. = TRUE
if(!GLOB.ntnet_global.check_function(NTNET_SOFTWAREDOWNLOAD))
if(!computer.get_ntnet_status(NTNET_SOFTWAREDOWNLOAD))
to_chat(ui.user, SPAN_WARNING("Cannot connect to NTNet download servers. Please try again later."))
return
if(params["enroll_type"] & DEVICE_COMPANY)
@@ -8,13 +8,19 @@ GLOBAL_VAR_INIT(ntnet_card_uid, 1)
critical = FALSE
icon_state = "netcard_basic"
hardware_size = 1
var/identification_id // Identification ID. Technically MAC address of this device. Can't be changed by user.
var/identification_string = "" // Identification string, technically nickname seen in the network. Can be set by user.
/// Identification ID. Technically MAC address of this device. Can't be changed by user.
var/identification_id
/// Identification string, technically nickname seen in the network. Can be set by user.
var/identification_string = ""
var/long_range = FALSE
var/ethernet = FALSE // Hard-wired, therefore always on, ignores NTNet wireless checks.
var/obj/item/integrated_signaler/signal/sradio = FALSE // integrated signaler - not present on basic model.
var/obj/item/integrated_signaler/signal/secondary_sradio = FALSE // second receiver for NTOS signaler software.
var/obj/item/integrated_signaler/signal/transmit_sradio = FALSE // transmitter for NTOS signaler software.
/// Hard-wired, therefore always on, ignores NTNet wireless checks.
var/ethernet = FALSE
/// integrated signaler - not present on basic model.
var/obj/item/integrated_signaler/signal/sradio = FALSE
/// second receiver for NTOS signaler software.
var/obj/item/integrated_signaler/signal/secondary_sradio = FALSE
/// transmitter for NTOS signaler software.
var/obj/item/integrated_signaler/signal/transmit_sradio = FALSE
malfunction_probability = 1
/obj/item/computer_hardware/network_card/diagnostics(mob/user)
@@ -47,7 +53,7 @@ GLOBAL_VAR_INIT(ntnet_card_uid, 1)
/obj/item/computer_hardware/network_card/advanced
name = "advanced NTNet network card"
desc = "An advanced network card for usage with standard NTNet frequencies. Its transmitter is strong enough to connect even off-station."
desc = "An advanced network card for usage with standard NTNet frequencies. Its transmitter can sustain high-bandwidth links to nearby NTNet relays."
long_range = TRUE
origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 2)
power_usage = 150 // Better range but higher power usage.
@@ -110,11 +116,11 @@ GLOBAL_VAR_INIT(ntnet_card_uid, 1)
return TRUE
// Returns a string identifier of this network card
/// Returns a string identifier of this network card
/obj/item/computer_hardware/network_card/proc/get_network_tag()
return "[identification_string] (NID [identification_id])"
// 0 - No signal, 1 - Low signal, 2 - High signal. 3 - Wired Connection
/// 0 - No signal, 1 - Low signal, 2 - High signal. 3 - Wired Connection
/obj/item/computer_hardware/network_card/proc/get_signal(var/specific_action = 0)
if(!parent_computer) // Hardware is not installed in anything. No signal. How did this even get called?
return 0
@@ -122,27 +128,10 @@ GLOBAL_VAR_INIT(ntnet_card_uid, 1)
return 0
if(!check_functionality())
return 0
if(!GLOB.ntnet_global || !GLOB.ntnet_global.check_function(specific_action))
if(!GLOB.ntnet_global)
return 0
if(parent_computer)
var/turf/T = get_turf(parent_computer)
if((T && istype(T)) && is_station_level(T.z))
// Computer is on station. Low/High signal depending on what type of network card you have
if(ethernet)
return 3
else if(long_range)
return 2
else
return 1
var/area/A = get_area(parent_computer)
if(A.centcomm_area && ethernet)
return 3
if(long_range) // Computer is not on station, but it has upgraded network card. Low signal.
return 1
return 0 // Computer is not on station and does not have upgraded network card. No signal.
return GLOB.ntnet_global.get_signal_for_endpoint(parent_computer, specific_action, ethernet, long_range)
/obj/item/computer_hardware/network_card/Destroy()
if(sradio)