mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-02-09 07:49:09 +00:00
## About The Pull Request You can now wear a hat on any modsuit, even w/o the stabilizing module. However: - It will always sit slightly askew, at an angle. - Involuntarily falling to the ground for any reason will cause the hat to fall to the ground. - Being thrown, slapped, or slipped will send it flying off. Added the Atrocinator, Hat Stabilizer, and Tanning modules to the black market. Added the loose hat component to bio/bomb/rad hoods and space helmets. ## Why It's Good For The Game > You can now wear a hat on any modsuit, even w/o the stabilizing module. I think the notion of, say, the Head of Security putting his cap on his modsuit and then being slipped by the clown, who then steals the cap, is really funny. https://github.com/user-attachments/assets/3ad8a74d-0cb8-4118-8beb-d2ce9c76b358 The module is fairly rare and sometimes I just want to wear a silly hat alongside the modsuit without badgering the captain for his hat module. The downsides are rather plentiful so it's not like the hat module is made irrelevant - if anything it makes it more notable. This will add a bunch of enjoyable silliness to rounds, so I think it's worth it. > Added the Atrocinator, Hat Stabilizer, and Tanning modules to the black market. > Added the loose hat component to bio/bomb/rad hoods and space helmets. It sucks losing your iconic drip when you need to venture out to space for whichever reason - this lets you keep it without taking up space in your bag, while having the throw downside. They just feel perfect for the vibes of the black market. More miscellaneous completely useless fancy stuff that has exorbitant prices please! ## Changelog <!-- If your PR modifies aspects of the game that can be concretely observed by players or admins you should add a changelog. If your change does NOT meet this description, remove this section. Be sure to properly mark your PRs to prevent unnecessary GBP loss. You can read up on GBP and it's effects on PRs in the tgstation guides for contributors. Please note that maintainers freely reserve the right to remove and add tags should they deem it appropriate. You can attempt to finagle the system all you want, but it's best to shoot for clear communication right off the bat. --> 🆑 add: You can now wear a hat on any modsuit, even w/o the stabilizing module. But it may easily fall off... add: Added the Atrocinator, Hat Stabilizer, and Tanning modules to the black market. add: Added the loose hat component to bio/bomb/rad hoods and space helmets. /🆑 ~~I'm having a bit of an issue. Somewhere I fugged up and now the worn overlay on the mod helmet sprite doesn't work properly...~~ Turns out that code was never used and nonfunctional to begin with so I removed it entirely yay
232 lines
7.8 KiB
Plaintext
232 lines
7.8 KiB
Plaintext
/// Allows players to place hats on the atom this is attached to
|
|
/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
|
|
/// 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
|
|
var/former_flags
|
|
var/former_visor_flags
|
|
/// If true, add_overlay will use worn overlay instead of item appearance
|
|
var/use_worn_icon = TRUE
|
|
/// Pixel_y offset for the hat
|
|
var/pixel_y_offset
|
|
|
|
/datum/component/hat_stabilizer/Initialize(use_worn_icon = FALSE, pixel_y_offset = 0, loose_hat = FALSE)
|
|
if(!ismovable(parent))
|
|
return COMPONENT_INCOMPATIBLE
|
|
|
|
var/atom/movable/source = parent
|
|
source.flags_1 |= HAS_CONTEXTUAL_SCREENTIPS_1
|
|
|
|
src.use_worn_icon = use_worn_icon
|
|
src.pixel_y_offset = pixel_y_offset
|
|
src.loose_hat = loose_hat
|
|
// Examine signals
|
|
RegisterSignal(source, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
|
|
RegisterSignal(source, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context_from_item))
|
|
|
|
// Equip signals, used to drop loose hats
|
|
RegisterSignal(source, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip))
|
|
RegisterSignal(source, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
|
|
|
|
// Wear & Remove
|
|
RegisterSignal(source, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby))
|
|
RegisterSignal(source, COMSIG_ATOM_ATTACK_HAND_SECONDARY, PROC_REF(on_secondary_attack_hand))
|
|
|
|
// Overlays
|
|
RegisterSignals(source, list(COMSIG_MODULE_GENERATE_WORN_OVERLAY, COMSIG_ITEM_GET_WORN_OVERLAYS), PROC_REF(get_worn_overlays))
|
|
|
|
RegisterSignal(source, COMSIG_QDELETING, PROC_REF(on_qdel))
|
|
|
|
// Inherit the new values passed to the component
|
|
/datum/component/hat_stabilizer/InheritComponent(datum/component/hat_stabilizer/new_comp, original, use_worn_icon, pixel_y_offset, loose_hat)
|
|
if(!original)
|
|
return
|
|
|
|
if(!isnull(use_worn_icon))
|
|
src.use_worn_icon = use_worn_icon
|
|
if(!isnull(use_worn_icon))
|
|
src.use_worn_icon = use_worn_icon
|
|
if(!isnull(pixel_y_offset))
|
|
src.pixel_y_offset = pixel_y_offset
|
|
if(!isnull(loose_hat))
|
|
src.loose_hat = loose_hat
|
|
|
|
/datum/component/hat_stabilizer/UnregisterFromParent()
|
|
if (attached_hat)
|
|
remove_hat()
|
|
UnregisterSignal(parent, list(COMSIG_ATOM_EXAMINE, COMSIG_ATOM_ATTACKBY,
|
|
COMSIG_ATOM_ATTACK_HAND_SECONDARY, COMSIG_MODULE_GENERATE_WORN_OVERLAY,
|
|
COMSIG_ITEM_GET_WORN_OVERLAYS, COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_QDELETING,
|
|
COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED))
|
|
|
|
/datum/component/hat_stabilizer/proc/on_equip(datum/source, mob/equipper, slot)
|
|
SIGNAL_HANDLER
|
|
|
|
if(!loose_hat)
|
|
return
|
|
|
|
var/obj/item/our_item = parent
|
|
if(!(slot & our_item.slot_flags))
|
|
return
|
|
RegisterSignals(equipper, list(COMSIG_MOB_SLIPPED, COMSIG_LIVING_SLAPPED, COMSIG_MOVABLE_POST_THROW), PROC_REF(throw_hat))
|
|
RegisterSignal(equipper, COMSIG_LIVING_THUD, PROC_REF(drop_hat))
|
|
|
|
/datum/component/hat_stabilizer/proc/on_drop(datum/source, mob/dropper)
|
|
SIGNAL_HANDLER
|
|
UnregisterSignal(dropper, list(COMSIG_MOB_SLIPPED, COMSIG_LIVING_SLAPPED, COMSIG_MOVABLE_POST_THROW, COMSIG_LIVING_THUD))
|
|
|
|
/datum/component/hat_stabilizer/proc/throw_hat(mob/hatless)
|
|
SIGNAL_HANDLER
|
|
if(!loose_hat)
|
|
return
|
|
var/obj/item/hat = remove_hat()
|
|
if(!hat)
|
|
return
|
|
hat.visible_message(span_danger("[hat] goes flying off [hatless]'s head!"))
|
|
hat.throw_at(get_edge_target_turf(get_turf(hat), pick(GLOB.alldirs)), 2, 1, spin = TRUE)
|
|
|
|
/datum/component/hat_stabilizer/proc/drop_hat(mob/hatless)
|
|
SIGNAL_HANDLER
|
|
if(!loose_hat)
|
|
return
|
|
remove_hat()
|
|
|
|
/datum/component/hat_stabilizer/proc/on_examine(datum/source, mob/user, list/base_examine)
|
|
SIGNAL_HANDLER
|
|
if(attached_hat)
|
|
base_examine += span_notice("There's \a [attached_hat] [loose_hat ? "loosely" : ""] placed on [parent].")
|
|
else
|
|
base_examine += span_notice("There's nothing placed on [parent]. Yet.")
|
|
|
|
/datum/component/hat_stabilizer/proc/get_worn_overlays(atom/movable/source, list/overlays, mutable_appearance/standing, isinhands, icon_file)
|
|
SIGNAL_HANDLER
|
|
if (isinhands)
|
|
return
|
|
if(attached_hat)
|
|
var/mutable_appearance/worn_overlay = attached_hat.build_worn_icon(default_layer = ABOVE_BODY_FRONT_HEAD_LAYER-0.1, default_icon_file = 'icons/mob/clothing/head/default.dmi')
|
|
// loose hats are slightly angled
|
|
if(loose_hat)
|
|
var/matrix/tilt_trix = matrix(worn_overlay.transform)
|
|
var/angle = 5
|
|
tilt_trix.Turn(angle * pick(1, -1))
|
|
worn_overlay.transform = tilt_trix
|
|
worn_overlay.pixel_y = pixel_y_offset + attached_hat.worn_y_offset
|
|
overlays += worn_overlay
|
|
|
|
/datum/component/hat_stabilizer/proc/on_qdel(atom/movable/source)
|
|
SIGNAL_HANDLER
|
|
|
|
if (attached_hat)
|
|
QDEL_NULL(attached_hat)
|
|
|
|
/datum/component/hat_stabilizer/proc/on_attackby(datum/source, obj/item/hitting_item, mob/user)
|
|
SIGNAL_HANDLER
|
|
|
|
var/atom/movable/movable_parent = parent
|
|
if(!istype(hitting_item, /obj/item/clothing/head))
|
|
return
|
|
|
|
if(attached_hat)
|
|
movable_parent.balloon_alert(user, "hat already attached!")
|
|
return
|
|
|
|
var/obj/item/clothing/hat = hitting_item
|
|
if(hat.clothing_flags & STACKABLE_HELMET_EXEMPT)
|
|
movable_parent.balloon_alert(user, "invalid hat!")
|
|
return
|
|
|
|
if(!user.transferItemToLoc(hat, parent, force = FALSE, silent = TRUE))
|
|
return
|
|
|
|
attach_hat(hat, user)
|
|
|
|
/datum/component/hat_stabilizer/proc/attach_hat(obj/item/clothing/hat, mob/user)
|
|
var/atom/movable/movable_parent = parent
|
|
attached_hat = hat
|
|
RegisterSignal(hat, COMSIG_MOVABLE_MOVED, PROC_REF(on_hat_movement))
|
|
|
|
if (!isnull(user))
|
|
movable_parent.balloon_alert(user, "hat attached")
|
|
|
|
if (!istype(parent, /obj/item/clothing))
|
|
movable_parent.update_appearance()
|
|
return
|
|
|
|
var/obj/item/clothing/apparel = parent
|
|
apparel.attach_clothing_traits(attached_hat.clothing_traits)
|
|
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))
|
|
var/mob/wearer = apparel.loc
|
|
wearer.update_clothing(wearer.get_slot_by_item(apparel))
|
|
|
|
/datum/component/hat_stabilizer/proc/on_hat_movement(obj/hat, mob/user)
|
|
SIGNAL_HANDLER
|
|
remove_hat(user)
|
|
|
|
/datum/component/hat_stabilizer/proc/on_secondary_attack_hand(datum/source, mob/user)
|
|
SIGNAL_HANDLER
|
|
. = COMPONENT_CANCEL_ATTACK_CHAIN
|
|
if(!attached_hat)
|
|
return
|
|
var/atom/movable/movable_parent = parent
|
|
if (remove_hat(user))
|
|
movable_parent.balloon_alert(user, "hat removed")
|
|
else
|
|
movable_parent.balloon_alert_to_viewers("the hat falls to the floor!")
|
|
|
|
/datum/component/hat_stabilizer/proc/on_retraction()
|
|
|
|
/datum/component/hat_stabilizer/proc/remove_hat(mob/user)
|
|
if(QDELETED(attached_hat))
|
|
return
|
|
|
|
var/atom/movable/movable_parent = parent
|
|
UnregisterSignal(attached_hat, COMSIG_MOVABLE_MOVED)
|
|
|
|
if (attached_hat.loc == parent)
|
|
attached_hat.forceMove(movable_parent.drop_location())
|
|
|
|
if(!isnull(user))
|
|
. = user.put_in_active_hand(attached_hat)
|
|
else
|
|
movable_parent.balloon_alert_to_viewers("the hat falls to the floor!")
|
|
|
|
if (!istype(parent, /obj/item/clothing))
|
|
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)
|
|
apparel.flags_cover = former_flags
|
|
apparel.visor_flags_cover = former_visor_flags
|
|
apparel.update_appearance()
|
|
attached_hat = null
|
|
if (ismob(apparel.loc))
|
|
var/mob/wearer = apparel.loc
|
|
wearer.update_clothing(wearer.get_slot_by_item(apparel))
|
|
|
|
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
|
|
|
|
if(attached_hat && !held_item)
|
|
context[SCREENTIP_CONTEXT_RMB] = "Remove hat"
|
|
return CONTEXTUAL_SCREENTIP_SET
|
|
|
|
if(istype(held_item, /obj/item/clothing/head))
|
|
context[SCREENTIP_CONTEXT_LMB] = "Attach hat"
|
|
return CONTEXTUAL_SCREENTIP_SET
|
|
|
|
return NONE
|