diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 9733856a3c3..b6e91f96dd9 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -398,11 +398,153 @@
var/vision_flags = 0
var/see_in_dark = 0
var/lighting_alpha
+ /// the head clothing that this item may be attached to.
+ var/obj/item/clothing/under/has_under = null
+ /// the attached hats to this hat.
+ var/list/attached_hats = list()
+ /// if this hat can have hats placed on top of it.
+ var/can_have_hats = FALSE
+ /// if this hat can be a hat of a hat. Hat^2
+ var/can_be_hat = TRUE
/obj/item/clothing/head/update_icon_state()
if(..())
item_state = "[replacetext("[item_state]", "_up", "")][up ? "_up" : ""]"
+/obj/item/clothing/head/AltShiftClick(mob/user)
+ if(user.stat || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED) || !Adjacent(user))
+ return
+ if(!length(attached_hats))
+ return
+ var/obj/item/clothing/head/hat
+ if(length(attached_hats) > 1)
+ var/pick = radial_menu_helper(usr, src, attached_hats, custom_check = FALSE, require_near = TRUE)
+ if(!pick || !istype(pick, /obj/item/clothing/head) || !Adjacent(usr))
+ return
+ hat = pick
+ else
+ hat = attached_hats[1]
+ remove_hat(user, hat)
+
+/obj/item/clothing/head/Destroy()
+ if(is_equipped())
+ var/mob/M = loc
+ for(var/obj/item/clothing/head/H as anything in attached_hats)
+ H.on_removed(M)
+ else
+ for(var/obj/item/clothing/head/H as anything in attached_hats)
+ H.forceMove(get_turf(src))
+ attached_hats = null
+ return ..()
+
+/obj/item/clothing/head/dropped(mob/user, silent)
+ ..()
+ if(!ishuman(user))
+ return
+ var/mob/living/carbon/human/H = user
+ if(H.get_item_by_slot(SLOT_HUD_HEAD) == src)
+ for(var/obj/item/clothing/head/hat as anything in attached_hats)
+ hat.attached_unequip()
+
+/obj/item/clothing/head/examine(mob/user)
+ . = ..()
+ for(var/obj/item/clothing/head/hat as anything in attached_hats)
+ . += "\A [hat] is placed neatly on top."
+
+//when user attached a hat to H (another hat)
+/obj/item/clothing/head/proc/on_attached(obj/item/clothing/head/H, mob/user as mob)
+ if(!istype(H))
+ return
+ has_under = H
+ forceMove(has_under)
+ has_under.overlays += item_state
+ has_under.actions += actions
+
+ for(var/datum/action/A in actions)
+ if(has_under.is_equipped())
+ var/mob/M = has_under.loc
+ A.Grant(M)
+
+ if(user)
+ to_chat(user, "You attach [src] to [has_under].")
+ add_fingerprint(user)
+
+/obj/item/clothing/head/proc/on_removed(mob/user)
+ if(!has_under)
+ return
+ has_under.overlays -= icon_state
+ has_under.actions -= actions
+
+ for(var/datum/action/A in actions)
+ if(ismob(has_under.loc))
+ var/mob/M = has_under.loc
+ A.Remove(M)
+
+ has_under = null
+ if(user)
+ user.put_in_hands(src)
+ add_fingerprint(user)
+
+/obj/item/clothing/head/proc/detach_hat(obj/item/clothing/head/hat, mob/user)
+ attached_hats -= hat
+ hat.on_removed(user)
+ if(ishuman(loc))
+ var/mob/living/carbon/human/H = loc
+ H.update_inv_head()
+
+/obj/item/clothing/head/proc/remove_hat(mob/user, obj/item/clothing/head/hat)
+ if(!(hat in attached_hats))
+ return
+ if(!isliving(user))
+ return
+ if(user.incapacitated())
+ return
+ if(!Adjacent(user))
+ return
+ detach_hat(hat, user)
+ to_chat(user, "You remove [hat] from [src].")
+
+/obj/item/clothing/head/proc/attached_unequip(mob/user) // If we need to do something special when clothing is removed from the user
+ return
+
+/obj/item/clothing/head/proc/attached_equip(mob/user) // If we need to do something special when clothing is removed from the user
+ return
+
+/*
+ * # can_attach_hat
+ *
+ * Arguments:
+ * * Hat - The clothing/head object being checked. MUST BE TYPE /obj/item/clothing/head
+*/
+/obj/item/clothing/head/proc/can_attach_hat(obj/item/clothing/head/hat)
+ return length(attached_hats) < 1 && can_have_hats && hat.can_be_hat // this hat already has a hat or cannot be a hat of a hat!
+
+/obj/item/clothing/head/proc/attach_hat(obj/item/clothing/head/hat, mob/user, unequip = FALSE)
+ if(can_attach_hat(hat))
+ if(unequip && !user.unEquip(hat)) // Make absolutely sure this hat is removed from hands
+ return FALSE
+
+ attached_hats += hat
+ hat.on_attached(src, user)
+
+ if(ishuman(loc))
+ var/mob/living/carbon/human/H = loc
+ H.update_inv_head()
+
+ return TRUE
+ else if(hat.has_under)
+ return FALSE
+ else
+ to_chat(user, "You cannot place [hat] ontop of [src].")
+
+ return FALSE
+
+/obj/item/clothing/head/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/clothing/head) && can_have_hats)
+ attach_hat(I, user, TRUE)
+
+ return ..()
+
//////////////////////////////
// MARK: MASK
//////////////////////////////
diff --git a/code/modules/clothing/head/misc_hats.dm b/code/modules/clothing/head/misc_hats.dm
index 304a6c092f0..bc9ea7066ee 100644
--- a/code/modules/clothing/head/misc_hats.dm
+++ b/code/modules/clothing/head/misc_hats.dm
@@ -536,6 +536,7 @@
icon_state = "crown"
armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 10, BOMB = 0, RAD = 0, FIRE = INFINITY, ACID = 50)
resistance_flags = FIRE_PROOF
+ can_be_hat = FALSE
/obj/item/clothing/head/crown/fancy
name = "magnificent crown"
diff --git a/code/modules/clothing/spacesuits/plasmamen.dm b/code/modules/clothing/spacesuits/plasmamen.dm
index 461f780e99d..500a1f000a8 100644
--- a/code/modules/clothing/spacesuits/plasmamen.dm
+++ b/code/modules/clothing/spacesuits/plasmamen.dm
@@ -23,6 +23,8 @@
icon = 'icons/obj/clothing/species/plasmaman/hats.dmi'
species_restricted = list("Plasmaman")
sprite_sheets = list("Plasmaman" = 'icons/mob/clothing/species/plasmaman/helmet.dmi')
+ can_have_hats = TRUE
+ can_be_hat = FALSE
/obj/item/clothing/head/helmet/space/plasmaman/Initialize(mapload)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm
index 47f744999fe..52db0245ce1 100644
--- a/code/modules/mob/living/carbon/human/human_update_icons.dm
+++ b/code/modules/mob/living/carbon/human/human_update_icons.dm
@@ -855,15 +855,24 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
var/mutable_appearance/standing
if(head.sprite_sheets && head.sprite_sheets[dna.species.sprite_sheet_name])
standing = mutable_appearance(head.sprite_sheets[dna.species.sprite_sheet_name], "[head.icon_state]", layer = -HEAD_LAYER)
- if(istype(head, /obj/item/clothing/head/helmet/space/plasmaman))
- var/obj/item/clothing/head/helmet/space/plasmaman/P = head
- if(!P.up)
- standing.overlays += P.visor_icon
else if(head.icon_override)
standing = mutable_appearance(head.icon_override, "[head.icon_state]", layer = -HEAD_LAYER)
else
standing = mutable_appearance('icons/mob/clothing/head.dmi', "[head.icon_state]", layer = -HEAD_LAYER)
+ if(istype(head, /obj/item/clothing/head/helmet/space/plasmaman))
+ var/obj/item/clothing/head/helmet/space/plasmaman/P = head
+ if(!P.up)
+ standing.overlays += P.visor_icon
+
+ if(istype(head, /obj/item/clothing/head))
+ var/obj/item/clothing/head/w_hat = head
+ for(var/obj/item/clothing/head/hat in w_hat.attached_hats)
+ if(hat.sprite_sheets && hat.sprite_sheets[dna.species.sprite_sheet_name])
+ standing.overlays += image("icon" = hat.sprite_sheets[dna.species.sprite_sheet_name], "icon_state" = "[hat.icon_state]")
+ else
+ standing.overlays += image("icon" = hat.icon_override, "icon_state" = "[hat.icon_state]")
+
if(head.blood_DNA)
var/image/bloodsies = image("icon" = dna.species.blood_mask, "icon_state" = "helmetblood")
bloodsies.color = head.blood_color