mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-21 12:04:48 +01:00
Merge pull request #14089 from Kyep/tgui_robotics_console
[TGUI] Robotics Control Console
This commit is contained in:
@@ -20,221 +20,210 @@
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/robotics/proc/is_authenticated(var/mob/user as mob)
|
||||
/obj/machinery/computer/robotics/proc/is_authenticated(mob/user)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(user.can_admin_interact())
|
||||
return 1
|
||||
else if(allowed(user))
|
||||
return 1
|
||||
return 0
|
||||
return TRUE
|
||||
if(allowed(user))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/computer/robotics/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/**
|
||||
* Does this borg show up in the console
|
||||
*
|
||||
* Returns TRUE if a robot will show up in the console
|
||||
* Returns FALSE if a robot will not show up in the console
|
||||
* Arguments:
|
||||
* * R - The [mob/living/silicon/robot] to be checked
|
||||
*/
|
||||
/obj/machinery/computer/robotics/proc/console_shows(mob/living/silicon/robot/R)
|
||||
if(!istype(R))
|
||||
return FALSE
|
||||
if(istype(R, /mob/living/silicon/robot/drone))
|
||||
return FALSE
|
||||
if(R.scrambledcodes)
|
||||
return FALSE
|
||||
if(!atoms_share_level(src, R))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Check if a user can send a lockdown/detonate command to a specific borg
|
||||
*
|
||||
* Returns TRUE if a user can send the command (does not guarantee it will work)
|
||||
* Returns FALSE if a user cannot
|
||||
* Arguments:
|
||||
* * user - The [mob/user] to be checked
|
||||
* * R - The [mob/living/silicon/robot] to be checked
|
||||
* * telluserwhy - Bool of whether the user should be sent a to_chat message if they don't have access
|
||||
*/
|
||||
/obj/machinery/computer/robotics/proc/can_control(mob/user, mob/living/silicon/robot/R, telluserwhy = FALSE)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(!console_shows(R))
|
||||
return FALSE
|
||||
if(isAI(user))
|
||||
if(R.connected_ai != user)
|
||||
if(telluserwhy)
|
||||
to_chat(user, "<span class='warning'>AIs can only control cyborgs which are linked to them.</span>")
|
||||
return FALSE
|
||||
if(isrobot(user))
|
||||
if(R != user)
|
||||
if(telluserwhy)
|
||||
to_chat(user, "<span class='warning'>Cyborgs cannot control other cyborgs.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Check if the user is the right kind of entity to be able to hack borgs
|
||||
*
|
||||
* Returns TRUE if a user is a traitor AI, or aghost
|
||||
* Returns FALSE otherwise
|
||||
* Arguments:
|
||||
* * user - The [mob/user] to be checked
|
||||
*/
|
||||
/obj/machinery/computer/robotics/proc/can_hack_any(mob/user)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(user.can_admin_interact())
|
||||
return TRUE
|
||||
if(!isAI(user))
|
||||
return FALSE
|
||||
return (user.mind.special_role && user.mind.original == user)
|
||||
|
||||
/**
|
||||
* Check if the user is allowed to hack a specific borg
|
||||
*
|
||||
* Returns TRUE if a user can hack the specific cyborg
|
||||
* Returns FALSE if a user cannot
|
||||
* Arguments:
|
||||
* * user - The [mob/user] to be checked
|
||||
* * R - The [mob/living/silicon/robot] to be checked
|
||||
*/
|
||||
/obj/machinery/computer/robotics/proc/can_hack(mob/user, mob/living/silicon/robot/R)
|
||||
if(!can_hack_any(user))
|
||||
return FALSE
|
||||
if(!istype(R))
|
||||
return FALSE
|
||||
if(R.emagged)
|
||||
return FALSE
|
||||
if(R.connected_ai != user)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/robotics/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "robot_control.tmpl", "Robotic Control Console", 400, 500)
|
||||
ui = new(user, src, ui_key, "RoboticsControlConsole", name, 500, 460, master_ui, state)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/computer/robotics/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
var/data[0]
|
||||
var/list/robots = get_cyborgs(user)
|
||||
if(robots.len)
|
||||
data["robots"] = robots
|
||||
/obj/machinery/computer/robotics/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["auth"] = is_authenticated(user)
|
||||
data["can_hack"] = can_hack_any(user)
|
||||
data["cyborgs"] = list()
|
||||
data["safety"] = safety
|
||||
// Also applies for cyborgs. Hides the manual self-destruct button.
|
||||
data["is_ai"] = issilicon(user)
|
||||
data["allowed"] = is_authenticated(user)
|
||||
for(var/mob/living/silicon/robot/R in GLOB.mob_list)
|
||||
if(!console_shows(R))
|
||||
continue
|
||||
var/area/A = get_area(R)
|
||||
var/turf/T = get_turf(R)
|
||||
var/list/cyborg_data = list(
|
||||
name = R.name,
|
||||
uid = R.UID(),
|
||||
locked_down = R.lockcharge,
|
||||
locstring = "[A.name] ([T.x], [T.y])",
|
||||
status = R.stat,
|
||||
health = round(R.health * 100 / R.maxHealth, 0.1),
|
||||
charge = R.cell ? round(R.cell.percent()) : null,
|
||||
cell_capacity = R.cell ? R.cell.maxcharge : null,
|
||||
module = R.module ? R.module.name : "No Module Detected",
|
||||
synchronization = R.connected_ai,
|
||||
is_hacked = R.connected_ai && R.emagged,
|
||||
hackable = can_hack(user, R),
|
||||
)
|
||||
data["cyborgs"] += list(cyborg_data)
|
||||
data["show_detonate_all"] = (data["auth"] && length(data["cyborgs"]) > 0 && ishuman(user))
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/robotics/Topic(href, href_list)
|
||||
/obj/machinery/computer/robotics/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
var/mob/user = usr
|
||||
if(!is_authenticated(user))
|
||||
to_chat(user, "<span class='warning'>Access denied.</span>")
|
||||
return
|
||||
|
||||
// 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
|
||||
if(isAI(user) && (target.connected_ai != user))
|
||||
to_chat(user, "<span class='warning'>Access Denied. This robot is not linked to you.</span>")
|
||||
return
|
||||
// Cyborgs may blow up themselves via the console
|
||||
if((isrobot(user) && user != target) || !is_authenticated(user))
|
||||
to_chat(user, "<span class='warning'>Access Denied.</span>")
|
||||
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)
|
||||
to_chat(target, "Extreme danger. Termination codes detected. Scrambling security codes and automatic AI unlink triggered.")
|
||||
target.ResetSecurityCodes()
|
||||
else
|
||||
message_admins("<span class='notice'>[key_name_admin(usr)] detonated [key_name_admin(target)] (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[target.x];Y=[target.y];Z=[target.z]'>JMP</a>)!</span>")
|
||||
log_game("\<span class='notice'>[key_name(usr)] detonated [key_name(target)]!</span>")
|
||||
to_chat(target, "<span class='danger'>Self-destruct command received.</span>")
|
||||
if(target.connected_ai)
|
||||
to_chat(target.connected_ai, "<br><br><span class='alert'>ALERT - Cyborg detonation detected: [target.name]</span><br>")
|
||||
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(isAI(user) && (target.connected_ai != user))
|
||||
to_chat(user, "<span class='warning'>Access Denied. This robot is not linked to you.</span>")
|
||||
return
|
||||
|
||||
if(isrobot(user))
|
||||
to_chat(user, "<span class='warning'>Access Denied.</span>")
|
||||
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("<span class='notice'>[key_name_admin(usr)] [target.canmove ? "locked down" : "released"] [key_name_admin(target)]!</span>")
|
||||
log_game("[key_name(usr)] [target.canmove ? "locked down" : "released"] [key_name(target)]!")
|
||||
target.SetLockdown(!target.lockcharge)
|
||||
to_chat(target, "[!target.lockcharge ? "<span class='notice'>Your lockdown has been lifted!</span>" : "<span class='alert'>You have been locked down!</span>"]")
|
||||
if(target.connected_ai)
|
||||
to_chat(target.connected_ai, "[!target.lockcharge ? "<span class='notice'>NOTICE - Cyborg lockdown lifted</span>" : "<span class='alert'>ALERT - Cyborg lockdown detected</span>"]: <a href='?src=[target.connected_ai.UID()];track=[html_encode(target.name)]'>[target.name]</a></span><br>")
|
||||
|
||||
// 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))
|
||||
to_chat(user, "<span class='warning'>Access Denied.</span>")
|
||||
return
|
||||
|
||||
if(target.connected_ai != user)
|
||||
to_chat(user, "<span class='warning'>Access Denied. This robot is not linked to you.</span>")
|
||||
return
|
||||
|
||||
if(target.emagged)
|
||||
to_chat(user, "<span class='warning'>Robot is already hacked.</span>")
|
||||
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("<span class='notice'>[key_name_admin(usr)] emagged [key_name_admin(target)] using robotic console!</span>")
|
||||
log_game("[key_name(usr)] emagged [key_name(target)] using robotic console!")
|
||||
target.emagged = 1
|
||||
to_chat(target, "<span class='notice'>Failsafe protocols overriden. New tools available.</span>")
|
||||
|
||||
// Arms the emergency self-destruct system
|
||||
else if(href_list["arm"])
|
||||
if(istype(user, /mob/living/silicon))
|
||||
to_chat(user, "<span class='warning'>Access Denied.</span>")
|
||||
return
|
||||
|
||||
safety = !safety
|
||||
to_chat(user, "<span class='notice'>You [safety ? "disarm" : "arm"] the emergency self destruct.</span>")
|
||||
|
||||
// Destroys all accessible cyborgs if safety is disabled
|
||||
else if(href_list["nuke"])
|
||||
if(istype(user, /mob/living/silicon))
|
||||
to_chat(user, "Access Denied")
|
||||
return
|
||||
if(safety)
|
||||
to_chat(user, "Self-destruct aborted - safety active")
|
||||
return
|
||||
|
||||
message_admins("<span class='notice'>[key_name_admin(usr)] detonated all cyborgs!</span>")
|
||||
log_game("\<span class='notice'>[key_name(usr)] detonated all cyborgs!</span>")
|
||||
|
||||
for(var/mob/living/silicon/robot/R in GLOB.mob_list)
|
||||
if(istype(R, /mob/living/silicon/robot/drone))
|
||||
continue
|
||||
// Ignore antagonistic cyborgs
|
||||
if(R.scrambledcodes)
|
||||
continue
|
||||
. = FALSE
|
||||
if(!is_authenticated(usr))
|
||||
to_chat(usr, "<span class='warning'>Access denied.</span>")
|
||||
return
|
||||
switch(action)
|
||||
if("arm") // Arms the emergency self-destruct system
|
||||
if(issilicon(usr))
|
||||
to_chat(usr, "<span class='danger'>Access Denied (silicon detected)</span>")
|
||||
return
|
||||
safety = !safety
|
||||
to_chat(usr, "<span class='notice'>You [safety ? "disarm" : "arm"] the emergency self destruct.</span>")
|
||||
. = TRUE
|
||||
if("nuke") // Destroys all accessible cyborgs if safety is disabled
|
||||
if(issilicon(usr))
|
||||
to_chat(usr, "<span class='danger'>Access Denied (silicon detected)</span>")
|
||||
return
|
||||
if(safety)
|
||||
to_chat(usr, "<span class='danger'>Self-destruct aborted - safety active</span>")
|
||||
return
|
||||
message_admins("<span class='notice'>[key_name_admin(usr)] detonated all cyborgs!</span>")
|
||||
log_game("\<span class='notice'>[key_name(usr)] detonated all cyborgs!</span>")
|
||||
for(var/mob/living/silicon/robot/R in GLOB.mob_list)
|
||||
if(istype(R, /mob/living/silicon/robot/drone))
|
||||
continue
|
||||
// Ignore antagonistic cyborgs
|
||||
if(R.scrambledcodes)
|
||||
continue
|
||||
to_chat(R, "<span class='danger'>Self-destruct command received.</span>")
|
||||
if(R.connected_ai)
|
||||
to_chat(R.connected_ai, "<br><br><span class='alert'>ALERT - Cyborg detonation detected: [R.name]</span><br>")
|
||||
R.self_destruct()
|
||||
. = TRUE
|
||||
if("killbot") // destroys one specific cyborg
|
||||
var/mob/living/silicon/robot/R = locateUID(params["uid"])
|
||||
if(!can_control(usr, R, TRUE))
|
||||
return
|
||||
if(R.mind && R.mind.special_role && R.emagged)
|
||||
to_chat(R, "<span class='userdanger'>Extreme danger! Termination codes detected. Scrambling security codes and automatic AI unlink triggered.</span>")
|
||||
R.ResetSecurityCodes()
|
||||
. = TRUE
|
||||
return
|
||||
var/turf/T = get_turf(R)
|
||||
message_admins("<span class='notice'>[key_name_admin(usr)] detonated [key_name_admin(R)] ([ADMIN_COORDJMP(T)])!</span>")
|
||||
log_game("\<span class='notice'>[key_name(usr)] detonated [key_name(R)]!</span>")
|
||||
to_chat(R, "<span class='danger'>Self-destruct command received.</span>")
|
||||
if(R.connected_ai)
|
||||
to_chat(R.connected_ai, "<br><br><span class='alert'>ALERT - Cyborg detonation detected: [R.name]</span><br>")
|
||||
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 GLOB.mob_list)
|
||||
// Ignore drones
|
||||
if(istype(R, /mob/living/silicon/robot/drone))
|
||||
continue
|
||||
// Ignore antagonistic cyborgs
|
||||
if(R.scrambledcodes)
|
||||
continue
|
||||
|
||||
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
|
||||
|
||||
var/turf/pos = get_turf(R)
|
||||
var/area/bot_area = get_area(R)
|
||||
robot["xpos"] = pos.x
|
||||
robot["ypos"] = pos.y
|
||||
robot["zpos"] = pos.z
|
||||
robot["area"] = format_text(bot_area.name)
|
||||
|
||||
robot["health"] = round(R.health * 100 / R.maxHealth,0.1)
|
||||
|
||||
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 GLOB.mob_list)
|
||||
if(R.name == name)
|
||||
return R
|
||||
R.self_destruct()
|
||||
. = TRUE
|
||||
if("stopbot") // lock or unlock the borg
|
||||
if(isrobot(usr))
|
||||
to_chat(usr, "<span class='danger'>Access Denied.</span>")
|
||||
return
|
||||
var/mob/living/silicon/robot/R = locateUID(params["uid"])
|
||||
if(!can_control(usr, R, TRUE))
|
||||
return
|
||||
message_admins("<span class='notice'>[ADMIN_LOOKUPFLW(usr)] [!R.lockcharge ? "locked down" : "released"] [ADMIN_LOOKUPFLW(R)]!</span>")
|
||||
log_game("[key_name(usr)] [!R.lockcharge ? "locked down" : "released"] [key_name(R)]!")
|
||||
R.SetLockdown(!R.lockcharge)
|
||||
to_chat(R, "[!R.lockcharge ? "<span class='notice'>Your lockdown has been lifted!" : "<span class='alert'>You have been locked down!"]</span>")
|
||||
if(R.connected_ai)
|
||||
to_chat(R.connected_ai, "[!R.lockcharge ? "<span class='notice'>NOTICE - Cyborg lockdown lifted</span>" : "<span class='alert'>ALERT - Cyborg lockdown detected</span>"]: <a href='?src=[R.connected_ai.UID()];track=[html_encode(R.name)]'>[R.name]</a></span><br>")
|
||||
. = TRUE
|
||||
if("hackbot") // AIs hacking/emagging a borg
|
||||
var/mob/living/silicon/robot/R = locateUID(params["uid"])
|
||||
if(!can_hack(usr, R))
|
||||
return
|
||||
var/choice = input("Really hack [R.name]? This cannot be undone.") in list("Yes", "No")
|
||||
if(choice != "Yes")
|
||||
return
|
||||
log_game("[key_name(usr)] emagged [key_name(R)] using robotic console!")
|
||||
message_admins("<span class='notice'>[key_name_admin(usr)] emagged [key_name_admin(R)] using robotic console!</span>")
|
||||
R.emagged = TRUE
|
||||
to_chat(R, "<span class='notice'>Failsafe protocols overriden. New tools available.</span>")
|
||||
. = TRUE
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
{{if data.robots}}
|
||||
{{if !data.is_ai}}
|
||||
<div class='notice'>
|
||||
<div class="itemContentSmall" style="width: 180px">
|
||||
Emergency Self-Destruct:
|
||||
</div>
|
||||
<div class="itemContentFull">
|
||||
{{if data.safety}}
|
||||
{{:helper.link('ARM', 'unlock', {'arm' : 1}, !data.allowed ? 'disabled' : null)}}
|
||||
{{:helper.link('DETONATE', 'exclamation-circle', {'nuke' : 1}, 'disabled')}}
|
||||
{{else}}
|
||||
{{:helper.link('DISARM', 'lock', {'arm' : 1}, !data.allowed ? 'disabled' : null)}}
|
||||
{{:helper.link('DETONATE', 'exclamation-circle', {'nuke' : 1}, !data.allowed ? 'disabled' : null, 'redButton')}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="clearBoth"></div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{for data.robots}}
|
||||
<hr>
|
||||
<div class='item'>
|
||||
<h2>{{:value.name}}</h2>
|
||||
<h3>Information</h3>
|
||||
<span class="itemLabel">
|
||||
Status:
|
||||
</span>
|
||||
<span class="itemContent">
|
||||
{{:value.status}}
|
||||
</span>
|
||||
<span class="itemLabel">
|
||||
System Integrity:
|
||||
</span>
|
||||
<span class="itemContent">
|
||||
{{:helper.smoothRound(value.health)}}%
|
||||
</span>
|
||||
<span class="itemLabel">
|
||||
Location:
|
||||
</span>
|
||||
<span class="itemContent">
|
||||
({{:value.xpos}}, {{:value.ypos}}, {{:value.zpos}}): {{:value.area}}
|
||||
</span>
|
||||
<span class="itemLabel">
|
||||
Master AI:
|
||||
</span>
|
||||
<span class="itemContent">
|
||||
{{:value.master_ai}}
|
||||
</span>
|
||||
<span class="itemLabel">
|
||||
Module:
|
||||
</span>
|
||||
<span class="itemContent">
|
||||
{{:value.module}}
|
||||
</span>
|
||||
|
||||
{{if value.hackable}}
|
||||
<span class="itemLabel">
|
||||
Safeties:
|
||||
</span>
|
||||
<span class="itemContent">
|
||||
ENABLED
|
||||
</span>
|
||||
{{else value.hacked}}
|
||||
<span class="itemLabel">
|
||||
Safeties:
|
||||
</span>
|
||||
<span class="itemContent">
|
||||
DISABLED
|
||||
</span>
|
||||
{{/if}}
|
||||
<h3>Power Cell</h3>
|
||||
{{if value.cell}}
|
||||
<span class="itemLabel">
|
||||
Rating:
|
||||
</span>
|
||||
<span class="itemContent">
|
||||
{{:value.cell_capacity}}
|
||||
</span>
|
||||
{{:helper.displayBar(value.cell_percentage, 0, 100, (value.cell_percentage >= 50) ? 'good' : (value.cell_percentage >= 25) ? 'average' : 'bad')}}
|
||||
<b> {{:helper.smoothRound(value.cell_percentage)}}%</b>
|
||||
{{else}}
|
||||
<b><i>Not Installed</i></b>
|
||||
{{:helper.displayBar(100, 0, 100, 'bad')}}
|
||||
{{/if}}
|
||||
<h3>Actions</h3>
|
||||
{{if value.status == "Operational"}}
|
||||
{{:helper.link('Lockdown', 'lock', {'lockdown' : value.name}, !data.allowed ? 'disabled' : null)}}
|
||||
{{else}}
|
||||
{{:helper.link('Unlock', 'unlock', {'lockdown' : value.name}, !data.allowed ? 'disabled' : null)}}
|
||||
{{/if}}
|
||||
{{:helper.link('Self-Destruct', 'exclamation-circle', {'detonate' : value.name}, !data.allowed ? 'disabled' : null, 'redButton')}}
|
||||
{{if value.hackable}}
|
||||
{{:helper.link('Hack', 'calculator', {'hack' : value.name}, !data.allowed ? 'disabled' : null, 'redButton')}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/for}}
|
||||
{{else}}
|
||||
<div class='item'>
|
||||
<h3>No robots were found.</h3>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -0,0 +1,143 @@
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend, useSharedState } from '../backend';
|
||||
import { Box, Button, LabeledList, ProgressBar, NoticeBox, Section, Tabs } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
export const RoboticsControlConsole = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
can_hack,
|
||||
safety,
|
||||
show_detonate_all,
|
||||
cyborgs = [],
|
||||
} = data;
|
||||
return (
|
||||
<Window resizable>
|
||||
<Window.Content scrollable>
|
||||
{!!show_detonate_all && (
|
||||
<Section title="Emergency Self Destruct">
|
||||
<Button
|
||||
icon={safety ? 'lock' : 'unlock'}
|
||||
content={safety ? 'Disable Safety' : 'Enable Safety'}
|
||||
selected={safety}
|
||||
onClick={() => act('arm', {})} />
|
||||
<Button
|
||||
icon="bomb"
|
||||
disabled={safety}
|
||||
content="Destroy ALL Cyborgs"
|
||||
color="bad"
|
||||
onClick={() => act('nuke', {})} />
|
||||
</Section>
|
||||
)}
|
||||
<Cyborgs cyborgs={cyborgs} can_hack={can_hack} />
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const Cyborgs = (props, context) => {
|
||||
const { cyborgs, can_hack } = props;
|
||||
const { act, data } = useBackend(context);
|
||||
if (!cyborgs.length) {
|
||||
return (
|
||||
<NoticeBox>
|
||||
No cyborg units detected within access parameters.
|
||||
</NoticeBox>
|
||||
);
|
||||
}
|
||||
return cyborgs.map(cyborg => {
|
||||
return (
|
||||
<Section
|
||||
key={cyborg.uid}
|
||||
title={cyborg.name}
|
||||
buttons={(
|
||||
<Fragment>
|
||||
{!!cyborg.hackable && !cyborg.emagged && (
|
||||
<Button
|
||||
icon="terminal"
|
||||
content="Hack"
|
||||
color="bad"
|
||||
onClick={() => act('hackbot', {
|
||||
uid: cyborg.uid,
|
||||
})} />
|
||||
)}
|
||||
<Button.Confirm
|
||||
icon={cyborg.locked_down ? 'unlock' : 'lock'}
|
||||
color={cyborg.locked_down ? 'good' : 'default'}
|
||||
content={cyborg.locked_down ? "Release" : "Lockdown"}
|
||||
disabled={!data.auth}
|
||||
onClick={() => act('stopbot', {
|
||||
uid: cyborg.uid,
|
||||
})} />
|
||||
<Button.Confirm
|
||||
icon="bomb"
|
||||
content="Detonate"
|
||||
disabled={!data.auth}
|
||||
color="bad"
|
||||
onClick={() => act('killbot', {
|
||||
uid: cyborg.uid,
|
||||
})} />
|
||||
</Fragment>
|
||||
)}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Status">
|
||||
<Box color={cyborg.status
|
||||
? 'bad'
|
||||
: cyborg.locked_down
|
||||
? 'average'
|
||||
: 'good'}>
|
||||
{cyborg.status
|
||||
? "Not Responding"
|
||||
: cyborg.locked_down
|
||||
? "Locked Down"
|
||||
: "Nominal"}
|
||||
</Box>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Location">
|
||||
<Box>
|
||||
{cyborg.locstring}
|
||||
</Box>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Integrity">
|
||||
<ProgressBar
|
||||
color={cyborg.health > 50 ? "good" : "bad"}
|
||||
value={cyborg.health / 100} />
|
||||
</LabeledList.Item>
|
||||
{(typeof cyborg.charge === 'number') && (
|
||||
<Fragment>
|
||||
<LabeledList.Item label="Cell Charge">
|
||||
<ProgressBar
|
||||
color={cyborg.charge > 30 ? "good" : "bad"}
|
||||
value={cyborg.charge / 100} />
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Cell Capacity">
|
||||
<Box color={cyborg.cell_capacity < 30000 ? "average" : "good"}>
|
||||
{cyborg.cell_capacity}
|
||||
</Box>
|
||||
</LabeledList.Item>
|
||||
</Fragment>
|
||||
) || (
|
||||
<LabeledList.Item label="Cell">
|
||||
<Box color="bad">
|
||||
No Power Cell
|
||||
</Box>
|
||||
</LabeledList.Item>
|
||||
)}
|
||||
{!!cyborg.is_hacked && (
|
||||
<LabeledList.Item label="Safeties">
|
||||
<Box color="bad">DISABLED</Box>
|
||||
</LabeledList.Item>
|
||||
)}
|
||||
<LabeledList.Item label="Module">
|
||||
{cyborg.module}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Master AI">
|
||||
<Box color={cyborg.synchronization ? 'default' : 'average'}>
|
||||
{cyborg.synchronization || "None"}
|
||||
</Box>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
});
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user