/* Research and Development (R&D) Console This is the main work horse of the R&D system. It contains the menus/controls for the Destructive Analyzer, Protolathe, and Circuit imprinter. Basic use: When it first is created, it will attempt to link up to related devices within 3 squares. It'll only link up if they aren't already linked to another console. Any consoles it cannot link up with (either because all of a certain type are already linked or there aren't any in range), you'll just not have access to that menu. In the settings menu, there are menu options that allow a player to attempt to re-sync with nearby consoles. You can also force it to disconnect from a specific console. The only thing that requires toxins access is locking and unlocking the console on the settings menu. Nothing else in the console has ID requirements. */ /obj/machinery/computer/rdconsole name = "R&D Console" desc = "A console used to interface with R&D tools." icon_screen = "rdcomp" icon_keyboard = "rd_key" var/datum/techweb/stored_research //Reference to global science techweb. var/obj/item/disk/tech_disk/t_disk //Stores the technology disk. var/obj/item/disk/design_disk/d_disk //Stores the design disk. circuit = /obj/item/circuitboard/computer/rdconsole var/obj/machinery/rnd/destructive_analyzer/linked_destroy //Linked Destructive Analyzer var/obj/machinery/rnd/production/protolathe/linked_lathe //Linked Protolathe var/obj/machinery/rnd/production/circuit_imprinter/linked_imprinter //Linked Circuit Imprinter req_access = list(ACCESS_TOX) //lA AND SETTING MANIPULATION REQUIRES SCIENTIST ACCESS. //UI VARS var/screen = RDSCREEN_MENU var/back = RDSCREEN_MENU var/locked = FALSE var/tdisk_uple = FALSE var/ddisk_uple = FALSE var/datum/selected_node_id var/datum/selected_design_id var/selected_category var/list/matching_design_ids var/disk_slot_selected var/searchstring = "" var/searchtype = "" var/ui_mode = RDCONSOLE_UI_MODE_NORMAL var/research_control = TRUE /// Long action cooldown to prevent spam var/last_long_action = 0 /obj/machinery/computer/rdconsole/production circuit = /obj/item/circuitboard/computer/rdconsole/production research_control = FALSE /proc/CallMaterialName(ID) if (istype(ID, /datum/material)) var/datum/material/material = ID return material.name else if(GLOB.chemical_reagents_list[ID]) var/datum/reagent/reagent = GLOB.chemical_reagents_list[ID] return reagent.name return ID /obj/machinery/computer/rdconsole/proc/SyncRDevices() //Makes sure it is properly sync'ed up with the devices attached to it (if any). for(var/obj/machinery/rnd/D in oview(3,src)) if(D.linked_console != null || D.disabled || D.panel_open) continue if(istype(D, /obj/machinery/rnd/destructive_analyzer)) if(linked_destroy == null) linked_destroy = D D.linked_console = src else if(istype(D, /obj/machinery/rnd/production/protolathe)) if(linked_lathe == null) var/obj/machinery/rnd/production/protolathe/P = D if(!P.console_link) continue linked_lathe = D D.linked_console = src else if(istype(D, /obj/machinery/rnd/production/circuit_imprinter)) if(linked_imprinter == null) var/obj/machinery/rnd/production/circuit_imprinter/C = D if(!C.console_link) continue linked_imprinter = D D.linked_console = src /obj/machinery/computer/rdconsole/Initialize(mapload) . = ..() stored_research = SSresearch.science_tech stored_research.consoles_accessing[src] = TRUE matching_design_ids = list() SyncRDevices() /obj/machinery/computer/rdconsole/Destroy() if(stored_research) stored_research.consoles_accessing -= src if(linked_destroy) linked_destroy.linked_console = null linked_destroy = null if(linked_lathe) linked_lathe.linked_console = null linked_lathe = null if(linked_imprinter) linked_imprinter.linked_console = null linked_imprinter = null if(t_disk) t_disk.forceMove(get_turf(src)) t_disk = null if(d_disk) d_disk.forceMove(get_turf(src)) d_disk = null matching_design_ids = null return ..() /obj/machinery/computer/rdconsole/attackby(obj/item/D, mob/user, params) //Loading a disk into it. if(istype(D, /obj/item/disk)) if(istype(D, /obj/item/disk/tech_disk)) if(t_disk) to_chat(user, "A technology disk is already loaded!") return if(!user.transferItemToLoc(D, src)) to_chat(user, "[D] is stuck to your hand!") return t_disk = D else if (istype(D, /obj/item/disk/design_disk)) if(d_disk) to_chat(user, "A design disk is already loaded!") return if(!user.transferItemToLoc(D, src)) to_chat(user, "[D] is stuck to your hand!") return d_disk = D else to_chat(user, "Machine cannot accept disks in that format.") return to_chat(user, "You insert [D] into \the [src]!") else if(!(linked_destroy && linked_destroy.busy) && !(linked_lathe && linked_lathe.busy) && !(linked_imprinter && linked_imprinter.busy)) . = ..() /obj/machinery/computer/rdconsole/proc/research_node(id, mob/user) if(!stored_research.available_nodes[id] || stored_research.researched_nodes[id]) say("Node unlock failed: Either already researched or not available!") return FALSE var/datum/techweb_node/TN = SSresearch.techweb_node_by_id(id) if(!istype(TN)) say("Node unlock failed: Unknown error.") return FALSE var/list/price = TN.get_price(stored_research) if(stored_research.can_afford(price)) investigate_log("[key_name(user)] researched [id]([json_encode(price)]) on techweb id [stored_research.id].", INVESTIGATE_RESEARCH) if(stored_research == SSresearch.science_tech) SSblackbox.record_feedback("associative", "science_techweb_unlock", 1, list("id" = "[id]", "name" = TN.display_name, "price" = "[json_encode(price)]", "time" = SQLtime())) if(stored_research.research_node_id(id)) say("Successfully researched [TN.display_name].") var/logname = "Unknown" if(isAI(user)) logname = "AI: [user.name]" else if(iscyborg(user)) logname = "Cyborg: [user.name]" else if(isliving(user)) var/mob/living/L = user logname = L.get_visible_name() stored_research.research_logs += "[logname] researched node id [id] with cost [json_encode(price)] at [COORD(src)]." return TRUE else say("Failed to research node: Internal database error!") return FALSE say("Not enough research points...") return FALSE /obj/machinery/computer/rdconsole/on_deconstruction() if(linked_destroy) linked_destroy.linked_console = null linked_destroy = null if(linked_lathe) linked_lathe.linked_console = null linked_lathe = null if(linked_imprinter) linked_imprinter.linked_console = null linked_imprinter = null ..() /obj/machinery/computer/rdconsole/emag_act(mob/user) . = ..() if(obj_flags & EMAGGED) return to_chat(user, "You disable the security protocols[locked? " and unlock the console":""].") playsound(src, "sparks", 75, 1) obj_flags |= EMAGGED locked = FALSE return TRUE /obj/machinery/computer/rdconsole/multitool_act(mob/user, obj/item/I) if(!I.tool_behaviour == TOOL_MULTITOOL) return var/lathe = linked_lathe && linked_lathe.multitool_act(user, I) var/print = linked_imprinter && linked_imprinter.multitool_act(user, I) return lathe || print /obj/machinery/computer/rdconsole/proc/list_categories(list/categories, menu_num as num) if(!categories) return var/line_length = 1 var/list/l = "" for(var/C in categories) if(line_length > 2) l += "" line_length = 1 l += "" line_length++ l += "
[C]
" return l /obj/machinery/computer/rdconsole/proc/ui_header() var/list/l = list() var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/research_designs) l += "[sheet.css_tag()][RDSCREEN_NOBREAK]" l += "
[stored_research.organization] Research and Development Network" l += "Available points:
[techweb_point_display_rdconsole(stored_research.research_points, stored_research.last_bitcoins)]" l += "Security protocols: [obj_flags & EMAGGED ? "Disabled" : "Enabled"]" l += "Main Menu | Back
[RDSCREEN_NOBREAK]" l += "[ui_mode == 1? "Normal View" : "Normal View"] | [ui_mode == 2? "Expert View" : "Expert View"] | [ui_mode == 3? "List View" : "List View"]" return l /obj/machinery/computer/rdconsole/proc/ui_main_menu() var/list/l = list() if(research_control) l += "

