Bots refactor (#23550)

* ugh... bots refactor

* everyone uses pathfind and eyes

* most hunt logic to proc

* Update code/modules/mob/living/simple_animal/bot/ed209bot.dm

Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com>

* Update code/modules/mob/living/simple_animal/bot/ed209bot.dm

Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com>

* Sirryan review

* Update code/modules/mob/living/simple_animal/bot/honkbot.dm

Co-authored-by: warriorstar-orion <orion@snowfrost.garden>

* better var naming i guess?

* Update code/modules/mob/living/simple_animal/bot/ed209bot.dm

Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com>

* Update code/modules/mob/living/simple_animal/bot/griefsky.dm

Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com>

* Update code/modules/mob/living/simple_animal/bot/secbot.dm

Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com>

* Update code/modules/mob/living/simple_animal/bot/secbot.dm

Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com>

* Update code/modules/mob/living/simple_animal/bot/secbot.dm

Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com>

* Update code/modules/mob/living/simple_animal/bot/secbot.dm

Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com>

* Update code/modules/mob/living/simple_animal/bot/secbot.dm

Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com>

* Update code/modules/mob/living/simple_animal/bot/secbot.dm

Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com>

* review

* uh oh

* Update code/modules/mob/living/simple_animal/bot/secbot.dm

Co-authored-by: Deniz <66401072+Oyu07@users.noreply.github.com>

* Update code/modules/mob/living/simple_animal/bot/secbot.dm

Co-authored-by: Deniz <66401072+Oyu07@users.noreply.github.com>

* return FALSE

---------

Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com>
Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Co-authored-by: Deniz <66401072+Oyu07@users.noreply.github.com>
This commit is contained in:
HMBGERDO
2024-02-21 23:01:48 +00:00
committed by GitHub
co-authored by Ryan warriorstar-orion Deniz
parent ac32162dbc
commit ba98eb4d16
7 changed files with 340 additions and 285 deletions
@@ -96,6 +96,11 @@
hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD)//Diagnostic HUD views
/// storing last chased target known location
var/turf/last_target_location
/// will be true if we lost target we were chasing
var/lost_target = FALSE
/obj/item/radio/headset/bot
requires_tcomms = FALSE
canhear_range = 0
@@ -110,6 +115,36 @@
B.radio_config["[B.radio_channel]"] = 1
config(B.radio_config)
/mob/living/simple_animal/bot/proc/try_chasing_target(mob/target)
if(target in view(12, src))
if(lost_target)
frustration = 0
lost_target = FALSE
last_target_location = get_turf(target)
var/dist = get_dist(src, target)
walk_to(src, target, 1, 4)
if(get_dist(src, target) >= dist)
frustration++
return
if(!lost_target)
walk_to(src, 0)
lost_target = TRUE
frustration = 0
if(get_turf(src) == last_target_location)
frustration += 2
return
if(!bot_move(last_target_location, move_speed = 6))
var/last_target_pos_path = get_path_to(src, last_target_location, id = access_card, skip_first = TRUE)
if(length(last_target_pos_path) == 0)
frustration = 10
return
set_path(last_target_pos_path)
bot_move(last_target_location, move_speed = 6)
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(paicard)
@@ -605,6 +640,8 @@ Pass a positive integer as an argument to override a bot's default speed.
deltimer(reset_access_timer_id)
reset_access_timer_id = null
set_path(null)
last_target_location = null
lost_target = FALSE
summon_target = null
pathset = FALSE
access_card.access = prev_access
@@ -40,14 +40,16 @@
var/idcheck = FALSE //If true, arrest people with no IDs
var/weapons_check = TRUE //If true, arrest people for weapons if they don't have access
var/check_records = TRUE //Does it check security records?
var/arrest_type = FALSE //If true, don't handcuff
var/no_handcuffs = FALSE //If true, don't handcuff
var/projectile = /obj/item/projectile/beam/disabler //Holder for projectile type
var/shoot_sound = 'sound/weapons/taser.ogg'
var/baton_delayed = FALSE
var/obj/item/melee/baton/infinite_cell/baton = null // stunbaton bot uses to melee attack
var/currently_cuffing = FALSE // TRUE if we're cuffing someone right now
/mob/living/simple_animal/bot/ed209/Initialize(mapload, created_name, created_lasercolor)
. = ..()
baton = new(src)
if(created_name)
name = created_name
if(created_lasercolor)
@@ -59,7 +61,7 @@
if(lasercolor)
shot_delay = 6 //Longer shot delay because JESUS CHRIST
check_records = FALSE //Don't actively target people set to arrest
arrest_type = TRUE //Don't even try to cuff
no_handcuffs = TRUE //Don't even try to cuff
declare_arrests = FALSE // Don't spam sec
req_access = list(ACCESS_MAINT_TUNNELS, ACCESS_THEATRE, ACCESS_ROBOTICS)
@@ -69,6 +71,10 @@
else if(lasercolor == "r")
name = pick("RED RAMPAGE","RED ROVER","RED KILLDEATH MURDERBOT")
/mob/living/simple_animal/bot/ed209/Destroy()
QDEL_NULL(baton)
return ..()
/mob/living/simple_animal/bot/ed209/proc/setup_access()
if(access_card)
var/datum/job/detective/J = new/datum/job/detective
@@ -89,6 +95,7 @@
target = null
oldtarget_name = null
anchored = FALSE
currently_cuffing = FALSE
walk_to(src,0)
set_path(null)
last_found = world.time
@@ -116,7 +123,7 @@
data["check_id"] = idcheck
data["check_weapons"] = weapons_check
data["check_warrant"] = check_records
data["arrest_mode"] = arrest_type // detain or arrest
data["arrest_mode"] = no_handcuffs // detain or arrest
data["arrest_declare"] = declare_arrests // announce arrests on radio
return data
@@ -148,7 +155,7 @@
if("authwarrant")
check_records = !check_records
if("arrtype")
arrest_type = !arrest_type
no_handcuffs = !no_handcuffs
if("arrdeclare")
declare_arrests = !declare_arrests
if("ejectpai")
@@ -240,40 +247,36 @@
walk_to(src,0)
set_path(null)
if(!lasercolor) //lasertag bots don't want to arrest anyone
look_for_perp() // see if any criminals are in range
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
if(BOT_HUNT) // hunting for perp
// if can't reach perp for long enough, go idle
if(frustration >= 8)
walk_to(src,0)
walk_to(src, 0)
set_path(null)
back_to_idle()
return
if(target) // make sure target exists
if(Adjacent(target) && isturf(target.loc) && !baton_delayed) // if right next to perp
stun_attack(target)
if(!lasercolor)
mode = BOT_PREP_ARREST
anchored = TRUE
target_lastloc = target.loc
return
else
mode = BOT_HUNT
target = null
target_lastloc = null
return
else if(!disabled) // not next to perp
var/turf/olddist = get_dist(src, target)
walk_to(src, target,1,4)
if((get_dist(src, target)) >= (olddist))
frustration++
else
frustration = 0
else
if(!target) // make sure target exists
back_to_idle()
return
if(Adjacent(target) && isturf(target.loc) && !baton_delayed) // if right next to perp
stun_attack(target)
if(!lasercolor)
mode = BOT_PREP_ARREST
anchored = TRUE
target_lastloc = target.loc
return
mode = BOT_HUNT
target = null
target_lastloc = null
return
try_chasing_target(target)
if(BOT_PREP_ARREST) // preparing to arrest target
@@ -282,42 +285,43 @@
back_to_hunt()
return
if(iscarbon(target) && target.canBeHandcuffed())
if(!arrest_type)
if(!target.handcuffed) //he's not cuffed? Try to cuff him!
start_cuffing(target)
else
back_to_idle()
return
else
if(no_handcuffs) // should we not cuff?
back_to_idle()
return
if(BOT_ARREST)
if(!target)
anchored = FALSE
mode = BOT_IDLE
last_found = world.time
frustration = 0
if(!(iscarbon(target) && target.canBeHandcuffed()))
back_to_idle()
return
if(target.handcuffed) //no target or target cuffed? back to idle.
if(currently_cuffing)
return
if(!target.handcuffed)
cuff(target)
return
back_to_idle()
if(BOT_ARREST)
if(!target || target.handcuffed)
back_to_idle()
return
if(!Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && world.time - target.stam_regen_start_time < 4 SECONDS && target.getStaminaLoss() <= 100)) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again.
back_to_hunt()
return
else
mode = BOT_PREP_ARREST
anchored = FALSE
mode = BOT_PREP_ARREST
anchored = FALSE
if(BOT_START_PATROL)
look_for_perp()
if(find_new_target())
return
start_patrol()
if(BOT_PATROL)
look_for_perp()
if(find_new_target())
return
bot_patrol()
@@ -339,9 +343,9 @@
// look for a criminal in view of the bot
/mob/living/simple_animal/bot/ed209/proc/look_for_perp()
/mob/living/simple_animal/bot/ed209/proc/find_new_target()
if(disabled)
return
return FALSE
anchored = FALSE
threatlevel = 0
for(var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
@@ -353,20 +357,18 @@
threatlevel = C.assess_threat(src, lasercolor)
if(!threatlevel)
if(!threatlevel || threatlevel < 4)
continue
else if(threatlevel >= 4)
target = C
oldtarget_name = C.name
speak("Level [threatlevel] infraction alert!")
playsound(loc, pick('sound/voice/ed209_20sec.ogg', 'sound/voice/edplaceholder.ogg'), 50, 0)
visible_message("<b>[src]</b> points at [C.name]!")
mode = BOT_HUNT
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
break
else
continue
target = C
oldtarget_name = C.name
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
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
return TRUE
return FALSE
/mob/living/simple_animal/bot/ed209/proc/check_for_weapons(obj/item/slot_item)
if(slot_item && slot_item.needs_permit)
@@ -541,10 +543,10 @@
return
if(iscarbon(A))
var/mob/living/carbon/C = A
if(!C.IsStunned() || arrest_type && !baton_delayed)
if(!C.IsStunned() || no_handcuffs && !baton_delayed)
stun_attack(A)
else if(C.canBeHandcuffed() && !C.handcuffed)
start_cuffing(A)
cuff(A)
else
..()
@@ -562,37 +564,33 @@
shootAt(A)
/mob/living/simple_animal/bot/ed209/proc/stun_attack(mob/living/carbon/C)
playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
var/threat = C.assess_threat(src)
var/prev_intent = a_intent
a_intent = INTENT_HELP
baton.attack(C, src)
a_intent = prev_intent
baton_delayed = TRUE
addtimer(VARSET_CALLBACK(src, baton_delayed, FALSE), BATON_COOLDOWN)
icon_state = "[lasercolor]ed209-c"
addtimer(VARSET_CALLBACK(src, icon_state, "[lasercolor]ed209[on]"), 2)
var/threat = C.assess_threat(src)
C.SetStuttering(10 SECONDS)
C.apply_damage(60, STAMINA)
baton_delayed = TRUE
C.apply_status_effect(STATUS_EFFECT_DELAYED, 2.5 SECONDS, CALLBACK(C, TYPE_PROC_REF(/mob/living/, KnockDown), 10 SECONDS), COMSIG_LIVING_CLEAR_STUNS)
addtimer(VARSET_CALLBACK(src, baton_delayed, FALSE), BATON_COOLDOWN)
add_attack_logs(src, C, "batoned")
if(declare_arrests)
var/area/location = get_area(src)
speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag <b>[C]</b> in [location].", radio_channel)
C.visible_message("<span class='danger'>[src] has stunned [C]!</span>",\
"<span class='userdanger'>[src] has stunned you!</span>")
speak("[no_handcuffs ? "Detaining" : "Arresting"] level [threat] scumbag <b>[C]</b> in [location].", radio_channel)
/mob/living/simple_animal/bot/ed209/proc/start_cuffing(mob/living/carbon/C)
/mob/living/simple_animal/bot/ed209/proc/cuff(mob/living/carbon/C)
mode = BOT_ARREST
playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -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>")
addtimer(CALLBACK(src, PROC_REF(cuff_target), C), 6 SECONDS)
INVOKE_ASYNC(src, PROC_REF(cuff_callback), C)
/mob/living/simple_animal/bot/ed209/proc/cuff_target(mob/living/carbon/C)
if(!Adjacent(C)|| !isturf(C.loc)) //if he's in a closet or not adjacent, we cancel cuffing.
/mob/living/simple_animal/bot/ed209/proc/cuff_callback(mob/living/carbon/C)
if(!do_after(src, 6 SECONDS, target = C))
return
if(!C.handcuffed)
if(!C.handcuffed && on)
C.handcuffed = new /obj/item/restraints/handcuffs/cable/zipties/used(C)
C.update_handcuffed()
back_to_idle()
back_to_idle()
#undef BATON_COOLDOWN
@@ -110,7 +110,8 @@
icon_state = "griefsky1"
walk_to(src,0)
set_path(null)
look_for_perp() // see if any criminals are in range
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
if(BOT_HUNT) // hunting for perp
@@ -121,38 +122,38 @@
set_path(null)
back_to_idle()
return
if(target) // make sure target exists
if(target.stat == !DEAD)
if(Adjacent(target) && isturf(target.loc)) // if right next to perp
target_lastloc = target.loc
sword_attack(target)
anchored = TRUE
frustration++
return
else // not next to perp
var/turf/olddist = get_dist(src, target)
walk_to(src, target,1,3) //he's a fast fucker
if((get_dist(src, target)) >= (olddist))
frustration++
else
frustration = 0
else
back_to_idle()
speak("You fool")
else
if(!target) // make sure target exists
back_to_idle()
speak("You fool")
return
if(target.stat == DEAD)
back_to_idle()
return
if(Adjacent(target) && isturf(target.loc)) // if right next to perp
target_lastloc = target.loc
sword_attack(target)
anchored = TRUE
frustration++
return // not next to perp
try_chasing_target(target)
if(BOT_START_PATROL)
look_for_perp()
if(find_new_target())
return
start_patrol()
if(BOT_PATROL)
icon_state = "griefsky1"
look_for_perp()
if(find_new_target())
return
bot_patrol()
return
/mob/living/simple_animal/bot/secbot/griefsky/look_for_perp()
/mob/living/simple_animal/bot/secbot/griefsky/find_new_target()
anchored = FALSE
for(var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
if((C.stat) || (C.handcuffed))
@@ -163,22 +164,20 @@
threatlevel = C.assess_threat(src)
if(!threatlevel)
if(!threatlevel || threatlevel < 4)
continue
else if(threatlevel >= 4)
target = C
oldtarget_name = C.name
speak("You are a bold one")
playsound(src,'sound/weapons/saberon.ogg',50,TRUE,-1)
visible_message("[src] ignites his energy swords!")
icon_state = "griefsky-c"
visible_message("<b>[src]</b> points at [C.name]!")
mode = BOT_HUNT
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
break
else
continue
target = C
oldtarget_name = C.name
speak("You are a bold one")
playsound(src,'sound/weapons/saberon.ogg', 50, TRUE, -1)
visible_message("[src] ignites his energy swords!")
icon_state = "griefsky-c"
visible_message("<b>[src]</b> points at [C.name]!")
mode = BOT_HUNT
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
return TRUE
return FALSE
/mob/living/simple_animal/bot/secbot/griefsky/explode()
walk_to(src,0)
@@ -20,14 +20,14 @@
var/honksound = 'sound/items/bikehorn.ogg' //customizable sound
var/spam_flag = FALSE
var/cooldowntime = 30
var/cooldowntimehorn = 10
var/cooldowntime = 3 SECONDS
var/cooldowntimehorn = 1 SECONDS
var/mob/living/carbon/target
var/oldtarget_name
var/target_lastloc = FALSE //Loc of target when arrested.
var/last_found = FALSE //There's a delay
var/threatlevel = FALSE
var/arrest_type = FALSE
var/no_handcuffs = FALSE
/mob/living/simple_animal/bot/honkbot/Initialize(mapload)
. = ..()
@@ -37,9 +37,6 @@
access_card.access += J.get_access()
prev_access = access_card.access
/mob/living/simple_animal/bot/honkbot/proc/spam_flag_false() //used for addtimer
spam_flag = FALSE
/mob/living/simple_animal/bot/honkbot/proc/sensor_blink()
icon_state = "honkbot-c"
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), 5, TIMER_OVERRIDE|TIMER_UNIQUE)
@@ -49,7 +46,7 @@
playsound(src, 'sound/machines/ping.ogg', 50, TRUE, -1) //the first sound upon creation!
spam_flag = TRUE
sensor_blink()
addtimer(CALLBACK(src, PROC_REF(spam_flag_false)), 18) // calibrates before starting the honk
addtimer(VARSET_CALLBACK(src, spam_flag, FALSE), 1.8 SECONDS)
/mob/living/simple_animal/bot/honkbot/proc/react_buzz()
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE, -1)
@@ -146,7 +143,7 @@
if(!emagged)
honk_attack(A)
else
if(!C.IsStunned() || arrest_type)
if(!C.IsStunned() || no_handcuffs)
stun_attack(A)
..()
else if(!spam_flag) //honking at the ground
@@ -167,21 +164,21 @@
playsound(src, honksound, 50, TRUE, -1)
spam_flag = TRUE //prevent spam
sensor_blink()
addtimer(CALLBACK(src, PROC_REF(spam_flag_false)), cooldowntimehorn)
else if(emagged) //emagged honkbots will spam short and memorable sounds.
addtimer(VARSET_CALLBACK(src, spam_flag, FALSE), cooldowntimehorn)
else //emagged honkbots will spam short and memorable sounds.
if(!spam_flag)
playsound(src, "honkbot_e", 50, 0)
spam_flag = TRUE // prevent spam
icon_state = "honkbot-e"
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), 30, TIMER_OVERRIDE|TIMER_UNIQUE)
addtimer(CALLBACK(src, PROC_REF(spam_flag_false)), cooldowntimehorn)
addtimer(VARSET_CALLBACK(src, spam_flag, FALSE), cooldowntimehorn)
/mob/living/simple_animal/bot/honkbot/proc/honk_attack(mob/living/carbon/C) // horn attack
if(!spam_flag)
playsound(loc, honksound, 50, TRUE, -1)
spam_flag = TRUE // prevent spam
sensor_blink()
addtimer(CALLBACK(src, PROC_REF(spam_flag_false)), cooldowntimehorn)
addtimer(VARSET_CALLBACK(src, spam_flag, FALSE), cooldowntimehorn)
/mob/living/simple_animal/bot/honkbot/proc/stun_attack(mob/living/carbon/C) // airhorn stun
if(!spam_flag)
@@ -203,14 +200,14 @@
target = oldtarget_name
else // you really don't want to hit an emagged honkbot
threatlevel = 6 // will never let you go
addtimer(CALLBACK(src, PROC_REF(spam_flag_false)), cooldowntime)
addtimer(VARSET_CALLBACK(src, spam_flag, FALSE), cooldowntimehorn)
add_attack_logs(src, C, "honked by [src]")
C.visible_message("<span class='danger'>[src] has honked [C]!</span>",\
"<span class='userdanger'>[src] has honked you!</span>")
else
C.Stuttering(40 SECONDS)
C.Stun(20 SECONDS)
addtimer(CALLBACK(src, PROC_REF(spam_flag_false)), cooldowntime)
addtimer(VARSET_CALLBACK(src, spam_flag, FALSE), cooldowntimehorn)
/mob/living/simple_animal/bot/honkbot/handle_automated_action()
@@ -219,7 +216,8 @@
switch(mode)
if(BOT_IDLE) // idle
walk_to(src, 0)
look_for_perp()
if(find_new_target())
return
if(!mode && auto_patrol)
mode = BOT_START_PATROL
if(BOT_HUNT)
@@ -229,33 +227,31 @@
playsound(loc, 'sound/misc/sadtrombone.ogg', 25, 1, -1)
back_to_idle()
return
if(target) // make sure target exists
if(Adjacent(target) && isturf(target.loc))
if(threatlevel <= 4)
honk_attack(target)
else
if(threatlevel >= 6)
set waitfor = 0
stun_attack(target)
anchored = FALSE
target_lastloc = target.loc
return
else // not next to perp
var/turf/olddist = get_dist(src, target)
walk_to(src, target, 1, 4)
if((get_dist(src, target)) >= (olddist))
frustration++
else
frustration = 0
else
if(!target) // make sure target exists
back_to_idle()
return
if(Adjacent(target) && isturf(target.loc))
if(threatlevel <= 4)
honk_attack(target)
else
if(threatlevel >= 6)
stun_attack(target)
anchored = FALSE
target_lastloc = target.loc
return
try_chasing_target(target)
if(BOT_START_PATROL)
look_for_perp()
if(find_new_target())
return
start_patrol()
if(BOT_PATROL)
look_for_perp()
if(find_new_target())
return
bot_patrol()
return
@@ -273,7 +269,7 @@
mode = BOT_HUNT
INVOKE_ASYNC(src, PROC_REF(handle_automated_action)) // responds quickly
/mob/living/simple_animal/bot/honkbot/proc/look_for_perp()
/mob/living/simple_animal/bot/honkbot/proc/find_new_target()
anchored = FALSE
for(var/mob/living/carbon/C in view(7, src))
if((C.stat) || (C.handcuffed))
@@ -282,24 +278,26 @@
if((C.name == oldtarget_name) && (world.time < last_found + 100))
continue
if(threatlevel <= 3 && !emagged)
if(C in view(4, src)) //keep the range short for patrolling
if(!spam_flag)
bike_horn()
else if(threatlevel >= 4)
if(!spam_flag || emagged)
target = C
oldtarget_name = C.name
if(threatlevel < 4)
if(emagged) // actually emagged
bike_horn()
speak("Honk!")
visible_message("<b>[src]</b> starts chasing [C.name]!")
mode = BOT_HUNT
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
break
else
continue
else if(emagged)
bike_horn() //just spam the shit outta this
if(C in view(4, src) && !spam_flag) //keep the range short for patrolling
bike_horn()
continue
if(spam_flag && !emagged)
continue
target = C
oldtarget_name = C.name
bike_horn()
speak("Honk!")
visible_message("<b>[src]</b> starts chasing [C.name]!")
mode = BOT_HUNT
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
return TRUE
return FALSE
/mob/living/simple_animal/bot/honkbot/explode() //doesn't drop cardboard nor its assembly, since its a very frail material.
walk_to(src, 0)
@@ -32,12 +32,27 @@
var/idcheck = FALSE //If true, arrest people with no IDs
var/weapons_check = FALSE //If true, arrest people for weapons if they lack access
var/check_records = TRUE //Does it check security records?
var/arrest_type = FALSE //If true, don't handcuff
var/no_handcuffs = FALSE //If true, don't handcuff
var/harmbaton = FALSE //If true, beat instead of stun
var/flashing_lights = FALSE //If true, flash lights
var/baton_delayed = FALSE
var/prev_flashing_lights = FALSE
allow_pai = FALSE
var/obj/item/melee/baton/infinite_cell/baton = null // stunbaton bot uses to melee attack
var/currently_cuffing = FALSE // TRUE if we're cuffing someone right now
var/played_sound_this_hunt = FALSE // used to make beepsky beep when it lost its target
/mob/living/simple_animal/bot/secbot/Initialize(mapload)
. = ..()
baton = new(src)
icon_state = "[base_icon][on]"
var/datum/job/detective/J = new/datum/job/detective
access_card.access += J.get_access()
prev_access = access_card.access
/mob/living/simple_animal/bot/secbot/Destroy()
QDEL_NULL(baton)
return ..()
/mob/living/simple_animal/bot/secbot/beepsky
name = "Officer Beepsky"
@@ -72,7 +87,7 @@
base_icon = "rustbot"
icon_state = "rustbot0"
declare_arrests = FALSE
arrest_type = TRUE
no_handcuffs = TRUE
harmbaton = TRUE
emagged = TRUE
@@ -81,16 +96,9 @@
health = 100
maxHealth = 100
idcheck = TRUE
arrest_type = TRUE
no_handcuffs = TRUE
weapons_check = TRUE
/mob/living/simple_animal/bot/secbot/Initialize(mapload)
. = ..()
icon_state = "[base_icon][on]"
var/datum/job/detective/J = new/datum/job/detective
access_card.access += J.get_access()
prev_access = access_card.access
/mob/living/simple_animal/bot/secbot/turn_on()
..()
@@ -102,6 +110,8 @@
/mob/living/simple_animal/bot/secbot/bot_reset()
..()
currently_cuffing = FALSE
played_sound_this_hunt = FALSE
target = null
oldtarget_name = null
anchored = FALSE
@@ -131,7 +141,7 @@
data["check_id"] = idcheck
data["check_weapons"] = weapons_check
data["check_warrant"] = check_records
data["arrest_mode"] = arrest_type // detain or arrest
data["arrest_mode"] = no_handcuffs // detain or arrest
data["arrest_declare"] = declare_arrests // announce arrests on radio
return data
@@ -163,7 +173,7 @@
if("authwarrant")
check_records = !check_records
if("arrtype")
arrest_type = !arrest_type
no_handcuffs = !no_handcuffs
if("arrdeclare")
declare_arrests = !declare_arrests
if("ejectpai")
@@ -214,7 +224,7 @@
return
if(iscarbon(A))
var/mob/living/carbon/C = A
if((!C.IsWeakened() || arrest_type) && !baton_delayed)
if((!C.IsWeakened() || no_handcuffs) && !baton_delayed)
stun_attack(A)
else if(C.canBeHandcuffed() && !C.handcuffed)
cuff(A)
@@ -239,34 +249,30 @@
INVOKE_ASYNC(src, PROC_REF(cuff_callback), C)
/mob/living/simple_animal/bot/secbot/proc/cuff_callback(mob/living/carbon/C)
if(do_after(src, 60, target = C))
if(!C.handcuffed && on)
C.handcuffed = new /obj/item/restraints/handcuffs/cable/zipties/used(C)
C.update_handcuffed()
playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0)
back_to_idle()
currently_cuffing = TRUE
if(!do_after(src, 6 SECONDS, target = C))
currently_cuffing = FALSE
return
currently_cuffing = FALSE
if(!C.handcuffed && on)
C.handcuffed = new /obj/item/restraints/handcuffs/cable/zipties/used(C)
C.update_handcuffed()
playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, FALSE)
back_to_idle()
/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
if(harmbaton)
playsound(loc, 'sound/weapons/genhit1.ogg', 50, 1, -1)
do_attack_animation(C)
var/threat = C.assess_threat(src)
var/prev_intent = a_intent
a_intent = harmbaton ? INTENT_HARM : INTENT_HELP
baton.attack(C, src)
a_intent = prev_intent
baton_delayed = TRUE
addtimer(VARSET_CALLBACK(src, baton_delayed, FALSE), BATON_COOLDOWN)
icon_state = "[base_icon]-c"
addtimer(VARSET_CALLBACK(src, icon_state, "[base_icon][on]"), 2)
var/threat = C.assess_threat(src)
if(ishuman(C) && harmbaton) // Bots with harmbaton enabled become shitcurity. - Dave
C.apply_damage(10, BRUTE)
C.SetStuttering(10 SECONDS)
C.apply_damage(60, STAMINA)
baton_delayed = TRUE
C.apply_status_effect(STATUS_EFFECT_DELAYED, 2.5 SECONDS, CALLBACK(C, TYPE_PROC_REF(/mob/living/, KnockDown), 10 SECONDS), COMSIG_LIVING_CLEAR_STUNS)
addtimer(VARSET_CALLBACK(src, baton_delayed, FALSE), BATON_COOLDOWN)
add_attack_logs(src, C, "batoned")
if(declare_arrests)
var/area/location = get_area(src)
speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag <b>[C]</b> in [location].", radio_channel)
C.visible_message("<span class='danger'>[src] has [harmbaton ? "beaten" : "stunned"] [C]!</span>",\
"<span class='userdanger'>[src] has [harmbaton ? "beaten" : "stunned"] you!</span>")
speak("[no_handcuffs ? "Detaining" : "Arresting"] level [threat] scumbag <b>[C]</b> in [location].", radio_channel)
/mob/living/simple_animal/bot/secbot/Life(seconds, times_fired)
. = ..()
@@ -289,6 +295,15 @@
flashing_lights = !flashing_lights
/mob/living/simple_animal/bot/secbot/try_chasing_target()
. = ..()
if(lost_target && !played_sound_this_hunt && frustration > 2)
playsound(loc, 'sound/machines/synth_no.ogg', 50, FALSE)
played_sound_this_hunt = TRUE
if(!lost_target && played_sound_this_hunt)
playsound(loc, 'sound/machines/synth_yes.ogg', 50, FALSE)
played_sound_this_hunt = FALSE
/mob/living/simple_animal/bot/secbot/handle_automated_action()
if(!..())
return
@@ -297,84 +312,80 @@
switch(mode)
if(BOT_IDLE) // idle
walk_to(src,0)
walk_to(src, 0)
set_path(null)
look_for_perp() // see if any criminals are in range
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
if(BOT_HUNT) // hunting for perp
// if can't reach perp for long enough, go idle
if(frustration >= 8)
walk_to(src,0)
playsound(loc, 'sound/machines/buzz-two.ogg', 25, FALSE)
walk_to(src, 0)
set_path(null)
back_to_idle()
return
if(target) // make sure target exists
if(Adjacent(target) && isturf(target.loc) && !baton_delayed) // if right next to perp
stun_attack(target)
mode = BOT_PREP_ARREST
anchored = TRUE
target_lastloc = target.loc
return
else // not next to perp
var/turf/olddist = get_dist(src, target)
walk_to(src, target,1,4)
if((get_dist(src, target)) >= (olddist))
frustration++
else
frustration = 0
else
if(!target) // make sure target exists
back_to_idle()
return
if(Adjacent(target) && isturf(target.loc) && !baton_delayed) // if right next to perp
stun_attack(target)
mode = BOT_PREP_ARREST
anchored = TRUE
target_lastloc = target.loc
return
try_chasing_target(target)
if(BOT_PREP_ARREST) // preparing to arrest target
// see if he got away. If he's no no longer adjacent or inside a closet or about to get up, we hunt again.
if(!Adjacent(target) || !isturf(target.loc) || world.time - target.stam_regen_start_time < 4 SECONDS && target.getStaminaLoss() <= 100)
back_to_hunt()
return
if(iscarbon(target) && target.canBeHandcuffed())
if(!arrest_type)
if(!target.handcuffed) //he's not cuffed? Try to cuff him!
cuff(target)
else
back_to_idle()
return
else
// target is stunned and nearby
if(no_handcuffs) // should we not cuff?
back_to_idle()
return
if(BOT_ARREST)
if(!target)
anchored = FALSE
mode = BOT_IDLE
last_found = world.time
frustration = 0
if(!(iscarbon(target) && target.canBeHandcuffed()))
back_to_idle()
return
if(target.handcuffed) //no target or target cuffed? back to idle.
if(currently_cuffing)
return
if(!target.handcuffed)
cuff(target)
return
back_to_idle()
if(BOT_ARREST)
if(!target || target.handcuffed)
back_to_idle()
return
if(!Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && target.AmountWeakened() < 4 SECONDS)) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again.
back_to_hunt()
return
else //Try arresting again if the target escapes.
mode = BOT_PREP_ARREST
anchored = FALSE
//Try arresting again if the target escapes.
mode = BOT_PREP_ARREST
anchored = FALSE
if(BOT_START_PATROL)
look_for_perp()
if(find_new_target())
return
start_patrol()
if(BOT_PATROL)
look_for_perp()
if(find_new_target())
return
bot_patrol()
return
/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
@@ -392,7 +403,7 @@
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
// look for a criminal in view of the bot
/mob/living/simple_animal/bot/secbot/proc/look_for_perp()
/mob/living/simple_animal/bot/secbot/proc/find_new_target()
anchored = FALSE
for(var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
if((C.stat) || (C.handcuffed))
@@ -403,20 +414,19 @@
threatlevel = C.assess_threat(src)
if(!threatlevel)
if(!threatlevel || threatlevel < 4)
continue
else if(threatlevel >= 4)
target = C
oldtarget_name = C.name
speak("Level [threatlevel] infraction alert!")
playsound(loc, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, 0)
visible_message("<b>[src]</b> points at [C.name]!")
mode = BOT_HUNT
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
break
else
continue
target = C
oldtarget_name = C.name
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
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
return TRUE
return FALSE
/mob/living/simple_animal/bot/secbot/proc/check_for_weapons(obj/item/slot_item)
if(slot_item && slot_item.needs_permit)
return 1
@@ -10,7 +10,7 @@
maxHealth = 300
declare_arrests = FALSE
idcheck = TRUE
arrest_type = TRUE
no_handcuffs = TRUE
auto_patrol = TRUE
emagged = TRUE
faction = list("syndicate")
@@ -72,6 +72,11 @@
/mob/living/simple_animal/bot/ed209/syndicate/emag_act(mob/user)
to_chat(user, "<span class='warning'>[src] has no card reader slot!</span>")
/mob/living/simple_animal/bot/ed209/syndicate/try_chasing_target()
. = ..()
if(!lost_target)
shootAt(target)
/mob/living/simple_animal/bot/ed209/syndicate/ed209_ai()
var/turf/current_turf = get_turf(src)
if(saved_turf && current_turf != saved_turf)
@@ -86,39 +91,42 @@
if(BOT_IDLE)
walk_to(src,0)
set_path(null)
look_for_perp()
if(find_new_target())
return
if(!mode && auto_patrol)
mode = BOT_START_PATROL
if(BOT_HUNT)
if(frustration >= 8)
walk_to(src,0)
set_path(null)
back_to_idle()
if(target)
if(isliving(target))
if(target.stat == DEAD)
back_to_idle()
return
shootAt(target)
var/turf/olddist = get_dist(src, target)
walk_to(src, target,1,4)
if((get_dist(src, target)) >= (olddist))
frustration++
else
frustration = 0
else
return
if(!target)
back_to_idle()
return
if(isliving(target) && target.stat == DEAD)
back_to_idle()
return
try_chasing_target(target)
if(BOT_START_PATROL)
look_for_perp()
if(find_new_target())
return
start_patrol()
if(BOT_PATROL)
look_for_perp()
if(find_new_target())
return
bot_patrol()
else
back_to_idle()
return
/mob/living/simple_animal/bot/ed209/syndicate/look_for_perp()
/mob/living/simple_animal/bot/ed209/syndicate/find_new_target()
if(disabled)
return
for(var/mob/M in view(7, src))
@@ -133,9 +141,9 @@
target = M
oldtarget_name = M.name
mode = BOT_HUNT
spawn(0)
handle_automated_action()
break
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
return TRUE
return FALSE
/mob/living/simple_animal/bot/ed209/syndicate/shootAt(atom/target)
@@ -178,7 +186,7 @@
return
shootAt(A)
/mob/living/simple_animal/bot/ed209/syndicate/start_cuffing(mob/living/carbon/C)
/mob/living/simple_animal/bot/ed209/syndicate/cuff(mob/living/carbon/C)
shootAt(C)
/mob/living/simple_animal/bot/ed209/syndicate/stun_attack(mob/living/carbon/C)