diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index 84a6b7730c7..d0d72fc53f2 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -1,5 +1,3 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 - /obj/machinery/computer/robotics name = "robotics control console" desc = "Used to remotely lockdown or detonate linked cyborgs." @@ -9,218 +7,205 @@ req_access = list(access_robotics) circuit = "/obj/item/weapon/circuitboard/robotics" - var/id = 0.0 - var/temp = null - var/status = 0 - var/timeleft = 60 - var/stop = 0.0 - var/screen = 0 // 0 - Main Menu, 1 - Cyborg Status, 2 - Kill 'em All! -- In text - + var/safety = 1 /obj/machinery/computer/robotics/attack_ai(var/mob/user as mob) - return src.attack_hand(user) + ui_interact(user) /obj/machinery/computer/robotics/attack_hand(var/mob/user as mob) - if(..()) - return - if (src.z > 6) - user << "\red Unable to establish a connection: \black You're too far away from the station!" - return - user.set_machine(src) - var/dat - if (src.temp) - dat = "[src.temp]

Clear Screen" - else - if(screen == 0) - dat += "

Cyborg Control Console


" - dat += "1. Cyborg Status
" - dat += "2. Emergency Full Destruct
" - if(screen == 1) - for(var/mob/living/silicon/robot/R in mob_list) - if(istype(R, /mob/living/silicon/robot/drone)) - continue //There's a specific console for drones. - if(istype(user, /mob/living/silicon/ai)) - if (R.connected_ai != user) - continue - if(istype(user, /mob/living/silicon/robot)) - if (R != user) - continue - if(R.scrambledcodes) - continue + ui_interact(user) - dat += "[R.name] |" - if(R.stat) - dat += " Not Responding |" - else if (!R.canmove) - dat += " Locked Down |" - else - dat += " Operating Normally |" - if (!R.canmove) - else if(R.cell) - dat += " Battery Installed ([R.cell.charge]/[R.cell.maxcharge]) |" - else - dat += " No Cell Installed |" - if(R.module) - dat += " Module Installed ([R.module.name]) |" - else - dat += " No Module Installed |" - if(R.connected_ai) - dat += " Slaved to [R.connected_ai.name] |" - else - dat += " Independent from AI |" - if (istype(user, /mob/living/silicon)) - if((user.mind.special_role && user.mind.original == user) && !R.emagged) - dat += "(Hack) " - dat += "([R.canmove ? "Lockdown" : "Release"]) " - dat += "(Destroy)" - dat += "
" - dat += "(Return to Main Menu)
" - if(screen == 2) - if(!src.status) - dat += {"
Emergency Robot Self-Destruct
\nStatus: Off
- \n
- \nCountdown: [src.timeleft]/60 \[Reset\]
- \n
- \nStart Sequence
- \n
- \nClose"} - else - dat = {"Emergency Robot Self-Destruct
\nStatus: Activated
- \n
- \nCountdown: [src.timeleft]/60 \[Reset\]
- \n
\nStop Sequence
- \n
- \nClose"} - dat += "(Return to Main Menu)
" +/obj/machinery/computer/robotics/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + data["robots"] = get_cyborgs(user) + data["safety"] = safety + // Also applies for cyborgs. Hides the manual self-destruct button. + data["is_ai"] = user.isSilicon() - user << browse(dat, "window=computer;size=400x500") - onclose(user, "computer") - return + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "robot_control.tmpl", "Robotic Control Console", 400, 500) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) /obj/machinery/computer/robotics/Topic(href, href_list) if(..()) - return 1 - if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) + return + var/mob/user = usr + if(!src.allowed(user)) + user << "Access Denied" + return - if (href_list["eject"]) - src.temp = {"Destroy Robots?
-
\[Swipe ID to initiate destruction sequence\]
- Cancel"} - - else if (href_list["eject2"]) - var/obj/item/weapon/card/id/I = usr.get_active_hand() - if (istype(I, /obj/item/device/pda)) - var/obj/item/device/pda/pda = I - I = pda.id - if (istype(I)) - if(src.check_access(I)) - if (!status) - message_admins("\blue [key_name_admin(usr)] has initiated the global cyborg killswitch!") - log_game("\blue [key_name(usr)] has initiated the global cyborg killswitch!") - src.status = 1 - src.start_sequence() - src.temp = null - - else - usr << "\red Access Denied." - - else if (href_list["stop"]) - src.temp = {" - Stop Robot Destruction Sequence?
-
Yes
- No"} - - else if (href_list["stop2"]) - src.stop = 1 - src.temp = null - src.status = 0 - - else if (href_list["reset"]) - src.timeleft = 60 - - else if (href_list["temp"]) - src.temp = null - else if (href_list["screen"]) - switch(href_list["screen"]) - if("0") - screen = 0 - if("1") - screen = 1 - if("2") - screen = 2 - else if (href_list["killbot"]) - if(src.allowed(usr)) - var/mob/living/silicon/robot/R = locate(href_list["killbot"]) - if(R) - var/choice = input("Are you certain you wish to detonate [R.name]?") in list("Confirm", "Abort") - if(choice == "Confirm") - if(R && istype(R)) - if(R.mind && R.mind.special_role && R.emagged) - R << "Extreme danger. Termination codes detected. Scrambling security codes and automatic AI unlink triggered." - R.ResetSecurityCodes() - - else - message_admins("\blue [key_name_admin(usr)] detonated [R.name]!") - log_game("\blue [key_name_admin(usr)] detonated [R.name]!") - R.self_destruct() - else - usr << "\red Access Denied." - - else if (href_list["stopbot"]) - if(src.allowed(usr)) - var/mob/living/silicon/robot/R = locate(href_list["stopbot"]) - if(R && istype(R)) // Extra sancheck because of input var references - var/choice = input("Are you certain you wish to [R.canmove ? "lock down" : "release"] [R.name]?") in list("Confirm", "Abort") - if(choice == "Confirm") - if(R && istype(R)) - message_admins("\blue [key_name_admin(usr)] [R.canmove ? "locked down" : "released"] [R.name]!") - log_game("[key_name(usr)] [R.canmove ? "locked down" : "released"] [R.name]!") - R.canmove = !R.canmove - if (R.lockcharge) - // R.cell.charge = R.lockcharge - R.lockcharge = !R.lockcharge - R << "Your lockdown has been lifted!" - else - R.lockcharge = !R.lockcharge - // R.cell.charge = 0 - R << "You have been locked down!" - - else - usr << "\red Access Denied." - - else if (href_list["magbot"]) - if(src.allowed(usr)) - var/mob/living/silicon/robot/R = locate(href_list["magbot"]) - - // whatever weirdness this is supposed to be, but that is how the href gets added, so here it is again - if(istype(R) && istype(usr, /mob/living/silicon) && usr.mind.special_role && (usr.mind.original == usr) && !R.emagged) - - var/choice = input("Are you certain you wish to hack [R.name]?") in list("Confirm", "Abort") - if(choice == "Confirm") - if(R && istype(R)) -// message_admins("\blue [key_name_admin(usr)] emagged [R.name] using robotic console!") - log_game("[key_name(usr)] emagged [R.name] using robotic console!") - R.emagged = 1 - if(R.mind.special_role) - R.verbs += /mob/living/silicon/robot/proc/ResetSecurityCodes - - src.add_fingerprint(usr) - src.updateUsrDialog() - return - -/obj/machinery/computer/robotics/proc/start_sequence() - - do - if(src.stop) - src.stop = 0 + // Destroys the cyborg + if(href_list["detonate"]) + var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["detonate"]) + if(!target || !istype(target)) return - src.timeleft-- - sleep(10) - while(src.timeleft) + if(user.isMobAI() && (target.connected_ai != user)) + user << "Access Denied. This robot is not linked to you." + return + // Cyborgs may blow up themselves via the console + if(isrobot(user) && user != target) + user << "Access Denied." + return + var/choice = input("Really detonate [target.name]?") in list ("Yes", "No") + if(choice != "Yes") + return + if(!target || !istype(target)) + return + + // Antagonistic cyborgs? Left here for downstream + if(target.mind && target.mind.special_role && target.emagged) + target << "Extreme danger. Termination codes detected. Scrambling security codes and automatic AI unlink triggered." + target.ResetSecurityCodes() + else + message_admins("\blue [key_name_admin(usr)] detonated [target.name]!") + log_game("\blue [key_name_admin(usr)] detonated [target.name]!") + target << "Self-destruct command received." + spawn(10) + target.self_destruct() + + + + // Locks or unlocks the cyborg + else if (href_list["lockdown"]) + var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["lockdown"]) + if(!target || !istype(target)) + return + + if(user.isMobAI() && (target.connected_ai != user)) + user << "Access Denied. This robot is not linked to you." + return + + if(isrobot(user)) + user << "Access Denied." + return + + var/choice = input("Really [target.lockcharge ? "unlock" : "lockdown"] [target.name] ?") in list ("Yes", "No") + if(choice != "Yes") + return + + if(!target || !istype(target)) + return + + message_admins("\blue [key_name_admin(usr)] [target.canmove ? "locked down" : "released"] [target.name]!") + log_game("[key_name(usr)] [target.canmove ? "locked down" : "released"] [target.name]!") + target.canmove = !target.canmove + if (target.lockcharge) + target.lockcharge = !target.lockcharge + target << "Your lockdown has been lifted!" + else + target.lockcharge = !target.lockcharge + target << "You have been locked down!" + + // Remotely hacks the cyborg. Only antag AIs can do this and only to linked cyborgs. + else if (href_list["hack"]) + var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["hack"]) + if(!target || !istype(target)) + return + + // Antag AI checks + if(!istype(user, /mob/living/silicon/ai) || !(user.mind.special_role && user.mind.original == user)) + user << "Access Denied" + return + + if(target.emagged) + user << "Robot is already hacked." + return + + var/choice = input("Really hack [target.name]? This cannot be undone.") in list("Yes", "No") + if(choice != "Yes") + return + + if(!target || !istype(target)) + return + + message_admins("\blue [key_name_admin(usr)] emagged [target.name] using robotic console!") + log_game("[key_name(usr)] emagged [target.name] using robotic console!") + target.emagged = 1 + target << "Failsafe protocols overriden. New tools available." + + // Arms the emergency self-destruct system + else if(href_list["arm"]) + if(istype(user, /mob/living/silicon)) + user << "Access Denied" + return + + safety = !safety + user << "You [safety ? "disarm" : "arm"] the emergency self destruct" + + // Destroys all accessible cyborgs if safety is disabled + else if(href_list["nuke"]) + if(istype(user, /mob/living/silicon)) + user << "Access Denied" + return + if(safety) + user << "Self-destruct aborted - safety active" + return + + message_admins("\blue [key_name_admin(usr)] detonated all cyborgs!") + log_game("[key_name(usr)] detonated all cyborgs!") + + for(var/mob/living/silicon/robot/R in mob_list) + if(istype(R, /mob/living/silicon/robot/drone)) + continue + // Ignore antagonistic cyborgs + if(R.scrambledcodes) + continue + R << "Self-destruct command received." + spawn(10) + R.self_destruct() + + +// Proc: get_cyborgs() +// Parameters: 1 (operator - mob which is operating the console.) +// Description: Returns NanoUI-friendly list of accessible cyborgs. +/obj/machinery/computer/robotics/proc/get_cyborgs(var/mob/operator) + var/list/robots = list() for(var/mob/living/silicon/robot/R in mob_list) - if(!R.scrambledcodes && !istype(R, /mob/living/silicon/robot/drone)) - R.self_destruct() + // Ignore drones + if(istype(R, /mob/living/silicon/robot/drone)) + continue + // Ignore antagonistic cyborgs + if(R.scrambledcodes) + continue - return + var/list/robot = list() + robot["name"] = R.name + if(R.stat) + robot["status"] = "Not Responding" + else if (!R.canmove) + robot["status"] = "Lockdown" + else + robot["status"] = "Operational" + + if(R.cell) + robot["cell"] = 1 + robot["cell_capacity"] = R.cell.maxcharge + robot["cell_current"] = R.cell.charge + robot["cell_percentage"] = round(R.cell.percent()) + else + robot["cell"] = 0 + + robot["module"] = R.module ? R.module.name : "None" + robot["master_ai"] = R.connected_ai ? R.connected_ai.name : "None" + robot["hackable"] = 0 + // Antag AIs know whether linked cyborgs are hacked or not. + if(operator && istype(operator, /mob/living/silicon/ai) && (R.connected_ai == operator) && (operator.mind.special_role && operator.mind.original == operator)) + robot["hacked"] = R.emagged ? 1 : 0 + robot["hackable"] = R.emagged? 0 : 1 + robots.Add(list(robot)) + return robots + +// Proc: get_cyborg_by_name() +// Parameters: 1 (name - Cyborg we are trying to find) +// Description: Helper proc for finding cyborg by name +/obj/machinery/computer/robotics/proc/get_cyborg_by_name(var/name) + if (!name) + return + for(var/mob/living/silicon/robot/R in mob_list) + if(R.name == name) + return R diff --git a/code/modules/supermatter/supermatter.dm b/code/modules/supermatter/supermatter.dm index bf5d6957a6a..bbeb1603b7e 100644 --- a/code/modules/supermatter/supermatter.dm +++ b/code/modules/supermatter/supermatter.dm @@ -120,10 +120,15 @@ if(lum != light_range || clr != light_color) set_light(lum, l_color = clr) -/obj/machinery/power/supermatter/proc/announce_warning() +/obj/machinery/power/supermatter/proc/get_integrity() var/integrity = damage / explosion_point integrity = round(100 - integrity * 100) integrity = integrity < 0 ? 0 : integrity + return integrity + + +/obj/machinery/power/supermatter/proc/announce_warning() + var/integrity = get_integrity() var/alert_msg = " Integrity at [integrity]%" if(damage > emergency_point) @@ -267,11 +272,11 @@ if(Adjacent(user)) return attack_hand(user) else - user << "You attempt to interface with the control circuits but find they are not connected to your network. Maybe in a future firmware update." + ui_interact(user) return /obj/machinery/power/supermatter/attack_ai(mob/user as mob) - user << "You attempt to interface with the control circuits but find they are not connected to your network. Maybe in a future firmware update." + ui_interact(user) /obj/machinery/power/supermatter/attack_hand(mob/user as mob) user.visible_message("\The [user] reaches out and touches \the [src], inducing a resonance... \his body starts to glow and bursts into flames before flashing into ash.",\ @@ -280,6 +285,31 @@ Consume(user) +// This is purely informational UI that may be accessed by AIs or robots +/obj/machinery/power/supermatter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + + data["integrity_percentage"] = round(get_integrity()) + var/datum/gas_mixture/env = null + if(!istype(src.loc, /turf/space)) + env = src.loc.return_air() + + if(!env) + data["ambient_temp"] = 0 + data["ambient_pressure"] = 0 + else + data["ambient_temp"] = round(env.temperature) + data["ambient_pressure"] = round(env.return_pressure()) + data["detonating"] = grav_pulling + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "supermatter_crystal.tmpl", "Supermatter Crystal", 500, 300) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + + /* /obj/machinery/power/supermatter/proc/transfer_energy() for(var/obj/machinery/power/rad_collector/R in rad_collectors) diff --git a/html/changelogs/Atlantis-PR-8816.yml b/html/changelogs/Atlantis-PR-8816.yml new file mode 100644 index 00000000000..f3d30f9abec --- /dev/null +++ b/html/changelogs/Atlantis-PR-8816.yml @@ -0,0 +1,6 @@ +author: Atlantis +delete-after: True + +changes: + - rscadd: "NanoUI for Robotics Control Console" + - rscdel: "NanoUI for Supermatter Crystal - AI/Robot only, purely informational" diff --git a/nano/templates/robot_control.tmpl b/nano/templates/robot_control.tmpl new file mode 100644 index 00000000000..57bbebd490b --- /dev/null +++ b/nano/templates/robot_control.tmpl @@ -0,0 +1,83 @@ +{{if !data.is_ai}} +
+
+ Emergency Self-Destruct: +
+
+ {{if data.safety}} + {{:helper.link('ARM', 'unlocked', {'arm' : 1})}} + {{:helper.link('DETONATE', 'radiation', {'nuke' : 1}, 'disabled')}} + {{else}} + {{:helper.link('DISARM', 'locked', {'arm' : 1})}} + {{:helper.link('DETONATE', 'radiation', {'nuke' : 1}, null, 'redButton')}} + {{/if}} +
+
+
+{{/if}} +{{for data.robots}} +
+
+

