Files
CHOMPStation2/code/modules/multiz/movement_vr.dm
CHOMPStation2StaffMirrorBot c963d7d54b [MIRROR] The Bigger They Are, The Harder They Fall (#11856)
Co-authored-by: SatinIsle <98125273+SatinIsle@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 02:01:38 -04:00

320 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)
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!")