Skip to content

Commit

Permalink
Teleportation Cleanup & Cult Teleports Respecting Anti-Magic (#11466)
Browse files Browse the repository at this point in the history
* done testing I think

* spelling mistake

* Added overrides for bible and nullrod so they don't inheritly block teleports

* If we're looping through all the items anyways, we might as well use the built-in type filter.

* maybe we should call parent

* fixes a hand-tele oopsie

* Wizard can teleport with full hardsuit.

* Not needed anymore
  • Loading branch information
mystery3525 authored Sep 28, 2024
1 parent b161b73 commit bdb1698
Show file tree
Hide file tree
Showing 22 changed files with 158 additions and 92 deletions.
2 changes: 1 addition & 1 deletion code/__DEFINES/dcs/signals/signals_atom/signals_atom.dm
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@
#define COMSIG_ATOM_CREATEDBY_PROCESSING "atom_createdby_processing"
///when an atom is processed (mob/living/user, obj/item/I, list/atom/results)
#define COMSIG_ATOM_PROCESSED "atom_processed"
///! called when teleporting into a protected turf: (channel, turf/origin)
///! from the base of atom/intercept_teleport: (channel, turf/origin, turf/destination)
#define COMSIG_ATOM_INTERCEPT_TELEPORT "intercept_teleport"
#define COMPONENT_BLOCK_TELEPORT 1
///called when an atom starts orbiting another atom: (atom)
Expand Down
10 changes: 2 additions & 8 deletions code/__DEFINES/movement.dm
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,8 @@
#define TELEPORT_ALLOW_CLOCKWORK 2
/// Everyone but abductors is restricted
#define TELEPORT_ALLOW_ABDUCTORS 3

//Teleport modes
/// Default teleport mode
#define TELEPORT_MODE_DEFAULT 0
/// A clockwork teleport
#define TELEPORT_MODE_CLOCKWORK 2
/// An abductor teleport
#define TELEPORT_MODE_ABDUCTORS 3
/// Everyone but wizards is restricted
#define TELEPORT_ALLOW_WIZARD 4

// Jetpack Thrust
/// Thrust needed with gravity
Expand Down
153 changes: 100 additions & 53 deletions code/datums/helper_datums/teleport.dm
Original file line number Diff line number Diff line change
@@ -1,13 +1,85 @@
// teleatom: atom to teleport
// destination: destination to teleport to
// precision: teleport precision (0 is most precise, the default)
// effectin: effect to show right before teleportation
// effectout: effect to show right after teleportation
// asoundin: soundfile to play before teleportation
// asoundout: soundfile to play after teleportation
// no_effects: disable the default effectin/effectout of sparks
// forced: whether or not to ignore no_teleport
/proc/do_teleport(atom/movable/teleatom, atom/destination, precision=null, datum/effect_system/effectin=null, datum/effect_system/effectout=null, asoundin=null, asoundout=null, no_effects=FALSE, channel=TELEPORT_CHANNEL_BLUESPACE, forced = FALSE, teleport_mode = TELEPORT_MODE_DEFAULT, commit = TRUE, no_wake = FALSE)
/**
* Returns FALSE if we SHOULDN'T do_teleport() with the given arguments
*
* Arguments:
* * teleatom: The atom to teleport
* * dest_turf: The destination turf for the atom to go
* * channel: Which teleport channel/type should we try to use (for blocking checks), defaults to TELEPORT_CHANNEL_BLUESPACE
* * bypass_area_restriction: Should we ignore SOFT atom and area TRAIT_NO_TELEPORT restriction and other area-related restrictions? Defaults to FALSE
* * teleport_mode: Teleport mode for religion/faction checks
*/
/proc/check_teleport(atom/movable/teleatom, turf/dest_turf, channel = TELEPORT_CHANNEL_BLUESPACE, bypass_area_restriction = FALSE, teleport_mode = TELEPORT_ALLOW_ALL)
var/turf/cur_turf = get_turf(teleatom)

if(!istype(dest_turf))
stack_trace("Destination [dest_turf] is not a turf.")
return FALSE
if(!istype(cur_turf) || dest_turf.is_transition_turf())
return FALSE

// Checks bluespace anchors
if(channel != TELEPORT_CHANNEL_WORMHOLE && channel != TELEPORT_CHANNEL_FREE)
var/cur_zlevel = cur_turf.get_virtual_z_level()
var/dest_zlevel = dest_turf.get_virtual_z_level()
for (var/obj/machinery/bluespace_anchor/anchor as() in GLOB.active_bluespace_anchors)
var/anchor_zlevel = anchor.get_virtual_z_level()
// Not in range of our current turf or destination turf
if((cur_zlevel != anchor_zlevel && get_dist(cur_turf, anchor) > anchor.range) && (dest_zlevel != anchor_zlevel && get_dist(dest_turf, anchor) > anchor.range))
continue

// Try to activate the anchor, this also does the effect
if(!anchor.try_activate())
continue

// We're anchored, return false
return FALSE

// Checks antimagic
if(ismob(teleatom))
var/mob/tele_mob = teleatom
if(channel == TELEPORT_CHANNEL_CULT && tele_mob.anti_magic_check(magic = FALSE, holy = TRUE, self = TRUE))
return FALSE
if(channel == TELEPORT_CHANNEL_MAGIC && tele_mob.anti_magic_check(magic = TRUE, holy = FALSE, self = TRUE))
return FALSE

// Check for NO_TELEPORT restrictions
if(!bypass_area_restriction)
var/area/cur_area = cur_turf.loc
var/area/dest_area = dest_turf.loc
if(HAS_TRAIT(teleatom, TRAIT_NO_TELEPORT))
return FALSE
if(cur_area.teleport_restriction && cur_area.teleport_restriction != teleport_mode)
return FALSE
if(dest_area.teleport_restriction && dest_area.teleport_restriction != teleport_mode)
return FALSE

// Check for intercepting the teleport
if(cur_turf.intercept_teleport(channel, cur_turf, dest_turf) == COMPONENT_BLOCK_TELEPORT)
return FALSE
if(dest_turf.intercept_teleport(channel, cur_turf, dest_turf) == COMPONENT_BLOCK_TELEPORT)
return FALSE
if(teleatom.intercept_teleport(channel, cur_turf, dest_turf) == COMPONENT_BLOCK_TELEPORT)
return FALSE

return TRUE

/**
* Returns TRUE if the teleport has been successful
*
* Arguments:
* * teleatom: atom to teleport
* * destination: destination to teleport to
* * precision: teleport precision (0 is most precise, the default)
* * effectin: effect to show right before teleportation
* * asoundin: soundfile to play before teleportation
* * asoundout: soundfile to play after teleportation
* * no_effects: disable the default effectin/effectout of sparks
* * channel: Which teleport channel/type should we try to use (for blocking checks)
* * ignore_check_teleport: Set this to true ONLY if you have already run check_teleport
* * bypass_area_restriction: Should we ignore SOFT atom and area TRAIT_NO_TELEPORT restriction and other area-related restrictions? Defaults to FALSE
* * no_wake: Whether or not we want a teleport wake to be created
*/
/proc/do_teleport(atom/movable/teleatom, atom/destination, precision=null, datum/effect_system/effectin=null, datum/effect_system/effectout=null, asoundin=null, asoundout=null, no_effects=FALSE, channel=TELEPORT_CHANNEL_BLUESPACE, bypass_area_restriction = FALSE, teleport_mode = TELEPORT_ALLOW_ALL, ignore_check_teleport = FALSE, no_wake = FALSE)
// teleporting most effects just deletes them
var/static/list/delete_atoms = typecacheof(list(
/obj/effect,
Expand All @@ -23,22 +95,6 @@
qdel(teleatom)
return FALSE

//Check bluespace anchors
if(channel != TELEPORT_CHANNEL_WORMHOLE && channel != TELEPORT_CHANNEL_FREE)
for (var/obj/machinery/bluespace_anchor/anchor as() in GLOB.active_bluespace_anchors)
//Not nearby
if (anchor.get_virtual_z_level() != teleatom.get_virtual_z_level() || (get_dist(teleatom, anchor) > anchor.range && get_dist(destination, anchor) > anchor.range))
continue
//Check it
if(!anchor.try_activate())
continue
do_sparks(5, FALSE, teleatom)
playsound(anchor, 'sound/magic/repulse.ogg', 80, TRUE)
if(ismob(teleatom))
to_chat(teleatom, "<span class='warning'>You feel like you are being held in place.</span>")
//Anchored...
return FALSE

// argument handling
// if the precision is not specified, default to 0, but apply BoH penalties
if (isnull(precision))
Expand All @@ -48,8 +104,7 @@
if(istype(teleatom, /obj/item/storage/backpack/holding))
precision = rand(1,100)

var/static/list/bag_cache = typecacheof(/obj/item/storage/backpack/holding)
var/list/bagholding = typecache_filter_list(teleatom.GetAllContents(), bag_cache)
var/list/bagholding = teleatom.GetAllContents(/obj/item/storage/backpack/holding)
if(bagholding.len)
precision = max(rand(1,100)*bagholding.len,100)
if(isliving(teleatom))
Expand All @@ -69,34 +124,25 @@
var/turf/curturf = get_turf(teleatom)
var/turf/destturf = get_teleport_turf(get_turf(destination), precision)

if(!destturf || !curturf || destturf.is_transition_turf())
return FALSE

var/area/A = get_area(curturf)
var/area/B = get_area(destturf)
if(!forced && (HAS_TRAIT(teleatom, TRAIT_NO_TELEPORT)))
return FALSE

//Either area has teleport restriction and teleport mode isn't allowed in that area
if(!forced && ((A.teleport_restriction && A.teleport_restriction != teleport_mode) || (B.teleport_restriction && B.teleport_restriction != teleport_mode)))
return FALSE

if(SEND_SIGNAL(destturf, COMSIG_ATOM_INTERCEPT_TELEPORT, channel, curturf, destturf))
return FALSE

if(isobserver(teleatom))
teleatom.abstract_move(destturf)
return TRUE

if (!commit)
return TRUE
if(!ignore_check_teleport) // If we've already done it let's not check again
if(!check_teleport(teleatom, destturf, channel, bypass_area_restriction, teleport_mode))
return FALSE

// If we leave behind a wake, then create that here.
// Only leave a wake if we are going to a location that we can actually teleport to.
if (!no_wake && (channel == TELEPORT_CHANNEL_BLUESPACE || channel == TELEPORT_CHANNEL_CULT || channel == TELEPORT_CHANNEL_MAGIC) && A.teleport_restriction == TELEPORT_MODE_DEFAULT && B.teleport_restriction == TELEPORT_MODE_DEFAULT && teleport_mode == TELEPORT_MODE_DEFAULT)
new /obj/effect/temp_visual/teleportation_wake(get_turf(teleatom), destturf)
if (!no_wake && (channel == TELEPORT_CHANNEL_BLUESPACE || channel == TELEPORT_CHANNEL_CULT || channel == TELEPORT_CHANNEL_MAGIC))
var/area/cur_area = curturf.loc
var/area/dest_area = destturf.loc
if(cur_area.teleport_restriction == TELEPORT_ALLOW_ALL && dest_area.teleport_restriction == TELEPORT_ALLOW_ALL && teleport_mode == TELEPORT_ALLOW_ALL)
new /obj/effect/temp_visual/teleportation_wake(get_turf(teleatom), destturf)

tele_play_specials(teleatom, curturf, effectin, asoundin)

// Actually teleport them
var/success = teleatom.forceMove(destturf)
if (success)
log_game("[key_name(teleatom)] has teleported from [loc_name(curturf)] to [loc_name(destturf)]")
Expand All @@ -113,12 +159,13 @@
return TRUE

/proc/tele_play_specials(atom/movable/teleatom, atom/location, datum/effect_system/effect, sound)
if (location && !isobserver(teleatom))
if (sound)
playsound(location, sound, 60, 1)
if (effect)
effect.attach(location)
effect.start()
if (!istype(location) || isobserver(teleatom))
return
if (sound)
playsound(location, sound, 60, 1)
if (effect)
effect.attach(location)
effect.start()

// Safe location finder
/proc/find_safe_turf(zlevel, list/zlevels, extended_safety_checks = FALSE, dense_atoms = TRUE)
Expand Down
2 changes: 1 addition & 1 deletion code/game/area/areas/centcom.dm
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
dynamic_lighting = DYNAMIC_LIGHTING_ENABLED
requires_power = FALSE
has_gravity = STANDARD_GRAVITY
teleport_restriction = TELEPORT_ALLOW_NONE
teleport_restriction = TELEPORT_ALLOW_WIZARD
area_flags = VALID_TERRITORY | UNIQUE_AREA
flags_1 = NONE
network_root_id = "MAGIC_NET"
Expand Down
21 changes: 21 additions & 0 deletions code/game/atoms.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,27 @@ CREATION_TEST_IGNORE_SUBTYPES(/atom)
/atom/proc/teleport_act()
SEND_SIGNAL(src,COMSIG_ATOM_TELEPORT_ACT)

/**
* Intercept our atom being teleported if we need to
*
* return COMPONENT_BLOCK_TELEPORT to explicity block teleportation
*/
/atom/proc/intercept_teleport(channel, turf/origin, turf/destination)
. = SEND_SIGNAL(src, COMSIG_ATOM_INTERCEPT_TELEPORT, channel, origin, destination)

if(. == COMPONENT_BLOCK_TELEPORT)
return

// Recursively check contents by default. This can be overriden if we want different behavior.
for(var/atom/thing in contents)
// For the purposes of intercepting teleports, mobs on the turf don't count.
// We're already doing logic for intercepting teleports on the teleatom-level
if(isturf(src) && ismob(thing))
continue
var/result = thing.intercept_teleport(channel, origin, destination)
if(result == COMPONENT_BLOCK_TELEPORT)
return result

/**
* Respond to our atom being checked by a virus extrapolator.
*
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/items/scrolls.dm
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
to_chat(user, "The spell matrix was unable to locate a suitable teleport destination for an unknown reason. Sorry.")
return

if(do_teleport(user, pick(L), channel = TELEPORT_CHANNEL_MAGIC, forced = TRUE))
if(do_teleport(user, pick(L), channel = TELEPORT_CHANNEL_MAGIC, bypass_area_restriction = TRUE))
smoke.start()
uses--
else
Expand Down
9 changes: 3 additions & 6 deletions code/game/objects/items/teleportation.dm
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,10 @@
qdel(target_effect)
qdel(source_effect)
return
var/area/A = get_area(teleport_target)
if(A.teleport_restriction)
to_chat(user, "<span class='notice'>\The [src] is malfunctioning.</span>")
return
current_location = get_turf(user) //Recheck.
current_area = current_location.loc
if(!current_location || current_area.teleport_restriction || is_away_level(current_location.z) || is_centcom_level(current_location.z) || !isturf(user.loc))//If turf was not found or they're on z level 2 or >7 which does not currently exist. or if user is not located on a turf
var/turf/dest_turf = get_teleport_turf(get_turf(teleport_target))
if(isnull(current_area) || !check_teleport(user, dest_turf, channel = TELEPORT_CHANNEL_BLUESPACE) || is_away_level(current_location.z) || is_centcom_level(current_location.z))//If turf was not found or they're on z level 2 or >7 which does not currently exist. or if user is not located on a turf
to_chat(user, "<span class='notice'>\The [src] is malfunctioning.</span>")
return
var/list/obj/effect/portal/created = create_portal_pair(current_location, get_teleport_turf(get_turf(teleport_target)), src, 300, 1, null, atmos_link_override)
Expand Down Expand Up @@ -359,7 +356,7 @@

// Check if we can move here
current_area = current_location.loc
if(!do_teleport(C, current_location, no_effects = TRUE, channel = TELEPORT_CHANNEL_BLINK, commit = FALSE))//If turf was not found or they're on z level 2 or >7 which does not currently exist. or if user is not located on a turf
if(!check_teleport(C, current_location, channel = TELEPORT_CHANNEL_BLINK))//If turf was not found or they're on z level 2 or >7 which does not currently exist. or if user is not located on a turf
current_location = previous
break
// If it contains objects, try to break it
Expand Down
2 changes: 1 addition & 1 deletion code/modules/antagonists/abductor/machinery/experiment.dm
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@
H.uncuff()
H.cauterise_wounds()
if(console && console.pad && console.pad.teleport_target)
do_teleport(H, console.pad.teleport_target, channel = TELEPORT_CHANNEL_BLINK, no_effects = TRUE, teleport_mode = TELEPORT_MODE_ABDUCTORS)
do_teleport(H, console.pad.teleport_target, channel = TELEPORT_CHANNEL_BLINK, no_effects = TRUE, teleport_mode = TELEPORT_ALLOW_ABDUCTORS)
return
//Area not chosen / It's not safe area - teleport to arrivals
SSjob.SendToLateJoin(H, FALSE)
Expand Down
8 changes: 4 additions & 4 deletions code/modules/antagonists/abductor/machinery/pad.dm
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@

/obj/machinery/abductor/pad/proc/Warp(mob/living/target)
if(!target.buckled)
do_teleport(target, get_turf(src), no_effects = TRUE, channel = TELEPORT_CHANNEL_BLINK, teleport_mode = TELEPORT_MODE_ABDUCTORS)
do_teleport(target, get_turf(src), no_effects = TRUE, channel = TELEPORT_CHANNEL_BLINK, teleport_mode = TELEPORT_ALLOW_ABDUCTORS)

/obj/machinery/abductor/pad/proc/Send()
if(teleport_target == null)
teleport_target = GLOB.teleportlocs[pick(GLOB.teleportlocs)]
flick("alien-pad", src)
for(var/mob/living/target in loc)
do_teleport(target, teleport_target, no_effects = TRUE, channel = TELEPORT_CHANNEL_BLINK, teleport_mode = TELEPORT_MODE_ABDUCTORS)
do_teleport(target, teleport_target, no_effects = TRUE, channel = TELEPORT_CHANNEL_BLINK, teleport_mode = TELEPORT_ALLOW_ABDUCTORS)
new /obj/effect/temp_visual/dir_setting/ninja(get_turf(target), target.dir)
to_chat(target, "<span class='warning'>The instability of the warp leaves you disoriented!</span>")
target.SetSleeping(60)
Expand All @@ -33,7 +33,7 @@

/obj/machinery/abductor/pad/proc/doMobToLoc(place, atom/movable/target)
flick("alien-pad", src)
do_teleport(target, place, no_effects = TRUE, channel = TELEPORT_CHANNEL_BLINK, teleport_mode = TELEPORT_MODE_ABDUCTORS)
do_teleport(target, place, no_effects = TRUE, channel = TELEPORT_CHANNEL_BLINK, teleport_mode = TELEPORT_ALLOW_ABDUCTORS)
new /obj/effect/temp_visual/dir_setting/ninja(get_turf(target), target.dir)

/obj/machinery/abductor/pad/proc/MobToLoc(place,mob/living/target)
Expand All @@ -43,7 +43,7 @@
/obj/machinery/abductor/pad/proc/doPadToLoc(place)
flick("alien-pad", src)
for(var/mob/living/target in get_turf(src))
do_teleport(target, place, no_effects = TRUE, channel = TELEPORT_CHANNEL_BLINK, teleport_mode = TELEPORT_MODE_ABDUCTORS)
do_teleport(target, place, no_effects = TRUE, channel = TELEPORT_CHANNEL_BLINK, teleport_mode = TELEPORT_ALLOW_ABDUCTORS)
new /obj/effect/temp_visual/dir_setting/ninja(get_turf(target), target.dir)

/obj/machinery/abductor/pad/proc/PadToLoc(place)
Expand Down
4 changes: 2 additions & 2 deletions code/modules/antagonists/clock_cult/helpers/servant_warp.dm
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
playsound(target_location, 'sound/magic/magic_missile.ogg', 50, TRUE)
do_sparks(5, TRUE, servant)
do_sparks(5, TRUE, target_location)
do_teleport(M, target_location, channel = TELEPORT_CHANNEL_BLINK, no_effects = TRUE, teleport_mode = TELEPORT_MODE_CLOCKWORK)
do_teleport(M, target_location, channel = TELEPORT_CHANNEL_CULT, no_effects = TRUE, teleport_mode = TELEPORT_ALLOW_CLOCKWORK)
new /obj/effect/temp_visual/ratvar/warp(target_location)
to_chat(servant, "<span class='inathneq'>You warp to [get_area(target_location)].</span>")
if(istype(P) && bring_dragging)
do_teleport(P, target_location, channel = TELEPORT_CHANNEL_BLINK, no_effects = TRUE, teleport_mode = TELEPORT_MODE_CLOCKWORK)
do_teleport(P, target_location, channel = TELEPORT_CHANNEL_CULT, no_effects = TRUE, teleport_mode = TELEPORT_ALLOW_CLOCKWORK)
P.Paralyze(30)
to_chat(P, "<span class='warning'>You feel sick and confused...</span>")
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
if(do_after(M, 50, target=src))
var/obj/effect/landmark/city_of_cogs/target_spawn = pick(GLOB.city_of_cogs_spawns)
var/turf/T = get_turf(target_spawn)
do_teleport(M, T, no_effects = TRUE, channel = TELEPORT_CHANNEL_FREE, forced = TRUE)
do_teleport(M, T, no_effects = TRUE, channel = TELEPORT_CHANNEL_FREE, bypass_area_restriction = TRUE)
var/mob/living/M_mob = M
if(istype(M_mob))
if(M_mob.client)
Expand All @@ -43,4 +43,4 @@
//So we can push crates in too
var/obj/effect/landmark/city_of_cogs/target_spawn = pick(GLOB.city_of_cogs_spawns)
var/turf/T = get_turf(target_spawn)
do_teleport(M, T, no_effects = TRUE, channel = TELEPORT_CHANNEL_FREE, forced = TRUE)
do_teleport(M, T, no_effects = TRUE, channel = TELEPORT_CHANNEL_FREE, bypass_area_restriction = TRUE)
2 changes: 1 addition & 1 deletion code/modules/antagonists/cult/runes.dm
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/rune/teleport)
visible_message("<span class='warning'>There is a sharp crack of inrushing air, and everything above the rune disappears!</span>", null, "<i>You hear a sharp crack.</i>")
to_chat(user, "<span class='cult'>You[moveuserlater ? "r vision blurs, and you suddenly appear somewhere else":" send everything above the rune away"].</span>")
else
to_chat(user, "<span class='cult'>You[moveuserlater ? "r vision blurs briefly, but nothing happens":" try send everything above the rune away, but the teleportation fails"].</span>")
to_chat(user, "<span class='cult'>You[moveuserlater ? "r vision blurs briefly, but nothing happens":" try send everything above the rune away, but the teleportation fails"].</span>")
if(is_mining_level(z) && !is_mining_level(target.z)) //No effect if you stay on lavaland
actual_selected_rune.handle_portal("lava")
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@
return

// Send 'em to the destination. If the teleport fails, just disembowel them and stop the chain
if(!destination || !do_teleport(sac_target, destination, asoundin = 'sound/magic/repulse.ogg', asoundout = 'sound/magic/blind.ogg', no_effects = TRUE, channel = TELEPORT_CHANNEL_MAGIC, forced = TRUE, no_wake = TRUE))
if(!destination || !do_teleport(sac_target, destination, asoundin = 'sound/magic/repulse.ogg', asoundout = 'sound/magic/blind.ogg', no_effects = TRUE, channel = TELEPORT_CHANNEL_MAGIC, bypass_area_restriction = TRUE, no_wake = TRUE))
disembowel_target(sac_target)
return

Expand Down Expand Up @@ -374,7 +374,7 @@
safe_turf = get_turf(backup_loc)
stack_trace("[type] - return_target was unable to find a safe turf for [sac_target] to return to. Defaulting to observer start turf.")

if(!do_teleport(sac_target, safe_turf, asoundout = 'sound/magic/blind.ogg', no_effects = TRUE, channel = TELEPORT_CHANNEL_FREE, forced = TRUE, no_wake = TRUE))
if(!do_teleport(sac_target, safe_turf, asoundout = 'sound/magic/blind.ogg', no_effects = TRUE, channel = TELEPORT_CHANNEL_FREE, bypass_area_restriction = TRUE, no_wake = TRUE))
safe_turf = get_turf(backup_loc)
sac_target.forceMove(safe_turf)
stack_trace("[type] - return_target was unable to teleport [sac_target] to the observer start turf. Forcemoving.")
Expand Down
Loading

0 comments on commit bdb1698

Please sign in to comment.