Allows head-equippable items that are not /obj/item/clothing to be attached to /datum/component/hat_stabilizer (#93345)

<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may
not be viewable. -->
<!-- You can view Contributing.MD for a detailed description of the pull
request process. -->

## About The Pull Request

the `/datum/component/hat_stabilizer` component, which is the thing on
the magnate MODsuit(and apparently on other spacesuits(and wigs)) that
allows you to attach an additional piece of headwear on top of the helm,
was `istype()`ed to only allowing `/obj/item/clothing`. This prevented
many non- `/clothing` items from being attached, despite being
equippable to the head, the only one of which I care about being
flowers.

This pr changes the `istype()` check to checking for the head slot flag,
and modifies surrounding logic to account for this. The only items I can
think of that are non-clothing and are equippable to the head are
various flowers and `mob_holder`s for various animals.

Also fixes an unrelated bug where updating the appearance of the holding
item would change the offset of any loose-hat holders over and over
again, causing it to move around over your head if you, for example,
toggled a MOD flashlight on and off repeatedly.

Also fixes an unrelated bug where the hat taken off would never be put
in your hands when it was seemingly intended to, due to always returning
the hat rather than `put_in_active_hand()` (unless the parent isn't
clothing, but there's no non-clothing items with the component attached)

## Why It's Good For The Game

I want to put flowers on my helmet, and I don't see any possible
negative ramifications.

## Changelog

🆑

qol: Flowers can now be attached to space helmets.
qol: Taking hats off of helmets will now put them in your hand.
fix: MOD flashlights won't move hats on them when toggling.

/🆑

<!-- Both 🆑's are required for the changelog to work! You can put
your name to the right of the first 🆑 if you want to overwrite your
GitHub username as author ingame. -->
<!-- You can use multiple of the same prefix (they're only used for the
icon ingame) and delete the unneeded ones. Despite some of the tags,
changelogs should generally represent how a player might be affected by
the changes rather than a summary of the PR's contents. -->
This commit is contained in:
Leland Kemble
2025-10-10 18:16:35 -04:00
committed by GitHub
parent dd8af45715
commit 8f8bfb22ef
+26 -19
View File
@@ -2,7 +2,7 @@
/datum/component/hat_stabilizer
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
/// Currently "stored" hat. No armor or function will be inherited, only the icon and cover flags.
var/obj/item/clothing/head/attached_hat
var/obj/item/attached_hat
/// If TRUE, the hat will fall to the ground when the owner does so. It can also be shot off.
var/loose_hat = FALSE
/// Original cover flags for the helmet, before a hat is placed
@@ -12,6 +12,8 @@
var/use_worn_icon = TRUE
/// Pixel z offset for the hat
var/pixel_z_offset
/// Which way a loose hat is offset
var/head_angle = 1
/datum/component/hat_stabilizer/Initialize(use_worn_icon = FALSE, pixel_z_offset = 0, loose_hat = FALSE)
if(!ismovable(parent))
@@ -114,7 +116,7 @@
if(loose_hat)
var/matrix/tilt_trix = matrix(worn_overlay.transform)
var/angle = 5
tilt_trix.Turn(angle * pick(1, -1))
tilt_trix.Turn(angle * head_angle)
worn_overlay.transform = tilt_trix
worn_overlay.pixel_z = pixel_z_offset + attached_hat.worn_y_offset
overlays += worn_overlay
@@ -132,7 +134,7 @@
if(loose_hat)
var/matrix/tilt_trix = matrix(worn_overlay.transform)
var/angle = 5
tilt_trix.Turn(angle * pick(1, -1))
tilt_trix.Turn(angle * head_angle)
worn_overlay.transform = tilt_trix
worn_overlay.pixel_z = pixel_z_offset + attached_hat.worn_y_offset
overlays += worn_overlay
@@ -147,41 +149,44 @@
SIGNAL_HANDLER
var/atom/movable/movable_parent = parent
if(!istype(hitting_item, /obj/item/clothing/head))
if(!(hitting_item.slot_flags & ITEM_SLOT_HEAD))
return
if(attached_hat)
movable_parent.balloon_alert(user, "hat already attached!")
return
if(isclothing(hitting_item))
var/obj/item/clothing/hat = hitting_item
if(hat.clothing_flags & STACKABLE_HELMET_EXEMPT)
movable_parent.balloon_alert(user, "invalid hat!")
return
var/obj/item/clothing/hat = hitting_item
if(hat.clothing_flags & STACKABLE_HELMET_EXEMPT)
movable_parent.balloon_alert(user, "invalid hat!")
if(!user.transferItemToLoc(hitting_item, parent, force = FALSE, silent = TRUE))
return
if(!user.transferItemToLoc(hat, parent, force = FALSE, silent = TRUE))
return
attach_hat(hitting_item, user)
attach_hat(hat, user)
/datum/component/hat_stabilizer/proc/attach_hat(obj/item/clothing/hat, mob/user)
/datum/component/hat_stabilizer/proc/attach_hat(obj/item/hat, mob/user)
var/atom/movable/movable_parent = parent
attached_hat = hat
RegisterSignal(hat, COMSIG_MOVABLE_MOVED, PROC_REF(on_hat_movement))
head_angle = pick(1, -1)
if (!isnull(user))
movable_parent.balloon_alert(user, "hat attached")
if (!istype(parent, /obj/item/clothing))
if (!isclothing(parent))
movable_parent.update_appearance()
return
var/obj/item/clothing/apparel = parent
apparel.attach_clothing_traits(attached_hat.clothing_traits)
if(isclothing(attached_hat))
var/obj/item/clothing/realhat = attached_hat
apparel.attach_clothing_traits(realhat.clothing_traits)
apparel.visor_flags_cover |= realhat.visor_flags_cover
former_flags = apparel.flags_cover
former_visor_flags = apparel.visor_flags_cover
apparel.flags_cover |= attached_hat.flags_cover
apparel.visor_flags_cover |= attached_hat.visor_flags_cover
apparel.update_appearance()
if (ismob(apparel.loc))
@@ -220,14 +225,16 @@
else
movable_parent.balloon_alert_to_viewers("the hat falls to the floor!")
if (!istype(parent, /obj/item/clothing))
if (!isclothing(parent))
attached_hat = null
movable_parent.update_appearance()
return
var/former_hat = attached_hat
var/obj/item/clothing/apparel = parent
apparel.detach_clothing_traits(attached_hat.clothing_traits)
if(isclothing(attached_hat))
var/obj/item/clothing/truehat = attached_hat
apparel.detach_clothing_traits(truehat.clothing_traits)
apparel.flags_cover = former_flags
apparel.visor_flags_cover = former_visor_flags
apparel.update_appearance()
@@ -235,8 +242,8 @@
if (ismob(apparel.loc))
var/mob/wearer = apparel.loc
wearer.update_clothing(wearer.get_slot_by_item(apparel))
return former_hat
if(isnull(user))
return former_hat
/datum/component/hat_stabilizer/proc/on_requesting_context_from_item(atom/source, list/context, obj/item/held_item, mob/user)
SIGNAL_HANDLER