diff --git a/code/datums/elements/high_fiver.dm b/code/datums/elements/high_fiver.dm new file mode 100644 index 00000000000..d4dc594e64f --- /dev/null +++ b/code/datums/elements/high_fiver.dm @@ -0,0 +1,92 @@ +/** + * # High Fiver Element + * + * Attach to an item to make it offer a "high five" when offered to people + */ +/datum/element/high_fiver + +/datum/element/high_fiver/Attach(datum/target) + . = ..() + if(!isitem(target)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, COMSIG_ITEM_OFFERING, PROC_REF(on_offer)) + RegisterSignal(target, COMSIG_ITEM_OFFER_TAKEN, PROC_REF(on_offer_taken)) + +/datum/element/high_fiver/Detach(datum/source, ...) + . = ..() + UnregisterSignal(source, list(COMSIG_ITEM_OFFERING, COMSIG_ITEM_OFFER_TAKEN)) + +/// Signal proc for [COMSIG_ITEM_OFFERING] to set up the high-five on offer +/datum/element/high_fiver/proc/on_offer(obj/item/source, mob/living/carbon/offerer) + SIGNAL_HANDLER + + if(locate(/mob/living/carbon) in orange(1, offerer)) + offerer.visible_message( + span_notice("[offerer] raises [offerer.p_their()] arm, looking for a high-five!"), + span_notice("You post up, looking for a high-five!"), + vision_distance = 2, + ) + offerer.apply_status_effect(/datum/status_effect/offering, source, /atom/movable/screen/alert/give/highfive) + + else + offerer.visible_message( + span_danger("[offerer] raises [offerer.p_their()] arm, looking around for a high-five, but there's no one around!"), + span_warning("You post up, looking for a high-five, but find no one to accept it..."), + vision_distance = 4, + ) + + return COMPONENT_OFFER_INTERRUPT + +/// Signal proc for [COMSIG_ITEM_OFFER_TAKEN] to continue through with the high-five on take +/datum/element/high_fiver/proc/on_offer_taken(obj/item/source, mob/living/carbon/offerer, mob/living/carbon/taker) + SIGNAL_HANDLER + + var/open_hands_taker = 0 + var/slappers_giver = 0 + // see how many hands the taker has open for high'ing + for(var/hand in taker.held_items) + if(isnull(hand)) + open_hands_taker++ + + // see how many hands the offerer is using for high'ing + for(var/obj/item/slap_check in offerer.held_items) + if(slap_check.item_flags & HAND_ITEM) + slappers_giver++ + + var/high_ten = (slappers_giver >= 2) + var/descriptor = "high-[high_ten ? "ten" : "five"]" + + if(open_hands_taker <= 0) + to_chat(taker, span_warning("You can't [descriptor] [offerer] with no open hands!")) + taker.add_mood_event(descriptor, /datum/mood_event/high_five_full_hand) // not so successful now! + return COMPONENT_OFFER_INTERRUPT + + playsound(offerer, 'sound/weapons/slap.ogg', min(50 * slappers_giver, 300), TRUE, 1) + offerer.mind.add_memory(MEMORY_HIGH_FIVE, list(DETAIL_DEUTERAGONIST = taker, DETAIL_HIGHFIVE_TYPE = descriptor), story_value = STORY_VALUE_OKAY) + taker.mind.add_memory(MEMORY_HIGH_FIVE, list(DETAIL_DEUTERAGONIST = offerer, DETAIL_HIGHFIVE_TYPE = descriptor), story_value = STORY_VALUE_OKAY) + + if(high_ten) + to_chat(taker, span_nicegreen("You give high-tenning [offerer] your all!")) + offerer.visible_message( + span_notice("[taker] enthusiastically high-tens [offerer]!"), + span_nicegreen("Wow! You're high-tenned [taker]!"), + span_hear("You hear a sickening sound of flesh hitting flesh!"), + ignored_mobs = taker, + ) + + offerer.add_mood_event(descriptor, /datum/mood_event/high_ten) + taker.add_mood_event(descriptor, /datum/mood_event/high_ten) + else + to_chat(taker, span_nicegreen("You high-five [offerer]!")) + offerer.visible_message( + span_notice("[taker] high-fives [offerer]!"), + span_nicegreen("All right! You're high-fived by [taker]!"), + span_hear("You hear a sickening sound of flesh hitting flesh!"), + ignored_mobs = taker, + ) + + offerer.add_mood_event(descriptor, /datum/mood_event/high_five) + taker.add_mood_event(descriptor, /datum/mood_event/high_five) + + return COMPONENT_OFFER_INTERRUPT diff --git a/code/game/objects/items/hand_items.dm b/code/game/objects/items/hand_items.dm index 55576bfc609..358b5c208fb 100644 --- a/code/game/objects/items/hand_items.dm +++ b/code/game/objects/items/hand_items.dm @@ -212,6 +212,10 @@ /// How many smaller table smacks we can do before we're out var/table_smacks_left = 3 +/obj/item/hand_item/slapper/Initialize(mapload) + . = ..() + AddElement(/datum/element/high_fiver) + /obj/item/hand_item/slapper/attack(mob/living/slapped, mob/living/carbon/human/user) SEND_SIGNAL(user, COMSIG_LIVING_SLAP_MOB, slapped) @@ -313,54 +317,12 @@ user.visible_message("[span_danger("[user] slams [user.p_their()] fist down on [table]!")]", "[span_danger("You slam your fist down on [table]!")]") qdel(src) -/obj/item/hand_item/slapper/on_offered(mob/living/carbon/offerer, mob/living/carbon/offered) - . = TRUE - - if(!(locate(/mob/living/carbon) in orange(1, offerer))) - visible_message(span_danger("[offerer] raises [offerer.p_their()] arm, looking around for a high-five, but there's no one around!"), \ - span_warning("You post up, looking for a high-five, but finding no one within range!"), null, 2) - return - - offerer.visible_message(span_notice("[offerer] raises [offerer.p_their()] arm, looking for a high-five!"), \ - span_notice("You post up, looking for a high-five!"), null, 2) - offerer.apply_status_effect(/datum/status_effect/offering, src, /atom/movable/screen/alert/give/highfive) - -/// Yeah broh! This is where we do the high-fiving (or high-tenning :o) +// Successful takes will qdel our hand after /obj/item/hand_item/slapper/on_offer_taken(mob/living/carbon/offerer, mob/living/carbon/taker) - . = TRUE - - var/open_hands_taker - var/slappers_giver - for(var/i in taker.held_items) // see how many hands the taker has open for high'ing - if(isnull(i)) - open_hands_taker++ - - if(!open_hands_taker) - to_chat(taker, span_warning("You can't high-five [offerer] with no open hands!")) - taker.add_mood_event("high_five", /datum/mood_event/high_five_full_hand) // not so successful now! + . = ..() + if(!.) return - for(var/i in offerer.held_items) - var/obj/item/hand_item/slapper/slap_check = i - if(istype(slap_check)) - slappers_giver++ - - if(slappers_giver >= 2) // we only check this if it's already established the taker has 2+ hands free - offerer.visible_message(span_notice("[taker] enthusiastically high-tens [offerer]!"), span_nicegreen("Wow! You're high-tenned [taker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), ignored_mobs=taker) - to_chat(taker, span_nicegreen("You give high-tenning [offerer] your all!")) - playsound(offerer, 'sound/weapons/slap.ogg', 100, TRUE, 1) - offerer.mind.add_memory(MEMORY_HIGH_FIVE, list(DETAIL_DEUTERAGONIST = taker, DETAIL_HIGHFIVE_TYPE = "high ten"), story_value = STORY_VALUE_OKAY) - taker.mind.add_memory(MEMORY_HIGH_FIVE, list(DETAIL_DEUTERAGONIST = offerer, DETAIL_HIGHFIVE_TYPE = "high ten"), story_value = STORY_VALUE_OKAY) - offerer.add_mood_event("high_five", /datum/mood_event/high_ten) - taker.add_mood_event("high_five", /datum/mood_event/high_ten) - else - offerer.visible_message(span_notice("[taker] high-fives [offerer]!"), span_nicegreen("All right! You're high-fived by [taker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), ignored_mobs=taker) - to_chat(taker, span_nicegreen("You high-five [offerer]!")) - playsound(offerer, 'sound/weapons/slap.ogg', 50, TRUE, -1) - offerer.mind.add_memory(MEMORY_HIGH_FIVE, list(DETAIL_DEUTERAGONIST = taker, DETAIL_HIGHFIVE_TYPE = "high five"), story_value = STORY_VALUE_OKAY) - taker.mind.add_memory(MEMORY_HIGH_FIVE, list(DETAIL_DEUTERAGONIST = offerer, DETAIL_HIGHFIVE_TYPE = "high five"), story_value = STORY_VALUE_OKAY) - offerer.add_mood_event("high_five", /datum/mood_event/high_five) - taker.add_mood_event("high_five", /datum/mood_event/high_five) qdel(src) diff --git a/code/modules/spells/spell_types/touch/_touch.dm b/code/modules/spells/spell_types/touch/_touch.dm index ce7fced2ce4..6fab59c54ef 100644 --- a/code/modules/spells/spell_types/touch/_touch.dm +++ b/code/modules/spells/spell_types/touch/_touch.dm @@ -132,6 +132,10 @@ RegisterSignal(attached_hand, COMSIG_ITEM_DROPPED, PROC_REF(on_hand_dropped)) RegisterSignal(attached_hand, COMSIG_PARENT_QDELETING, PROC_REF(on_hand_deleted)) + // We can high five with our touch hand. It casts the spell on people. Radical + attached_hand.AddElement(/datum/element/high_fiver) + RegisterSignal(attached_hand, COMSIG_ITEM_OFFER_TAKEN, PROC_REF(on_hand_taken)) + /// Unregisters all signal procs for the hand. /datum/action/cooldown/spell/touch/proc/unregister_hand_signals() SHOULD_CALL_PARENT(TRUE) @@ -141,6 +145,7 @@ COMSIG_ITEM_AFTERATTACK_SECONDARY, COMSIG_ITEM_DROPPED, COMSIG_PARENT_QDELETING, + COMSIG_ITEM_OFFER_TAKEN, )) // Touch spells don't go on cooldown OR give off an invocation until the hand is used itself. @@ -289,6 +294,20 @@ remove_hand(dropper, reset_cooldown_after = TRUE) +/** + * Signal proc for [COMSIG_ITEM_OFFER_TAKEN] from our attached hand. + * + * Giving a high five with our hand makes it cast + */ +/datum/action/cooldown/spell/touch/proc/on_hand_taken(obj/item/source, mob/living/carbon/offerer, mob/living/carbon/taker) + SIGNAL_HANDLER + + if(!can_hit_with_hand(taker, offerer)) + return + + INVOKE_ASYNC(src, PROC_REF(do_hand_hit), source, taker, offerer) + return COMPONENT_OFFER_INTERRUPT + /** * Called whenever our spell is cast, but blocked by antimagic. */ diff --git a/tgstation.dme b/tgstation.dme index 1833abd9988..d863683a64c 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1155,6 +1155,7 @@ #include "code\datums\elements\forced_gravity.dm" #include "code\datums\elements\frozen.dm" #include "code\datums\elements\haunted.dm" +#include "code\datums\elements\high_fiver.dm" #include "code\datums\elements\honkspam.dm" #include "code\datums\elements\item_fov.dm" #include "code\datums\elements\item_scaling.dm"