diff --git a/code/modules/mob/living/simple_animal/bot/griefsky.dm b/code/modules/mob/living/simple_animal/bot/griefsky.dm
new file mode 100644
index 00000000000..0709c2158ae
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/bot/griefsky.dm
@@ -0,0 +1,562 @@
+/mob/living/simple_animal/bot/griefsky
+ name = "\improper General Griefsky"
+ desc = "A little security robot. He looks less than thrilled."
+ icon = 'icons/obj/aibots.dmi'
+ icon_state = "griefsky0"
+ density = 0
+ anchored = 0
+ health = 25
+ maxHealth = 25
+ damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
+ pass_flags = PASSMOB
+
+ radio_channel = "Security" //Security channel
+ bot_type = SEC_BOT
+ bot_filter = RADIO_SECBOT
+ model = "Securitron"
+ bot_purpose = "seek out criminals, handcuff them, and report their location to security"
+ bot_core_type = /obj/machinery/bot_core/secbot
+ window_id = "autosec"
+ window_name = "Automatic Security Unit v9.0"
+ path_image_color = "#FF0000"
+ data_hud_type = DATA_HUD_SECURITY_ADVANCED
+ allow_pai = 0
+
+ var/base_icon = "griefsky"
+ var/mob/living/carbon/target
+ var/oldtarget_name
+ 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 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/harmbaton = 1 //If true, beat instead of stun
+ var/flashing_lights = 0 //If true, flash lights
+ var/prev_flashing_lights = 0 //REMOVE VARS WHEN DONE!!!!!!!!!!!!!PLEASE SACALAS >:/, ya estna en beepsky
+ var/onetime = 0
+
+ var/baton_type = /obj/item/melee/baton
+
+/mob/living/simple_animal/bot/secbot/grievous/Initialize()
+. = ..()
+weapon = new baton_type(src)
+weapon.attack_self(src)
+
+/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/griefsky/explode()
+ var/turf/Tsec = get_turf(src)
+ new /obj/item/stock_parts/cell/potato(Tsec)
+ var/obj/item/reagent_containers/food/drinks/drinkingglass/S = new(Tsec)
+ S.reagents.add_reagent("whiskey", 15)
+ S.on_reagent_change()
+ ..()
+
+/mob/living/simple_animal/bot/griefsky/New()
+ ..()
+ icon_state = "[base_icon][on]"
+ spawn(3)
+ var/datum/job/detective/J = new/datum/job/detective
+ access_card.access += J.get_access()
+ prev_access = access_card.access
+
+ //SECHUD
+ var/datum/atom_hud/secsensor = huds[DATA_HUD_SECURITY_ADVANCED]
+ secsensor.add_hud_to(src)
+ permanent_huds |= secsensor
+
+/mob/living/simple_animal/bot/griefsky/turn_on()
+ ..()
+ icon_state = "[base_icon][on]"
+
+/mob/living/simple_animal/bot/griefsky/turn_off()
+ ..()
+ icon_state = "[base_icon][on]"
+
+/mob/living/simple_animal/bot/griefsky/bot_reset()
+ ..()
+ target = null
+ oldtarget_name = null
+ anchored = 0
+ walk_to(src,0)
+ last_found = world.time
+
+/mob/living/simple_animal/bot/griefsky/set_custom_texts()
+
+ text_hack = "You overload [name]'s target identification system."
+ text_dehack = "You reboot [name] and restore the target identification."
+ text_dehack_fail = "[name] refuses to accept your authority!"
+
+/mob/living/simple_animal/bot/griefsky/get_controls(mob/user)
+ var/dat
+ dat += hack(user)
+ dat += showpai(user)
+ dat += text({"
+Securitron v1.6 controls
+Status: []
+Behaviour controls are [locked ? "locked" : "unlocked"]
+Maintenance panel panel is [open ? "opened" : "closed"]"},
+
+"[on ? "On" : "Off"]" )
+
+ if(!locked || issilicon(user) || user.can_admin_interact())
+ dat += text({"
+Arrest Unidentifiable Persons: []
+Arrest for Unauthorized Weapons: []
+Arrest for Warrant: []
+Operating Mode: []
+Report Arrests[]
+Auto Patrol: []"},
+
+"[idcheck ? "Yes" : "No"]",
+"[weaponscheck ? "Yes" : "No"]",
+"[check_records ? "Yes" : "No"]",
+"[arrest_type ? "Detain" : "Arrest"]",
+"[declare_arrests ? "Yes" : "No"]",
+"[auto_patrol ? "On" : "Off"]" )
+
+ return dat
+
+/mob/living/simple_animal/bot/griefsky/Topic(href, href_list)
+ if(..())
+ return 1
+
+ switch(href_list["operation"])
+ if("idcheck")
+ idcheck = !idcheck
+ update_controls()
+ if("weaponscheck")
+ weaponscheck = !weaponscheck
+ update_controls()
+ if("ignorerec")
+ check_records = !check_records
+ update_controls()
+ if("switchmode")
+ arrest_type = !arrest_type
+ update_controls()
+ if("declarearrests")
+ declare_arrests = !declare_arrests
+ update_controls()
+
+ /*
+
+/mob/living/simple_animal/bot/griefsky/proc/retaliate(mob/living/carbon/human/H)
+ threatlevel = H.assess_threat(src)
+ threatlevel += 6
+ if(threatlevel >= 4)
+ target = H
+ mode = BOT_HUNT
+
+/mob/living/simple_animal/bot/griefsky/attack_hand(mob/living/carbon/human/H)
+ if(H.a_intent == INTENT_HARM || H.a_intent == INTENT_DISARM)
+ retaliate(H)
+ return ..()
+
+/mob/living/simple_animal/bot/griefsky/attackby(obj/item/W, mob/user, params)
+ ..()
+ if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry.
+ 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)
+
+/mob/living/simple_animal/bot/griefsky/emag_act(mob/user)
+ ..()
+ if(emagged == 2)
+ if(user)
+ 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 = "[base_icon][on]"
+
+/mob/living/simple_animal/bot/griefsky/bullet_act(obj/item/projectile/Proj)
+ if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet))
+ if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
+ if(!Proj.nodamage && Proj.damage < src.health)
+ retaliate(Proj.firer)
+ ..()
+
+
+/mob/living/simple_animal/bot/griefsky/UnarmedAttack(atom/A)
+ if(!on)
+ return
+ if(iscarbon(A))
+ var/mob/living/carbon/C = A
+ if(!C.stunned || arrest_type)
+ stun_attack(A)
+ else if(C.canBeHandcuffed() && !C.handcuffed)
+ cuff(A)
+ else
+ ..()
+
+
+/mob/living/simple_animal/bot/griefsky/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0)
+ if(istype(AM, /obj/item))
+ var/obj/item/I = AM
+ if(I.throwforce < src.health && I.thrownby && ishuman(I.thrownby))
+ var/mob/living/carbon/human/H = I.thrownby
+ retaliate(H)
+ ..()
+
+
+/mob/living/simple_animal/bot/griefsky/proc/cuff(mob/living/carbon/C)
+ mode = BOT_ARREST
+ playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
+ C.visible_message("[src] is trying to put zipties on [C]!",\
+ "[src] is trying to put zipties on you!")
+ spawn(60)
+ if( !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
+ return
+ if(!C.handcuffed)
+ 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()
+
+/mob/living/simple_animal/bot/griefsky/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)
+ spawn(2)
+ icon_state = "[base_icon][on]"
+ var/threat = C.assess_threat(src)
+ if(ishuman(C) && harmbaton) // Bots with harmbaton enabled become shitcurity. - Dave
+ C.apply_damage(10, BRUTE)
+ C.SetStuttering(5)
+ C.Stun(5)
+ C.Weaken(5)
+ add_attack_logs(src, C, "stunned")
+ if(declare_arrests)
+ var/area/location = get_area(src)
+ speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag [C] in [location].", radio_channel)
+ C.visible_message("[src] has [harmbaton ? "beaten" : "stunned"] [C]!",\
+ "[src] has [harmbaton ? "beaten" : "stunned"] you!")
+
+/mob/living/simple_animal/bot/griefsky/Life(seconds, times_fired)
+ . = ..()
+ if(flashing_lights)
+ switch(light_color)
+ if(LIGHT_COLOR_PURE_RED)
+ light_color = LIGHT_COLOR_PURE_BLUE
+ if(LIGHT_COLOR_PURE_BLUE)
+ light_color = LIGHT_COLOR_PURE_RED
+ update_light()
+ else if(prev_flashing_lights)
+ light_color = LIGHT_COLOR_PURE_RED
+ update_light()
+
+ prev_flashing_lights = flashing_lights
+
+/mob/living/simple_animal/bot/griefsky/verb/toggle_flashing_lights()
+ set name = "Toggle Flashing Lights"
+ set category = "Object"
+ set src = usr
+
+ flashing_lights = !flashing_lights
+
+/mob/living/simple_animal/bot/griefsky/handle_automated_action()
+ if(!..())
+ return
+
+ flashing_lights = mode == BOT_HUNT
+
+ switch(mode)
+ if(BOT_IDLE) // idle
+ 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
+ // if can't reach perp for long enough, go idle
+ if(frustration >= 8)
+ 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
+ stun_attack(target)
+
+ mode = BOT_PREP_ARREST
+ anchored = 1
+ 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
+ back_to_idle()
+
+ if(BOT_PREP_ARREST) // preparing to arrest target
+ icon_state = "griefsky-c"
+ // 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) || target.weakened < 2 )
+ 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
+ back_to_idle()
+ return
+
+ if(BOT_ARREST)
+ if(!target)
+ anchored = 0
+ mode = BOT_IDLE
+ last_found = world.time
+ frustration = 0
+ return
+
+ if(target.handcuffed) //no target or target cuffed? back to idle.
+ back_to_idle()
+ return
+
+ if(!Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && target.weakened < 2)) //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 = 0
+
+ if(BOT_START_PATROL)
+ look_for_perp()
+ start_patrol()
+
+ if(BOT_PATROL)
+ look_for_perp()
+ bot_patrol()
+
+
+ return
+
+/mob/living/simple_animal/bot/griefsky/proc/back_to_idle()
+ anchored = 0
+ mode = BOT_IDLE
+ target = null
+ last_found = world.time
+ frustration = 0
+ spawn(0)
+ handle_automated_action() //ensure bot quickly responds
+
+/mob/living/simple_animal/bot/griefsky/proc/back_to_hunt()
+ anchored = 0
+ frustration = 0
+ mode = BOT_HUNT
+ spawn(0)
+ handle_automated_action() //ensure bot quickly responds
+// look for a criminal in view of the bot
+
+/mob/living/simple_animal/bot/griefsky/proc/look_for_perp()
+ anchored = 0
+ 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(src)
+
+ if(!threatlevel)
+ 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("[src] points at [C.name]!")
+ mode = BOT_HUNT
+ icon_state = "griefsky-c"
+ spawn(0)
+ handle_automated_action() // ensure bot quickly responds to a perp
+ break
+ else
+ continue
+/mob/living/simple_animal/bot/griefsky/proc/check_for_weapons(var/obj/item/slot_item)
+ if(slot_item && slot_item.needs_permit)
+ return 1
+ return 0
+
+/*/mob/living/simple_animal/bot/griefsky/explode()
+
+ walk_to(src,0)
+ visible_message("[src] blows apart!")
+ var/turf/Tsec = get_turf(src)
+
+ var/obj/item/griefsky_assembly/Sa = new /obj/item/griefsky_assembly(Tsec)
+ Sa.build_step = 1
+ Sa.overlays += "hs_hole"
+ Sa.created_name = name
+ new /obj/item/assembly/prox_sensor(Tsec)
+ new /obj/item/melee/baton(Tsec)
+
+ if(prob(50))
+ new /obj/item/robot_parts/l_arm(Tsec)
+
+ do_sparks(3, 1, src)
+
+ new /obj/effect/decal/cleanable/blood/oil(loc)
+ ..()*/
+
+/mob/living/simple_animal/bot/griefsky/attack_alien(var/mob/living/carbon/alien/user as mob)
+ ..()
+ if(!isalien(target))
+ target = user
+ mode = BOT_HUNT
+
+/mob/living/simple_animal/bot/griefsky/Crossed(atom/movable/AM)
+ if(ismob(AM) && target)
+ var/mob/living/carbon/C = AM
+ if(!istype(C) || !C || in_range(src, target))
+ return
+ C.visible_message("[pick( \
+ "[C] dives out of [src]'s way!", \
+ "[C] stumbles over [src]!", \
+ "[C] jumps out of [src]'s path!", \
+ "[C] trips over [src] and falls!", \
+ "[C] topples over [src]!", \
+ "[C] leaps out of [src]'s way!")]")
+ C.Weaken(2)
+ return
+ ..() */
+
+ /mob/living/simple_animal/bot/secbot/griefsky/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/griefsky/Initialize()
+ . = ..()
+ weapon = new baton_type(src)
+ weapon.attack_self(src)
+
+/mob/living/simple_animal/bot/secbot/griefsky/Destroy()
+ QDEL_NULL(weapon)
+ return ..()
+
+/mob/living/simple_animal/bot/secbot/griefsky/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/griefsky/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/griefsky/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/griefsky/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/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE)
+ playsound(src,'sound/weapons/saberon.ogg',50,TRUE,-1)
+ visible_message("[src] ignites his energy swords!")
+ icon_state = "griefsky-c"
+ visible_message("[src] points at [C.name]!")
+ mode = BOT_HUNT
+ INVOKE_ASYNC(src, .proc/handle_automated_action)
+ break
+ else
+ continue
+
+/obj/machinery/bot_core/secbot
+ req_access = list(access_security)
\ No newline at end of file
diff --git a/icons/obj/aibots.dmi b/icons/obj/aibots.dmi
index 14ac2d95ac9..8b062c0bb58 100644
Binary files a/icons/obj/aibots.dmi and b/icons/obj/aibots.dmi differ
diff --git a/paradise.dme b/paradise.dme
index 9e36bf7b5af..a45839b77a4 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -1843,6 +1843,7 @@
#include "code\modules\mob\living\simple_animal\bot\emote.dm"
#include "code\modules\mob\living\simple_animal\bot\floorbot.dm"
#include "code\modules\mob\living\simple_animal\bot\honkbot.dm"
+#include "code\modules\mob\living\simple_animal\bot\griefsky.dm"
#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"