diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index efe94a3261..2c8e3164a9 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -45,7 +45,7 @@ radiomod = ";" //AIs will, by default, state their laws on the internal radio. var/obj/item/pda/ai/aiPDA var/obj/item/multitool/aiMulti - var/mob/living/simple_animal/bot/Bot + var/datum/weakref/bot_ref var/tracking = FALSE //this is 1 if the AI is currently tracking somebody, but the track has not yet been completed. var/datum/effect_system/spark_spread/spark_system //So they can initialize sparks whenever/N var/obj/machinery/status_display/controlled_display @@ -100,7 +100,6 @@ var/display_icon_override var/emote_display = "Neutral" //text string of the current emote we set for the status displays, to prevent logins resetting it. - // TODO: Currently unused, needs port from TG. var/datum/robot_control/robot_control // TODO: Currently unused, needs port from TG. /// Station alert datum for showing alerts UI @@ -203,14 +202,13 @@ QDEL_NULL(spark_system) QDEL_NULL(malf_picker) QDEL_NULL(doomsday_device) - // TODO: Port implementation of these from TG or remove the unused code. - // QDEL_NULL(robot_control) + QDEL_NULL(robot_control) // QDEL_NULL(alert_control) QDEL_NULL(aiMulti) QDEL_NULL(aiPDA) malfhack = null current = null - Bot = null + bot_ref = null controlled_equipment = null linked_core = null apc_override = null @@ -480,24 +478,6 @@ else to_chat(src, "Target is not on or near any active cameras on the station.") return - if(href_list["callbot"]) //Command a bot to move to a selected location. - if(call_bot_cooldown > world.time) - to_chat(src, "Error: Your last call bot command is still processing, please wait for the bot to finish calculating a route.") - return - Bot = locate(href_list["callbot"]) in GLOB.alive_mob_list - if(!Bot || Bot.remote_disabled || src.control_disabled) - return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off. - waypoint_mode = 1 - to_chat(src, "Set your waypoint by clicking on a valid location free of obstructions.") - return - if(href_list["interface"]) //Remotely connect to a bot! - Bot = locate(href_list["interface"]) in GLOB.alive_mob_list - if(!Bot || Bot.remote_disabled || src.control_disabled) - return - Bot.attack_ai(src) - if(href_list["botrefresh"]) //Refreshes the bot control panel. - botcall() - return if (href_list["ai_take_control"]) //Mech domination var/obj/vehicle/sealed/mecha/M = locate(href_list["ai_take_control"]) in GLOB.mechas_list @@ -544,33 +524,11 @@ set category = "AI Commands" set name = "Access Robot Control" set desc = "Wirelessly control various automatic robots." - if(incapacitated()) - return - if(control_disabled) - to_chat(src, "Wireless control is disabled.") - return - var/turf/ai_current_turf = get_turf(src) - var/ai_Zlevel = ai_current_turf.z - var/d - d += "Query network status
" - d += "" + if(!robot_control) + robot_control = new(src) - for (Bot in GLOB.alive_mob_list) - if(Bot.z == ai_Zlevel && !Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected! - var/bot_mode = Bot.get_mode() - d += "" - //If the bot is on, it will display the bot's current mode status. If the bot is not mode, it will just report "Idle". "Inactive if it is not on at all. - d += "" - d += "" - d += "" - d += "" - d += "" - d = format_text(d) - - var/datum/browser/popup = new(src, "botcall", "Remote Robot Control", 700, 400) - popup.set_content(d) - popup.open() + robot_control.ui_interact(src) /mob/living/silicon/ai/proc/set_waypoint(atom/A) var/turf/turf_check = get_turf(A) @@ -580,22 +538,21 @@ else if(GLOB.cameranet && GLOB.cameranet.checkTurfVis(turf_check)) call_bot(turf_check) else - to_chat(src, "Selected location is not visible.") + to_chat(src, span_danger("Selected location is not visible.")) /mob/living/silicon/ai/proc/call_bot(turf/waypoint) - - if(!Bot) + var/mob/living/simple_animal/bot/bot = bot_ref.resolve() + if(!bot) return - if(Bot.calling_ai && Bot.calling_ai != src) //Prevents an override if another AI is controlling this bot. - to_chat(src, "Interface error. Unit is already in use.") + if(bot.calling_ai && bot.calling_ai != src) //Prevents an override if another AI is controlling this bot. + to_chat(src, span_danger("Interface error. Unit is already in use.")) return - to_chat(src, "Sending command to bot...") + to_chat(src, span_notice("Sending command to bot...")) call_bot_cooldown = world.time + CALL_BOT_COOLDOWN - Bot.call_bot(src, waypoint) + bot.call_bot(src, waypoint) call_bot_cooldown = 0 - /mob/living/silicon/ai/triggerAlarm(class, area/home, cameras, obj/source) if(source.z != z) return diff --git a/code/modules/mob/living/silicon/ai/robot_control.dm b/code/modules/mob/living/silicon/ai/robot_control.dm index bbfb7604ba..a723fd05e2 100644 --- a/code/modules/mob/living/silicon/ai/robot_control.dm +++ b/code/modules/mob/living/silicon/ai/robot_control.dm @@ -10,7 +10,7 @@ if(user != owner || owner.incapacitated()) return FALSE if(owner.control_disabled) - to_chat(user, "Wireless control is disabled.") + to_chat(user, span_warning("Wireless control is disabled.")) return FALSE return TRUE @@ -35,17 +35,23 @@ var/turf/ai_current_turf = get_turf(owner) var/ai_zlevel = ai_current_turf.z + var/mob/living/simple_animal/bot/bot = owner.bot_ref?.resolve() + if((owner.waypoint_mode && bot) && !(bot.remote_disabled || owner.control_disabled)) + data["commandeering"] = REF(bot) + else + data["commandeering"] = null + data["robots"] = list() - for(var/mob/living/simple_animal/bot/B in GLOB.bots_list) - if(B.z != ai_zlevel || B.remote_disabled) //Only non-emagged bots on the same Z-level are detected! + for(var/mob/living/simple_animal/bot/our_bot as anything in GLOB.bots_list) + if(our_bot.z != ai_zlevel || our_bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected! continue var/list/robot_data = list( - name = B.name, - model = B.model, - mode = B.get_mode(), - hacked = B.hacked, - location = get_area_name(B, TRUE), - ref = REF(B) + name = our_bot.name, + model = our_bot.model, + mode = our_bot.get_mode(), + hacked = our_bot.hacked, + location = get_area_name(our_bot, TRUE), + ref = REF(our_bot) ) data["robots"] += list(robot_data) @@ -54,23 +60,30 @@ /datum/robot_control/ui_act(action, params) if(..()) return - if(!is_interactable(usr)) + var/mob/living/our_user = usr + if(!is_interactable(our_user)) + return + + var/mob/living/simple_animal/bot/bot = locate(params["ref"]) in GLOB.bots_list + if(isnull(bot)) return switch(action) if("callbot") //Command a bot to move to a selected location. if(owner.call_bot_cooldown > world.time) - to_chat(usr, "Error: Your last call bot command is still processing, please wait for the bot to finish calculating a route.") + to_chat(our_user, span_danger("Error: Your last call bot command is still processing, please wait for the bot to finish calculating a route.")) return - owner.Bot = locate(params["ref"]) in GLOB.bots_list - if(!owner.Bot || owner.Bot.remote_disabled || owner.control_disabled) + + if(bot.remote_disabled) return + + owner.bot_ref = WEAKREF(bot) owner.waypoint_mode = TRUE - to_chat(usr, "Set your waypoint by clicking on a valid location free of obstructions.") - . = TRUE + to_chat(our_user, span_notice("Set your waypoint by clicking on a valid location free of obstructions.")) if("interface") //Remotely connect to a bot! - owner.Bot = locate(params["ref"]) in GLOB.bots_list - if(!owner.Bot || owner.Bot.remote_disabled || owner.control_disabled) + owner.bot_ref = WEAKREF(bot) + if(bot.remote_disabled) return - owner.Bot.attack_ai(usr) - . = TRUE + bot.attack_ai(our_user) + + return TRUE diff --git a/tgstation.dme b/tgstation.dme index 7d0afa0259..a201f09456 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2840,6 +2840,7 @@ #include "code\modules\mob\living\silicon\ai\login.dm" #include "code\modules\mob\living\silicon\ai\logout.dm" #include "code\modules\mob\living\silicon\ai\multicam.dm" +#include "code\modules\mob\living\silicon\ai\robot_control.dm" #include "code\modules\mob\living\silicon\ai\say.dm" #include "code\modules\mob\living\silicon\ai\vox_sounds.dm" #include "code\modules\mob\living\silicon\ai\freelook\cameranet.dm" diff --git a/tgui/packages/tgui/interfaces/RemoteRobotControl.js b/tgui/packages/tgui/interfaces/RemoteRobotControl.js index 75be82c8e3..85a15dbfd8 100644 --- a/tgui/packages/tgui/interfaces/RemoteRobotControl.js +++ b/tgui/packages/tgui/interfaces/RemoteRobotControl.js @@ -20,6 +20,7 @@ export const RemoteRobotControlContent = (props, context) => { const { act, data } = useBackend(context); const { robots = [], + commandeering, } = data; if (!robots.length) { return ( @@ -46,6 +47,7 @@ export const RemoteRobotControlContent = (props, context) => {

Name

Status

Location

Control

[Bot.hacked ? "(!)" : ""] [Bot.name] ([Bot.model])[bot_mode][get_area_name(Bot, TRUE)]InterfaceCall