diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index 51742f30bca..3122f089bd6 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -64,6 +64,10 @@ aiCamera.captureimage(A, usr) return + if(waypoint_mode) + set_waypoint(A) + waypoint_mode = 0 + return /* AI restrained() currently does nothing if(restrained()) diff --git a/code/game/machinery/bots/floorbot.dm b/code/game/machinery/bots/floorbot.dm index f85d57657f3..dda1b8afcd0 100644 --- a/code/game/machinery/bots/floorbot.dm +++ b/code/game/machinery/bots/floorbot.dm @@ -343,8 +343,9 @@ obj/machinery/bot/floorbot/process_scan(var/scan_target) result = F if(FIX_TILE) //Selects only damaged floors. F = scan_target - if(F.broken || F.burnt) - result = F + if(istype(F, /turf)) + if(F.broken || F.burnt) + result = F if(TILE_EMAG) //Emag mode! Rip up the floor and cause breaches to space! F = scan_target if(!istype(F, /turf/simulated/floor/plating)) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 59afd4794db..bd9f66d7b35 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -55,6 +55,9 @@ var/list/ai_list = list() var/datum/trackable/track = null var/can_shunt = 1 var/last_announcement = "" + var/obj/machinery/bot/Bot + var/turf/waypoint //Holds the turf of the currently selected waypoint. + var/waypoint_mode = 0 //Waypoint mode is for selecting a turf via clicking. /mob/living/silicon/ai/New(loc, var/datum/ai_laws/L, var/obj/item/device/mmi/B, var/safety = 0) var/list/possibleNames = ai_names @@ -100,7 +103,7 @@ var/list/ai_list = list() if (istype(loc, /turf)) verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \ /mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \ - /mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/control_integrated_radio) + /mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/botcall, /mob/living/silicon/ai/proc/control_integrated_radio) if(!safety)//Only used by AIize() to successfully spawn an AI. if (!B)//If there is no player/brain inside. @@ -442,6 +445,24 @@ var/list/ai_list = list() if(A && target) A.ai_actual_track(target) return + + if (href_list["callbot"]) //Command a bot to move to a selected location. + Bot = locate(href_list["callbot"]) in aibots + 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 + 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 aibots + if(!Bot || Bot.remote_disabled || src.control_disabled) + return + Bot.attack_ai(src) + + if (href_list["botrefresh"]) //Refreshes the bot control panel. + botcall() + return else if (href_list["faketrack"]) var/mob/target = locate(href_list["track"]) in mob_list @@ -536,7 +557,61 @@ var/list/ai_list = list() if(camera_light_on) A.SetLuminosity(AI_CAMERA_LUMINOSITY) else A.SetLuminosity(0) +/mob/living/silicon/ai/proc/botcall() + set category = "AI Commands" + set name = "Access Robot Control" + set desc = "Wirelessly control various automatic robots." + if(stat == 2) + src << "Critical error. System offline." + return + if(control_disabled) + src << "Wireless communication is disabled." + return + var/turf/ai_current_turf = get_turf(src) + var/ai_Zlevel = ai_current_turf.z + var/d + var/area/bot_area + d += "Query network status
" + d += "" + + for (Bot in aibots) + if(Bot.z == ai_Zlevel && !Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected! + bot_area = get_area(Bot) + 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() + +/mob/living/silicon/ai/proc/set_waypoint(var/atom/A) + var/turf/turf_check = get_turf(A) + //The target must be in view of a camera or near the core. + if(turf_check in range(get_turf(src))) + call_bot(turf_check) + else if(cameranet && cameranet.checkTurfVis(turf_check)) + call_bot(turf_check) + else + src << "Selected location is not visible." + +/mob/living/silicon/ai/proc/call_bot(var/turf/waypoint) + + if(!Bot) + return + + if(Bot.calling_ai && Bot.calling_ai != src) //Prevents an override if another AI is controlling this bot. + src << "Interface error. Unit is already in use." + return + + Bot.call_bot(src, waypoint) + /mob/living/silicon/ai/proc/switchCamera(var/obj/machinery/camera/C) src.cameraFollow = null

Name

Status

Location

Control

[Bot.hacked ? "(!) [Bot.name]" : Bot.name][Bot.on ? "[Bot.mode ? "[ Bot.mode_name[Bot.mode] ]": "Idle"]" : "Inactive"][bot_area.name]InterfaceCall