diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index c2c28f31257..fea3644ef39 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -150,7 +150,12 @@ #define COMSIG_LIVING_WALL_EXITED "living_wall_exited" ///From base of mob/living/ZImpactDamage() (mob/living, levels, turf/t) #define COMSIG_LIVING_Z_IMPACT "living_z_impact" - #define NO_Z_IMPACT_DAMAGE (1<<0) + /// Just for the signal return, does not run normal living handing of z fall damage for mobs + #define ZIMPACT_CANCEL_DAMAGE (1<<0) + /// Do not show default z-impact message + #define ZIMPACT_NO_MESSAGE (1<<1) + /// Do not do the spin animation when landing + #define ZIMPACT_NO_SPIN (1<<2) /// From mob/living/try_speak(): (message, ignore_spam, forced) #define COMSIG_LIVING_TRY_SPEECH "living_vocal_speech" diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index e031bc50ba8..3632f24a55b 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -716,6 +716,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_THROWINGARM "throwing_arm" #define TRAIT_SETTLER "settler" +/// This mob always lands on their feet when they fall, for better or for worse. +#define TRAIT_CATLIKE_GRACE "catlike_grace" + ///if the atom has a sticker attached to it #define TRAIT_STICKERED "stickered" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index a88d8a43998..6fa83f703fa 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -141,6 +141,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_CANNOT_CRYSTALIZE" = TRAIT_CANNOT_CRYSTALIZE, "TRAIT_CANNOT_OPEN_PRESENTS" = TRAIT_CANNOT_OPEN_PRESENTS, "TRAIT_CANT_RIDE" = TRAIT_CANT_RIDE, + "TRAIT_CATLIKE_GRACE" = TRAIT_CATLIKE_GRACE, "TRAIT_CHANGELING_HIVEMIND_MUTE" = TRAIT_CHANGELING_HIVEMIND_MUTE, "TRAIT_CHASM_DESTROYED" = TRAIT_CHASM_DESTROYED, "TRAIT_CHEF_KISS" = TRAIT_CHEF_KISS, diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 1f7bde586ab..fe4b65950a6 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -318,18 +318,15 @@ overlays.Insert(1, emissive_block) return overlays -/atom/movable/proc/onZImpact(turf/impacted_turf, levels, message = TRUE) +/atom/movable/proc/onZImpact(turf/impacted_turf, levels, impact_flags = NONE) SHOULD_CALL_PARENT(TRUE) - if(message) - visible_message(span_danger("[src] crashes into [impacted_turf]!")) - var/atom/highest = impacted_turf - for(var/atom/hurt_atom as anything in impacted_turf.contents) - if(!hurt_atom.density) - continue - if(isobj(hurt_atom) || ismob(hurt_atom)) - if(hurt_atom.layer > highest.layer) - highest = hurt_atom - INVOKE_ASYNC(src, PROC_REF(SpinAnimation), 5, 2) + if(!(impact_flags & ZIMPACT_NO_MESSAGE)) + visible_message( + span_danger("[src] crashes into [impacted_turf]!"), + span_userdanger("You crash into [impacted_turf]!"), + ) + if(!(impact_flags & ZIMPACT_NO_SPIN)) + INVOKE_ASYNC(src, PROC_REF(SpinAnimation), 5, 2) SEND_SIGNAL(src, COMSIG_ATOM_ON_Z_IMPACT, impacted_turf, levels) return TRUE diff --git a/code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm b/code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm index 6ca9c59c926..f80f1f3dae2 100644 --- a/code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm +++ b/code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm @@ -140,3 +140,9 @@ base_pixel_y = -16 base_pixel_x = -16 duration = 1 SECONDS + +/obj/effect/temp_visual/mook_dust/small + +/obj/effect/temp_visual/mook_dust/small/Initialize(mapload) + . = ..() + transform = transform.Scale(0.5) diff --git a/code/modules/mob/living/basic/pets/cat/cat.dm b/code/modules/mob/living/basic/pets/cat/cat.dm index 425dd428ce5..17fb3841e2d 100644 --- a/code/modules/mob/living/basic/pets/cat/cat.dm +++ b/code/modules/mob/living/basic/pets/cat/cat.dm @@ -55,7 +55,7 @@ AddElement(/datum/element/ai_retaliate) AddElement(/datum/element/pet_bonus, "purrs!") add_verb(src, /mob/living/proc/toggle_resting) - ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) + add_traits(list(TRAIT_CATLIKE_GRACE, TRAIT_VENTCRAWLER_ALWAYS), INNATE_TRAIT) ai_controller.set_blackboard_key(BB_HUNTABLE_PREY, typecacheof(huntable_items)) if(can_breed) add_breeding_component() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 6921eb20a97..07ad2bb097b 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -66,17 +66,6 @@ return ..() -/mob/living/carbon/human/ZImpactDamage(turf/T, levels) - if(stat != CONSCIOUS || levels > 1) // you're not The One - return ..() - var/obj/item/organ/external/wings/gliders = get_organ_by_type(/obj/item/organ/external/wings) - if(HAS_TRAIT(src, TRAIT_FREERUNNING) || gliders?.can_soften_fall()) // the power of parkour or wings allows falling short distances unscathed - visible_message(span_danger("[src] makes a hard landing on [T] but remains unharmed from the fall."), \ - span_userdanger("You brace for the fall. You make a hard landing on [T] but remain unharmed.")) - Knockdown(levels * 40) - return - return ..() - /mob/living/carbon/human/prepare_data_huds() //Update med hud images... ..() diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index 49f18aa9f6b..161b42fff5b 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -11,6 +11,7 @@ /obj/item/organ/external/tail/cat = "Cat", ) inherent_traits = list( + TRAIT_CATLIKE_GRACE, TRAIT_HATED_BY_DOGS, TRAIT_USES_SKINTONES, ) @@ -172,6 +173,14 @@ SPECIES_PERK_NAME = "Grooming", SPECIES_PERK_DESC = "Felinids can lick wounds to reduce bleeding.", ), + list( + SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK, + SPECIES_PERK_ICON = FA_ICON_PERSON_FALLING, + SPECIES_PERK_NAME = "Catlike Grace", + SPECIES_PERK_DESC = "Felinids have catlike instincts allowing them to land upright on their feet. \ + Instead of being knocked down from falling, you only recieve a short slowdown. \ + However, they do not have catlike legs, and the fall will deal additional damage.", + ), list( SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK, SPECIES_PERK_ICON = "assistive-listening-systems", diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index d87554b8c09..bc55ac9d149 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -46,19 +46,74 @@ QDEL_LIST(surgeries) return ..() -/mob/living/onZImpact(turf/T, levels, message = TRUE) - if(!isgroundlessturf(T)) - ZImpactDamage(T, levels) - message = FALSE +/mob/living/onZImpact(turf/impacted_turf, levels, impact_flags = NONE) + if(!isgroundlessturf(impacted_turf)) + impact_flags |= ZImpactDamage(impacted_turf, levels) + return ..() -/mob/living/proc/ZImpactDamage(turf/T, levels) - if(SEND_SIGNAL(src, COMSIG_LIVING_Z_IMPACT, levels, T) & NO_Z_IMPACT_DAMAGE) - return - visible_message(span_danger("[src] crashes into [T] with a sickening noise!"), \ - span_userdanger("You crash into [T] with a sickening noise!")) - adjustBruteLoss((levels * 5) ** 1.5) - Knockdown(levels * 50) +/** + * Called when this mob is receiving damage from falling + * + * * impacted_turf - the turf we are falling onto + * * levels - the number of levels we are falling + */ +/mob/living/proc/ZImpactDamage(turf/impacted_turf, levels) + . = SEND_SIGNAL(src, COMSIG_LIVING_Z_IMPACT, levels, impacted_turf) + if(. & ZIMPACT_CANCEL_DAMAGE) + return . + + // If you are incapped, you probably can't brace yourself + var/can_help_themselves = !incapacitated(IGNORE_RESTRAINTS) + if(levels <= 1 && can_help_themselves) + var/obj/item/organ/external/wings/gliders = get_organ_by_type(/obj/item/organ/external/wings) + if(HAS_TRAIT(src, TRAIT_FREERUNNING) || gliders?.can_soften_fall()) // the power of parkour or wings allows falling short distances unscathed + visible_message( + span_notice("[src] makes a hard landing on [impacted_turf] but remains unharmed from the fall."), + span_notice("You brace for the fall. You make a hard landing on [impacted_turf], but remain unharmed."), + ) + Knockdown(levels * 4 SECONDS) + return . | ZIMPACT_NO_MESSAGE + + var/incoming_damage = (levels * 5) ** 1.5 + // Smaller mobs with catlike grace can ignore damage (EG: cats) + var/small_surface_area = mob_size <= MOB_SIZE_SMALL + var/skip_knockdown = FALSE + if(HAS_TRAIT(src, TRAIT_CATLIKE_GRACE) && (small_surface_area || usable_legs >= 2) && body_position == STANDING_UP && can_help_themselves) + . |= ZIMPACT_NO_MESSAGE|ZIMPACT_NO_SPIN + skip_knockdown = TRUE + if(small_surface_area) + visible_message( + span_notice("[src] makes a hard landing on [impacted_turf], but lands safely on [p_their()] feet!"), + span_notice("You make a hard landing on [impacted_turf], but land safely on your feet!"), + ) + new /obj/effect/temp_visual/mook_dust/small(impacted_turf) + return . + + incoming_damage *= 1.66 + add_movespeed_modifier(/datum/movespeed_modifier/landed_on_feet) + addtimer(CALLBACK(src, TYPE_PROC_REF(/mob, remove_movespeed_modifier), /datum/movespeed_modifier/landed_on_feet), levels * 2 SECONDS) + visible_message( + span_danger("[src] makes a hard landing on [impacted_turf], landing on [p_their()] feet painfully!"), + span_userdanger("You make a hard landing on [impacted_turf], and instinctively land on your feet - painfully!"), + ) + new /obj/effect/temp_visual/mook_dust(impacted_turf) + + if(body_position == STANDING_UP) + var/damage_for_each_leg = round(incoming_damage / 2) + apply_damage(damage_for_each_leg, BRUTE, BODY_ZONE_L_LEG, wound_bonus = -2.5 * levels) + apply_damage(damage_for_each_leg, BRUTE, BODY_ZONE_R_LEG, wound_bonus = -2.5 * levels) + else + apply_damage(incoming_damage, BRUTE, spread_damage = TRUE) + + if(!skip_knockdown) + Knockdown(levels * 5 SECONDS) + return . + +/// Modifier for mobs landing on their feet after a fall +/datum/movespeed_modifier/landed_on_feet + movetypes = GROUND|UPSIDE_DOWN + multiplicative_slowdown = CRAWLING_ADD_SLOWDOWN / 2 //Generic Bump(). Override MobBump() and ObjBump() instead of this. /mob/living/Bump(atom/A) diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index 58857b7730c..e87391b1758 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -476,12 +476,16 @@ UnregisterSignal(mod.wearer, COMSIG_LIVING_Z_IMPACT) /obj/item/mod/module/longfall/proc/z_impact_react(datum/source, levels, turf/fell_on) - if(!drain_power(use_power_cost*levels)) - return + SIGNAL_HANDLER + if(!drain_power(use_power_cost * levels)) + return NONE new /obj/effect/temp_visual/mook_dust(fell_on) mod.wearer.Stun(levels * 1 SECONDS) - to_chat(mod.wearer, span_notice("[src] protects you from the damage!")) - return NO_Z_IMPACT_DAMAGE + mod.wearer.visible_message( + span_notice("[mod.wearer] lands on [fell_on] safely."), + span_notice("[src] protects you from the damage!"), + ) + return ZIMPACT_CANCEL_DAMAGE|ZIMPACT_NO_MESSAGE|ZIMPACT_NO_SPIN ///Thermal Regulator - Regulates the wearer's core temperature. /obj/item/mod/module/thermal_regulator