From 592353088e3edeb2fa2331ff607462b7a0d8bf52 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Wed, 23 Oct 2024 20:32:01 +0200 Subject: [PATCH] Refactors hat stabilizers into a component shared with plasmamen helmets (#87305) ## About The Pull Request Hat stabilization is now a component shared between MODsuits and plasmaman helmets, only change this results in is attached helmets applying their visor flags to plasmaman helmets (like it was with MODsuits), but that should not have any impact envirohelms already cover your face ## Why It's Good For The Game Less copypasted code and maybe some day we can get hat stands. ## Changelog :cl: refactor: Refactored hat stabilizers into a component shared with plasmaman helmets /:cl: --------- Co-authored-by: Fikou <23585223+Fikou@users.noreply.github.com> --- code/__DEFINES/dcs/signals/signals_mod.dm | 2 + code/datums/components/hat_stabilizer.dm | 140 ++++++++++++++++++ code/modules/clothing/spacesuits/plasmamen.dm | 78 +++------- code/modules/mod/modules/_module.dm | 1 + code/modules/mod/modules/modules_general.dm | 66 +-------- tgstation.dme | 1 + 6 files changed, 164 insertions(+), 124 deletions(-) create mode 100644 code/datums/components/hat_stabilizer.dm diff --git a/code/__DEFINES/dcs/signals/signals_mod.dm b/code/__DEFINES/dcs/signals/signals_mod.dm index 8cabf7537ab..09b29c93784 100644 --- a/code/__DEFINES/dcs/signals/signals_mod.dm +++ b/code/__DEFINES/dcs/signals/signals_mod.dm @@ -41,3 +41,5 @@ #define COMSIG_MOD_WEARER_UNSET "mod_wearer_unset" /// Sent by the tether module when it triggers its snapping function #define COMSIG_MOD_TETHER_SNAP "mod_tether_snap" +/// Called when a MOD module generats its worn overlay +#define COMSIG_MODULE_GENERATE_WORN_OVERLAY "mod_module_generate_worn_overlay" diff --git a/code/datums/components/hat_stabilizer.dm b/code/datums/components/hat_stabilizer.dm new file mode 100644 index 00000000000..e7951e49956 --- /dev/null +++ b/code/datums/components/hat_stabilizer.dm @@ -0,0 +1,140 @@ +/// Allows players to place hats on the atom this is attached to +/datum/component/hat_stabilizer + /// Currently "stored" hat. No armor or function will be inherited, only the icon and cover flags. + var/obj/item/clothing/head/attached_hat + /// 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(add_overlay = FALSE, use_worn_icon = TRUE, pixel_y_offset = 0) + if(!ismovable(parent)) + return COMPONENT_INCOMPATIBLE + + src.use_worn_icon = use_worn_icon + src.pixel_y_offset = pixel_y_offset + RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) + RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(on_qdel)) + RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND_SECONDARY, PROC_REF(on_secondary_attack_hand)) + RegisterSignals(parent, list(COMSIG_MODULE_GENERATE_WORN_OVERLAY, COMSIG_ITEM_GET_WORN_OVERLAYS), PROC_REF(get_worn_overlays)) + if (add_overlay) + RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_update_overlays)) + +/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)) + +/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] placed on [parent]. Right-click to remove it.") + 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') + worn_overlay.pixel_y = pixel_y_offset + overlays += worn_overlay + +/datum/component/hat_stabilizer/proc/on_update_overlays(atom/movable/source, list/overlays) + SIGNAL_HANDLER + var/mutable_appearance/worn_overlay = use_worn_icon ? attached_hat.build_worn_icon(default_layer = ABOVE_OBJ_LAYER, default_icon_file = 'icons/mob/clothing/head/default.dmi') : mutable_appearance(attached_hat, layer = ABOVE_OBJ_LAYER) + worn_overlay.pixel_y = pixel_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 + attached_hat = hat + RegisterSignal(hat, COMSIG_MOVABLE_MOVED, PROC_REF(remove_hat)) + movable_parent.balloon_alert(user, "hat attached, right-click to remove") + + 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_secondary_attack_hand(datum/source, mob/user) + SIGNAL_HANDLER + . = SECONDARY_ATTACK_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/remove_hat(mob/user) + SIGNAL_HANDLER + + 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/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)) diff --git a/code/modules/clothing/spacesuits/plasmamen.dm b/code/modules/clothing/spacesuits/plasmamen.dm index d1578c20342..616ff463d8d 100644 --- a/code/modules/clothing/spacesuits/plasmamen.dm +++ b/code/modules/clothing/spacesuits/plasmamen.dm @@ -89,18 +89,17 @@ light_color = "#ffcc99" light_on = FALSE fishing_modifier = 0 - var/helmet_on = FALSE - var/smile = FALSE - var/smile_color = COLOR_RED - var/visor_icon = "envisor" - var/smile_state = "envirohelm_smile" - var/obj/item/clothing/head/attached_hat actions_types = list(/datum/action/item_action/toggle_helmet_light, /datum/action/item_action/toggle_welding_screen) visor_vars_to_toggle = VISOR_FLASHPROTECT | VISOR_TINT flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT flags_cover = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF visor_flags_inv = HIDEEYES|HIDEFACE slowdown = 0 + var/helmet_on = FALSE + var/smile = FALSE + var/smile_color = COLOR_RED + var/visor_icon = "envisor" + var/smile_state = "envirohelm_smile" /datum/armor/space_plasmaman bio = 100 @@ -110,30 +109,17 @@ /obj/item/clothing/head/helmet/space/plasmaman/Initialize(mapload) . = ..() visor_toggling() + AddComponent(/datum/component/hat_stabilizer) update_appearance() register_context() /obj/item/clothing/head/helmet/space/plasmaman/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) context[SCREENTIP_CONTEXT_ALT_LMB] = "Toggle Welding Screen" - - if(attached_hat) - context[SCREENTIP_CONTEXT_RMB] = "Remove hat" - - if(istype(held_item, /obj/item/clothing/head)) - context[SCREENTIP_CONTEXT_LMB] = "Attach hat" - if(istype(held_item, /obj/item/toy/crayon)) context[SCREENTIP_CONTEXT_LMB] = "Vandalize" return CONTEXTUAL_SCREENTIP_SET -/obj/item/clothing/head/helmet/space/plasmaman/examine() - . = ..() - if(attached_hat) - . += span_notice("There's [attached_hat.name] placed on the helmet.") - else - . += span_notice("There's nothing placed on the helmet.") - /obj/item/clothing/head/helmet/space/plasmaman/click_alt(mob/user) if(user.can_perform_action(src)) adjust_visor(user) @@ -171,37 +157,21 @@ . += smiley /obj/item/clothing/head/helmet/space/plasmaman/item_interaction(mob/living/user, obj/item/tool, list/modifiers) - if(istype(tool, /obj/item/toy/crayon)) - if(smile) - to_chat(user, span_warning("Seems like someone already drew something on [src]'s visor!")) - return ITEM_INTERACT_BLOCKING - - var/obj/item/toy/crayon/crayon = tool - to_chat(user, span_notice("You start drawing a smiley face on [src]'s visor...")) - if(!do_after(user, 2.5 SECONDS, target = src)) - return ITEM_INTERACT_BLOCKING - - smile = TRUE - smile_color = crayon.paint_color - to_chat(user, "You draw a smiley on [src] visor.") - update_appearance() - return ITEM_INTERACT_SUCCESS - - if(!istype(tool, /obj/item/clothing/head)) + if(!istype(tool, /obj/item/toy/crayon)) return NONE - var/obj/item/clothing/hitting_clothing = tool - if(hitting_clothing.clothing_flags & STACKABLE_HELMET_EXEMPT) - to_chat(user, span_notice("You cannot place [hitting_clothing.name] on [src]!")) + if(smile) + to_chat(user, span_warning("Seems like someone already drew something on [src]'s visor!")) return ITEM_INTERACT_BLOCKING - if(attached_hat) - to_chat(user, span_notice("There's already something placed on [src]!")) + var/obj/item/toy/crayon/crayon = tool + to_chat(user, span_notice("You start drawing a smiley face on [src]'s visor...")) + if(!do_after(user, 2.5 SECONDS, target = src)) return ITEM_INTERACT_BLOCKING - attached_hat = hitting_clothing - to_chat(user, span_notice("You placed [hitting_clothing.name] on [src]!")) - hitting_clothing.forceMove(src) + smile = TRUE + smile_color = crayon.paint_color + to_chat(user, "You draw a smiley on [src] visor.") update_appearance() return ITEM_INTERACT_SUCCESS @@ -209,11 +179,9 @@ /obj/item/clothing/head/helmet/space/plasmaman/worn_overlays(mutable_appearance/standing, isinhands) . = ..() if(!isinhands && smile) - var/mutable_appearance/M = mutable_appearance('icons/mob/clothing/head/plasmaman_head.dmi', smile_state) - M.color = smile_color - . += M - if(!isinhands && attached_hat) - . += attached_hat.build_worn_icon(default_layer = HEAD_LAYER, default_icon_file = 'icons/mob/clothing/head/default.dmi') + var/mutable_appearance/smiley = mutable_appearance('icons/mob/clothing/head/plasmaman_head.dmi', smile_state) + smiley.color = smile_color + . += smiley if(!isinhands && !up) . += mutable_appearance('icons/mob/clothing/head/plasmaman_head.dmi', visor_icon) else @@ -249,16 +217,6 @@ update_appearance() return TRUE -/obj/item/clothing/head/helmet/space/plasmaman/attack_hand_secondary(mob/user) - ..() - . = SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN - if(!attached_hat) - return - user.put_in_active_hand(attached_hat) - to_chat(user, span_notice("You removed [attached_hat.name] from helmet!")) - attached_hat = null - update_appearance() - /obj/item/clothing/head/helmet/space/plasmaman/security name = "security plasma envirosuit helmet" desc = "A plasmaman containment helmet designed for security officers, protecting them from burning alive, alongside other undesirables." diff --git a/code/modules/mod/modules/_module.dm b/code/modules/mod/modules/_module.dm index 551145b5e6d..6065a486d0c 100644 --- a/code/modules/mod/modules/_module.dm +++ b/code/modules/mod/modules/_module.dm @@ -340,6 +340,7 @@ if(!use_mod_colors) module_icon.appearance_flags |= RESET_COLOR . += module_icon + SEND_SIGNAL(src, COMSIG_MODULE_GENERATE_WORN_OVERLAY, ., standing) /// Updates the signal used by active modules to be activated /obj/item/mod/module/proc/update_signal(value) diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index 485b66941d4..4ebd0c177ac 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -704,77 +704,15 @@ var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) if(!istype(helmet)) return - RegisterSignal(helmet, COMSIG_ATOM_EXAMINE, PROC_REF(add_examine)) - RegisterSignal(helmet, COMSIG_ATOM_ATTACKBY, PROC_REF(place_hat)) - RegisterSignal(helmet, COMSIG_ATOM_ATTACK_HAND_SECONDARY, PROC_REF(remove_hat)) + helmet.AddComponent(/datum/component/hat_stabilizer) /obj/item/mod/module/hat_stabilizer/on_suit_deactivation(deleting = FALSE) if(deleting) return - if(attached_hat) //knock off the helmet if its on their head. Or, technically, auto-rightclick it for them; that way it saves us code, AND gives them the bubble - remove_hat(src, mod.wearer) var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) if(!istype(helmet)) return - UnregisterSignal(helmet, COMSIG_ATOM_EXAMINE) - UnregisterSignal(helmet, COMSIG_ATOM_ATTACKBY) - UnregisterSignal(helmet, COMSIG_ATOM_ATTACK_HAND_SECONDARY) - -/obj/item/mod/module/hat_stabilizer/proc/add_examine(datum/source, mob/user, list/base_examine) - SIGNAL_HANDLER - if(attached_hat) - base_examine += span_notice("There's \a [attached_hat] placed on the helmet. Right-click to remove it.") - else - base_examine += span_notice("There's nothing placed on the helmet. Yet.") - -/obj/item/mod/module/hat_stabilizer/proc/place_hat(datum/source, obj/item/hitting_item, mob/user) - SIGNAL_HANDLER - if(!istype(hitting_item, /obj/item/clothing/head)) - return - var/obj/item/clothing/hat = hitting_item - if(!mod.active) - balloon_alert(user, "suit must be active!") - return - if(attached_hat) - balloon_alert(user, "hat already attached!") - return - if(hat.clothing_flags & STACKABLE_HELMET_EXEMPT) - balloon_alert(user, "invalid hat!") - return - if(mod.wearer.transferItemToLoc(hitting_item, src, force = FALSE, silent = TRUE)) - attached_hat = hat - var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) - if(istype(helmet)) - helmet.attach_clothing_traits(attached_hat.clothing_traits) - former_flags = helmet.flags_cover - former_visor_flags = helmet.visor_flags_cover - helmet.flags_cover |= attached_hat.flags_cover - helmet.visor_flags_cover |= attached_hat.visor_flags_cover - balloon_alert(user, "hat attached, right-click to remove") - mod.wearer.update_clothing(mod.slot_flags) - -/obj/item/mod/module/hat_stabilizer/generate_worn_overlay() - . = ..() - if(attached_hat) - . += attached_hat.build_worn_icon(default_layer = ABOVE_BODY_FRONT_HEAD_LAYER-0.1, default_icon_file = 'icons/mob/clothing/head/default.dmi') - -/obj/item/mod/module/hat_stabilizer/proc/remove_hat(datum/source, mob/user) - SIGNAL_HANDLER - . = SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN - if(!attached_hat) - return - attached_hat.forceMove(drop_location()) - if(user.put_in_active_hand(attached_hat)) - balloon_alert(user, "hat removed") - else - balloon_alert_to_viewers("the hat falls to the floor!") - var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) - if(istype(helmet)) - helmet.detach_clothing_traits(attached_hat) - helmet.flags_cover = former_flags - helmet.visor_flags_cover = former_visor_flags - attached_hat = null - mod.wearer.update_clothing(mod.slot_flags) + qdel(helmet.GetComponent(/datum/component/hat_stabilizer)) /obj/item/mod/module/hat_stabilizer/syndicate name = "MOD elite hat stabilizer module" diff --git a/tgstation.dme b/tgstation.dme index e4d5d5a3f96..3b955640875 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1134,6 +1134,7 @@ #include "code\datums\components\growth_and_differentiation.dm" #include "code\datums\components\gunpoint.dm" #include "code\datums\components\happiness.dm" +#include "code\datums\components\hat_stabilizer.dm" #include "code\datums\components\hazard_area.dm" #include "code\datums\components\healing_touch.dm" #include "code\datums\components\health_scaling_effects.dm"