Files
Aurora.3/code/datums/helper_datums/teleport.dm
BurgerLUA 0c842b5c84 Adds Bluespace Inhibitors (Telescience Nerf) (#5652)
Adds telescience inhibitors to the station. These are fragile, powered machines that inhibit where bluespace activity can occur. The way it works is that it creates an 8 radius (16 tile wide) circular field that displaces any incoming or outgoing bluespace signal to an unintended destination just outside the area of effect.

Basically, incoming teleport signals are redirected to around a random location around the circle, and outgoing teleport signals are redirected to around a random location around the circle. For example, if a ninja was inside the area of effect and tried to teleport outside of it, it wouldn't work but instead teleport something else around me just outside the circle. This will very rarely occur, so most that will happen is that the ninja won't be able to teleport while inside the area of effect. If a ninja was outside the area of effect and tried teleporting inside the circle, they would instead teleport to a random location outside the circle.

A semi-intended side effect is that it would be harder for ninjas/wizards to break into the armory/vault/ai core. Of course, they could use other tools and walk inside the vault. This does not stop them from ever entering it, but makes it unsafe to teleport out.

EMPing a bluespace inhibitor teleports everything in a 20 tile radius to a random location on the station. This teleportation is "safe" and will only teleport the objects in a random station area in unoccupied space.
2018-12-16 15:08:02 +02:00

351 lines
12 KiB
Plaintext

//wrapper
/proc/do_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null)
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_system/effectin //effect to show right before teleportation
var/datum/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)
/datum/teleport/New(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null)
..()
if(!initTeleport(arglist(args)))
return 0
return 1
/datum/teleport/proc/initTeleport(ateleatom,adestination,aprecision,afteleport,aeffectin,aeffectout,asoundin,asoundout)
if(!setTeleatom(ateleatom))
return 0
if(!setDestination(adestination))
return 0
if(!setPrecision(aprecision))
return 0
setEffects(aeffectin,aeffectout)
setForceTeleport(afteleport)
setSounds(asoundin,asoundout)
return 1
//must succeed
/datum/teleport/proc/setPrecision(aprecision)
if(isnum(aprecision))
precision = aprecision
return 1
return 0
/datum/teleport/proc/checkInhibitors(atom/adestination)
if(istype(adestination))
var/list/turf/good_turfs = list()
var/list/turf/bad_turfs = list()
for(var/found_inhibitor in circlerange(adestination,8))
if(!istype(found_inhibitor,/obj/machinery/anti_bluespace))
continue
var/obj/machinery/anti_bluespace/AB = found_inhibitor
if(AB.stat & (NOPOWER | BROKEN) )
continue
AB.use_power(AB.active_power_usage)
bad_turfs += circlerangeturfs(get_turf(AB),8)
good_turfs += circlerangeturfs(get_turf(AB),9)
if(good_turfs.len && bad_turfs.len)
good_turfs -= bad_turfs
return pick(good_turfs)
return adestination
//must succeed
/datum/teleport/proc/setDestination(atom/adestination)
if(istype(adestination))
destination = checkInhibitors(adestination)
return 1
return 0
//must succeed in most cases
/datum/teleport/proc/setTeleatom(atom/movable/ateleatom)
if(!istype(ateleatom))
return 0
teleatom = checkInhibitors(ateleatom)
if(isturf(teleatom))
var/turf/T = teleatom
var/atom/valid_atoms = list()
for(var/atom/movable in T)
valid_atoms += T
ateleatom = pick(valid_atoms)
if(istype(ateleatom, /obj/effect) && !istype(ateleatom, /obj/effect/dummy/chameleon))
qdel(ateleatom)
return 0
return 1
//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_system/effect,sound)
if(location)
if(effect)
spawn(-1)
src = null
effect.location = location
effect.queue()
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)
var/area/destarea = get_area(destination)
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(force_teleport)
teleatom.forceMove(destturf)
playSpecials(destturf,effectout,soundout)
var/atom/impediment
var/valid = 0
if(destturf.density)
impediment = destturf
else
for(var/atom/movable/A in destturf)
if(A.density && A.anchored)
if(A.flags & ON_BORDER)
if(prob(10))
impediment = A
break
else
impediment = A
break
if(impediment)
var/turf/newdest
var/boominess = 0
for(var/turf/T in range(1, destturf))
if(!T.density)
for(var/atom/movable/A in T)
var/blocked = 0
if(A.density && A.opacity && A.anchored)
blocked = 1
break
if(!blocked)
newdest = T
break
if(istype(teleatom, /obj))
valid = 1
var/obj/O = teleatom
if(newdest)
O.ex_act(3)
boominess += max(0, O.w_class - 1)
if(O.density)
boominess += 5
if(O.opacity)
boominess += 10
if(istype(teleatom, /mob/living))
valid = 1
var/mob/living/L = teleatom
boominess += L.mob_size/4
if(!L.incorporeal_move)
if(istype(L, /mob/living/carbon/human))
var/mob/living/carbon/human/H = L
if(newdest)
var/list/organs_to_gib = list()
for(var/obj/item/organ/external/ext in H.organs)
if(!ext.vital) //ensures someone doesn't instantly die, allowing them to slowly die instead
organs_to_gib.Add(ext)
if(organs_to_gib.len)
var/obj/item/organ/external/E = pick(organs_to_gib)
to_chat(H, "<span class='danger'>You partially phase into \the [impediment], causing your [E.name] to violently dematerialize!</span>")
E.droplimb(0,DROPLIMB_BLUNT)
else
if(newdest)
to_chat(L, "<span class='danger'>You partially phase into \the [impediment], causing a chunk of you to violently dematerialize!</span>")
L.adjustBruteLoss(40)
if(!newdest && L.mind)
var/mob/living/simple_animal/shade/bluespace/BS = new /mob/living/simple_animal/shade/bluespace(destturf)
to_chat(L, "<span class='danger'>You feel your spirit violently rip from your body in a flurry of violent extradimensional disarray!</span>")
L.mind.transfer_to(BS)
to_chat(BS, "<b>You are now a bluespace echo - consciousness imprinted upon wavelengths of bluespace energy. You currently retain no memories of your previous life, but do express a strong desire to return to corporeality. You will die soon, fading away forever. Good luck!</b>")
BS.original_body = L
var/list/turfs_to_teleport = list()
for(var/turf/T in orange(20, get_turf(BS)))
turfs_to_teleport += T
do_teleport(BS, pick(turfs_to_teleport))
for(var/mob/living/M in L)
if(M.mind)
var/mob/living/simple_animal/shade/bluespace/more_BS = new /mob/living/simple_animal/shade/bluespace(get_turf(M))
to_chat(M, "<span class='danger'>You feel your spirit violently rip from your body in a flurry of violent extradimensional disarray!</span>")
M.mind.transfer_to(more_BS)
to_chat(more_BS, "<b>You are now a bluespace echo - consciousness imprinted upon wavelengths of bluespace energy. You currently retain no memories of your previous life, but do express a strong desire to return to corporeality. You will die soon, fading away forever. Good luck!</b>")
more_BS.original_body = M
for(var/turf/T in orange(20, get_turf(BS)))
turfs_to_teleport += T
do_teleport(more_BS, pick(turfs_to_teleport))
else
newdest = destturf
valid = 0
if(valid && newdest)
destturf.visible_message("<span class ='danger'>There is a sizable emission of energy as \the [teleatom] phases into \the [impediment]!</span>")
explosion(destturf, ((boominess > 10) ? 1 : 0), ((boominess > 5) ? (boominess/10) : 0), boominess/5, boominess/2)
teleatom.forceMove(newdest)
else if(!newdest)
var/list/turfs_to_teleport = list()
var/turf/target_turf
for(var/turf/T in orange(10, get_turf(teleatom)))
turfs_to_teleport += T
target_turf = pick(turfs_to_teleport)
if(target_turf)
do_teleport(teleatom, target_turf)
else
do_teleport(teleatom, get_turf(teleatom))
else if(istype(teleatom, /mob/living/simple_animal/shade/bluespace))
var/mob/living/simple_animal/shade/bluespace/BS = teleatom
for(var/mob/living/L in destturf)
if(!L.mind && !isvaurca(L))
if(BS.message_countdown >= 200)
to_chat(BS, "<span class='notice'><b>You feel relief wash over you as your harried spirit fills into \the [L] like water into a vase.</b></span>")
BS.mind.transfer_to(L)
to_chat(L, "<b>You have been restored to a corporeal form. You retain no memories of your time as a bluespace echo, but regardless of your current form the memories of your time before being a bluespace echo are returned.</b>")
qdel(BS)
else
to_chat(BS, "<span class='warning'>You lack the strength of echoes necessary to reattain corporeality in \the [L]!</span>")
break
else
if(teleatom.Move(destturf))
playSpecials(destturf,effectout,soundout)
if(C)
C.forceMove(destturf)
destarea.Entered(teleatom)
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, 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_system/sparks/aeffect = new(null, FALSE, 5, alldirs)
effectin = effectin || aeffect
effectout = effectout || aeffect
return 1
else
return ..()
/datum/teleport/instant/science/setPrecision(aprecision)
..()
if(istype(teleatom, /obj/item/weapon/storage/backpack/holding))
precision = rand(1,100)
var/list/bagholding = teleatom.search_contents_for(/obj/item/weapon/storage/backpack/holding)
if(bagholding.len)
precision = max(rand(1,100)*bagholding.len,100)
if(istype(teleatom, /mob/living))
var/mob/living/MM = teleatom
MM << "<span class='danger'>The Bluespace interface on your [teleatom] interferes with the teleport!</span>"
return 1
/datum/teleport/instant/science/teleportChecks()
if(istype(teleatom, /obj/item/weapon/disk/nuclear)) // Don't let nuke disks get teleported --NeoFite
teleatom.visible_message("<span class='danger'>\The [teleatom] bounces off of the portal!</span>")
return 0
if(isobserver(teleatom)) // do not teleport ghosts
return 0
if(!isemptylist(teleatom.search_contents_for(/obj/item/weapon/disk/nuclear)))
if(istype(teleatom, /mob/living))
var/mob/living/MM = teleatom
MM.visible_message("<span class='danger'>\The [MM] bounces off of the portal!</span>","<span class='warning'>Something you are carrying seems to be unable to pass through the portal. Better drop it if you want to go through.</span>")
else
teleatom.visible_message("<span class='danger'>\The [teleatom] bounces off of the portal!</span>")
return 0
if(destination.z in current_map.admin_levels) //centcomm z-level
if(istype(teleatom, /obj/mecha))
var/obj/mecha/MM = teleatom
MM.occupant << "<span class='danger'>\The [MM] would not survive the jump to a location so far away!</span>"
return 0
if(!isemptylist(teleatom.search_contents_for(/obj/item/weapon/storage/backpack/holding)))
teleatom.visible_message("<span class='danger'>\The [teleatom] bounces off of the portal!</span>")
return 0
if(destination.z > max_default_z_level()) //Away mission z-levels
return 0
return 1