diff --git a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm
new file mode 100644
index 000000000000..6fde8cede83d
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm
@@ -0,0 +1,150 @@
+/mob/living/simple_animal/bot/secbot/grievous //This bot is powerful. If you managed to get 4 eswords somehow, you deserve this horror. Emag him for best results.
+ name = "General Beepsky"
+ desc = "Is that a secbot with four eswords in its arms...?"
+ icon = 'icons/mob/aibots.dmi'
+ icon_state = "grievous"
+ health = 150
+ maxHealth = 150
+ baton_type = /obj/item/melee/transforming/energy/sword
+ base_speed = 4 //he's a fast fucker
+ var/obj/item/weapon
+ var/block_chance = 50
+
+
+/mob/living/simple_animal/bot/secbot/grievous/toy //A toy version of general beepsky!
+ name = "Genewul Bweepskee"
+ desc = "An adorable looking secbot with four toy swords taped to its arms"
+ health = 50
+ maxHealth = 50
+ baton_type = /obj/item/toy/sword
+
+/mob/living/simple_animal/bot/secbot/grievous/bullet_act(obj/item/projectile/P)
+ visible_message("[src] deflects [P] with its energy swords!")
+ playsound(src, 'sound/weapons/blade1.ogg', 50, TRUE)
+ return FALSE
+
+/mob/living/simple_animal/bot/secbot/grievous/Crossed(atom/movable/AM)
+ ..()
+ if(ismob(AM) && AM == target)
+ visible_message("[src] flails his swords and cuts [AM]!")
+ playsound(src,'sound/effects/beepskyspinsabre.ogg',100,TRUE,-1)
+ stun_attack(AM)
+
+/mob/living/simple_animal/bot/secbot/grievous/Initialize()
+ . = ..()
+ weapon = new baton_type(src)
+ weapon.attack_self(src)
+
+/mob/living/simple_animal/bot/secbot/grievous/Destroy()
+ QDEL_NULL(weapon)
+ return ..()
+
+/mob/living/simple_animal/bot/secbot/grievous/special_retaliate_after_attack(mob/user)
+ if(mode != BOT_HUNT)
+ return
+ if(prob(block_chance))
+ visible_message("[src] deflects [user]'s attack with his energy swords!")
+ playsound(src, 'sound/weapons/blade1.ogg', 50, TRUE, -1)
+ return TRUE
+
+/mob/living/simple_animal/bot/secbot/grievous/stun_attack(mob/living/carbon/C) //Criminals don't deserve to live
+ weapon.attack(C, src)
+ playsound(src, 'sound/weapons/blade1.ogg', 50, TRUE, -1)
+ if(C.stat == DEAD)
+ addtimer(CALLBACK(src, .proc/update_icon), 2)
+ back_to_idle()
+
+
+/mob/living/simple_animal/bot/secbot/grievous/handle_automated_action()
+ if(!on)
+ return
+ switch(mode)
+ if(BOT_IDLE) // idle
+ update_icon()
+ walk_to(src,0)
+ look_for_perp() // 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
+ update_icon()
+ playsound(src,'sound/effects/beepskyspinsabre.ogg',100,TRUE,-1)
+ // general beepsky doesn't give up so easily, jedi scum
+ if(frustration >= 20)
+ walk_to(src,0)
+ back_to_idle()
+ return
+ if(target) // make sure target exists
+ if(Adjacent(target) && isturf(target.loc)) // if right next to perp
+ target_lastloc = target.loc //stun_attack() can clear the target if they're dead, so this needs to be set first
+ stun_attack(target)
+ anchored = TRUE
+ 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
+ back_to_idle()
+
+ if(BOT_START_PATROL)
+ look_for_perp()
+ start_patrol()
+
+ if(BOT_PATROL)
+ look_for_perp()
+ bot_patrol()
+
+/mob/living/simple_animal/bot/secbot/grievous/look_for_perp()
+ anchored = FALSE
+ var/judgement_criteria = judgement_criteria()
+ for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
+ if((C.stat) || (C.handcuffed))
+ continue
+
+ if((C.name == oldtarget_name) && (world.time < last_found + 100))
+ continue
+
+ threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
+
+ if(!threatlevel)
+ continue
+
+ else if(threatlevel >= 4)
+ target = C
+ oldtarget_name = C.name
+ speak("Level [threatlevel] infraction alert!")
+ playsound(src, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, FALSE)
+ playsound(src,'sound/weapons/saberon.ogg',50,TRUE,-1)
+ visible_message("[src] ignites his energy swords!")
+ icon_state = "grievous-c"
+ visible_message("[src] points at [C.name]!")
+ mode = BOT_HUNT
+ INVOKE_ASYNC(src, .proc/handle_automated_action)
+ break
+ else
+ continue
+
+
+/mob/living/simple_animal/bot/secbot/grievous/explode()
+
+ walk_to(src,0)
+ visible_message("[src] lets out a huge cough as it blows apart!")
+ var/atom/Tsec = drop_location()
+
+ var/obj/item/bot_assembly/secbot/Sa = new (Tsec)
+ Sa.build_step = 1
+ Sa.add_overlay("hs_hole")
+ Sa.created_name = name
+ new /obj/item/assembly/prox_sensor(Tsec)
+
+ if(prob(50))
+ drop_part(robot_arm, Tsec)
+
+ do_sparks(3, TRUE, src)
+ for(var/IS = 0 to 4)
+ drop_part(baton_type, Tsec)
+ new /obj/effect/decal/cleanable/oil(Tsec)
+ qdel(src)
diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm
index c9ece767a56e..56d37f667c1a 100644
--- a/code/modules/mob/living/simple_animal/bot/construction.dm
+++ b/code/modules/mob/living/simple_animal/bot/construction.dm
@@ -379,6 +379,8 @@
icon_state = "helmet_signaler"
item_state = "helmet"
created_name = "Securitron" //To preserve the name if it's a unique securitron I guess
+ var/swordamt = 0 //If you're converting it into a grievousbot, how many swords have you attached
+ var/toyswordamt = 0 //honk
/obj/item/bot_assembly/secbot/attackby(obj/item/I, mob/user, params)
..()
@@ -441,6 +443,29 @@
S.robot_arm = robot_arm
qdel(I)
qdel(src)
+ if(istype(I, /obj/item/wrench))
+ to_chat(user, "You adjust [src]'s arm slots to mount extra weapons")
+ build_step ++
+ return
+ if(istype(I, /obj/item/toy/sword))
+ if(toyswordamt < 3 && swordamt <= 0)
+ if(!user.temporarilyRemoveItemFromInventory(I))
+ return
+ created_name = "General Beepsky"
+ name = "helmet/signaler/prox sensor/robot arm/toy sword assembly"
+ icon_state = "grievous_assembly"
+ to_chat(user, "You superglue [I] onto one of [src]'s arm slots.")
+ qdel(I)
+ toyswordamt ++
+ else
+ if(!can_finish_build(I, user))
+ return
+ to_chat(user, "You complete the Securitron!...Something seems a bit wrong with it..?")
+ var/mob/living/simple_animal/bot/secbot/grievous/toy/S = new(Tsec)
+ S.name = created_name
+ S.robot_arm = robot_arm
+ qdel(I)
+ qdel(src)
else if(istype(I, /obj/item/screwdriver)) //deconstruct
cut_overlay("hs_arm")
@@ -448,3 +473,35 @@
robot_arm = null
to_chat(user, "You remove [dropped_arm] from [src].")
build_step--
+ if(toyswordamt > 0 || toyswordamt)
+ icon_state = initial(icon_state)
+ to_chat(user, "The superglue binding [src]'s toy swords to its chassis snaps!")
+ for(var/IS in 1 to toyswordamt)
+ new /obj/item/toy/sword(Tsec)
+
+ if(ASSEMBLY_FIFTH_STEP)
+ if(istype(I, /obj/item/melee/transforming/energy/sword/saber))
+ if(swordamt < 3)
+ if(!user.temporarilyRemoveItemFromInventory(I))
+ return
+ created_name = "General Beepsky"
+ name = "helmet/signaler/prox sensor/robot arm/energy sword assembly"
+ icon_state = "grievous_assembly"
+ to_chat(user, "You bolt [I] onto one of [src]'s arm slots.")
+ qdel(I)
+ swordamt ++
+ else
+ if(!can_finish_build(I, user))
+ return
+ to_chat(user, "You complete the Securitron!...Something seems a bit wrong with it..?")
+ var/mob/living/simple_animal/bot/secbot/grievous/S = new(Tsec)
+ S.name = created_name
+ S.robot_arm = robot_arm
+ qdel(I)
+ qdel(src)
+ else if(istype(I, /obj/item/screwdriver)) //deconstruct
+ build_step--
+ icon_state = initial(icon_state)
+ to_chat(user, "You unbolt [src]'s energy swords")
+ for(var/IS in 1 to swordamt)
+ new /obj/item/melee/transforming/energy/sword/saber(Tsec)
diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
index e8a92dce9eab..a3b93236c6b3 100644
--- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
@@ -26,7 +26,7 @@
var/lastfired = 0
var/shot_delay = 15
var/lasercolor = ""
- var/disabled = 0//A holder for if it needs to be disabled, if true it will not seach for targets, shoot at targets, or move, currently only used for lasertag
+ var/disabled = FALSE //A holder for if it needs to be disabled, if true it will not seach for targets, shoot at targets, or move, currently only used for lasertag
var/mob/living/carbon/target
@@ -34,11 +34,11 @@
var/threatlevel = 0
var/target_lastloc //Loc of target when arrested.
var/last_found //There's a delay
- var/declare_arrests = 1 //When making an arrest, should it notify everyone wearing sechuds?
- var/idcheck = 1 //If true, arrest people with no IDs
- var/weaponscheck = 1 //If true, arrest people for weapons if they don't have access
- var/check_records = 1 //Does it check security records?
- var/arrest_type = 0 //If true, don't handcuff
+ var/declare_arrests = TRUE //When making an arrest, should it notify everyone wearing sechuds?
+ var/idcheck = TRUE //If true, arrest people with no IDs
+ var/weaponscheck = 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/projectile = /obj/item/projectile/energy/electrode //Holder for projectile type
var/shoot_sound = 'sound/weapons/taser.ogg'
var/cell_type = /obj/item/stock_parts/cell
@@ -199,7 +199,7 @@ Auto Patrol[]"},
to_chat(user, "You short out [src]'s target assessment circuits.")
oldtarget_name = user.name
audible_message("[src] buzzes oddly!")
- declare_arrests = 0
+ declare_arrests = FALSE
icon_state = "[lasercolor]ed209[on]"
set_weapon()
@@ -357,7 +357,7 @@ Auto Patrol[]"},
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)
+ playsound(src, pick('sound/voice/ed209_20sec.ogg', 'sound/voice/edplaceholder.ogg'), 50, FALSE)
visible_message("[src] points at [C.name]!")
mode = BOT_HUNT
spawn(0)
@@ -447,7 +447,7 @@ Auto Patrol[]"},
return
var/obj/item/projectile/A = new projectile (loc)
- playsound(loc, shoot_sound, 50, 1)
+ playsound(src, shoot_sound, 50, TRUE)
A.preparePixelProjectile(target, src)
A.fire()
@@ -538,7 +538,7 @@ Auto Patrol[]"},
shootAt(A)
/mob/living/simple_animal/bot/ed209/proc/stun_attack(mob/living/carbon/C)
- playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
+ playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
icon_state = "[lasercolor]ed209-c"
spawn(2)
icon_state = "[lasercolor]ed209[on]"
@@ -558,7 +558,7 @@ Auto Patrol[]"},
/mob/living/simple_animal/bot/ed209/proc/cuff(mob/living/carbon/C)
mode = BOT_ARREST
- playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
+ playsound(src, '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/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index 5249fd5a54f5..f9330c74ebd7 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -2,7 +2,7 @@
name = "\improper Securitron"
desc = "A little security robot. He looks less than thrilled."
icon = 'icons/mob/aibots.dmi'
- icon_state = "secbot0"
+ icon_state = "secbot"
density = FALSE
anchored = FALSE
health = 25
@@ -24,21 +24,21 @@
var/baton_type = /obj/item/melee/baton
var/mob/living/carbon/target
var/oldtarget_name
- var/threatlevel = 0
+ var/threatlevel = FALSE
var/target_lastloc //Loc of target when arrested.
var/last_found //There's a delay
- var/declare_arrests = 1 //When making an arrest, should it notify everyone on the security channel?
- var/idcheck = 0 //If true, arrest people with no IDs
- var/weaponscheck = 0 //If true, arrest people for weapons if they lack access
- var/check_records = 1 //Does it check security records?
- var/arrest_type = 0 //If true, don't handcuff
+ var/declare_arrests = TRUE //When making an arrest, should it notify everyone on the security channel?
+ var/idcheck = FALSE //If true, arrest people with no IDs
+ var/weaponscheck = 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
/mob/living/simple_animal/bot/secbot/beepsky
name = "Officer Beep O'sky"
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
- idcheck = 0
- weaponscheck = 0
- auto_patrol = 1
+ idcheck = FALSE
+ weaponscheck = FALSE
+ auto_patrol = TRUE
/mob/living/simple_animal/bot/secbot/beepsky/jr
name = "Officer Pipsqueak"
@@ -65,7 +65,7 @@
/mob/living/simple_animal/bot/secbot/Initialize()
. = ..()
- icon_state = "secbot[on]"
+ update_icon()
var/datum/job/detective/J = new/datum/job/detective
access_card.access += J.get_access()
prev_access = access_card.access
@@ -74,13 +74,15 @@
var/datum/atom_hud/secsensor = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
secsensor.add_hud_to(src)
-/mob/living/simple_animal/bot/secbot/turn_on()
+/mob/living/simple_animal/bot/secbot/update_icon()
+ if(mode == BOT_HUNT)
+ icon_state = "[initial(icon_state)]-c"
+ return
..()
- icon_state = "secbot[on]"
/mob/living/simple_animal/bot/secbot/turn_off()
..()
- icon_state = "secbot[on]"
+ mode = BOT_IDLE
/mob/living/simple_animal/bot/secbot/bot_reset()
..()
@@ -167,9 +169,14 @@ Auto Patrol: []"},
final = final|JUDGE_EMAGGED
return final
+/mob/living/simple_animal/bot/secbot/proc/special_retaliate_after_attack(mob/user) //allows special actions to take place after being attacked.
+ return
+
/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H)
if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM))
retaliate(H)
+ if(special_retaliate_after_attack(H))
+ return
return ..()
@@ -179,6 +186,8 @@ Auto Patrol: []"},
return
if(!istype(W, /obj/item/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
retaliate(user)
+ if(special_retaliate_after_attack(user))
+ return
/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
..()
@@ -187,8 +196,8 @@ Auto Patrol: []"},
to_chat(user, "You short out [src]'s target assessment circuits.")
oldtarget_name = user.name
audible_message("[src] buzzes oddly!")
- declare_arrests = 0
- icon_state = "secbot[on]"
+ declare_arrests = FALSE
+ update_icon()
/mob/living/simple_animal/bot/secbot/bullet_act(obj/item/projectile/Proj)
if(istype(Proj , /obj/item/projectile/beam)||istype(Proj, /obj/item/projectile/bullet))
@@ -222,7 +231,7 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
mode = BOT_ARREST
- playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
+ playsound(src, '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!")
addtimer(CALLBACK(src, .proc/attempt_handcuff, C), 60)
@@ -236,14 +245,11 @@ Auto Patrol: []"},
playsound(src, "law", 50, 0)
back_to_idle()
-/mob/living/simple_animal/bot/secbot/proc/update_onsprite()
- icon_state = "secbot[on]"
-
/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
var/judgement_criteria = judgement_criteria()
- playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
+ playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
icon_state = "secbot-c"
- addtimer(CALLBACK(src, .proc/update_onsprite), 2)
+ addtimer(CALLBACK(src, .proc/update_icon), 2)
var/threat = 5
if(ishuman(C))
C.stuttering = 5
@@ -384,7 +390,7 @@ Auto Patrol: []"},
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)
+ playsound(src, 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
INVOKE_ASYNC(src, .proc/handle_automated_action)
diff --git a/icons/mob/aibots.dmi b/icons/mob/aibots.dmi
index 74137e8947e4..6278563d6d77 100644
Binary files a/icons/mob/aibots.dmi and b/icons/mob/aibots.dmi differ
diff --git a/sound/effects/beepskyspinsabre.ogg b/sound/effects/beepskyspinsabre.ogg
new file mode 100644
index 000000000000..87be7dae7982
Binary files /dev/null and b/sound/effects/beepskyspinsabre.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index cab978c7a480..5433ae9c668b 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1983,6 +1983,7 @@
#include "code\modules\mob\living\simple_animal\bot\medbot.dm"
#include "code\modules\mob\living\simple_animal\bot\mulebot.dm"
#include "code\modules\mob\living\simple_animal\bot\secbot.dm"
+#include "code\modules\mob\living\simple_animal\bot\SuperBeepsky.dm"
#include "code\modules\mob\living\simple_animal\friendly\butterfly.dm"
#include "code\modules\mob\living\simple_animal\friendly\cat.dm"
#include "code\modules\mob\living\simple_animal\friendly\cockroach.dm"