diff --git a/code/__DEFINES/dcs/signals/signals.dm b/code/__DEFINES/dcs/signals/signals.dm index 638b5220bc3c..9e034edeeb2c 100644 --- a/code/__DEFINES/dcs/signals/signals.dm +++ b/code/__DEFINES/dcs/signals/signals.dm @@ -527,7 +527,6 @@ #define COMSIG_CARBON_HUGGED "carbon_hugged" ///When a carbon mob is headpatted, this is called on the carbon that is headpatted. (mob/living/headpatter) #define COMSIG_CARBON_HEADPAT "carbon_headpatted" - ///When a carbon slips. Called on /turf/open/handle_slip() #define COMSIG_ON_CARBON_SLIP "carbon_slip" ///When a carbon gets a vending machine tilted on them diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index f5e51d1d59f4..a3b44b5c29e1 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -302,3 +302,18 @@ description = span_boldwarning("It isn't ending... it isn't ending, come on...\n") mood_change = -18 timeout = 3 MINUTES + +/datum/mood_event/bad_touch_bear_hug + description = "I just got squeezed way too hard." + mood_change = -3 + timeout = 2 MINUTES + +/datum/mood_event/rippedtail + description = "I ripped their tail right off, what have I done!\n" + mood_change = -5 + timeout = 30 SECONDS + +/datum/mood_event/bad_boop + description = "Someone booped my nose... ACK!\n" + mood_change = -3 + timeout = 4 MINUTES diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm index 1ab201bc0186..e35d798386c8 100644 --- a/code/datums/mood_events/generic_positive_events.dm +++ b/code/datums/mood_events/generic_positive_events.dm @@ -1,6 +1,11 @@ /datum/mood_event/hug description = "Hugs are nice.\n" mood_change = 1 + timeout = 2 + +/datum/mood_event/bear_hug + description = "I got squeezed very tightly, but it was quite nice." + mood_change = 2 timeout = 2 MINUTES /datum/mood_event/betterhug @@ -19,6 +24,14 @@ /datum/mood_event/besthug/add_effects(mob/friend) description = "[friend.name] is great to be around, [friend.p_they()] makes me feel so happy!\n" +/datum/mood_event/best_boop + description = "Someone booped my nose, they are silly!\n" + mood_change = 5 + timeout = 4 MINUTES + +/datum/mood_event/best_boop/add_effects(mob/friend) + description = "[friend.name] booped my nose, [friend.p_they()] [friend.p_are()] silly!\n" + /datum/mood_event/warmhug description = "Warm cozy hugs are the best!\n" mood_change = 1 diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index e5cc9709559c..8a90ac9fe614 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -582,8 +582,8 @@ GLOBAL_LIST_EMPTY(created_baseturf_lists) /turf/proc/acid_melt() return -/turf/handle_fall(mob/faller) - if(has_gravity(src)) +/turf/handle_fall(mob/faller, fall_sound_played) + if(has_gravity(src) && !fall_sound_played) playsound(src, "bodyfall", 50, TRUE) faller.drop_all_held_items() diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 62174120a60f..56b8fe2792d4 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -399,6 +399,8 @@ Paralyze(60) /mob/living/carbon/proc/help_shake_act(mob/living/carbon/M) + var/datum/component/mood/hugger_mood = M.GetComponent(/datum/component/mood) + var/nosound = FALSE if(on_fire) to_chat(M, "You can't put [p_them()] out with just your bare hands!") return @@ -426,6 +428,22 @@ mothdust += 10; if(istype(dna.species, /datum/species/moth)) M.mothdust += 10; // End WS edit + + if(M.zone_selected == BODY_ZONE_PRECISE_MOUTH) // Nose boops! + nosound = TRUE + playsound(src, 'sound/effects/boop.ogg', 50, 0) + if (HAS_TRAIT(M, TRAIT_FRIENDLY)) + M.visible_message(span_notice("[M] playfully boops your nose."), span_notice("You playfully boop [src]'s nose.")) + if (hugger_mood.sanity >= SANITY_GREAT) + new /obj/effect/temp_visual/heart(loc) + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "best_boop", /datum/mood_event/best_boop, M) + else + M.visible_message(span_notice("[M] boops [src]'s nose."), span_notice("You boop [src] on the nose.")) + if(HAS_TRAIT(src, TRAIT_BADTOUCH)) + to_chat(M, span_warning("A scowl forms on [src]'s face as you daringly press your finger against [p_their()] nose.")) + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "bad_boop", /datum/mood_event/bad_boop, M) + + else if(check_zone(M.zone_selected) == BODY_ZONE_HEAD) //Headpats! SEND_SIGNAL(src, COMSIG_CARBON_HEADPAT, M) M.visible_message("[M] gives [src] a pat on the head to make [p_them()] feel better!", \ @@ -440,10 +458,35 @@ if(HAS_TRAIT(src, TRAIT_BADTOUCH)) to_chat(M, "[src] looks visibly upset as you pat [p_them()] on the head.") +// Tail pulls! + else if((M.zone_selected == BODY_ZONE_PRECISE_GROIN) && !isnull(src.getorgan(/obj/item/organ/tail))) + M.visible_message(span_notice("[M] pulls on [src]'s tail!"), \ + null, span_hear("You hear a soft patter."), DEFAULT_MESSAGE_RANGE, list(M, src)) + to_chat(M, span_notice("You pull on [src]'s tail!")) + to_chat(src, span_notice("[M] pulls on your tail!")) + +// Rips off fake tails + else if((M.zone_selected == BODY_ZONE_PRECISE_GROIN) && (istype(head, /obj/item/clothing/head/kitty) || istype(head, /obj/item/clothing/head/collectable/kitty))) + var/obj/item/clothing/head/faketail = head + M.visible_message(span_danger("[M] pulls on [src]'s tail... and it rips off!"), \ + null, span_hear("You hear a ripping sound."), DEFAULT_MESSAGE_RANGE, list(M, src)) + to_chat(M, span_danger("You pull on [src]'s tail... and it rips off!")) + to_chat(src, span_userdanger("[M] pulls on your tail... and it rips off!")) + playsound(loc, 'sound/effects/rip1.ogg', 75, TRUE) + dropItemToGround(faketail) + M.put_in_hands(faketail) + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "rippedtail", /datum/mood_event/rippedtail) + else if(M.zone_selected == BODY_ZONE_CHEST || M.zone_selected == BODY_ZONE_PRECISE_GROIN) //WS Edit - Adds more help emotes SEND_SIGNAL(src, COMSIG_CARBON_HUGGED, M) SEND_SIGNAL(M, COMSIG_CARBON_HUG, M, src) - M.visible_message("[M] hugs [src] to make [p_them()] feel better!", \ + if (M.grab_state >= GRAB_AGGRESSIVE) + M.visible_message(span_notice("[M] embraces [src] in a tight bear hug!"), \ + null, span_hear("You hear the rustling of clothes."), DEFAULT_MESSAGE_RANGE, list(M, src)) + to_chat(M, span_notice("You wrap [src] into a tight bear hug!")) + to_chat(src, span_notice("[M] squeezes you super tightly in a firm bear hug!")) + else + M.visible_message("[M] hugs [src] to make [p_them()] feel better!", \ "You hug [src] to make [p_them()] feel better!") if(istype(M.dna.species, /datum/species/moth)) //WS edit - moth dust from hugging mothdust += 15; @@ -455,12 +498,17 @@ // No moodlets for people who hate touches if(!HAS_TRAIT(src, TRAIT_BADTOUCH)) - if(bodytemperature > M.bodytemperature) - if(!HAS_TRAIT(M, TRAIT_BADTOUCH)) - SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/warmhug, src) // Hugger got a warm hug (Unless they hate hugs) - SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/hug) // Reciver always gets a mood for being hugged - else - SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/warmhug, M) // You got a warm hug + if (M.grab_state >= GRAB_AGGRESSIVE) + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/bear_hug) + if(bodytemperature > M.bodytemperature) + if(!HAS_TRAIT(M, TRAIT_BADTOUCH)) + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/warmhug) // Hugger got a warm hug (Unless they hate hugs) + SEND_SIGNAL(M, "hug", /datum/mood_event/hug) // Receiver always gets a mood for being hugged + else + SEND_SIGNAL(M, "hug", /datum/mood_event/warmhug,) // You got a warm hug + else + if (M.grab_state >= GRAB_AGGRESSIVE) + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/bad_touch_bear_hug) // Let people know if they hugged someone really warm or really cold if(M.bodytemperature > M.dna.species.bodytemp_heat_damage_limit) @@ -474,7 +522,6 @@ to_chat(M, "It feels like [src] is freezing as you hug them.") if(HAS_TRAIT(M, TRAIT_FRIENDLY)) - var/datum/component/mood/hugger_mood = M.GetComponent(/datum/component/mood) if (hugger_mood.sanity >= SANITY_GREAT) new /obj/effect/temp_visual/heart(loc) SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/besthug, M) @@ -503,8 +550,17 @@ AdjustParalyzed(-60) AdjustImmobilized(-60) set_resting(FALSE) - - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) + if(!nosound) + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) + +// Shake animation +#define SHAKE_ANIMATION_OFFSET (4) + if (incapacitated()) + var/direction = prob(50) ? -1 : 1 + animate(src, pixel_x = pixel_x + SHAKE_ANIMATION_OFFSET * direction, time = 1, easing = QUAD_EASING | EASE_OUT, flags = ANIMATION_PARALLEL) + animate(pixel_x = pixel_x - (SHAKE_ANIMATION_OFFSET * 2 * direction), time = 1) + animate(pixel_x = pixel_x + SHAKE_ANIMATION_OFFSET * direction, time = 1, easing = QUAD_EASING | EASE_IN) +#undef SHAKE_ANIMATION_OFFSET /// Check ourselves to see if we've got any shrapnel, return true if we do. This is a much simpler version of what humans do, we only indicate we're checking ourselves if there's actually shrapnel /mob/living/carbon/proc/check_self_for_injuries() diff --git a/code/modules/mob/living/carbon/emote.dm b/code/modules/mob/living/carbon/emote.dm index 5e5e8fca6d24..358fa0626092 100644 --- a/code/modules/mob/living/carbon/emote.dm +++ b/code/modules/mob/living/carbon/emote.dm @@ -39,25 +39,6 @@ key = "blink_r" message = "blinks rapidly." -/datum/emote/living/carbon/clap - key = "clap" - key_third_person = "claps" - message = "claps." - muzzle_ignore = TRUE - hands_use_check = TRUE - emote_type = EMOTE_AUDIBLE - vary = TRUE - -/datum/emote/living/carbon/clap/get_sound(mob/living/user) - if(ishuman(user)) - if(!user.get_bodypart(BODY_ZONE_L_ARM) || !user.get_bodypart(BODY_ZONE_R_ARM)) - return - else - return pick('sound/misc/clap1.ogg', - 'sound/misc/clap2.ogg', - 'sound/misc/clap3.ogg', - 'sound/misc/clap4.ogg') - /datum/emote/living/carbon/crack key = "crack" key_third_person = "cracks" diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 56ae0db795e5..f4042464f981 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -232,6 +232,16 @@ message = "jumps!" hands_use_check = TRUE +/datum/emote/living/jump/run_emote(mob/living/user, params, type_override, intentional) + . = ..() + if(!.) + return FALSE + animate(user, pixel_y = user.pixel_y + 4, time = 0.1 SECONDS) + animate(pixel_y = user.pixel_y - 4, time = 0.1 SECONDS) + +/datum/emote/living/jump/get_sound(mob/living/user) + return 'sound/weapons/thudswoosh.ogg' + /datum/emote/living/kiss key = "kiss" key_third_person = "kisses" @@ -361,6 +371,18 @@ message = "shivers." emote_type = EMOTE_AUDIBLE +#define SHIVER_LOOP_DURATION (1 SECONDS) +/datum/emote/living/shiver/run_emote(mob/living/user, params, type_override, intentional) + . = ..() + if(!.) + return FALSE + animate(user, pixel_x = user.pixel_x + 1, time = 0.1 SECONDS) + for(var/i in 1 to SHIVER_LOOP_DURATION / (0.2 SECONDS)) //desired total duration divided by the iteration duration to give the necessary iteration count + animate(pixel_x = user.pixel_x - 1, time = 0.1 SECONDS) + animate(pixel_x = user.pixel_x + 1, time = 0.1 SECONDS) + animate(pixel_x = user.pixel_x - 1, time = 0.1 SECONDS) +#undef SHIVER_LOOP_DURATION + /datum/emote/living/sigh key = "sigh" key_third_person = "sighs" @@ -460,20 +482,62 @@ key_third_person = "sways" message = "sways around dizzily." +/datum/emote/living/sway/run_emote(mob/living/user, params, type_override, intentional) + . = ..() + if(!.) + return FALSE + animate(user, pixel_x = user.pixel_x + 2, time = 0.5 SECONDS) + for(var/i in 1 to 2) + animate(pixel_x = user.pixel_x - 4, time = 1.0 SECONDS) + animate(pixel_x = user.pixel_x + 4, time = 1.0 SECONDS) + animate(pixel_x = user.pixel_x - 2, time = 0.5 SECONDS) + /datum/emote/living/tremble key = "tremble" key_third_person = "trembles" message = "trembles in fear!" +#define TREMBLE_LOOP_DURATION (4.4 SECONDS) +/datum/emote/living/tremble/run_emote(mob/living/user, params, type_override, intentional) + . = ..() + if(!.) + return FALSE + animate(user, pixel_x = user.pixel_x + 2, time = 0.2 SECONDS) + for(var/i in 1 to TREMBLE_LOOP_DURATION / (0.4 SECONDS)) //desired total duration divided by the iteration duration to give the necessary iteration count + animate(pixel_x = user.pixel_x - 2, time = 0.2 SECONDS) + animate(pixel_x = user.pixel_x + 2, time = 0.2 SECONDS) + animate(pixel_x = user.pixel_x - 2, time = 0.2 SECONDS) +#undef TREMBLE_LOOP_DURATION + /datum/emote/living/twitch key = "twitch" key_third_person = "twitches" message = "twitches violently." +/datum/emote/living/twitch/run_emote(mob/living/user, params, type_override, intentional) + . = ..() + if(!.) + return FALSE + animate(user, pixel_x = user.pixel_x - 1, time = 0.1 SECONDS) + animate(pixel_x = user.pixel_x + 1, time = 0.1 SECONDS) + animate(time = 0.1 SECONDS) + animate(pixel_x = user.pixel_x - 1, time = 0.1 SECONDS) + animate(pixel_x = user.pixel_x + 1, time = 0.1 SECONDS) + /datum/emote/living/twitch_s key = "twitch_s" message = "twitches." +/datum/emote/living/twitch_s/run_emote(mob/living/user, params, type_override, intentional) + . = ..() + if(!.) + return FALSE + animate(user, pixel_x = user.pixel_x - 1, time = 0.1 SECONDS) + animate(pixel_x = user.pixel_x + 1, time = 0.1 SECONDS) + animate(time = 0.1 SECONDS) + animate(pixel_x = user.pixel_x - 1, time = 0.1 SECONDS) + animate(pixel_x = user.pixel_x + 1, time = 0.1 SECONDS) + /datum/emote/living/wave key = "wave" key_third_person = "waves" @@ -603,3 +667,85 @@ key_third_person = "clacks" message = "clacks their beak." emote_type = EMOTE_VISIBLE + +/datum/emote/living/tilt + key = "tilt" + key_third_person = "tilts" + message = "tilts their head to the side." + +/datum/emote/living/carbon/snap + key = "snap" + key_third_person = "snaps" + message = "snaps their fingers." + message_param = "snaps their fingers at %t." + emote_type = EMOTE_AUDIBLE + hands_use_check = TRUE + muzzle_ignore = TRUE + +/datum/emote/living/carbon/snap/get_sound(mob/living/user) + if(ishuman(user)) + if(!user.get_bodypart(BODY_ZONE_L_ARM) || !user.get_bodypart(BODY_ZONE_R_ARM)) + return + else + return pick('sound/misc/fingersnap1.ogg', + 'sound/misc/fingersnap2.ogg') + +/datum/emote/living/snap2 + key = "snap2" + key_third_person = "snaps twice" + message = "snaps twice." + message_param = "snaps twice at %t." + emote_type = EMOTE_AUDIBLE + muzzle_ignore = TRUE + hands_use_check = TRUE + vary = TRUE + sound = 'sound/misc/snap2.ogg' + +/datum/emote/living/snap3 + key = "snap3" + key_third_person = "snaps thrice" + message = "snaps thrice." + message_param = "snaps thrice at %t." + emote_type = EMOTE_AUDIBLE + muzzle_ignore = TRUE + hands_use_check = TRUE + vary = TRUE + sound = 'sound/misc/snap3.ogg' + +/datum/emote/living/carbon/clap + key = "clap" + key_third_person = "claps" + message = "claps." + muzzle_ignore = TRUE + hands_use_check = TRUE + emote_type = EMOTE_AUDIBLE + vary = TRUE + +/datum/emote/living/carbon/clap/get_sound(mob/living/user) + if(ishuman(user)) + if(!user.get_bodypart(BODY_ZONE_L_ARM) || !user.get_bodypart(BODY_ZONE_R_ARM)) + return + else + return pick('sound/misc/clap1.ogg', + 'sound/misc/clap2.ogg', + 'sound/misc/clap3.ogg', + 'sound/misc/clap4.ogg') + +/datum/emote/living/clap1 + key = "clap1" + key_third_person = "claps once" + message = "claps once." + emote_type = EMOTE_AUDIBLE + muzzle_ignore = TRUE + hands_use_check = TRUE + vary = TRUE + mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) + +/datum/emote/living/clap1/get_sound(mob/living/user) + return pick('sound/misc/claponce1.ogg', + 'sound/misc/claponce2.ogg') + +/datum/emote/living/clap1/can_run_emote(mob/living/carbon/user, status_check = TRUE , intentional) + if(user.usable_hands < 2) + return FALSE + return ..() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 741dfcc16015..5e3442ba039a 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -484,7 +484,9 @@ if(!silent) to_chat(src, "You will now lay down as soon as you are able to.") else - if(!silent) + if(!silent && m_intent == MOVE_INTENT_WALK) + to_chat(src, "You gently lay down.") + else if(!silent) to_chat(src, "You lay down.") set_lying_down() else @@ -1787,12 +1789,15 @@ GLOBAL_VAR_INIT(ssd_indicator_overlay, mutable_appearance('icons/mob/ssd_indicat /// Changes the value of the [living/body_position] variable. -/mob/living/proc/set_body_position(new_value) +/mob/living/proc/set_body_position(new_value, fall_sound_played) if(body_position == new_value) return . = body_position body_position = new_value if(new_value == LYING_DOWN) // From standing to lying down. + if(has_gravity() && m_intent != MOVE_INTENT_WALK) + playsound(src, "bodyfall", 50, TRUE) // Will play the falling sound if not walking + fall_sound_played = TRUE on_lying_down() else // From lying down to standing up. on_standing_up() diff --git a/sound/effects/Nose_boop.ogg b/sound/effects/Nose_boop.ogg new file mode 100644 index 000000000000..6a742e95eac6 Binary files /dev/null and b/sound/effects/Nose_boop.ogg differ diff --git a/sound/effects/boop.ogg b/sound/effects/boop.ogg new file mode 100644 index 000000000000..482a2a8ecdab Binary files /dev/null and b/sound/effects/boop.ogg differ diff --git a/sound/misc/claponce1.ogg b/sound/misc/claponce1.ogg new file mode 100644 index 000000000000..1e12d0daa3b5 Binary files /dev/null and b/sound/misc/claponce1.ogg differ diff --git a/sound/misc/claponce2.ogg b/sound/misc/claponce2.ogg new file mode 100644 index 000000000000..10dfdba121b4 Binary files /dev/null and b/sound/misc/claponce2.ogg differ diff --git a/sound/misc/fingersnap1.ogg b/sound/misc/fingersnap1.ogg new file mode 100644 index 000000000000..2d5d255be1ce Binary files /dev/null and b/sound/misc/fingersnap1.ogg differ diff --git a/sound/misc/fingersnap2.ogg b/sound/misc/fingersnap2.ogg new file mode 100644 index 000000000000..d11f2f7a7415 Binary files /dev/null and b/sound/misc/fingersnap2.ogg differ diff --git a/sound/misc/snap2.ogg b/sound/misc/snap2.ogg new file mode 100644 index 000000000000..1537084be43c Binary files /dev/null and b/sound/misc/snap2.ogg differ diff --git a/sound/misc/snap3.ogg b/sound/misc/snap3.ogg new file mode 100644 index 000000000000..ca7506dc2c36 Binary files /dev/null and b/sound/misc/snap3.ogg differ