diff --git a/code/datums/beepsky_fashion.dm b/code/datums/beepsky_fashion.dm
new file mode 100644
index 0000000000..d9de8e6d7f
--- /dev/null
+++ b/code/datums/beepsky_fashion.dm
@@ -0,0 +1,75 @@
+//similar to dog_fashion, but for beepsky, who has far more refined fashion tastes
+/datum/beepsky_fashion
+ var/name
+ var/desc
+
+ var/icon_file = 'icons/mob/secbot_head.dmi'
+ var/obj_icon_state
+ var/obj_alpha
+ var/obj_color
+
+ //emotes
+ var/death_emote
+ var/capture_one
+ var/capture_two
+ var/infraction
+ var/taunt
+ var/attack_one
+ var/attack_two
+
+/datum/beepsky_fashion/proc/get_overlay(var/dir)
+ if(icon_file && obj_icon_state)
+ var/image/beepsky_overlay = image(icon_file, obj_icon_state, dir = dir)
+ beepsky_overlay.alpha = obj_alpha
+ beepsky_overlay.color = obj_color
+ return beepsky_overlay
+
+/datum/beepsky_fashion/proc/apply(mob/living/simple_animal/bot/secbot/beepers) //set the emote depending on the fashion datum, if nothing set, turn it back to how it was initially
+ //assume name and description is always set, because otherwise, what would be the point of beepsky fashion?
+ src.name = name
+ src.desc = desc
+ if(death_emote)
+ beepers.death_emote = death_emote
+ else
+ beepers.death_emote = initial(beepers.death_emote)
+
+ if(capture_one)
+ beepers.capture_one = capture_one
+ else
+ beepers.capture_one = initial(beepers.capture_one)
+
+ if(capture_two)
+ beepers.capture_two = capture_two
+ else
+ beepers.capture_two = initial(beepers.capture_two)
+
+ if(infraction)
+ beepers.infraction = infraction
+ else
+ beepers.infraction = initial(beepers.infraction)
+
+ if(infraction)
+ beepers.taunt = taunt
+ else
+ beepers.taunt = initial(beepers.taunt)
+
+ if(attack_one)
+ beepers.attack_one = attack_one
+ else
+ beepers.attack_one = initial(beepers.attack_one)
+
+ if(attack_two)
+ beepers.attack_two = attack_two
+ else
+ beepers.attack_two = initial(beepers.attack_two)
+
+//actual fashions from here on out
+/datum/beepsky_fashion/wizard
+ name = "Archmage Beepsky"
+ desc = "A secbot stolen from the wizard federation."
+ death_emote = "BOT casts EI NATH on themselves!"
+ capture_one = "BOT is casting cable ties on CRIMINAL!"
+ capture_two = "BOT is casting cable ties on you!"
+ infraction = "Magical disturbance of magnitude THREAT_LEVEL detected!"
+ attack_one = "BOT casts magic missile on CRIMINAL!"
+ attack_two = "BOT casts magic missile on you!"
diff --git a/code/datums/dog_fashion.dm b/code/datums/dog_fashion.dm
index 744f57c391..2e80feac67 100644
--- a/code/datums/dog_fashion.dm
+++ b/code/datums/dog_fashion.dm
@@ -38,7 +38,6 @@
corgI.color = obj_color
return corgI
-
/datum/dog_fashion/head
icon_file = 'icons/mob/corgi_head.dmi'
@@ -53,7 +52,6 @@
name = "Sous chef REAL_NAME"
desc = "Your food will be taste-tested. All of it."
-
/datum/dog_fashion/head/captain
name = "Captain REAL_NAME"
desc = "Probably better than the last captain."
diff --git a/code/modules/clothing/head/_head.dm b/code/modules/clothing/head/_head.dm
index 475e7a4e51..0854d9c270 100644
--- a/code/modules/clothing/head/_head.dm
+++ b/code/modules/clothing/head/_head.dm
@@ -8,6 +8,7 @@
var/blockTracking = 0 //For AI tracking
var/can_toggle = null
dynamic_hair_suffix = "+generic"
+ var/datum/beepsky_fashion/beepsky_fashion //the associated datum for applying this hat to a secbot
/obj/item/clothing/head/Initialize()
. = ..()
diff --git a/code/modules/clothing/head/collectable.dm b/code/modules/clothing/head/collectable.dm
index 314142d0cc..71b3e2e144 100644
--- a/code/modules/clothing/head/collectable.dm
+++ b/code/modules/clothing/head/collectable.dm
@@ -116,6 +116,7 @@
icon_state = "wizard"
dog_fashion = /datum/dog_fashion/head/blue_wizard
+ beepsky_fashion = /datum/beepsky_fashion/wizard
/obj/item/clothing/head/collectable/hardhat
name = "collectable hard hat"
diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm
index 047dc7b7a3..c513168e47 100644
--- a/code/modules/clothing/suits/wiz_robe.dm
+++ b/code/modules/clothing/suits/wiz_robe.dm
@@ -9,6 +9,7 @@
equip_delay_other = 50
resistance_flags = FIRE_PROOF | ACID_PROOF
dog_fashion = /datum/dog_fashion/head/blue_wizard
+ beepsky_fashion = /datum/beepsky_fashion/wizard
var/magic_flags = SPELL_WIZARD_HAT
/obj/item/clothing/head/wizard/ComponentInitialize()
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index cfff3eb751..669828a0e9 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -33,6 +33,17 @@
var/check_records = TRUE //Does it check security records?
var/arrest_type = FALSE //If true, don't handcuff
+ var/obj/item/clothing/head/bot_hat
+
+ //emotes (BOT is replaced with bot name, CRIMINAL with criminal name, THREAT_LEVEL with threat level)
+ var/death_emote = "BOT blows apart!"
+ var/capture_one = "BOT is trying to put zipties on CRIMINAL!"
+ var/capture_two = "BOT is trying to put zipties on you!"
+ var/infraction = "Level THREAT_LEVEL infraction alert!"
+ var/taunt = "BOT points at CRIMINAL!"
+ var/attack_one = "BOT has stunned CRIMINAL!"
+ var/attack_two = "BOT has stunned you!"
+
/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."
@@ -49,6 +60,34 @@
resize = 0.8
update_transform()
+/mob/living/simple_animal/bot/secbot/proc/process_emote(var/emote_type, var/atom/criminal, var/threat)
+ var/emote = "The continuity of space itself collapses around [src]. You should probably report that to someone higher up."
+ switch(emote_type)
+ if("DEATH")
+ emote = death_emote
+ if("CAPTURE_ONE")
+ emote = capture_one
+ if("CAPTURE_TWO")
+ emote = capture_two
+ if("INFRACTION")
+ emote = infraction
+ if("TAUNT")
+ emote = taunt
+ if("ATTACK_PME")
+ emote = attack_one
+ if("ATTACK_TWO")
+ emote = attack_two
+
+ //now replace pieces of the text with the information we have
+ if(!taunt)
+ emote = replacetext(emote, "BOT", name)
+ else
+ emote = replacetext(emote, "BOT", "[name]") //needs to be bold if its a taunt
+ if(criminal)
+ emote = replacetext(emote, "CRIMINAL", criminal.name)
+ if(threat)
+ emote = replacetext(emote, "THREAT_LEVEL", threat)
+ return emote
/mob/living/simple_animal/bot/secbot/beepsky/explode()
var/atom/Tsec = drop_location()
@@ -185,11 +224,38 @@ Auto Patrol: []"},
..()
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/clothing/head))
+ attempt_place_on_head(user, W)
+ 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/proc/attempt_place_on_head(mob/user, obj/item/clothing/head/H)
+ if(user && !user.temporarilyRemoveItemFromInventory(H))
+ to_chat(user, "\The [H] is stuck to your hand, you cannot put it on [src]'s head!")
+ return
+ if(bot_hat)
+ to_chat("\[src] already has a hat, and the laws of physics disallow him from wearing a second!")
+ if(H.beepsky_fashion)
+ bot_hat = H
+ H.forceMove(src)
+ else
+ to_chat(user, "You set [H] on [src]'s head, but it falls off!")
+ H.forceMove(drop_location())
+
+/mob/living/simple_animal/bot/secbot/proc/update_beepsky_fluff()
+ var/datum/beepsky_fashion/BF = new bot_hat.beepsky_fashion
+ if(BF)
+ BF.apply(src)
+
+/mob/living/simple_animal/bot/secbot/regenerate_icons()
+ ..()
+ if(bot_hat)
+ update_beepsky_fluff()
+ add_overlay(bot_hat.beepsky_fashion.get_overlay())
+
/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
. = ..()
if(emagged == 2)
@@ -233,8 +299,8 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
mode = BOT_ARREST
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!")
+ C.visible_message("[process_emote("CAPTURE_ONE", C)]",\
+ "[process_emote("CAPTURE_TWO", C)]")
if(do_after(src, 60, FALSE, C))
attempt_handcuff(C)
@@ -267,8 +333,8 @@ Auto Patrol: []"},
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 stunned [C]!",\
- "[src] has stunned you!")
+ C.visible_message("[process_emote("ATTACK_ONE", C)]",\
+ "[process_emote("ATTACK_TWO", C)]")
/mob/living/simple_animal/bot/secbot/handle_automated_action()
if(!..())
@@ -391,9 +457,9 @@ Auto Patrol: []"},
else if(threatlevel >= 4)
target = C
oldtarget_name = C.name
- speak("Level [threatlevel] infraction alert!")
+ speak(process_emote("INFRACTION", target, threatlevel))
playsound(loc, pick('sound/voice/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE)
- visible_message("[src] points at [C.name]!")
+ visible_message(process_emote("TAUNT", target, threatlevel))
mode = BOT_HUNT
INVOKE_ASYNC(src, .proc/handle_automated_action)
break
@@ -408,7 +474,7 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/explode()
walk_to(src,0)
- visible_message("[src] blows apart!")
+ visible_message("[process_emote("DEATH")]")
var/atom/Tsec = drop_location()
var/obj/item/bot_assembly/secbot/Sa = new (Tsec)
diff --git a/icons/mob/secbot_head.dmi b/icons/mob/secbot_head.dmi
new file mode 100644
index 0000000000..2a246b8e42
Binary files /dev/null and b/icons/mob/secbot_head.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 9314992c5f..4f9e52622a 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -352,6 +352,7 @@
#include "code\datums\ai_laws.dm"
#include "code\datums\armor.dm"
#include "code\datums\beam.dm"
+#include "code\datums\beepsky_fashion.dm"
#include "code\datums\browser.dm"
#include "code\datums\callback.dm"
#include "code\datums\chatmessage.dm"