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 <orion@snowfrost.garden>
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 <orion@snowfrost.garden>
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 <funnyman3595@gmail.com>
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 <orion@snowfrost.garden>
Co-authored-by: Charlie Nolan <funnyman3595@gmail.com>
This commit is contained in:
Kapu1178
2025-02-11 20:20:42 +00:00
committed by GitHub
co-authored by chuga-git warriorstar-orion Charlie Nolan
parent ff4277d5e3
commit 2793a1c7f4
13 changed files with 315 additions and 229 deletions
@@ -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, "<span class='notice'>[bicon(src)] [name] called to [end_area.name]. [length(path)-1] meters to destination.</span>")
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)
@@ -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("<span class='notice'>[src] begins to clean up [target]</span>")
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()
@@ -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("<b>[src]</b> 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 <b>[C]</b> 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("<span class='danger'>[src] is trying to put zipties on [C]!</span>",\
"<span class='userdanger'>[src] is trying to put zipties on you!</span>")
@@ -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("<span class='notice'>[src] begins to repair the hole.</span>")
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("<span class='notice'>[src] begins repairing the floor.</span>")
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("<span class='notice'>[src] begins to collect tiles.</span>")
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("<span class='notice'>[src] begins to create tiles.</span>")
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()
@@ -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("<b>[src]</b> points at [C.name]!")
mode = BOT_HUNT
set_mode(BOT_HUNT)
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
return TRUE
return FALSE
@@ -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("<span class='danger'>[src] is trying to put zipties on [C]!</span>",
"<span class='userdanger'>[src] is trying to put zipties on you!</span>")
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("<b>[src]</b> 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
@@ -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("<span class='danger'>[src] buzzes oddly!</span>")
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("<span class='danger'>[src] is trying to inject [patient]!</span>", \
"<span class='userdanger'>[src] is trying to inject you!</span>")
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(
"<span class='danger'>[src] is trying to inject [patient]!</span>",
"<span class='userdanger'>[src] is trying to inject you!</span>"
)
C.visible_message("<span class='danger'>[src] injects [patient] with its syringe!</span>", "<span class='userdanger'>[src] injects you with its syringe!</span>")
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(
"<span class='danger'>[src] injects [patient] with its syringe!</span>",
"<span class='userdanger'>[src] injects you with its syringe!</span>"
)
// 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
@@ -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
@@ -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("<span class='danger'>[src] is trying to put zipties on [C]!</span>",\
"<span class='userdanger'>[src] is trying to put zipties on you!</span>")
@@ -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("<b>[src]</b> 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)
@@ -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, "<span class='warning'>[src] has no card reader slot!</span>")
@@ -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