Technology" if(d_disk) l += "
Design Disk" if(t_disk) l += "
Tech Disk" if(linked_destroy) l += "
Destructive Analyzer" if(linked_lathe) l += "
Protolathe" if(linked_imprinter) l += "
Circuit Imprinter" l += "
Settings

" return l /obj/machinery/computer/rdconsole/proc/ui_locked() return list("

SYSTEM LOCKED


") /obj/machinery/computer/rdconsole/proc/ui_settings() var/list/l = list() l += "

R&D Console Settings:

" l += "Device Linkage Menu" l += "Lock Console
" return l /obj/machinery/computer/rdconsole/proc/ui_device_linking() var/list/l = list() l += "Settings Menu
" l += "

R&D Console Device Linkage Menu:

" l += "Re-sync with Nearby Devices" l += "

Linked Devices:

" l += linked_destroy? "* Destructive Analyzer Disconnect" : "* No Destructive Analyzer Linked" l += linked_lathe? "* Protolathe Disconnect" : "* No Protolathe Linked" l += linked_imprinter? "* Circuit Imprinter Disconnect" : "* No Circuit Imprinter Linked" l += "
" return l /obj/machinery/computer/rdconsole/proc/ui_protolathe_header() var/list/l = list() l += "
Protolathe Menu" if(linked_lathe.materials.mat_container) l += "Material Amount: [linked_lathe.materials.format_amount()]" else l += "No material storage connected, please contact the quartermaster." l += "Chemical volume: [linked_lathe.reagents.total_volume] / [linked_lathe.reagents.maximum_volume]
" return l /obj/machinery/computer/rdconsole/proc/ui_protolathe_category_view() //Legacy code RDSCREEN_UI_LATHE_CHECK var/list/l = list() l += ui_protolathe_header() l += "

Browsing [selected_category]:

