diff --git a/code/controllers/subsystem/traumas.dm b/code/controllers/subsystem/traumas.dm
index 1dea40a802..47b93928d4 100644
--- a/code/controllers/subsystem/traumas.dm
+++ b/code/controllers/subsystem/traumas.dm
@@ -158,8 +158,8 @@ SUBSYSTEM_DEF(traumas)
/obj/item/clothing/head/frenchberet, /obj/item/clothing/suit/suspenders, /obj/item/reagent_containers/food/drinks/bottle/bottleofnothing,
/obj/item/storage/backpack/mime, /obj/item/reagent_containers/food/snacks/grown/banana/mime,
/obj/item/grown/bananapeel/mimanapeel, /obj/item/cartridge/virus/mime, /obj/item/clothing/shoes/sneakers/mime,
- /obj/item/bedsheet/mime, /obj/item/reagent_containers/food/snacks/burger/mime, /obj/item/clothing/head/beret, /obj/item/clothing/mask/gas/sexymime,
- /obj/item/clothing/under/rank/civilian/mime/sexy, /obj/item/toy/figure/mime, /obj/item/toy/crayon/mime, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced, /obj/mecha/combat/reticence)),
+ /obj/item/bedsheet/mime, /obj/item/reagent_containers/food/snacks/burger/mime, /obj/item/clothing/head/beret,
+ /obj/item/toy/figure/mime, /obj/item/toy/crayon/mime, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced, /obj/mecha/combat/reticence)),
"cats" = typecacheof(list(/obj/item/organ/ears/cat, /obj/item/organ/tail/cat, /obj/item/laser_pointer, /obj/item/toy/cattoy, /obj/item/clothing/head/kitty,
/obj/item/clothing/head/collectable/kitty, /obj/item/melee/chainofcommand/tailwhip/kitty, /obj/item/stack/sheet/animalhide/cat)),
diff --git a/code/datums/action.dm b/code/datums/action.dm
index fbf7487e4d..4e65a0a698 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -273,6 +273,13 @@
if(istype(H))
H.toggle_welding_screen(owner)
+/datum/action/item_action/toggle_welding_screen/plasmaman
+
+/datum/action/item_action/toggle_welding_screen/plasmaman/Trigger()
+ var/obj/item/clothing/head/helmet/space/plasmaman/H = target
+ if(istype(H))
+ H.toggle_welding_screen(owner)
+
/datum/action/item_action/toggle_headphones
name = "Toggle Headphones"
desc = "UNTZ UNTZ UNTZ"
diff --git a/code/game/objects/effects/spawners/bundle.dm b/code/game/objects/effects/spawners/bundle.dm
index b75df644eb..4304fc3c9c 100644
--- a/code/game/objects/effects/spawners/bundle.dm
+++ b/code/game/objects/effects/spawners/bundle.dm
@@ -160,13 +160,13 @@
/obj/effect/spawner/bundle/costume/sexyclown
name = "sexy clown costume spawner"
items = list(
- /obj/item/clothing/mask/gas/sexyclown,
+ /obj/item/clothing/mask/gas/clown_hat/sexy,
/obj/item/clothing/under/rank/civilian/clown/sexy)
/obj/effect/spawner/bundle/costume/sexymime
name = "sexy mime costume spawner"
items = list(
- /obj/item/clothing/mask/gas/sexymime,
+ /obj/item/clothing/mask/gas/mime/sexy,
/obj/item/clothing/under/rank/civilian/mime/sexy)
/obj/effect/spawner/bundle/crate/Initialize(mapload)
diff --git a/code/modules/clothing/masks/_masks.dm b/code/modules/clothing/masks/_masks.dm
index 94f7ee179a..c4063108db 100644
--- a/code/modules/clothing/masks/_masks.dm
+++ b/code/modules/clothing/masks/_masks.dm
@@ -44,30 +44,38 @@
var/mob/M = loc
M.update_inv_wear_mask()
-//Proc that moves gas/breath masks out of the way, disabling them and allowing pill/food consumption
-/obj/item/clothing/mask/proc/adjustmask(mob/living/user)
+/**
+ * Proc that moves gas/breath masks out of the way, disabling them and allowing pill/food consumption
+ * The flavor_details variable is for masks that use this function only to toggle HIDEFACE for identity.
+ */
+/obj/item/clothing/mask/proc/adjustmask(mob/living/user, just_flavor = FALSE)
if(user && user.incapacitated())
- return
+ return FALSE
mask_adjusted = !mask_adjusted
if(!mask_adjusted)
- src.icon_state = initial(icon_state)
- gas_transfer_coefficient = initial(gas_transfer_coefficient)
- permeability_coefficient = initial(permeability_coefficient)
- clothing_flags |= visor_flags
+ if(!just_flavor)
+ src.icon_state = initial(icon_state)
+ gas_transfer_coefficient = initial(gas_transfer_coefficient)
+ permeability_coefficient = initial(permeability_coefficient)
+ slot_flags = initial(slot_flags)
+ flags_cover |= visor_flags_cover
+ clothing_flags |= visor_flags
flags_inv |= visor_flags_inv
- flags_cover |= visor_flags_cover
- to_chat(user, "You push \the [src] back into place.")
- slot_flags = initial(slot_flags)
else
- icon_state += "_up"
- to_chat(user, "You push \the [src] out of the way.")
- gas_transfer_coefficient = null
- permeability_coefficient = null
- clothing_flags &= ~visor_flags
+ if(!just_flavor)
+ icon_state += "_up"
+ gas_transfer_coefficient = null
+ permeability_coefficient = null
+ clothing_flags &= ~visor_flags
+ flags_cover &= ~visor_flags_cover
+ if(adjusted_flags)
+ slot_flags = adjusted_flags
flags_inv &= ~visor_flags_inv
- flags_cover &= ~visor_flags_cover
- if(adjusted_flags)
- slot_flags = adjusted_flags
if(user)
- user.wear_mask_update(src, toggle_off = mask_adjusted)
- user.update_action_buttons_icon() //when mask is adjusted out, we update all buttons icon so the user's potential internal tank correctly shows as off.
+ if(!just_flavor)
+ to_chat(user, "You push \the [src] [mask_adjusted ? "out of the way" : "back into place"].")
+ user.wear_mask_update(src, toggle_off = mask_adjusted)
+ user.update_action_buttons_icon() //when mask is adjusted out, we update all buttons icon so the user's potential internal tank correctly shows as off.
+ else
+ to_chat(usr, "You adjust [src], it will now [mask_adjusted ? "not" : ""] obscure your identity while worn.")
+ return TRUE
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index 4c26a0863e..0d1b6861c8 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -72,18 +72,29 @@
flags_cover = MASKCOVERSEYES
resistance_flags = FLAMMABLE
actions_types = list(/datum/action/item_action/adjust)
+ visor_flags_inv = HIDEFACE
dog_fashion = /datum/dog_fashion/head/clown
- var/list/clownmask_designs = list()
+ var/static/list/clownmask_designs = list()
/obj/item/clothing/mask/gas/clown_hat/Initialize(mapload)
.=..()
- clownmask_designs = list(
- "True Form" = image(icon = src.icon, icon_state = "clown"),
- "The Feminist" = image(icon = src.icon, icon_state = "sexyclown"),
- "The Jester" = image(icon = src.icon, icon_state = "chaos"),
- "The Madman" = image(icon = src.icon, icon_state = "joker"),
- "The Rainbow Color" = image(icon = src.icon, icon_state = "rainbow")
- )
+ if(!clownmask_designs)
+ clownmask_designs = list(
+ "True Form" = image(icon = src.icon, icon_state = "clown"),
+ "The Feminist" = image(icon = src.icon, icon_state = "sexyclown"),
+ "The Jester" = image(icon = src.icon, icon_state = "chaos"),
+ "The Madman" = image(icon = src.icon, icon_state = "joker"),
+ "The Rainbow Color" = image(icon = src.icon, icon_state = "rainbow")
+ )
+
+/obj/item/clothing/mask/gas/clown_hat/examine(mob/user)
+ . = ..()
+ . += "Alt-click to toggle identity concealment. it's currently [flags_inv & HIDEFACE ? "on" : "off"]."
+
+/obj/item/clothing/mask/gas/clown_hat/AltClick(mob/user)
+ . = ..()
+ if(adjustmask(user, TRUE))
+ return TRUE
/obj/item/clothing/mask/gas/clown_hat/ui_action_click(mob/user)
if(!istype(user) || user.incapacitated())
@@ -103,14 +114,12 @@
to_chat(user, "Your Clown Mask has now morphed into [choice], all praise the Honkmother!")
return TRUE
-/obj/item/clothing/mask/gas/sexyclown
+/obj/item/clothing/mask/gas/clown_hat/sexy
name = "sexy-clown wig and mask"
desc = "A feminine clown mask for the dabbling crossdressers or female entertainers."
- clothing_flags = ALLOWINTERNALS
icon_state = "sexyclown"
item_state = "sexyclown"
- flags_cover = MASKCOVERSEYES
- resistance_flags = FLAMMABLE
+ actions_types = list()
/obj/item/clothing/mask/gas/mime
name = "mime mask"
@@ -121,18 +130,27 @@
flags_cover = MASKCOVERSEYES
resistance_flags = FLAMMABLE
actions_types = list(/datum/action/item_action/adjust)
- var/list/mimemask_designs = list()
+ visor_flags_inv = HIDEFACE
+ var/static/list/mimemask_designs = list()
+/obj/item/clothing/mask/gas/mime/examine(mob/user)
+ . = ..()
+ . += "Alt-click to toggle identity concealment. it's currently [flags_inv & HIDEFACE ? "on" : "off"]."
+
+/obj/item/clothing/mask/gas/mime/AltClick(mob/user)
+ . = ..()
+ if(adjustmask(user, TRUE))
+ return TRUE
/obj/item/clothing/mask/gas/mime/Initialize(mapload)
.=..()
- mimemask_designs = list(
- "Blanc" = image(icon = src.icon, icon_state = "mime"),
- "Excité" = image(icon = src.icon, icon_state = "sexymime"),
- "Triste" = image(icon = src.icon, icon_state = "sadmime"),
- "Effrayé" = image(icon = src.icon, icon_state = "scaredmime")
- )
-
+ if(!mimemask_designs)
+ mimemask_designs = list(
+ "Blanc" = image(icon = src.icon, icon_state = "mime"),
+ "Excité" = image(icon = src.icon, icon_state = "sexymime"),
+ "Triste" = image(icon = src.icon, icon_state = "sadmime"),
+ "Effrayé" = image(icon = src.icon, icon_state = "scaredmime")
+ )
/obj/item/clothing/mask/gas/mime/ui_action_click(mob/user)
if(!istype(user) || user.incapacitated())
@@ -151,6 +169,13 @@
to_chat(user, "Your Mime Mask has now morphed into [choice]!")
return TRUE
+/obj/item/clothing/mask/gas/mime/sexy
+ name = "sexy mime mask"
+ desc = "A traditional female mime's mask."
+ icon_state = "sexymime"
+ item_state = "sexymime"
+ actions_types = list()
+
/obj/item/clothing/mask/gas/monkeymask
name = "monkey mask"
desc = "A mask used when acting as a monkey."
@@ -160,15 +185,6 @@
flags_cover = MASKCOVERSEYES
resistance_flags = FLAMMABLE
-/obj/item/clothing/mask/gas/sexymime
- name = "sexy mime mask"
- desc = "A traditional female mime's mask."
- clothing_flags = ALLOWINTERNALS
- icon_state = "sexymime"
- item_state = "sexymime"
- flags_cover = MASKCOVERSEYES
- resistance_flags = FLAMMABLE
-
/obj/item/clothing/mask/gas/death_commando
name = "Death Commando Mask"
icon_state = "death_commando_mask"
diff --git a/code/modules/clothing/spacesuits/plasmamen.dm b/code/modules/clothing/spacesuits/plasmamen.dm
index 5128f77433..b50c2b45db 100644
--- a/code/modules/clothing/spacesuits/plasmamen.dm
+++ b/code/modules/clothing/spacesuits/plasmamen.dm
@@ -40,37 +40,115 @@
icon_state = "plasmaman-helm"
item_state = "plasmaman-helm"
strip_delay = 80
+ flash_protect = 2
+ tint = 2
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 0, "fire" = 100, "acid" = 75, "wound" = 10)
resistance_flags = FIRE_PROOF
var/brightness_on = 4 //luminosity when the light is on
- var/on = FALSE
+ var/helmet_on = FALSE
+ var/smile = FALSE
+ var/smile_color = "#FF0000"
var/light_overlay = "envirohelm-light"
- actions_types = list(/datum/action/item_action/toggle_helmet_light)
+ var/visor_icon = "envisor"
+ var/smile_state = "envirohelm_smile"
+ actions_types = list(/datum/action/item_action/toggle_helmet_light, /datum/action/item_action/toggle_welding_screen/plasmaman)
+ visor_vars_to_toggle = VISOR_FLASHPROTECT | VISOR_TINT
+ flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT
+ flags_cover = HEADCOVERSMOUTH|HEADCOVERSEYES
+ visor_flags_inv = HIDEEYES|HIDEFACE|HIDEFACIALHAIR
mutantrace_variation = NONE
+/obj/item/clothing/head/helmet/space/plasmaman/Initialize()
+ . = ..()
+ visor_toggling()
+ update_icon()
+
+/obj/item/clothing/head/helmet/space/plasmaman/ComponentInitialize()
+ . = ..()
+ RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, .proc/wipe_that_smile_off_your_face)
+ AddElement(/datum/element/update_icon_updates_onmob)
+
+/obj/item/clothing/head/helmet/space/plasmaman/AltClick(mob/user)
+ . = ..()
+ if(user.canUseTopic(src, BE_CLOSE))
+ toggle_welding_screen(user)
+ return TRUE
+
+/obj/item/clothing/head/helmet/space/plasmaman/proc/toggle_welding_screen(mob/living/user)
+ if(weldingvisortoggle(user))
+ if(helmet_on)
+ to_chat(user, "Your helmet's torch can't pass through your welding visor!")
+ helmet_on = FALSE
+ set_light(0)
+ playsound(src, 'sound/mecha/mechmove03.ogg', 50, TRUE) //Visors don't just come from nothing
+ update_icon()
+
+/obj/item/clothing/head/helmet/space/plasmaman/update_overlays()
+ . = ..()
+ if(!up)
+ . += visor_icon
+ if(helmet_on)
+ . += light_overlay
+ if(smile)
+ var/mutable_appearance/M = mutable_appearance(icon, smile_state)
+ M.color = smile_color
+ . += M
+
+/obj/item/clothing/head/helmet/space/plasmaman/attackby(obj/item/C, mob/living/user)
+ . = ..()
+ if(istype(C, /obj/item/toy/crayon))
+ if(!smile)
+ var/obj/item/toy/crayon/CR = C
+ to_chat(user, "You start drawing a smiley face on the helmet's visor..")
+ if(do_after(user, 25, target = src))
+ smile = TRUE
+ smile_color = CR.paint_color
+ to_chat(user, "You draw a smiley on the helmet visor.")
+ update_icon()
+ else
+ to_chat(user, "Seems like someone already drew something on this helmet's visor!")
+
+///gets called when receiving the CLEAN_ACT signal from something, i.e soap or a shower. exists to remove any smiley faces drawn on the helmet.
+/obj/item/clothing/head/helmet/space/plasmaman/proc/wipe_that_smile_off_your_face()
+ if(smile)
+ smile = FALSE
+ update_icon()
+
/obj/item/clothing/head/helmet/space/plasmaman/attack_self(mob/user)
if(!light_overlay)
return
- on = !on
- if(!on)
- cut_overlay(light_overlay)
- else
- add_overlay(light_overlay)
- user.update_inv_head() //So the mob overlay updates
+ if(!up)
+ to_chat(user, "Your helmet's torch can't pass through your welding visor!")
+ return
+ helmet_on = !helmet_on
- if(on)
+ if(helmet_on)
set_light(brightness_on, 0.8, "#FFCC66")
else
set_light(0)
- for(var/X in actions)
- var/datum/action/A=X
- A.UpdateButtonIcon()
+ update_icon()
+
+/obj/item/clothing/head/helmet/space/plasmaman/visor_toggling() //handles all the actual toggling of flags
+ up = !up
+ clothing_flags ^= visor_flags
+ flags_inv ^= visor_flags_inv
+ if(visor_vars_to_toggle & VISOR_FLASHPROTECT)
+ flash_protect ^= initial(flash_protect)
+ if(visor_vars_to_toggle & VISOR_TINT)
+ tint ^= initial(tint)
/obj/item/clothing/head/helmet/space/plasmaman/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE)
. = ..()
- if(!isinhands && on)
- . += mutable_appearance(icon_file, light_overlay)
+ if(!isinhands)
+ if(smile)
+ var/mutable_appearance/M = mutable_appearance(icon_file, smile_state)
+ M.color = smile_color
+ . += M
+ if(!up)
+ . += mutable_appearance(icon_file, visor_icon)
+ if(helmet_on)
+ . += mutable_appearance(icon_file, light_overlay)
/obj/item/clothing/head/helmet/space/plasmaman/security
name = "security plasma envirosuit helmet"
@@ -170,6 +248,7 @@
desc = "A khaki helmet given to plasmamen miners operating on lavaland."
icon_state = "explorer_envirohelm"
item_state = "explorer_envirohelm"
+ visor_icon = "explorer_envisor"
/obj/item/clothing/head/helmet/space/plasmaman/chaplain
name = "chaplain's plasma envirosuit helmet"
@@ -202,7 +281,9 @@
icon_state = "prototype_envirohelm"
item_state = "prototype_envirohelm"
light_overlay = null
- actions_types = list()
+ actions_types = list(/datum/action/item_action/toggle_welding_screen/plasmaman)
+ smile_state = "prototype_smile"
+ visor_icon = "prototype_envisor"
/obj/item/clothing/head/helmet/space/plasmaman/botany
name = "botany plasma envirosuit helmet"
@@ -222,6 +303,7 @@
icon_state = "mime_envirohelm"
item_state = "mime_envirohelm"
light_overlay = "mime_envirohelm-light"
+ visor_icon = "mime_envisor"
/obj/item/clothing/head/helmet/space/plasmaman/clown
name = "clown envirosuit helmet"
@@ -229,3 +311,6 @@
icon_state = "clown_envirohelm"
item_state = "clown_envirohelm"
light_overlay = "clown_envirohelm-light"
+ item_state = "clown_envirohelm"
+ visor_icon = "clown_envisor"
+ smile_state = "clown_smile"
diff --git a/code/modules/vending/autodrobe.dm b/code/modules/vending/autodrobe.dm
index 14cdd30931..b4490f715b 100644
--- a/code/modules/vending/autodrobe.dm
+++ b/code/modules/vending/autodrobe.dm
@@ -74,9 +74,9 @@
/obj/item/staff = 3,
/obj/item/clothing/under/rank/civilian/mime/skirt = 1,
/obj/item/clothing/under/rank/captain/suit/skirt = 1,
- /obj/item/clothing/mask/gas/sexyclown = 1,
+ /obj/item/clothing/mask/gas/clown_hat/sexy = 1,
/obj/item/clothing/under/rank/civilian/clown/sexy = 1,
- /obj/item/clothing/mask/gas/sexymime = 1,
+ /obj/item/clothing/mask/gas/mime/sexy = 1,
/obj/item/clothing/under/rank/civilian/mime/sexy = 1,
/obj/item/clothing/mask/rat/bat = 1,
/obj/item/clothing/mask/rat/bee = 1,
diff --git a/html/changelogs/AutoChangeLog-pr-13581.yml b/html/changelogs/AutoChangeLog-pr-13581.yml
new file mode 100644
index 0000000000..42db54450b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13581.yml
@@ -0,0 +1,6 @@
+author: "Ghommie, porting PRs by MMMiracles and pireamaineach, credits to BlueWildrose too."
+delete-after: True
+changes:
+ - rscadd: "You can now draw on plasmaman helmets with a crayon to turn their frown upside-down."
+ - balance: "Plasmaman helmets no longer hide your identity when worn by themselves."
+ - balance: "Plasmaman helmets now have welding visors, which can't stack with their torches in the helmet and are visible."
diff --git a/html/changelogs/AutoChangeLog-pr-13588.yml b/html/changelogs/AutoChangeLog-pr-13588.yml
new file mode 100644
index 0000000000..7ab9d67bab
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13588.yml
@@ -0,0 +1,5 @@
+author: "Delams-The-SM"
+delete-after: True
+changes:
+ - rscadd: "Added 3 new emotes *hiss *purr *meow"
+ - soundadd: "ported sounds from Citadel RP for *purr and *meow"
diff --git a/html/changelogs/AutoChangeLog-pr-13606.yml b/html/changelogs/AutoChangeLog-pr-13606.yml
new file mode 100644
index 0000000000..568f8cf7e6
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-13606.yml
@@ -0,0 +1,5 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - bugfix: "adminhelping no longer removes entire admin tab"
+ - bugfix: "end of round no longer removes entire admin tab"
diff --git a/html/statbrowser.html b/html/statbrowser.html
index 0920081fd2..346a198746 100644
--- a/html/statbrowser.html
+++ b/html/statbrowser.html
@@ -412,8 +412,8 @@ function verbs_cat_check(cat) {
}
for(var v = 0; v < verbs.length; v++){
var part = verbs[v];
- verbcat = part[0].indexOf(".") != -1 ? part[0].split(".") : part[0];
- if(verbcat != cat || verbcat.trim() == ""){
+ verbcat = part[0].indexOf(".") != -1 ? part[0].split(".")[0] : part[0];
+ if(verbcat != tabCat || verbcat.trim() == ""){
continue;
}
else{
@@ -446,9 +446,9 @@ function add_verb_list(v) {
to_add.sort(); // sort what we're adding
for(var i = 0; i < to_add.length; i++) {
var part = to_add[i];
- if (!part[0])
+ if(!part[0])
continue;
- var category = part[0].indexOf(".") == -1 ? part[0] : part[0].split(".")[0]
+ var category = part[0].indexOf(".") == -1 ? part[0] : part[0].split(".")[0];
if(findVerbindex(part[1], verbs))
continue;
if(verb_tabs.includes(category)){
diff --git a/icons/mob/clothing/custom_w.dmi b/icons/mob/clothing/custom_w.dmi
index 18e07f41ed..5b1fd0876c 100644
Binary files a/icons/mob/clothing/custom_w.dmi and b/icons/mob/clothing/custom_w.dmi differ
diff --git a/icons/mob/clothing/head.dmi b/icons/mob/clothing/head.dmi
index 16571a4aa1..889888ef0a 100644
Binary files a/icons/mob/clothing/head.dmi and b/icons/mob/clothing/head.dmi differ
diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi
index 4f650f8561..95a31f8b9f 100644
Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ
diff --git a/icons/obj/custom.dmi b/icons/obj/custom.dmi
index 50f536d1d3..e17d55dc85 100644
Binary files a/icons/obj/custom.dmi and b/icons/obj/custom.dmi differ
diff --git a/modular_citadel/code/modules/client/loadout/__donator.dm b/modular_citadel/code/modules/client/loadout/__donator.dm
index bb9162789e..35b6e08d0e 100644
--- a/modular_citadel/code/modules/client/loadout/__donator.dm
+++ b/modular_citadel/code/modules/client/loadout/__donator.dm
@@ -522,3 +522,10 @@
slot = SLOT_HEAD
path = /obj/item/clothing/head/halo
ckeywhitelist = list("hisakaki")
+
+/datum/gear/donator/vest
+ name = "vest and shirt"
+ slot = SLOT_W_UNIFORM
+ path = /obj/item/clothing/under/custom/vest
+ ckeywhitelist = list("maylowfox")
+
diff --git a/modular_citadel/code/modules/custom_loadout/custom_items.dm b/modular_citadel/code/modules/custom_loadout/custom_items.dm
index ee41d0a25d..23ef9d5f20 100644
--- a/modular_citadel/code/modules/custom_loadout/custom_items.dm
+++ b/modular_citadel/code/modules/custom_loadout/custom_items.dm
@@ -567,3 +567,12 @@
icon = 'icons/mob/clothing/custom_w.dmi'
mob_overlay_icon = 'icons/mob/clothing/custom_w.dmi'
dynamic_hair_suffix = ""
+
+/obj/item/clothing/under/custom/vest
+ name = "vest"
+ desc = "A vest with a shirt underlining it."
+ icon_state = "vest"
+ item_state = "vest"
+ icon = 'icons/obj/custom.dmi'
+ mob_overlay_icon = 'icons/mob/clothing/custom_w.dmi'
+
diff --git a/modular_citadel/code/modules/mob/cit_emotes.dm b/modular_citadel/code/modules/mob/cit_emotes.dm
index 28c3f7ea99..f7911def84 100644
--- a/modular_citadel/code/modules/mob/cit_emotes.dm
+++ b/modular_citadel/code/modules/mob/cit_emotes.dm
@@ -132,6 +132,54 @@
user.nextsoundemote = world.time + 7
playsound(user, 'modular_citadel/sound/voice/awoo.ogg', 50, 1, -1)
+/datum/emote/living/hiss
+ key = "hiss"
+ key_third_person = "hisses"
+ message = "hisses!"
+ emote_type = EMOTE_AUDIBLE
+ muzzle_ignore = FALSE
+ restraint_check = FALSE
+
+/datum/emote/living/hiss/run_emote(mob/living/user, params)
+ if(!(. = ..()))
+ return
+ if(user.nextsoundemote >= world.time)
+ return
+ user.nextsoundemote = world.time + 7
+ playsound(user, 'modular_citadel/sound/voice/hiss.ogg', 50, 1, -1)
+
+/datum/emote/living/meow
+ key = "meow"
+ key_third_person = "mrowls"
+ message = "mrowls!"
+ emote_type = EMOTE_AUDIBLE
+ muzzle_ignore = FALSE
+ restraint_check = FALSE
+
+/datum/emote/living/meow/run_emote(mob/living/user, params)
+ if(!(. = ..()))
+ return
+ if(user.nextsoundemote >= world.time)
+ return
+ user.nextsoundemote = world.time + 7
+ playsound(user, 'modular_citadel/sound/voice/meow1.ogg', 50, 1, -1)
+
+/datum/emote/living/purr
+ key = "purr"
+ key_third_person = "purrs softly"
+ message = "purrs softly."
+ emote_type = EMOTE_AUDIBLE
+ muzzle_ignore = FALSE
+ restraint_check = FALSE
+
+/datum/emote/living/purr/run_emote(mob/living/user, params)
+ if(!(. = ..()))
+ return
+ if(user.nextsoundemote >= world.time)
+ return
+ user.nextsoundemote = world.time + 7
+ playsound(user, 'modular_citadel/sound/voice/purr.ogg', 50, 1, -1)
+
/datum/emote/living/nya
key = "nya"
key_third_person = "lets out a nya"
diff --git a/modular_citadel/sound/voice/hiss.ogg b/modular_citadel/sound/voice/hiss.ogg
index cd9fa22c37..3508f47f13 100644
Binary files a/modular_citadel/sound/voice/hiss.ogg and b/modular_citadel/sound/voice/hiss.ogg differ
diff --git a/modular_citadel/sound/voice/meow1.ogg b/modular_citadel/sound/voice/meow1.ogg
new file mode 100644
index 0000000000..be9393d7d6
Binary files /dev/null and b/modular_citadel/sound/voice/meow1.ogg differ
diff --git a/modular_citadel/sound/voice/purr.ogg b/modular_citadel/sound/voice/purr.ogg
new file mode 100644
index 0000000000..d0ea06d9a0
Binary files /dev/null and b/modular_citadel/sound/voice/purr.ogg differ