Files
Paradise/code/game/machinery/tcomms/core.dm
S34N ea0c492094 CC tcomms QoL (#18827)
* auto-relinking!

* makes these work everywhere

* makes it clearer this is a UID

* works

* fix

* Update code/game/machinery/tcomms/presets.dm

Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>

Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>
2022-09-07 13:36:40 +01:00

342 lines
12 KiB
Plaintext

#define UI_TAB_CONFIG "CONFIG"
#define UI_TAB_LINKS "LINKS"
#define UI_TAB_FILTER "FILTER"
/**
* # Telecommunications Core
*
* The core of the entire telecomms operation
*
* This thing basically handles the main broadcasting of the data, as well as NTTC configs
* The relays dont do any actual processing, they are just objects which can bring tcomms to another zlevel
*/
/obj/machinery/tcomms/core
name = "Telecommunications Core"
desc = "A large rack full of communications equipment. Looks important."
icon_state = "core"
// This starts as off so you cant make cores as hot spares
active = FALSE
/// The NTTC config for this device
var/datum/nttc_configuration/nttc = new()
/// List of all reachable devices
var/list/reachable_zlevels = list()
/// List of all linked relays
var/list/linked_relays = list()
/// Password for linking stuff together
var/link_password
/// What tab of the UI were currently on
var/ui_tab = UI_TAB_CONFIG
/**
* Initializer for the core.
*
* Calls parent to ensure its added to the GLOB of tcomms machines, before generating a link password and adding itself to the list of reachable Zs.
*/
/obj/machinery/tcomms/core/Initialize(mapload)
. = ..()
link_password = GenerateKey()
reachable_zlevels |= loc.z
component_parts += new /obj/item/circuitboard/tcomms/core(null)
if(check_power_on())
active = TRUE
else
visible_message("<span class='warning'>Error: Another core is already active in this sector. Power-up cancelled due to radio interference.</span>")
update_icon()
if(mapload) //Automatically links new midround tcomms cores to the cc relay
return
var/obj/machinery/tcomms/relay/cc/cc_relay = locateUID(GLOB.cc_tcomms_relay_uid)
if(cc_relay?.linked_core) //if we are already linked, ignore!
return
cc_relay.AddLink(src)
/**
* Destructor for the core.
*
* Ensures that the machine is taken out of the global list when destroyed, and also unlinks all connected relays
*/
/obj/machinery/tcomms/core/Destroy()
for(var/obj/machinery/tcomms/relay/R in linked_relays)
R.Reset()
QDEL_NULL(nttc) // Delete the NTTC datum
linked_relays.Cut() // Just to be sure
return ..()
/**
* Helper to see if a zlevel is reachable
*
* This is a simple check to see if the input z-level is in the list of reachable ones
* Returns TRUE if it can, FALSE if it cant
*
* Arguments:
* * zlevel - The input z level to test
*/
/obj/machinery/tcomms/core/proc/zlevel_reachable(zlevel)
// Nothing is reachable if the core is offline, unpowered, or ion'd
if(!active || (stat & NOPOWER) || ion)
return FALSE
if(zlevel in reachable_zlevels)
return TRUE
else
return FALSE
/**
* Proc which takes in the message datum
*
* Some checks are ran on the signal, and NTTC is applied
* After that, it is broadcasted out to the required Z-levels
*
* Arguments:
* * tcm - The tcomms message datum
*/
/obj/machinery/tcomms/core/proc/handle_message(datum/tcomms_message/tcm)
// Don't do anything with rejected signals, if were offline, if we are ion'd, or if we have no power
if(tcm.reject || !active || (stat & NOPOWER) || ion)
return FALSE
// Kill the signal if its on a z-level that isnt reachable
if(!zlevel_reachable(tcm.source_level))
return FALSE
// Now we can run NTTC
tcm = nttc.modify_message(tcm)
// If the signal shouldnt be broadcast, dont broadcast it
if(!tcm.pass)
// We still return TRUE here because the signal was handled, even though we didnt broadcast
return TRUE
// Now we generate the list of where that signal should go to
tcm.zlevels = reachable_zlevels.Copy()
tcm.zlevels |= tcm.source_level
// Now check if they actually have pieces, if so, broadcast
if(tcm.message_pieces)
broadcast_message(tcm)
return TRUE
return FALSE
/**
* Proc to remake the list of available zlevels
*
* Loops through the list of connected relays and adds their zlevels in.
* This is called if a relay is added or removed
*
*/
/obj/machinery/tcomms/core/proc/refresh_zlevels()
// Refresh the list
reachable_zlevels = list()
// Add itself as a reachable Z-level
reachable_zlevels |= loc.z
// Add all the linked relays in
for(var/obj/machinery/tcomms/relay/R in linked_relays)
// Only if the relay is active
if(R.active && !(R.stat & NOPOWER))
reachable_zlevels |= R.loc.z
/**
* Z-Level transit change helper
*
* Handles parent call of disabling the machine if it changes Z-level, but also rebuilds the list of reachable levels
*/
/obj/machinery/tcomms/core/onTransitZ(old_z, new_z)
. = ..()
refresh_zlevels()
/**
* Power-on checker
*
* Checks the z-level to see if an existing core is already powered on, and deny this one turning on if there is one. Returns TRUE if it can power on, or FALSE if it cannot
*/
/obj/machinery/tcomms/core/proc/check_power_on()
// Cancel if we are already on
if(active)
return TRUE
for(var/obj/machinery/tcomms/core/C in GLOB.tcomms_machines)
// Make sure we dont check ourselves
if(C == src)
continue
// We dont care about ones on other zlevels
if(!atoms_share_level(C, src))
continue
// If another core is active, return FALSE
if(C.active)
if(C.stat & NOPOWER) // If another core has no power but is supposed to be on, we shut it down so we can continue.
C.active = FALSE // Since only one active core is allowed per z level, give priority to the one actually working.
C.update_icon()
else
return FALSE
// If we got here there isnt an active core on this Z-level. So return true
return TRUE
//////////////
// UI STUFF //
//////////////
/obj/machinery/tcomms/core/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
// This needs to happen here because of how late the language datum initializes. I dont like it
if(length(nttc.valid_languages) == 1)
nttc.update_languages()
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "TcommsCore", name, 900, 600, master_ui, state)
ui.open()
/obj/machinery/tcomms/core/ui_data(mob/user)
var/list/data = list()
data["ion"] = ion
// Z-level list. Note that this will also show sectors with hidden relay links, but you cant see the relays themselves
// This allows the crew to realise that sectors have hidden relays
data["sectors_available"] = "Count: [length(reachable_zlevels)] | List: [jointext(reachable_zlevels, " ")]"
// Toggles
data["active"] = active
data["nttc_toggle_jobs"] = nttc.toggle_jobs
data["nttc_toggle_job_color"] = nttc.toggle_job_color
data["nttc_toggle_name_color"] = nttc.toggle_name_color
data["nttc_toggle_command_bold"] = nttc.toggle_command_bold
// Strings
data["nttc_setting_language"] = nttc.setting_language
data["nttc_job_indicator_type"] = nttc.job_indicator_type
// Network ID
data["network_id"] = network_id
data["link_password"] = link_password
// You ready to see some awful shit?
var/list/relays = list()
for(var/obj/machinery/tcomms/relay/R in linked_relays)
// Dont show relays with a hidden link
if(R.hidden_link)
continue
// Assume false
var/status = FALSE
if(R.active && !(R.stat & NOPOWER))
status = TRUE
relays += list(list("addr" = "\ref[R]", "net_id" = R.network_id, "sector" = R.loc.z, "status" = status))
data["relay_entries"] = relays
// End the shit
data["filtered_users"] = nttc.filtering
return data
/obj/machinery/tcomms/core/ui_act(action, list/params)
// Check against href exploits
if(..())
return
. = TRUE
switch(action)
// All the toggle on/offs go here
if("toggle_active")
if(check_power_on())
active = !active
update_icon()
else
to_chat(usr, "<span class='warning'>Error: Another core is already active in this sector. Power-up cancelled due to radio interference.</span>")
// NTTC Toggles
if("nttc_toggle_jobs")
nttc.toggle_jobs = !nttc.toggle_jobs
log_action(usr, "toggled job tags (Now [nttc.toggle_jobs])")
if("nttc_toggle_job_color")
nttc.toggle_job_color = !nttc.toggle_job_color
log_action(usr, "toggled job colors (Now [nttc.toggle_job_color])")
if("nttc_toggle_name_color")
nttc.toggle_name_color = !nttc.toggle_name_color
log_action(usr, "toggled name colors (Now [nttc.toggle_name_color])")
if("nttc_toggle_command_bold")
nttc.toggle_command_bold = !nttc.toggle_command_bold
log_action(usr, "toggled command bold (Now [nttc.toggle_command_bold])")
// We need to be a little more fancy for the others
// Job Format
if("nttc_job_indicator_type")
var/card_style = input(usr, "Pick a job card format.", "Job Card Format") as null|anything in nttc.job_card_styles
if(!card_style)
return
nttc.job_indicator_type = card_style
to_chat(usr, "<span class='notice'>Jobs will now have the style of [card_style].</span>")
log_action(usr, "has set NTTC job card format to [card_style]")
// Language Settings
if("nttc_setting_language")
var/new_language = input(usr, "Pick a language to convert messages to.", "Language Conversion") as null|anything in nttc.valid_languages
if(!new_language)
return
if(new_language == "--DISABLE--")
nttc.setting_language = null
to_chat(usr, "<span class='notice'>Language conversion disabled.</span>")
else
nttc.setting_language = new_language
to_chat(usr, "<span class='notice'>Messages will now be converted to [new_language].</span>")
log_action(usr, new_language == "--DISABLE--" ? "disabled NTTC language conversion" : "set NTTC language conversion to [new_language]", TRUE)
// Imports and exports
if("import")
var/json = input(usr, "Provide configuration JSON below.", "Load Config", nttc.nttc_serialize()) as message
if(nttc.nttc_deserialize(json, usr.ckey))
log_action(usr, "has uploaded a NTTC JSON configuration: [ADMIN_SHOWDETAILS("Show", json)]", TRUE)
if("export")
usr << browse(nttc.nttc_serialize(), "window=save_nttc")
// Set network ID
if("network_id")
var/new_id = input(usr, "Please enter a new network ID", "Network ID", network_id)
log_action(usr, "renamed core with ID [network_id] to [new_id]")
to_chat(usr, "<span class='notice'>Device ID changed from <b>[network_id]</b> to <b>[new_id]</b>.</span>")
network_id = new_id
if("unlink")
var/obj/machinery/tcomms/relay/R = locate(params["addr"])
if(istype(R, /obj/machinery/tcomms/relay))
var/confirm = alert("Are you sure you want to unlink this relay?\nID: [R.network_id]\nADDR: \ref[R]", "Relay Unlink", "Yes", "No")
if(confirm == "Yes")
log_action(usr, "has unlinked tcomms relay with ID [R.network_id] from tcomms core with ID [network_id]", TRUE)
R.Reset()
else
to_chat(usr, "<span class='alert'><b>ERROR:</b> Relay not found. Please file an issue report.</span>")
if("change_password")
var/new_password = input(usr, "Please enter a new password","New Password", link_password)
log_action(usr, "has changed the password on core with ID [network_id] from [link_password] to [new_password]")
to_chat(usr, "<span class='notice'>Successfully changed password from <b>[link_password]</b> to <b>[new_password]</b>.</span>")
link_password = new_password
if("add_filter")
// This is a stripped input because I did NOT come this far for this system to be abused by HTML injection
var/name_to_add = html_decode(stripped_input(usr, "Enter a name to add to the filtering list", "Name Entry"))
if(name_to_add == "")
return
if(name_to_add in nttc.filtering)
to_chat(usr, "<span class='alert'><b>ERROR:</b> User already in filtering list.</span>")
else
nttc.filtering |= name_to_add
log_action(usr, "has added [name_to_add] to the NTTC filter list on core with ID [network_id]", TRUE)
to_chat(usr, "<span class='notice'>Successfully added <b>[name_to_add]</b> to the NTTC filtering list.</span>")
if("remove_filter")
var/name_to_remove = params["user"]
if(!(name_to_remove in nttc.filtering))
to_chat(usr, "<span class='alert'><b>ERROR:</b> Name does not exist in filter list. Please file an issue report.</span>")
else
var/confirm = alert(usr, "Are you sure you want to remove [name_to_remove] from the filtering list?", "Confirm Removal", "Yes", "No")
if(confirm == "Yes")
nttc.filtering -= name_to_remove
log_action(usr, "has removed [name_to_remove] from the NTTC filter list on core with ID [network_id]", TRUE)
to_chat(usr, "<span class='notice'>Successfully removed <b>[name_to_remove]</b> from the NTTC filtering list.</span>")
#undef UI_TAB_CONFIG
#undef UI_TAB_LINKS
#undef UI_TAB_FILTER