" for(var/v in stored_research.researched_designs) var/datum/design/D = SSresearch.techweb_design_by_id(v) if(!(selected_category in D.category)|| !(D.build_type & PROTOLATHE)) continue if(!(isnull(linked_lathe.allowed_department_flags) || (D.departmental_flags & linked_lathe.allowed_department_flags))) continue var/temp_material var/c = 50 var/coeff = linked_lathe.print_cost_coeff if(!linked_lathe.efficient_with(D.build_path)) coeff = 1 var/all_materials = D.materials + D.reagents_list for(var/M in all_materials) var/t = linked_lathe.check_mat(D, M) temp_material += " | " if (t < 1) temp_material += "[all_materials[M] * coeff] [CallMaterialName(M)]" else temp_material += " [all_materials[M] * coeff] [CallMaterialName(M)]" c = min(c,t) var/clearance = !(linked_lathe.obj_flags & EMAGGED) && (linked_lathe.offstation_security_levels || is_station_level(linked_lathe.z)) var/sec_text = "" if(clearance && (D.min_security_level > SEC_LEVEL_GREEN || D.max_security_level < SEC_LEVEL_DELTA)) sec_text = " (Allowed security levels: " for(var/n in D.min_security_level to D.max_security_level) sec_text += NUM2SECLEVEL(n) if(n + 1 <= D.max_security_level) sec_text += ", " sec_text += ")" clearance = !clearance || ISINRANGE(GLOB.security_level, D.min_security_level, D.max_security_level) if (c >= 1 && clearance) l += "[D.name][RDSCREEN_NOBREAK]" if(c >= 5) l += "x5[RDSCREEN_NOBREAK]" if(c >= 10) l += "x10[RDSCREEN_NOBREAK]" l += "[temp_material][sec_text][RDSCREEN_NOBREAK]" else l += "[D.name][temp_material][sec_text][RDSCREEN_NOBREAK]" l += "" l += "
" return l /obj/machinery/computer/rdconsole/proc/ui_protolathe() //Legacy code RDSCREEN_UI_LATHE_CHECK var/list/l = list() l += ui_protolathe_header() l += "
\ \ \ \ \ \

" l += list_categories(linked_lathe.categories, RDSCREEN_PROTOLATHE_CATEGORY_VIEW) return l /obj/machinery/computer/rdconsole/proc/ui_protolathe_search() //Legacy code RDSCREEN_UI_LATHE_CHECK var/list/l = list() l += ui_protolathe_header() for(var/id in matching_design_ids) var/datum/design/D = SSresearch.techweb_design_by_id(id) if(!(isnull(linked_lathe.allowed_department_flags) || (D.departmental_flags & linked_lathe.allowed_department_flags))) continue var/temp_material var/c = 50 var/all_materials = D.materials + D.reagents_list var/coeff = linked_lathe.print_cost_coeff if(!linked_lathe.efficient_with(D.build_path)) coeff = 1 for(var/M in all_materials) var/t = linked_lathe.check_mat(D, M) temp_material += " | " if (t < 1) temp_material += "[all_materials[M] * coeff] [CallMaterialName(M)]" else temp_material += " [all_materials[M] * coeff] [CallMaterialName(M)]" c = min(c,t) if (c >= 1) l += "[D.name][RDSCREEN_NOBREAK]" if(c >= 5) l += "x5[RDSCREEN_NOBREAK]" if(c >= 10) l += "x10[RDSCREEN_NOBREAK]" l += "[temp_material][RDSCREEN_NOBREAK]" else l += "[D.name][temp_material][RDSCREEN_NOBREAK]" l += "" l += "" return l /obj/machinery/computer/rdconsole/proc/ui_protolathe_materials() //Legacy code RDSCREEN_UI_LATHE_CHECK var/datum/component/material_container/mat_container = linked_lathe.materials.mat_container if (!mat_container) screen = RDSCREEN_PROTOLATHE return ui_protolathe() var/list/l = list() l += ui_protolathe_header() l += "

Material Storage:

" for(var/mat_id in mat_container.materials) var/datum/material/M = mat_id var/amount = mat_container.materials[mat_id] var/ref = REF(M) l += "* [amount] of [M.name]: " if(amount >= MINERAL_MATERIAL_AMOUNT) l += "Eject [RDSCREEN_NOBREAK]" if(amount >= MINERAL_MATERIAL_AMOUNT*5) l += "5x [RDSCREEN_NOBREAK]" if(amount >= MINERAL_MATERIAL_AMOUNT) l += "All[RDSCREEN_NOBREAK]" l += "" l += "
[RDSCREEN_NOBREAK]" return l /obj/machinery/computer/rdconsole/proc/ui_protolathe_chemicals() //Legacy code RDSCREEN_UI_LATHE_CHECK var/list/l = list() l += ui_protolathe_header() l += "
Disposal All Chemicals in Storage" l += "

Chemical Storage:

" for(var/datum/reagent/R in linked_lathe.reagents.reagent_list) l += "[R.name]: [R.volume]" l += "Purge" l += "
" return l /obj/machinery/computer/rdconsole/proc/ui_circuit_header() //Legacy Code var/list/l = list() l += "
Circuit Imprinter Menu" if (linked_imprinter.materials.mat_container) l += "Material Amount: [linked_imprinter.materials.format_amount()]" else l += "No material storage connected, please contact the quartermaster." l += "Chemical volume: [linked_imprinter.reagents.total_volume] / [linked_imprinter.reagents.maximum_volume]
" return l /obj/machinery/computer/rdconsole/proc/ui_circuit() //Legacy code RDSCREEN_UI_IMPRINTER_CHECK var/list/l = list() l += ui_circuit_header() l += "

Circuit Imprinter Menu:

" l += "
\ \ \ \ \ \

" l += list_categories(linked_imprinter.categories, RDSCREEN_IMPRINTER_CATEGORY_VIEW) return l /obj/machinery/computer/rdconsole/proc/ui_circuit_category_view() //Legacy code RDSCREEN_UI_IMPRINTER_CHECK var/list/l = list() l += ui_circuit_header() l += "

Browsing [selected_category]:

