diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index 8d86826ac2..e01bf5669b 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -73,6 +73,8 @@
#define COMSIG_ATOM_CANREACH "atom_can_reach" //from internal loop in atom/movable/proc/CanReach(): (list/next)
#define COMPONENT_BLOCK_REACH 1
#define COMSIG_ATOM_SCREWDRIVER_ACT "atom_screwdriver_act" //from base of atom/screwdriver_act(): (mob/living/user, obj/item/I)
+#define COMSIG_ATOM_INTERCEPT_TELEPORT "intercept_teleport" //called when teleporting into a protected turf: (channel, turf/origin)
+ #define COMPONENT_BLOCK_TELEPORT 1
/////////////////
#define COMSIG_ATOM_ATTACK_GHOST "atom_attack_ghost" //from base of atom/attack_ghost(): (mob/dead/observer/ghost)
#define COMSIG_ATOM_ATTACK_HAND "atom_attack_hand" //from base of atom/attack_hand(): (mob/user)
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 73711fe02d..2ba1563001 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -455,6 +455,13 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define SUMMON_GUNS "guns"
#define SUMMON_MAGIC "magic"
+#define TELEPORT_CHANNEL_BLUESPACE "bluespace" //Classic bluespace teleportation, requires a sender but no receiver
+#define TELEPORT_CHANNEL_QUANTUM "quantum" //Quantum-based teleportation, requires both sender and receiver, but is free from normal disruption
+#define TELEPORT_CHANNEL_WORMHOLE "wormhole" //Wormhole teleportation, is not disrupted by bluespace fluctuations but tends to be very random or unsafe
+#define TELEPORT_CHANNEL_MAGIC "magic" //Magic teleportation, does whatever it wants (unless there's antimagic)
+#define TELEPORT_CHANNEL_CULT "cult" //Cult teleportation, does whatever it wants (unless there's holiness)
+#define TELEPORT_CHANNEL_FREE "free" //Anything else
+
//Run the world with this parameter to enable a single run though of the game setup and tear down process with unit tests in between
#define TEST_RUN_PARAMETER "test-run"
//Force the log directory to be something specific in the data/logs folder
diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm
index 0623e2f5f9..6462a1998a 100644
--- a/code/datums/helper_datums/teleport.dm
+++ b/code/datums/helper_datums/teleport.dm
@@ -5,11 +5,19 @@
// effectout: effect to show right after teleportation
// asoundin: soundfile to play before teleportation
// asoundout: soundfile to play after teleportation
-// force_teleport: if false, teleport will use Move() proc (dense objects will prevent teleportation)
// no_effects: disable the default effectin/effectout of sparks
-/proc/do_teleport(atom/movable/teleatom, atom/destination, precision=null, force_teleport=TRUE, datum/effect_system/effectin=null, datum/effect_system/effectout=null, asoundin=null, asoundout=null, no_effects=FALSE)
+// forceMove: if false, teleport will use Move() proc (dense objects will prevent teleportation)
+// forced: whether or not to ignore no_teleport
+/proc/do_teleport(atom/movable/teleatom, atom/destination, precision=null, forceMove = FALSE, datum/effect_system/effectin=null, datum/effect_system/effectout=null, asoundin=null, asoundout=null, no_effects=FALSE, channel=TELEPORT_CHANNEL_BLUESPACE, forced = FALSE)
// teleporting most effects just deletes them
- if(iseffect(teleatom) && !istype(teleatom, /obj/effect/dummy/chameleon))
+ var/static/list/delete_atoms = typecacheof(list(
+ /obj/effect,
+ )) - typecacheof(list(
+ /obj/effect/dummy/chameleon,
+ /obj/effect/wisp,
+ /obj/effect/mob_spawn
+ ))
+ if(delete_atoms[teleatom.type])
qdel(teleatom)
return FALSE
@@ -17,25 +25,37 @@
// if the precision is not specified, default to 0, but apply BoH penalties
if (isnull(precision))
precision = 0
- 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)
- if(bagholding.len)
- precision = max(rand(1,100)*bagholding.len,100)
- if(isliving(teleatom))
- var/mob/living/MM = teleatom
- to_chat(MM, "The bluespace interface on your bag of holding interferes with the teleport!")
+ switch(channel)
+ if(TELEPORT_CHANNEL_BLUESPACE)
+ if(istype(teleatom, /obj/item/storage/backpack/holding))
+ precision = rand(1,100)
- // if effects are not specified and not explicitly disabled, sparks
- if ((!effectin || !effectout) && !no_effects)
- var/datum/effect_system/spark_spread/sparks = new
- sparks.set_up(5, 1, teleatom)
- if (!effectin)
- effectin = sparks
- if (!effectout)
- effectout = sparks
+ var/static/list/bag_cache = typecacheof(/obj/item/storage/backpack/holding)
+ var/list/bagholding = typecache_filter_list(teleatom.GetAllContents(), bag_cache)
+ if(bagholding.len)
+ precision = max(rand(1,100)*bagholding.len,100)
+ if(isliving(teleatom))
+ var/mob/living/MM = teleatom
+ to_chat(MM, "The bluespace interface on your bag of holding interferes with the teleport!")
+
+ // if effects are not specified and not explicitly disabled, sparks
+ if ((!effectin || !effectout) && !no_effects)
+ var/datum/effect_system/spark_spread/sparks = new
+ sparks.set_up(5, 1, teleatom)
+ if (!effectin)
+ effectin = sparks
+ if (!effectout)
+ effectout = sparks
+ if(TELEPORT_CHANNEL_QUANTUM)
+ // if effects are not specified and not explicitly disabled, rainbow sparks
+ if ((!effectin || !effectout) && !no_effects)
+ var/datum/effect_system/spark_spread/quantum/sparks = new
+ sparks.set_up(5, 1, teleatom)
+ if (!effectin)
+ effectin = sparks
+ if (!effectout)
+ effectout = sparks
// perform the teleport
var/turf/curturf = get_turf(teleatom)
@@ -45,11 +65,15 @@
return FALSE
var/area/A = get_area(curturf)
- if(A.noteleport)
+ var/area/B = get_area(destturf)
+ if(!forced && (A.noteleport || B.noteleport))
+ return FALSE
+
+ if(SEND_SIGNAL(destturf, COMSIG_ATOM_INTERCEPT_TELEPORT, channel, curturf, destturf))
return FALSE
tele_play_specials(teleatom, curturf, effectin, asoundin)
- var/success = force_teleport ? teleatom.forceMove(destturf) : teleatom.Move(destturf)
+ var/success = forceMove ? teleatom.forceMove(destturf) : teleatom.Move(destturf)
if (success)
log_game("[key_name(teleatom)] has teleported from [loc_name(curturf)] to [loc_name(destturf)]")
tele_play_specials(teleatom, destturf, effectout, asoundout)
diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm
index 86fcefb340..43582e39bf 100644
--- a/code/game/machinery/computer/camera_advanced.dm
+++ b/code/game/machinery/computer/camera_advanced.dm
@@ -361,14 +361,16 @@
return
button_icon_state = "warp_down"
owner.update_action_buttons()
+ QDEL_NULL(warping)
+ if(!do_teleport(user, T, channel = TELEPORT_CHANNEL_CULT, forced = TRUE))
+ to_chat(user, "Warp Failed. Something deflected our attempt to warp to [AR].")
+ return
T.visible_message("[user] warps in!")
playsound(user, 'sound/magic/magic_missile.ogg', 50, TRUE)
playsound(T, 'sound/magic/magic_missile.ogg', 50, TRUE)
- user.forceMove(get_turf(T))
user.setDir(SOUTH)
flash_color(user, flash_color = "#AF0AAF", flash_time = 5)
R.remove_eye_control(user)
- QDEL_NULL(warping)
/datum/action/innate/servant_warp/proc/is_canceled()
return !cancel
diff --git a/code/game/machinery/launch_pad.dm b/code/game/machinery/launch_pad.dm
index 4016c32162..db59f3f413 100644
--- a/code/game/machinery/launch_pad.dm
+++ b/code/game/machinery/launch_pad.dm
@@ -127,7 +127,7 @@
if(first_inner)
log_msg += "empty"
log_msg += ")"
- do_teleport(ROI, dest, no_effects = !first)
+ do_teleport(ROI, dest, no_effects = !first, channel = TELEPORT_CHANNEL_BLUESPACE)
first = FALSE
if (first)
@@ -206,7 +206,7 @@
/obj/item/storage/briefcase/launchpad/PopulateContents()
new /obj/item/pen(src)
- new /obj/item/launchpad_remote(src, pad)
+ new /obj/item/launchpad_remote(src, pad)
/obj/item/storage/briefcase/launchpad/attack_self(mob/user)
if(!isturf(user.loc)) //no setting up in a locker
@@ -227,7 +227,7 @@
L.pad = src.pad
to_chat(user, "You link [pad] to [L].")
else
- return ..()
+ return ..()
/obj/item/launchpad_remote
name = "folder"
diff --git a/code/game/machinery/quantum_pad.dm b/code/game/machinery/quantum_pad.dm
index 7a8552607b..b5ef38b42c 100644
--- a/code/game/machinery/quantum_pad.dm
+++ b/code/game/machinery/quantum_pad.dm
@@ -36,7 +36,7 @@
to_chat(user, "The panel is screwed in, obstructing the linking device.")
else
to_chat(user, "The linking device is now able to be scanned with a multitool.")
-
+
/obj/machinery/quantumpad/RefreshParts()
var/E = 0
for(var/obj/item/stock_parts/capacitor/C in component_parts)
@@ -74,15 +74,26 @@
to_chat(user, "There is no quantum pad data saved in [I]'s buffer!")
return TRUE
+ else if(istype(I, /obj/item/quantum_keycard))
+ var/obj/item/quantum_keycard/K = I
+ if(K.qpad)
+ to_chat(user, "You insert [K] into [src]'s card slot, activating it.")
+ interact(user, K.qpad)
+ else
+ to_chat(user, "You insert [K] into [src]'s card slot, initiating the link procedure.")
+ if(do_after(user, 40, target = src))
+ to_chat(user, "You complete the link between [K] and [src].")
+ K.qpad = src
+
if(default_deconstruction_crowbar(I))
return
return ..()
-/obj/machinery/quantumpad/interact(mob/user)
- if(!linked_pad || QDELETED(linked_pad))
+/obj/machinery/quantumpad/interact(mob/user, obj/machinery/quantumpad/target_pad = linked_pad)
+ if(!target_pad || QDELETED(target_pad))
if(!map_pad_link_id || !initMappedLink())
- to_chat(user, "There is no linked pad!")
+ to_chat(user, "Target pad not found!")
return
if(world.time < last_teleport + teleport_cooldown)
@@ -93,18 +104,18 @@
to_chat(user, "[src] is charging up. Please wait.")
return
- if(linked_pad.teleporting)
- to_chat(user, "Linked pad is busy. Please wait.")
+ if(target_pad.teleporting)
+ to_chat(user, "Target pad is busy. Please wait.")
return
- if(linked_pad.stat & NOPOWER)
- to_chat(user, "Linked pad is not responding to ping.")
+ if(target_pad.stat & NOPOWER)
+ to_chat(user, "Target pad is not responding to ping.")
return
add_fingerprint(user)
- doteleport(user)
+ doteleport(user, target_pad)
/obj/machinery/quantumpad/proc/sparks()
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
+ var/datum/effect_system/spark_spread/quantum/s = new
s.set_up(5, 1, get_turf(src))
s.start()
@@ -117,8 +128,8 @@
if(linked_pad)
ghost.forceMove(get_turf(linked_pad))
-/obj/machinery/quantumpad/proc/doteleport(mob/user)
- if(linked_pad)
+/obj/machinery/quantumpad/proc/doteleport(mob/user, obj/machinery/quantumpad/target_pad = linked_pad)
+ if(target_pad)
playsound(get_turf(src), 'sound/weapons/flash.ogg', 25, 1)
teleporting = TRUE
@@ -130,7 +141,7 @@
to_chat(user, "[src] is unpowered!")
teleporting = FALSE
return
- if(!linked_pad || QDELETED(linked_pad) || linked_pad.stat & NOPOWER)
+ if(!target_pad || QDELETED(target_pad) || target_pad.stat & NOPOWER)
to_chat(user, "Linked pad is not responding to ping. Teleport aborted.")
teleporting = FALSE
return
@@ -141,26 +152,30 @@
// use a lot of power
use_power(10000 / power_efficiency)
sparks()
- linked_pad.sparks()
+ target_pad.sparks()
flick("qpad-beam", src)
playsound(get_turf(src), 'sound/weapons/emitter2.ogg', 25, 1, extrarange = 3, falloff = 5)
- flick("qpad-beam", linked_pad)
- playsound(get_turf(linked_pad), 'sound/weapons/emitter2.ogg', 25, 1, extrarange = 3, falloff = 5)
+ flick("qpad-beam", target_pad)
+ playsound(get_turf(target_pad), 'sound/weapons/emitter2.ogg', 25, 1, extrarange = 3, falloff = 5)
for(var/atom/movable/ROI in get_turf(src))
+ if(QDELETED(ROI))
+ continue //sleeps in CHECK_TICK
+
// if is anchored, don't let through
if(ROI.anchored)
if(isliving(ROI))
var/mob/living/L = ROI
- if(L.buckled)
- // TP people on office chairs
- if(L.buckled.anchored)
- continue
+ //only TP living mobs buckled to non anchored items
+ if(!L.buckled || L.buckled.anchored)
+ continue
else
continue
+ //Don't TP camera mobs
else if(!isobserver(ROI))
continue
- do_teleport(ROI, get_turf(linked_pad))
+ do_teleport(ROI, get_turf(target_pad),null,TRUE,null,null,null,null,TRUE, channel = TELEPORT_CHANNEL_QUANTUM)
+ CHECK_TICK
/obj/machinery/quantumpad/proc/initMappedLink()
. = FALSE
diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm
index cc83e6502a..64081a77e4 100644
--- a/code/game/machinery/teleporter.dm
+++ b/code/game/machinery/teleporter.dm
@@ -66,7 +66,7 @@
visible_message("Cannot authenticate locked on coordinates. Please reinstate coordinate matrix.")
return
if (ismovableatom(M))
- if(do_teleport(M, com.target))
+ if(do_teleport(M, com.target, channel = TELEPORT_CHANNEL_BLUESPACE))
use_power(5000)
if(!calibrated && prob(30 - ((accurate) * 10))) //oh dear a problem
log_game("[M] ([key_name(M)]) was turned into a fly person")
diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm
index 80c92c7922..a8ba9850ff 100644
--- a/code/game/mecha/equipment/tools/other_tools.dm
+++ b/code/game/mecha/equipment/tools/other_tools.dm
@@ -17,7 +17,7 @@
return
var/turf/T = get_turf(target)
if(T)
- do_teleport(chassis, T, 4)
+ do_teleport(chassis, T, 4, channel = TELEPORT_CHANNEL_BLUESPACE)
return 1
diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm
index 91df57052e..fbe25c5d1b 100644
--- a/code/game/objects/effects/anomalies.dm
+++ b/code/game/objects/effects/anomalies.dm
@@ -190,11 +190,11 @@
/obj/effect/anomaly/bluespace/anomalyEffect()
..()
for(var/mob/living/M in range(1,src))
- do_teleport(M, locate(M.x, M.y, M.z), 4)
+ do_teleport(M, locate(M.x, M.y, M.z), 4, channel = TELEPORT_CHANNEL_BLUESPACE)
/obj/effect/anomaly/bluespace/Bumped(atom/movable/AM)
if(isliving(AM))
- do_teleport(AM, locate(AM.x, AM.y, AM.z), 8)
+ do_teleport(AM, locate(AM.x, AM.y, AM.z), 8, channel = TELEPORT_CHANNEL_BLUESPACE)
/obj/effect/anomaly/bluespace/detonate()
var/turf/T = safepick(get_area_turfs(impact_area))
diff --git a/code/game/objects/effects/blessing.dm b/code/game/objects/effects/blessing.dm
index 06ba2bb47c..5df90d65c7 100644
--- a/code/game/objects/effects/blessing.dm
+++ b/code/game/objects/effects/blessing.dm
@@ -16,3 +16,12 @@
I.alpha = 64
I.appearance_flags = RESET_ALPHA
add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/blessedAware, "blessing", I)
+ RegisterSignal(loc, COMSIG_ATOM_INTERCEPT_TELEPORT, .proc/block_cult_teleport)
+
+/obj/effect/blessing/Destroy()
+ UnregisterSignal(loc, COMSIG_ATOM_INTERCEPT_TELEPORT)
+ return ..()
+
+/obj/effect/blessing/proc/block_cult_teleport(datum/source, channel, turf/origin, turf/destination)
+ if(channel == TELEPORT_CHANNEL_CULT)
+ return COMPONENT_BLOCK_TELEPORT
\ No newline at end of file
diff --git a/code/game/objects/effects/effect_system/effects_sparks.dm b/code/game/objects/effects/effect_system/effects_sparks.dm
index 0656d9b3ca..19b0dc76dd 100644
--- a/code/game/objects/effects/effect_system/effects_sparks.dm
+++ b/code/game/objects/effects/effect_system/effects_sparks.dm
@@ -26,7 +26,7 @@
/obj/effect/particle_effect/sparks/Initialize()
. = ..()
- flick("sparks", src) // replay the animation
+ flick(icon_state, src) // replay the animation
playsound(src, "sparks", 100, TRUE)
var/turf/T = loc
if(isturf(T))
@@ -48,6 +48,8 @@
/datum/effect_system/spark_spread
effect_type = /obj/effect/particle_effect/sparks
+/datum/effect_system/spark_spread/quantum
+ effect_type = /obj/effect/particle_effect/sparks/quantum
//electricity
@@ -55,5 +57,9 @@
name = "lightning"
icon_state = "electricity"
+/obj/effect/particle_effect/sparks/quantum
+ name = "quantum sparks"
+ icon_state = "quantum_sparks"
+
/datum/effect_system/lightning_spread
effect_type = /obj/effect/particle_effect/sparks/electricity
diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm
index d69cfd38ef..631b87cada 100644
--- a/code/game/objects/effects/portals.dm
+++ b/code/game/objects/effects/portals.dm
@@ -20,6 +20,7 @@
var/mech_sized = FALSE
var/obj/effect/portal/linked
var/hardlinked = TRUE //Requires a linked portal at all times. Destroy if there's no linked portal, if there is destroy it when this one is deleted.
+ var/teleport_channel = TELEPORT_CHANNEL_BLUESPACE
var/creator
var/turf/hard_target //For when a portal needs a hard target and isn't to be linked.
var/atmos_link = FALSE //Link source/destination atmos.
@@ -34,6 +35,7 @@
icon = 'icons/obj/objects.dmi'
icon_state = "anom"
mech_sized = TRUE
+ teleport_channel = TELEPORT_CHANNEL_WORMHOLE
/obj/effect/portal/Move(newloc)
for(var/T in newloc)
@@ -160,7 +162,7 @@
no_effect = TRUE
else
last_effect = world.time
- if(do_teleport(M, real_target, innate_accuracy_penalty, no_effects = no_effect))
+ if(do_teleport(M, real_target, innate_accuracy_penalty, no_effects = no_effect, channel = teleport_channel))
if(istype(M, /obj/item/projectile))
var/obj/item/projectile/P = M
P.ignore_source_check = TRUE
diff --git a/code/game/objects/items/devices/quantum_keycard.dm b/code/game/objects/items/devices/quantum_keycard.dm
new file mode 100644
index 0000000000..37079722c0
--- /dev/null
+++ b/code/game/objects/items/devices/quantum_keycard.dm
@@ -0,0 +1,32 @@
+/obj/item/quantum_keycard
+ name = "quantum keycard"
+ desc = "A keycard able to link to a quantum pad's particle signature, allowing other quantum pads to travel there instead of their linked pad."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "quantum_keycard"
+ item_state = "card-id"
+ lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
+ w_class = WEIGHT_CLASS_TINY
+ var/obj/machinery/quantumpad/qpad
+
+/obj/item/quantum_keycard/examine(mob/user)
+ ..()
+ if(qpad)
+ to_chat(user, "It's currently linked to a quantum pad.")
+ to_chat(user, "Alt-click to unlink the keycard.")
+ else
+ to_chat(user, "Insert [src] into an active quantum pad to link it.")
+
+/obj/item/quantum_keycard/AltClick(mob/living/user)
+ if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ return
+ to_chat(user, "You start pressing [src]'s unlink button...")
+ if(do_after(user, 40, target = src))
+ to_chat(user, "The keycard beeps twice and disconnects the quantum link.")
+ qpad = null
+
+/obj/item/quantum_keycard/update_icon()
+ if(qpad)
+ icon_state = "quantum_keycard_on"
+ else
+ icon_state = initial(icon_state)
diff --git a/code/game/objects/items/scrolls.dm b/code/game/objects/items/scrolls.dm
index 07f6edb828..28a4664a24 100644
--- a/code/game/objects/items/scrolls.dm
+++ b/code/game/objects/items/scrolls.dm
@@ -66,7 +66,8 @@
to_chat(user, "The spell matrix was unable to locate a suitable teleport destination for an unknown reason. Sorry.")
return
- user.forceMove(pick(L))
-
- smoke.start()
- uses--
+ if(do_teleport(user, pick(L), forceMove = TRUE, channel = TELEPORT_CHANNEL_MAGIC, forced = TRUE))
+ smoke.start()
+ uses--
+ else
+ to_chat(user, "The spell matrix was disrupted by something near the destination.")
diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm
index 522e1a1153..49a735af9c 100644
--- a/code/game/objects/items/stacks/bscrystal.dm
+++ b/code/game/objects/items/stacks/bscrystal.dm
@@ -33,7 +33,7 @@
use(1)
/obj/item/stack/ore/bluespace_crystal/proc/blink_mob(mob/living/L)
- do_teleport(L, get_turf(L), blink_range, asoundin = 'sound/effects/phasein.ogg')
+ do_teleport(L, get_turf(L), blink_range, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
/obj/item/stack/ore/bluespace_crystal/throw_impact(atom/hit_atom)
if(!..()) // not caught in mid-air
diff --git a/code/game/objects/items/teleprod.dm b/code/game/objects/items/teleprod.dm
index 341c85fa1c..40392c19c3 100644
--- a/code/game/objects/items/teleprod.dm
+++ b/code/game/objects/items/teleprod.dm
@@ -10,7 +10,7 @@
. = ..()
if(!. || !istype(M) || M.anchored)
return
- do_teleport(M, get_turf(M), 15)
+ do_teleport(M, get_turf(M), 15, channel = TELEPORT_CHANNEL_BLUESPACE)
/obj/item/melee/baton/cattleprod/teleprod/clowning_around(mob/living/user)
user.visible_message("[user] accidentally hits [user.p_them()]self with [src]!", \
@@ -18,7 +18,7 @@
SEND_SIGNAL(user, COMSIG_LIVING_MINOR_SHOCK)
user.Knockdown(stunforce*3)
playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
- if(do_teleport(user, get_turf(user), 50))
+ if(do_teleport(user, get_turf(user), 50, channel = TELEPORT_CHANNEL_BLUESPACE))
deductcharge(hitcost)
else
deductcharge(hitcost * 0.25)
diff --git a/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm b/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm
index ea2ec4d6ef..5cf7ab7923 100644
--- a/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm
+++ b/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm
@@ -133,6 +133,9 @@
return FALSE
if(!uses)
return FALSE
+ if(!do_teleport(A, get_turf(linked_gateway), channel = TELEPORT_CHANNEL_CULT, forced = TRUE))
+ visible_message("[A] bounces off [src]!")
+ return FALSE
if(isliving(A))
var/mob/living/user = A
to_chat(user, "You pass through [src] and appear elsewhere!")
@@ -141,7 +144,6 @@
playsound(linked_gateway, 'sound/effects/empulse.ogg', 50, 1)
transform = matrix() * 1.5
linked_gateway.transform = matrix() * 1.5
- A.forceMove(get_turf(linked_gateway))
if(!no_cost)
uses = max(0, uses - 1)
linked_gateway.uses = max(0, linked_gateway.uses - 1)
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
index 552a747651..510c279f3c 100644
--- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
@@ -27,7 +27,7 @@
to_chat(invoker, "Stargazers can't be built off-station.")
return
return ..()
-
+
//Integration Cog: Creates an integration cog that can be inserted into APCs to passively siphon power.
/datum/clockwork_scripture/create_object/integration_cog
@@ -224,12 +224,14 @@
. = ..()
/datum/clockwork_scripture/abscond/scripture_effects()
- var/take_pulling = invoker.pulling && isliving(invoker.pulling) && get_clockwork_power(ABSCOND_ABDUCTION_COST)
+ var/mob/living/pulled_mob = invoker.pulling && isliving(invoker.pulling) && get_clockwork_power(ABSCOND_ABDUCTION_COST)
var/turf/T
if(GLOB.ark_of_the_clockwork_justiciar)
T = get_step(GLOB.ark_of_the_clockwork_justiciar, SOUTH)
else
T = get_turf(pick(GLOB.servant_spawns))
+ if(!do_teleport(invoker, T, channel = TELEPORT_CHANNEL_CULT, forced = TRUE))
+ return
invoker.visible_message("[invoker] flickers and phases out of existence!", \
"You feel a dizzying sense of vertigo as you're yanked back to Reebe!")
T.visible_message("[invoker] flickers and phases into existence!")
@@ -237,10 +239,9 @@
playsound(T, 'sound/magic/magic_missile.ogg', 50, TRUE)
do_sparks(5, TRUE, invoker)
do_sparks(5, TRUE, T)
- if(take_pulling)
+ if(pulled_mob && do_teleport(pulled_mob, T, channel = TELEPORT_CHANNEL_CULT, forced = TRUE))
adjust_clockwork_power(-special_power_cost)
- invoker.pulling.forceMove(T)
- invoker.forceMove(T)
+ invoker.start_pulling(pulled_mob) //forcemove resets pulls, so we need to re-pull
if(invoker.client)
animate(invoker.client, color = client_color, time = 25)
diff --git a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm
index 2b1d9d5f02..4cf7c1ba60 100644
--- a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm
+++ b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm
@@ -131,10 +131,10 @@
if(!M || !M.current)
continue
if(isliving(M.current) && M.current.stat != DEAD)
+ var/turf/t_turf
if(isAI(M.current))
- M.current.forceMove(get_step(get_step(src, NORTH),NORTH)) // AI too fat, must make sure it always ends up a 2 tiles north instead of on the ark.
- else
- M.current.forceMove(get_turf(src))
+ t_turf = isAI(M.current) ? get_step(get_step(src, NORTH),NORTH) : get_turf(src) // AI too fat, must make sure it always ends up a 2 tiles north instead of on the ark.
+ do_teleport(M, t_turf, channel = TELEPORT_CHANNEL_CULT, forced = TRUE)
M.current.overlay_fullscreen("flash", /obj/screen/fullscreen/flash)
M.current.clear_fullscreen("flash", 5)
playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 50, FALSE)
diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm
index a5fd516a42..f58ffc56d2 100644
--- a/code/modules/antagonists/cult/blood_magic.dm
+++ b/code/modules/antagonists/cult/blood_magic.dm
@@ -490,11 +490,12 @@
to_chat(user, "The target rune is blocked. Attempting to teleport to it would be massively unwise.")
return
uses--
- user.visible_message("Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!", \
- "You speak the words of the talisman and find yourself somewhere else!", "You hear a sharp crack.")
+ var/turf/origin = get_turf(user)
var/mob/living/L = target
- L.forceMove(dest)
- dest.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.")
+ if(do_teleport(L, dest, channel = TELEPORT_CHANNEL_CULT))
+ origin.visible_message("Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!", \
+ "You speak the words of the talisman and find yourself somewhere else!", "You hear a sharp crack.")
+ dest.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.")
..()
//Shackles
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index 9a17c3270b..dc2c29eb6d 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -568,7 +568,7 @@
var/mob/living/carbon/C = user
if(C.pulling)
var/atom/movable/pulled = C.pulling
- pulled.forceMove(T)
+ do_teleport(pulled, T, channel = TELEPORT_CHANNEL_CULT)
. = pulled
/obj/item/cult_shift/attack_self(mob/user)
@@ -593,13 +593,12 @@
new /obj/effect/temp_visual/dir_setting/cult/phase/out(mobloc, C.dir)
var/atom/movable/pulled = handle_teleport_grab(destination, C)
- C.forceMove(destination)
- if(pulled)
- C.start_pulling(pulled) //forcemove resets pulls, so we need to re-pull
-
- new /obj/effect/temp_visual/dir_setting/cult/phase(destination, C.dir)
- playsound(destination, 'sound/effects/phasein.ogg', 25, 1)
- playsound(destination, "sparks", 50, 1)
+ if(do_teleport(C, destination, channel = TELEPORT_CHANNEL_CULT))
+ if(pulled)
+ C.start_pulling(pulled) //forcemove resets pulls, so we need to re-pull
+ new /obj/effect/temp_visual/dir_setting/cult/phase(destination, C.dir)
+ playsound(destination, 'sound/effects/phasein.ogg', 25, 1)
+ playsound(destination, "sparks", 50, 1)
else
to_chat(C, "The veil cannot be torn here!")
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index be8d3b2e0a..bbab86729b 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -422,6 +422,7 @@ structure_check() searches for nearby cultist structures required for the invoca
return
var/movedsomething = FALSE
var/moveuserlater = FALSE
+ var/movesuccess = FALSE
for(var/atom/movable/A in T)
if(ishuman(A))
new /obj/effect/temp_visual/dir_setting/cult/phase/out(T, A.dir)
@@ -432,20 +433,26 @@ structure_check() searches for nearby cultist structures required for the invoca
continue
if(!A.anchored)
movedsomething = TRUE
- A.forceMove(target)
+ if(do_teleport(A, T, forceMove = TRUE, channel = TELEPORT_CHANNEL_CULT))
+ movesuccess = TRUE
if(movedsomething)
..()
- 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"].")
if(moveuserlater)
- user.forceMove(target)
+ if(do_teleport(user, T, channel = TELEPORT_CHANNEL_CULT))
+ movesuccess = TRUE
+ if(movesuccess)
+ 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"].")
if(is_mining_level(z) && !is_mining_level(target.z)) //No effect if you stay on lavaland
actual_selected_rune.handle_portal("lava")
else
var/area/A = get_area(T)
if(A.map_name == "Space")
actual_selected_rune.handle_portal("space", T)
- target.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.")
+ if(movesuccess)
+ target.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.")
else
fail_invoke()
diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm
index 9fb2c3e2b7..87cee7586d 100644
--- a/code/modules/antagonists/swarmer/swarmer.dm
+++ b/code/modules/antagonists/swarmer/swarmer.dm
@@ -488,7 +488,7 @@
S.set_up(4,0,get_turf(target))
S.start()
playsound(src,'sound/effects/sparks4.ogg',50,1)
- do_teleport(target, F, 0)
+ do_teleport(target, F, 0, channel = TELEPORT_CHANNEL_BLUESPACE)
/mob/living/simple_animal/hostile/swarmer/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = FALSE, tesla_shock = FALSE, illusion = FALSE, stun = TRUE)
if(!tesla_shock)
diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm
index 86493f6322..08e00ea0f4 100644
--- a/code/modules/antagonists/wizard/equipment/artefact.dm
+++ b/code/modules/antagonists/wizard/equipment/artefact.dm
@@ -408,7 +408,7 @@
break
var/turf/potential_T = find_safe_turf()
if(T.z != potential_T.z || abs(get_dist_euclidian(potential_T,T)) > 50 - breakout)
- user.forceMove(potential_T)
+ do_teleport(user, potential_T, channel = TELEPORT_CHANNEL_MAGIC)
user.canmove = 0
T = potential_T
break
diff --git a/code/modules/events/wizard/shuffle.dm b/code/modules/events/wizard/shuffle.dm
index ec253f13c3..7e37429223 100644
--- a/code/modules/events/wizard/shuffle.dm
+++ b/code/modules/events/wizard/shuffle.dm
@@ -27,7 +27,7 @@
for(var/mob/living/carbon/human/H in mobs)
if(!moblocs)
break //locs aren't always unique, so this may come into play
- do_teleport(H, moblocs[moblocs.len])
+ do_teleport(H, moblocs[moblocs.len], channel = TELEPORT_CHANNEL_MAGIC)
moblocs.len -= 1
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
diff --git a/code/modules/events/wormholes.dm b/code/modules/events/wormholes.dm
index 412e54878a..bb601b7c82 100644
--- a/code/modules/events/wormholes.dm
+++ b/code/modules/events/wormholes.dm
@@ -63,4 +63,4 @@
hard_target = P.loc
if(!hard_target)
return
- do_teleport(M, hard_target, 1, 1, 0, 0) ///You will appear adjacent to the beacon
+ do_teleport(M, hard_target, 1, 1, 0, 0, channel = TELEPORT_CHANNEL_WORMHOLE) ///You will appear adjacent to the beacon
diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm
index 17462c0626..db529e8ffb 100644
--- a/code/modules/hydroponics/plant_genes.dm
+++ b/code/modules/hydroponics/plant_genes.dm
@@ -290,15 +290,15 @@
var/teleport_radius = max(round(G.seed.potency / 10), 1)
var/turf/T = get_turf(target)
new /obj/effect/decal/cleanable/molten_object(T) //Leave a pile of goo behind for dramatic effect...
- do_teleport(target, T, teleport_radius)
+ do_teleport(target, T, teleport_radius, channel = TELEPORT_CHANNEL_BLUESPACE)
/datum/plant_gene/trait/teleport/on_slip(obj/item/reagent_containers/food/snacks/grown/G, mob/living/carbon/C)
var/teleport_radius = max(round(G.seed.potency / 10), 1)
var/turf/T = get_turf(C)
to_chat(C, "You slip through spacetime!")
- do_teleport(C, T, teleport_radius)
+ do_teleport(C, T, teleport_radius, channel = TELEPORT_CHANNEL_BLUESPACE)
if(prob(50))
- do_teleport(G, T, teleport_radius)
+ do_teleport(G, T, teleport_radius, channel = TELEPORT_CHANNEL_BLUESPACE)
else
new /obj/effect/decal/cleanable/molten_object(T) //Leave a pile of goo behind for dramatic effect...
qdel(G)
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 2c663b4094..88dd59749c 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -420,7 +420,7 @@
H.visible_message("[H] teleports!", "You destabilize and teleport!")
new /obj/effect/particle_effect/sparks(get_turf(H))
playsound(get_turf(H), "sparks", 50, 1)
- do_teleport(H, get_turf(H), 6, asoundin = 'sound/weapons/emitter2.ogg')
+ do_teleport(H, get_turf(H), 6, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
last_teleport = world.time
/datum/species/golem/bluespace/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
@@ -486,7 +486,7 @@
spark_system.set_up(10, 0, src)
spark_system.attach(H)
spark_system.start()
- do_teleport(H, get_turf(H), 12, asoundin = 'sound/weapons/emitter2.ogg')
+ do_teleport(H, get_turf(H), 12, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
last_teleport = world.time
UpdateButtonIcon() //action icon looks unavailable
sleep(cooldown + 5)
diff --git a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
index 8fb1de18df..ff2f453207 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
@@ -22,7 +22,7 @@
var/mob/living/M = target
if(!M.anchored && M != summoner && !hasmatchingsummoner(M))
new /obj/effect/temp_visual/guardian/phase/out(get_turf(M))
- do_teleport(M, M, 10)
+ do_teleport(M, M, 10, channel = TELEPORT_CHANNEL_BLUESPACE)
for(var/mob/living/L in range(1, M))
if(hasmatchingsummoner(L)) //if the summoner matches don't hurt them
continue
diff --git a/code/modules/mob/living/simple_animal/guardian/types/support.dm b/code/modules/mob/living/simple_animal/guardian/types/support.dm
index 8ef70e439f..794683e69f 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/support.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/support.dm
@@ -142,5 +142,5 @@
L.flash_act()
A.visible_message("[A] disappears in a flash of light!", \
"Your vision is obscured by a flash of light!")
- do_teleport(A, beacon, 0)
+ do_teleport(A, beacon, 0, channel = TELEPORT_CHANNEL_BLUESPACE)
new /obj/effect/temp_visual/guardian/phase(get_turf(A))
diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm
index e3724fdf31..42033d8c88 100644
--- a/code/modules/projectiles/guns/magic/wand.dm
+++ b/code/modules/projectiles/guns/magic/wand.dm
@@ -131,7 +131,7 @@
no_den_usage = 1
/obj/item/gun/magic/wand/teleport/zap_self(mob/living/user)
- if(do_teleport(user, user, 10))
+ if(do_teleport(user, user, 10, channel = TELEPORT_CHANNEL_MAGIC))
var/datum/effect_system/smoke_spread/smoke = new
smoke.set_up(3, user.loc)
smoke.start()
diff --git a/code/modules/projectiles/projectile/energy/net_snare.dm b/code/modules/projectiles/projectile/energy/net_snare.dm
index f5d0607341..c8333a811c 100644
--- a/code/modules/projectiles/projectile/energy/net_snare.dm
+++ b/code/modules/projectiles/projectile/energy/net_snare.dm
@@ -42,10 +42,10 @@
/obj/effect/nettingportal/proc/pop(teletarget)
if(teletarget)
for(var/mob/living/L in get_turf(src))
- do_teleport(L, teletarget, 2)//teleport what's in the tile to the beacon
+ do_teleport(L, teletarget, 2, channel = TELEPORT_CHANNEL_BLUESPACE)//teleport what's in the tile to the beacon
else
for(var/mob/living/L in get_turf(src))
- do_teleport(L, L, 15) //Otherwise it just warps you off somewhere.
+ do_teleport(L, L, 15, channel = TELEPORT_CHANNEL_BLUESPACE) //Otherwise it just warps you off somewhere.
qdel(src)
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index dee88f176f..5b84608fad 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -67,7 +67,7 @@
teleloc = target.loc
for(var/atom/movable/stuff in teleloc)
if(!stuff.anchored && stuff.loc)
- if(do_teleport(stuff, stuff, 10))
+ if(do_teleport(stuff, stuff, 10, channel = TELEPORT_CHANNEL_MAGIC))
teleammount++
var/datum/effect_system/smoke_spread/smoke = new
smoke.set_up(max(round(4 - teleammount),0), stuff.loc) //Smoke drops off if a lot of stuff is moved for the sake of sanity
diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
index 211fddca26..a46a4d61e4 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
@@ -2076,7 +2076,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/blazaam/on_mob_life(mob/living/carbon/M)
if(M.drunkenness > 40)
if(stored_teleports)
- do_teleport(M, get_turf(M), rand(1,3))
+ do_teleport(M, get_turf(M), rand(1,3), channel = TELEPORT_CHANNEL_WORMHOLE)
stored_teleports--
if(prob(10))
stored_teleports += rand(2,6)
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 840a57055c..db927411c0 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -346,7 +346,7 @@
//We only get 30u to start with...
/datum/reagent/fuel/holyoil/reaction_obj(obj/O, reac_volume)
- . = ..()
+ . = ..()
if(istype(O, /obj/item/stack/sheet/metal))
var/obj/item/stack/sheet/metal/M = O
reac_volume = min(reac_volume, M.amount)
@@ -989,7 +989,7 @@
/datum/reagent/bluespace/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
if(method == TOUCH || method == VAPOR)
- do_teleport(M, get_turf(M), (reac_volume / 5), asoundin = 'sound/effects/phasein.ogg') //4 tiles per crystal
+ do_teleport(M, get_turf(M), (reac_volume / 5), asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE) //4 tiles per crystal
..()
/datum/reagent/bluespace/on_mob_life(mob/living/carbon/M)
@@ -1001,7 +1001,7 @@
..()
/mob/living/proc/bluespace_shuffle()
- do_teleport(src, get_turf(src), 5, asoundin = 'sound/effects/phasein.ogg')
+ do_teleport(src, get_turf(src), 5, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
/datum/reagent/aluminium
name = "Aluminium"
diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm
index 59df0f6e85..d27c876f88 100644
--- a/code/modules/research/designs/misc_designs.dm
+++ b/code/modules/research/designs/misc_designs.dm
@@ -460,6 +460,16 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+/datum/design/quantum_keycard
+ name = "Quantum Keycard"
+ desc = "Allows for the construction of a quantum keycard."
+ id = "quantum_keycard"
+ build_type = PROTOLATHE
+ materials = list(MAT_GLASS = 500, MAT_METAL = 500, MAT_SILVER = 500, MAT_BLUESPACE = 1000)
+ build_path = /obj/item/quantum_keycard
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING
+
/datum/design/anomaly_neutralizer
name = "Anomaly Neutralizer"
desc = "An advanced tool capable of instantly neutralizing anomalies, designed to capture the fleeting aberrations created by the engine."
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index ebd386513e..e56350a280 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -651,7 +651,7 @@
if(loc == user && !is_centcom_level(userturf.z)) //Because Nuke Ops bringing this back on their shuttle, then looting the ERT area is 2fun4you!
visible_message("[src] twists and bends, relocating itself!")
throwSmoke(userturf)
- do_teleport(user, userturf, 8, asoundin = 'sound/effects/phasein.ogg')
+ do_teleport(user, userturf, 8, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
throwSmoke(get_turf(user))
warn_admins(user, "Teleport", 0)
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index c6487c92f0..1cbe3f0dea 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -227,33 +227,42 @@
display_name = "Basic Bluespace Theory"
description = "Basic studies into the mysterious alternate dimension known as bluespace."
prereq_ids = list("base", "datatheory")
- design_ids = list("beacon", "xenobioconsole", "telesci_gps")
+ design_ids = list("beacon", "xenobioconsole", "telesci_gps", "bluespace_crystal", "xenobio_monkeys")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
+/datum/techweb_node/bluespace_travel
+ id = "bluespace_travel"
+ display_name = "Bluespace Travel"
+ description = "Application of Bluespace for static teleportation technology."
+ prereq_ids = list("practical_bluespace")
+ design_ids = list("tele_station", "tele_hub", "quantumpad", "launchpad", "launchpad_console", "bluespace_pod")
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
+ export_price = 5000
+
+/datum/techweb_node/micro_bluespace
+ id = "micro_bluespace"
+ display_name = "Miniaturized Bluespace Research"
+ description = "Extreme reduction in space required for bluespace engines, leading to portable bluespace technology."
+ prereq_ids = list("bluespace_travel", "practical_bluespace", "high_efficiency")
+ design_ids = list("bluespace_matter_bin", "femto_mani", "triphasic_scanning", "bag_holding", "quantum_keycard", "wormholeprojector", "xenobio_slimeadv")
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000)
+ export_price = 5000
+
/datum/techweb_node/practical_bluespace
id = "practical_bluespace"
display_name = "Applied Bluespace Research"
description = "Using bluespace to make things faster and better."
prereq_ids = list("bluespace_basic", "engineering")
- design_ids = list("bs_rped","biobag_holding","minerbag_holding", "bluespacebeaker", "bluespacesyringe", "phasic_scanning", "bluespacesmartdart")
+ design_ids = list("bs_rped","biobag_holding","minerbag_holding", "bluespacebeaker", "bluespacesyringe", "phasic_scanning", "bluespacesmartdart", "xenobio_slimebasic")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
export_price = 5000
-/datum/techweb_node/adv_bluespace
- id = "adv_bluespace"
- display_name = "Advanced Bluespace Research"
- description = "Deeper understanding of how the Bluespace dimension works"
- prereq_ids = list("practical_bluespace", "high_efficiency")
- design_ids = list("bluespace_matter_bin", "femto_mani", "triphasic_scanning", "bluespace_crystal")
- research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000)
- export_price = 5000
-
/datum/techweb_node/bluespace_power
id = "bluespace_power"
display_name = "Bluespace Power Technology"
description = "Even more powerful.. power!"
- prereq_ids = list("adv_power", "adv_bluespace")
+ prereq_ids = list("adv_power", "practical_bluespace")
design_ids = list("bluespace_cell", "quadratic_capacitor")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
index ad5bfa27dc..b9e7122d07 100644
--- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
@@ -680,7 +680,7 @@ datum/status_effect/stabilized/blue/on_remove()
if(!F)
F = get_turf(owner)
range = 50
- if(do_teleport(owner, F, range))
+ if(do_teleport(owner, F, range, channel = TELEPORT_CHANNEL_BLUESPACE))
to_chat(owner, "[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)
diff --git a/code/modules/research/xenobiology/crossbreeding/burning.dm b/code/modules/research/xenobiology/crossbreeding/burning.dm
index 38362e6d64..363331e12d 100644
--- a/code/modules/research/xenobiology/crossbreeding/burning.dm
+++ b/code/modules/research/xenobiology/crossbreeding/burning.dm
@@ -144,7 +144,7 @@ Burning extracts:
user.visible_message("[src] sparks, and lets off a shockwave of bluespace energy!")
for(var/mob/living/L in range(1, get_turf(user)))
if(L != user)
- do_teleport(L, get_turf(L), 6, asoundin = 'sound/effects/phasein.ogg') //Somewhere between the effectiveness of fake and real BS crystal
+ do_teleport(L, get_turf(L), 6, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE) //Somewhere between the effectiveness of fake and real BS crystal
new /obj/effect/particle_effect/sparks(get_turf(L))
playsound(get_turf(L), "sparks", 50, 1)
..()
diff --git a/code/modules/research/xenobiology/crossbreeding/consuming.dm b/code/modules/research/xenobiology/crossbreeding/consuming.dm
index b51a7b2553..0b2d60da8c 100644
--- a/code/modules/research/xenobiology/crossbreeding/consuming.dm
+++ b/code/modules/research/xenobiology/crossbreeding/consuming.dm
@@ -232,7 +232,7 @@ Consuming extracts:
L.Cut(I,I+1)
if(target)
- do_teleport(M, target, 0, asoundin = 'sound/effects/phasein.ogg')
+ do_teleport(M, target, 0, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
new /obj/effect/particle_effect/sparks(get_turf(M))
playsound(get_turf(M), "sparks", 50, 1)
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index ce36be8e42..7acbaaac1c 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -494,7 +494,7 @@
to_chat(user, "You feel your body vibrating...")
if(do_after(user, 25, target = user))
to_chat(user, "You teleport!")
- do_teleport(user, get_turf(user), 6, asoundin = 'sound/weapons/emitter2.ogg')
+ do_teleport(user, get_turf(user), 6, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
return 300
if(SLIME_ACTIVATE_MAJOR)
@@ -510,7 +510,7 @@
if(teleport_x && teleport_y && teleport_z)
var/turf/T = locate(teleport_x, teleport_y, teleport_z)
to_chat(user, "You snap back to your anchor point!")
- do_teleport(user, T, asoundin = 'sound/weapons/emitter2.ogg')
+ do_teleport(user, T, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
return 450
diff --git a/code/modules/spells/spell_types/area_teleport.dm b/code/modules/spells/spell_types/area_teleport.dm
index ab399f4e2a..7bede9f8be 100644
--- a/code/modules/spells/spell_types/area_teleport.dm
+++ b/code/modules/spells/spell_types/area_teleport.dm
@@ -58,7 +58,7 @@
var/success = 0
while(tempL.len)
attempt = pick(tempL)
- target.Move(attempt)
+ do_teleport(target, attempt, channel = TELEPORT_CHANNEL_MAGIC)
if(get_turf(target) == attempt)
success = 1
break
@@ -66,7 +66,7 @@
tempL.Remove(attempt)
if(!success)
- target.forceMove(L)
+ do_teleport(target, L, forceMove = TRUE, channel = TELEPORT_CHANNEL_MAGIC)
playsound(get_turf(user), sound2, 50,1)
return
diff --git a/code/modules/spells/spell_types/turf_teleport.dm b/code/modules/spells/spell_types/turf_teleport.dm
index 093285b74d..8a45f2be22 100644
--- a/code/modules/spells/spell_types/turf_teleport.dm
+++ b/code/modules/spells/spell_types/turf_teleport.dm
@@ -40,6 +40,5 @@
if(!picked || !isturf(picked))
return
- if(!target.Move(picked))
- target.forceMove(picked)
- playsound(get_turf(user), sound2, 50,1)
+ if(do_teleport(user, picked, forceMove = TRUE, channel = TELEPORT_CHANNEL_MAGIC))
+ playsound(get_turf(user), sound1, 50,1)
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 29086033c8..e13ce10347 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index 55c33e5e83..032b0c27ad 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ
diff --git a/modular_citadel/code/modules/research/techweb/all_nodes.dm b/modular_citadel/code/modules/research/techweb/all_nodes.dm
index c0ddaceaf7..55b3a55736 100644
--- a/modular_citadel/code/modules/research/techweb/all_nodes.dm
+++ b/modular_citadel/code/modules/research/techweb/all_nodes.dm
@@ -1,15 +1,3 @@
-/datum/techweb_node/bluespace_basic/New()
- . = ..()
- design_ids += "xenobio_monkeys"
-
-/datum/techweb_node/practical_bluespace/New()
- . = ..()
- design_ids += "xenobio_slimebasic"
-
-/datum/techweb_node/adv_bluespace/New()
- . = ..()
- design_ids += "xenobio_slimeadv"
-
/datum/techweb_node/ballistic_weapons/New()
. = ..()
design_ids += "mag_oldsmg_rubber"
diff --git a/tgstation.dme b/tgstation.dme
index 24477d885b..ab360ad73d 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -861,6 +861,7 @@
#include "code\game\objects\items\devices\pipe_painter.dm"
#include "code\game\objects\items\devices\powersink.dm"
#include "code\game\objects\items\devices\pressureplates.dm"
+#include "code\game\objects\items\devices\quantum_keycard.dm"
#include "code\game\objects\items\devices\reverse_bear_trap.dm"
#include "code\game\objects\items\devices\scanners.dm"
#include "code\game\objects\items\devices\sensor_device.dm"