From ce7c7f98850b9cff3b5f19120a16965c52d1de8a Mon Sep 17 00:00:00 2001 From: Deniz <66401072+Oyu07@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:05:39 +0000 Subject: [PATCH] Yet another Bot refactor. 2.0 (#23900) * test 1 claim_job comment spaces start * yay, its BROKE * Update bot.dm * alcohol is the only escape * static * it works * spacing * cleanbot list cleanup * comments * space AREA This is what insanity looks like. Every bot PR breaks something, without fail. fixed replace tiles? broke hull breach fixed hullbreach? broke cleanbots fixed hullbreach? well also broke it * Comment Sorting * comments 2/2 * comments 3/? * comments 4/? * autodoc 1/? * maketile doesnt drop * maketile update * floor - snake_case + if else * Floor - comments * floor - snake_case 2/? * cleanbot turf reservation comment * floorbot ignore list * comments * var/atom/A * target check. null runtime * tile clean comment removal * again * reviews. final_result removal * comment block * avoid bot TRUE * comments ?/? I lost track of how manny comment commits there are * autodocs * autodoc * autodocs * ignore_job -= target.UID() additions * anchored Noticed that, if a tile is in space, they will dance around it as they do not anchor. Now they do * runtime fix * ignore_job edits. clean after 30 * typo * fix before replace, DUH * ignore job clearing * Time Dilation 106% no more * eat tile fix, oops * replace plating * comment shift * lets try again * mode ! * process_type = null + to_chat cleanup + ignore_job bot_reset * remove extra ignore_job * target.loc * TRUE * ignore job and revert loc * move speed and such * comment with proc * God I hate myself * TRUE / FALSE * comments :) * else if * pesky comment * mods are asleep, rename the vars * small edits * Make ignore_job culling based on amount of bots alive. 1 job per bot * Revert move speed changes. Bots move slower than security on cere * Emag fixes oof * ++ * + 1? * ++ * comment * dropped metal amount * paranthesis * no need for absolute * Thanks VSC conflict resolver for duplicating this here * Emag is a bool now, self remind comment removed * Documentation * move speed null nulled * replace_tile lag / freeze fix + removed extra job stuff * clarification about which list is being used in comment --- .../mob/living/simple_animal/bot/bot.dm | 352 ++++++++++-------- .../mob/living/simple_animal/bot/cleanbot.dm | 5 +- .../mob/living/simple_animal/bot/floorbot.dm | 110 +++--- 3 files changed, 265 insertions(+), 202 deletions(-) diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 7445fed15fd..1dbf4a1c62f 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -15,7 +15,7 @@ minbodytemp = 0 has_unlimited_silicon_privilege = TRUE sentience_type = SENTIENCE_ARTIFICIAL - status_flags = 0 //no default canpush + status_flags = 0 // No default canpush can_strip = FALSE speak_emote = list("states") @@ -23,66 +23,104 @@ bubble_icon = "machine" faction = list("neutral", "silicon") - var/list/users = list() //for dialog updates + var/list/users = list() // For dialog updates var/window_id = "bot_control" - var/window_name = "Protobot 1.0" //Popup title - var/window_width = 0 //0 for default size + var/window_name = "Protobot 1.0" // Popup title + var/window_width = 0 // 0 for default size var/window_height = 0 - var/obj/item/paicard/paicard // Inserted pai card. - var/allow_pai = TRUE // Are we even allowed to insert a pai card. + var/obj/item/paicard/paicard // Inserted pai card. + var/allow_pai = TRUE // Are we even allowed to insert a pai card. var/bot_name var/disabling_timer_id = null var/list/player_access = list() var/emagged = FALSE - var/obj/item/card/id/access_card // the ID card that the bot "holds" + /// The ID card that the bot "holds" + var/obj/item/card/id/access_card var/list/prev_access = list() var/on = TRUE - var/open = FALSE //Maint panel + /// Maint panel + var/open = FALSE var/locked = TRUE - var/hacked = FALSE //Used to differentiate between being hacked by silicons and emagged by humans. + /// Used to differentiate between being hacked by silicons and emagged by humans. + var/hacked = FALSE /// Is currently hijacked by a pulse demon? var/hijacked = FALSE - var/text_hack = "" //Custom text returned to a silicon upon hacking a bot. - var/text_dehack = "" //Text shown when resetting a bots hacked status to normal. - var/text_dehack_fail = "" //Shown when a silicon tries to reset a bot emagged with the emag item, which cannot be reset. - var/declare_message = "" //What the bot will display to the HUD user. - var/frustration = 0 //Used by some bots for tracking failures to reach their target. - var/base_speed = 2 //The speed at which the bot moves, or the number of times it moves per process() tick. - var/turf/ai_waypoint //The end point of a bot's path, or the target location. - var/list/path = list() //List of turfs through which a bot 'steps' to reach the waypoint + /// Custom text returned to a silicon upon hacking a bot. + var/text_hack = "" + /// Text shown when resetting a bots hacked status to normal. + var/text_dehack = "" + /// Shown when a silicon tries to reset a bot emagged with the emag item, which cannot be reset. + var/text_dehack_fail = "" + /// What the bot will display to the HUD user. + var/declare_message = "" + /// Used by some bots for tracking failures to reach their target. + var/frustration = 0 + /// The speed at which the bot moves, or the number of times it moves per process() tick. + var/base_speed = 2 + /// The end point of a bot's path, or the target location. + var/turf/ai_waypoint + /// List of turfs through which a bot 'steps' to reach the waypoint + var/list/path = list() var/pathset = FALSE - var/list/ignore_list = list() //List of unreachable targets for an ignore-list enabled bot to ignore. - var/mode = BOT_IDLE //Standardizes the vars that indicate the bot is busy with its function. - var/tries = 0 //Number of times the bot tried and failed to move. - var/remote_disabled = FALSE //If enabled, the AI cannot *Remotely* control a bot. It can still control it through cameras. - var/mob/living/silicon/ai/calling_ai //Links a bot to the AI calling it. - var/obj/item/radio/Radio //The bot's radio, for speaking to people. - var/list/radio_config = null //which channels can the bot listen to - var/radio_channel = "Common" //The bot's default radio channel - var/auto_patrol = FALSE // set to make bot automatically patrol - var/turf/patrol_target // this is turf to navigate to (location of beacon) - var/turf/summon_target // The turf of a user summoning a bot. - var/new_destination // pending new destination (waiting for beacon response) - var/destination // destination description tag - var/next_destination // the next destination in the patrol route - var/ignorelistcleanuptimer = 1 // This ticks up every automated action, at 300 we clean the ignore list + /// List of unreachable targets for an ignore-list enabled bot to ignore. + var/list/ignore_list = list() + /// List of jobs claimed by bot + var/static/list/ignore_job = list() + /// Standardizes the vars that indicate the bot is busy with its function. + var/mode = BOT_IDLE + /// Number of times the bot tried and failed to move. + var/tries = 0 + /// If enabled, the AI cannot *Remotely* control a bot. It can still control it through cameras. + var/remote_disabled = FALSE + /// Links a bot to the AI calling it. + var/mob/living/silicon/ai/calling_ai + /// The bot's radio, for speaking to people. + var/obj/item/radio/Radio + /// Which channels can the bot listen to + var/list/radio_config = null + /// The bot's default radio channel + var/radio_channel = "Common" + /// Set to make bot automatically patrol + var/auto_patrol = FALSE + /// This is turf to navigate to (location of beacon) + var/turf/patrol_target + /// The turf of a user summoning a bot. + var/turf/summon_target + /// Pending new destination (waiting for beacon response) + var/new_destination + /// Destination description tag + var/destination + /// The next destination in the patrol route + var/next_destination + /// This ticks up every automated action, at 300 we clean the ignore list + var/ignore_list_cleanup_timer = 1 var/robot_arm = /obj/item/robot_parts/r_arm - var/blockcount = 0 //number of times retried a blocked path - var/awaiting_beacon = 0 // count of pticks awaiting a beacon response + /// Number of times retried a blocked path + var/blockcount = 0 + /// Count of pticks awaiting a beacon response + var/awaiting_beacon = 0 - var/nearest_beacon // the nearest beacon's tag - var/turf/nearest_beacon_loc // the nearest beacon's location + /// The nearest beacon's tag + var/nearest_beacon + /// The nearest beacon's location + var/turf/nearest_beacon_loc - var/model = "" //The type of bot it is. + ///The type of bot it is. + var/model = "" + /// Bot Purpose under Show Laws var/bot_purpose = "improve the station to the best of your ability" - var/control_freq = BOT_FREQ // bot control frequency - var/bot_filter // The radio filter the bot uses to identify itself on the network. - var/bot_type = 0 //The type of bot it is, for radio control. + /// Bot control frequency + var/control_freq = BOT_FREQ + + /// The radio filter the bot uses to identify itself on the network. + var/bot_filter + /// The type of bot it is, for radio control. + var/bot_type = 0 /// The type of data HUD the bot uses. Diagnostic by default. var/data_hud_type = DATA_HUD_DIAGNOSTIC_BASIC - //This holds text for what the bot is mode doing, reported on the remote bot control interface. + // This holds text for what the bot is mode doing, reported on the remote bot control interface. var/list/mode_name = list("In Pursuit","Preparing to Arrest", "Arresting", \ "Beginning Patrol", "Patrolling", "Summoned by PDA", \ "Cleaning", "Repairing", "Proceeding to work site", "Healing", \ @@ -94,11 +132,11 @@ /// List of access values you can have to access the bot. Consider this as req_one_access var/list/req_access = list() - hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD)//Diagnostic HUD views + hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD) // Diagnostic HUD views - /// storing last chased target known location + /// Storing last chased target known location var/turf/last_target_location - /// will be true if we lost target we were chasing + /// Will be true if we lost target we were chasing var/lost_target = FALSE /obj/item/radio/headset/bot @@ -110,7 +148,7 @@ if(istype(B)) if(!B.radio_config) B.radio_config = list("AI Private" = 1) - if(!(B.radio_channel in B.radio_config)) // put it first so it's the :h channel + if(!(B.radio_channel in B.radio_config)) // Put it first so it's the :h channel B.radio_config.Insert(1, "[B.radio_channel]") B.radio_config["[B.radio_channel]"] = 1 config(B.radio_config) @@ -146,7 +184,7 @@ frustration++ /mob/living/simple_animal/bot/proc/get_mode() - if(client) //Player bots do not have modes, thus the override. Also an easy way for PDA users/AI to know when a bot is a player. + if(client) // Player bots do not have modes, thus the override. Also an easy way for PDA users/AI to know when a bot is a player. if(paicard) return "pAI Controlled" else @@ -164,20 +202,20 @@ if(disabling_timer_id) return FALSE if(stat) - return 0 + return FALSE on = TRUE REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, "depowered") set_light(initial(light_range)) update_icon(UPDATE_ICON_STATE | UPDATE_OVERLAYS) update_controls() diag_hud_set_botstat() - return 1 + return TRUE /mob/living/simple_animal/bot/proc/turn_off() on = FALSE ADD_TRAIT(src, TRAIT_IMMOBILIZED, "depowered") set_light(0) - bot_reset() //Resets an AI's call, should it exist. + bot_reset() // Resets an AI's call, should it exist. update_icon(UPDATE_ICON_STATE | UPDATE_OVERLAYS) update_controls() @@ -187,7 +225,7 @@ icon_living = icon_state icon_dead = icon_state access_card = new /obj/item/card/id(src) - //This access is so bots can be immediately set to patrol and leave Robotics, instead of having to be let out first. + // This access is so bots can be immediately set to patrol and leave Robotics, instead of having to be let out first. access_card.access += ACCESS_ROBOTICS set_custom_texts() Radio = new/obj/item/radio/headset/bot(src) @@ -210,10 +248,10 @@ /mob/living/simple_animal/bot/med_hud_set_health() - return //we use a different hud + return // We use a different hud /mob/living/simple_animal/bot/med_hud_set_status() - return //we use a different hud + return // We use a different hud /mob/living/simple_animal/bot/Destroy() @@ -250,21 +288,23 @@ qdel(src) /mob/living/simple_animal/bot/emag_act(mob/user) - if(locked) //First emag application unlocks the bot's interface. Apply a screwdriver to use the emag again. + if(locked) // First emag application unlocks the bot's interface. Apply a screwdriver to use the emag again. locked = FALSE to_chat(user, "You bypass [src]'s controls.") return TRUE + if(!locked && open) //Bot panel is unlocked by ID or emag, and the panel is screwed open. Ready for emagging. emagged = TRUE - remote_disabled = TRUE //Manually emagging the bot locks out the AI built in panel. - locked = TRUE //Access denied forever! + remote_disabled = TRUE // Manually emagging the bot locks out the AI built in panel. + locked = TRUE // Access denied forever! bot_reset() - turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP. + turn_on() // The bot automatically turns on when emagged, unless recently hit with EMP. to_chat(src, "(#$*#$^^( OVERRIDE DETECTED") show_laws() if(user) add_attack_logs(user, src, "Emagged") return TRUE + else //Bot is unlocked, but the maint panel has not been opened with a screwdriver yet. to_chat(user, "You need to open maintenance panel first!") @@ -290,14 +330,14 @@ /mob/living/simple_animal/bot/handle_automated_action() diag_hud_set_botmode() - if(ignorelistcleanuptimer % 300 == 0) // Every 300 actions, clean up the ignore list from old junk + if(++ignore_list_cleanup_timer == 300) // Every 300 actions, clean up the ignore list from old junk for(var/uid in ignore_list) - var/atom/referredatom = locateUID(uid) - if(!referredatom || QDELETED(referredatom)) + var/atom/referred_atom = locateUID(uid) + if(!referred_atom || QDELETED(referred_atom)) ignore_list -= uid - ignorelistcleanuptimer = 1 + ignore_list_cleanup_timer = 0 else - ignorelistcleanuptimer++ + ignore_list_cleanup_timer++ if(!on) return @@ -305,14 +345,14 @@ if(hijacked) return - switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command. - if(BOT_RESPONDING) //Called by the AI. + switch(mode) // High-priority overrides are processed first. Bots can do nothing else while under direct command. + if(BOT_RESPONDING) // Called by the AI. call_mode() return - if(BOT_SUMMON) //Called by PDA + if(BOT_SUMMON) // Called by PDA bot_summon() return - return 1 //Successful completion. Used to prevent child process() continuing if this one is ended early. + return TRUE // Successful completion. Used to prevent child process() continuing if this one is ended early. /mob/living/simple_animal/bot/attack_alien(mob/living/carbon/alien/user) user.changeNext_move(CLICK_CD_MELEE) @@ -407,7 +447,7 @@ return ..() if(locked) to_chat(user, "The maintenance panel is locked.") - return TRUE // must be true or we attempt to stab the bot + return TRUE // Must be true or we attempt to stab the bot open = !open I.play_tool_sound(src) @@ -418,7 +458,7 @@ /mob/living/simple_animal/bot/welder_act(mob/user, obj/item/I) if(user.a_intent != INTENT_HELP) return - if(user == src) //No self-repair dummy + if(user == src) // No self-repair dummy return . = TRUE if(health >= maxHealth) @@ -467,7 +507,7 @@ /mob/living/simple_animal/bot/proc/disable(time) if(disabling_timer_id) - deltimer(disabling_timer_id) // if we already have disabling timer, lets replace it with new one + deltimer(disabling_timer_id) // If we already have disabling timer, lets replace it with new one if(on) turn_off() disabling_timer_id = addtimer(CALLBACK(src, PROC_REF(enable)), time, TIMER_STOPPABLE) @@ -486,12 +526,12 @@ set_custom_texts() return TRUE -/mob/living/simple_animal/bot/proc/set_custom_texts() //Superclass for setting hack texts. Appears only if a set is not given to a bot locally. +/mob/living/simple_animal/bot/proc/set_custom_texts() // Superclass for setting hack texts. Appears only if a set is not given to a bot locally. text_hack = "You hack [name]." text_dehack = "You reset [name]." text_dehack_fail = "You fail to reset [name]." -/mob/living/simple_animal/bot/proc/speak(message, channel) //Pass a message to have the bot say() it. Pass a frequency to say it on the radio. +/mob/living/simple_animal/bot/proc/speak(message, channel) // Pass a message to have the bot say() it. Pass a frequency to say it on the radio. if((!on) || (!message)) return if(channel) @@ -500,74 +540,73 @@ say(message) return -//Generalized behavior code, override where needed! +// Generalized behavior code, override where needed! /* scan() will search for a given type (such as turfs, human mobs, or objects) in the bot's view range, and return a single result. Arguments: The object type to be searched (such as "/mob/living/carbon/human"), the old scan result to be ignored, if one exists, and the view range, which defaults to 7 (full screen) if an override is not passed. If the bot maintains an ignore list, it is also checked here. -If the bot has avoid_bot, which inserts its own path, it will ignore turfs with the same bot type - +If avoid_bot = TRUE, it will claim it's target. List of bots that use it: Cleanbot and Floorbot Example usage: patient = scan(/mob/living/carbon/human, oldpatient, 1) The proc would return a human next to the bot to be set to the patient var. Pass the desired type path itself, declaring a temporary var beforehand is not required. */ /mob/living/simple_animal/bot/proc/scan(atom/scan_type, atom/old_target, scan_range = DEFAULT_SCAN_RANGE, avoid_bot) - var/final_result - for(var/scan in view(scan_range, src)) //Search for something in range! - var/atom/A = scan - if(!istype(A, scan_type)) //Check that the thing we found is the type we want! - continue //If not, keep searching! - if((A.UID() in ignore_list) || (A == old_target)) //Filter for blacklisted elements, usually unreachable or previously processed oness + for(var/atom/A in view(scan_range, src)) // Search for something in range! + if(!istype(A, scan_type)) // Check that the thing we found is the type we want! + continue // If not, keep searching! + if((A.UID() in ignore_list) || (A == old_target)) // Filter for blacklisted elements, usually unreachable or previously processed oness continue - if(turf_has_bot(avoid_bot, get_turf(A))) //Ignores targets that already have a bot of the same type on it, meant for cleanbot and floorbot seperation + var/scan_result = process_scan(A) // Some bots may require additional processing when a result is selected. + if(!scan_result) + continue // The current element failed assessment, move on to the next. + if(assign_bot(A, avoid_bot)) // Is the target claimed by a bot continue - var/scan_result = process_scan(A) //Some bots may require additional processing when a result is selected. - if(scan_result) - final_result = scan_result - else - continue //The current element failed assessment, move on to the next. - return final_result + return scan_result -/mob/living/simple_animal/bot/proc/turf_has_bot(avoid_bot, turf/turf_to_search) - if(!avoid_bot) +/mob/living/simple_animal/bot/proc/assign_bot(atom/A, avoid_bot) + if(!avoid_bot) // Only bots with avoid bot should be considered return FALSE - for(var/bot in turf_to_search) - if(istype(bot, avoid_bot)) - return TRUE - return FALSE + if(A.UID() in ignore_job) // Is this target already claimed by a bot + return TRUE + claim_job(A) // Claim the job so other bots don't come -//When the scan finds a target, run bot specific processing to select it for the next step. Empty by default. +/mob/living/simple_animal/bot/proc/claim_job(atom/A) // Adds the target to ignore_job list + var/ignore_amount = length(GLOB.bots_list) // 1 claim per bot + if(length(ignore_job) >= ++ignore_amount) // Something went wrong, cull the herd + ignore_job.Cut() + ignore_job |= A.UID() + +// When the scan finds a target, run bot specific processing to select it for the next step. Empty by default. /mob/living/simple_animal/bot/proc/process_scan(atom/scan_target) return scan_target /mob/living/simple_animal/bot/proc/add_to_ignore(atom/A) - if(ignore_list.len < 50) //This will help keep track of them, so the bot is always trying to reach a blocked spot. - ignore_list |= A.UID() - else //If the list is full, insert newest, delete oldest. - ignore_list.Cut(1, 2) - ignore_list |= A.UID() + if(length(ignore_list) >= 50) // This will help keep track of them, so the bot is always trying to reach a blocked spot. + ignore_list.Cut(1, 2) // If the list is full, insert newest, delete oldest. + ignore_list |= A.UID() + /* Movement proc for stepping a bot through a path generated through A-star. Pass a positive integer as an argument to override a bot's default speed. */ /mob/living/simple_animal/bot/proc/bot_move(dest, move_speed) - if(!dest || !path || !length(path)) //A-star failed or a path/destination was not set. + if(!dest || !path || !length(path)) // A-star failed or a path/destination was not set. set_path(null) return FALSE - dest = get_turf(dest) //We must always compare turfs, so get the turf of the dest var if dest was originally something else. - var/turf/last_node = get_turf(path[length(path)]) //This is the turf at the end of the path, it should be equal to dest. - if(get_turf(src) == dest) //We have arrived, no need to move again. + dest = get_turf(dest) // We must always compare turfs, so get the turf of the dest var if dest was originally something else. + var/turf/last_node = get_turf(path[length(path)]) // This is the turf at the end of the path, it should be equal to dest. + if(get_turf(src) == dest) // We have arrived, no need to move again. return TRUE - else if(dest != last_node) //The path should lead us to our given destination. If this is not true, we must stop. + else if(dest != last_node) // The path should lead us to our given destination. If this is not true, we must stop. set_path(null) return FALSE - var/step_count = move_speed ? move_speed : base_speed //If a value is passed into move_speed, use that instead of the default speed var. + var/step_count = move_speed ? move_speed : base_speed // If a value is passed into move_speed, use that instead of the default speed var. if(step_count >= 1 && tries < BOT_STEP_MAX_RETRIES) for(var/step_number in 1 to step_count) @@ -578,7 +617,7 @@ Pass a positive integer as an argument to override a bot's default speed. return TRUE -/mob/living/simple_animal/bot/proc/bot_step() //Step,increase tries if failed +/mob/living/simple_animal/bot/proc/bot_step() // Step,increase tries if failed if(!length(path)) return FALSE @@ -596,19 +635,19 @@ Pass a positive integer as an argument to override a bot's default speed. access_card.access = prev_access /mob/living/simple_animal/bot/proc/call_bot(caller, turf/waypoint, message=TRUE) - bot_reset() //Reset a bot before setting it to call mode. + bot_reset() // Reset a bot before setting it to call mode. var/area/end_area = get_area(waypoint) var/datum/job/captain/All = new/datum/job/captain access_card.access = All.get_access() // Give the bot temporary all access set_path(get_path_to(src, waypoint, 200, id = access_card)) - calling_ai = caller //Link the AI to the bot! + calling_ai = caller // Link the AI to the bot! ai_waypoint = waypoint - if(path && length(path)) //Ensures that a valid path is calculated! + if(path && length(path)) // Ensures that a valid path is calculated! if(!on) - turn_on() //Saves the AI the hassle of having to activate a bot manually. + turn_on() // Saves the AI the hassle of having to activate a bot manually. if(client) reset_access_timer_id = addtimer(CALLBACK(src, PROC_REF(bot_reset)), 600, TIMER_OVERRIDE|TIMER_STOPPABLE) //if the bot is player controlled, they get the extra access for a limited time to_chat(src, "Priority waypoint set by [calling_ai] [caller]. Proceed to [end_area.name].
[length(path)-1] meters to destination. You have been granted additional door access for 60 seconds.
") @@ -624,8 +663,8 @@ Pass a positive integer as an argument to override a bot's default speed. access_card.access = prev_access // Don't forget to reset it set_path(null) -/mob/living/simple_animal/bot/proc/call_mode() //Handles preparing a bot for a call, as well as calling the move proc. -//Handles the bot's movement during a call. +/mob/living/simple_animal/bot/proc/call_mode() // Handles preparing a bot for a call, as well as calling the move proc. +// Handles the bot's movement during a call. var/success = bot_move(ai_waypoint, 3) if(!success) if(calling_ai) @@ -634,13 +673,14 @@ Pass a positive integer as an argument to override a bot's default speed. bot_reset() /mob/living/simple_animal/bot/proc/bot_reset() - if(calling_ai) //Simple notification to the AI if it called a bot. It will not know the cause or identity of the bot. + if(calling_ai) // Simple notification to the AI if it called a bot. It will not know the cause or identity of the bot. to_chat(calling_ai, "Call command to a bot has been reset.") calling_ai = null if(reset_access_timer_id) deltimer(reset_access_timer_id) reset_access_timer_id = null set_path(null) + ignore_job.Cut() last_target_location = null lost_target = FALSE summon_target = null @@ -668,21 +708,21 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/proc/start_patrol() set_path(null) - if(tries >= BOT_STEP_MAX_RETRIES) //Bot is trapped, so stop trying to patrol. + if(tries >= BOT_STEP_MAX_RETRIES) // Bot is trapped, so stop trying to patrol. auto_patrol = FALSE tries = 0 speak("Unable to start patrol.") return - if(!auto_patrol) //A bot not set to patrol should not be patrolling. + if(!auto_patrol) // A bot not set to patrol should not be patrolling. mode = BOT_IDLE return if(patrol_target) // has patrol target INVOKE_ASYNC(src, PROC_REF(target_patrol)) - else // no patrol target, so need a new one + else // No patrol target, so need a new one speak("Engaging patrol mode.") find_patrol_target() tries++ @@ -694,30 +734,30 @@ Pass a positive integer as an argument to override a bot's default speed. return mode = BOT_PATROL -// perform a single patrol step +// Perform a single patrol step /mob/living/simple_animal/bot/proc/patrol_step() if(client) // In use by player, don't actually move. return - if(loc == patrol_target) // reached target - //Find the next beacon matching the target. + if(loc == patrol_target) // Reached target + // Find the next beacon matching the target. if(!get_next_patrol_target()) - find_patrol_target() //If it fails, look for the nearest one instead. + find_patrol_target() // If it fails, look for the nearest one instead. return - else if(length(path) && patrol_target) // valid path + else if(length(path) && patrol_target) // Valid path if(path[1] == loc) increment_path() return - var/moved = bot_move(patrol_target)//step_towards(src, next) // attempt to move - if(!moved) //Couldn't proceed the next step of the path BOT_STEP_MAX_RETRIES times + var/moved = bot_move(patrol_target) // step_towards(src, next) // attempt to move + if(!moved) // Couldn't proceed the next step of the path BOT_STEP_MAX_RETRIES times addtimer(CALLBACK(src, PROC_REF(patrol_step_not_moved)), 2) - else // no path, so calculate new one + else // No path, so calculate new one mode = BOT_START_PATROL /mob/living/simple_animal/bot/proc/patrol_step_not_moved() @@ -726,7 +766,7 @@ Pass a positive integer as an argument to override a bot's default speed. find_patrol_target() tries = 0 -// finds the nearest beacon to self +// Finds the nearest beacon to self /mob/living/simple_animal/bot/proc/find_patrol_target() nearest_beacon = null new_destination = null @@ -740,13 +780,13 @@ Pass a positive integer as an argument to override a bot's default speed. speak("Disengaging patrol mode.") /mob/living/simple_animal/bot/proc/get_next_patrol_target() - // search the beacon list for the next target in the list. + // Search the beacon list for the next target in the list. for(var/obj/machinery/navbeacon/NB in GLOB.navbeacons["[z]"]) - if(NB.location == next_destination) //Does the Beacon location text match the destination? - destination = new_destination //We now know the name of where we want to go. - patrol_target = NB.loc //Get its location and set it as the target. - next_destination = NB.codes["next_patrol"] //Also get the name of the next beacon in line. - return 1 + if(NB.location == next_destination) // Does the Beacon location text match the destination? + destination = new_destination // We now know the name of where we want to go. + patrol_target = NB.loc // Get its location and set it as the target. + next_destination = NB.codes["next_patrol"] // Also get the name of the next beacon in line. + return TRUE /mob/living/simple_animal/bot/proc/find_nearest_beacon() for(var/obj/machinery/navbeacon/NB in GLOB.navbeacons["[z]"]) @@ -786,17 +826,17 @@ Pass a positive integer as an argument to override a bot's default speed. if(!on) return FALSE - // check to see if we are the commanded bot - if(emagged || remote_disabled || hijacked) //Emagged bots do not respect anyone's authority! Bots with their remote controls off cannot get commands. + // Check to see if we are the commanded bot + if(emagged || remote_disabled || hijacked) // Emagged bots do not respect anyone's authority! Bots with their remote controls off cannot get commands. return FALSE if(client) bot_control_message(command, user, params["target"] ? params["target"] : "Unknown") - // process control input + // Process control input switch(command) if("stop") - bot_reset() //HOLD IT!! + bot_reset() // HOLD IT!! auto_patrol = FALSE if("go") @@ -808,7 +848,7 @@ Pass a positive integer as an argument to override a bot's default speed. summon_target = params["target"] // Location of the user if(length(user_access)) - access_card.access = user_access + prev_access //Adds the user's access, if any. + access_card.access = user_access + prev_access // Adds the user's access, if any. mode = BOT_SUMMON calc_summon_path() @@ -817,11 +857,11 @@ Pass a positive integer as an argument to override a bot's default speed. return TRUE -/mob/living/simple_animal/bot/proc/bot_summon() // summoned to PDA +/mob/living/simple_animal/bot/proc/bot_summon() // Summoned to PDA summon_step() -// calculates a path to the current destination -// given an optional turf to avoid +// Calculates a path to the current destination +// Given an optional turf to avoid /mob/living/simple_animal/bot/proc/calc_path(turf/avoid) check_bot_access() set_path(get_path_to(src, patrol_target, 120, id=access_card, exclude=avoid)) @@ -830,7 +870,7 @@ Pass a positive integer as an argument to override a bot's default speed. set waitfor = FALSE check_bot_access() set_path(get_path_to(src, summon_target, 150, id=access_card, exclude=avoid)) - if(!length(path)) //Cannot reach target. Give up and announce the issue. + if(!length(path)) // Cannot reach target. Give up and announce the issue. speak("Summon command failed, destination unreachable.",radio_channel) bot_reset() @@ -854,7 +894,7 @@ Pass a positive integer as an argument to override a bot's default speed. addtimer(CALLBACK(src, PROC_REF(try_calc_path)), 2) - else // no path, so calculate new one + else // No path, so calculate new one calc_summon_path() /mob/living/simple_animal/bot/proc/try_calc_path() @@ -886,22 +926,22 @@ Pass a positive integer as an argument to override a bot's default speed. return "PROTOBOT - NOT FOR USE" /mob/living/simple_animal/bot/proc/allowed(mob/M) - var/acc = M.get_access() //see mob.dm + var/acc = M.get_access() // See mob.dm if(acc == IGNORE_ACCESS || M.can_admin_interact()) - return TRUE //Mob ignores access + return TRUE // Mob ignores access return has_access(list(), req_access, acc) /mob/living/simple_animal/bot/Topic(href, href_list) - if(href_list["close"])// HUE HUE + if(href_list["close"]) // HUE HUE if(usr in users) users.Remove(usr) - return 1 + return TRUE if(topic_denied(usr)) to_chat(usr, "[src]'s interface is not responding!") - return 1 + return TRUE add_fingerprint(usr) if((href_list["power"]) && (allowed(usr) || !locked || usr.can_admin_interact())) @@ -927,7 +967,7 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/proc/canhack(mob/M) return ((issilicon(M) && (!emagged || hacked)) || M.can_admin_interact()) -/mob/living/simple_animal/bot/proc/handle_hacking(mob/M) // refactored out of Topic/ to allow re-use by TGUIs +/mob/living/simple_animal/bot/proc/handle_hacking(mob/M) // Refactored out of Topic/ to allow re-use by TGUIs if(!canhack(M)) return if(!emagged) @@ -951,15 +991,15 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/update_icon_state() icon_state = "[initial(icon_state)][on]" -/mob/living/simple_animal/bot/proc/topic_denied(mob/user) //Access check proc for bot topics! Remember to place in a bot's individual Topic if desired. +/mob/living/simple_animal/bot/proc/topic_denied(mob/user) // Access check proc for bot topics! Remember to place in a bot's individual Topic if desired. if(user.can_admin_interact()) return FALSE if(user.incapacitated() || !(issilicon(user) || in_range(src, user))) return TRUE - if(emagged) //An emagged bot cannot be controlled by humans, silicons can if one hacked it. - if(!hacked) //Manually emagged by a human - access denied to all. + if(emagged) // An emagged bot cannot be controlled by humans, silicons can if one hacked it. + if(!hacked) // Manually emagged by a human - access denied to all. return TRUE - else if(!(issilicon(user) || ispulsedemon(user))) //Bot is hacked, so only silicons are allowed access. + else if(!(issilicon(user) || ispulsedemon(user))) // Bot is hacked, so only silicons are allowed access. return TRUE if(hijacked && !ispulsedemon(user)) return FALSE @@ -969,10 +1009,10 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/proc/hack(mob/user) var/hack - if(issilicon(user) || user.can_admin_interact()) //Allows silicons or admins to toggle the emag status of a bot. + if(issilicon(user) || user.can_admin_interact()) // Allows silicons or admins to toggle the emag status of a bot. hack += "[emagged ? "Software compromised! Unit may exhibit dangerous or erratic behavior." : "Unit operating normally. Release safety lock?"]
" hack += "Harm Prevention Safety System: [emagged ? "DANGER" : "Engaged"]
" - else if(!locked) //Humans with access can use this option to hide a bot from the AI's remote control panel and PDA control. + else if(!locked) // Humans with access can use this option to hide a bot from the AI's remote control panel and PDA control. hack += "Remote network control radio: [remote_disabled ? "Disconnected" : "Connected"]
" return hack @@ -1095,7 +1135,7 @@ Pass a positive integer as an argument to override a bot's default speed. used_radios += Radio /mob/living/simple_animal/bot/is_mechanical() - return 1 + return TRUE /mob/living/simple_animal/bot/proc/set_path(list/newpath) path = newpath ? newpath : list() @@ -1112,13 +1152,13 @@ Pass a positive integer as an argument to override a bot's default speed. // Common data shared among all the bots, used by BotStatus.js /mob/living/simple_animal/bot/ui_data(mob/user) var/list/data = list() - data["locked"] = locked // controls, locked or not - data["noaccess"] = topic_denied(user) // does the current user have access? admins, silicons etc can still access bots with locked controls + data["locked"] = locked // Controls, locked or not + data["noaccess"] = topic_denied(user) // Does the current user have access? admins, silicons etc can still access bots with locked controls data["maintpanel"] = open data["on"] = on data["autopatrol"] = auto_patrol data["painame"] = paicard ? paicard.pai.name : null data["canhack"] = canhack(user) - data["emagged"] = emagged // this is an int, NOT a boolean + data["emagged"] = emagged data["remote_disabled"] = remote_disabled return data diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index cba5965884b..10090833b57 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -124,7 +124,7 @@ audible_message("[src] makes an excited beeping booping sound!") if(!target) //Search for cleanables it can see. - target = scan(/obj/effect/decal/cleanable, avoid_bot = /mob/living/simple_animal/bot/cleanbot) + target = scan(/obj/effect/decal/cleanable, avoid_bot = TRUE) if(!target && auto_patrol) //Search for cleanables it can see. if(mode == BOT_IDLE || mode == BOT_START_PATROL) @@ -143,12 +143,14 @@ //Try to produce a path to the target, and ignore airlocks to which it has access. path = get_path_to(src, target, 30, id=access_card) if(!bot_move(target)) + ignore_job -= target.UID() add_to_ignore(target) target = null path = list() return mode = BOT_MOVING else if(!bot_move(target)) + ignore_job -= target.UID() target = null mode = BOT_IDLE return @@ -164,6 +166,7 @@ /mob/living/simple_animal/bot/cleanbot/proc/do_clean(obj/effect/decal/cleanable/target) if(mode == BOT_CLEANING) + ignore_job -= target.UID() QDEL_NULL(target) anchored = FALSE mode = BOT_IDLE diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index bfbbcc18702..a8e7e3d0653 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -1,4 +1,4 @@ -//Floorbot +// Floorbot /mob/living/simple_animal/bot/floorbot name = "\improper Floorbot" desc = "A little floor repairing robot, he looks so excited!" @@ -167,37 +167,37 @@ if(prob(5)) audible_message("[src] makes an excited booping beeping sound!") - //Normal scanning procedure. We have tiles loaded, are not emagged. + // Normal scanning procedure. We have tiles loaded, are not emagged. if(!target && !emagged && amount) if(!target) - process_type = HULL_BREACH //Ensures the floorbot does not try to "fix" space areas or shuttle docking zones. - target = scan(/turf/space, avoid_bot = /mob/living/simple_animal/bot/floorbot) + process_type = HULL_BREACH // Ensures the floorbot does not try to "fix" space areas or shuttle docking zones. + target = scan(/turf/space, avoid_bot = TRUE) - if(!target && replace_tiles) //Finds a floor without a tile and gives it one. - process_type = REPLACE_TILE //The target must be the floor and not a tile. The floor must not already have a floortile. - target = scan(/turf/simulated/floor, avoid_bot = /mob/living/simple_animal/bot/floorbot) - - if(!target && fix_floor) //Repairs damaged floors and tiles. + if(!target && fix_floor) // Repairs damaged floors and tiles. process_type = FIX_TILE - target = scan(/turf/simulated/floor, avoid_bot = /mob/living/simple_animal/bot/floorbot) + target = scan(/turf/simulated/floor, avoid_bot = TRUE) - if(!target && emagged) //We are emagged! Time to rip up the floors! + if(!target && replace_tiles) // Finds a floor without a tile and gives it one. + process_type = REPLACE_TILE // The target must be the floor and not a tile. The floor must not already have a floortile. + target = scan(/turf/simulated/floor/plating, avoid_bot = TRUE) + + if(!target && emagged) // We are emagged! Time to rip up the floors! process_type = TILE_EMAG - target = scan(/turf/simulated/floor, avoid_bot = /mob/living/simple_animal/bot/floorbot) + target = scan(/turf/simulated/floor, avoid_bot = TRUE) - if(amount < MAX_AMOUNT && !target) //Out of tiles! We must refill! - if(eat_tiles) //Configured to find and consume floortiles! + if(amount < MAX_AMOUNT && !target) // Out of tiles! We must refill! + + if(!target && eat_tiles) // Configured to find and consume floortiles! process_type = null target = scan(/obj/item/stack/tile/plasteel) - if(!target && make_tiles) //We did not manage to find any floor tiles! Scan for metal stacks and make our own! + if(!target && make_tiles) // We did not manage to find any floor tiles! Scan for metal stacks and make our own! process_type = null target = scan(/obj/item/stack/sheet/metal) - if(!target && nag_on_empty) //Floorbot is empty and cannot acquire more tiles, nag the engineers for more! + if(!target && nag_on_empty) // Floorbot is empty and cannot acquire more tiles, nag the engineers for more! nag() - if(!target) if(auto_patrol) @@ -211,10 +211,10 @@ if(loc == target || loc == target.loc) if(istype(target, /obj/item/stack/tile/plasteel)) - start_eattile(target) + start_eat_tile(target) if(istype(target, /obj/item/stack/sheet/metal)) - start_maketile(target) + start_make_tile(target) if(isturf(target) && !emagged) repair(target) @@ -232,7 +232,7 @@ path = list() return - if(!length(path)) + if(!length(path)) // No path, need a new one if(!isturf(target)) var/turf/TL = get_turf(target) path = get_path_to(src, TL, 30, id = access_card, simulated_only = 0) @@ -241,10 +241,12 @@ if(!bot_move(target)) add_to_ignore(target) + ignore_job -= target.UID() target = null mode = BOT_IDLE return else if(!bot_move(target)) + ignore_job -= target.UID() target = null mode = BOT_IDLE return @@ -255,45 +257,50 @@ amount ++ anchored = FALSE mode = BOT_IDLE + ignore_job -= target.UID() target = null -/mob/living/simple_animal/bot/floorbot/proc/nag() //Annoy everyone on the channel to refill us! +/mob/living/simple_animal/bot/floorbot/proc/nag() // Annoy everyone on the channel to refill us! if(!nagged) speak("Requesting refill [MAX_AMOUNT - amount] at [get_area(src)]!", radio_channel) nagged = TRUE -/mob/living/simple_animal/bot/floorbot/proc/is_hull_breach(turf/t) //Ignore space tiles not considered part of a structure, also ignores shuttle docking areas. +/mob/living/simple_animal/bot/floorbot/proc/is_hull_breach(turf/t) // Ignore space tiles not considered part of a structure, also ignores shuttle docking areas. return !istype(get_area(t), /area/space) -//Floorbots, having several functions, need sort out special conditions here. +// Floorbots, having several functions, need sort out special conditions here. /mob/living/simple_animal/bot/floorbot/process_scan(atom/scan_target) var/result var/turf/simulated/floor/F switch(process_type) - if(HULL_BREACH) //The most common job, patching breaches in the station's hull. - if(is_hull_breach(scan_target)) //Ensure that the targeted space turf is actually part of the station, and not random space. + if(HULL_BREACH) // The most common job, patching breaches in the station's hull. + if(is_hull_breach(scan_target)) // Ensure that the targeted space turf is actually part of the station, and not random space. result = scan_target - anchored = TRUE //Prevent the floorbot being blown off-course while trying to reach a hull breach. + anchored = TRUE // Prevent the floorbot being blown off-course while trying to reach a hull breach. if(REPLACE_TILE) F = scan_target - if(istype(F, /turf/simulated/floor/plating)) //The floor must not already have a tile. + if(istype(F, /turf/simulated/floor/plating)) // The floor must not already have a tile. + if(locate(/obj/structure/window) in get_turf(F)) // Targeting plating under window + add_to_ignore(scan_target) + return FALSE result = F - if(FIX_TILE) //Selects only damaged floors. + if(FIX_TILE) // Selects only damaged floors. F = scan_target if(istype(F) && (F.broken || F.burnt)) result = F - if(TILE_EMAG) //Emag mode! Rip up the floor and cause breaches to space! + if(TILE_EMAG) // Emag mode! Rip up the floor and cause breaches to space! F = scan_target if(!istype(F, /turf/simulated/floor/plating)) result = F - else //If no special processing is needed, simply return the result. + else // If no special processing is needed, simply return the result. result = scan_target return result /mob/living/simple_animal/bot/floorbot/proc/repair(turf/target_turf) if(isspaceturf(target_turf)) - //Must be a hull breach to continue. + // Must be a hull breach to continue. if(!is_hull_breach(target_turf)) + ignore_job -= target.UID() target = null return @@ -302,12 +309,13 @@ if(amount <= 0) mode = BOT_IDLE + ignore_job -= target.UID() target = null return anchored = TRUE - if(isspaceturf(target_turf)) //If we are fixing an area not part of pure space, it is + if(isspaceturf(target_turf)) // If we are fixing an area not part of pure space, it is visible_message("[src] begins to repair the hole.") mode = BOT_REPAIRING update_icon(UPDATE_OVERLAYS) @@ -326,6 +334,8 @@ if(mode != BOT_REPAIRING) return + ignore_job -= target_turf.UID() // If called after the tile fix, turf changes and the UID with it + if(autotile || replace_tiles) if(process_type != HULL_BREACH) F.break_tile_to_plating() @@ -339,15 +349,16 @@ anchored = FALSE target = null -/mob/living/simple_animal/bot/floorbot/proc/start_eattile(obj/item/stack/tile/plasteel/T) +/mob/living/simple_animal/bot/floorbot/proc/start_eat_tile(obj/item/stack/tile/plasteel/T) if(!istype(T, /obj/item/stack/tile/plasteel)) return + anchored = TRUE visible_message("[src] begins to collect tiles.") mode = BOT_EAT_TILE update_icon(UPDATE_OVERLAYS) - addtimer(CALLBACK(src, PROC_REF(do_eattile), T), 2 SECONDS) + addtimer(CALLBACK(src, PROC_REF(do_eat_tile), T), 2 SECONDS) -/mob/living/simple_animal/bot/floorbot/proc/do_eattile(obj/item/stack/tile/plasteel/T) +/mob/living/simple_animal/bot/floorbot/proc/do_eat_tile(obj/item/stack/tile/plasteel/T) if(isnull(T)) target = null mode = BOT_IDLE @@ -359,30 +370,39 @@ else amount += T.amount qdel(T) + anchored = FALSE target = null mode = BOT_IDLE update_icon(UPDATE_OVERLAYS) -/mob/living/simple_animal/bot/floorbot/proc/start_maketile(obj/item/stack/sheet/metal/M) +/mob/living/simple_animal/bot/floorbot/proc/start_make_tile(obj/item/stack/sheet/metal/M) if(!istype(M, /obj/item/stack/sheet/metal)) return + anchored = TRUE visible_message("[src] begins to create tiles.") mode = BOT_MAKE_TILE update_icon(UPDATE_OVERLAYS) - addtimer(CALLBACK(src, PROC_REF(do_maketile), M), 2 SECONDS) + addtimer(CALLBACK(src, PROC_REF(do_make_tile), M), 2 SECONDS) -/mob/living/simple_animal/bot/floorbot/proc/do_maketile(obj/item/stack/sheet/metal/M) +/mob/living/simple_animal/bot/floorbot/proc/do_make_tile(obj/item/stack/sheet/metal/M) if(isnull(M)) target = null mode = BOT_IDLE return - var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel - T.amount = 4 - T.forceMove(M.loc) + + if((amount + 4) > MAX_AMOUNT) // 1 metal = 4 tiles, hence + 4 + var/missing_amount = MAX_AMOUNT - amount + var/extra = amount + 4 - MAX_AMOUNT + amount += missing_amount + new /obj/item/stack/tile/plasteel(get_turf(src), extra) + else + amount += 4 + if(M.amount > 1) - M.amount-- + M.amount -- else qdel(M) + anchored = FALSE target = null mode = BOT_IDLE update_icon(UPDATE_OVERLAYS) @@ -408,7 +428,7 @@ if(prob(50)) drop_part(robot_arm, Tsec) - while(amount)//Dumps the tiles into the appropriate sized stacks + while(amount)// Dumps the tiles into the appropriate sized stacks if(amount >= 16) var/obj/item/stack/tile/plasteel/T = new (Tsec) T.amount = 16 @@ -425,9 +445,9 @@ if(isturf(A)) repair(A) else if(istype(A,/obj/item/stack/tile/plasteel)) - start_eattile(A) + start_eat_tile(A) else if(istype(A,/obj/item/stack/sheet/metal)) - start_maketile(A) + start_make_tile(A) else ..()