" for(var/v in stored_research.researched_designs) var/datum/design/D = SSresearch.techweb_design_by_id(v) if(!(selected_category in D.category) || !(D.build_type & IMPRINTER)) continue if(!(isnull(linked_imprinter.allowed_department_flags) || (D.departmental_flags & linked_imprinter.allowed_department_flags))) continue var/temp_materials var/check_materials = TRUE var/all_materials = D.materials + D.reagents_list var/coeff = linked_imprinter.print_cost_coeff if(!linked_imprinter.efficient_with(D.build_path)) coeff = 1 for(var/M in all_materials) temp_materials += " | " if (!linked_imprinter.check_mat(D, M)) check_materials = FALSE temp_materials += " [all_materials[M] * coeff] [CallMaterialName(M)]" else temp_materials += " [all_materials[M] * coeff] [CallMaterialName(M)]" if (check_materials) l += "[D.name][temp_materials]" else l += "[D.name][temp_materials]" l += "
" return l /obj/machinery/computer/rdconsole/proc/ui_circuit_search() //Legacy code RDSCREEN_UI_IMPRINTER_CHECK var/list/l = list() l += ui_circuit_header() l += "

Search results:

" for(var/id in matching_design_ids) var/datum/design/D = SSresearch.techweb_design_by_id(id) if(!(isnull(linked_imprinter.allowed_department_flags) || (D.departmental_flags & linked_imprinter.allowed_department_flags))) continue var/temp_materials var/check_materials = TRUE var/all_materials = D.materials + D.reagents_list var/coeff = linked_imprinter.print_cost_coeff if(!linked_imprinter.efficient_with(D.build_path)) coeff = 1 for(var/M in all_materials) temp_materials += " | " if (!linked_imprinter.check_mat(D, M)) check_materials = FALSE temp_materials += " [all_materials[M] * coeff] [CallMaterialName(M)]" else temp_materials += " [all_materials[M] * coeff] [CallMaterialName(M)]" if (check_materials) l += "[D.name][temp_materials]" else l += "[D.name][temp_materials]" l += "
" return l /obj/machinery/computer/rdconsole/proc/ui_circuit_chemicals() //legacy code RDSCREEN_UI_IMPRINTER_CHECK var/list/l = list() l += ui_circuit_header() l += "Disposal All Chemicals in Storage
" l += "

Chemical Storage:

" for(var/datum/reagent/R in linked_imprinter.reagents.reagent_list) l += "[R.name]: [R.volume]" l += "Purge" return l /obj/machinery/computer/rdconsole/proc/ui_circuit_materials() //Legacy code! RDSCREEN_UI_IMPRINTER_CHECK var/datum/component/material_container/mat_container = linked_imprinter.materials.mat_container if (!mat_container) screen = RDSCREEN_IMPRINTER return ui_circuit() var/list/l = list() l += ui_circuit_header() l += "

Material Storage:

" for(var/mat_id in mat_container.materials) var/datum/material/M = mat_id var/amount = mat_container.materials[mat_id] var/ref = REF(M) l += "* [amount] of [M.name]: " if(amount >= MINERAL_MATERIAL_AMOUNT) l += "Eject [RDSCREEN_NOBREAK]" if(amount >= MINERAL_MATERIAL_AMOUNT*5) l += "5x [RDSCREEN_NOBREAK]" if(amount >= MINERAL_MATERIAL_AMOUNT) l += "All[RDSCREEN_NOBREAK]
" return l /obj/machinery/computer/rdconsole/proc/ui_techdisk() //Legacy code RDSCREEN_UI_TDISK_CHECK var/list/l = list() l += "
Disk Operations: Clear Disk" l += "Eject Disk" l += "Upload All" l += "Load Technology to Disk
" l += "

Stored Technology Nodes:

" for(var/i in t_disk.stored_research.researched_nodes) var/datum/techweb_node/N = SSresearch.techweb_node_by_id(i) l += "[N.display_name]" l += "
" return l /obj/machinery/computer/rdconsole/proc/ui_designdisk() //Legacy code RDSCREEN_UI_DDISK_CHECK var/list/l = list() l += "Disk Operations: Clear DiskUpload AllEject Disk" for(var/i in 1 to d_disk.max_blueprints) l += "
" if(d_disk.blueprints[i]) var/datum/design/D = d_disk.blueprints[i] l += "[D.name]" l += "Operations: Upload to database Clear Slot" else l += "Empty Slot Operations: Load Design to Slot" l += "
" return l /obj/machinery/computer/rdconsole/proc/ui_designdisk_upload() //Legacy code RDSCREEN_UI_DDISK_CHECK var/list/l = list() l += "Return to Disk Operations
" l += "

Load Design to Disk:

