R&D Rework PT1 - The network refactor (#26420)

* R&D Rework PT1

* Give robotics access too

* Run prettier

* More lints

* This is INCREDIBLY ironic

* Re-add blacklisting

* Oops

* Review changes

* Some fixes

* Fix outstanding issues

* Warriorstar fixes

* Tiny tweak
This commit is contained in:
AffectedArc07
2024-09-08 16:38:17 +00:00
committed by GitHub
parent e87982e794
commit 03bc64ad13
34 changed files with 1773 additions and 724 deletions
+33 -1
View File
@@ -66,7 +66,8 @@ GLOBAL_LIST_INIT(admin_verbs_admin, list(
/client/proc/start_vote,
/client/proc/ping_all_admins,
/client/proc/show_watchlist,
/client/proc/debugstatpanel
/client/proc/debugstatpanel,
/client/proc/create_rnd_restore_disk
))
GLOBAL_LIST_INIT(admin_verbs_ban, list(
/client/proc/ban_panel,
@@ -1229,3 +1230,34 @@ GLOBAL_LIST_INIT(view_runtimes_verbs, list(
vis.set_content(ui_dat.Join(""))
vis.open(FALSE)
/client/proc/create_rnd_restore_disk()
set name = "Create RnD Backup Restore Disk"
set category = "Event" // Im putting this in event because the name is long and will offset everything
if(!check_rights(R_ADMIN))
return
var/list/targets = list()
for(var/rnc_uid in SSresearch.backups)
var/datum/rnd_backup/B = SSresearch.backups[rnc_uid]
targets["[B.last_name] - [B.last_timestamp]"] = rnc_uid
var/choice = input(src, "Select a backup to restore", "RnD Backup Restore") as null|anything in targets
if(!choice || !(choice in targets))
return
var/actual_target = targets[choice]
if(!(actual_target in SSresearch.backups))
return
var/datum/rnd_backup/B = SSresearch.backups[actual_target]
var/confirmation = alert("Are you sure you want to restore this RnD backup? The disk will spawn below your character.", "Are you sure?", "Yes", "No")
if(confirmation != "Yes")
return
B.to_backup_disk(get_turf(usr))
@@ -395,6 +395,7 @@
new /obj/item/circuitboard/destructive_analyzer(src)
new /obj/item/circuitboard/protolathe(src)
new /obj/item/circuitboard/rdconsole/public(src)
new /obj/item/circuitboard/rnd_network_controller(src)
new /obj/item/reagent_containers/glass/beaker(src)
new /obj/item/reagent_containers/glass/beaker(src)
new /obj/item/reagent_containers/glass/beaker(src)
+297
View File
@@ -0,0 +1,297 @@
/// R&D backup console - just saves tech levels
/obj/machinery/computer/rnd_backup
name = "R&D backup console"
desc = "Can be used to backup an R&D network's research data."
icon_screen = "comm_logs" // looks good enough
circuit = /obj/item/circuitboard/rnd_backup_console
/// ID to autolink to, used in mapload
var/autolink_id = null
/// UID of the network that we use
var/network_manager_uid = null
/// Inserted disk
var/obj/item/disk/rnd_backup_disk/inserted_disk
/obj/machinery/computer/rnd_backup/station
autolink_id = "station_rnd"
/obj/machinery/computer/rnd_backup/Initialize(mapload)
..()
return INITIALIZE_HINT_LATELOAD
/obj/machinery/computer/rnd_backup/LateInitialize()
for(var/obj/machinery/computer/rnd_network_controller/RNC in GLOB.rnd_network_managers)
if(RNC.network_name == autolink_id)
network_manager_uid = RNC.UID()
RNC.backupconsoles += UID()
/obj/machinery/computer/rnd_backup/Destroy()
unlink()
eject_disk()
return ..()
/obj/machinery/computer/rnd_backup/proc/unlink()
network_manager_uid = null
SStgui.update_uis(src)
/obj/machinery/computer/rnd_backup/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/disk/rnd_backup_disk) && istype(user, /mob/living/carbon/human))
var/mob/living/carbon/human/H = user
if(!H.unEquip(O))
return TRUE
O.forceMove(src)
inserted_disk = O
to_chat(user, "<span class='notice'>You insert [O] into [src].</span>")
SStgui.update_uis(src)
return TRUE
return ..()
/obj/machinery/computer/rnd_backup/proc/eject_disk()
if(!inserted_disk)
return
inserted_disk.forceMove(get_turf(src))
inserted_disk = null
/obj/machinery/computer/rnd_backup/attack_hand(mob/user)
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
ui_interact(user)
/obj/machinery/computer/rnd_backup/ui_data(mob/user)
var/list/data = list()
var/has_network = FALSE
var/list/tech_assoc_temp = list()
data["has_disk"] = FALSE
if(network_manager_uid)
var/obj/machinery/computer/rnd_network_controller/RNC = locateUID(network_manager_uid)
if(RNC)
var/datum/research/files = RNC.research_files
has_network = TRUE
data["linked"] = TRUE
data["network_name"] = RNC.network_name
for(var/tech_id in files.known_tech)
if(!(tech_id in tech_assoc_temp))
tech_assoc_temp[tech_id] = list()
var/datum/tech/T = files.known_tech[tech_id]
var/list/tech_data = tech_assoc_temp[tech_id]
tech_data["name"] = T.name
tech_data["network_level"] = T.level
else
network_manager_uid = null
if(inserted_disk)
data["has_disk"] = TRUE
data["disk_name"] = inserted_disk.name
data["last_timestamp"] = inserted_disk.last_backup_time || "None"
for(var/tech_id in inserted_disk.stored_tech_assoc)
if(!(tech_id in tech_assoc_temp))
tech_assoc_temp[tech_id] = list()
var/tech_name = GLOB.rnd_tech_id_to_name[tech_id]
var/list/tech_data = tech_assoc_temp[tech_id]
tech_data["name"] = tech_name
tech_data["disk_level"] = inserted_disk.stored_tech_assoc[tech_id]
if(!has_network)
data["linked"] = FALSE
var/list/controllers = list()
for(var/obj/machinery/computer/rnd_network_controller/RNC in GLOB.rnd_network_managers)
controllers += list(list("addr" = RNC.UID(), "net_id" = RNC.network_name))
data["controllers"] = controllers
data["techs"] = tech_assoc_temp
return data
/obj/machinery/computer/rnd_backup/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(..())
return
. = TRUE
switch(action)
if("unlink")
if(!network_manager_uid)
return FALSE
var/choice = tgui_alert(usr, "Are you SURE you want to unlink this backup console?\nYou won't be able to re-link without the network manager password", "Unlink", list("Yes", "No"))
if(choice == "Yes")
unlink()
if("eject_disk")
eject_disk()
if("savetech2network")
if(!network_manager_uid)
return FALSE
if(!inserted_disk)
return FALSE
var/tech = params["tech"]
var/obj/machinery/computer/rnd_network_controller/RNC = locateUID(network_manager_uid)
if(!RNC)
network_manager_uid = null
return FALSE
var/datum/tech/T = RNC.research_files.known_tech[tech]
if(!T)
return
var/choice = tgui_alert(usr, "Do you want to import this level to the network (Network level: [T.level] | Disk level: [inserted_disk.stored_tech_assoc[tech]])", "Data Import", "Yes", "No")
if(choice != "Yes")
return FALSE
T.level = inserted_disk.stored_tech_assoc[tech]
if("savetech2disk")
if(!network_manager_uid)
return FALSE
if(!inserted_disk)
return FALSE
var/tech = params["tech"]
var/obj/machinery/computer/rnd_network_controller/RNC = locateUID(network_manager_uid)
if(!RNC)
network_manager_uid = null
return FALSE
var/datum/tech/T = RNC.research_files.known_tech[tech]
if(!T)
return
var/choice = tgui_alert(usr, "Do you want to export this tech data to the disk (Network level: [T.level] | Disk level: [inserted_disk.stored_tech_assoc[tech]])", "Data Export", "Yes", "No")
if(choice != "Yes")
return FALSE
inserted_disk.stored_tech_assoc[tech] = T.level
inserted_disk.last_backup_time = time2text(ROUND_TIME, "hh:mm:ss")
if("saveall2network")
if(!network_manager_uid)
return FALSE
if(!inserted_disk)
return FALSE
var/obj/machinery/computer/rnd_network_controller/RNC = locateUID(network_manager_uid)
if(!RNC)
network_manager_uid = null
return FALSE
var/choice = tgui_alert(usr, "Are you SURE you want to import all the data on the disk to the network?", "Data Import", "Yes", "No")
if(choice != "Yes")
return FALSE
var/datum/research/files = RNC.research_files
for(var/tech_id in files.known_tech)
var/datum/tech/T = files.known_tech[tech_id]
T.level = inserted_disk.stored_tech_assoc[tech_id]
if("saveall2disk")
if(!network_manager_uid)
return FALSE
if(!inserted_disk)
return FALSE
var/obj/machinery/computer/rnd_network_controller/RNC = locateUID(network_manager_uid)
if(!RNC)
network_manager_uid = null
return FALSE
var/choice = tgui_alert(usr, "Are you SURE you want to export all the data on the network to the disk?", "Data Export", "Yes", "No")
if(choice != "Yes")
return FALSE
var/datum/research/files = RNC.research_files
for(var/tech_id in files.known_tech)
var/datum/tech/T = files.known_tech[tech_id]
inserted_disk.stored_tech_assoc[tech_id] = T.level
inserted_disk.last_backup_time = time2text(ROUND_TIME, "hh:mm:ss")
if("linktonetworkcontroller")
if(network_manager_uid)
return FALSE
var/obj/machinery/computer/rnd_network_controller/C = locateUID(params["target_controller"])
if(istype(C, /obj/machinery/computer/rnd_network_controller))
var/user_pass = tgui_input_text(usr, "Please enter network password", "Password Entry")
// Check the password
if(user_pass == C.network_password)
network_manager_uid = C.UID()
to_chat(usr, "<span class='notice'>Successfully linked to <b>[C.network_name]</b>.</span>")
else
to_chat(usr, "<span class='alert'><b>ERROR:</b> Password incorrect.</span>")
else
to_chat(usr, "<span class='alert'><b>ERROR:</b> Controller not found. Please file an issue report.</span>")
/obj/machinery/computer/rnd_backup/ui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "RndBackupConsole", name)
ui.open()
// The disk itself - does nothing other than exist to hold variables.
/obj/item/disk/rnd_backup_disk
name = "rnd backup disk"
desc = "A disk for storing technology data for backup purposes."
icon_state = "datadisk2"
materials = list(MAT_METAL = 30, MAT_GLASS = 10)
/// Assoc list of tech levels. Key is tech ID, value is tech level
var/list/stored_tech_assoc = list()
/// Text of last backup time
var/last_backup_time
/obj/item/disk/rnd_backup_disk/Initialize(mapload)
. = ..()
pixel_x = rand(-5, 5)
pixel_y = rand(-5, 5)
// Level it all out
for(var/tech_id in GLOB.rnd_tech_id_to_name)
stored_tech_assoc[tech_id] = 0
/obj/item/disk/rnd_backup_disk/examine(mob/user)
. = ..()
if(last_backup_time)
. += "The timestamp label reads '[last_backup_time]'."
else
. += "The timestamp label is empty."
/obj/item/disk/rnd_backup_disk/admin
name = "admin rnd backup disk"
desc = "You shouldnt have this."
/obj/item/disk/rnd_backup_disk/admin/Initialize(mapload)
. = ..()
// Just make it 10 on everything - who cares
for(var/tech_id in GLOB.rnd_tech_id_to_name)
stored_tech_assoc[tech_id] = 10
@@ -243,13 +243,23 @@
category = list("Computer Boards")
/datum/design/rdservercontrol
name = "Console Board (R&D Server Control Console)"
desc = "The circuit board for a R&D Server Control Console"
id = "rdservercontrol"
name = "Console Board (R&D Network Controller)"
desc = "The circuit board for a R&D Network Controller Console"
id = "rdnetworkcontrol"
req_tech = list("programming" = 3)
build_type = IMPRINTER
materials = list(MAT_GLASS = 1000)
build_path = /obj/item/circuitboard/rdservercontrol
build_path = /obj/item/circuitboard/rnd_network_controller
category = list("Computer Boards")
/datum/design/rdbackup
name = "Console Board (R&D Backup)"
desc = "The circuit board for a R&D Backup Console"
id = "rdbackup"
req_tech = list("programming" = 3)
build_type = IMPRINTER
materials = list(MAT_GLASS = 1000)
build_path = /obj/item/circuitboard/rnd_backup_console
category = list("Computer Boards")
/datum/design/robocontrol
@@ -51,6 +51,17 @@
build_path = /obj/item/disk/tech_disk
category = list("Miscellaneous")
/datum/design/backup_disk
name = "Technology Backup Disk"
desc = "Produce additional backup disks for storing technology data."
id = "backup_disk"
req_tech = list("programming" = 1)
build_type = PROTOLATHE | AUTOLATHE
materials = list(MAT_METAL = 300, MAT_GLASS = 100)
build_path = /obj/item/disk/rnd_backup_disk
category = list("Miscellaneous")
/datum/design/training_disk
name = "Training Authentification Disk"
desc = "Replacement authentication disk for the nuclear training bomb."
+4 -1
View File
@@ -574,8 +574,11 @@
if(dotype != FAIL)
if(process && process.origin_tech)
var/list/temp_tech = ConvertReqString2List(process.origin_tech)
var/datum/research/F = linked_console.get_files()
if(!F)
return
for(var/T in temp_tech)
linked_console.files.UpdateTech(T, temp_tech[T])
F.UpdateTech(T, temp_tech[T])
updateUsrDialog()
return
+136 -110
View File
@@ -65,13 +65,20 @@ won't update every console in existence) but it's more of a hassle to do. Also,
icon_keyboard = "rd_key"
light_color = LIGHT_COLOR_FADEDPURPLE
circuit = /obj/item/circuitboard/rdconsole
var/datum/research/files //Stores all the collected research data.
var/obj/item/disk/tech_disk/t_disk = null //Stores the technology disk.
var/obj/item/disk/design_disk/d_disk = null //Stores the design disk.
var/obj/machinery/r_n_d/destructive_analyzer/linked_destroy = null //Linked Destructive Analyzer
var/obj/machinery/r_n_d/protolathe/linked_lathe = null //Linked Protolathe
var/obj/machinery/r_n_d/circuit_imprinter/linked_imprinter = null //Linked Circuit Imprinter
/// Holder for our inserted technology disk
var/obj/item/disk/tech_disk/t_disk = null
/// Holder for the inserted design disk
var/obj/item/disk/design_disk/d_disk = null
/// Linked destructive analyser
var/obj/machinery/r_n_d/destructive_analyzer/linked_destroy = null
/// Linked protolathe
var/obj/machinery/r_n_d/protolathe/linked_lathe = null
/// Linked circuit imprinter
var/obj/machinery/r_n_d/circuit_imprinter/linked_imprinter = null
/// ID to autolink to, used in mapload
var/autolink_id = null
/// UID of the network that we use
var/network_manager_uid = null
/// The ID of the top-level menu, such as protolathe, analyzer, etc.
var/menu = MENU_MAIN
@@ -81,22 +88,24 @@ won't update every console in existence) but it's more of a hassle to do. Also,
var/submenu_imprinter = SUBMENU_PRINTER_MAIN
var/wait_message = 0
var/wait_message_timer = 0
var/id = 0 //ID of the computer (for server restrictions).
var/sync = TRUE //If sync if FALSE, it doesn't show up on Server Control Console
///Range to search for rnd devices in proximity to console
var/range = 3
req_access = list(ACCESS_TOX) //Data and setting manipulation requires scientist access.
req_one_access = list(ACCESS_TOX, ACCESS_ROBOTICS)
var/selected_category
var/list/datum/design/matching_designs = list() //for the search function
/proc/CallTechName(ID) //A simple helper proc to find the name of a tech with a given ID.
for(var/T in subtypesof(/datum/tech))
var/datum/tech/tt = T
if(initial(tt.id) == ID)
return initial(tt.name)
/obj/machinery/computer/rdconsole/proc/get_files()
if(!network_manager_uid)
return null
var/obj/machinery/computer/rnd_network_controller/RNC = locateUID(network_manager_uid)
if(!RNC)
network_manager_uid = null
return null
return RNC.research_files
/proc/CallMaterialName(return_name)
switch(return_name)
@@ -134,27 +143,19 @@ won't update every console in existence) but it's more of a hassle to do. Also,
linked_imprinter = D
D.linked_console = src
//Have it automatically push research to the centcom server so wild griffins can't fuck up R&D's work --NEO
/obj/machinery/computer/rdconsole/proc/griefProtection()
for(var/obj/machinery/r_n_d/server/centcom/C in GLOB.machines)
files.push_data(C.files)
/obj/machinery/computer/rdconsole/proc/Maximize()
for(var/datum/tech/T in files.possible_tech)
files.known_tech[T.id] = T
for(var/v in files.known_tech)
var/datum/tech/KT = files.known_tech[v]
KT.level = 8
files.RefreshResearch()
/obj/machinery/computer/rdconsole/Initialize(mapload)
. = ..()
files = new /datum/research(src) //Setup the research data holder.
matching_designs = list()
SyncRDevices()
return INITIALIZE_HINT_LATELOAD
/obj/machinery/computer/rdconsole/LateInitialize()
for(var/obj/machinery/computer/rnd_network_controller/RNC in GLOB.rnd_network_managers)
if(RNC.network_name == autolink_id)
network_manager_uid = RNC.UID()
RNC.consoles += UID()
/obj/machinery/computer/rdconsole/Destroy()
QDEL_NULL(files)
QDEL_NULL(t_disk)
QDEL_NULL(d_disk)
matching_designs.Cut()
@@ -168,16 +169,16 @@ won't update every console in existence) but it's more of a hassle to do. Also,
linked_imprinter.linked_console = null
linked_imprinter = null
var/obj/machinery/computer/rnd_network_controller/RNC = locateUID(network_manager_uid)
if(RNC)
// Unlink us
RNC.consoles -= UID()
if(wait_message_timer)
deltimer(wait_message_timer)
wait_message_timer = 0
return ..()
/* Instead of calling this every tick, it is only being called when needed
/obj/machinery/computer/rdconsole/process()
griefProtection()
*/
/obj/machinery/computer/rdconsole/attackby(obj/item/D as obj, mob/user as mob, params)
//Loading a disk into it.
@@ -202,8 +203,8 @@ won't update every console in existence) but it's more of a hassle to do. Also,
/obj/machinery/computer/rdconsole/emag_act(user as mob)
if(!emagged)
playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1)
req_access = list()
playsound(get_turf(src), 'sound/effects/sparks4.ogg', 75, 1)
req_one_access = list()
emagged = TRUE
to_chat(user, "<span class='notice'>You disable the security protocols</span>")
return TRUE
@@ -230,6 +231,9 @@ won't update every console in existence) but it's more of a hassle to do. Also,
/obj/machinery/computer/rdconsole/proc/update_from_disk()
clear_wait_message()
var/datum/research/files = get_files()
if(!files)
return
if(d_disk && d_disk.blueprint)
files.AddDesign2Known(d_disk.blueprint)
else if(t_disk && t_disk.tech_id)
@@ -237,36 +241,6 @@ won't update every console in existence) but it's more of a hassle to do. Also,
if(!isnull(tech))
tech.level = t_disk.tech_level
SStgui.update_uis(src)
griefProtection() //Update centcom too
/obj/machinery/computer/rdconsole/proc/sync_research()
if(!sync)
return
var/list/temp_unblacklist = files.unblacklisted_designs
files.unblacklisted_designs = list() //Remove this asap, else it will stick around
clear_wait_message()
for(var/obj/machinery/r_n_d/server/S in GLOB.machines)
var/server_processed = FALSE
if((id in S.id_with_upload) || istype(S, /obj/machinery/r_n_d/server/centcom))
S.files.blacklisted_designs -= temp_unblacklist
files.push_data(S.files)
server_processed = TRUE
if(((id in S.id_with_download) && !istype(S, /obj/machinery/r_n_d/server/centcom)))
S.files.push_data(files)
server_processed = TRUE
if(!istype(S, /obj/machinery/r_n_d/server/centcom) && server_processed)
S.produce_heat(100)
SStgui.update_uis(src)
/obj/machinery/computer/rdconsole/proc/reset_research()
qdel(files)
files = new /datum/research(src)
clear_wait_message()
SStgui.update_uis(src)
/obj/machinery/computer/rdconsole/proc/find_devices()
SyncRDevices()
@@ -285,6 +259,10 @@ won't update every console in existence) but it's more of a hassle to do. Also,
to_chat(user, "<span class='danger'>[linked_destroy] appears to be empty.</span>")
return
var/datum/research/files = get_files()
if(!files)
return
var/list/temp_tech = linked_destroy.ConvertReqString2List(linked_destroy.loaded_item.origin_tech)
var/pointless = FALSE
@@ -322,6 +300,10 @@ won't update every console in existence) but it's more of a hassle to do. Also,
if(!linked_destroy || !temp_tech)
return
var/datum/research/files = get_files()
if(!files)
return
if(!linked_destroy.loaded_item)
to_chat(user, "<span class='danger'>[linked_destroy] appears to be empty.</span>")
else
@@ -357,6 +339,10 @@ won't update every console in existence) but it's more of a hassle to do. Also,
to_chat(usr, "<span class='danger'>No linked device detected.</span>")
return
var/datum/research/files = get_files()
if(!files)
return
var/is_lathe = istype(machine, /obj/machinery/r_n_d/protolathe)
var/is_imprinter = istype(machine, /obj/machinery/r_n_d/circuit_imprinter)
@@ -469,6 +455,44 @@ won't update every console in existence) but it's more of a hassle to do. Also,
add_fingerprint(ui.user)
// We switch these actions first because they can be done without files
switch(action)
if("unlink")
if(!network_manager_uid)
return
var/choice = tgui_alert(usr, "Are you SURE you want to unlink this console?\nYou won't be able to re-link without the network manager password", "Unlink", list("Yes", "No"))
if(choice == "Yes")
unlink()
return TRUE
// You should only be able to link if its not linked, to prevent weirdness
if("linktonetworkcontroller")
if(network_manager_uid)
return
var/obj/machinery/computer/rnd_network_controller/C = locateUID(params["target_controller"])
if(istype(C, /obj/machinery/computer/rnd_network_controller))
if(!atoms_share_level(C, src))
return
var/user_pass = input(usr, "Please enter network password", "Password Entry")
// Check the password
if(user_pass == C.network_password)
network_manager_uid = C.UID()
to_chat(usr, "<span class='notice'>Successfully linked to <b>[C.network_name]</b>.</span>")
else
to_chat(usr, "<span class='alert'><b>ERROR:</b> Password incorrect.</span>")
else
to_chat(usr, "<span class='alert'><b>ERROR:</b> Controller not found. Please file an issue report.</span>")
return TRUE
// Now we do a files check
var/datum/research/files = get_files()
if(!files)
to_chat(usr, "<span class='danger'>Error - No research network linked.</span>")
return
switch(action)
if("nav") //Switches menu screens. Converts a sent text string into a number. Saves a LOT of code.
var/next_menu = text2num(params["menu"])
@@ -573,29 +597,9 @@ won't update every console in existence) but it's more of a hassle to do. Also,
linked_destroy.loaded_item = null
linked_destroy.icon_state = "d_analyzer"
if("maxresearch")
if(!check_rights(R_ADMIN))
return
if(tgui_alert(ui.user, "Are you sure you want to maximize research levels?", "Confirmation", list("Yes", "No")) != "Yes")
return
log_admin("[key_name(ui.user)] has maximized the research levels.")
message_admins("[key_name_admin(ui.user)] has maximized the research levels.")
Maximize()
griefProtection() //Update centcomm too
if("deconstruct") //Deconstruct the item in the destructive analyzer and update the research holder.
start_destroyer(ui.user)
if("sync") //Sync the research holder with all the R&D consoles in the game that aren't sync protected.
if(!sync)
to_chat(ui.user, "<span class='danger'>You must connect to the network first!</span>")
else
add_wait_message("Syncing Database...", SYNC_RESEARCH_DELAY)
addtimer(CALLBACK(src, PROC_REF(sync_research)), SYNC_RESEARCH_DELAY)
if("togglesync") //Prevents the console from being synced by other consoles. Can still send data.
sync = !sync
if("build") //Causes the Protolathe to build something.
start_machine(linked_lathe, params["id"], text2num(params["amount"]))
@@ -645,13 +649,6 @@ won't update every console in existence) but it's more of a hassle to do. Also,
linked_imprinter = null
submenu_imprinter = SUBMENU_PRINTER_MAIN
if("reset") //Reset the R&D console's database.
griefProtection()
var/choice = tgui_alert(ui.user, "Are you sure you want to reset the R&D console's database? Data lost cannot be recovered.", "R&D Console Database Reset", list("Continue", "Cancel"))
if(choice == "Continue")
add_wait_message("Resetting Database...", RESET_RESEARCH_DELAY)
addtimer(CALLBACK(src, PROC_REF(reset_research)), RESET_RESEARCH_DELAY)
if("search") //Search for designs with name matching pattern
var/query = params["to_search"]
var/compare
@@ -683,8 +680,35 @@ won't update every console in existence) but it's more of a hassle to do. Also,
selected_category = "Search Results for '[query]'"
if("unlink")
if(!network_manager_uid)
return
var/choice = alert(usr, "Are you SURE you want to unlink this console?\nYou wont be able to re-link without the network manager password", "Unlink","Yes","No")
if(choice == "Yes")
unlink()
// You should only be able to link if its not linked, to prevent weirdness
if("linktonetworkcontroller")
if(network_manager_uid)
return
var/obj/machinery/computer/rnd_network_controller/C = locateUID(params["target_controller"])
if(istype(C, /obj/machinery/computer/rnd_network_controller))
var/user_pass = input(usr, "Please enter network password", "Password Entry")
// Check the password
if(user_pass == C.network_password)
network_manager_uid = C.UID()
to_chat(usr, "<span class='notice'>Successfully linked to <b>[C.network_name]</b>.</span>")
else
to_chat(usr, "<span class='alert'><b>ERROR:</b> Password incorrect.</span>")
else
to_chat(usr, "<span class='alert'><b>ERROR:</b> Controller not found. Please file an issue report.</span>")
return TRUE // update uis
/obj/machinery/computer/rdconsole/proc/unlink()
network_manager_uid = null
SStgui.update_uis(src)
/obj/machinery/computer/rdconsole/attack_hand(mob/user)
if(..())
@@ -798,6 +822,20 @@ won't update every console in existence) but it's more of a hassle to do. Also,
/obj/machinery/computer/rdconsole/ui_data(mob/user)
var/list/data = list()
var/datum/research/files = get_files()
// If we have no linked files, dont even process anything else, just get a link up
if(!files)
data["linked"] = FALSE
var/list/controllers = list()
for(var/obj/machinery/computer/rnd_network_controller/RNC in GLOB.rnd_network_managers)
if(atoms_share_level(RNC, src))
controllers += list(list("addr" = RNC.UID(), "net_id" = RNC.network_name))
data["controllers"] = controllers
return data
data["linked"] = TRUE
files.RefreshResearch()
data["menu"] = menu
@@ -809,8 +847,6 @@ won't update every console in existence) but it's more of a hassle to do. Also,
data["linked_destroy"] = linked_destroy ? 1 : 0
data["linked_lathe"] = linked_lathe ? 1 : 0
data["linked_imprinter"] = linked_imprinter ? 1 : 0
data["sync"] = sync
data["admin"] = check_rights(R_ADMIN, FALSE, user)
data["disk_type"] = d_disk ? "design" : (t_disk ? "tech" : null)
data["disk_data"] = null
data["loaded_item"] = null
@@ -943,27 +979,17 @@ won't update every console in existence) but it's more of a hassle to do. Also,
/obj/machinery/computer/rdconsole/core
name = "core R&D console"
desc = "A console used to interface with R&D tools."
id = 1
/obj/machinery/computer/rdconsole/robotics
name = "robotics R&D console"
desc = "A console used to interface with R&D tools."
id = 2
req_access = list(ACCESS_ROBOTICS)
circuit = /obj/item/circuitboard/rdconsole/robotics
autolink_id = "station_rnd"
/obj/machinery/computer/rdconsole/experiment
name = "\improper E.X.P.E.R.I-MENTOR R&D console"
desc = "A console used to interface with R&D tools."
id = 3
autolink_id = "station_rnd"
range = 5
circuit = /obj/item/circuitboard/rdconsole/experiment
/obj/machinery/computer/rdconsole/public
name = "public R&D console"
desc = "A console used to interface with R&D tools."
id = 5
req_access = list()
req_one_access = list()
circuit = /obj/item/circuitboard/rdconsole/public
#undef TECH_UPDATE_DELAY
+1
View File
@@ -8,6 +8,7 @@
anchored = TRUE
var/busy = FALSE
var/obj/machinery/computer/rdconsole/linked_console
// Why is this scoped here????????
var/obj/item/loaded_item = null
var/datum/component/material_container/materials //Store for hyper speed!
var/efficiency_coeff = 1
+13 -8
View File
@@ -44,16 +44,21 @@ research holder datum.
** Includes all the helper procs and basic tech processing. **
***************************************************************/
/// Holder for all the existing, archived, and known tech. Individual to console.
/// Holder for all the existing, archived, and known tech. Individual to each network controller.
/datum/research
// These lists hold datum/tech
//Datum/tech go here.
// Possible is a list of direct datum references
// known is a list of id -> datum mappings
var/list/possible_tech = list() //List of all tech in the game that players have access to (barring special events).
var/list/known_tech = list() //List of locally known tech.
var/list/possible_designs = list() //List of all designs
var/list/known_designs = list() //List of available designs
// Possible is a list of direct datum references known is a list of id -> datum mappings
var/list/possible_tech = list()
/// List of locally known tech.
var/list/known_tech = list()
/// List of all designs
var/list/possible_designs = list()
/// List of available designs
var/list/known_designs = list()
/// List of designs that have been blacklisted by the server controller
var/list/blacklisted_designs = list()
/// Used during the rnd sync system, to ensure that blacklists are reverted, then cleared.
@@ -0,0 +1,327 @@
GLOBAL_LIST_EMPTY(rnd_network_managers)
/obj/machinery/computer/rnd_network_controller
// Dont call this R&D, you break tooltips from the &
name = "\improper RnD network manager"
desc = "Use this to manage an R&D network and its connected servers"
icon_screen = "rnd_netmanager"
icon_keyboard = "rd_key"
light_color = LIGHT_COLOR_FADEDPURPLE
circuit = /obj/item/circuitboard/rnd_network_controller
/// List of R&D servers connected. Soft-refs only.
var/list/servers = list()
/// List of R&D consoles connected. Soft-refs only.
var/list/consoles = list()
/// List of mechfabs connected. Soft-refs only.
var/list/mechfabs = list()
/// List of backup consoles. Soft-refs only.
var/list/backupconsoles = list()
/// The files for all the research data on this system
var/datum/research/research_files
/// The link ID of this console, used for map purposes
var/network_name = null
/// The network password for this device
var/network_password
/obj/machinery/computer/rnd_network_controller/Initialize()
. = ..()
GLOB.rnd_network_managers += src
research_files = new
network_password = GenerateKey()
// Make sure that name isnt already in use
if(network_name)
network_name = trim(network_name)
if(name_check(network_name))
var/myuid = UID()
stack_trace("[src] at [x],[y],[z] tried to init with a network name of [network_name] when its already in use. Name has been randomised to [myuid]")
network_name = myuid
if(!network_name)
network_name = UID()
/**
* Name sanity check
*
* Makes sure the target network name isnt already in use. Returns TRUE or FALSE depending on that criteria.
* Arguments:
* * pending_name - The name to check
*/
/obj/machinery/computer/rnd_network_controller/proc/name_check(pending_name)
var/list/all_names = list()
for(var/obj/machinery/computer/rnd_network_controller/RNC in GLOB.rnd_network_managers)
if(RNC == src)
continue
all_names += RNC.network_name
return (pending_name in all_names)
/obj/machinery/computer/rnd_network_controller/Destroy()
GLOB.rnd_network_managers -= src
// Inform admins - this is kinda round impacting
if(usr)
message_admins("[key_name_admin(usr)] destroyed [src] at [src ? "[get_location_name(src, TRUE)] [COORD(src)]" : "nonexistent location"] [ADMIN_JMP(src)]. If this was a non-antag please investigate as it has major round implications.")
// Unlink all attached servers
for(var/server_uid in servers)
var/obj/machinery/r_n_d/server/S = locateUID(server_uid)
if(!S)
continue
S.unlink()
// Unlink all attached consoles
for(var/console_uid in consoles)
var/obj/machinery/computer/rdconsole/RDC = locateUID(console_uid)
if(!RDC)
continue
RDC.unlink()
// Unlink all attached mechfabs
for(var/mechfab_uid in mechfabs)
var/obj/machinery/mecha_part_fabricator/MF = locateUID(mechfab_uid)
if(!MF)
continue
MF.unlink()
// Unlink all attached backup consoles
for(var/backupconsoles_uid in backupconsoles)
var/obj/machinery/computer/rnd_backup/BC = locateUID(backupconsoles_uid)
if(!BC)
continue
BC.unlink()
QDEL_NULL(research_files)
return ..()
/obj/machinery/computer/rnd_network_controller/screwdriver_act(mob/user, obj/item/I)
var/areyousure = tgui_alert(user, "Disassembling this console will wipe its network's RnD progress from this round. If you are doing this as a non-antag, expect a bollocking.\n\nAre you sure?", "Think for a moment", list("Yes", "No"))
if(areyousure != "Yes")
return TRUE // Dont attack the console, pretend we did something
return ..()
/obj/machinery/computer/rnd_network_controller/attack_hand(mob/user)
ui_interact(user)
/obj/machinery/computer/rnd_network_controller/ui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "RndNetController", name)
ui.open()
/obj/machinery/computer/rnd_network_controller/ui_data(mob/user)
var/list/data = list()
data["network_password"] = network_password
data["network_name"] = network_name
var/list/devices = list()
for(var/server_uid in servers)
var/obj/machinery/r_n_d/server/S = locateUID(server_uid)
if(!S)
servers -= server_uid
continue
devices += list(list("name" = S.name, "id" = S.UID(), "dclass" = "SRV"))
for(var/console_uid in consoles)
var/obj/machinery/computer/rdconsole/RDC = locateUID(console_uid)
if(!RDC)
consoles -= console_uid
continue
devices += list(list("name" = RDC.name, "id" = RDC.UID(), "dclass" = "RDC"))
for(var/mechfab_uid in mechfabs)
var/obj/machinery/mecha_part_fabricator/MF = locateUID(mechfab_uid)
if(!MF)
mechfabs -= mechfab_uid
continue
devices += list(list("name" = MF.name, "id" = MF.UID(), "dclass" = "MFB"))
for(var/backup_uid in backupconsoles)
var/obj/machinery/computer/rnd_backup/RB = locateUID(backup_uid)
if(!RB)
backupconsoles -= backup_uid
continue
devices += list(list("name" = RB.name, "id" = RB.UID(), "dclass" = "BCK"))
data["devices"] = devices
var/list/designs = list()
// Handle design blacklisting and unblacklisting
for(var/datum/design/D in research_files.possible_designs)
if(!(D.id in research_files.known_designs) && !(D.id in research_files.blacklisted_designs))
continue
var/list/design_data = list()
design_data["name"] = D.name
design_data["id"] = D.id
design_data["blacklisted"] = (D.id in research_files.blacklisted_designs)
design_data["uid"] = D.UID()
designs += list(design_data)
data["designs"] = designs
return data
/obj/machinery/computer/rnd_network_controller/ui_act(action, list/params)
if(..())
return
. = TRUE
switch(action)
// Set network name
if("network_name")
var/new_name = tgui_input_text(usr, "Please enter a new network ID", "Network ID", network_name)
if(!Adjacent(usr) || !new_name)
return
new_name = trim(new_name)
if(length(new_name) == 0)
return
if(name_check(new_name))
to_chat(usr, "<span class='warning'>Error, network name <code>[new_name]</code> already in use.</span>")
return
to_chat(usr, "<span class='notice'>Network name changed from <code>[network_name]</code> to <code>[new_name]</code>.</span>")
network_name = new_name
if("blacklist_design")
var/design_uid = params["d_uid"]
var/datum/design/D = locateUID(design_uid)
// If null design, ignore
if(!istype(D))
return
// If not one of our designs, disallow
if(!(D.id in research_files.known_designs))
return
message_admins("[key_name_admin(usr)] blacklisted [D.name] from the R&D network [network_name].")
log_game("[key_name(usr)] blacklisted [D.name] from the R&D network [network_name].")
research_files.known_designs -= D.id
research_files.blacklisted_designs += D.id
research_files.RefreshResearch()
if("unblacklist_design")
var/design_uid = params["d_uid"]
var/datum/design/D = locateUID(design_uid)
// If null design, ignore
if(!istype(D, /datum/design))
return
// If not one of our designs, disallow
if(!(D.id in research_files.blacklisted_designs))
return
message_admins("[key_name_admin(usr)] unblacklisted [D.name] from the R&D network [network_name].")
log_game("[key_name(usr)] unblacklisted [D.name] from the R&D network [network_name].")
research_files.unblacklisted_designs += D.id
research_files.blacklisted_designs -= D.id
research_files.RefreshResearch()
// Set network password
if("network_password")
var/new_password = tgui_input_text(usr, "Please enter a new network ID", "Network ID", network_password)
if(!Adjacent(usr))
return
to_chat(usr, "<span class='notice'>Network password changed from <code>[network_password]</code> to <code>[new_password]</code>.</span>")
network_password = new_password
// Remove a device
if("unlink_device")
switch(params["dclass"])
if("SRV")
if(!(params["uid"] in servers))
message_admins("[key_name_admin(usr)] attempted a href exploit with [src]")
return
var/choice = tgui_alert(usr, "Are you SURE you want to unlink this device?", "Unlink", list("Yes", "No"))
if(choice != "Yes" || !Adjacent(usr))
return
var/obj/machinery/r_n_d/server/S = locateUID(params["uid"])
servers -= params["uid"]
if(S)
S.unlink()
to_chat(usr, "<span class='notice'>Successfully unlinked <code>[S.name]</code> from the network <code>[network_name]</code>")
return
if("RDC")
if(!(params["uid"] in consoles))
message_admins("[key_name_admin(usr)] attempted a href exploit with [src]")
return
var/choice = tgui_alert(usr, "Are you SURE you want to unlink this device?", "Unlink", list("Yes", "No"))
if(choice != "Yes" || !Adjacent(usr))
return
var/obj/machinery/computer/rdconsole/RDC = locateUID(params["uid"])
consoles -= params["uid"]
if(RDC)
RDC.unlink()
to_chat(usr, "<span class='notice'>Successfully unlinked <code>[RDC.name]</code> from the network <code>[network_name]</code>")
return
if("MFB")
if(!(params["uid"] in mechfabs))
message_admins("[key_name_admin(usr)] attempted a href exploit with [src]")
return
var/choice = tgui_alert(usr, "Are you SURE you want to unlink this device?", "Unlink", list("Yes", "No"))
if(choice != "Yes" || !Adjacent(usr))
return
var/obj/machinery/mecha_part_fabricator/MPF = locateUID(params["uid"])
mechfabs -= params["uid"]
if(MPF)
MPF.unlink()
to_chat(usr, "<span class='notice'>Successfully unlinked <code>[MPF.name]</code> from the network <code>[network_name]</code>")
return
if("BCK")
if(!(params["uid"] in backupconsoles))
message_admins("[key_name_admin(usr)] attempted a href exploit with [src]")
return
var/choice = tgui_alert(usr, "Are you SURE you want to unlink this device?", "Unlink", list("Yes", "No"))
if(choice != "Yes" || !Adjacent(usr))
return
var/obj/machinery/computer/rnd_backup/RB = locateUID(params["uid"])
backupconsoles -= params["uid"]
if(RB)
RB.unlink()
to_chat(usr, "<span class='notice'>Successfully unlinked <code>[RB.name]</code> from the network <code>[network_name]</code></span>")
return
// Presets
/obj/machinery/computer/rnd_network_controller/station
network_name = "station_rnd"
/obj/machinery/computer/rnd_network_controller/golems
network_name = "golems_rnd"
+92 -335
View File
@@ -1,48 +1,33 @@
// These currently dont actually do anything
// They will serve a purpose once the R&D rework is done
/obj/machinery/r_n_d/server
name = "R&D Server"
name = "\improper R&D Server"
icon = 'icons/obj/machines/research.dmi'
icon_state = "RD-server-off"
var/datum/research/files
var/health = 100
var/list/id_with_upload = list() //List of R&D consoles with upload to server access.
var/list/id_with_download = list() //List of R&D consoles with download from server access.
var/id_with_upload_string = "" //String versions for easy editing in map editor.
var/id_with_download_string = ""
var/server_id = 0
var/heat_gen = 100
var/heating_power = 40000
var/delay = 10
req_access = list(ACCESS_RD) //Only the R&D can change server settings.
var/plays_sound = 0
/// ID to autolink to, used in mapload
var/autolink_id = null
/// UID of the network that we use
var/network_manager_uid = null
/obj/machinery/r_n_d/server/Initialize(mapload)
. = ..()
..()
component_parts = list()
component_parts += new /obj/item/circuitboard/rdserver(null)
component_parts += new /obj/item/stock_parts/scanning_module(null)
component_parts += new /obj/item/stack/cable_coil(null,1)
component_parts += new /obj/item/stack/cable_coil(null,1)
RefreshParts()
initialize_serv(); //Agouri // fuck you agouri
return INITIALIZE_HINT_LATELOAD
/obj/machinery/r_n_d/server/upgraded/Initialize(mapload)
. = ..()
component_parts = list()
component_parts += new /obj/item/circuitboard/rdserver(null)
component_parts += new /obj/item/stock_parts/scanning_module/phasic(null)
component_parts += new /obj/item/stack/cable_coil(null,1)
component_parts += new /obj/item/stack/cable_coil(null,1)
RefreshParts()
/obj/machinery/r_n_d/server/Destroy()
griefProtection()
return ..()
/obj/machinery/r_n_d/server/LateInitialize()
for(var/obj/machinery/computer/rnd_network_controller/RNC in GLOB.rnd_network_managers)
if(RNC.network_name == autolink_id)
network_manager_uid = RNC.UID()
RNC.servers += UID()
/obj/machinery/r_n_d/server/RefreshParts()
var/tot_rating = 0
for(var/obj/item/stock_parts/SP in src)
tot_rating += SP.rating
heat_gen /= max(1, tot_rating)
/obj/machinery/r_n_d/server/update_icon_state()
if(stat & NOPOWER)
@@ -50,341 +35,113 @@
else
icon_state = "RD-server-on"
/obj/machinery/r_n_d/server/power_change()
if(!..())
return
update_icon(UPDATE_ICON_STATE)
/obj/machinery/r_n_d/server/proc/initialize_serv()
if(!files)
files = new /datum/research(src)
var/list/temp_list
if(!length(id_with_upload))
temp_list = list()
temp_list = splittext(id_with_upload_string, ";")
for(var/N in temp_list)
id_with_upload += text2num(N)
if(!length(id_with_download))
temp_list = list()
temp_list = splittext(id_with_download_string, ";")
for(var/N in temp_list)
id_with_download += text2num(N)
/obj/machinery/r_n_d/server/process()
if(prob(3) && plays_sound)
playsound(loc, "computer_ambience", 10, TRUE, ignore_walls = FALSE)
var/turf/T = get_turf(src)
var/datum/gas_mixture/environment = T.get_readonly_air()
switch(environment.temperature())
if(0 to T0C)
health = min(100, health + 1)
if(T0C to (T20C + 20))
health = clamp(health, 0, 100)
if((T20C + 20) to INFINITY)
health = max(0, health - 1)
if(health <= 0)
/*griefProtection() This seems to get called twice before running any code that deletes/damages the server or it's files anwyay.
refreshParts and the hasReq procs that get called by this are laggy and do not need to be called by every server on the map every tick */
var/updateRD = 0
files.known_designs = list()
for(var/v in files.known_tech)
var/datum/tech/tech = files.known_tech[v]
// Slowly decrease research if health drops below 0
if(prob(1))
updateRD++
tech.level--
if(updateRD)
files.RefreshResearch()
if(delay)
delay--
else
produce_heat(heat_gen)
delay = initial(delay)
/obj/machinery/r_n_d/server/emp_act(severity)
griefProtection()
..()
/obj/machinery/r_n_d/server/ex_act(severity)
griefProtection()
return ..()
/obj/machinery/r_n_d/server/blob_act(obj/structure/blob/B)
griefProtection()
return ..()
// Backup files to CentComm to help admins recover data after griefer attacks
/obj/machinery/r_n_d/server/proc/griefProtection()
for(var/obj/machinery/r_n_d/server/centcom/C in GLOB.machines)
files.push_data(C.files)
/obj/machinery/r_n_d/server/proc/produce_heat(heat_amt)
var/datum/milla_safe/rnd_server_heat/milla = new()
milla.invoke_async(src, heat_amt)
/datum/milla_safe/rnd_server_heat
/datum/milla_safe/rnd_server_heat/on_run(obj/machinery/r_n_d/server/server, heat)
var/turf/T = get_turf(server)
var/datum/gas_mixture/env = get_turf_air(T)
if(server.stat & (NOPOWER|BROKEN))
return
if(env.temperature() >= (heat + T0C))
return
var/transfer_moles = 0.25 * env.total_moles()
var/datum/gas_mixture/removed = env.remove(transfer_moles)
if(!removed)
return
var/heat_capacity = removed.heat_capacity()
if(heat_capacity == 0 || heat_capacity == null)
heat_capacity = 1
removed.set_temperature(min((removed.temperature() * heat_capacity + server.heating_power) / heat_capacity, 1000))
env.merge(removed)
/obj/machinery/r_n_d/server/crowbar_act(mob/living/user, obj/item/I)
if(!panel_open)
return
. = TRUE
griefProtection()
default_deconstruction_crowbar(user, I)
/obj/machinery/r_n_d/server/screwdriver_act(mob/living/user, obj/item/I)
default_deconstruction_screwdriver(user, "RD-server-on_t", "RD-server-on", I)
return TRUE
/obj/machinery/r_n_d/server/centcom
name = "CentComm. Central R&D Database"
server_id = -1
/obj/machinery/r_n_d/server/proc/unlink()
network_manager_uid = null
SStgui.update_uis(src)
/obj/machinery/r_n_d/server/centcom/Initialize()
. = ..()
var/list/no_id_servers = list()
var/list/server_ids = list()
for(var/obj/machinery/r_n_d/server/S in GLOB.machines)
switch(S.server_id)
if(-1)
continue
if(0)
no_id_servers += S
else
server_ids += S.server_id
for(var/obj/machinery/r_n_d/server/S in no_id_servers)
var/num = 1
while(!S.server_id)
if(num in server_ids)
num++
else
S.server_id = num
server_ids += num
no_id_servers -= S
/obj/machinery/r_n_d/server/centcom/process()
return PROCESS_KILL //don't need process()
/obj/machinery/r_n_d/server/attack_hand(mob/user)
ui_interact(user)
/obj/machinery/computer/rdservercontrol
name = "\improper R&D server controller"
icon_screen = "rdcomp"
icon_keyboard = "rd_key"
light_color = LIGHT_COLOR_FADEDPURPLE
circuit = /obj/item/circuitboard/rdservercontrol
var/screen = 0
var/obj/machinery/r_n_d/server/temp_server
var/list/servers = list()
var/list/consoles = list()
var/badmin = 0
/obj/machinery/r_n_d/server/ui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "RndServer", name)
ui.open()
/obj/machinery/computer/rdservercontrol/Topic(href, href_list)
/obj/machinery/r_n_d/server/ui_data(mob/user)
var/list/data = list()
var/obj/machinery/computer/rnd_network_controller/RNC
if(network_manager_uid)
RNC = locateUID(network_manager_uid)
if(!network_manager_uid || !RNC)
network_manager_uid = null
data["network_name"] = null
var/list/controllers = list()
for(var/obj/machinery/computer/rnd_network_controller/RNC2 in GLOB.rnd_network_managers)
if(atoms_share_level(RNC2, src))
controllers += list(list("addr" = "\ref[RNC2]", "netname" = RNC2.network_name))
data["controllers"] = controllers
return data // Short circuit here, we aint linked
// Network metadata
data["network_name"] = RNC.network_name
data["linked_core_addr"] = "\ref[RNC]"
return data
/obj/machinery/r_n_d/server/ui_act(action, list/params)
// Check against href exploits
if(..())
return
add_fingerprint(usr)
usr.set_machine(src)
if(!src.allowed(usr) && !emagged)
to_chat(usr, "<span class='warning'>You do not have the required access level</span>")
return
. = TRUE
if(href_list["main"])
screen = 0
else if(href_list["access"] || href_list["data"] || href_list["transfer"])
temp_server = null
consoles = list()
servers = list()
for(var/obj/machinery/r_n_d/server/S in GLOB.machines)
if(istype(S, /obj/machinery/r_n_d/server/centcom) && !badmin)
continue
if(!atoms_share_level(get_turf(src), get_turf(S)) && !badmin)
continue
if(S.server_id == text2num(href_list["access"]) || S.server_id == text2num(href_list["data"]) || S.server_id == text2num(href_list["transfer"]))
temp_server = S
break
if(href_list["access"])
screen = 1
for(var/obj/machinery/computer/rdconsole/C in GLOB.machines)
if(C.sync)
consoles += C
else if(href_list["data"])
screen = 2
else if(href_list["transfer"])
screen = 3
for(var/obj/machinery/r_n_d/server/S in GLOB.machines)
if(S == src)
continue
servers += S
else if(href_list["upload_toggle"])
var/num = text2num(href_list["upload_toggle"])
for(var/obj/machinery/computer/rdconsole/C in consoles)
if(C.id != num)
continue
if(!atoms_share_level(get_turf(src), get_turf(C)) && !badmin)
to_chat(usr, "<span class='warning'>Unable to modify upload protocols of this console; is it in the same sector?</span>")
switch(action)
if("unlink")
if(!network_manager_uid)
return
if(num in temp_server.id_with_upload)
temp_server.id_with_upload -= num
else
temp_server.id_with_upload += num
var/choice = tgui_alert(usr, "Are you SURE you want to unlink this server?\nYou won't be able to re-link without the network password", "Unlink", list("Yes", "No"))
if(choice == "Yes")
// To the person who asks "Why not call unlink() here"
// Well, all it does is null the network manager UID and update the ui
// and we already update the UI at the end of this
var/obj/machinery/computer/rnd_network_controller/RNC = locateUID(network_manager_uid)
if(RNC)
RNC.servers -= UID()
network_manager_uid = null
else if(href_list["download_toggle"])
var/num = text2num(href_list["download_toggle"])
if(num in temp_server.id_with_download)
temp_server.id_with_download -= num
else
temp_server.id_with_download += num
// You should only be able to link if its not linked, to prevent weirdness
if("link")
if(network_manager_uid)
return
else if(href_list["reset_tech"])
var/choice = tgui_alert(usr, "Technology Data Reset", "Are you sure you want to reset this technology to its default data? Data lost cannot be recovered.", list("Continue", "Cancel"))
if(choice == "Continue")
for(var/I in temp_server.files.known_tech)
var/datum/tech/T = temp_server.files.known_tech[I]
if(T.id == href_list["reset_tech"])
T.level = 1
break
temp_server.files.RefreshResearch()
var/obj/machinery/computer/rnd_network_controller/RNC = locate(params["addr"])
if(istype(RNC, /obj/machinery/computer/rnd_network_controller))
// No linking unless were on the same Z
if(!atoms_share_level(RNC, src))
return
else if(href_list["reset_design"])
var/choice = tgui_alert(usr, "Design Data Deletion", "Are you sure you want to blacklist this design? Ensure you sync servers after this decision.", list("Continue", "Cancel"))
if(choice == "Continue")
for(var/I in temp_server.files.known_designs)
var/datum/design/D = temp_server.files.known_designs[I]
if(D.id == href_list["reset_design"])
temp_server.files.known_designs -= D.id
temp_server.files.blacklisted_designs += D.id
message_admins("[key_name_admin(usr)] blacklisted [D.name] from the rnd server controler.")
log_game("[key_name(usr)] blacklisted [D.name] from the rnd server controler.")
break
temp_server.files.RefreshResearch()
else if(href_list["restore_design"])
var/choice = tgui_alert(usr, "Design Data Restoration", "Are you sure you want to restore this design? Ensure you sync servers after this decision.", list("Continue", "Cancel"))
if(choice == "Continue")
temp_server.files.blacklisted_designs -= href_list["restore_design"]
temp_server.files.unblacklisted_designs += href_list["restore_design"]
message_admins("[key_name_admin(usr)] unblacklisted [href_list["restore_design"]] from the rnd server controler.")
log_game("[key_name(usr)] unblacklisted [href_list["restore_design"]] from the rnd server controler.")
temp_server.files.RefreshResearch()
updateUsrDialog()
return
/obj/machinery/computer/rdservercontrol/attack_hand(mob/user as mob)
if(stat & (BROKEN|NOPOWER))
return
user.set_machine(src)
var/dat = ""
switch(screen)
if(0) //Main Menu
dat += "Connected Servers:<BR><BR>"
for(var/obj/machinery/r_n_d/server/S in GLOB.machines)
if(istype(S, /obj/machinery/r_n_d/server/centcom) && !badmin)
continue
if(!atoms_share_level(get_turf(src), get_turf(S)) && !badmin)
continue
dat += "[S.name] || "
dat += "<A href='byond://?src=[UID()];access=[S.server_id]'>Access Rights</A> | "
dat += "<A href='byond://?src=[UID()];data=[S.server_id]'>Data Management</A>"
if(badmin) dat += " | <A href='byond://?src=[UID()];transfer=[S.server_id]'>Server-to-Server Transfer</A>"
dat += "<BR>"
if(1) //Access rights menu
dat += "[temp_server.name] Access Rights<BR><BR>"
dat += "Consoles with Upload Access<BR>"
for(var/obj/machinery/computer/rdconsole/C in consoles)
var/turf/console_turf = get_turf(C)
dat += "* <A href='byond://?src=[UID()];upload_toggle=[C.id]'>[console_turf.loc]" //FYI, these are all numeric ids, eventually.
if(C.id in temp_server.id_with_upload)
dat += " (Remove)</A><BR>"
var/wifi_pass = tgui_input_text(usr, "Please enter network password","Password Entry") // ayo whats your wifi pass
// Check the password
if(wifi_pass == RNC.network_password)
network_manager_uid = RNC.UID()
RNC.servers += UID()
to_chat(usr, "<span class='notice'>Successfully linked to <b>[RNC.network_name]</b>.</span>")
else
dat += " (Add)</A><BR>"
dat += "Consoles with Download Access<BR>"
for(var/obj/machinery/computer/rdconsole/C in consoles)
var/turf/console_turf = get_turf(C)
dat += "* <A href='byond://?src=[UID()];download_toggle=[C.id]'>[console_turf.loc]"
if(C.id in temp_server.id_with_download)
dat += " (Remove)</A><BR>"
else
dat += " (Add)</A><BR>"
dat += "<HR><A href='byond://?src=[UID()];main=1'>Main Menu</A>"
to_chat(usr, "<span class='alert'><b>ERROR:</b> Password incorrect.</span>")
if(2) //Data Management menu
dat += "[temp_server.name] Data Management<BR><BR>"
dat += "Known Technologies<BR>"
for(var/I in temp_server.files.known_tech)
var/datum/tech/T = temp_server.files.known_tech[I]
if(T.level <= 0)
continue
dat += "* [T.name] "
dat += "<A href='byond://?src=[UID()];reset_tech=[T.id]'>(Reset)</A><BR>" //FYI, these are all strings.
dat += "Known Designs<BR>"
for(var/I in temp_server.files.known_designs)
var/datum/design/D = temp_server.files.known_designs[I]
dat += "* [D.name] "
dat += "<A href='byond://?src=[UID()];reset_design=[D.id]'>(Blacklist)</A><BR>"
if(length(temp_server.files.blacklisted_designs))
dat += "Blacklisted Designs<br>"
for(var/I in temp_server.files.blacklisted_designs)
dat += "* [I] "
dat += "<a href='byond://?src=[UID()];restore_design=[I]'>(Restore design)</a><br>"
dat += "<HR><A href='byond://?src=[UID()];main=1'>Main Menu</A>"
else
to_chat(usr, "<span class='alert'><b>ERROR:</b> Network manager not found. Please file an issue report.</span>")
if(3) //Server Data Transfer
dat += "[temp_server.name] Server to Server Transfer<BR><BR>"
dat += "Send Data to what server?<BR>"
for(var/obj/machinery/r_n_d/server/S in servers)
dat += "[S.name] <a href='byond://?src=[UID()];send_to=[S.server_id]'> (Transfer)</a><br>"
dat += "<hr><a href='byond://?src=[UID()];main=1'>Main Menu</a>"
user << browse("<title>R&D Server Control</title><hr><meta charset='UTF-8'>[dat]", "window=server_control;size=575x400")
onclose(user, "server_control")
return
/obj/machinery/computer/rdservercontrol/emag_act(user as mob)
if(!emagged)
playsound(loc, 'sound/effects/sparks4.ogg', 75, TRUE)
emagged = TRUE
to_chat(user, "<span class='notice'>You you disable the security protocols</span>")
return TRUE
src.updateUsrDialog()
/obj/machinery/r_n_d/server/core
name = "Core R&D Server"
id_with_upload_string = "1;3"
id_with_download_string = "1;3"
server_id = 1
plays_sound = 1
// PRESETS //
/obj/machinery/r_n_d/server/robotics
name = "Robotics R&D Server"
id_with_upload_string = "1;2;4"
id_with_download_string = "1;2;4"
server_id = 2
/obj/machinery/r_n_d/server/station
autolink_id = "station_rnd"