mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2025-12-22 16:12:19 +00:00
This pr changes how telescience works; instead of just teleport things with zero risk or consequences, telescience will now create two portals, one in the telepad, and the other in the location. Why? Telescience has always been a really problematic part of the game, causing a lot of fuckery over the ages. It is pretty much riskless, besides some possible explosion, limb loss or whatever if you fuck up, but if you somewhat knew what you were doing, you could steal shit, and just teleport bombs or whatever upon your victims. Now, telescience has some risk and difficulty attached to it. Since, for the scientist to steal/kidnapp/save someone, they must enter the portal, which puts them in the location of where they want to reach. It is also possible for the people that can reach the portal to end in the telescience lab, allowing for some counter play.
367 lines
12 KiB
Plaintext
367 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 && destturf != teleatom)
|
|
impediment = destturf
|
|
|
|
else
|
|
for(var/atom/movable/A in destturf)
|
|
if(A != teleatom && 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) && !istype(teleatom, /obj/effect/portal))
|
|
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, /obj/mecha))
|
|
valid = 1
|
|
var/obj/mecha/M = teleatom
|
|
if(newdest)
|
|
M.ex_act(3)
|
|
M.occupant.adjustHalLoss(25)
|
|
to_chat(M.occupant, "<span class='danger'>You feel a sharp abdominal pain inside yourself as the [teleatom] phases into \the [impediment]</span>")
|
|
|
|
boominess += max(0, M.w_class - 1)
|
|
if(M.density)
|
|
boominess += 5
|
|
if(M.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>")
|
|
H.apply_damage(35, BRUTE, E, 0, sharp=0, edge=0)
|
|
|
|
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
|
|
to_chat(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(!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
|