" for(var/v in stored_research.researched_designs) var/datum/design/D = SSresearch.techweb_design_by_id(v) l += "[D.name] " l += "Copy to Disk" l += "
" return l /obj/machinery/computer/rdconsole/proc/ui_deconstruct() //Legacy code RDSCREEN_UI_DECONSTRUCT_CHECK var/list/l = list() if(!linked_destroy.loaded_item) l += "
No item loaded. Standing-by...
" else l += "
[RDSCREEN_NOBREAK]" l += "
[icon2html(linked_destroy.loaded_item, usr)][linked_destroy.loaded_item.name] Eject
[RDSCREEN_NOBREAK]" l += "Select a node to boost by deconstructing this item. This item can boost:" var/list/boostable_nodes = techweb_item_boost_check(linked_destroy.loaded_item) for(var/id in boostable_nodes) var/list/worth = boostable_nodes[id] var/datum/techweb_node/N = SSresearch.techweb_node_by_id(id) l += "
[RDSCREEN_NOBREAK]" if (stored_research.researched_nodes[N.id]) // already researched l += "[N.display_name]" l += "This node has already been researched." else if(!length(worth)) // reveal only if (stored_research.hidden_nodes[N.id]) l += "[N.display_name]" l += "This node will be revealed." else l += "[N.display_name]" l += "This node has already been revealed." else // boost by the difference var/list/differences = list() var/list/already_boosted = stored_research.boosted_nodes[N.id] for(var/i in worth) var/already_boosted_amount = already_boosted? stored_research.boosted_nodes[N.id][i] : 0 var/amt = min(worth[i], N.research_costs[i]) - already_boosted_amount if(amt > 0) differences[i] = amt if (length(differences)) l += "[N.display_name]" l += "This node will be boosted with the following:
[techweb_point_display_generic(differences)]" else l += "[N.display_name]" l += "This node has already been boosted." l += "
[RDSCREEN_NOBREAK]" // point deconstruction and material reclamation use the same ID to prevent accidentally missing the points var/list/point_values = techweb_item_point_check(linked_destroy.loaded_item) if(point_values) l += "
[RDSCREEN_NOBREAK]" if (stored_research.deconstructed_items[linked_destroy.loaded_item.type]) l += "Point Deconstruction" l += "This item's points have already been claimed." else l += "Point Deconstruction" l += "This item is worth:
[techweb_point_display_generic(point_values)]!" l += "
[RDSCREEN_NOBREAK]" if(!(linked_destroy.loaded_item.resistance_flags & INDESTRUCTIBLE)) var/list/materials = linked_destroy.loaded_item.custom_materials l += "
[LAZYLEN(materials)? "Material Reclamation" : "Destroy Item"]" for (var/M in materials) l += "* [CallMaterialName(M)] x [materials[M]]" l += "
[RDSCREEN_NOBREAK]" l += "
Nondestructive Deep Scan
" l += "
" return l /obj/machinery/computer/rdconsole/proc/ui_techweb() var/list/l = list() if(islist(stored_research.research_logs) && stored_research.research_logs.len) l += "Last action: [stored_research.research_logs[stored_research.research_logs.len]]" if(ui_mode != RDCONSOLE_UI_MODE_LIST) var/list/columns = list() var/max_tier = 0 for (var/node_ in stored_research.tiers) var/datum/techweb_node/node = SSresearch.techweb_node_by_id(node_) var/tier = stored_research.tiers[node.id] LAZYINITLIST(columns["[tier]"]) // String hackery to make the numbers associative columns["[tier]"] += ui_techweb_single_node(node, minimal=(tier != 1)) max_tier = max(max_tier, tier) l += "[RDSCREEN_NOBREAK]" if(max_tier) for(var/tier in 0 to max_tier) l += "[RDSCREEN_NOBREAK]" l += "
ResearchedAvailableFuture
[RDSCREEN_NOBREAK]" l += columns["[tier]"] l += "
[RDSCREEN_NOBREAK]" else var/list/avail = list() //This could probably be optimized a bit later. var/list/unavail = list() var/list/res = list() for(var/v in stored_research.researched_nodes) res += SSresearch.techweb_node_by_id(v) for(var/v in stored_research.available_nodes) if(stored_research.researched_nodes[v]) continue avail += SSresearch.techweb_node_by_id(v) for(var/v in stored_research.visible_nodes) if(stored_research.available_nodes[v]) continue unavail += SSresearch.techweb_node_by_id(v) l += "

Technology Nodes:

[RDSCREEN_NOBREAK]" l += "

Available for Research:

" for(var/datum/techweb_node/N in avail) var/not_unlocked = (stored_research.available_nodes[N.id] && !stored_research.researched_nodes[N.id]) var/has_points = (stored_research.can_afford(N.get_price(stored_research))) var/research_href = not_unlocked? (has_points? "Research" : "Not Enough Points") : null l += "[N.display_name][research_href]" l += "

Locked Nodes:

" for(var/datum/techweb_node/N in unavail) l += "[N.display_name]" l += "

Researched Nodes:

" for(var/datum/techweb_node/N in res) l += "[N.display_name]" l += "
[RDSCREEN_NOBREAK]" return l /obj/machinery/computer/rdconsole/proc/machine_icon(atom/item) return icon2html(initial(item.icon), usr, initial(item.icon_state), SOUTH) /obj/machinery/computer/rdconsole/proc/ui_techweb_single_node(datum/techweb_node/node, selflink=TRUE, minimal=FALSE) var/list/l = list() if (stored_research.hidden_nodes[node.id]) return l var/display_name = node.display_name if (selflink) display_name = "[display_name]" l += "
[display_name] [RDSCREEN_NOBREAK]" if(minimal) l += "
[node.description]" else if(stored_research.researched_nodes[node.id]) l += "Researched" else if(stored_research.available_nodes[node.id]) if(stored_research.can_afford(node.get_price(stored_research))) l += "
[node.price_display(stored_research)]" else l += "
[node.price_display(stored_research)]" // gray - too expensive else l += "
[node.price_display(stored_research)]" // red - missing prereqs if(ui_mode == RDCONSOLE_UI_MODE_NORMAL) l += "[node.description]" for(var/i in node.design_ids) var/datum/design/D = SSresearch.techweb_design_by_id(i) l += "[D.icon_html(usr)][RDSCREEN_NOBREAK]" l += "
[RDSCREEN_NOBREAK]" return l /obj/machinery/computer/rdconsole/proc/ui_techweb_nodeview() var/datum/techweb_node/selected_node = SSresearch.techweb_node_by_id(selected_node_id) RDSCREEN_UI_SNODE_CHECK var/list/l = list() if(stored_research.hidden_nodes[selected_node.id]) l += "

