[MIRROR] Refactors do_teleport (#11935)

Co-authored-by: Guti <32563288+TheCaramelion@users.noreply.github.com>
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
CHOMPStation2StaffMirrorBot
2025-11-07 15:17:27 -07:00
committed by GitHub
parent 806a61ef5c
commit 1f8f2888f4
15 changed files with 185 additions and 258 deletions

View File

@@ -0,0 +1,4 @@
///Called before a movable is being teleported from `check_teleport_valid()`: (destination, channel)
#define COMSIG_MOVABLE_TELEPORTING "movable_teleporting"
///Called after a movable is teleported from `do_teleport()`: ()
#define COMSIG_MOVABLE_POST_TELEPORT "movable_post_teleport"

View File

@@ -0,0 +1,4 @@
/// Classic bluespace teleportation, requires a sender but no receiver
#define TELEPORT_CHANNEL_BLUESPACE "bluespace"
/// Quantum-based teleportation, requires both sender and receiver, but is free from normal disruption
#define TELEPORT_CHANNEL_QUANTUM "quantum"

View File

@@ -110,9 +110,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
*/
#define TRAIT_NODROP "nodrop"
#define TRAIT_DISRUPTED "disrupted"
#define TRAIT_NO_TELEPORT "no-teleport" //you just can't
/*
#define TRAIT_T_RAY_VISIBLE "t-ray-visible" // Visible on t-ray scanners if the atom/var/level == 1
#define TRAIT_NO_TELEPORT "no-teleport" //you just can't
//quirk traits
#define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance"

View File

@@ -24,7 +24,7 @@ GLOBAL_LIST_BOILERPLATE(all_darkportal_minions, /obj/structure/dark_portal/minio
to_check.Stun(10)
return
do_teleport(M, locked, precision, local = FALSE, bohsafe = TRUE)
do_teleport(M, locked, precision, channel = TELEPORT_CHANNEL_QUANTUM)
if(one_time_use)
one_time_use = 0

View File

@@ -76,7 +76,7 @@
var/obj/structure/closet/exit_closet = exit_point
if(!exit_closet.can_open()) // Bwomp. You're locked now. :)
for(var/atom/movable/AM in contents)
do_noeffect_teleport(AM, exit_closet, 0, 1)
do_teleport(AM, exit_closet, channel = TELEPORT_CHANNEL_BLUESPACE, no_effects = TRUE)
return
exit_closet.open()
@@ -86,7 +86,7 @@
for(var/atom/movable/AM in contents)
if(QDELETED(AM))
continue
do_noeffect_teleport(AM, get_turf(exit_point), 0, 1)
do_teleport(AM, get_turf(exit_point), channel = TELEPORT_CHANNEL_BLUESPACE, no_effects = TRUE)
if(!isbelly(exit_point))
AM.throw_at(target, throw_range, 1)
contents.Cut()

View File

@@ -6,223 +6,180 @@ GLOBAL_LIST_INIT(bluespace_item_types, list(
/obj/item/storage/belt/medical/holding
))
//wrapper
/proc/do_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=TRUE, bohsafe=FALSE)
new /datum/teleport/instant/science(arglist(args))
return
/datum/teleport
var/atom/movable/teleatom //atom to teleport
var/atom/destination //destination to teleport to
var/precision = 0 //teleport precision
var/datum/effect/effect/system/effectin //effect to show right before teleportation
var/datum/effect/effect/system/effectout //effect to show right after teleportation
var/soundin //soundfile to play before teleportation
var/soundout //soundfile to play after teleportation
var/force_teleport = 1 //if false, teleport will use Move() proc (dense objects will prevent teleportation)
var/local = TRUE //If false, can teleport from/to any z-level
var/bohsafe = FALSE //If true, can teleport safely with a BoH
/datum/teleport/New(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=TRUE, bohsafe=FALSE)
..()
if(!initTeleport(arglist(args)))
return 0
return 1
/datum/teleport/proc/initTeleport(ateleatom,adestination,aprecision,afteleport,aeffectin,aeffectout,asoundin,asoundout,local,bohsafe)
if(!setTeleatom(ateleatom))
return 0
if(!setDestination(adestination))
return 0
src.bohsafe = bohsafe
if(!setPrecision(aprecision))
return 0
setEffects(aeffectin,aeffectout)
setForceTeleport(afteleport)
setSounds(asoundin,asoundout)
src.local = local
return 1
//must succeed
/datum/teleport/proc/setPrecision(aprecision)
if(isnum(aprecision))
precision = aprecision
return 1
return 0
//must succeed
/datum/teleport/proc/setDestination(atom/adestination)
if(istype(adestination))
destination = adestination
return 1
return 0
//must succeed in most cases
/datum/teleport/proc/setTeleatom(atom/movable/ateleatom)
if(istype(ateleatom, /obj/effect) && !istype(ateleatom, /obj/effect/dummy/chameleon))
qdel(ateleatom)
return 0
if(istype(ateleatom))
teleatom = ateleatom
return 1
return 0
//custom effects must be properly set up first for instant-type teleports
//optional
/datum/teleport/proc/setEffects(datum/effect/effect/system/aeffectin=null,datum/effect/effect/system/aeffectout=null)
effectin = istype(aeffectin) ? aeffectin : null
effectout = istype(aeffectout) ? aeffectout : null
return 1
//optional
/datum/teleport/proc/setForceTeleport(afteleport)
force_teleport = afteleport
return 1
//optional
/datum/teleport/proc/setSounds(asoundin=null,asoundout=null)
soundin = isfile(asoundin) ? asoundin : null
soundout = isfile(asoundout) ? asoundout : null
return 1
//placeholder
/datum/teleport/proc/teleportChecks()
return 1
/datum/teleport/proc/playSpecials(atom/location,datum/effect/effect/system/effect,sound)
if(location)
if(effect)
spawn(-1)
src = null
effect.attach(location)
effect.start()
if(sound)
spawn(-1)
src = null
playsound(location,sound,60,1)
return
//do the monkey dance
/datum/teleport/proc/doTeleport()
var/turf/destturf
var/turf/curturf = get_turf(teleatom)
if(precision)
var/list/posturfs = circlerangeturfs(destination,precision)
destturf = safepick(posturfs)
else
destturf = get_turf(destination)
if(!destturf || !curturf)
return 0
playSpecials(curturf,effectin,soundin)
var/obj/structure/bed/chair/C = null
if(isliving(teleatom))
var/mob/living/L = teleatom
if(L.buckled)
C = L.buckled
if(try_televore())
return
if(force_teleport)
teleatom.forceMove(destturf)
playSpecials(destturf,effectout,soundout)
else
if(teleatom.Move(destturf))
playSpecials(destturf,effectout,soundout)
if(C)
C.forceMove(destturf)
return 1
/datum/teleport/proc/teleport()
if(teleportChecks())
return doTeleport()
return 0
/datum/teleport/instant //teleports when datum is created
/datum/teleport/instant/New(ateleatom, adestination, aprecision=0, afteleport=1, bohsafe=0, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null)
if(..())
teleport()
return
/datum/teleport/instant/science/setEffects(datum/effect/effect/system/aeffectin,datum/effect/effect/system/aeffectout)
if(!aeffectin || !aeffectout)
var/datum/effect/effect/system/spark_spread/aeffect = new
aeffect.set_up(5, 1, teleatom)
var/datum/effect/effect/system/spark_spread/aeffect2 = new
aeffect2.set_up(5, 1, teleatom)
effectin = effectin || aeffect
effectout = effectout || aeffect2
return 1
else
return ..()
/datum/teleport/instant/science/setPrecision(aprecision)
..()
if(bohsafe)
return 1
/proc/do_teleport(atom/movable/teleatom, atom/destination, precision = null, datum/effect/effect/effectin = null, datum/effect/effect/effectout = null, asoundin = null, asoundout = null, no_effects=FALSE, channel=TELEPORT_CHANNEL_BLUESPACE, forced = FALSE)
if(isnull(precision))
precision = 0
switch(channel)
if(TELEPORT_CHANNEL_BLUESPACE)
var/list/bluespace_things = newlist()
for(var/item in GLOB.bluespace_item_types)
if (istype(teleatom, item))
precision = rand(1, 100)
bluespace_things |= teleatom.search_contents_for(item)
if(isliving(teleatom))
var/mob/living/L = teleatom
if(LAZYLEN(L.buckled_mobs))
for(var/mob/rider in L.buckled_mobs)
for (var/item in GLOB.bluespace_item_types)
bluespace_things |= rider.search_contents_for(item)
if(bluespace_things.len)
precision = max(rand(1, 100)*bluespace_things.len, 100)
if(isliving(teleatom))
var/mob/living/MM = teleatom
to_chat(MM, span_danger("The Bluespace interface on your [teleatom] interferes with the teleport!"))
return 1
var/mob/living/mob = teleatom
to_chat(mob, span_warning("The bluespace interface on your equipment interferes with the teleport!"))
if((!effectin || !effectout) && !no_effects)
var/datum/effect/effect/system/spark_spread/sparks = new
sparks.set_up(5, 1, teleatom)
if(!effectin)
effectin = sparks
if(!effectout)
effectout = sparks
/datum/teleport/instant/science/teleportChecks()
if(istype(teleatom, /obj/item/disk/nuclear)) // Don't let nuke disks get teleported --NeoFite
teleatom.visible_message(span_danger("\The [teleatom] bounces off of the portal!"))
return 0
if(TELEPORT_CHANNEL_QUANTUM)
if((!effectin || !effectout) && !no_effects)
var/datum/effect/effect/system/spark_spread/sparks = new
sparks.set_up(5, 1, teleatom)
if(!effectin)
effectin = sparks
if(!effectout)
effectout = sparks
var/turf/curturf = get_turf(teleatom)
var/turf/destturf
destturf = get_teleport_turf(get_turf(destination), precision)
if(istype(destination, /obj/structure/closet)) // First check if it's a closet, for the bluespace locker funsies...
destturf = destination
if(isbelly(destination)) // And if it goes STRAIGHT to a belly? Toss them there. (If pref matches, of course)
var/obj/belly/belly = destination
if(can_spontaneous_vore(belly.owner, teleatom) && belly.owner != teleatom)
destturf = destination
// HOLD IT! destturf? Hell nah, televore finally works again.
// Now CHECK if someone capable of televoring is in the same turf...
if(!isemptylist(teleatom.search_contents_for(/obj/item/disk/nuclear)))
if(isliving(teleatom))
var/mob/living/MM = teleatom
MM.visible_message(span_danger("\The [MM] bounces off of the portal!"),span_warning("Something you are carrying seems to be unable to pass through the portal. Better drop it if you want to go through."))
else
teleatom.visible_message(span_danger("\The [teleatom] bounces off of the portal!"))
return 0
var/obstructed = 0
var/turf/dest_turf = get_turf(destination)
if(local && !(dest_turf.z in using_map.player_levels))
if(isliving(teleatom))
to_chat(teleatom, span_warning("The portal refuses to carry you that far away!"))
return 0
else if(istype(destination.loc, /obj/belly))
var/obj/belly/destination_belly = destination.loc
var/mob/living/telenommer = destination_belly.owner
if(istype(telenommer))
if(istype(teleatom, /obj/machinery) || istype(teleatom, /obj/structure))
return 0
else if(!isliving(teleatom))
return 1
else
var/mob/living/telemob = teleatom
if(telemob.can_be_drop_prey && telenommer.can_be_drop_pred)
return 1
obstructed = 1
else if(!((isturf(destination) && !destination.density) || (isturf(destination.loc) && !destination.loc.density)) || !destination.x || !destination.y || !destination.z) //If we're inside something or outside universe
obstructed = 1
to_chat(teleatom, span_warning("Something is blocking way on the other side!"))
if(obstructed)
return 0
var/mob/living/mob = locate() in destturf
// Needs the vore helpers later. Ough.
if(can_spontaneous_vore(mob, telemob))
destturf = mob.vore_selected
else if(can_spontaneous_vore(telemob, mob))
mob.forceMove(telemob.vore_selected)
if(!destturf || !curturf)
return FALSE
if(!forced)
if(!check_teleport_valid(teleatom, destturf, channel, original_destination = destination))
if(ismob(teleatom))
teleatom.balloon_alert(teleatom, "something holds you back!")
return FALSE
if(SEND_SIGNAL(teleatom, COMSIG_MOVABLE_TELEPORTING, destination, channel))
return FALSE
if(SEND_SIGNAL(destturf, COMSIG_ATOM_INTERCEPT_TELEPORT, channel, curturf))
return FALSE
if(isobserver(teleatom))
teleatom.forceMove(destturf)
return TRUE
tele_play_specials(teleatom, curturf, effectin, asoundin)
var/success = teleatom.forceMove(destturf)
if(!success)
return FALSE
. = TRUE
SEND_SIGNAL(teleatom, COMSIG_MOVABLE_POST_TELEPORT, destination, channel)
if(teleatom.has_buckled_mobs())
for(var/mob/living/rider in teleatom.buckled_mobs)
teleatom.unbuckle_mob(rider, TRUE)
var/rider_success = do_teleport(rider, destturf, precision, channel = channel, no_effects = TRUE)
if(!rider_success)
continue
if(get_turf(rider) != destturf)
to_chat(rider, span_warning("As you come to your senses, you realize you aren't riding [teleatom] anymore!"))
continue
teleatom.buckle_mob(rider, TRUE)
/proc/tele_play_specials(atom/movable/teleatom, atom/location, var/datum/effect/effect/system/effect, sound)
if(!location)
return
if(sound)
playsound(location, sound, 60, TRUE)
if(effect)
effect.attach()
effect.start()
/proc/find_safe_turf(zlevel, list/zlevels, dense_atoms = FALSE)
if(!zlevels)
if(zlevel)
zlevels = list(zlevel)
else
return 1
zlevels = using_map.station_levels
var/cycles = 1000
for(var/cycle in 1 to cycles)
var/x = rand(1, world.maxx)
var/y = rand(1, world.maxy)
var/z = pick(zlevels)
var/random_location = locate(x, y, z)
if(is_safe_turf(random_location, dense_atoms, cycle < 300))
return random_location
/proc/is_safe_turf(turf/random_location, dense_atoms = FALSE, no_teleport = FALSE)
. = FALSE
if(!isfloorturf(random_location))
return
var/turf/floor_turf = random_location
var/area/destination_area = floor_turf.loc
if(no_teleport && destination_area.flag_check(AREA_BLOCK_PHASE_SHIFT))
return
if(!dense_atoms)
var/density_found = FALSE
for(var/atom/movable/found_movable in floor_turf)
if(found_movable.density)
density_found = TRUE
break
if(density_found)
return
/proc/get_teleport_turfs(turf/center, precision = 0)
if(!precision)
return list(center)
var/list/posturfs = list()
for(var/turf/T in RANGE_TURFS(precision, center))
var/area/A = T.loc
if(!A.flag_check(AREA_BLOCK_PHASE_SHIFT))
posturfs.Add(T)
return posturfs
/proc/get_teleport_turf(turf/center, precision = 0)
var/list/turfs = get_teleport_turfs(center, precision)
if(length(turfs))
return pick(turfs)
/proc/check_teleport_valid(atom/teleported_atom, atom/destination, channel, atom/original_destination = null)
SHOULD_BE_PURE(TRUE)
if(isnull(destination))
return FALSE
var/area/origin_area = get_area(teleported_atom)
var/area/destination_area = get_area(destination)
if(HAS_TRAIT(teleported_atom, TRAIT_NO_TELEPORT))
return FALSE
if(origin_area.flag_check(AREA_BLOCK_PHASE_SHIFT) || destination_area.flag_check(AREA_BLOCK_PHASE_SHIFT))
return FALSE
return TRUE

View File

@@ -1,26 +0,0 @@
//wrapper
//This teleport effect means that bluespace items will cause a teleport location variation of 1 to 100 tiles.
/proc/do_noeffect_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=FALSE)
new /datum/teleport/instant/science/noeffect(arglist(args))
return
//This teleport effect does not interact with bluespace items.
/proc/do_safe_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=FALSE)
new /datum/teleport/instant(arglist(args))
return
/datum/teleport/instant/science/noeffect/setEffects(datum/effect/effect/system/aeffectin,datum/effect/effect/system/aeffectout)
return TRUE
/datum/teleport/proc/try_televore()
//Destination is in a belly
if(isbelly(destination.loc))
var/obj/belly/B = destination.loc
teleatom.forceMove(get_turf(B)) //So we can splash the sound and sparks and everything.
playSpecials(destination,effectout,soundout)
teleatom.forceMove(B)
return TRUE
//No fun!
return FALSE

View File

@@ -38,13 +38,13 @@
var/mob/living/L = A
if(L.buckled && istype(L.buckled,/obj/structure/bed/))
var/turf/O = L.buckled
do_teleport(O, pick(GLOB.endgame_safespawns), local = FALSE) //VOREStation Edit
do_teleport(O, pick(GLOB.endgame_safespawns))
L.loc = O.loc
else
do_teleport(L, pick(GLOB.endgame_safespawns), local = FALSE) //dead-on precision //VOREStation Edit
do_teleport(L, pick(GLOB.endgame_safespawns)) //dead-on precision
else if (istype(A, /obj/mecha/))
do_teleport(A, pick(GLOB.endgame_safespawns), local = FALSE) //dead-on precision //VOREStation Edit
do_teleport(A, pick(GLOB.endgame_safespawns)) //dead-on precision
else if (isturf(A))
var/turf/T = A

View File

@@ -30,6 +30,4 @@
if(!value["class"] || !value["value"])
return
destination = value["value"]
new /datum/teleport/instant/admin(target,destination)
/datum/teleport/instant/admin
local=FALSE
do_teleport(target, destination, channel = TELEPORT_CHANNEL_QUANTUM)

View File

@@ -135,9 +135,9 @@
to_chat(M, span_notice("Something blocks your way."))
return
temptarg = pick(possible_turfs)
do_safe_teleport(M, temptarg, 0)
do_teleport(M, temptarg)
else if (istype(M, /atom/movable))
do_safe_teleport(M, target, 0)
do_teleport(M, target)
/obj/structure/portal_event/Destroy()
if(target)

View File

@@ -155,7 +155,7 @@
var/datum/effect/effect/system/teleport_greyscale/tele2 = new /datum/effect/effect/system/teleport_greyscale()
tele2.set_up(linked_pad.newcolor, locate((linked_pad.x - xadjust), (linked_pad.y - yadjust), linked_pad.z))
limit += 1
do_teleport(ROI, locate((linked_pad.x - xadjust), (linked_pad.y - yadjust), linked_pad.z), local = FALSE, bohsafe = TRUE, asoundin = 'sound/weapons/emitter2.ogg', asoundout = 'sound/weapons/emitter2.ogg', aeffectin = tele1, aeffectout = tele2)
do_teleport(ROI, locate((linked_pad.x - xadjust), (linked_pad.y - yadjust), linked_pad.z), effectin = tele1, effectout = tele2, asoundin = 'sound/weapons/emitter2.ogg', asoundout = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_QUANTUM)
cut_overlays()
for(var/obj/machinery/hyperpad/P in linked)

View File

@@ -259,22 +259,11 @@
/obj/machinery/power/quantumpad/proc/transport_objects(turf/destination)
for(var/atom/movable/ROI in get_turf(src))
// if is anchored, don't let through
if(ROI.anchored && !ismecha(ROI))
if(ismecha(ROI))
if(boosted)
if(ROI.anchored || (ismecha(ROI) && !boosted))
continue
if(isliving(ROI))
var/mob/living/L = ROI
if(L.buckled)
// TP people on office chairs
if(L.buckled.anchored)
else if(isobserver(ROI) && isEye(ROI))
continue
else
continue
else if(!isobserver(ROI) && !isEye(ROI))
continue
do_teleport(ROI, destination, local = FALSE, asoundin = 'sound/weapons/emitter2.ogg', asoundout = 'sound/weapons/emitter2.ogg') //CHOMP Edit
do_teleport(ROI, destination, asoundin = 'sound/weapons/emitter2.ogg', asoundout = 'sound/weapons/emitter2.ogg') // CHOMPEdit - Noisy
/obj/machinery/power/quantumpad/proc/can_traverse_gateway()
// Well, if there's no gateway map we're definitely not on it

View File

@@ -70,7 +70,7 @@
playsound(src, 'sound/effects/supermatter.ogg', 75, 1)
if(ismob(A) && prob(5))//lucky day
var/destturf = locate(rand(5,world.maxx-5),rand(5,world.maxy-5),pick(using_map.station_levels))
new /datum/teleport/instant(A, destturf, 0, 1, null, null, null, 'sound/effects/phasein.ogg')
do_teleport(A, destturf, 0, 1, asoundin = 'sound/effects/phasein.ogg')
else
return ..()

View File

@@ -72,7 +72,7 @@
spark_system.start()
playsound(src, "sparks", 50, 1)
user.visible_message(span_danger("[user] is abruptly flung somewhere else in response to the damage!"))
do_teleport(user, locate(telex,teley,telez), local = 0, bohsafe = 1)
do_teleport(user, locate(telex,teley,telez), channel = TELEPORT_CHANNEL_QUANTUM)
tele_threshold = initial(tele_threshold)
return TRUE

View File

@@ -132,6 +132,7 @@
#include "code\__defines\misc_ch.dm"
#include "code\__defines\mobs.dm"
#include "code\__defines\mobs_yw.dm"
#include "code\__defines\movement.dm"
#include "code\__defines\nif.dm"
#include "code\__defines\nifsoft.dm"
#include "code\__defines\objects.dm"
@@ -235,6 +236,7 @@
#include "code\__defines\dcs\signals\signals_tgui.dm"
#include "code\__defines\dcs\signals\signals_turf.dm"
#include "code\__defines\dcs\signals\signals_atom\signals_atom_main.dm"
#include "code\__defines\dcs\signals\signals_atom\signals_atom_movable.dm"
#include "code\__defines\dcs\signals\signals_mob\signals_mob_main.dm"
#include "code\__defines\research\research_categories.dm"
#include "code\__defines\research\techweb_nodes.dm"
@@ -779,7 +781,6 @@
#include "code\datums\helper_datums\getrev.dm"
#include "code\datums\helper_datums\stack_end_detector.dm"
#include "code\datums\helper_datums\teleport.dm"
#include "code\datums\helper_datums\teleport_vr.dm"
#include "code\datums\helper_datums\topic_input.dm"
#include "code\datums\interfaces\appearance.dm"
#include "code\datums\locations\locations.dm"