diff --git a/code/datums/beepsky_fashion.dm b/code/datums/beepsky_fashion.dm
new file mode 100644
index 0000000000..1156822c93
--- /dev/null
+++ b/code/datums/beepsky_fashion.dm
@@ -0,0 +1,221 @@
+//similar to dog_fashion, but for beepsky, who has far more refined fashion tastes
+/datum/beepsky_fashion
+ var/name //not setting the name and desc makes them go to the default
+ var/desc
+
+ var/icon_file = 'icons/mob/secbot_accessories.dmi' //we sell secbots and secbot accessories
+ var/obj_icon_state
+ var/obj_alpha
+ var/obj_color
+
+ var/list/stun_sounds //sound that replaces the stun attack when set
+ var/ignore_sound = FALSE //whether to ignore sounds entirely or not
+
+ //emotes (don't set them if you want the default value)
+ var/death_emote //what is said when beepsky dies
+ var/capture_one //what is said when cuffing someone
+ var/capture_two //what is said when cuffing someone, directly to the person being cuffed
+ var/infraction //the level of threat detected
+ var/taunt // beepsky pointing at a criminal
+ var/attack_one //text when attacking criminal
+ var/attack_two //text when attacking criminal, but directly to the criminal
+ var/patrol_emote //engaging patrol text
+ var/patrol_fail_emote //failing to engage patrol text
+ var/list/arrest_texts //first is for not-cuffing, second is for cuffing
+ var/arrest_emote //text stating that you're cuffing some criminal C with a threat of level X in location Y
+
+ //for reference, the following words are replaced when processed before speech:
+ //LOCATION = the location passed, if any (this is only used by arrest_emote)
+ //CRIMINAL = the name of the criminal (this is used by everything but patrol_emote and infraction)
+ //BOT = the name of the bot (this can be used on any of the emotes)
+ //THREAT_LEVEL = the level of the threat detected (can be used on arrest_emote and infraction)
+
+/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/stun_attack(mob/living/carbon/C) //fired when beepsky does a stun attack with the fashion worn, for sounds/overlays/etc
+ return
+
+//actual fashions from here on out
+/datum/beepsky_fashion/wizard
+ obj_icon_state = "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!"
+ taunt = "BOT points his staff towards CRIMINAL!"
+ attack_one = "BOT casts magic missile on CRIMINAL!"
+ attack_two = "BOT casts magic missile on you!"
+ patrol_emote = "Beginning search for magical disturbances."
+ patrol_fail_emote = "Failure to find magical disturbances. Recallibrating."
+ arrest_emote = "ARREST_TYPE level THREAT_LEVEL magical practitioner CRIMINAL in LOCATION."
+ stun_sounds = list('sound/magic/lightningbolt.ogg',
+ 'sound/magic/fireball.ogg',
+ 'sound/weapons/zapbang.ogg',
+ 'sound/magic/knock.ogg',
+ 'sound/magic/fleshtostone.ogg',
+ 'sound/effects/magic.ogg',
+ 'sound/magic/disintegrate.ogg')
+
+/datum/beepsky_fashion/cowboy
+ obj_icon_state = "cowboy"
+ name = "Sheriff Beepsky"
+ desc = "The sheriff of this here station."
+ capture_one = "BOT is tying CRIMINAL up!"
+ capture_two = "BOT is tying you up!"
+ infraction = "Outlaws with a bounty of THREAT_LEVEL000 space dollars detected!"
+ taunt = "BOT aims his revolver towards CRIMINAL!"
+ attack_one = "BOT unloads his revolver onto CRIMINAL!"
+ attack_two = "BOT unloads his revolver onto you!"
+ patrol_emote = "Engaging bounty hunting protocols."
+ patrol_fail_emote = "Unable to find any bounties due to error. Rebooting."
+ arrest_emote = "ARREST_TYPE outlaw CRIMINAL with a bounty of THREAT_LEVEL000 in LOCATION."
+ stun_sounds = list('sound/weapons/Gunshot.ogg',
+ 'sound/weapons/Gunshot2.ogg',
+ 'sound/weapons/Gunshot3.ogg',
+ 'sound/weapons/Gunshot4.ogg')
+
+/datum/beepsky_fashion/chef
+ obj_icon_state = "chef"
+ name = "Chef Beepsky"
+ desc = "Cooking up the finest foods the station has ever seen."
+ death_emote = "Mamma-mia!"
+ infraction = "Grade THREAT_LEVEL prosciutto detected!"
+ taunt = "BOT glares at CRIMINAL."
+ attack_one = "BOT CQCs CRIMINAL!"
+ attack_two = "BOT CQCs you!"
+ patrol_emote = "Beginning search for the bad prosciutto."
+ patrol_fail_emote = "All prosciutto is stale. Rebooting."
+ arrest_texts = list("Frying", "Grilling") //any good secoff knows the difference
+ arrest_emote = "ARREST_TYPE grade THREAT_LEVEL prosciutto CRIMINAL in LOCATION."
+ stun_sounds = list('sound/weapons/cqchit1.ogg',
+ 'sound/weapons/cqchit2.ogg')
+
+/datum/beepsky_fashion/cat
+ obj_icon_state = "cat"
+ name = "OwOfficer Bweepskwee"
+ desc = "A beepsky unit with cat ears. Catgirl science has gone too far."
+ death_emote = "Nya!"
+ capture_one = "BOT is tying CRIMINAL up!!"
+ capture_two = "BOT is tying you up!"
+ infraction = "Wevel THREAT_LEVEL infwactwion awert!!!"
+ taunt = "BOT points at CRIMINAL and nyas!"
+ attack_one = "BOT shoves CRIMINAL onto a table!"
+ attack_two = "BOT shoves you onto a table!"
+ patrol_emote = "Enwgagwing patwol mwodies.."
+ patrol_fail_emote = "Unawbwle two stwawt patwollies. Nya."
+ arrest_texts = list("Dwetwaining", "Awwesting")
+ arrest_emote = "ARREST_TYPE wevel THREAT_LEVEL scwumbwag CRIMINAL in LOCATION. Nya."
+ ignore_sound = TRUE //we instead make the stunned person fire the nya emote
+
+/datum/beepsky_fashion/cat/stun_attack(var/mob/living/carbon/C) //makes a fake table under you on hit, makes cat people nya when hit
+ if(iscatperson(C))
+ C.emote("nya")
+ var/turf/target_turf = get_turf(C)
+ if(target_turf) //slams you on a fake table
+ playsound(src, 'sound/weapons/sonic_jackhammer.ogg', 50, 1)
+ var/obj/effect/overlay_holder = new(target_turf)
+ overlay_holder.name = "Catboy Table"
+ overlay_holder.desc = "Where bad catboys go."
+ var/image/table_overlay = image('icons/obj/smooth_structures/table.dmi', "table")
+ overlay_holder.add_overlay(table_overlay)
+ QDEL_IN(overlay_holder, 10)
+
+/datum/beepsky_fashion/cake //nothing else. it's just beepsky. with a cake on his head.
+ obj_icon_state = "cake"
+ name = "Cakesky"
+ desc = "It's a secbot, wearing a cake on his head!"
+
+/datum/beepsky_fashion/captain
+ obj_icon_state = "captain"
+ name = "Captainsky"
+ desc = "The real captain of this station."
+ capture_one = "BOT is lecturing CRIMINAL on why he is the captain!"
+ capture_two = "BOT is lecturing you on why he is the captain!"
+ infraction = "Level THREAT_LEVEL greytider detected."
+ attack_one = "BOT beats CRIMINAL with the chain of command!"
+ attack_two = "BOT beats you with the chain of command!"
+ patrol_emote = "Uselessness protocols engaged."
+ patrol_fail_emote = "Unit has been found as useless. Rebooting."
+ arrest_texts = list("Demoting", "Firing")
+ arrest_emote = "ARREST_TYPE level THREAT_LEVEL lesser crewmember CRIMINAL in LOCATION."
+ stun_sounds = list('sound/weapons/chainhit.ogg')
+
+/datum/beepsky_fashion/king
+ obj_icon_state = "king"
+ name = "King Beepsky"
+ desc = "He who has ascended to bare the right of king, sits atop the throne."
+ capture_one = "BOT is calling the guards onto CRIMINAL!"
+ capture_two = "BOT is calling the guards onto you!"
+ infraction = "Treason of level THREAT_LEVEL detected!"
+ attack_one = "BOT strikes CRIMINAL with his kingly authority!"
+ attack_two = "BOT strikes you with his kingly authority!"
+ patrol_emote = "Searching for peasants to beat up."
+ patrol_fail_emote = "Peasants are using dark magic. Recallibrating."
+ arrest_texts = list("Knighting", "Executing")
+ arrest_emote = "ARREST_TYPE level THREAT_LEVEL peasant CRIMINAL in LOCATION."
+ stun_sounds = list('sound/weapons/punch1.ogg',
+ 'sound/weapons/punch2.ogg',
+ 'sound/weapons/punch3.ogg',
+ 'sound/weapons/punch4.ogg')
+
+/datum/beepsky_fashion/pirate
+ obj_icon_state = "pirate"
+ name = "Beepsbeard the Pirate"
+ desc = "Sailor of the seven seas, all sea-faring bots fear the one known as Beepsbeard."
+ capture_one = "BOT is making CRIMINAL walk the plank!"
+ capture_two = "BOT is making you walk the plank!"
+ infraction = "Enemy vessel spotted with threat level THREAT_LEVEL!"
+ attack_one = "BOT strikes CRIMINAL with his cutlass!"
+ attack_two = "BOT strikes you with his cutlass!"
+ patrol_emote = "Searching for enemy vessels to board."
+ patrol_fail_emote = "No way to engage enemy vessels. Rebooting."
+ arrest_texts = list("Boarding", "Sinking")
+ arrest_emote = "ARREST_TYPE level THREAT_LEVEL vessel CRIMINAL in LOCATION."
+ stun_sounds = list('sound/weapons/bladeslice.ogg')
+
+/datum/beepsky_fashion/engineer
+ obj_icon_state = "engineer"
+ name = "Chief Engineer Beepsky"
+ desc = "He fixes criminals with a wrench to the face."
+ capture_one = "BOT is tying CRIMINAL up!"
+ capture_two = "BOT is tying you up!"
+ infraction = "Structural integrity issue spotted with threat level THREAT_LEVEL"
+ attack_one = "BOT strikes CRIMINAL with his wrench!"
+ attack_two = "BOT strikes you with his wrench!"
+ arrest_texts = list("Fixing", "Repairing")
+ arrest_emote = "ARREST_TYPE level THREAT_LEVEL structural issue in LOCATION"
+ stun_sounds = list('sound/weapons/genhit.ogg')
+
+/datum/beepsky_fashion/tophat
+ obj_icon_state = "tophat"
+ name = "Fancy Beepsky"
+ desc = "It's a secbot, wearing a top hat! How fancy."
+
+/datum/beepsky_fashion/fedora
+ obj_icon_state = "fedora"
+ name = "Fedorasky"
+ desc = "It's a secbot, wearing a fedora!"
+
+/datum/beepsky_fashion/sombrero
+ obj_icon_state = "sombrero"
+ name = "Sombrerosky"
+ desc = "A secbot wearing a sombrero. Truly, a hombre to all."
+
+/datum/beepsky_fashion/santa
+ obj_icon_state = "santa"
+ name = "Saint Beepsky"
+ desc = "Have you been a level 7 infraction this holiday season?"
+ capture_one = "BOT is tying CRIMINAL up with fairy lights!"
+ capture_two = "BOT is tying you up with fairy lights!"
+ infraction = "Level THREAT_LEVEL threat to holiday cheer spotted!"
+ attack_one = "BOT crushes CRIMINAL with their holiday spirit!"
+ attack_two = "BOT crushes you with their holiday spirit!"
+ arrest_emote = "ARREST_TYPE level THREAT_LEVEL threat to holiday cheer in LOCATION"
+
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 9682787de5..dc07d5e050 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 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..20cb7cc824 100644
--- a/code/modules/clothing/head/collectable.dm
+++ b/code/modules/clothing/head/collectable.dm
@@ -27,7 +27,9 @@
icon_state = "chef"
item_state = "chef"
dynamic_hair_suffix = ""
+
dog_fashion = /datum/dog_fashion/head/chef
+ beepsky_fashion = /datum/beepsky_fashion/chef
/obj/item/clothing/head/collectable/paper
name = "collectable paper hat"
@@ -42,6 +44,8 @@
icon_state = "tophat"
item_state = "that"
+ beepsky_fashion = /datum/beepsky_fashion/tophat
+
/obj/item/clothing/head/collectable/captain
name = "collectable captain's hat"
desc = "A collectable hat that'll make you look just like a real comdom!"
@@ -49,6 +53,7 @@
item_state = "caphat"
dog_fashion = /datum/dog_fashion/head/captain
+ beepsky_fashion = /datum/beepsky_fashion/captain
/obj/item/clothing/head/collectable/police
name = "collectable police officer's hat"
@@ -91,6 +96,7 @@
item_state = "pirate"
dog_fashion = /datum/dog_fashion/head/pirate
+ beepsky_fashion = /datum/beepsky_fashion/pirate
/obj/item/clothing/head/collectable/kitty
name = "collectable kitty ears"
@@ -100,6 +106,7 @@
dynamic_hair_suffix = ""
dog_fashion = /datum/dog_fashion/head/kitty
+ beepsky_fashion = /datum/beepsky_fashion/cat
/obj/item/clothing/head/collectable/rabbitears
name = "collectable rabbit ears"
@@ -116,6 +123,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/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm
index 80d0b7c8a8..12a4a43ca7 100644
--- a/code/modules/clothing/head/hardhat.dm
+++ b/code/modules/clothing/head/hardhat.dm
@@ -15,6 +15,7 @@
dynamic_hair_suffix = "+generic"
dog_fashion = /datum/dog_fashion/head
+ beepsky_fashion = /datum/beepsky_fashion/engineer
/obj/item/clothing/head/hardhat/ComponentInitialize()
diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm
index 638a0c2f23..5af694ea1b 100644
--- a/code/modules/clothing/head/jobs.dm
+++ b/code/modules/clothing/head/jobs.dm
@@ -13,7 +13,9 @@
strip_delay = 10
equip_delay_other = 10
dynamic_hair_suffix = ""
+
dog_fashion = /datum/dog_fashion/head/chef
+ beepsky_fashion = /datum/beepsky_fashion/chef
/obj/item/clothing/head/chefhat/suicide_act(mob/user)
user.visible_message("[user] is donning [src]! It looks like [user.p_theyre()] trying to become a chef.")
@@ -33,7 +35,9 @@
flags_inv = 0
armor = list("melee" = 40, "bullet" = 30, "laser" = 30, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
strip_delay = 60
+
dog_fashion = /datum/dog_fashion/head/captain
+ beepsky_fashion = /datum/beepsky_fashion/captain
//Captain: This is no longer space-worthy
/obj/item/clothing/head/caphat/parade
diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm
index 416d0d2383..72d0f68c18 100644
--- a/code/modules/clothing/head/misc.dm
+++ b/code/modules/clothing/head/misc.dm
@@ -20,9 +20,11 @@
desc = "It's an amish looking hat."
icon_state = "tophat"
item_state = "that"
- dog_fashion = /datum/dog_fashion/head
throwforce = 1
+ dog_fashion = /datum/dog_fashion/head
+ beepsky_fashion = /datum/beepsky_fashion/tophat
+
/obj/item/clothing/head/canada
name = "striped red tophat"
desc = "It smells like fresh donut holes. / Il sent comme des trous de beignets frais."
@@ -126,7 +128,9 @@
desc = "Yarr."
icon_state = "pirate"
item_state = "pirate"
+
dog_fashion = /datum/dog_fashion/head/pirate
+ beepsky_fashion = /datum/beepsky_fashion/pirate
/obj/item/clothing/head/pirate/captain
name = "pirate captain hat"
@@ -189,6 +193,8 @@
desc = "A really cool hat if you're a mobster. A really lame hat if you're not."
pocket_storage_component_path = /datum/component/storage/concrete/pockets/small
+ beepsky_fashion = /datum/beepsky_fashion/fedora
+
/obj/item/clothing/head/fedora/suicide_act(mob/user)
if(user.gender == FEMALE)
return 0
@@ -205,7 +211,9 @@
item_state = "sombrero"
desc = "You can practically taste the fiesta."
flags_inv = HIDEHAIR
+
dog_fashion = /datum/dog_fashion/head/sombrero
+ beepsky_fashion = /datum/beepsky_fashion/sombrero
/obj/item/clothing/head/sombrero/green
name = "green sombrero"
@@ -213,6 +221,7 @@
item_state = "greensombrero"
desc = "As elegant as a dancing cactus."
flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS
+
dog_fashion = null
/obj/item/clothing/head/sombrero/shamebrero
@@ -220,6 +229,7 @@
icon_state = "shamebrero"
item_state = "shamebrero"
desc = "Once it's on, it never comes off."
+
dog_fashion = null
/obj/item/clothing/head/sombrero/shamebrero/Initialize()
@@ -248,7 +258,9 @@
item_state = "that"
cold_protection = HEAD
min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT
+
dog_fashion = /datum/dog_fashion/head/santa
+ beepsky_fashion = /datum/beepsky_fashion/santa
/obj/item/clothing/head/jester
name = "jester hat"
@@ -286,6 +298,8 @@
resistance_flags = FIRE_PROOF
dynamic_hair_suffix = ""
+ beepsky_fashion = /datum/beepsky_fashion/king
+
/obj/item/clothing/head/crown/fancy
name = "magnificent crown"
desc = "A crown worn by only the highest emperors of the land space."
@@ -391,7 +405,9 @@
name = "cowboy hat"
desc = "A standard brown cowboy hat, yeehaw."
icon_state = "cowboyhat"
- item_state= "cowboyhat"
+ item_state = "cowboyhat"
+
+ beepsky_fashion = /datum/beepsky_fashion/cowboy
/obj/item/clothing/head/cowboyhat/black
name = "black cowboy hat"
diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm
index 54561c8a24..1d9c3dd325 100644
--- a/code/modules/clothing/head/misc_special.dm
+++ b/code/modules/clothing/head/misc_special.dm
@@ -50,6 +50,8 @@
flags_cover = HEADCOVERSEYES
heat = 1000
+ beepsky_fashion = /datum/beepsky_fashion/cake
+
/obj/item/clothing/head/hardhat/cakehat/process()
var/turf/location = src.loc
if(ishuman(location))
@@ -131,6 +133,7 @@
dynamic_hair_suffix = ""
dog_fashion = /datum/dog_fashion/head/kitty
+ beepsky_fashion = /datum/beepsky_fashion/cat
/obj/item/clothing/head/kitty/equipped(mob/living/carbon/human/user, slot)
if(ishuman(user) && slot == SLOT_HEAD)
diff --git a/code/modules/clothing/masks/_masks.dm b/code/modules/clothing/masks/_masks.dm
index 7a5a031e79..94f7ee179a 100644
--- a/code/modules/clothing/masks/_masks.dm
+++ b/code/modules/clothing/masks/_masks.dm
@@ -8,6 +8,7 @@
var/modifies_speech = FALSE
var/mask_adjusted = 0
var/adjusted_flags = null
+ var/datum/beepsky_fashion/beepsky_fashion //the associated datum for applying this to a secbot
/obj/item/clothing/mask/attack_self(mob/user)
if(CHECK_BITFIELD(clothing_flags, VOICEBOX_TOGGLABLE))
diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm
index 94273d2c73..977e916f87 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/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index a347b04e50..3ad19deeac 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -102,6 +102,10 @@
var/can_salute = TRUE
var/salute_delay = 60 SECONDS
+ //emotes/speech stuff
+ var/patrol_emote = "Engaging patrol mode."
+ var/patrol_fail_emote = "Unable to start patrol."
+
/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)
@@ -612,7 +616,7 @@ Pass a positive integer as an argument to override a bot's default speed.
if(tries >= BOT_STEP_MAX_RETRIES) //Bot is trapped, so stop trying to patrol.
auto_patrol = 0
tries = 0
- speak("Unable to start patrol.")
+ speak(patrol_fail_emote)
return
@@ -628,7 +632,7 @@ Pass a positive integer as an argument to override a bot's default speed.
return
mode = BOT_PATROL
else // no patrol target, so need a new one
- speak("Engaging patrol mode.")
+ speak(patrol_emote)
find_patrol_target()
tries++
return
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index cfff3eb751..9d45b96831 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -33,6 +33,20 @@
var/check_records = TRUE //Does it check security records?
var/arrest_type = FALSE //If true, don't handcuff
+ var/obj/item/clothing/head/bot_accessory
+ var/datum/beepsky_fashion/stored_fashion
+
+ //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!"
+ var/list/arrest_texts = list("Detaining", "Arresting")
+ var/arrest_emote = "ARREST_TYPE level THREAT_LEVEL scumbag CRIMINAL in LOCATION."
+
/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 +63,103 @@
resize = 0.8
update_transform()
+/mob/living/simple_animal/bot/secbot/proc/process_emote(var/emote_type, var/atom/criminal, var/threat, var/arrest = -1, var/location)
+ 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_ONE")
+ emote = attack_one
+ if("ATTACK_TWO")
+ emote = attack_two
+ if("ARREST")
+ emote = arrest_emote
+
+ //now replace pieces of the text with the information we have
+ if(emote_type != "TAUNT" && emote_type != "ARREST")
+ emote = replacetext(emote, "BOT", name)
+ else
+ emote = replacetext(emote, "BOT", "[name]") //needs to be bold if its a taunt or an arrest text
+ if(criminal)
+ emote = replacetext(emote, "CRIMINAL", criminal.name)
+ if(threat)
+ emote = replacetext(emote, "THREAT_LEVEL", threat)
+ if(arrest > -1)
+ emote = replacetext(emote, "ARREST_TYPE", arrest_texts[arrest + 1])
+ if(location)
+ emote = replacetext(emote, "LOCATION", location)
+ return emote
+
+/mob/living/simple_animal/bot/secbot/proc/apply_fashion(var/datum/beepsky_fashion/fashion)
+ stored_fashion = new fashion
+ if(stored_fashion.name)
+ name = stored_fashion.name
+
+ if(stored_fashion.desc)
+ desc = stored_fashion.desc
+
+ if(stored_fashion.death_emote)
+ death_emote = stored_fashion.death_emote
+
+ if(stored_fashion.capture_one)
+ capture_one = stored_fashion.capture_one
+
+ if(stored_fashion.capture_two)
+ capture_two = stored_fashion.capture_two
+
+ if(stored_fashion.infraction)
+ infraction = stored_fashion.infraction
+
+ if(stored_fashion.taunt)
+ taunt = stored_fashion.taunt
+
+ if(stored_fashion.attack_one)
+ attack_one = stored_fashion.attack_one
+
+ if(stored_fashion.attack_two)
+ attack_two = stored_fashion.attack_two
+
+ if(stored_fashion.patrol_emote)
+ patrol_emote = stored_fashion.patrol_emote
+
+ if(stored_fashion.patrol_fail_emote)
+ patrol_fail_emote = stored_fashion.patrol_fail_emote
+
+ if(stored_fashion.arrest_texts)
+ arrest_texts = stored_fashion.arrest_texts
+
+ if(stored_fashion.arrest_emote)
+ arrest_emote = stored_fashion.arrest_emote
+
+ regenerate_icons()
+
+/mob/living/simple_animal/bot/secbot/proc/reset_fashion()
+ bot_accessory.forceMove(get_turf(src))
+ //reset all emotes/sounds and name/desc
+ name = initial(name)
+ desc = initial(desc)
+ death_emote = initial(death_emote)
+ capture_one = initial(capture_one)
+ capture_two = initial(capture_two)
+ infraction = initial(infraction)
+ taunt = initial(taunt)
+ attack_one = initial(attack_one)
+ attack_two = initial(attack_two)
+ arrest_texts = initial(arrest_texts)
+ arrest_emote = initial(arrest_emote)
+ patrol_emote = initial(patrol_emote)
+ arrest_texts = initial(arrest_texts)
+ arrest_emote = initial(arrest_emote)
+ bot_accessory = null
+ regenerate_icons()
/mob/living/simple_animal/bot/secbot/beepsky/explode()
var/atom/Tsec = drop_location()
@@ -178,6 +289,11 @@ Auto Patrol: []"},
retaliate(H)
if(special_retaliate_after_attack(H))
return
+ if(H.a_intent == INTENT_HELP && bot_accessory)
+
+ to_chat(H, "You knock [bot_accessory] off of [src]'s head!")
+ reset_fashion()
+ return
return ..()
@@ -185,11 +301,48 @@ 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_accessory)
+ to_chat("\[src] already has an accessory, and the laws of physics disallow him from wearing a second!")
+ return
+
+ if(H.beepsky_fashion)
+ to_chat(user, "You set [H] on [src].")
+ bot_accessory = H
+ H.forceMove(src)
+ apply_fashion(H.beepsky_fashion)
+ 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/regenerate_icons()
+ ..()
+ if(bot_accessory)
+ if(!stored_fashion)
+ stored_fashion = new bot_accessory.beepsky_fashion
+ if(!stored_fashion.obj_icon_state)
+ stored_fashion.obj_icon_state = bot_accessory.icon_state
+ if(!stored_fashion.obj_alpha)
+ stored_fashion.obj_alpha = bot_accessory.alpha
+ if(!stored_fashion.obj_color)
+ stored_fashion.obj_color = bot_accessory.color
+ add_overlay(stored_fashion.get_overlay())
+ else
+ if(stored_fashion)
+ cut_overlay(stored_fashion.get_overlay())
+ stored_fashion = null
+
/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
. = ..()
if(emagged == 2)
@@ -233,8 +386,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)
@@ -249,16 +402,22 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
var/judgement_criteria = judgement_criteria()
- playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
icon_state = "secbot-c"
addtimer(CALLBACK(src, /atom/.proc/update_icon), 2)
var/threat = 5
if(ishuman(C))
+ if(stored_fashion)
+ stored_fashion.stun_attack(C)
+ if(stored_fashion.stun_sounds && !stored_fashion.ignore_sound)
+ playsound(src, pick(stored_fashion.stun_sounds), 50, TRUE, -1)
+ else
+ playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
C.stuttering = 5
C.DefaultCombatKnockdown(100)
var/mob/living/carbon/human/H = C
threat = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
else
+ playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
C.DefaultCombatKnockdown(100)
C.stuttering = 5
threat = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
@@ -266,9 +425,9 @@ Auto Patrol: []"},
log_combat(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 stunned [C]!",\
- "[src] has stunned you!")
+ speak(process_emote("ARREST", C, threat, arrest_type, location), radio_channel)
+ C.visible_message("[process_emote("ATTACK_ONE", C)]",\
+ "[process_emote("ATTACK_TWO", C)]")
/mob/living/simple_animal/bot/secbot/handle_automated_action()
if(!..())
@@ -355,7 +514,6 @@ Auto Patrol: []"},
look_for_perp()
bot_patrol()
-
return
/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
@@ -391,9 +549,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 +566,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_accessories.dmi b/icons/mob/secbot_accessories.dmi
new file mode 100644
index 0000000000..b6c7bad6fa
Binary files /dev/null and b/icons/mob/secbot_accessories.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 2a7156f043..6b3bf6eb88 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -353,6 +353,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"