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"