[TGUI] Drone Control Console (#15222)

* Drone UI V1

* Bigger button

And admin log clarification

* Review 1

Also commented out the drone 'rebooting' action, since it didn't work.

* Spacing

Seemed a bit too cluttered.

* Review 2

Co-Authored-By: dearmochi <shenesis@gmail.com>

Co-authored-by: dearmochi <shenesis@gmail.com>
This commit is contained in:
SabreML
2021-01-30 23:54:09 +00:00
committed by GitHub
parent 82f1d2ce59
commit c7bea0eb8e
7 changed files with 389 additions and 192 deletions
+1
View File
@@ -214,6 +214,7 @@
#define issilicon(A) (istype((A), /mob/living/silicon))
#define isAI(A) (istype((A), /mob/living/silicon/ai))
#define isrobot(A) (istype((A), /mob/living/silicon/robot))
#define isdrone(A) (istype((A), /mob/living/silicon/robot/drone))
#define ispAI(A) (istype((A), /mob/living/silicon/pai))
// For the tcomms monitor
@@ -1,4 +1,4 @@
#define EMAG_TIMER 3000
#define EMAG_TIMER 5 MINUTES
/mob/living/silicon/robot/drone
name = "drone"
real_name = "drone"
@@ -7,21 +7,19 @@
maxHealth = 35
health = 35
bubble_icon = "machine"
universal_speak = 0
universal_understand = 1
gender = NEUTER
pass_flags = PASSTABLE
braintype = "Robot"
lawupdate = 0
density = 0
lawupdate = FALSE
density = FALSE
has_camera = FALSE
req_one_access = list(ACCESS_ENGINE, ACCESS_ROBOTICS)
ventcrawler = 2
magpulse = 1
ventcrawler = VENTCRAWLER_ALWAYS
magpulse = TRUE
mob_size = MOB_SIZE_SMALL
pull_force = MOVE_FORCE_VERY_WEAK // Can only drag small items
modules_break = FALSE
/// Cooldown for law syncs
var/sync_cooldown = 0
// We need to keep track of a few module items so we don't need to do list operations
// every time we need them. These get set in New() after the module is chosen.
@@ -37,7 +35,7 @@
//Used for self-mailing.
var/mail_destination = 0
var/reboot_cooldown = 60 // one minute
var/reboot_cooldown = 1 MINUTES
var/last_reboot
var/list/pullable_drone_items = list(
/obj/item/pipe,
@@ -57,8 +55,8 @@
remove_language("Robot Talk")
remove_language("Galactic Common")
add_language("Drone Talk", 1)
add_language("Drone", 1)
add_language("Drone Talk", TRUE)
add_language("Drone", TRUE)
// Disable the microphone wire on Drones
if(radio)
@@ -86,13 +84,13 @@
radio.recalculateChannels()
//Grab stacks.
stack_metal = locate(/obj/item/stack/sheet/metal/cyborg) in src.module
stack_wood = locate(/obj/item/stack/sheet/wood) in src.module
stack_glass = locate(/obj/item/stack/sheet/glass/cyborg) in src.module
stack_plastic = locate(/obj/item/stack/sheet/plastic) in src.module
stack_metal = locate(/obj/item/stack/sheet/metal/cyborg) in module
stack_wood = locate(/obj/item/stack/sheet/wood) in module
stack_glass = locate(/obj/item/stack/sheet/glass/cyborg) in module
stack_plastic = locate(/obj/item/stack/sheet/plastic) in module
//Grab decompiler.
decompiler = locate(/obj/item/matter_decompiler) in src.module
decompiler = locate(/obj/item/matter_decompiler) in module
//Some tidying-up.
flavor_text = "It's a tiny little repair drone. The casing is stamped with an NT logo and the subscript: 'Nanotrasen Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'"
@@ -103,10 +101,10 @@
laws = new /datum/ai_laws/drone()
connected_ai = null
aiCamera = new/obj/item/camera/siliconcam/drone_camera(src)
aiCamera = new /obj/item/camera/siliconcam/drone_camera(src)
additional_law_channels["Drone"] = ";"
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
playsound(loc, 'sound/machines/twobeep.ogg', 50)
//Redefining some robot procs...
/mob/living/silicon/robot/drone/rename_character(oldname, newname)
@@ -114,7 +112,7 @@
return ..(newname, newname)
/mob/living/silicon/robot/drone/get_default_name()
return "maintenance drone ([rand(100,999)])"
return "maintenance drone ([rand(100, 999)])"
/mob/living/silicon/robot/drone/update_icons()
overlays.Cut()
@@ -126,7 +124,6 @@
/mob/living/silicon/robot/drone/choose_icon()
return
/mob/living/silicon/robot/drone/pick_module()
return
@@ -136,25 +133,23 @@
return FALSE
//Drones cannot be upgraded with borg modules so we need to catch some items before they get used in ..().
/mob/living/silicon/robot/drone/attackby(obj/item/W as obj, mob/user as mob, params)
if(istype(W, /obj/item/borg/upgrade/))
to_chat(user, "<span class='warning'>The maintenance drone chassis not compatible with \the [W].</span>")
/mob/living/silicon/robot/drone/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/borg/upgrade))
to_chat(user, "<span class='warning'>The maintenance drone chassis is not compatible with [I].</span>")
return
else if(istype(W, /obj/item/crowbar))
to_chat(user, "The machine is hermetically sealed. You can't open the case.")
else if(istype(I, /obj/item/crowbar))
to_chat(user, "<span class='warning'>The machine is hermetically sealed. You can't open the case.</span>")
return
else if(istype(W, /obj/item/card/id)||istype(W, /obj/item/pda))
else if(istype(I, /obj/item/card/id) || istype(I, /obj/item/pda))
if(stat == DEAD)
if(!config.allow_drone_spawn || emagged || health < -35) //It's dead, Dave.
// Currently not functional, so commenting out until it's fixed to avoid confusion
/*if(!config.allow_drone_spawn || emagged || health < -35) //It's dead, Dave.
to_chat(user, "<span class='warning'>The interface is fried, and a distressing burned smell wafts from the robot's interior. You're not rebooting this one.</span>")
return
if(!allowed(W))
if(!allowed(I))
to_chat(user, "<span class='warning'>Access denied.</span>")
return
@@ -164,25 +159,26 @@
to_chat(usr, "<span class='warning'>The reboot system is currently offline. Please wait another [cooldown_time] seconds.</span>")
return
user.visible_message("<span class='warning'>\the [user] swipes [user.p_their()] ID card through [src], attempting to reboot it.</span>", "<span class='warning'>You swipe your ID card through [src], attempting to reboot it.</span>")
user.visible_message("<span class='warning'>[user] swipes [user.p_their()] ID card through [src], attempting to reboot it.</span>",
"<span class='warning'>You swipe your ID card through [src], attempting to reboot it.</span>")
last_reboot = world.time / 10
var/drones = 0
for(var/mob/living/silicon/robot/drone/D in GLOB.silicon_mob_list)
if(D.key && D.client)
drones++
if(drones < config.max_maint_drones)
request_player()
request_player()*/
return
else
var/confirm = alert("Using your ID on a Maintenance Drone will shut it down, are you sure you want to do this?", "Disable Drone", "Yes", "No")
if(confirm == ("Yes") && (user in range(3, src)))
user.visible_message("<span class='warning'>\the [user] swipes [user.p_their()] ID card through [src], attempting to shut it down.</span>", "<span class='warning'>You swipe your ID card through \the [src], attempting to shut it down.</span>")
user.visible_message("<span class='warning'>[user] swipes [user.p_their()] ID card through [src], attempting to shut it down.</span>",
"<span class='warning'>You swipe your ID card through [src], attempting to shut it down.</span>")
if(emagged)
return
if(allowed(W))
if(allowed(I))
shut_down()
else
to_chat(user, "<span class='warning'>Access denied.</span>")
@@ -191,7 +187,7 @@
..()
/mob/living/silicon/robot/drone/emag_act(user as mob)
/mob/living/silicon/robot/drone/emag_act(mob/user)
if(!client || stat == DEAD)
to_chat(user, "<span class='warning'>There's not much point subverting this heap of junk.</span>")
return
@@ -210,7 +206,7 @@
if(jobban_isbanned(src, ROLE_SYNDICATE))
SSticker.mode.replace_jobbanned_player(src, ROLE_SYNDICATE)
to_chat(src, "<span class='warning'>You feel a sudden burst of malware loaded into your execute-as-root buffer. Your tiny brain methodically parses, loads and executes the script. You sense you have five minutes before the drone server detects this and automatically shuts you down.</span>")
to_chat(src, "<span class='warning'>You feel a sudden burst of malware loaded into your execute-as-root buffer. Your tiny brain methodically parses, loads and executes the script. You sense you have <b>five minutes</b> before the drone server detects this and automatically shuts you down.</span>")
message_admins("[key_name_admin(user)] emagged drone [key_name_admin(src)]. Laws overridden.")
log_game("[key_name(user)] emagged drone [key_name(src)]. Laws overridden.")
@@ -218,13 +214,12 @@
GLOB.lawchanges.Add("[time] <B>:</B> [H.name]([H.key]) emagged [name]([key])")
addtimer(CALLBACK(src, .proc/shut_down, TRUE), EMAG_TIMER)
emagged = 1
density = 1
emagged = TRUE
density = TRUE
pass_flags = 0
icon_state = "repairbot-emagged"
holder_type = /obj/item/holder/drone/emagged
update_icons()
lawupdate = 0
connected_ai = null
clear_supplied_laws()
clear_inherent_laws()
@@ -234,7 +229,6 @@
to_chat(src, "<b>Obey these laws:</b>")
laws.show_laws(src)
to_chat(src, "<span class='boldwarning'>ALERT: [H.real_name] is your new master. Obey your new laws and [H.real_name]'s commands.</span>")
return
//DRONE LIFE/DEATH
@@ -262,7 +256,7 @@
full_law_reset()
show_laws()
/mob/living/silicon/robot/drone/proc/shut_down(force=FALSE)
/mob/living/silicon/robot/drone/proc/shut_down(force = FALSE)
if(stat == DEAD)
return
@@ -285,32 +279,32 @@
for(var/mob/dead/observer/O in GLOB.player_list)
if(cannotPossess(O))
continue
if(jobban_isbanned(O,"nonhumandept") || jobban_isbanned(O,"Drone"))
if(jobban_isbanned(O, "nonhumandept") || jobban_isbanned(O, "Drone"))
continue
if(O.client)
if(ROLE_PAI in O.client.prefs.be_special)
question(O.client,O)
question(O.client, O)
/mob/living/silicon/robot/drone/proc/question(var/client/C,var/mob/M)
/mob/living/silicon/robot/drone/proc/question(client/C, mob/M)
spawn(0)
if(!C || !M || jobban_isbanned(M,"nonhumandept") || jobban_isbanned(M,"Drone")) return
if(!C || !M || jobban_isbanned(M, "nonhumandept") || jobban_isbanned(M, "Drone"))
return
var/response = alert(C, "Someone is attempting to reboot a maintenance drone. Would you like to play as one?", "Maintenance drone reboot", "Yes", "No")
if(!C || ckey)
return
if(response == "Yes")
transfer_personality(C)
/mob/living/silicon/robot/drone/proc/transfer_personality(var/client/player)
/mob/living/silicon/robot/drone/proc/transfer_personality(client/player)
if(!player)
return
if(!player) return
if(player.mob && player.mob.mind)
if(player.mob?.mind)
player.mob.mind.transfer_to(src)
player.mob.mind.assigned_role = "Drone"
else
ckey = player.ckey
lawupdate = 0
to_chat(src, "<b>Systems rebooted</b>. Loading base pattern maintenance protocol... <b>loaded</b>.")
full_law_reset()
to_chat(src, "<br><b>You are a maintenance drone, a tiny-brained robotic repair machine</b>.")
@@ -358,21 +352,21 @@
to_chat(src, "<span class='warning'>You are too small to pull that.</span>")
/mob/living/silicon/robot/drone/add_robot_verbs()
src.verbs |= silicon_subsystems
verbs |= silicon_subsystems
/mob/living/silicon/robot/drone/remove_robot_verbs()
src.verbs -= silicon_subsystems
verbs -= silicon_subsystems
/mob/living/silicon/robot/drone/update_canmove(delay_action_updates = 0)
/mob/living/silicon/robot/drone/update_canmove(delay_action_updates = FALSE)
. = ..()
density = emagged //this is reset every canmove update otherwise
/mob/living/simple_animal/drone/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0)
/mob/living/silicon/robot/drone/flash_eyes(intensity = 1, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE)
if(affect_silicon)
return ..()
/mob/living/silicon/robot/drone/decompile_act(obj/item/matter_decompiler/C, mob/user)
if(!client && istype(user, /mob/living/silicon/robot/drone))
if(!client && isdrone(user))
to_chat(user, "<span class='warning'>You begin decompiling the other drone.</span>")
if(!do_after(user, 5 SECONDS, target = loc))
to_chat(user, "<span class='warning'>You need to remain still while decompiling such a large object.</span>")
@@ -380,7 +374,7 @@
if(QDELETED(src) || QDELETED(user))
return ..()
to_chat(user, "<span class='warning'>You carefully and thoroughly decompile your downed fellow, storing as much of its resources as you can within yourself.</span>")
new/obj/effect/decal/cleanable/blood/oil(get_turf(src))
new /obj/effect/decal/cleanable/blood/oil(get_turf(src))
C.stored_comms["metal"] += 15
C.stored_comms["glass"] += 15
C.stored_comms["wood"] += 5
@@ -6,16 +6,18 @@
req_access = list(ACCESS_ENGINE_EQUIP)
circuit = /obj/item/circuitboard/drone_control
//Used when pinging drones.
var/drone_call_area = "Engineering"
//Used to enable or disable drone fabrication.
/// The linked fabricator
var/obj/machinery/drone_fabricator/dronefab
/// Used when pinging drones
var/drone_call_area = "Engineering"
/// Cooldown for area pings
var/ping_cooldown = 0
/obj/machinery/computer/drone_control/attack_ai(var/mob/user as mob)
return src.attack_hand(user)
/obj/machinery/computer/drone_control/Initialize(mapload)
. = ..()
find_fab()
/obj/machinery/computer/drone_control/attack_hand(var/mob/user as mob)
/obj/machinery/computer/drone_control/attack_hand(mob/user)
if(..())
return
@@ -23,105 +25,112 @@
to_chat(user, "<span class='warning'>Access denied.</span>")
return
interact(user)
ui_interact(user)
/obj/machinery/computer/drone_control/attack_ghost(mob/user as mob)
interact(user)
/obj/machinery/computer/drone_control/attack_ghost(mob/user)
ui_interact(user)
/obj/machinery/computer/drone_control/interact(mob/user)
// tgui\packages\tgui\interfaces\DroneConsole.js
/obj/machinery/computer/drone_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "DroneConsole", "Drone Control Console", 420, 500, master_ui, state)
ui.open()
user.set_machine(src)
var/dat
dat += "<B>Maintenance Units</B><BR>"
/obj/machinery/computer/drone_control/ui_data(mob/user)
var/list/data = list()
data["drone_fab"] = FALSE
data["fab_power"] = null
data["drone_prod"] = null
data["drone_progress"] = null
if(dronefab)
data["drone_fab"] = TRUE
data["fab_power"] = dronefab.stat & NOPOWER ? FALSE : TRUE
data["drone_prod"] = dronefab.produce_drones
data["drone_progress"] = dronefab.drone_progress
data["selected_area"] = drone_call_area
data["ping_cd"] = ping_cooldown > world.time ? TRUE : FALSE
data["drones"] = list()
for(var/mob/living/silicon/robot/drone/D in GLOB.silicon_mob_list)
dat += "<BR>[D.real_name] ([D.stat == 2 ? "<font color='red'>INACTIVE" : "<font color='green'>ACTIVE"]</FONT>)"
dat += "<font dize = 9><BR>Cell charge: [D.cell.charge]/[D.cell.maxcharge]."
dat += "<BR>Currently located in: [get_area(D)]."
dat += "<BR><A href='?src=[UID()];resync=\ref[D]'>Resync</A> | <A href='?src=[UID()];shutdown=\ref[D]'>Shutdown</A></font>"
var/area/A = get_area(D)
var/turf/T = get_turf(D)
var/list/drone_data = list(
name = D.real_name,
uid = D.UID(),
stat = D.stat,
client = D.client ? TRUE : FALSE,
health = round(D.health / D.maxHealth, 0.1),
charge = round(D.cell.charge / D.cell.maxcharge, 0.1),
location = "[A] ([T.x], [T.y])",
sync_cd = D.sync_cooldown > world.time ? TRUE : FALSE
)
data["drones"] += list(drone_data)
return data
dat += "<BR><BR><B>Request drone presence in area:</B> <A href='?src=[UID()];setarea=1'>[drone_call_area]</A> (<A href='?src=[UID()];ping=1'>Send ping</A>)"
/obj/machinery/computer/drone_control/ui_static_data(mob/user)
var/list/data = list()
data["area_list"] = GLOB.TAGGERLOCATIONS
return data
dat += "<BR><BR><B>Drone fabricator</B>: "
dat += "[dronefab ? "<A href='?src=[UID()];toggle_fab=1'>[(dronefab.produce_drones && !(dronefab.stat & NOPOWER)) ? "ACTIVE" : "INACTIVE"]</A>" : "<font color='red'><b>FABRICATOR NOT DETECTED.</b></font> (<A href='?src=[UID()];search_fab=1'>search</a>)"]"
user << browse(dat, "window=computer;size=400x500")
onclose(user, "computer")
return
/obj/machinery/computer/drone_control/Topic(href, href_list)
/obj/machinery/computer/drone_control/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(..())
return
. = TRUE
if(!allowed(usr) && !usr.can_admin_interact())
to_chat(usr, "<span class='warning'>Access denied.</span>")
switch(action)
if("find_fab")
find_fab(usr)
if("toggle_fab")
if(QDELETED(dronefab))
dronefab = null
return
dronefab.produce_drones = !dronefab.produce_drones
var/toggle = dronefab.produce_drones ? "enable" : "disable"
to_chat(usr, "<span class='notice'>You [toggle] drone production in the nearby fabricator.</span>")
message_admins("[key_name_admin(usr)] [toggle]d maintenance drone production from the control console.")
log_game("[key_name(usr)] [toggle]d maintenance drone production from the control console.")
if("set_area")
drone_call_area = params["area"]
if("ping")
ping_cooldown = world.time + 1 MINUTES // One minute cooldown to prevent chat spam
to_chat(usr, "<span class='notice'>You issue a maintenance request for all active drones, highlighting [drone_call_area].</span>")
for(var/mob/living/silicon/robot/drone/D in GLOB.silicon_mob_list)
if(D.client && D.stat == CONSCIOUS)
to_chat(D, "<span class='boldnotice'>-- Maintenance drone presence requested in: [drone_call_area].</span>")
if("resync")
var/mob/living/silicon/robot/drone/D = locateUID(params["uid"])
if(D)
D.sync_cooldown = world.time + 1 MINUTES // One minute cooldown to prevent chat spam
to_chat(usr, "<span class='notice'>You issue a law synchronization directive for the drone.</span>")
D.law_resync()
if("shutdown")
var/mob/living/silicon/robot/drone/D = locateUID(params["uid"])
if(D)
to_chat(usr, "<span class='warning'>You issue a kill command for the unfortunate drone.</span>")
message_admins("[key_name_admin(usr)] issued kill order for drone [key_name_admin(D)] from control console.")
log_game("[key_name(usr)] issued kill order for [key_name(D)] from control console.")
D.shut_down()
/obj/machinery/computer/drone_control/proc/find_fab(mob/user)
if(dronefab)
return
if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
usr.set_machine(src)
for(var/obj/machinery/drone_fabricator/fab in get_area(src))
if(href_list["setarea"])
if(fab.stat & NOPOWER)
continue
//Probably should consider using another list, but this one will do.
var/t_area = input("Select the area to ping.", "Set Target Area", null) as null|anything in GLOB.TAGGERLOCATIONS
dronefab = fab
if(user)
to_chat(user, "<span class='notice'>Drone fabricator located.</span>")
return
if(!t_area || GLOB.TAGGERLOCATIONS[t_area])
return
drone_call_area = t_area
to_chat(usr, "<span class='notice'>You set the area selector to [drone_call_area].</span>")
else if(href_list["ping"])
to_chat(usr, "<span class='notice'>You issue a maintenance request for all active drones, highlighting [drone_call_area].</span>")
for(var/mob/living/silicon/robot/drone/D in GLOB.silicon_mob_list)
if(D.client && D.stat == 0)
to_chat(D, "-- Maintenance drone presence requested in: [drone_call_area].")
else if(href_list["resync"])
var/mob/living/silicon/robot/drone/D = locate(href_list["resync"])
if(D.stat != 2)
to_chat(usr, "<span class='warning'>You issue a law synchronization directive for the drone.</span>")
D.law_resync()
else if(href_list["shutdown"])
var/mob/living/silicon/robot/drone/D = locate(href_list["shutdown"])
if(D.stat != 2)
to_chat(usr, "<span class='warning'>You issue a kill command for the unfortunate drone.</span>")
message_admins("[key_name_admin(usr)] issued kill order for drone [key_name_admin(D)] from control console.")
log_game("[key_name(usr)] issued kill order for [key_name(src)] from control console.")
D.shut_down()
else if(href_list["search_fab"])
if(dronefab)
return
for(var/obj/machinery/drone_fabricator/fab in get_area(src))
if(fab.stat & NOPOWER)
continue
dronefab = fab
to_chat(usr, "<span class='notice'>Drone fabricator located.</span>")
return
to_chat(usr, "<span class='warning'>Unable to locate drone fabricator.</span>")
else if(href_list["toggle_fab"])
if(!dronefab)
return
if(get_dist(src,dronefab) > 3)
dronefab = null
to_chat(usr, "<span class='warning'>Unable to locate drone fabricator.</span>")
return
dronefab.produce_drones = !dronefab.produce_drones
to_chat(usr, "<span class='notice'>You [dronefab.produce_drones ? "enable" : "disable"] drone production in the nearby fabricator.</span>")
src.updateUsrDialog()
if(user)
to_chat(user, "<span class='warning'>Unable to locate drone fabricator.</span>")
@@ -1,22 +1,18 @@
/obj/machinery/drone_fabricator
name = "drone fabricator"
desc = "A large automated factory for producing maintenance drones."
icon = 'icons/obj/machines/drone_fab.dmi'
icon_state = "drone_fab_idle"
density = 1
anchored = 1
density = TRUE
anchored = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 20
active_power_usage = 5000
var/drone_progress = 0
var/produce_drones = 1
var/time_last_drone = 500
icon = 'icons/obj/machines/drone_fab.dmi'
icon_state = "drone_fab_idle"
/obj/machinery/drone_fabricator/New()
..()
var/produce_drones = TRUE
var/drone_progress = 100
var/time_last_drone = 0
/obj/machinery/drone_fabricator/power_change()
if(powered())
@@ -31,7 +27,8 @@
return
if(stat & NOPOWER || !produce_drones)
if(icon_state != "drone_fab_nopower") icon_state = "drone_fab_nopower"
if(icon_state != "drone_fab_nopower")
icon_state = "drone_fab_nopower"
return
if(drone_progress >= 100)
@@ -40,14 +37,14 @@
icon_state = "drone_fab_active"
var/elapsed = world.time - time_last_drone
drone_progress = round((elapsed/config.drone_build_time)*100)
drone_progress = round((elapsed / config.drone_build_time) * 100)
if(drone_progress >= 100)
visible_message("\The [src] voices a strident beep, indicating a drone chassis is prepared.")
visible_message("[src] voices a strident beep, indicating a drone chassis is prepared.")
/obj/machinery/drone_fabricator/examine(mob/user)
. = ..()
if(produce_drones && drone_progress >= 100 && istype(user,/mob/dead) && config.allow_drone_spawn && count_drones() < config.max_maint_drones)
if(produce_drones && drone_progress >= 100 && isobserver(user) && config.allow_drone_spawn && count_drones() < config.max_maint_drones)
. += "<BR><B>A drone is prepared. Select 'Join As Drone' from the Ghost tab to spawn as a maintenance drone.</B>"
/obj/machinery/drone_fabricator/proc/count_drones()
@@ -57,18 +54,17 @@
drones++
return drones
/obj/machinery/drone_fabricator/proc/create_drone(var/client/player)
/obj/machinery/drone_fabricator/proc/create_drone(client/player)
if(stat & NOPOWER)
return
if(!produce_drones || !config.allow_drone_spawn || count_drones() >= config.max_maint_drones)
return
if(!player || !istype(player.mob,/mob/dead))
if(!player || !isobserver(player.mob))
return
visible_message("\The [src] churns and grinds as it lurches into motion, disgorging a shiny new drone after a few moments.")
visible_message("[src] churns and grinds as it lurches into motion, disgorging a shiny new drone after a few moments.")
flick("h_lathe_leave",src)
time_last_drone = world.time
@@ -88,41 +84,40 @@
to_chat(src, "<span class='warning'>That verb is not currently permitted.</span>")
return
if(!src.stat)
if(stat != DEAD)
return
if(usr != src)
return 0 //something is terribly wrong
return FALSE //something is terribly wrong
if(jobban_isbanned(src,"nonhumandept") || jobban_isbanned(src,"Drone"))
to_chat(usr, "<span class='warning'>You are banned from playing drones and cannot spawn as a drone.</span>")
if(jobban_isbanned(src, "nonhumandept") || jobban_isbanned(src, "Drone"))
to_chat(usr, "<span class='warning'>You are banned from playing drones, and cannot spawn as one.</span>")
return
if(!SSticker || SSticker.current_state < 3)
if(!SSticker || SSticker.current_state < GAME_STATE_PLAYING)
to_chat(src, "<span class='warning'>You can't join as a drone before the game starts!</span>")
return
var/drone_age = 14 // 14 days to play as a drone
var/player_age_check = check_client_age(usr.client, drone_age)
var/player_age_check = check_client_age(usr.client, 14) // 14 days to play as a drone
if(player_age_check && config.use_age_restriction_for_antags)
to_chat(usr, "<span class='warning'>This role is not yet available to you. You need to wait another [player_age_check] days.</span>")
return
var/pt_req = role_available_in_playtime(client, ROLE_DRONE)
var/pt_req = role_available_in_playtime(client, "Drone")
if(pt_req)
var/pt_req_string = get_exp_format(pt_req)
to_chat(usr, "<span class='warning'>This role is not yet available to you. Play another [pt_req_string] to unlock it.</span>")
return
var/deathtime = world.time - src.timeofdeath
var/joinedasobserver = 0
if(istype(src,/mob/dead/observer))
var/deathtime = world.time - timeofdeath
var/joinedasobserver = FALSE
if(isobserver(src))
var/mob/dead/observer/G = src
if(cannotPossess(G))
to_chat(usr, "<span class='warning'>Upon using the antagHUD you forfeited the ability to join the round.</span>")
return
if(G.started_as_observer == 1)
joinedasobserver = 1
if(G.started_as_observer == TRUE)
joinedasobserver = TRUE
var/deathtimeminutes = round(deathtime / 600)
var/pluralcheck = "minute"
@@ -132,7 +127,7 @@
pluralcheck = " [deathtimeminutes] minute and"
else if(deathtimeminutes > 1)
pluralcheck = " [deathtimeminutes] minutes and"
var/deathtimeseconds = round((deathtime - deathtimeminutes * 600) / 10,1)
var/deathtimeseconds = round((deathtime - deathtimeminutes * 600) / 10, 1)
if(deathtime < 6000 && joinedasobserver == 0)
to_chat(usr, "You have been dead for[pluralcheck] [deathtimeseconds] seconds.")
@@ -151,7 +146,7 @@
return
if(DF.drone_progress >= 100)
DF.create_drone(src.client)
DF.create_drone(client)
return
to_chat(src, "<span class='warning'>There are no available drone spawn points, sorry.</span>")
-3
View File
@@ -21,6 +21,3 @@ GLOBAL_DATUM_INIT(notcontained_state, /datum/ui_state/notcontained_state, new)
/mob/living/silicon/notcontained_can_use_topic(src_object)
return default_can_use_topic(src_object) // Silicons use default bevhavior.
/mob/living/simple_animal/drone/notcontained_can_use_topic(src_object)
return default_can_use_topic(src_object) // Drones use default bevhavior.
@@ -0,0 +1,201 @@
// code\modules\mob\living\silicon\robot\drone\drone_console.dm
import { toTitleCase } from 'common/string';
import { useBackend } from '../backend';
import { Box, Button, Divider, Dropdown, Flex, LabeledList, NoticeBox, ProgressBar, Section } from '../components';
import { Window } from '../layouts';
export const DroneConsole = (props, context) => {
return (
<Window>
<Window.Content scrollable>
<Fabricator />
<DroneList />
</Window.Content>
</Window>
);
};
const Fabricator = (props, context) => {
const { act, data } = useBackend(context);
const {
drone_fab,
fab_power,
drone_prod,
drone_progress,
} = data;
let FabDetected = () => {
if (drone_fab) {
return (
<LabeledList>
<LabeledList.Item label="External Power">
<Box color={fab_power ? "good" : "bad"}>
[ {fab_power ? "Online" : "Offline"} ]
</Box>
</LabeledList.Item>
<LabeledList.Item label="Drone Production">
<ProgressBar
value={drone_progress / 100}
ranges={{
good: [0.7, Infinity],
average: [0.4, 0.7],
bad: [-Infinity, 0.4],
}} />
</LabeledList.Item>
</LabeledList>
);
} else {
return (
<NoticeBox textAlign="center" danger={1}>
<Flex inline={1} direction="column">
<Flex.Item>
FABRICATOR NOT DETECTED.
</Flex.Item>
<Flex.Item>
<Button
icon="search"
content="Search"
onClick={() => act('find_fab')} />
</Flex.Item>
</Flex>
</NoticeBox>
);
}
};
return (
<Section
title="Drone Fabricator"
buttons={
<Button
icon="power-off"
content={drone_prod ? "Online" : "Offline"}
color={drone_prod ? "green" : "red"}
onClick={() => act('toggle_fab')} />
}>
{FabDetected()}
</Section>
);
};
const DroneList = (props, context) => {
const { act, data } = useBackend(context);
const {
drones,
area_list,
selected_area,
ping_cd,
} = data;
let status = (stat, client) => {
let box_color;
let text;
if (stat === 2) { // Dead
box_color='bad';
text="Disabled";
} else if ((stat === 1) || !client) { // Unconscious or SSD
box_color='average';
text="Inactive";
} else { // Alive
box_color='good';
text="Active";
}
return (
<Box color={box_color}>
{text}
</Box>
);
};
const Divide = () => {
if (drones.length) {
return (
<Box py={0.2}>
<Divider />
</Box>
);
}
};
return (
<Section title="Maintenance Units">
<Flex>
<Flex.Item>
Request Drone presence in area:&nbsp;
</Flex.Item>
<Flex.Item>
<Dropdown
options={area_list}
selected={selected_area}
width="125px"
onSelected={value => act('set_area', {
area: value,
})} />
</Flex.Item>
</Flex>
<Button
content="Send Ping"
icon="broadcast-tower"
disabled={ping_cd || !drones.length}
title={drones.length ? null : "No active drones!"}
fluid={1}
textAlign="center"
py={0.4}
mt={0.6}
onClick={() => act('ping')} />
<Divide />
{drones.map(drone => (
<Section key={drone.name}
title={toTitleCase(drone.name)}
buttons={(
<Flex>
<Button
icon="sync"
content="Resync"
disabled={drone.stat === 2 || drone.sync_cd}
onClick={() => act('resync', {
uid: drone.uid,
})} />
<Button.Confirm
icon="power-off"
content="Shutdown"
disabled={drone.stat === 2}
color="bad"
onClick={() => act('shutdown', {
uid: drone.uid,
})} />
</Flex>
)}>
<LabeledList>
<LabeledList.Item label="Status">
{status(drone.stat, drone.client)}
</LabeledList.Item>
<LabeledList.Item label="Integrity">
<ProgressBar
value={drone.health}
ranges={{
good: [0.7, Infinity],
average: [0.4, 0.7],
bad: [-Infinity, 0.4],
}} />
</LabeledList.Item>
<LabeledList.Item label="Charge">
<ProgressBar
value={drone.charge}
ranges={{
good: [0.7, Infinity],
average: [0.4, 0.7],
bad: [-Infinity, 0.4],
}} />
</LabeledList.Item>
<LabeledList.Item label="Location">
{drone.location}
</LabeledList.Item>
</LabeledList>
</Section>
))}
</Section>
);
};
File diff suppressed because one or more lines are too long