Cleans up /proc/find_safe_turf(), documenting and improving code (#93848)

## About The Pull Request

`/proc/find_safe_turf()` was cleaned up so that it did not have two
arguments that accomplished the same thing, removing opportunities for
user errors when calling the proc. Additionally, since I was here, I
decided to clean up some of the code and document it.

Some thresholds were changed in this PR (the max temperature threshold
was dropped from 360K to 340K), but I believe that it's better to keep
them consistent instead of using arbitrary values.

## Uncomfortably large gap

<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>

## Changelog

No user facing changes.

<!-- Both 🆑's are required for the changelog to work! You can put
your name to the right of the first 🆑 if you want to overwrite your
GitHub username as author ingame. -->
<!-- You can use multiple of the same prefix (they're only used for the
icon ingame) and delete the unneeded ones. Despite some of the tags,
changelogs should generally represent how a player might be affected by
the changes rather than a summary of the PR's contents. -->

---------

Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
This commit is contained in:
tonty
2025-11-09 18:21:57 -05:00
committed by GitHub
parent 18eec09669
commit aaead63f36
6 changed files with 75 additions and 43 deletions

View File

@@ -173,16 +173,20 @@ GLOBAL_LIST_EMPTY(gas_handbook)
return null
/**
* A simple helped proc that checks if the contents of a list of gases are within acceptable terms.
* A simple helper proc that checks if the contents of a list of gases are within acceptable terms.
*
* Arguments:
* * gases: The list of gases which contents are being checked
* * gases to check: An associated list of gas types and acceptable boundaries in moles. e.g. /datum/gas/oxygen = list(16, 30)
* * acceptable_gas_bounds: An associated list of gas types and acceptable boundaries in moles. e.g. /datum/gas/oxygen = list(16, 30)
* * * if the assoc list is null, then it'll be considered a safe gas and won't return FALSE.
* * extraneous_gas_limit: If a gas not in gases is found, this is the limit above which the proc will return FALSE.
*
* Returns TRUE if the list of gases is acceptable, FALSE otherwise.
*/
/proc/check_gases(list/gases, list/gases_to_check, extraneous_gas_limit = 0.1)
gases_to_check = gases_to_check.Copy()
/proc/check_gases(list/gases, list/acceptable_gas_bounds, extraneous_gas_limit = 0.1)
SHOULD_BE_PURE(TRUE)
var/list/gases_to_check = acceptable_gas_bounds.Copy() // thank you spaceman
for(var/id in gases)
var/gas_moles = gases[id][MOLES]
if(!(id in gases_to_check))

View File

@@ -125,26 +125,53 @@
effect.attach(location)
effect.start()
// Safe location finder
/proc/find_safe_turf(zlevel, list/zlevels, extended_safety_checks = FALSE, dense_atoms = FALSE)
if(!zlevels)
if (zlevel)
zlevels = list(zlevel)
else
zlevels = SSmapping.levels_by_trait(ZTRAIT_STATION)
var/cycles = 1000
for(var/cycle in 1 to cycles)
// DRUNK DIALLING WOOOOOOOOO
/**
* Attempts to find a "safe" floor turf within some given z-levels
* * zlevel_or_levels: The list of z-levels we are searching though. You can supply just a number and it will be turned into a list.
* * extended_safety_checks: Will do some additional checks to make sure the destination is safe, see [/proc/is_safe_turf].
* * dense_atoms: Will additionally check to see if the turf has any dense obstructions, like machines or structures.
*
* Returns a safe floor turf,
* **BUT** there is a chance of it being null if an extremely large portion of a z-level is unsafe or blocked.
*/
/proc/find_safe_turf(zlevel_or_levels, extended_safety_checks = FALSE, dense_atoms = FALSE) as /turf/open/floor
SHOULD_BE_PURE(TRUE)
RETURN_TYPE(/turf/open/floor)
var/list/zlevels
if(islist(zlevel_or_levels))
zlevels = zlevel_or_levels
else if(zlevel_or_levels)
zlevels = list(zlevel_or_levels)
else
zlevels = SSmapping.levels_by_trait(ZTRAIT_STATION)
for(var/cycle in 1 to 1000)
var/x = rand(1, world.maxx)
var/y = rand(1, world.maxy)
var/z = pick(zlevels)
var/random_location = locate(x,y,z)
if(is_safe_turf(random_location, extended_safety_checks, dense_atoms, cycle < 300))//if the area is mostly NOTELEPORT (centcom) we gotta give up on this fantasy at some point.
var/keep_trying_no_teleport = (cycle < 300) //if the area is mostly NOTELEPORT (centcom) we gotta give up on this fantasy at some point.
if(is_safe_turf(random_location, extended_safety_checks, dense_atoms, keep_trying_no_teleport))
return random_location
/// Checks if a given turf is a "safe" location
/**
* Checks to see if a given turf is a "safe" location. Being safe requires the following to be true:
* * Must be a [floor][/turf/open/floor]
* * Must have air, and that air must have [breathable bounds][/proc/check_gases] for humans
* * Must have goldilocks temperature
* * Must have safe pressure
*
* Optionally:
* * extended_safety_checks: Will make additional checks for turfs that technically pass all previous requirements but still may not be safe
* * dense_atoms: Must be unobstructed (no blocking objects such as machines, structures or mobs)
* * no_teleport: Must not have [NOTELEPORT][/area/var/area_flag]
*
* Returns TRUE if all conditions pass, FALSE otherwise.
*/
/proc/is_safe_turf(turf/random_location, extended_safety_checks = FALSE, dense_atoms = FALSE, no_teleport = FALSE)
SHOULD_BE_PURE(TRUE)
. = FALSE
if(!isfloorturf(random_location))
return
@@ -160,18 +187,18 @@
var/list/floor_gases = floor_gas_mixture.gases
var/static/list/gases_to_check = list(
/datum/gas/oxygen = list(16, 100),
/datum/gas/oxygen = list(/obj/item/organ/lungs::safe_oxygen_min, 100),
/datum/gas/nitrogen,
/datum/gas/carbon_dioxide = list(0, 10)
/datum/gas/carbon_dioxide = list(0, /obj/item/organ/lungs::safe_co2_max)
)
if(!check_gases(floor_gases, gases_to_check))
return FALSE
// Aim for goldilocks temperatures and pressure
if((floor_gas_mixture.temperature <= 270) || (floor_gas_mixture.temperature >= 360))
if((floor_gas_mixture.temperature <= BODYTEMP_COLD_DAMAGE_LIMIT) || (floor_gas_mixture.temperature >= BODYTEMP_HEAT_DAMAGE_LIMIT))
return
var/pressure = floor_gas_mixture.return_pressure()
if((pressure <= 20) || (pressure >= 550))
if((pressure <= HAZARD_LOW_PRESSURE) || (pressure >= HAZARD_HIGH_PRESSURE))
return
if(extended_safety_checks)

View File

@@ -135,11 +135,11 @@
var/effect_range = 5
/obj/effect/fun_balloon/scatter/effect()
for(var/mob/living/M in range(effect_range, get_turf(src)))
var/turf/T = find_safe_turf(zlevel = src.z)
new /obj/effect/temp_visual/gravpush(get_turf(M))
M.forceMove(T)
to_chat(M, span_notice("Pop!"), confidential = TRUE)
for(var/mob/living/dispersed_mob in range(effect_range, get_turf(src)))
var/turf/drop_off = find_safe_turf(z)
new /obj/effect/temp_visual/gravpush(get_turf(dispersed_mob))
dispersed_mob.forceMove(drop_off)
dispersed_mob.balloon_alert(dispersed_mob, "pop!")
// ----------- Station Crash
// Can't think of anywhere better to put it right now

View File

@@ -81,7 +81,7 @@
/// Attempts to teleport the passed mob to somewhere safe on the station, if they can use the blade.
/obj/item/melee/sickly_blade/proc/seek_safety(mob/user)
var/turf/safe_turf = find_safe_turf(zlevels = z, extended_safety_checks = TRUE)
var/turf/safe_turf = find_safe_turf(z, extended_safety_checks = TRUE)
if(check_usability(user))
if(do_teleport(user, safe_turf, channel = TELEPORT_CHANNEL_MAGIC))
to_chat(user, span_warning("As you shatter [src], you feel a gust of energy flow through your body. [after_use_message]"))

View File

@@ -16,19 +16,20 @@
. = ..()
if(.)
return
if(tgui_alert(usr,question,name,list("Yes","No")) == "Yes" && Adjacent(user))
var/turf/T = zlevels ? find_safe_turf(zlevels=zlevels) : get_safe_random_station_turf_equal_weight()
if(tgui_alert(usr,question,name,list("Yes","No")) != "Yes" && !Adjacent(user))
return
if(T)
var/atom/movable/AM = user.pulling
if(AM)
AM.forceMove(T)
user.forceMove(T)
if(AM)
user.start_pulling(AM)
to_chat(user, span_notice("You blink and find yourself in [get_area_name(T)]."))
else
to_chat(user, "Nothing happens. You feel that this is a bad sign.")
var/turf/safe_dropoff = zlevels ? find_safe_turf(zlevels) : get_safe_random_station_turf_equal_weight()
if(!safe_dropoff)
to_chat(user, "Nothing happens. You feel that this is a bad sign.")
return
var/atom/movable/pulled = user.pulling
user.forceMove(safe_dropoff)
if(pulled)
pulled.forceMove(safe_dropoff)
user.start_pulling(pulled)
to_chat(user, span_notice("You blink and find yourself in [get_area_name(safe_dropoff)]."))
/obj/structure/signpost/attackby(obj/item/W, mob/user, list/modifiers, list/attack_modifiers)
return interact(user)

View File

@@ -715,12 +715,12 @@
if(healthcheck && (healthcheck - owner.health) > 5)
owner.visible_message(span_warning("[linked_extract] notices the sudden change in [owner]'s physical health, and activates!"))
do_sparks(5,FALSE,owner)
var/F = find_safe_turf(zlevel = owner.z, extended_safety_checks = TRUE)
var/turf/emergency_turf = find_safe_turf(owner.z, extended_safety_checks = TRUE)
var/range = 0
if(!F)
F = get_turf(owner)
if(!emergency_turf)
emergency_turf = get_turf(owner)
range = 50
if(do_teleport(owner, F, range, channel = TELEPORT_CHANNEL_BLUESPACE))
if(do_teleport(owner, emergency_turf, range, channel = TELEPORT_CHANNEL_BLUESPACE))
to_chat(owner, span_notice("[linked_extract] will take some time to re-align you on the bluespace axis."))
do_sparks(5,FALSE,owner)
owner.apply_status_effect(/datum/status_effect/bluespacestabilization)