Files
VOREStation/code/modules/multiz/movement_vr.dm
T
SatinIsle 557ad96746 The Bigger They Are, The Harder They Fall (#18616)
* Heavy Landing

Added a new heavy landing trait (and hard fall var to other mobs) that cause the mob to take more damage, get weakened for longer and create some damage to the floor tiles (50% chance). Can not be taken with soft landing. Be the fatty you always meant to be.

* Changed to a defined trait thing

* Update code/modules/mob/living/carbon/human/species/species.dm

Co-authored-by: Guti <32563288+TheCaramelion@users.noreply.github.com>

* Update code/modules/multiz/movement.dm

Co-authored-by: Guti <32563288+TheCaramelion@users.noreply.github.com>

* Update code/modules/multiz/movement.dm

Co-authored-by: Guti <32563288+TheCaramelion@users.noreply.github.com>

---------

Co-authored-by: Guti <32563288+TheCaramelion@users.noreply.github.com>
Co-authored-by: Cameron Lennox <killer65311@gmail.com>
2025-10-22 01:46:45 -04:00

319 lines
15 KiB
Plaintext

/mob/living/handle_fall(var/turf/landing)
var/mob/living/drop_mob = locate(/mob/living, landing)
if(locate(/obj/structure/stairs) in landing)
for(var/atom/A in landing)
if(!A.CanPass(src, src.loc))
return FALSE
Move(landing)
if(isliving(src))
var/mob/living/L = src
if(L.pulling)
L.pulling.forceMove(landing)
return TRUE
for(var/obj/O in loc)
if(!O.CanFallThru(src, landing))
return TRUE
if(SEND_SIGNAL(src, COMSIG_LIVING_FALLING_DOWN, landing, drop_mob) & COMSIG_CANCEL_FALL)
return
if(drop_mob && drop_mob != src)
///Varible to tell if we take damage or not for falling.
var/safe_fall = FALSE
if(drop_mob.softfall || (isanimal(drop_mob) && drop_mob.mob_size <= MOB_SMALL))
safe_fall = TRUE
if(ishuman(drop_mob))
var/mob/living/carbon/human/H = drop_mob
if(H.species.soft_landing)
safe_fall = TRUE
forceMove(get_turf(drop_mob))
if(!safe_fall)
drop_mob.Weaken(8)
Weaken(8)
playsound(src, "punch", 25, 1, -1)
var/tdamage
for(var/i = 1 to 5) //Twice as less damage because cushioned fall, but both get damaged.
tdamage = rand(0, 5)
if(HAS_TRAIT(drop_mob, TRAIT_HEAVY_LANDING))
tdamage = tdamage * 1.5
drop_mob.adjustBruteLoss(tdamage)
adjustBruteLoss(tdamage)
drop_mob.updatehealth()
updatehealth()
if(HAS_TRAIT(drop_mob, TRAIT_HEAVY_LANDING))
drop_mob.visible_message(span_danger("\The [drop_mob] crashes down onto \the [src]!"))
else
drop_mob.visible_message(span_danger("\The [drop_mob] falls onto \the [src]!"))
else
drop_mob.visible_message(span_notice("\The [drop_mob] safely brushes past \the [src] as they land."))
// Then call parent to have us actually fall
return ..()
/mob/CheckFall(var/atom/movable/falling_atom)
return falling_atom.fall_impact(src)
/mob/observer/dead/CheckFall()
return
/mob/proc/CanZPass(atom/A, direction)
if(z == A.z) //moving FROM this turf
return direction == UP //can't go below
else
if(direction == UP) //on a turf below, trying to enter
return 0
if(direction == DOWN) //on a turf above, trying to enter
return 1
/turf/simulated/proc/climb_wall()
set name = "Climb Wall"
set desc = "Using nature's gifts or technology, scale that wall!"
set category = "Object"
set src in oview(1)
if(!isliving(usr)) return //Why would ghosts want to climb?
var/mob/living/L = usr
var/climbing_delay_min = L.climbing_delay
var/fall_chance = 0
var/drop_our_held = FALSE
var/nutrition_cost = 50 //Climbing up is harder!
//Checking if there's any point trying to climb
var/turf/above_wall = GetAbove(src)
if(L.nutrition <= nutrition_cost)
to_chat(L, span_warning("You [L.isSynthetic() ? "lack the energy" : "are too hungry"] for such strenous activities!"))
return
if(!above_wall) //No multiZ
to_chat(L, span_notice("There's nothing interesting over this cliff!"))
return
var/turf/above_mob = GetAbove(L) //Making sure we got headroom
if(!above_mob.CanZPass(L, UP))
to_chat(L, span_warning("\The [above_mob] blocks your way."))
return
if(above_wall.density) //We check density rather than type since some walls dont have a floor on top.
to_chat(L, span_warning("\The [above_wall] blocks your way."))
return
if(LAZYLEN(above_wall.contents) > 30) //We avoid checking the contents if it's too cluttered to avoid issues
to_chat(L, span_warning("\The [above_wall] is too cluttered to climb onto!"))
return
for(var/atom/A in above_wall.contents)
if(A.density)
to_chat(L, span_warning("\The [A.name] blocks your way!"))
return
//human mobs got species and can wear special equipment
//We give them some snowflake treatment as a consequence
if(ishuman(L))
var/permit_human = FALSE
var/mob/living/carbon/human/H = L
if(H.species.climbing_delay < H.climbing_delay)
climbing_delay_min = H.species.climbing_delay
var/list/gear = list(H.head, H.wear_mask, H.wear_suit, H.w_uniform,
H.gloves, H.shoes, H.belt, H.get_active_hand(), H.get_inactive_hand())
if(H.can_climb || H.species.can_climb)
permit_human = TRUE
for(var/obj/item/I in gear)
if(I.rock_climbing)
permit_human = TRUE
if(I.climbing_delay > climbing_delay_min)
climbing_delay_min = I.climbing_delay //We get the maximum possible speedup out of worn equipment
if(!permit_human)
var/sure = tgui_alert(H,"Are you sure you want to try without tools? It's VERY LIKELY \
you will fall and get hurt. More agile species might have better luck", "Second Thoughts", list("Bring it!", "Stay grounded"))
if(sure || sure == "Stay grounded") return
fall_chance = clamp(100 - H.species.agility, 40, 90) //This should be 80 for most species. Traceur would reduce to 10%, so clamping higher
//If not a human mob, must be simple or silicon. They got a var stored on their mob we can check
else if(!L.can_climb)
var/sure = tgui_alert(L,"Are you sure you want to try without tools? It's VERY LIKELY \
you will fall and get hurt. More agile species might have better luck", "Second Thoughts", list("Bring it!", "Stay grounded"))
if(!sure || sure == "Stay grounded") return
if(isrobot(L))
fall_chance = 80 // Robots get no mercy
else
fall_chance = 55 //Simple mobs do.
climbing_delay_min = 2
//Catslugs are a snowflake case because of references.
if(istype(L, /mob/living/simple_mob/vore/alienanimals/catslug))
var/obj/O = L.get_active_hand()
if(istype(O, /obj/item/material/twohanded/spear))
var/choice = tgui_alert(L, "Use your spear to climb faster? This will drop and break it!", "Scug Tactics", list("Yes!", "No"))
if(choice == "Yes!")
drop_our_held = TRUE
climbing_delay_min = 0.75
//We proceed with the actual climbing!
// ################### CLIMB TIME BELOW: #############################
// Climb time is 3.75 for scugs with spears (spear is dropped)
// Climb time is 5 for Master climbers, Vassilians, Well-geared humans
// Climb time is 9 for Tajara and Professional Climbers
// Climb time is 17.5 Seconds for amateur climbers
// Climb time is 20 seconds for scugs without a spear
// Climb time is 30 for gearless untrained people
var/climb_time = (5 * climbing_delay_min) SECONDS
if(fall_chance)
to_chat(L, span_warning("You begin climbing over \The [src]. Getting a grip is exceedingly difficult..."))
climb_time += 20 SECONDS
else
to_chat(L, span_notice("You begin climbing above \The [src]! "))
if(climbing_delay_min > 1.25)
climb_time += 10 SECONDS
if(climbing_delay_min > 1.0)
climb_time += 2.5 SECONDS
if(L.nutrition >= 100 && L.nutrition <= 200)
to_chat(L, span_notice("Climbing while [L.isSynthetic() ? "low on power" : "hungry"] slows you down"))
climb_time += 1 SECONDS
else if(L.nutrition >= nutrition_cost && L.nutrition <= 100)
to_chat(L, span_danger("You [L.isSynthetic() ? "lack enough power" : "are too hungry"] to climb safely!"))
climb_time +=3 SECONDS
if(fall_chance < 30)
fall_chance = 30
L.visible_message(message = span_infoplain(span_bold("[L]") + " begins to climb up on " + span_bold("\The [src]")), self_message = span_infoplain("You begin to clumb up on " + span_bold("\The [src]")), \
blind_message = span_infoplain("You hear the sounds of climbing!"), runemessage = "Tap Tap")
var/oops_time = world.time
var/grace_time = 4 SECONDS
to_chat(L, span_warning("If you get interrupted after [(grace_time / (1 SECOND))] seconds of climbing, you will fall and hurt yourself, beware!"))
if(do_after(L, climb_time, target = src))
if(prob(fall_chance))
L.forceMove(above_mob)
L.visible_message(message = span_infoplain(span_bold("[L]") + " falls off " + span_bold("\The [src]")), self_message = span_danger("You slipped off " + span_bold("\The [src]")), \
blind_message = span_infoplain("you hear a loud thud!"), runemessage = "CRASH!")
else
if(drop_our_held)
L.drop_item(get_turf(L))
L.forceMove(above_wall)
L.visible_message(message = span_infoplain(span_bold("[L]") + " climbed up on " + span_bold("\The [src]")), \
self_message = span_notice("You successfully scaled " + span_bold("\The [src]")), \
blind_message = span_infoplain("The sounds of climbing cease."), runemessage = "Tap Tap")
L.adjust_nutrition(-nutrition_cost)
else if(world.time > (oops_time + grace_time))
L.forceMove(above_mob)
L.visible_message(message = span_infoplain(span_bold("[L]") + " falls off " + span_bold("\The [src]")), self_message = span_danger("You slipped off " + span_bold("\The [src]")), \
blind_message = span_infoplain("you hear a loud thud!"), runemessage = "CRASH!")
/mob/living/verb/climb_down()
set name = "Climb down wall"
set desc = "attempt to climb down the wall you are standing on, in direction you're looking"
set category = "IC.Game"
var/fall_chance = 0 //Increased if we can't actually climb
var/turf/our_turf = get_turf(src) //floor we're standing on
var/climbing_delay_min = src.climbing_delay //We take the lowest climbing delay between mob, species and gear.
var/nutrition_cost = 25 //Descending is easier!
//Check if we can even try to climb
if(nutrition <= nutrition_cost)
to_chat(src, span_warning("You [isSynthetic() ? "lack the energy" : "are too hungry"] for such strenous activities!"))
return
var/turf/below_wall = GetBelow(our_turf)
if(!below_wall) //No multiZ
to_chat(src, span_notice("There's nothing interesting below us!"))
return
if(!istype(below_wall,/turf/simulated)) //Our var is on simulated turfs, we must enforce this
to_chat(src, span_notice("There's nothing useful to grab onto!"))
return
var/turf/simulated/climbing_surface = below_wall
if(!climbing_surface.density) //passable turfs make no sense to climb
to_chat(src, span_notice("There's nothing climbable below us!"))
return
var/turf/front_of_us = get_step(src, dir) //We get the spot we are facing
if(!front_of_us.CanZPass(src, DOWN)) //Makes sure where we're climbing isnt blocked by a tile or there's a wall below it.
to_chat(src, span_notice("\The [front_of_us] blocks your way in this direction!"))
return
var/turf/destination = GetBelow(front_of_us)
if(isopenspace(destination)) //We don't allow descending more than 1 Z at a time
to_chat(src, span_notice("You're too high up to climb down from here! Find a more gentle descent!"))
return
//Determining whether we should be able to climb safely and how fast
if(ishuman(src))
var/permit_human = FALSE
var/mob/living/carbon/human/H = src
if(H.species.climbing_delay < H.climbing_delay)
climbing_delay_min = H.species.climbing_delay
var/list/gear = list(H.head, H.wear_mask, H.wear_suit, H.w_uniform,
H.gloves, H.shoes, H.belt, H.get_active_hand(), H.get_inactive_hand())
if(H.can_climb || H.species.can_climb)
permit_human = TRUE
for(var/obj/item/I in gear)
if(I.rock_climbing)
permit_human = TRUE
if(I.climbing_delay > climbing_delay_min)
climbing_delay_min = I.climbing_delay //We get the maximum possible speedup out of worn equipment
if(!permit_human)
var/sure = tgui_alert(H,"Are you sure you want to try without tools? It's VERY LIKELY \
you will fall and get hurt. More agile species might have better luck", "Second Thoughts", list("Bring it!", "Stay grounded"))
if(!sure || sure == "Stay grounded") return
fall_chance = clamp(100 - H.species.agility, 40, 90) //This should be 80 for most species. Traceur would reduce to 10%, so clamping higher
//If not a human mob, must be simple or silicon. They got a var stored on their mob we can check
else if(!src.can_climb)
var/sure = tgui_alert(src,"Are you sure you want to try without tools? It's VERY LIKELY \
you will fall and get hurt. More agile species might have better luck", "Second Thoughts", list("Bring it!", "Stay grounded"))
if(!sure || sure == "Stay grounded") return
if(isrobot(src))
fall_chance = 80 // Robots get no mercy
else
fall_chance = 55 //Simple mobs do.
climbing_delay_min = 2
//This time, scugs get no snowflake treatment. We're climbing DOWN, not up!
//We proceed with the actual climbing!
// ################### CLIMB TIME BELOW: #############################
// Climb time is 3.75 for scugs with spears (spear is dropped)
// Climb time is 5 for Master climbers, Vassilians, Well-geared humans
// Climb time is 9 for Tajara and Professional Climbers
// Climb time is 17.5 Seconds for amateur climbers
// Climb time is 20 seconds for scugs without a spear
// Climb time is 30 for gearless untrained people
var/climb_time = (5 * climbing_delay_min) SECONDS
if(fall_chance)
to_chat(src, span_warning("You begin climbing down along \The [below_wall]. Getting a grip is exceedingly difficult..."))
climb_time += 20 SECONDS
else
to_chat(src, span_notice("You begin climbing down \The [below_wall]! "))
if(climbing_delay_min > 1.25)
climb_time += 10 SECONDS
if(climbing_delay_min > 1.0)
climb_time += 2.5 SECONDS
if(nutrition >= 100 && nutrition <= 200) //Values are 50 lower than the warning icon appearing
to_chat(src, span_notice("Climbing while [isSynthetic() ? "low on power" : "hungry"] slows you down"))
climb_time += 1 SECONDS
else if(nutrition >= nutrition_cost && nutrition <= 100)
to_chat(src, span_danger("You [isSynthetic() ? "lack enough power" : "are too hungry"] to climb safely!"))
climb_time +=3 SECONDS
if(fall_chance < 30)
fall_chance = 30
if(!climbing_surface.climbable)
to_chat(src, span_danger("\The [climbing_surface] is not suitable for climbing! Even for a master climber, this is risky!"))
if(fall_chance < 75 )
fall_chance = 75
src.visible_message(message = span_infoplain(span_bold("[src]") + " climb down " + span_bold("\The [below_wall]")), \
self_message = span_infoplain("You begin to descend " + span_bold("\The [below_wall]")), \
blind_message = span_infoplain("You hear the sounds of climbing!"), runemessage = "Tap Tap")
below_wall.audible_message(message = span_infoplain("You hear something climbing up " + span_bold("\The [below_wall]")), runemessage= "Tap Tap")
var/oops_time = world.time
var/grace_time = 3 SECONDS
to_chat(src, span_warning("If you get interrupted after [(grace_time / (1 SECOND))] seconds of climbing, you will fall and hurt yourself, beware!"))
if(do_after(src, climb_time, target = src))
if(prob(fall_chance))
src.forceMove(front_of_us)
src.visible_message(message = span_infoplain(span_bold("[src]") + " falls off " + span_bold("\The [below_wall]")), \
self_message = span_danger("You slipped off " + span_bold("\The [below_wall]")), \
blind_message = span_infoplain("you hear a loud thud!"), runemessage = "CRASH!")
else
src.forceMove(destination)
src.visible_message(message = span_infoplain(span_bold("[src]") + " climbed down on " + span_bold("\The [below_wall]")), \
self_message = span_notice("You successfully descended " + span_bold("\The [below_wall]")), \
blind_message = span_infoplain("The sounds of climbing cease."), runemessage = "Tap Tap")
adjust_nutrition(-nutrition_cost)
else if(world.time > (oops_time + grace_time))
src.forceMove(front_of_us)
src.visible_message(message = span_infoplain(span_bold("[src]") + " falls off " + span_bold("\The [below_wall]")), \
self_message = span_danger("You slipped off " + span_bold("\The [below_wall]")), \
blind_message = span_infoplain("you hear a loud thud!"), runemessage = "CRASH!")