diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom.dm
index 02079493f1cbc..f41faf1ef0272 100644
--- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom.dm
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom.dm
@@ -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)
diff --git a/code/__DEFINES/movement.dm b/code/__DEFINES/movement.dm
index c34bcb82259a8..b1ba18d0fae79 100644
--- a/code/__DEFINES/movement.dm
+++ b/code/__DEFINES/movement.dm
@@ -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
diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm
index 2f88159ad3296..50f22401bf52a 100644
--- a/code/datums/helper_datums/teleport.dm
+++ b/code/datums/helper_datums/teleport.dm
@@ -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,
@@ -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, "You feel like you are being held in place.")
- //Anchored...
- return FALSE
-
// argument handling
// if the precision is not specified, default to 0, but apply BoH penalties
if (isnull(precision))
@@ -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))
@@ -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)]")
@@ -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)
diff --git a/code/game/area/areas/centcom.dm b/code/game/area/areas/centcom.dm
index 3f162914b61e5..fc94c7d60b48b 100644
--- a/code/game/area/areas/centcom.dm
+++ b/code/game/area/areas/centcom.dm
@@ -125,7 +125,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"
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index c8ae188439383..c34be0707b21d 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -1010,6 +1010,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.
*
diff --git a/code/game/objects/items/scrolls.dm b/code/game/objects/items/scrolls.dm
index 98a642cb88746..487a0aa3c815a 100644
--- a/code/game/objects/items/scrolls.dm
+++ b/code/game/objects/items/scrolls.dm
@@ -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
diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm
index 16cdba633ad81..852bc8c326261 100644
--- a/code/game/objects/items/teleportation.dm
+++ b/code/game/objects/items/teleportation.dm
@@ -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, "\The [src] is malfunctioning.")
- 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, "\The [src] is malfunctioning.")
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)
@@ -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
diff --git a/code/modules/antagonists/abductor/machinery/experiment.dm b/code/modules/antagonists/abductor/machinery/experiment.dm
index 403a1e55bce35..bef2992c94f57 100644
--- a/code/modules/antagonists/abductor/machinery/experiment.dm
+++ b/code/modules/antagonists/abductor/machinery/experiment.dm
@@ -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)
diff --git a/code/modules/antagonists/abductor/machinery/pad.dm b/code/modules/antagonists/abductor/machinery/pad.dm
index 9c08ed9c88828..b892b098630da 100644
--- a/code/modules/antagonists/abductor/machinery/pad.dm
+++ b/code/modules/antagonists/abductor/machinery/pad.dm
@@ -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, "The instability of the warp leaves you disoriented!")
target.SetSleeping(60)
@@ -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)
@@ -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)
diff --git a/code/modules/antagonists/clock_cult/helpers/servant_warp.dm b/code/modules/antagonists/clock_cult/helpers/servant_warp.dm
index ee6b570a1f24d..5dfdefee00976 100644
--- a/code/modules/antagonists/clock_cult/helpers/servant_warp.dm
+++ b/code/modules/antagonists/clock_cult/helpers/servant_warp.dm
@@ -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, "You warp to [get_area(target_location)].")
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, "You feel sick and confused...")
diff --git a/code/modules/antagonists/clock_cult/structure/dimensional_rift.dm b/code/modules/antagonists/clock_cult/structure/dimensional_rift.dm
index 5a904c68d3649..3bbe183833175 100644
--- a/code/modules/antagonists/clock_cult/structure/dimensional_rift.dm
+++ b/code/modules/antagonists/clock_cult/structure/dimensional_rift.dm
@@ -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)
@@ -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)
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 7b13e2af68e76..7bc21a124e288 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -466,7 +466,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/rune/teleport)
visible_message("There is a sharp crack of inrushing air, and everything above the rune disappears!", null, "You hear a sharp crack.")
to_chat(user, "You[moveuserlater ? "r vision blurs, and you suddenly appear somewhere else":" send everything above the rune away"].")
else
- to_chat(user, "You[moveuserlater ? "r vision blurs briefly, but nothing happens":" try send everything above the rune away, but the teleportation fails"].")
+ to_chat(user, "You[moveuserlater ? "r vision blurs briefly, but nothing happens":" try send everything above the rune away, but the teleportation fails"].")
if(is_mining_level(z) && !is_mining_level(target.z)) //No effect if you stay on lavaland
actual_selected_rune.handle_portal("lava")
else
diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm
index 45d07518cd1a8..5de108942ad72 100644
--- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm
+++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm
@@ -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
@@ -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.")
diff --git a/code/modules/antagonists/revenant/revenant_abilities.dm b/code/modules/antagonists/revenant/revenant_abilities.dm
index 85b96e894dc64..9208c198a8a33 100644
--- a/code/modules/antagonists/revenant/revenant_abilities.dm
+++ b/code/modules/antagonists/revenant/revenant_abilities.dm
@@ -187,7 +187,7 @@
if(QDELETED(src)) // it's bad when someone spams this...
return
var/turf/targetturf = get_random_station_turf()
- if(!do_teleport(user, targetturf, channel = TELEPORT_CHANNEL_CULT, forced=TRUE))
+ if(!do_teleport(user, targetturf, channel = TELEPORT_CHANNEL_CULT, bypass_area_restriction=TRUE))
to_chat(user, "You have failed to recall yourself to the station... You should try again.")
else
user.reveal(80)
diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm
index e78e9d1d2f941..710cdf672cd60 100644
--- a/code/modules/antagonists/wizard/equipment/artefact.dm
+++ b/code/modules/antagonists/wizard/equipment/artefact.dm
@@ -488,7 +488,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/rend)
while(breakout < 50)
var/turf/potential_T = find_safe_turf()
if(T.get_virtual_z_level() != potential_T.get_virtual_z_level() || abs(get_dist_euclidian(potential_T,T)) > 50 - breakout)
- do_teleport(user, potential_T, channel = TELEPORT_CHANNEL_MAGIC)
+ do_teleport(user, potential_T, channel = TELEPORT_CHANNEL_MAGIC, teleport_mode = TELEPORT_ALLOW_WIZARD)
T = potential_T
break
breakout += 1
diff --git a/code/modules/bluespace_anchor/bluespace_anchor.dm b/code/modules/bluespace_anchor/bluespace_anchor.dm
index 0ab3ceffc12bf..d4b29d75e75fb 100644
--- a/code/modules/bluespace_anchor/bluespace_anchor.dm
+++ b/code/modules/bluespace_anchor/bluespace_anchor.dm
@@ -66,6 +66,11 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/bluespace_anchor)
src.Beam(L, icon_state="lightning[rand(1,12)]", time=5, maxdistance = INFINITY)
var/shock_damage = min(round(power_usage_per_teleport/600), 90) + rand(-5, 5)
L.electrocute_act(shock_damage, src)
+ // Give feedback
+ do_sparks(5, FALSE, teleatom)
+ playsound(src, 'sound/magic/repulse.ogg', 80, TRUE)
+ if(ismob(teleatom))
+ to_chat(teleatom, "You feel like you are being held in place.")
return TRUE
/obj/machinery/bluespace_anchor/proc/set_cell(cell)
diff --git a/code/modules/mob/living/simple_animal/hostile/bread.dm b/code/modules/mob/living/simple_animal/hostile/bread.dm
index 4c8ddba930b5b..7e62adfd45951 100644
--- a/code/modules/mob/living/simple_animal/hostile/bread.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bread.dm
@@ -27,6 +27,8 @@
mobchatspan = "blob"
/mob/living/simple_animal/hostile/breadloaf/teleport_act()
+ . = ..()
+
if(mutations == 0)
mutationcap = rand(1,mutability)
if(prob(90))
diff --git a/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm b/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm
index 1252ca6c07f6e..e5261d797ff27 100644
--- a/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm
+++ b/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm
@@ -507,7 +507,7 @@ GLOBAL_VAR_INIT(floor_cluwnes, 0)
return
// Send 'em to the destination. If the teleport fails, do nothing.
- 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))
return
// If our target died during the (short) wait timer,
@@ -594,7 +594,7 @@ GLOBAL_VAR_INIT(floor_cluwnes, 0)
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.")
diff --git a/code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm b/code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm
index c42e7457ff4a0..01bacdffe2c2d 100644
--- a/code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm
+++ b/code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm
@@ -114,7 +114,7 @@ It is possible to destroy the net by the occupant or someone else.
// Teleport
var/turf/picked_station_level = get_random_station_turf() //Don't want to limit this specifically to z 2 in case we get multi-z in rotation
var/turf/safe_location = find_safe_turf(picked_station_level.z, extended_safety_checks = TRUE, dense_atoms = FALSE)
- do_teleport(target, safe_location, channel = TELEPORT_CHANNEL_FREE, forced = TRUE)
+ do_teleport(target, safe_location, channel = TELEPORT_CHANNEL_FREE, bypass_area_restriction = TRUE)
target.Unconscious(3 SECONDS)
/obj/structure/energy_net/attack_paw(mob/user)
diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm
index ce80f3c01e65d..730186f0f3488 100644
--- a/code/modules/projectiles/guns/magic/wand.dm
+++ b/code/modules/projectiles/guns/magic/wand.dm
@@ -142,7 +142,7 @@
no_den_usage = TRUE
/obj/item/gun/magic/wand/teleport/zap_self(mob/living/user)
- if(do_teleport(user, user, 10, channel = TELEPORT_CHANNEL_MAGIC))
+ if(do_teleport(user, user, 10, channel = TELEPORT_CHANNEL_MAGIC, teleport_mode = TELEPORT_ALLOW_WIZARD))
var/datum/effect_system/smoke_spread/smoke = new
smoke.set_up(3, user.loc)
smoke.start()
@@ -162,7 +162,7 @@
var/turf/origin = get_turf(user)
var/turf/destination = find_safe_turf()
- if(do_teleport(user, destination, channel=TELEPORT_CHANNEL_MAGIC))
+ if(do_teleport(user, destination, channel=TELEPORT_CHANNEL_MAGIC, teleport_mode = TELEPORT_ALLOW_WIZARD))
for(var/t in list(origin, destination))
var/datum/effect_system/smoke_spread/smoke = new
smoke.set_up(0, t)
diff --git a/code/modules/spells/spell_types/area_teleport.dm b/code/modules/spells/spell_types/area_teleport.dm
index 2980830bd87f1..66362c4f43cae 100644
--- a/code/modules/spells/spell_types/area_teleport.dm
+++ b/code/modules/spells/spell_types/area_teleport.dm
@@ -60,7 +60,7 @@
var/success = FALSE
while(tempL.len)
attempt = pick(tempL)
- do_teleport(target, attempt, channel = TELEPORT_CHANNEL_MAGIC)
+ do_teleport(target, attempt, channel = TELEPORT_CHANNEL_MAGIC, teleport_mode = TELEPORT_ALLOW_WIZARD)
if(get_turf(target) == attempt)
success = TRUE
break
@@ -68,7 +68,7 @@
tempL.Remove(attempt)
if(!success)
- do_teleport(target, L, channel = TELEPORT_CHANNEL_MAGIC)
+ do_teleport(target, L, channel = TELEPORT_CHANNEL_MAGIC, teleport_mode = TELEPORT_ALLOW_WIZARD)
playsound(get_turf(user), sound2, 50,1)
/obj/effect/proc_holder/spell/targeted/area_teleport/invocation(area/chosenarea = null,mob/living/user = usr)
diff --git a/code/modules/spells/spell_types/turf_teleport.dm b/code/modules/spells/spell_types/turf_teleport.dm
index 3dbe76e5cddc4..15efcc345c6b0 100644
--- a/code/modules/spells/spell_types/turf_teleport.dm
+++ b/code/modules/spells/spell_types/turf_teleport.dm
@@ -34,5 +34,5 @@
if(!picked || !isturf(picked))
return
- if(do_teleport(user, picked, channel = TELEPORT_CHANNEL_MAGIC))
+ if(do_teleport(user, picked, channel = TELEPORT_CHANNEL_MAGIC, teleport_mode = TELEPORT_ALLOW_WIZARD))
playsound(get_turf(user), sound1, 50,1)