{{:value.name}}

+

Information

+ + Status: + + + {{:value.status}} + + + Master AI: + + + {{:value.master_ai}} + + + Module: + + + {{:value.module}} + + + {{if value.hackable}} + + Safeties: + + + ENABLED + + {{else value.hacked}} + + Safeties: + + + DISABLED + + {{/if}} +

Power Cell

+ {{if value.cell}} + + Rating : + + + {{:value.cell_capacity}} + + {{:helper.displayBar(value.cell_percentage, 0, 100, (value.cell_percentage >= 50) ? 'good' : (value.cell_percentage >= 25) ? 'average' : 'bad')}} + {{:value.cell_percentage}} % + {{else}} + Not Installed + {{:helper.displayBar(100, 0, 100, 'bad')}} + N/A % + {{/if}} +

Actions

+ {{if value.status == "Operational"}} + {{:helper.link('Lockdown', 'locked', {'lockdown' : value.name})}} + {{else}} + {{:helper.link('Unlock', 'unlocked', {'lockdown' : value.name})}} + {{/if}} + {{:helper.link('Self-Destruct', 'radiation', {'detonate' : value.name}, null, 'redButton')}} + {{if value.hackable}} + {{:helper.link('Hack', 'calculator', {'hack' : value.name}, null, 'redButton')}} + {{/if}} +
+{{/for}} \ No newline at end of file diff --git a/nano/templates/supermatter_crystal.tmpl b/nano/templates/supermatter_crystal.tmpl new file mode 100644 index 00000000000..b06aaae7466 --- /dev/null +++ b/nano/templates/supermatter_crystal.tmpl @@ -0,0 +1,25 @@ +{{if data.detonating}} +
+

CRYSTAL DELAMINATING

+

Evacuate area immediately

+
+
+{{else}} +

Crystal Integrity

+ {{:helper.displayBar(data.integrity_percentage, 0, 100, (data.integrity_percentage >= 90) ? 'good' : (data.integrity_percentage >= 25) ? 'average' : 'bad')}} + {{:data.integrity_percentage}} % +

Environment

+ + Temperature: + + + {{:helper.displayBar(data.ambient_temp, 0, 10000, (data.ambient_temp >= 5000) ? 'bad' : (data.ambient_temp >= 4000) ? 'average' : 'good')}} + {{:data.ambient_temp}} K + + + Pressure: + + + {{:data.ambient_pressure}} kPa + +{{/if}} \ No newline at end of file