diff --git a/code/modules/modular_computers/computers/item/computer_ui.dm b/code/modules/modular_computers/computers/item/computer_ui.dm index 4313bf2efbd..49859f46b4d 100644 --- a/code/modules/modular_computers/computers/item/computer_ui.dm +++ b/code/modules/modular_computers/computers/item/computer_ui.dm @@ -108,6 +108,7 @@ var/datum/computer_file/program/ai_restorer/airestore_app = locate() in stored_files if(airestore_app?.stored_card) data["removable_media"] += "intelliCard" + data["removable_media"] += handle_ui_removable_media_insert(user) // FLUFFY FRONTIER ADD data["programs"] = list() for(var/datum/computer_file/program/program in stored_files) @@ -207,6 +208,7 @@ if(RemoveID(user)) playsound(src, 'sound/machines/card_slide.ogg', 50) return TRUE + return handle_ui_removable_media_eject(param, user) // FLUFFFY FRONTIER ADD if("PC_Imprint_ID") imprint_id() diff --git a/code/modules/modular_computers/file_system/programs/techweb.dm b/code/modules/modular_computers/file_system/programs/techweb.dm index a72eef1bc9a..e6ceafb28f5 100644 --- a/code/modules/modular_computers/file_system/programs/techweb.dm +++ b/code/modules/modular_computers/file_system/programs/techweb.dm @@ -25,13 +25,17 @@ . = ..() if(!CONFIG_GET(flag/no_default_techweb_link) && !stored_research) CONNECT_TO_RND_SERVER_ROUNDSTART(stored_research, computer) + handle_rnd_control_install() // FLUFFY FRONTIER ADD /datum/computer_file/program/science/application_attackby(obj/item/attacking_item, mob/living/user) + if (istype(attacking_item, /obj/item/disk/tech_disk) || istype(attacking_item, /obj/item/disk/design_disk)) return handle_disks_insertion(attacking_item, user) // FLUFFY FRONTTIER ADD if(!istype(attacking_item, /obj/item/multitool)) return FALSE var/obj/item/multitool/attacking_tool = attacking_item if(!QDELETED(attacking_tool.buffer) && istype(attacking_tool.buffer, /datum/techweb)) + handle_rnd_control_remove() // FLUFFY FRONTIER ADD stored_research = attacking_tool.buffer + handle_rnd_control_install() // FLUFFY FRONTIER ADD return TRUE /datum/computer_file/program/science/ui_assets(mob/user) @@ -57,6 +61,7 @@ "d_disk" = null, //See above. "locked" = locked, ) + data = handle_disks_ui_data(data) // FLUFFY FRONTIER ADD // Serialize all nodes to display for(var/tier in stored_research.tiers) @@ -94,6 +99,7 @@ if (locked && action != "toggleLock") computer.say("Console is locked, cannot perform further actions.") return TRUE + if (action in list("ejectDisk", "uploadDisk", "loadTech")) return handle_disks_ui_act(action, params) // FLUFFY FRONTIER ADD switch (action) if ("toggleLock") diff --git a/tff_modular/modules/all_computers_to_modular_consoles/_helper.dm b/tff_modular/modules/all_computers_to_modular_consoles/_helper.dm new file mode 100644 index 00000000000..9da8b5c412f --- /dev/null +++ b/tff_modular/modules/all_computers_to_modular_consoles/_helper.dm @@ -0,0 +1,53 @@ +/* +// May I be cursed, but I am to lazy to copypast atom/allowed() code now +/datum/computer_file/program/proc/allowed(mob/accessor) + var/list/tmp_req_access = computer.req_access + var/list/tmp_req_one_access = computer.req_one_access + computer.req_access = null + computer.req_one_access = run_access + . = computer.allowed(accessor) + computer.req_access = tmp_req_access + computer.req_one_access = tmp_req_one_access +*/ +/datum/techweb + // We wanna track not only consoles but NT apps that connected to us too + var/list/datum/computer_file/program/science/apps_accessing = list() + +/datum/computer_file/program/proc/can_run_Adjacent(mob/accessor, loud, access_to_check, downloading, list/access) + // TODO: atom/allowed() handles syndie borgs. We - not. + if (can_run(accessor, loud, access_to_check, downloading, access)) + return TRUE + + // atom/allowed() copycode + var/obj/item/active_item = accessor.get_active_held_item() + var/obj/item/inactive_item = accessor.get_inactive_held_item() + if((active_item && can_run(accessor, loud, access_to_check, downloading, active_item?.GetAccess())) || (inactive_item && can_run(accessor, loud, access_to_check, downloading, inactive_item?.GetAccess()))) + return TRUE + else if(ishuman(accessor)) + var/mob/living/carbon/human/human_accessor = accessor + if(can_run(accessor, loud, access_to_check, downloading, human_accessor.wear_id?.GetAccess())) + return TRUE + else if(isanimal(accessor)) + var/mob/living/simple_animal/animal = accessor + if(can_run(accessor, loud, access_to_check, downloading, animal.access_card?.GetAccess())) + return TRUE + else if(isbrain(accessor)) + var/obj/item/mmi/brain_mmi = get(accessor.loc, /obj/item/mmi) + if(brain_mmi && ismecha(brain_mmi.loc)) + var/obj/vehicle/sealed/mecha/big_stompy_robot = brain_mmi.loc + return can_run(accessor, loud, access_to_check, downloading, big_stompy_robot.accesses) + return FALSE + +// Required access override for disk_binded +/datum/computer_file/program/disk_binded/can_run_Adjacent(mob/accessor, loud, access_to_check, downloading, list/access) + if (!access_to_check && length(download_access)) + access_to_check = download_access + + return ..() + +/datum/computer_file/program/proc/can_run_on_flags_to_text(flags = can_run_on_flags, as_list = FALSE) + if (flags == PROGRAM_ALL) + return as_list ? list("Anything") : "Anything" + else + var/list/supportable = bitfield_to_list(flags, list("Console", "Laptop", "PDA")) + return as_list ? supportable : supportable.Join(" | ") diff --git a/tff_modular/modules/all_computers_to_modular_consoles/circuit_disk.dm b/tff_modular/modules/all_computers_to_modular_consoles/circuit_disk.dm new file mode 100644 index 00000000000..ec1459da4ba --- /dev/null +++ b/tff_modular/modules/all_computers_to_modular_consoles/circuit_disk.dm @@ -0,0 +1,30 @@ +/obj/item/computer_console_disk + name = "Encrypted NTnet Modem" + desc = "Contains software which allows computer to establish secure connection to NTNet for certain function" + icon = 'icons/obj/devices/circuitry_n_data.dmi' + icon_state = "datadisk6" + // Actual program for instalation + var/datum/computer_file/program/disk_binded/program + // Pointer to program, cloned into PC, to remove when disk ejecting + var/datum/computer_file/program/disk_binded/installed_clone + +/obj/item/computer_console_disk/Initialize(mapload) + . = ..() + if (program) + if (ispath(program)) + program = new program() + name = "encrypted connection driver ([program.filename])" + desc = "Contains software which allows computer to establish secure connection to NTNet for certain function.\n\n[program.extended_desc]" + +/obj/item/computer_console_disk/Destroy(force) + if (program && isdatum(program)) + qdel(program) + program = null + if (installed_clone) + qdel(installed_clone) + installed_clone = null + + . = ..() + +/obj/item/computer_console_disk/command + icon_state = "datadisk7" diff --git a/tff_modular/modules/all_computers_to_modular_consoles/computer_ui.dm b/tff_modular/modules/all_computers_to_modular_consoles/computer_ui.dm new file mode 100644 index 00000000000..ae01eaafa5a --- /dev/null +++ b/tff_modular/modules/all_computers_to_modular_consoles/computer_ui.dm @@ -0,0 +1,36 @@ +/obj/item/modular_computer/proc/handle_ui_removable_media_insert(mob/user) + var/list/removable_media = list() + + // Removable console data disk + var/datum/computer_file/program/filemanager/fm = locate() in stored_files + if (fm?.console_disk) + removable_media += "[HAS_TRAIT(user, TRAIT_KNOW_ENGI_WIRES) ? "Safe removal:" : "Unsafe eject:"] [fm.console_disk.program?.filename] driver" + + // Science Hub disks + var/datum/computer_file/program/science/rnd = locate() in stored_files + if (rnd?.t_disk) + removable_media += "Technology Disk" + if (rnd?.d_disk) + removable_media += "Design Disk" + + return removable_media + +/obj/item/modular_computer/proc/handle_ui_removable_media_eject(param, mob/user) + // Removable console data disk (switch wants constant expression) + var/datum/computer_file/program/filemanager/fm = locate() in stored_files + if (param == "[HAS_TRAIT(user, TRAIT_KNOW_ENGI_WIRES) ? "Safe removal:" : "Unsafe eject:"] [fm?.console_disk?.program?.filename] driver") + if (fm?.try_eject(user)) + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + return TRUE + return + switch(param) + // Science Hub disks + if ("Technology Disk", "Design Disk") + var/datum/computer_file/program/science/rnd = locate() in stored_files + if (!rnd) + return + if(rnd.try_eject(user)) + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + return TRUE + + return diff --git a/tff_modular/modules/all_computers_to_modular_consoles/consoles_preset.dm b/tff_modular/modules/all_computers_to_modular_consoles/consoles_preset.dm new file mode 100644 index 00000000000..03068bc1659 --- /dev/null +++ b/tff_modular/modules/all_computers_to_modular_consoles/consoles_preset.dm @@ -0,0 +1,107 @@ +/obj/machinery/modular_computer/preset/battery_less + var/start_on_power_restore = FALSE + +/obj/machinery/modular_computer/preset/battery_less/Initialize(mapload) + . = ..() + if (!cpu) + return + + // ugh.. no idea how to change cpu type without breaking everything.. So just let it be and remove it's cell + var/cell = cpu.internal_cell + cpu.internal_cell = null + if (cell) + qdel(cell) + +/obj/machinery/modular_computer/preset/battery_less/power_change() + if (!start_on_power_restore) + return ..() + + var/was_unpowered = machine_stat & NOPOWER + . = ..() + if (was_unpowered && !(machine_stat & (BROKEN|NOPOWER)) && cpu && !cpu.enabled) + // Why not cpu.turn_on()? because its crashes without user =/ + if(cpu.looping_sound) + cpu.soundloop.start() + cpu.enabled = TRUE + cpu.update_appearance() + SEND_SIGNAL(cpu, COMSIG_MODULAR_COMPUTER_TURNED_ON, null) + +/obj/machinery/modular_computer/preset/battery_less/console + start_on_power_restore = TRUE + // Disk that will be installed on Initialize() + var/obj/item/computer_console_disk/console_disk + // If no disk. But us we making sure, that we autorun always as PC exist + // No need to fill if console_disk filled + var/datum/computer_file/program/autorunnable + // Sprites from consoles file. Written by program on console_disk. Can be overriden by you or mapper + var/icon_keyboard + +/obj/machinery/modular_computer/preset/battery_less/console/Initialize(mapload) + if (!console_disk && autorunnable && !(autorunnable in starting_programs)) + starting_programs += autorunnable + + . = ..() + + if (cpu && console_disk) + var/datum/computer_file/program/filemanager/filemanager = cpu.find_file_by_name("filemanager") + console_disk = new console_disk(cpu) + + // Oh, preset? Get fancy keyboard for free! (if provided by your program and not overriden) + if (!icon_keyboard && console_disk.program) + icon_keyboard = console_disk.program.icon_keyboard + + filemanager.application_attackby(console_disk) + + else if (cpu && autorunnable) + var/datum/computer_file/program/prog = locate(autorunnable) in cpu.stored_files + // First start for free + cpu.active_program = prog + RegisterSignal(cpu, COMSIG_MODULAR_COMPUTER_TURNED_ON, PROC_REF(autorun)) + + // Autoenable on init + // cpu.turn_on() copycode + if(cpu.use_energy(cpu.base_active_power_usage)) // checks if the PC is powered + if(cpu.looping_sound) + cpu.soundloop.skip_starting_sounds = TRUE + cpu.soundloop.start() + cpu.soundloop.skip_starting_sounds = initial(cpu.soundloop.skip_starting_sounds) + cpu.enabled = TRUE + cpu.update_appearance() + SEND_SIGNAL(cpu, COMSIG_MODULAR_COMPUTER_TURNED_ON, null) + +/obj/machinery/modular_computer/preset/battery_less/console/Destroy() + UnregisterSignal(cpu, COMSIG_MODULAR_COMPUTER_TURNED_ON) + . = ..() + +// Custom keyboard icon for maploaded consoles +/obj/machinery/modular_computer/preset/battery_less/console/update_overlays() + . = ..() + if (icon_keyboard) + // There was keyboard_change_icon var but its always TRUE... + if(machine_stat & NOPOWER || !cpu?.enabled) + . += mutable_appearance('icons/obj/machines/computer.dmi', "[icon_keyboard]_off") + else + . += mutable_appearance('icons/obj/machines/computer.dmi', icon_keyboard) + + +// Only for not disked programs like Science Hub or Cargo. Those who accessed ingame via NTnet +/obj/machinery/modular_computer/preset/battery_less/console/proc/autorun(datum/source, mob/user) + SIGNAL_HANDLER + + if (cpu && autorunnable) + var/datum/computer_file/program/prog = locate(autorunnable) in cpu.stored_files + if (prog) + // Not writing in active_programs so user need to check his access + cpu.open_program(user, prog, cpu.enabled) + +// Actual presets of non console_disk computers +/obj/machinery/modular_computer/preset/battery_less/console/rdconsole_unQoL + name = "R&D Console" + desc = "A console used to interface with R&D tools." + icon_keyboard = "rd_key" + autorunnable = /datum/computer_file/program/science + +/obj/machinery/modular_computer/preset/battery_less/console/cargo_unQoL + name = "supply console" + desc = "Used to order supplies, approve requests, and control the shuttle." + autorunnable = /datum/computer_file/program/budgetorders diff --git a/tff_modular/modules/all_computers_to_modular_consoles/disk_binded.dm b/tff_modular/modules/all_computers_to_modular_consoles/disk_binded.dm new file mode 100644 index 00000000000..da69453381c --- /dev/null +++ b/tff_modular/modules/all_computers_to_modular_consoles/disk_binded.dm @@ -0,0 +1,28 @@ +/datum/computer_file/program/disk_binded + size = 0 + program_flags = PROGRAM_REQUIRES_NTNET + can_run_on_flags = PROGRAM_CONSOLE + undeletable = TRUE + // Okay. Now about accesses: we are never on NTstore, so download_access doesn't care + // Meanwhile program run is always (or almost) free, but interactions... + // So run_access should be empty, but all yours req_access type into download_access + // So I didn't have to create another access variable + download_access = list() + run_access = list() + // Icon_state of the keyboard overlay for mapload. If any... + var/icon_keyboard + +/datum/computer_file/program/disk_binded/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing) + ..() + RegisterSignal(computer, COMSIG_MODULAR_COMPUTER_TURNED_ON, PROC_REF(autorun)) + +/datum/computer_file/program/disk_binded/Destroy() + . = ..() + + if (!QDELETED(computer)) + UnregisterSignal(computer, COMSIG_MODULAR_COMPUTER_TURNED_ON) + +/datum/computer_file/program/disk_binded/proc/autorun(datum/source, mob/user) + SIGNAL_HANDLER + + computer.open_program(user, src, computer.enabled) diff --git a/tff_modular/modules/all_computers_to_modular_consoles/file_browser.dm b/tff_modular/modules/all_computers_to_modular_consoles/file_browser.dm new file mode 100644 index 00000000000..11e0cd40dbb --- /dev/null +++ b/tff_modular/modules/all_computers_to_modular_consoles/file_browser.dm @@ -0,0 +1,70 @@ +/datum/computer_file/program/filemanager + var/obj/item/computer_console_disk/console_disk + +/datum/computer_file/program/filemanager/application_attackby(obj/item/computer_console_disk/attacking_item, mob/living/user) + if (!istype(attacking_item)) + return FALSE + + if (console_disk) + if (user) + to_chat(user, span_warning("It's secure disk drive already occupied!")) + return FALSE + if (!attacking_item.program) + computer.say("I/O ERROR: Unable to access encrypted data disk. Ejecting...") + return FALSE + + if (!attacking_item.program.is_supported_by_hardware(computer.hardware_flag)) + var/supported_hardware = attacking_item.program.can_run_on_flags_to_text() + if (supported_hardware == "Anything") + // how you aren't supported, if you support anything?! + computer.say("HARDWARE ERROR: Software compatibility mismatch! Please report that info to NTTechSupport. PC hardware code: [computer.hardware_flag]. Filename: [attacking_item.program.filename].[lowertext(attacking_item.program.filetype)]") + return FALSE + else + computer.say("HARDWARE ERROR: Incompatible software. Ejecting... Supported devices: [supported_hardware]") + return FALSE + + if(user && !user.transferItemToLoc(attacking_item, computer)) + return FALSE + console_disk = attacking_item + playsound(computer, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + + if (console_disk.program) + // Remove BSOD if present + var/datum/computer_file/program/bsod/bsod = computer.find_file_by_name("nt_recovery") + if (bsod) + computer.remove_file(bsod) + + var/datum/computer_file/program/disk_binded/clone = console_disk.program.clone() + console_disk.installed_clone = clone + computer.store_file(clone) + // Initial start + computer.open_program(user, clone, computer.enabled) + + return TRUE + +/datum/computer_file/program/filemanager/try_eject(mob/living/user, forced = FALSE) + if (forced || !user || HAS_TRAIT(user, TRAIT_KNOW_ENGI_WIRES)) + if (user) + user.put_in_hands(console_disk) + user.visible_message(span_warning("[user] removes [console_disk] from [computer]!"), span_notice("You use 'Safely Remove Hardware' option to eject [console_disk] from [computer]...")) + else + console_disk.forceMove(computer.drop_location()) + computer.remove_file(console_disk.installed_clone) + console_disk.installed_clone = null + console_disk = null + return TRUE + else + // 2 to unscrew, 3 to eject glass, cut wires and eject circuit + user.visible_message(span_warning("[user] tries to rip off [console_disk] from [computer]!"), span_notice("You try to forcibly remove stuck [console_disk] from [computer]...")) + if (do_after(user, 5 SECONDS, computer.physical ? computer.physical : get_turf(computer))) + var/datum/computer_file/program/bsod/bsod = new(lowertext("[console_disk.program.filename].[console_disk.program.filetype]")) + + computer.remove_file(console_disk.installed_clone) + user.put_in_hands(console_disk) + console_disk.installed_clone = null + console_disk = null + + computer.store_file(bsod) + return TRUE + to_chat(user, span_warning("You should be near \the [computer.physical ? computer.physical : computer]!")) + return FALSE diff --git a/tff_modular/modules/all_computers_to_modular_consoles/integration.dm b/tff_modular/modules/all_computers_to_modular_consoles/integration.dm new file mode 100644 index 00000000000..f6231584326 --- /dev/null +++ b/tff_modular/modules/all_computers_to_modular_consoles/integration.dm @@ -0,0 +1,21 @@ +GLOBAL_LIST_INIT(consoles_replacement_map, list( + /obj/machinery/computer/rdservercontrol = /obj/machinery/modular_computer/preset/battery_less/console/rdservercontrol, +)) + +/obj/machinery/computer/Initialize(mapload, obj/item/circuitboard/C) + . = ..() + if (mapload && (src.type in GLOB.consoles_replacement_map)) + var/obj/machinery/modular_computer/preset/battery_less/console/console = GLOB.consoles_replacement_map[src.type] + console = new console(src.loc) + transfer_data_to_modular_console(console) + console.update_appearance() + return INITIALIZE_HINT_QDEL + +/obj/machinery/computer/proc/transfer_data_to_modular_console(obj/machinery/modular_computer/preset/battery_less/console/console) + SHOULD_CALL_PARENT(TRUE) + + console.setDir(dir) + console.name = name + + if (console.cpu) + console.cpu.desc = desc diff --git a/tff_modular/modules/all_computers_to_modular_consoles/programms/_bsod_program.dm b/tff_modular/modules/all_computers_to_modular_consoles/programms/_bsod_program.dm new file mode 100644 index 00000000000..e82d9b81c3d --- /dev/null +++ b/tff_modular/modules/all_computers_to_modular_consoles/programms/_bsod_program.dm @@ -0,0 +1,129 @@ +/datum/computer_file/program/bsod + filename = "nt_recovery" + filedesc = "System Recovery" + extended_desc = "When something goes wrong this program should tell you how to fix it." + undeletable = TRUE + size = 0 + power_cell_use = NONE + program_flags = PROGRAM_HEADER | PROGRAM_RUNS_WITHOUT_POWER + program_open_overlay = "bsod" + program_icon = "bug-slash" + tgui_id = "NtosConsolesRevamp" + + var/bsod_reason = "unknown.dbg" + var/initial_icon_state_menu = "menu" + var/modular_icon_state_menu = "menu" + var/modular_icon_state_screensaver = "standby" + +/datum/computer_file/program/bsod/New(bsod_source) + . = ..() + if (bsod_source) + bsod_reason = bsod_source + +/datum/computer_file/program/bsod/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing) + ..() + RegisterSignal(computer, COMSIG_MODULAR_COMPUTER_TURNED_ON, PROC_REF(computer_on)) + + playsound(computer, 'sound/machines/terminal_alert.ogg', 100) + initial_icon_state_menu = computer_installing.icon_state_menu + + // Show BSOD in any condition + computer_installing.icon_state_menu = "bsod" + if (computer_installing.physical && istype(computer_installing.physical, /obj/machinery/modular_computer)) + var/obj/machinery/modular_computer/console = computer_installing.physical + modular_icon_state_menu = console.screen_icon_state_menu + modular_icon_state_screensaver = console.screen_icon_screensaver + + console.screen_icon_state_menu = "bsod" + console.screen_icon_screensaver = "bsod" + + if(!computer.open_program(null, src, computer_installing.enabled)) + // Opening program will update icon, so we need to do this only if program wasn't opened + update_computer_icon() + +/datum/computer_file/program/bsod/Destroy() + computer.icon_state_menu = initial_icon_state_menu + + // Curse you staionary console! + if (computer.physical && istype(computer.physical, /obj/machinery/modular_computer)) + var/obj/machinery/modular_computer/console = computer.physical + console.screen_icon_state_menu = modular_icon_state_menu + console.screen_icon_screensaver = modular_icon_state_screensaver + + computer.physical?.visible_message(span_notice("\The [computer] flashes its screen few times as it reboots from safe mode.")) + playsound(computer, 'sound/machines/computer/computer_start.ogg', 10) + update_computer_icon() + UnregisterSignal(computer, COMSIG_MODULAR_COMPUTER_TURNED_ON) + . = ..() + +/datum/computer_file/program/bsod/on_examine(obj/item/modular_computer/source, mob/user) + var/list/examine_text = list() + examine_text += span_warning("Its screen tells you that previous session of [bsod_reason] finished incorrectly.") + examine_text += span_notice("However you can reboot [computer]\s driver with multitool to remove that noisy message.\nOr just install another similar program.") + return examine_text + +/datum/computer_file/program/bsod/application_attackby(obj/item/attacking_item, mob/living/user) + if(!istype(attacking_item, /obj/item/multitool)) + return FALSE + + user.visible_message(span_notice("[user] tries to diagnose [computer]\s BSOD reason."), span_notice("You plug [attacking_item] pins into [computer] to force restart its drivers...")) + playsound(computer, 'sound/machines/terminal_processing.ogg', 50) + if (do_after(user, 10 SECONDS, computer.physical ? computer.physical : get_turf(computer))) + playsound(computer, 'sound/machines/high_tech_confirm.ogg', 50) + computer.remove_file(src) + return TRUE + return FALSE + +/datum/computer_file/program/bsod/ui_static_data(mob/user) + var/list/data = list() + data["show_imprint"] = istype(computer, /obj/item/modular_computer/pda) + return data + +// If PC has active program it won't sent us any data. +// But for fancy "Overlay" we still need it. So we will collect it manualy +/datum/computer_file/program/bsod/ui_data(mob/user) + var/list/data = list() + data["pai"] = computer.inserted_pai + data["has_light"] = computer.has_light + data["light_on"] = computer.light_on + data["comp_light_color"] = computer.comp_light_color + + data["login"] = list( + IDName = computer.saved_identification || "Unknown", + IDJob = computer.saved_job || "Unknown", + ) + + data["proposed_login"] = list( + IDInserted = computer.computer_id_slot ? TRUE : FALSE, + IDName = computer.computer_id_slot?.registered_name, + IDJob = computer.computer_id_slot?.assignment, + ) + + data["removable_media"] = list() + if(computer.inserted_disk) + data["removable_media"] += "Eject Disk" + var/datum/computer_file/program/ai_restorer/airestore_app = locate() in computer.stored_files + if(airestore_app?.stored_card) + data["removable_media"] += "intelliCard" + data["removable_media"] += computer.handle_ui_removable_media_insert(user) + + data["programs"] = list() + for(var/datum/computer_file/program/program in computer.stored_files) + data["programs"] += list(list( + "name" = program.filename, + "desc" = program.filedesc, + "header_program" = !!(program.program_flags & PROGRAM_HEADER), + "running" = !!(program in computer.idle_threads), + "icon" = program.program_icon, + "alert" = program.alert_pending, + )) + + // Nope no way to avoid us + data["PC_showexitprogram"] = FALSE + data["reason"] = bsod_reason + return data + +// I am inevitable +/datum/computer_file/program/bsod/proc/computer_on(datum/source, mob/user) + SIGNAL_HANDLER + computer.open_program(user, src, TRUE) diff --git a/tff_modular/modules/all_computers_to_modular_consoles/programms/rdconsole.dm b/tff_modular/modules/all_computers_to_modular_consoles/programms/rdconsole.dm new file mode 100644 index 00000000000..cc484ed0697 --- /dev/null +++ b/tff_modular/modules/all_computers_to_modular_consoles/programms/rdconsole.dm @@ -0,0 +1,154 @@ +#define RND_TECH_DISK "tech" +#define RND_DESIGN_DISK "design" + +/datum/computer_file/program/science + // The stored technology disk, if present + var/obj/item/disk/tech_disk/t_disk + // The stored design disk, if present + var/obj/item/disk/design_disk/d_disk + // Options same as can_run_on_flags + var/disk_support_hardware_flags = PROGRAM_CONSOLE + var/techweb_tracked = FALSE + +/datum/computer_file/program/science/proc/handle_rnd_control_install() + if (stored_research) + if (!techweb_tracked) + // Do not count PDAs in nullspace, please + if (computer.loc && !(src in stored_research.apps_accessing)) + stored_research.apps_accessing += src + techweb_tracked = TRUE + // Oh wait, you are off-station or emgged? Be unlocked, please! + if (!istype(stored_research, /datum/techweb/science) || (computer.obj_flags & EMAGGED)) + locked = FALSE + else + techweb_tracked = FALSE + +/datum/computer_file/program/science/proc/handle_rnd_control_remove() + if (stored_research) + stored_research.apps_accessing -= src + techweb_tracked = FALSE + +/datum/computer_file/program/science/Destroy() + handle_rnd_control_remove() + . = ..() + +// Why? Because on computer_file init moment, we are in nullspace. +// And bringing here LateInititialize() proc only for this is a bad idea +// Still do not need nullspaced apps in my RD Server Control >=( +/datum/computer_file/program/science/on_start(mob/living/user) + . = ..() + if (!techweb_tracked) + handle_rnd_control_install() + +/datum/computer_file/program/science/clone() + var/datum/computer_file/program/science/temp = ..() + // No, you can't reassemble console to reset access lock + temp.locked = TRUE + return temp + +/datum/computer_file/program/science/kill_program(mob/user) + try_eject(forced = TRUE) + return ..() + +/datum/computer_file/program/science/on_examine(obj/item/modular_computer/source, mob/user) + if (!(disk_support_hardware_flags & source.hardware_flag)) + return + + var/list/examine_text = list() + if(!t_disk && !d_disk) + examine_text += "It has a slot installed for science data disk." + return examine_text + + if(computer.Adjacent(user)) + examine_text += "It has a slot installed for science data which contains: [t_disk ? t_disk.name : d_disk.name]" + else + examine_text += "It has a slot installed for science data, which appears to be occupied." + // examine_text += span_info("Alt-click to eject the science data disk.") + return examine_text + +/datum/computer_file/program/science/proc/handle_disks_insertion(obj/item/D, mob/living/user) + // No disks in PDA please + if (!(disk_support_hardware_flags & computer.hardware_flag)) + to_chat(user, span_warning("There is no slot for [D]. Maybe you should try: [can_run_on_flags_to_text(disk_support_hardware_flags)]?")) + return FALSE + // Unfortunatly eject code doesn't support diffrent ejectables + if (t_disk || d_disk) + to_chat(user, span_warning("Science data disk slot already occupied!")) + return FALSE + if(istype(D, /obj/item/disk/tech_disk)) + if(!user.transferItemToLoc(D, computer)) + to_chat(user, span_warning("[D] is stuck to your hand!")) + return FALSE + t_disk = D + else if (istype(D, /obj/item/disk/design_disk)) + if(!user.transferItemToLoc(D, computer)) + to_chat(user, span_warning("[D] is stuck to your hand!")) + return FALSE + d_disk = D + to_chat(user, span_notice("You insert [D] into \the [computer.name]!")) + playsound(computer, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + return TRUE + +/datum/computer_file/program/science/proc/handle_disks_ui_data(list/data) + if (t_disk) + data["t_disk"] = list ( + "stored_research" = t_disk.stored_research.researched_nodes, + ) + if (d_disk) + data["d_disk"] = list("blueprints" = list()) + for (var/datum/design/D in d_disk.blueprints) + data["d_disk"]["blueprints"] += D.id + + return data + +/datum/computer_file/program/science/proc/handle_disks_ui_act(action, list/params) + switch(action) + if ("ejectDisk") + return try_eject() + if ("uploadDisk") + if (params["type"] == RND_DESIGN_DISK) + if(QDELETED(d_disk)) + computer.say("No design disk inserted!") + return TRUE + for(var/D in d_disk.blueprints) + if(D) + stored_research.add_design(D, TRUE) + computer.say("Uploading blueprints from disk.") + d_disk.on_upload(stored_research) + return TRUE + if (params["type"] == RND_TECH_DISK) + if (QDELETED(t_disk)) + computer.say("No tech disk inserted!") + return TRUE + computer.say("Uploading technology disk.") + t_disk.stored_research.copy_research_to(stored_research) + return TRUE + //Tech disk-only action. + if ("loadTech") + if(QDELETED(t_disk)) + computer.say("No tech disk inserted!") + return + stored_research.copy_research_to(t_disk.stored_research) + computer.say("Downloading to technology disk.") + return TRUE + +/datum/computer_file/program/science/try_eject(mob/living/user, forced = FALSE) + if (!t_disk && !d_disk) + if (user) + to_chat(user, span_warning("There is no card in \the [computer.name].")) + return FALSE + + var/obj/item/disk = t_disk ? t_disk : d_disk + if(user && computer.Adjacent(user)) + to_chat(user, span_notice("You remove [disk] from [computer.name].")) + user.put_in_hands(disk) + else + disk.forceMove(computer.drop_location()) + + t_disk = null + d_disk = null + + return TRUE + +#undef RND_TECH_DISK +#undef RND_DESIGN_DISK diff --git a/tff_modular/modules/all_computers_to_modular_consoles/programms/server_control.dm b/tff_modular/modules/all_computers_to_modular_consoles/programms/server_control.dm new file mode 100644 index 00000000000..d706b16da64 --- /dev/null +++ b/tff_modular/modules/all_computers_to_modular_consoles/programms/server_control.dm @@ -0,0 +1,118 @@ +/datum/computer_file/program/disk_binded/rdservercontrol + filename = "sci_net_admin" + filedesc = "Researh Network Admin Panel" + program_open_overlay = "research" + extended_desc = "Connect to the internal science server in order to control their behavior." + program_flags = PROGRAM_REQUIRES_NTNET + size = 0 + tgui_id = "NtosServerControl" + program_icon = FA_ICON_SERVER + download_access = list(ACCESS_RD) + icon_keyboard = "rd_key" + // Reference to global science techweb + var/datum/techweb/stored_research + +/datum/computer_file/program/disk_binded/rdservercontrol/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing) + . = ..() + if(!CONFIG_GET(flag/no_default_techweb_link) && !stored_research) + CONNECT_TO_RND_SERVER_ROUNDSTART(stored_research, computer) + +/datum/computer_file/program/disk_binded/rdservercontrol/application_attackby(obj/item/attacking_item, mob/living/user) + if(!istype(attacking_item, /obj/item/multitool)) + return FALSE + var/obj/item/multitool/attacking_tool = attacking_item + if(!QDELETED(attacking_tool.buffer) && istype(attacking_tool.buffer, /datum/techweb)) + stored_research = attacking_tool.buffer + computer.say("[filedesc]: Established connection to [stored_research.organization] research network.") // Network id: [stored_research.id] not sure, id may be OOC info + return TRUE + return FALSE + +/datum/computer_file/program/disk_binded/rdservercontrol/ui_data(mob/user) + var/list/data = list() + + data["server_connected"] = !!stored_research + + if(stored_research) + data["logs"] += stored_research.research_logs + + for(var/obj/machinery/rnd/server/server as anything in stored_research.techweb_servers) + data["servers"] += list(list( + "server_name" = server, + "server_details" = server.get_status_text(), + "server_disabled" = server.research_disabled, + "server_ref" = REF(server), + )) + + for(var/obj/machinery/computer/rdconsole/console as anything in stored_research.consoles_accessing) + data["consoles"] += list(list( + "console_name" = console, + "console_location" = console.loc == null ? "UNKNOWN" : get_area(console), + "console_locked" = console.locked, + "console_ref" = REF(console), + )) + for (var/datum/computer_file/program/science/app in stored_research.apps_accessing) + data["consoles"] += list(list( + "console_name" = app.computer, + "console_location" = app.computer.loc == null ? "UNKNOWN" : get_area(app.computer), + "console_locked" = app.locked, + "console_ref" = REF(app), + )) + + return data + +/datum/computer_file/program/disk_binded/rdservercontrol/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return TRUE + if(!can_run_Adjacent(usr) && !(computer.obj_flags & EMAGGED)) + computer.say("Access denied!") + playsound(computer, 'sound/machines/terminal_error.ogg', 20, TRUE) + return TRUE + + switch(action) + if("lockdown_server") + var/obj/machinery/rnd/server/server_selected = locate(params["selected_server"]) in stored_research.techweb_servers + if(!server_selected) + return FALSE + server_selected.toggle_disable(usr) + return TRUE + if("lock_console") + var/obj/machinery/computer/rdconsole/console_selected = locate(params["selected_console"]) in stored_research.consoles_accessing + if(!console_selected) + var/datum/computer_file/program/science/app = locate(params["selected_console"]) in stored_research.apps_accessing + if (!app) + return FALSE + app.locked = !app.locked + return TRUE + console_selected.locked = !console_selected.locked + return TRUE + +// Legacy computer code +// Inject into console code to add science app tracking +/* +/obj/machinery/computer/rdservercontrol/proc/handle_ui_data_apps_insertion() + var/list/data = list() + + for (var/datum/computer_file/program/science/app in stored_research.apps_accessing) + data += list(list( + "console_name" = app.computer, + "console_location" = app.computer.loc == null ? "UNKNOWN" : get_area(app.computer), + "console_locked" = app.locked, + "console_ref" = REF(app), + )) + return data + +/obj/machinery/computer/rdservercontrol/proc/handle_ui_act_apps_lock(choosen_app) + var/datum/computer_file/program/science/app = locate(choosen_app) in stored_research.apps_accessing + if (!app) + return FALSE + app.locked = !app.locked + return TRUE +*/ +/obj/item/computer_console_disk/command/rdservercontrol + program = /datum/computer_file/program/disk_binded/rdservercontrol + +/obj/machinery/modular_computer/preset/battery_less/console/rdservercontrol + name = "R&D Server Controller" + desc = "Manages access to research databases and consoles." + console_disk = /obj/item/computer_console_disk/command/rdservercontrol diff --git a/tgstation.dme b/tgstation.dme index 33f9e58a08f..953d08802b9 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -8282,6 +8282,16 @@ #include "tff_modular\master_files\code\modules\mod\_module.dm" #include "tff_modular\master_files\code\modules\mod\mod_clothes.dm" #include "tff_modular\master_files\code\modules\reagents\recipe\coagulant_recipe.dm" +#include "tff_modular\modules\all_computers_to_modular_consoles\_helper.dm" +#include "tff_modular\modules\all_computers_to_modular_consoles\circuit_disk.dm" +#include "tff_modular\modules\all_computers_to_modular_consoles\computer_ui.dm" +#include "tff_modular\modules\all_computers_to_modular_consoles\consoles_preset.dm" +#include "tff_modular\modules\all_computers_to_modular_consoles\disk_binded.dm" +#include "tff_modular\modules\all_computers_to_modular_consoles\file_browser.dm" +#include "tff_modular\modules\all_computers_to_modular_consoles\integration.dm" +#include "tff_modular\modules\all_computers_to_modular_consoles\programms\_bsod_program.dm" +#include "tff_modular\modules\all_computers_to_modular_consoles\programms\rdconsole.dm" +#include "tff_modular\modules\all_computers_to_modular_consoles\programms\server_control.dm" #include "tff_modular\modules\autoaccent\code\autoaccent.dm" #include "tff_modular\modules\barsigns\code\barsigns.dm" #include "tff_modular\modules\blooper\atoms_movable.dm" diff --git a/tgui/packages/tgui/interfaces/NtosConsolesRevamp.tsx b/tgui/packages/tgui/interfaces/NtosConsolesRevamp.tsx new file mode 100644 index 00000000000..135d2e3c63f --- /dev/null +++ b/tgui/packages/tgui/interfaces/NtosConsolesRevamp.tsx @@ -0,0 +1,80 @@ +// THIS IS A FLUFFY FONTIER UI FILE +import { ReactElement } from 'react'; + +import { useBackend } from '../backend'; +import { Blink, Box, Dimmer, Flex, Icon } from '../components'; +import { NtosWindow, Window } from '../layouts'; +import { NtosMain } from './NtosMain'; +// Components for replacement +import { ServerControl } from './ServerControl'; + +type Data = { + reason: string; +}; + +const replaceWindowWithNtosWindow = (node: ReactElement) => { + return ( + + + {node.props.children.props.children} + + + ); +}; + +export const NtosConsolesRevamp = (props) => { + const mainScreen = NtosMain(NtosWindow); + const { data } = useBackend(); + const { reason } = data; + return ( + + + + + + The application is not responding + +
+ + + + +
+ + +
+ + Error with process: +
+ ' + + {reason} + + ' +
+
+ + Try to plug back installation device or restart disk drive systems + with multitool + + + + {mainScreen.props.children.props.children} + + + ); +}; + +export const NtServerControl = (props) => { + return replaceWindowWithNtosWindow(ServerControl(Window)); +}; diff --git a/tgui/packages/tgui/interfaces/NtosServerControl.tsx b/tgui/packages/tgui/interfaces/NtosServerControl.tsx new file mode 100644 index 00000000000..0813a240217 --- /dev/null +++ b/tgui/packages/tgui/interfaces/NtosServerControl.tsx @@ -0,0 +1,5 @@ +import { NtServerControl } from './NtosConsolesRevamp'; + +export const NtosServerControl = (props) => { + return ; +};