ERROR: RESEARCH NODE UNKNOWN.

" return l += "[RDSCREEN_NOBREAK]" if (length(selected_node.prereq_ids)) l += "[RDSCREEN_NOBREAK]" l += "[RDSCREEN_NOBREAK]" if (length(selected_node.unlock_ids)) l += "[RDSCREEN_NOBREAK]" l += "[RDSCREEN_NOBREAK]" if (length(selected_node.prereq_ids)) l += "[RDSCREEN_NOBREAK]" l += "[RDSCREEN_NOBREAK]" if (length(selected_node.unlock_ids)) l += "[RDSCREEN_NOBREAK]" l += "
RequiresCurrent NodeUnlocks
[RDSCREEN_NOBREAK]" for (var/i in selected_node.prereq_ids) l += ui_techweb_single_node(SSresearch.techweb_node_by_id(i)) l += "[RDSCREEN_NOBREAK]" l += ui_techweb_single_node(selected_node, selflink=FALSE) l += "[RDSCREEN_NOBREAK]" for (var/i in selected_node.unlock_ids) l += ui_techweb_single_node(SSresearch.techweb_node_by_id(i)) l += "
[RDSCREEN_NOBREAK]" return l /obj/machinery/computer/rdconsole/proc/ui_techweb_designview() //Legacy code var/datum/design/selected_design = SSresearch.techweb_design_by_id(selected_design_id) RDSCREEN_UI_SDESIGN_CHECK var/list/l = list() l += "
[selected_design.icon_html(usr)][selected_design.name]
[RDSCREEN_NOBREAK]" if(selected_design.build_type) var/lathes = list() if(selected_design.build_type & IMPRINTER) lathes += "[machine_icon(/obj/machinery/rnd/production/circuit_imprinter)][RDSCREEN_NOBREAK]" if (linked_imprinter && stored_research.researched_designs[selected_design.id]) l += "Imprint" if(selected_design.build_type & PROTOLATHE) lathes += "[machine_icon(/obj/machinery/rnd/production/protolathe)][RDSCREEN_NOBREAK]" if (linked_lathe && stored_research.researched_designs[selected_design.id]) l += "Construct" if(selected_design.build_type & AUTOLATHE) lathes += "[machine_icon(/obj/machinery/autolathe)][RDSCREEN_NOBREAK]" if(selected_design.build_type & MECHFAB) lathes += "[machine_icon(/obj/machinery/mecha_part_fabricator)][RDSCREEN_NOBREAK]" if(selected_design.build_type & BIOGENERATOR) lathes += "[machine_icon(/obj/machinery/biogenerator)][RDSCREEN_NOBREAK]" if(selected_design.build_type & LIMBGROWER) lathes += "[machine_icon(/obj/machinery/limbgrower)][RDSCREEN_NOBREAK]" if(selected_design.build_type & SMELTER) lathes += "[machine_icon(/obj/machinery/mineral/processing_unit)][RDSCREEN_NOBREAK]" l += "Construction types:" l += lathes l += "" l += "Required materials:" var/all_mats = selected_design.materials + selected_design.reagents_list for(var/M in all_mats) l += "* [CallMaterialName(M)] x [all_mats[M]]" l += "Unlocked by:" for (var/i in selected_design.unlocked_by) l += ui_techweb_single_node(SSresearch.techweb_node_by_id(i)) l += "[RDSCREEN_NOBREAK]
" return l //Fuck TGUI. /obj/machinery/computer/rdconsole/proc/generate_ui() var/list/ui = list() ui += ui_header() if(locked) ui += ui_locked() else switch(screen) if(RDSCREEN_MENU) ui += ui_main_menu() if(RDSCREEN_TECHWEB) ui += ui_techweb() if(RDSCREEN_TECHWEB_NODEVIEW) ui += ui_techweb_nodeview() if(RDSCREEN_TECHWEB_DESIGNVIEW) ui += ui_techweb_designview() if(RDSCREEN_DESIGNDISK) ui += ui_designdisk() if(RDSCREEN_DESIGNDISK_UPLOAD) ui += ui_designdisk_upload() if(RDSCREEN_TECHDISK) ui += ui_techdisk() if(RDSCREEN_DECONSTRUCT) ui += ui_deconstruct() if(RDSCREEN_PROTOLATHE) ui += ui_protolathe() if(RDSCREEN_PROTOLATHE_CATEGORY_VIEW) ui += ui_protolathe_category_view() if(RDSCREEN_PROTOLATHE_MATERIALS) ui += ui_protolathe_materials() if(RDSCREEN_PROTOLATHE_CHEMICALS) ui += ui_protolathe_chemicals() if(RDSCREEN_PROTOLATHE_SEARCH) ui += ui_protolathe_search() if(RDSCREEN_IMPRINTER) ui += ui_circuit() if(RDSCREEN_IMPRINTER_CATEGORY_VIEW) ui += ui_circuit_category_view() if(RDSCREEN_IMPRINTER_MATERIALS) ui += ui_circuit_materials() if(RDSCREEN_IMPRINTER_CHEMICALS) ui += ui_circuit_chemicals() if(RDSCREEN_IMPRINTER_SEARCH) ui += ui_circuit_search() if(RDSCREEN_SETTINGS) ui += ui_settings() if(RDSCREEN_DEVICE_LINKING) ui += ui_device_linking() for(var/i in 1 to length(ui)) if(!findtextEx(ui[i], RDSCREEN_NOBREAK)) ui[i] += "
" . = ui.Join("") return replacetextEx(., RDSCREEN_NOBREAK, "") /obj/machinery/computer/rdconsole/Topic(raw, ls) if(..()) return add_fingerprint(usr) usr.set_machine(src) if(ls["switch_screen"]) back = screen screen = text2num(ls["switch_screen"]) if(ls["ui_mode"]) ui_mode = text2num(ls["ui_mode"]) if(ls["lock_console"]) if(obj_flags & EMAGGED) to_chat(usr, "Security protocol error: Unable to lock.") return if(allowed(usr)) lock_console(usr) else to_chat(usr, "Unauthorized Access.") if(ls["unlock_console"]) if(allowed(usr)) unlock_console(usr) else to_chat(usr, "Unauthorized Access.") if(ls["find_device"]) SyncRDevices() say("Resynced with nearby devices.") if(ls["back_screen"]) back = text2num(ls["back_screen"]) if(ls["build"]) //Causes the Protolathe to build something. if(QDELETED(linked_lathe)) say("No Protolathe Linked!") return if(linked_lathe.busy) say("Warning: Protolathe busy!") else linked_lathe.user_try_print_id(ls["build"], ls["amount"]) if(ls["imprint"]) if(QDELETED(linked_imprinter)) say("No Circuit Imprinter Linked!") return if(linked_imprinter.busy) say("Warning: Imprinter busy!") else linked_imprinter.user_try_print_id(ls["imprint"]) if(ls["category"]) selected_category = ls["category"] if(ls["disconnect"]) //The R&D console disconnects with a specific device. switch(ls["disconnect"]) if("destroy") if(QDELETED(linked_destroy)) say("No Destructive Analyzer Linked!") return linked_destroy.linked_console = null linked_destroy = null if("lathe") if(QDELETED(linked_lathe)) say("No Protolathe Linked!") return linked_lathe.linked_console = null linked_lathe = null if("imprinter") if(QDELETED(linked_imprinter)) say("No Circuit Imprinter Linked!") return linked_imprinter.linked_console = null linked_imprinter = null if(ls["eject_design"]) //Eject the design disk. eject_disk("design") screen = RDSCREEN_MENU say("Ejecting Design Disk") if(ls["eject_tech"]) //Eject the technology disk. eject_disk("tech") screen = RDSCREEN_MENU say("Ejecting Technology Disk") if(ls["deconstruct"]) if((last_long_action + 1 SECONDS) > world.time) return last_long_action = world.time if(QDELETED(linked_destroy)) say("No Destructive Analyzer Linked!") return if(!linked_destroy.user_try_decon_id(ls["deconstruct"], usr)) say("Destructive analysis failed!") //Protolathe Materials if(ls["disposeP"]) //Causes the protolathe to dispose of a single reagent (all of it) if(QDELETED(linked_lathe)) say("No Protolathe Linked!") return linked_lathe.reagents.del_reagent(ls["disposeP"]) if(ls["disposeallP"]) //Causes the protolathe to dispose of all it's reagents. if(QDELETED(linked_lathe)) say("No Protolathe Linked!") return linked_lathe.reagents.clear_reagents() if(ls["ejectsheet"]) //Causes the protolathe to eject a sheet of material if(QDELETED(linked_lathe)) say("No Protolathe Linked!") return if(!linked_lathe.materials.mat_container) say("No material storage linked to protolathe!") return var/datum/material/M = locate(ls["ejectsheet"]) in linked_lathe.materials.mat_container.materials linked_lathe.eject_sheets(M, ls["eject_amt"]) //Circuit Imprinter Materials if(ls["disposeI"]) //Causes the circuit imprinter to dispose of a single reagent (all of it) if(QDELETED(linked_imprinter)) say("No Circuit Imprinter Linked!") return linked_imprinter.reagents.del_reagent(ls["disposeI"]) if(ls["disposeallI"]) //Causes the circuit imprinter to dispose of all it's reagents. if(QDELETED(linked_imprinter)) say("No Circuit Imprinter Linked!") return linked_imprinter.reagents.clear_reagents() if(ls["imprinter_ejectsheet"]) //Causes the imprinter to eject a sheet of material if(QDELETED(linked_imprinter)) say("No Circuit Imprinter Linked!") return if(!linked_imprinter.materials.mat_container) say("No material storage linked to circuit imprinter!") return var/datum/material/M = locate(ls["imprinter_ejectsheet"]) in linked_imprinter.materials.mat_container.materials linked_imprinter.eject_sheets(M, ls["eject_amt"]) if(ls["disk_slot"]) disk_slot_selected = text2num(ls["disk_slot"]) if(ls["research_node"]) if(!research_control) return //honestly should call them out for href exploiting :^) if(!SSresearch.science_tech.available_nodes[ls["research_node"]]) return //Nope! research_node(ls["research_node"], usr) if(ls["clear_tech"]) //Erase la on the technology disk. if(QDELETED(t_disk)) say("No Technology Disk Inserted!") return qdel(t_disk.stored_research) t_disk.stored_research = new say("Wiping technology disk.") if(ls["copy_tech"]) //Copy some technology from the research holder to the disk. if(QDELETED(t_disk)) say("No Technology Disk Inserted!") return stored_research.copy_research_to(t_disk.stored_research) screen = RDSCREEN_TECHDISK say("Downloading to technology disk.") if(ls["clear_design"]) //Erases la on the design disk. if(QDELETED(d_disk)) say("No Design Disk Inserted!") return var/n = text2num(ls["clear_design"]) if(!n) for(var/i in 1 to d_disk.max_blueprints) d_disk.blueprints[i] = null say("Wiping design disk.") else var/datum/design/D = d_disk.blueprints[n] say("Wiping design [D.name] from design disk.") d_disk.blueprints[n] = null if(ls["search"]) //Search for designs with name matching pattern searchstring = ls["to_search"] searchtype = ls["type"] rescan_views() if(searchtype == "proto") screen = RDSCREEN_PROTOLATHE_SEARCH else screen = RDSCREEN_IMPRINTER_SEARCH if(ls["updt_tech"]) //Uple the research holder with information from the technology disk. if(QDELETED(t_disk)) say("No Technology Disk Inserted!") return say("Uploading technology disk.") t_disk.stored_research.copy_research_to(stored_research) if(ls["copy_design"]) //Copy design from the research holder to the design disk. if(QDELETED(d_disk)) say("No Design Disk Inserted!") return var/slot = text2num(ls["copy_design"]) var/datum/design/D = SSresearch.techweb_design_by_id(ls["copy_design_ID"]) if(D) var/autolathe_friendly = TRUE if(D.reagents_list.len) autolathe_friendly = FALSE D.category -= "Imported" else for(var/x in D.materials) if( !(x in list(/datum/material/iron, /datum/material/glass))) autolathe_friendly = FALSE D.category -= "Imported" if(D.build_type & (AUTOLATHE|PROTOLATHE|TOYLATHE)) // Specifically excludes circuit imprinter and mechfab D.build_type = autolathe_friendly ? (D.build_type | AUTOLATHE) : D.build_type D.category |= "Imported" d_disk.blueprints[slot] = D screen = RDSCREEN_DESIGNDISK if(ls["eject_item"]) //Eject the item inside the destructive analyzer. if(QDELETED(linked_destroy)) say("No Destructive Analyzer Linked!") return if(linked_destroy.busy) to_chat(usr, "The destructive analyzer is busy at the moment.") else if(linked_destroy.loaded_item) linked_destroy.unload_item() screen = RDSCREEN_MENU if(ls["view_node"]) selected_node_id = ls["view_node"] screen = RDSCREEN_TECHWEB_NODEVIEW if(ls["view_design"]) selected_design_id = ls["view_design"] screen = RDSCREEN_TECHWEB_DESIGNVIEW if(ls["updt_design"]) //Uploads a design from disk to the techweb. if(QDELETED(d_disk)) say("No design disk found.") return var/n = text2num(ls["updt_design"]) if(!n) for(var/D in d_disk.blueprints) if(D) stored_research.add_design(D, TRUE) else stored_research.add_design(d_disk.blueprints[n], TRUE) updateUsrDialog() /obj/machinery/computer/rdconsole/ui_interact(mob/user) . = ..() var/datum/browser/popup = new(user, "rndconsole", name, 900, 600) var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/research_designs) popup.add_head_content("") popup.add_stylesheet("techwebs", 'html/browser/techwebs.css') popup.set_content(generate_ui()) popup.open() /obj/machinery/computer/rdconsole/proc/tdisk_uple_complete() tdisk_uple = FALSE updateUsrDialog() /obj/machinery/computer/rdconsole/proc/ddisk_uple_complete() ddisk_uple = FALSE updateUsrDialog() /obj/machinery/computer/rdconsole/proc/eject_disk(type) if(type == "design") d_disk.forceMove(get_turf(src)) d_disk = null if(type == "tech") t_disk.forceMove(get_turf(src)) t_disk = null /obj/machinery/computer/rdconsole/proc/rescan_views() var/compare matching_design_ids.Cut() if(searchtype == "proto") compare = PROTOLATHE else if(searchtype == "imprint") compare = IMPRINTER for(var/v in stored_research.researched_designs) var/datum/design/D = SSresearch.techweb_design_by_id(v) if(!(D.build_type & compare)) continue if(findtext(D.name,searchstring)) matching_design_ids.Add(D.id) /obj/machinery/computer/rdconsole/proc/check_canprint(datum/design/D, buildtype) var/amount = 50 if(buildtype == IMPRINTER) if(QDELETED(linked_imprinter)) return FALSE for(var/M in D.materials + D.reagents_list) amount = min(amount, linked_imprinter.check_mat(D, M)) if(amount < 1) return FALSE else if(buildtype == PROTOLATHE) if(QDELETED(linked_lathe)) return FALSE for(var/M in D.materials + D.reagents_list) amount = min(amount, linked_lathe.check_mat(D, M)) if(amount < 1) return FALSE else return FALSE return amount /obj/machinery/computer/rdconsole/proc/lock_console(mob/user) locked = TRUE /obj/machinery/computer/rdconsole/proc/unlock_console(mob/user) locked = FALSE /obj/machinery/computer/rdconsole/robotics name = "Robotics R&D Console" req_access = null req_access_txt = "29" /obj/machinery/computer/rdconsole/robotics/Initialize(mapload) . = ..() if(circuit) circuit.name = "R&D Console - Robotics (Computer Board)" circuit.build_path = /obj/machinery/computer/rdconsole/robotics /obj/machinery/computer/rdconsole/core name = "Core R&D Console" /obj/machinery/computer/rdconsole/experiment name = "E.X.P.E.R.I-MENTOR R&D Console"