diff --git a/code/__HELPERS/atmospherics.dm b/code/__HELPERS/atmospherics.dm index 9ebafd5fbb5..6264823b7f2 100644 --- a/code/__HELPERS/atmospherics.dm +++ b/code/__HELPERS/atmospherics.dm @@ -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)) diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index 8dcaa2ecfaf..d8fdb8f846b 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -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) diff --git a/code/modules/admin/fun_balloon.dm b/code/modules/admin/fun_balloon.dm index 3e8d212d071..fdde0aa1cb2 100644 --- a/code/modules/admin/fun_balloon.dm +++ b/code/modules/admin/fun_balloon.dm @@ -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 diff --git a/code/modules/antagonists/heretic/items/heretic_blades.dm b/code/modules/antagonists/heretic/items/heretic_blades.dm index ae66020dd02..fe3eefc5eb3 100644 --- a/code/modules/antagonists/heretic/items/heretic_blades.dm +++ b/code/modules/antagonists/heretic/items/heretic_blades.dm @@ -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]")) diff --git a/code/modules/awaymissions/signpost.dm b/code/modules/awaymissions/signpost.dm index 94c71287eef..4a2f63b8cfb 100644 --- a/code/modules/awaymissions/signpost.dm +++ b/code/modules/awaymissions/signpost.dm @@ -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) diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm index f3b4801f54b..8ed179a3207 100644 --- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm +++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm @@ -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)