From 2793a1c7f4329117197de2012d8fc0adbdf3b36a Mon Sep 17 00:00:00 2001 From: Kapu1178 <75460809+Kapu1178@users.noreply.github.com> Date: Tue, 11 Feb 2025 15:20:42 -0500 Subject: [PATCH] Medbot code cleanup + extras (#27749) * mode = -> set_mode * medbot_phrase() * medbot cleanup * code cleanup * forgot this! * your linter is gay * oops * Update code/modules/mob/living/simple_animal/bot/medbot.dm Co-authored-by: chuga-git <98280110+chuga-git@users.noreply.github.com> Signed-off-by: Kapu1178 <75460809+Kapu1178@users.noreply.github.com> * Update code/modules/mob/living/simple_animal/bot/medbot.dm Co-authored-by: chuga-git <98280110+chuga-git@users.noreply.github.com> Signed-off-by: Kapu1178 <75460809+Kapu1178@users.noreply.github.com> * Update code/modules/mob/living/simple_animal/bot/bot.dm Co-authored-by: chuga-git <98280110+chuga-git@users.noreply.github.com> Signed-off-by: Kapu1178 <75460809+Kapu1178@users.noreply.github.com> * Update code/modules/mob/living/simple_animal/bot/medbot.dm Co-authored-by: warriorstar-orion Signed-off-by: Kapu1178 <75460809+Kapu1178@users.noreply.github.com> * Update code/modules/mob/living/simple_animal/bot/medbot.dm Co-authored-by: warriorstar-orion Signed-off-by: Kapu1178 <75460809+Kapu1178@users.noreply.github.com> * fix medbots getting deadlocked * Update code/modules/mob/living/simple_animal/bot/bot.dm Co-authored-by: Charlie Nolan Signed-off-by: Kapu1178 <75460809+Kapu1178@users.noreply.github.com> --------- Signed-off-by: Kapu1178 <75460809+Kapu1178@users.noreply.github.com> Co-authored-by: chuga-git <98280110+chuga-git@users.noreply.github.com> Co-authored-by: warriorstar-orion Co-authored-by: Charlie Nolan --- code/__DEFINES/bots.dm | 22 ++ code/game/data_huds.dm | 2 +- .../mob/living/simple_animal/bot/bot.dm | 164 ++++++++------ .../mob/living/simple_animal/bot/cleanbot.dm | 15 +- .../mob/living/simple_animal/bot/ed209bot.dm | 24 +- .../mob/living/simple_animal/bot/floorbot.dm | 30 +-- .../mob/living/simple_animal/bot/griefsky.dm | 4 +- .../mob/living/simple_animal/bot/honkbot.dm | 18 +- .../mob/living/simple_animal/bot/medbot.dm | 209 +++++++++++------- .../mob/living/simple_animal/bot/mulebot.dm | 32 +-- .../mob/living/simple_animal/bot/secbot.dm | 18 +- .../simple_animal/bot/syndicate_bots.dm | 6 +- sound/voice/mfuck_you.ogg | Bin 0 -> 11422 bytes 13 files changed, 315 insertions(+), 229 deletions(-) create mode 100644 sound/voice/mfuck_you.ogg diff --git a/code/__DEFINES/bots.dm b/code/__DEFINES/bots.dm index ff3712ed9c0..9e77ad7779c 100644 --- a/code/__DEFINES/bots.dm +++ b/code/__DEFINES/bots.dm @@ -26,6 +26,7 @@ #define BOT_NO_ROUTE 17 // no destination beacon found (or no route) #define BOT_MAKE_TILE 18 // converting metal into tiles (floorbots) #define BOT_EAT_TILE 19 // adding said tiles to inventory (floorbots) +#define BOT_PATHING 20 // Actively pathfinding. //Bot types #define SEC_BOT "Security" // Secutritrons (Beepsky) and ED-209s @@ -42,3 +43,24 @@ #define SENTIENCE_OTHER 3 #define SENTIENCE_MINEBOT 4 #define SENTIENCE_BOSS 5 + +// Medbot voice keys +#define MEDIBOT_VOICED_HOLD_ON "Hey, %TARGET%! Hold on, I'm coming." +#define MEDIBOT_VOICED_WANT_TO_HELP "Wait, %TARGET%! I want to help!" +#define MEDIBOT_VOICED_YOU_ARE_INJURED "%TARGET%, you appear to be injured!" + +#define MEDIBOT_VOICED_ALL_PATCHED_UP "All patched up!" +#define MEDIBOT_VOICED_APPLE_A_DAY "An apple a day keeps me away." +#define MEDIBOT_VOICED_FEEL_BETTER "Feel better soon!" + +#define MEDIBOT_VOICED_STAY_WITH_ME "No! Stay with me!" +#define MEDIBOT_VOICED_LIVE "Live, damnit! LIVE!" +#define MEDIBOT_VOICED_NEVER_LOST "I...I've never lost a patient before. Not today, I mean." + +#define MEDIBOT_VOICED_DELICIOUS "Delicious!" +#define MEDIBOT_VOICED_PLASTIC_SURGEON "I knew it, I should've been a plastic surgeon." +#define MEDIBOT_VOICED_MASK_ON "Radar, put a mask on!" +#define MEDIBOT_VOICED_ALWAYS_A_CATCH "There's always a catch, and I'm the best there is." +#define MEDIBOT_VOICED_LIKE_FLIES "What kind of medbay is this? Everyone's dropping like flies." + +#define MEDIBOT_VOICED_FUCK_YOU "Fuck you." diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 83704a83585..79931aced4b 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -407,7 +407,7 @@ holder.icon_state = "hudpatrol" if(BOT_PREP_ARREST, BOT_ARREST, BOT_HUNT, BOT_BLOCKED, BOT_NO_ROUTE) //STOP RIGHT THERE, CRIMINAL SCUM! holder.icon_state = "hudalert" - if(BOT_MOVING, BOT_DELIVER, BOT_GO_HOME, BOT_NAV, BOT_WAIT_FOR_NAV) //Moving to target for normal bots, moving to deliver or go home for MULES. + if(BOT_MOVING, BOT_PATHING, BOT_DELIVER, BOT_GO_HOME, BOT_NAV, BOT_WAIT_FOR_NAV) //Moving to target for normal bots, moving to deliver or go home for MULES. holder.icon_state = "hudmove" else holder.icon_state = "" diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 18541c78ab8..dfe5e10570b 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -143,6 +143,58 @@ /// Will be true if we lost target we were chasing var/lost_target = FALSE + /// Cooldown for when to cleanup the ignore list. + COOLDOWN_DECLARE(ignore_list_cleanup_cd) + +/mob/living/simple_animal/bot/Initialize(mapload) + . = ..() + GLOB.bots_list += src + 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. + access_card.access += ACCESS_ROBOTICS + set_custom_texts() + Radio = new/obj/item/radio/headset/bot(src) + Radio.follow_target = src + add_language("Galactic Common", 1) + add_language("Sol Common", 1) + add_language("Tradeband", 1) + add_language("Gutter", 1) + add_language("Trinary", 1) + default_language = GLOB.all_languages["Galactic Common"] + + prepare_huds() + for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) + diag_hud.add_to_hud(src) + permanent_huds |= diag_hud + + diag_hud_set_bothealth() + diag_hud_set_botstat() + diag_hud_set_botmode() + + REMOVE_TRAIT(src, TRAIT_CAN_STRIP, TRAIT_GENERIC) + +/mob/living/simple_animal/bot/Destroy() + if(paicard) + ejectpai() + set_path(null) + + var/datum/atom_hud/data_hud = GLOB.huds[data_hud_type] + if(data_hud) + data_hud.remove_hud_from(src) + + GLOB.bots_list -= src + QDEL_NULL(path) + QDEL_NULL(Radio) + QDEL_NULL(access_card) + + if(reset_access_timer_id) + deltimer(reset_access_timer_id) + reset_access_timer_id = null + + ignore_list = null + return ..() /obj/item/radio/headset/bot requires_tcomms = FALSE @@ -188,6 +240,10 @@ bot_move(last_target_location, move_speed = 6) frustration++ +/// Setter for mode, so it's all tracable to one place. +/mob/living/simple_animal/bot/proc/set_mode(new_mode) + mode = new_mode + /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(paicard) @@ -224,62 +280,12 @@ update_icon() update_controls() -/mob/living/simple_animal/bot/Initialize(mapload) - . = ..() - GLOB.bots_list += src - 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. - access_card.access += ACCESS_ROBOTICS - set_custom_texts() - Radio = new/obj/item/radio/headset/bot(src) - Radio.follow_target = src - add_language("Galactic Common", 1) - add_language("Sol Common", 1) - add_language("Tradeband", 1) - add_language("Gutter", 1) - add_language("Trinary", 1) - default_language = GLOB.all_languages["Galactic Common"] - - prepare_huds() - for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) - diag_hud.add_to_hud(src) - permanent_huds |= diag_hud - - diag_hud_set_bothealth() - diag_hud_set_botstat() - diag_hud_set_botmode() - - REMOVE_TRAIT(src, TRAIT_CAN_STRIP, TRAIT_GENERIC) - /mob/living/simple_animal/bot/med_hud_set_health() return // We use a different hud /mob/living/simple_animal/bot/med_hud_set_status() return // We use a different hud - -/mob/living/simple_animal/bot/Destroy() - if(paicard) - ejectpai() - set_path(null) - - var/datum/atom_hud/data_hud = GLOB.huds[data_hud_type] - if(data_hud) - data_hud.remove_hud_from(src) - - GLOB.bots_list -= src - QDEL_NULL(path) - QDEL_NULL(Radio) - QDEL_NULL(access_card) - - if(reset_access_timer_id) - deltimer(reset_access_timer_id) - reset_access_timer_id = null - - return ..() - /mob/living/simple_animal/bot/mob_negates_gravity() return anchored @@ -333,17 +339,35 @@ ..(reason) diag_hud_set_bothealth() +/// Add an atom to our list of ignored objects. +/mob/living/simple_animal/bot/proc/add_to_ignore(atom/subject) + if(isnull(subject) || (subject in ignore_list)) + return + + if(length(ignore_list) >= 50) + remove_ignored_atom(ignore_list[1]) + + ignore_list += subject + RegisterSignal(subject, COMSIG_PARENT_QDELETING, PROC_REF(remove_ignored_atom)) + +/// Remove an atom from the ignore list. +/mob/living/simple_animal/bot/proc/remove_ignored_atom(datum/source) + SIGNAL_HANDLER + + UnregisterSignal(source, COMSIG_PARENT_QDELETING) + ignore_list -= source + +/// Wipe the ignore list. +/mob/living/simple_animal/bot/proc/clear_ignore_list() + for(var/atom/A as anything in ignore_list) + remove_ignored_atom(A) + /mob/living/simple_animal/bot/handle_automated_action() diag_hud_set_botmode() - 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/referred_atom = locateUID(uid) - if(!referred_atom || QDELETED(referred_atom)) - ignore_list -= uid - ignore_list_cleanup_timer = 0 - else - ignore_list_cleanup_timer++ + if(COOLDOWN_FINISHED(src, ignore_list_cleanup_cd)) + clear_ignore_list() + COOLDOWN_START(src, ignore_list_cleanup_cd, 20 SECONDS) if(!on) return @@ -358,6 +382,8 @@ if(BOT_SUMMON) // Called by PDA bot_summon() return + if(BOT_PATHING) + return FALSE 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) @@ -574,7 +600,7 @@ Pass the desired type path itself, declaring a temporary var beforehand is not r 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 + if((A in ignore_list) || (A == old_target)) // Filter for blacklisted elements, usually unreachable or previously processed ones continue var/scan_result = process_scan(A) // Some bots may require additional processing when a result is selected. if(!scan_result) @@ -600,12 +626,6 @@ Pass the desired type path itself, declaring a temporary var beforehand is not r /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(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. @@ -671,7 +691,7 @@ Pass a positive integer as an argument to override a bot's default speed. if(message) to_chat(calling_ai, "[bicon(src)] [name] called to [end_area.name]. [length(path)-1] meters to destination.") pathset = TRUE - mode = BOT_RESPONDING + set_mode(BOT_RESPONDING) tries = 0 else if(message) @@ -706,7 +726,7 @@ Pass a positive integer as an argument to override a bot's default speed. pathset = FALSE access_card.access = prev_access tries = 0 - mode = BOT_IDLE + set_mode(BOT_IDLE) diag_hud_set_botstat() diag_hud_set_botmode() @@ -734,7 +754,7 @@ Pass a positive integer as an argument to override a bot's default speed. return if(!auto_patrol) // A bot not set to patrol should not be patrolling. - mode = BOT_IDLE + set_mode(BOT_IDLE) return @@ -750,7 +770,7 @@ Pass a positive integer as an argument to override a bot's default speed. if(!length(path)) patrol_target = null return - mode = BOT_PATROL + set_mode(BOT_PATROL) // Perform a single patrol step @@ -776,7 +796,7 @@ Pass a positive integer as an argument to override a bot's default speed. addtimer(CALLBACK(src, PROC_REF(patrol_step_not_moved)), 2) else // No path, so calculate new one - mode = BOT_START_PATROL + set_mode(BOT_START_PATROL) /mob/living/simple_animal/bot/proc/patrol_step_not_moved() calc_path() @@ -794,7 +814,7 @@ Pass a positive integer as an argument to override a bot's default speed. destination = next_destination else auto_patrol = FALSE - mode = BOT_IDLE + set_mode(BOT_IDLE) speak("Disengaging patrol mode.") /mob/living/simple_animal/bot/proc/get_next_patrol_target() @@ -868,7 +888,7 @@ Pass a positive integer as an argument to override a bot's default speed. if(length(user_access)) access_card.access = user_access + prev_access // Adds the user's access, if any. - mode = BOT_SUMMON + set_mode(BOT_SUMMON) calc_summon_path() speak("Responding.", radio_channel) diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index f9ed81612f1..697b726d359 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -77,7 +77,7 @@ /mob/living/simple_animal/bot/cleanbot/bot_reset() ..() - ignore_list.Cut() //Allows the bot to clean targets it previously ignored due to being unreachable. + clear_ignore_list() target = null oldloc = null area_locked = null @@ -155,8 +155,8 @@ target = null if(target) - if(!path || !length(path)) //No path, need a new one - //Try to produce a path to the target, and ignore airlocks to which it has access. + if(!length(path)) //No path, need a new one + set_mode(BOT_PATHING) path = get_path_to(src, target, 30, access = access_card.access) if(!bot_move(target)) ignore_job -= target.UID() @@ -164,11 +164,12 @@ target = null path = list() return - mode = BOT_MOVING + set_mode(BOT_MOVING) + else if(!bot_move(target)) ignore_job -= target.UID() target = null - mode = BOT_IDLE + set_mode(BOT_IDLE) return oldloc = loc @@ -184,7 +185,7 @@ /mob/living/simple_animal/bot/cleanbot/proc/start_clean(obj/effect/decal/cleanable/target) anchored = TRUE visible_message("[src] begins to clean up [target]") - mode = BOT_CLEANING + set_mode(BOT_CLEANING) update_icon(UPDATE_OVERLAYS) addtimer(CALLBACK(src, PROC_REF(do_clean), target), 5 SECONDS) @@ -193,7 +194,7 @@ ignore_job -= target.UID() QDEL_NULL(target) anchored = FALSE - mode = BOT_IDLE + set_mode(BOT_IDLE) update_icon(UPDATE_OVERLAYS) /mob/living/simple_animal/bot/cleanbot/explode() diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index e3a63cf9dd9..a92dc4b75ec 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -85,7 +85,7 @@ /mob/living/simple_animal/bot/ed209/turn_on() . = ..() icon_state = "[lasercolor]ed209[on]" - mode = BOT_IDLE + set_mode(BOT_IDLE) /mob/living/simple_animal/bot/ed209/turn_off() ..() @@ -177,7 +177,7 @@ threatlevel += 6 if(threatlevel >= 4) target = H - mode = BOT_HUNT + set_mode(BOT_HUNT) /mob/living/simple_animal/bot/ed209/attack_hand(mob/living/carbon/human/H) if(H.a_intent == INTENT_HARM) @@ -266,7 +266,7 @@ if(find_new_target()) return // see if any criminals are in range if(!mode && auto_patrol) // still idle, and set to patrol - mode = BOT_START_PATROL // switch to patrol mode + set_mode(BOT_START_PATROL) // switch to patrol mode if(BOT_HUNT) // hunting for perp // if can't reach perp for long enough, go idle @@ -287,11 +287,11 @@ if(Adjacent(target) && isturf(target.loc) && !baton_delayed) // if right next to perp stun_attack(target) if(!lasercolor) - mode = BOT_PREP_ARREST + set_mode(BOT_PREP_ARREST) anchored = TRUE target_lastloc = target.loc return - mode = BOT_HUNT + set_mode(BOT_HUNT) target = null target_lastloc = null return @@ -330,7 +330,7 @@ back_to_hunt() return - mode = BOT_PREP_ARREST + set_mode(BOT_PREP_ARREST) anchored = FALSE if(BOT_START_PATROL) @@ -348,7 +348,7 @@ /mob/living/simple_animal/bot/ed209/proc/back_to_idle() anchored = FALSE - mode = BOT_IDLE + set_mode(BOT_IDLE) target = null last_found = world.time frustration = 0 @@ -357,7 +357,7 @@ /mob/living/simple_animal/bot/ed209/proc/back_to_hunt() anchored = FALSE frustration = 0 - mode = BOT_HUNT + set_mode(BOT_HUNT) INVOKE_ASYNC(src, PROC_REF(handle_automated_action)) // look for a criminal in view of the bot @@ -384,7 +384,7 @@ speak("Level [threatlevel] infraction alert!") playsound(loc, pick('sound/voice/ed209_20sec.ogg', 'sound/voice/edplaceholder.ogg'), 50, FALSE) visible_message("[src] points at [C.name]!") - mode = BOT_HUNT + set_mode(BOT_HUNT) INVOKE_ASYNC(src, PROC_REF(handle_automated_action)) return TRUE return FALSE @@ -482,7 +482,7 @@ ..() if(!isalien(target)) target = user - mode = BOT_HUNT + set_mode(BOT_HUNT) /mob/living/simple_animal/bot/ed209/emp_act(severity) @@ -519,7 +519,7 @@ var/mob/toarrest = pick(targets) if(toarrest) target = toarrest - mode = BOT_HUNT + set_mode(BOT_HUNT) /mob/living/simple_animal/bot/ed209/proc/unset_disabled() disabled = FALSE @@ -571,7 +571,7 @@ speak("[no_handcuffs ? "Detaining" : "Arresting"] level [threat] scumbag [C] in [location].", radio_channel) /mob/living/simple_animal/bot/ed209/proc/cuff(mob/living/carbon/C) - mode = BOT_ARREST + set_mode(BOT_ARREST) playsound(loc, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2) C.visible_message("[src] is trying to put zipties on [C]!",\ "[src] is trying to put zipties on you!") diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index 20b1ec93929..f4c1ae6edec 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -60,7 +60,7 @@ ..() target = null oldloc = null - ignore_list.Cut() + clear_ignore_list() nagged = 0 anchored = FALSE update_icon() @@ -222,7 +222,7 @@ if(emagged && isfloorturf(target)) var/turf/simulated/floor/F = target anchored = TRUE - mode = BOT_REPAIRING + set_mode(BOT_REPAIRING) if(prob(90)) F.break_tile_to_plating() else @@ -243,12 +243,12 @@ add_to_ignore(target) ignore_job -= target.UID() target = null - mode = BOT_IDLE + set_mode(BOT_IDLE) return else if(!bot_move(target)) ignore_job -= target.UID() target = null - mode = BOT_IDLE + set_mode(BOT_IDLE) return oldloc = loc @@ -256,7 +256,7 @@ /mob/living/simple_animal/bot/floorbot/proc/inc_amount_callback() amount ++ anchored = FALSE - mode = BOT_IDLE + set_mode(BOT_IDLE) ignore_job -= target.UID() target = null @@ -308,7 +308,7 @@ return if(amount <= 0) - mode = BOT_IDLE + set_mode(BOT_IDLE) ignore_job -= target.UID() target = null return @@ -317,13 +317,13 @@ 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 + set_mode(BOT_REPAIRING) update_icon(UPDATE_OVERLAYS) addtimer(CALLBACK(src, PROC_REF(make_bridge_plating), target_turf), 5 SECONDS) else var/turf/simulated/floor/F = target_turf - mode = BOT_REPAIRING + set_mode(BOT_REPAIRING) update_icon(UPDATE_OVERLAYS) visible_message("[src] begins repairing the floor.") addtimer(CALLBACK(src, PROC_REF(make_bridge_plating), F), 5 SECONDS) @@ -343,7 +343,7 @@ else target_turf.ChangeTurf(/turf/simulated/floor/plating) - mode = BOT_IDLE + set_mode(BOT_IDLE) amount-- update_icon(UPDATE_OVERLAYS) anchored = FALSE @@ -354,14 +354,14 @@ return anchored = TRUE visible_message("[src] begins to collect tiles.") - mode = BOT_EAT_TILE + set_mode(BOT_EAT_TILE) update_icon(UPDATE_OVERLAYS) addtimer(CALLBACK(src, PROC_REF(do_eat_tile), T), 2 SECONDS) /mob/living/simple_animal/bot/floorbot/proc/do_eat_tile(obj/item/stack/tile/plasteel/T) if(isnull(T)) target = null - mode = BOT_IDLE + set_mode(BOT_IDLE) return if((amount + T.amount) > MAX_AMOUNT) var/i = MAX_AMOUNT - amount @@ -372,7 +372,7 @@ qdel(T) anchored = FALSE target = null - mode = BOT_IDLE + set_mode(BOT_IDLE) update_icon(UPDATE_OVERLAYS) /mob/living/simple_animal/bot/floorbot/proc/start_make_tile(obj/item/stack/sheet/metal/M) @@ -380,14 +380,14 @@ return anchored = TRUE visible_message("[src] begins to create tiles.") - mode = BOT_MAKE_TILE + set_mode(BOT_MAKE_TILE) update_icon(UPDATE_OVERLAYS) addtimer(CALLBACK(src, PROC_REF(do_make_tile), M), 2 SECONDS) /mob/living/simple_animal/bot/floorbot/proc/do_make_tile(obj/item/stack/sheet/metal/M) if(isnull(M)) target = null - mode = BOT_IDLE + set_mode(BOT_IDLE) return if((amount + 4) > MAX_AMOUNT) // 1 metal = 4 tiles, hence + 4 @@ -404,7 +404,7 @@ qdel(M) anchored = FALSE target = null - mode = BOT_IDLE + set_mode(BOT_IDLE) update_icon(UPDATE_OVERLAYS) /mob/living/simple_animal/bot/floorbot/update_icon_state() diff --git a/code/modules/mob/living/simple_animal/bot/griefsky.dm b/code/modules/mob/living/simple_animal/bot/griefsky.dm index 380840b7e1c..515bd7eb59b 100644 --- a/code/modules/mob/living/simple_animal/bot/griefsky.dm +++ b/code/modules/mob/living/simple_animal/bot/griefsky.dm @@ -115,7 +115,7 @@ if(find_new_target()) return // see if any criminals are in range if(!mode && auto_patrol) // still idle, and set to patrol - mode = BOT_START_PATROL // switch to patrol mode + set_mode(BOT_START_PATROL) // switch to patrol mode if(BOT_HUNT) // hunting for perp icon_state = spin_icon playsound(loc,'sound/effects/spinsabre.ogg',50, TRUE,-1) @@ -176,7 +176,7 @@ visible_message("[src] ignites his energy swords!") icon_state = "griefsky-c" visible_message("[src] points at [C.name]!") - mode = BOT_HUNT + set_mode(BOT_HUNT) INVOKE_ASYNC(src, PROC_REF(handle_automated_action)) return TRUE return FALSE diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm index c3476bc8ff6..53d9435b9b7 100644 --- a/code/modules/mob/living/simple_animal/bot/honkbot.dm +++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm @@ -108,7 +108,7 @@ /mob/living/simple_animal/bot/honkbot/proc/retaliate(mob/living/carbon/human/H) threatlevel = 6 target = H - mode = BOT_HUNT + set_mode(BOT_HUNT) /mob/living/simple_animal/bot/honkbot/attack_hand(mob/living/carbon/human/H) if(H.a_intent == INTENT_HARM) @@ -209,20 +209,20 @@ addtimer(VARSET_CALLBACK(src, spam_flag, FALSE), cooldowntimehorn) /mob/living/simple_animal/bot/honkbot/proc/cuff_callback(mob/living/carbon/C) - mode = BOT_ARREST + set_mode(BOT_ARREST) sleep(1 SECONDS) playsound(loc, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2) C.visible_message("[src] is trying to put zipties on [C]!", "[src] is trying to put zipties on you!") if(!do_after(src, 6 SECONDS, target = C) || !on) - mode = BOT_IDLE + set_mode(BOT_IDLE) return if(!C.handcuffed) C.handcuffed = new /obj/item/restraints/handcuffs/twimsts(C) C.update_handcuffed() C.SetDeaf(0) playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/bcreep.ogg'), 50, FALSE) - mode = BOT_IDLE + set_mode(BOT_IDLE) /mob/living/simple_animal/bot/honkbot/proc/stun_attack(mob/living/carbon/C) // airhorn stun if(spam_flag) @@ -270,7 +270,7 @@ if(find_new_target()) return if(!mode && auto_patrol) - mode = BOT_START_PATROL + set_mode(BOT_START_PATROL) if(BOT_HUNT) // if can't reach perp for long enough, go idle if(frustration >= 5) //gives up easier than beepsky @@ -308,7 +308,7 @@ /mob/living/simple_animal/bot/honkbot/proc/back_to_idle() anchored = FALSE - mode = BOT_IDLE + set_mode(BOT_IDLE) target = null last_found = world.time frustration = 0 @@ -317,7 +317,7 @@ /mob/living/simple_animal/bot/honkbot/proc/back_to_hunt() anchored = FALSE frustration = 0 - mode = BOT_HUNT + set_mode(BOT_HUNT) INVOKE_ASYNC(src, PROC_REF(handle_automated_action)) // responds quickly /mob/living/simple_animal/bot/honkbot/proc/find_new_target() @@ -352,7 +352,7 @@ else speak("Honk!") visible_message("[src] starts chasing [C.name]!") - mode = BOT_HUNT + set_mode(BOT_HUNT) INVOKE_ASYNC(src, PROC_REF(handle_automated_action)) return TRUE return FALSE @@ -375,7 +375,7 @@ ..() if(!isalien(target)) target = user - mode = BOT_HUNT + set_mode(BOT_HUNT) /mob/living/simple_animal/bot/honkbot/proc/on_atom_entered(datum/source, atom/movable/entered) if(ismob(entered) && on) //only if its online diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm index 91d39972eeb..2124643b007 100644 --- a/code/modules/mob/living/simple_animal/bot/medbot.dm +++ b/code/modules/mob/living/simple_animal/bot/medbot.dm @@ -26,10 +26,45 @@ window_name = "Automatic Medical Unit v1.1" data_hud_type = DATA_HUD_MEDICAL_ADVANCED + var/list/idle_phrases = list( + MEDIBOT_VOICED_MASK_ON = 'sound/voice/mradar.ogg', + MEDIBOT_VOICED_ALWAYS_A_CATCH = 'sound/voice/mcatch.ogg', + MEDIBOT_VOICED_PLASTIC_SURGEON = 'sound/voice/msurgeon.ogg', + MEDIBOT_VOICED_LIKE_FLIES = 'sound/voice/mflies.ogg', + MEDIBOT_VOICED_DELICIOUS = 'sound/voice/mdelicious.ogg', + ) + + var/list/finish_healing_phrases = list( + MEDIBOT_VOICED_ALL_PATCHED_UP = 'sound/voice/mpatchedup.ogg', + MEDIBOT_VOICED_APPLE_A_DAY = 'sound/voice/mapple.ogg', + MEDIBOT_VOICED_FEEL_BETTER = 'sound/voice/mfeelbetter.ogg', + ) + + var/list/located_patient_phrases = list( + MEDIBOT_VOICED_HOLD_ON = 'sound/voice/mcoming.ogg', + MEDIBOT_VOICED_WANT_TO_HELP = 'sound/voice/mhelp.ogg', + MEDIBOT_VOICED_YOU_ARE_INJURED = 'sound/voice/minjured.ogg', + ) + + var/list/patient_died_phrases = list( + MEDIBOT_VOICED_STAY_WITH_ME = 'sound/voice/mno.ogg', + MEDIBOT_VOICED_LIVE = 'sound/voice/mlive.ogg', + MEDIBOT_VOICED_NEVER_LOST = 'sound/voice/mlost.ogg', + ) + + var/list/frustration_phrases = list( + MEDIBOT_VOICED_FUCK_YOU = 'sound/voice/mfuck_you.ogg', + ) + + /// The above lists joined into one, for one-place lookups + var/list/all_phrases + var/obj/item/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents. var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits. var/mob/living/carbon/patient = null - var/mob/living/carbon/oldpatient = null + /// UID of the previous patient. Used to avoid running selection checks on them if we failed to heal them. + var/previous_patient + var/oldloc = null var/last_found = 0 var/last_warning = 0 @@ -129,6 +164,8 @@ prev_access = access_card.access qdel(J) + all_phrases = idle_phrases + located_patient_phrases + finish_healing_phrases + patient_died_phrases + frustration_phrases + if(new_skin) skin = new_skin update_icon() @@ -136,17 +173,19 @@ /mob/living/simple_animal/bot/medbot/bot_reset() ..() patient = null - oldpatient = null + previous_patient = null oldloc = null last_found = world.time declare_cooldown = FALSE + frustration = 0 update_icon() /mob/living/simple_animal/bot/medbot/proc/soft_reset() //Allows the medibot to still actively perform its medical duties without being completely halted as a hard reset does. path = list() patient = null - mode = BOT_IDLE + set_mode(BOT_IDLE) last_found = world.time + frustration = 0 update_icon() /mob/living/simple_animal/bot/medbot/set_custom_texts() @@ -268,7 +307,7 @@ audible_message("[src] buzzes oddly!") flick("medibot_spark", src) if(user) - oldpatient = user + previous_patient = user.UID() /mob/living/simple_animal/bot/medbot/process_scan(mob/living/carbon/human/H) if(buckled) @@ -280,16 +319,13 @@ if(H.stat == DEAD) return - if((H == oldpatient) && (world.time < last_found + 200)) + if((H.UID() == previous_patient) && (world.time < last_found + 200)) return if(assess_patient(H)) last_found = world.time - if((last_newpatient_speak + 300) < world.time) //Don't spam these messages! - var/list/messagevoice = list("Hey, [H.name]! Hold on, I'm coming." = 'sound/voice/mcoming.ogg', "Wait [H.name]! I want to help!" = 'sound/voice/mhelp.ogg', "[H.name], you appear to be injured!" = 'sound/voice/minjured.ogg') - var/message = pick(messagevoice) - speak(message) - playsound(loc, messagevoice[message], 50, FALSE) + if((last_newpatient_speak + 30 SECONDS) < world.time) //Don't spam these messages! + medbot_phrase(pick(located_patient_phrases), H) last_newpatient_speak = world.time return H else @@ -299,57 +335,57 @@ if(!..()) return - if(mode == BOT_HEALING) - return + switch(mode) + if(BOT_HEALING) + return - if(frustration > 8) - oldpatient = patient + if(frustration > 5) + previous_patient = patient.UID() soft_reset() + medbot_phrase(MEDIBOT_VOICED_FUCK_YOU) if(!patient) if(!shut_up && prob(1)) - var/list/messagevoice = list("Radar, put a mask on!" = 'sound/voice/mradar.ogg', "There's always a catch, and I'm the best there is." = 'sound/voice/mcatch.ogg', "I knew it, I should've been a plastic surgeon." = 'sound/voice/msurgeon.ogg', "What kind of medbay is this? Everyone's dropping like flies." = 'sound/voice/mflies.ogg', "Delicious!" = 'sound/voice/mdelicious.ogg') - var/message = pick(messagevoice) - speak(message) - playsound(loc, messagevoice[message], 50, FALSE) + medbot_phrase(pick(idle_phrases)) + var/scan_range = (stationary_mode ? 1 : DEFAULT_SCAN_RANGE) //If in stationary mode, scan range is limited to adjacent patients. - patient = scan(/mob/living/carbon/human, oldpatient, scan_range) - oldpatient = patient + patient = scan(/mob/living/carbon/human, scan_range = scan_range) - if(patient && (get_dist(src,patient) <= 1)) //Patient is next to us, begin treatment! - if(mode != BOT_HEALING) - mode = BOT_HEALING - update_icon() - frustration = 0 - medicate_patient(patient) - return + if(patient) + if((get_dist(src,patient) <= 1)) //Patient is next to us, begin treatment! + if(mode != BOT_HEALING) + set_mode(BOT_HEALING) + update_icon() + medicate_patient(patient) + return - //Patient has moved away from us! - else if(patient && length(path) && (get_dist(patient,path[length(path)]) > 2)) - path = list() - mode = BOT_IDLE - last_found = world.time - - else if(stationary_mode && patient) //Since we cannot move in this mode, ignore the patient and wait for another. - soft_reset() - return - - if(patient && !length(path) && (get_dist(src,patient) > 1)) - path = get_path_to(src, patient, 30, access = access_card.access) - mode = BOT_MOVING - if(!length(path)) //try to get closer if you can't reach the patient directly - path = get_path_to(src, patient, 30, 1, access = access_card.access) - if(!length(path)) //Do not chase a patient we cannot reach. - soft_reset() - - if(length(path) && patient) - if(!bot_move(path[length(path)])) - oldpatient = patient + else if(stationary_mode) //Since we cannot move in this mode, ignore the patient and wait for another. soft_reset() - return + return + + //Patient has moved away from us! + else if(!length(path) || (length(path) && (get_dist(patient, path[length(path)]) > 2))) + path = list() + set_mode(BOT_IDLE) + last_found = world.time + + if(!length(path) && (get_dist(src,patient) > 1)) + set_mode(BOT_PATHING) + path = get_path_to(src, patient, 30, access = access_card.access) + set_mode(BOT_MOVING) + if(!length(path)) //try to get closer if you can't reach the patient directly + path = get_path_to(src, patient, 30, 1, access = access_card.access) + if(!length(path)) //Do not chase a patient we cannot reach. + add_to_ignore(patient) + soft_reset() + + if(length(path)) + frustration++ + if(!bot_move(path[length(path)])) + previous_patient = patient.UID() + soft_reset() + return - if(length(path) > 8 && patient) - frustration++ if(auto_patrol && !stationary_mode && !patient) if(mode == BOT_IDLE || mode == BOT_START_PATROL) @@ -358,7 +394,6 @@ if(mode == BOT_PATROL) bot_patrol() - return /mob/living/simple_animal/bot/medbot/proc/assess_beaker_injection(mob/living/carbon/C) //If we have and are using a medicine beaker, return any reagent the patient is missing @@ -431,7 +466,7 @@ if(iscarbon(A)) var/mob/living/carbon/C = A patient = C - mode = BOT_HEALING + set_mode(BOT_HEALING) update_icon() medicate_patient(C) update_icon() @@ -444,20 +479,19 @@ chemscan(src, A) /mob/living/simple_animal/bot/medbot/proc/medicate_patient(mob/living/carbon/C) + set waitfor = FALSE + if(!on) return if(!istype(C)) - oldpatient = patient + previous_patient = patient.UID() soft_reset() return if(C.stat == DEAD || HAS_TRAIT(C, TRAIT_FAKEDEATH)) - var/list/messagevoice = list("No! Stay with me!" = 'sound/voice/mno.ogg', "Live, damnit! LIVE!" = 'sound/voice/mlive.ogg', "I...I've never lost a patient before. Not today, I mean." = 'sound/voice/mlost.ogg') - var/message = pick(messagevoice) - speak(message) - playsound(loc, messagevoice[message], 50, FALSE) - oldpatient = patient + medbot_phrase(pick(patient_died_phrases), C) + previous_patient = patient.UID() soft_reset() return @@ -471,38 +505,39 @@ reagent_id = select_medication(C, beaker_injection) if(!reagent_id) //If they don't need any of that they're probably cured! - var/list/messagevoice = list("All patched up!" = 'sound/voice/mpatchedup.ogg', "An apple a day keeps me away." = 'sound/voice/mapple.ogg', "Feel better soon!" = 'sound/voice/mfeelbetter.ogg') - var/message = pick(messagevoice) - speak(message) - playsound(loc, messagevoice[message], 50, FALSE) + medbot_phrase(pick(finish_healing_phrases), C) bot_reset() return - else - if(!emagged && !hijacked && check_overdose(patient, reagent_id, injection_amount)) - soft_reset() - return - C.visible_message("[src] is trying to inject [patient]!", \ - "[src] is trying to inject you!") - addtimer(CALLBACK(src, PROC_REF(do_inject), C, !isnull(beaker_injection), reagent_id), 3 SECONDS) + if(!emagged && !hijacked && check_overdose(patient, reagent_id, injection_amount)) + soft_reset() return -/mob/living/simple_animal/bot/medbot/proc/do_inject(mob/living/carbon/C, inject_beaker, reagent_id) - if((get_dist(src, patient) <= 1) && on && assess_patient(patient)) - if(inject_beaker) - if(use_beaker && reagent_glass?.reagents.total_volume) - var/fraction = min(injection_amount/reagent_glass.reagents.total_volume, 1) - reagent_glass.reagents.reaction(patient, REAGENT_INGEST, fraction) - reagent_glass.reagents.trans_to(patient, injection_amount) //Inject from beaker instead. - else - patient.reagents.add_reagent(reagent_id, injection_amount) + C.visible_message( + "[src] is trying to inject [patient]!", + "[src] is trying to inject you!" + ) - C.visible_message("[src] injects [patient] with its syringe!", "[src] injects you with its syringe!") - else + if(!do_after(src, 3 SECONDS, target = C) || !on || (get_dist(src, patient) > 1) || !assess_patient(patient)) + soft_reset() visible_message("[src] retracts its syringe.") + return - update_icon() - soft_reset() + if(!isnull(beaker_injection)) + if(use_beaker && reagent_glass?.reagents.total_volume) + var/fraction = min(injection_amount/reagent_glass.reagents.total_volume, 1) + reagent_glass.reagents.reaction(patient, REAGENT_INGEST, fraction) + reagent_glass.reagents.trans_to(patient, injection_amount) //Inject from beaker instead. + else + patient.reagents.add_reagent(reagent_id, injection_amount) + + C.visible_message( + "[src] injects [patient] with its syringe!", + "[src] injects you with its syringe!" + ) + + // Don't soft reset here, we already have a patient, only soft reset if we fail to heal them. + set_mode(BOT_IDLE) /mob/living/simple_animal/bot/medbot/proc/check_overdose(mob/living/carbon/patient,reagent_id,injection_amount) var/datum/reagent/R = GLOB.chemical_reagents_list[reagent_id] @@ -568,6 +603,14 @@ spawn(200) //Twenty seconds declare_cooldown = FALSE +/// Given a proper medbot phrase key, say the line with any replacements, and play its sound. +/mob/living/simple_animal/bot/medbot/proc/medbot_phrase(phrase, mob/target) + var/sound_path = all_phrases[phrase] + if(target) + phrase = replacetext(phrase, "%TARGET%", "[target]") + + speak(phrase) + playsound(src, sound_path, 75, FALSE) #undef MEDBOT_MIN_HEALING_THRESHOLD #undef MEDBOT_MAX_HEALING_THRESHOLD diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 48ef878ac71..bf6f273569c 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -432,7 +432,7 @@ AM.forceMove(src) load = AM - mode = BOT_IDLE + set_mode(BOT_IDLE) update_icon() /mob/living/simple_animal/bot/mulebot/proc/load_mob(mob/living/M) @@ -461,7 +461,7 @@ if(!load) return - mode = BOT_IDLE + set_mode(BOT_IDLE) unbuckle_all_mobs() @@ -556,55 +556,55 @@ increment_path() path -= loc if(destination == home_destination) - mode = BOT_GO_HOME + set_mode(BOT_GO_HOME) else - mode = BOT_DELIVER + set_mode(BOT_DELIVER) else // failed to move blockcount++ - mode = BOT_BLOCKED + set_mode(BOT_BLOCKED) if(blockcount == 3) buzz(ANNOYED) if(blockcount > 10) // attempt 10 times before recomputing // find new path excluding blocked turf buzz(SIGH) - mode = BOT_WAIT_FOR_NAV + set_mode(BOT_WAIT_FOR_NAV) blockcount = 0 addtimer(CALLBACK(src, PROC_REF(process_blocked), next), 2 SECONDS) return return else buzz(ANNOYED) - mode = BOT_NAV + set_mode(BOT_NAV) return else - mode = BOT_NAV + set_mode(BOT_NAV) return if(BOT_NAV) // calculate new path - mode = BOT_WAIT_FOR_NAV + set_mode(BOT_WAIT_FOR_NAV) INVOKE_ASYNC(src, PROC_REF(process_nav)) /mob/living/simple_animal/bot/mulebot/proc/process_blocked(turf/next) calc_path(avoid=next) if(length(path)) buzz(DELIGHT) - mode = BOT_BLOCKED + set_mode(BOT_BLOCKED) /mob/living/simple_animal/bot/mulebot/proc/process_nav() calc_path() if(length(path)) blockcount = 0 - mode = BOT_BLOCKED + set_mode(BOT_BLOCKED) buzz(DELIGHT) else buzz(SIGH) - mode = BOT_NO_ROUTE + set_mode(BOT_NO_ROUTE) // calculates a path to the current destination // given an optional turf to avoid @@ -624,9 +624,9 @@ if(!on) return if(destination == home_destination) - mode = BOT_GO_HOME + set_mode(BOT_GO_HOME) else - mode = BOT_DELIVER + set_mode(BOT_DELIVER) update_icon() get_nav() @@ -639,7 +639,7 @@ /mob/living/simple_animal/bot/mulebot/proc/do_start_home() set_destination(home_destination) - mode = BOT_BLOCKED + set_mode(BOT_BLOCKED) update_icon() // called when bot reaches current target @@ -685,7 +685,7 @@ if(auto_return && home_destination && destination != home_destination) // auto return set and not at home already start_home() - mode = BOT_BLOCKED + set_mode(BOT_BLOCKED) else bot_reset() // otherwise go idle diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index 87b2aed467e..f47a7fa6b50 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -189,7 +189,7 @@ threatlevel += 6 if(threatlevel >= 4) target = H - mode = BOT_HUNT + set_mode(BOT_HUNT) /mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H) if(H.a_intent == INTENT_HARM || H.a_intent == INTENT_DISARM) @@ -245,7 +245,7 @@ /mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C) - mode = BOT_ARREST + set_mode(BOT_ARREST) playsound(loc, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2) C.visible_message("[src] is trying to put zipties on [C]!",\ "[src] is trying to put zipties on you!") @@ -320,7 +320,7 @@ if(find_new_target()) // see if any criminals are in range return if(!mode && auto_patrol) // still idle, and set to patrol - mode = BOT_START_PATROL // switch to patrol mode + set_mode(BOT_START_PATROL) // switch to patrol mode if(BOT_HUNT) // hunting for perp // if can't reach perp for long enough, go idle @@ -341,7 +341,7 @@ if(Adjacent(target) && isturf(target.loc) && !baton_delayed) // if right next to perp stun_attack(target) - mode = BOT_PREP_ARREST + set_mode(BOT_PREP_ARREST) anchored = TRUE target_lastloc = target.loc return @@ -380,7 +380,7 @@ back_to_hunt() return //Try arresting again if the target escapes. - mode = BOT_PREP_ARREST + set_mode(BOT_PREP_ARREST) anchored = FALSE if(BOT_START_PATROL) @@ -397,7 +397,7 @@ /mob/living/simple_animal/bot/secbot/proc/back_to_idle() anchored = FALSE - mode = BOT_IDLE + set_mode(BOT_IDLE) target = null last_found = world.time frustration = 0 @@ -406,7 +406,7 @@ /mob/living/simple_animal/bot/secbot/proc/back_to_hunt() anchored = FALSE frustration = 0 - mode = BOT_HUNT + set_mode(BOT_HUNT) INVOKE_ASYNC(src, PROC_REF(handle_automated_action)) // look for a criminal in view of the bot @@ -429,7 +429,7 @@ speak("Level [threatlevel] infraction alert!") playsound(loc, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, FALSE) visible_message("[src] points at [C.name]!") - mode = BOT_HUNT + set_mode(BOT_HUNT) INVOKE_ASYNC(src, PROC_REF(handle_automated_action)) return TRUE return FALSE @@ -460,7 +460,7 @@ ..() if(!isalien(target)) target = user - mode = BOT_HUNT + set_mode(BOT_HUNT) /mob/living/simple_animal/bot/secbot/proc/on_atom_entered(datum/source, atom/movable/entered) if(ismob(entered) && target) diff --git a/code/modules/mob/living/simple_animal/bot/syndicate_bots.dm b/code/modules/mob/living/simple_animal/bot/syndicate_bots.dm index ca2bdaa2045..6b09e40452b 100644 --- a/code/modules/mob/living/simple_animal/bot/syndicate_bots.dm +++ b/code/modules/mob/living/simple_animal/bot/syndicate_bots.dm @@ -67,7 +67,7 @@ if(!H) return target = H - mode = BOT_HUNT + set_mode(BOT_HUNT) /mob/living/simple_animal/bot/ed209/syndicate/emag_act(mob/user) to_chat(user, "[src] has no card reader slot!") @@ -94,7 +94,7 @@ if(find_new_target()) return if(!mode && auto_patrol) - mode = BOT_START_PATROL + set_mode(BOT_START_PATROL) if(BOT_HUNT) if(frustration >= 8) @@ -140,7 +140,7 @@ continue target = M oldtarget_name = M.name - mode = BOT_HUNT + set_mode(BOT_HUNT) INVOKE_ASYNC(src, PROC_REF(handle_automated_action)) return TRUE return FALSE diff --git a/sound/voice/mfuck_you.ogg b/sound/voice/mfuck_you.ogg new file mode 100644 index 0000000000000000000000000000000000000000..5eacff615fe3e3ae5e1299e775006c65053e7aea GIT binary patch literal 11422 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 H1=IflQv?IP literal 0 HcmV?d00001