mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
[READY] The Portal Update - Linked portals, momentum conservation, and more! (#28055)
* THE PORTAL UPDATE * portal gun checks * damn functions * o_range(s) * Atmos Portals (#12) * Rod Form's damage now scales with how much it's upgraded * buffs chem grenades * Fix getrev runtime * Automatic changelog generation for PR #27948 [ci skip] * Automatic changelog generation for PR #27951 [ci skip] * Fixes admiral recall (#27861) * the man with the 2 shotguns that blasted me to the end of the world with dualwielding. nerf (#27978) * Beam rifles now slowdown while scoped (#27898) * Update beam_rifle.dm * Update beam_rifle.dm * Update beam_rifle.dm * Fixes a very silly clockwork false wall trick (#27996) * Fixes #27979 (#28002) * Automatic changelog generation for PR #28002 [ci skip] * Fixes #27989 : Riot suits no longer hide jumpsuits (#28003) * Fixes #27989 * remove tag * Automatic changelog generation for PR #28003 [ci skip] * Refactors a cooldown var to not require a spawn or sleep (#28011) * wat (#28012) * Remove spawns in favour of stacktrace calls, which don't stop the called (#28013) proc * Refactor another spawned cooldown var (#28014) * Come on, pathetic (#28015) * Refactor another spawn cooldown (#28016) * Goodbye spawn (#28017) * Another spawn timer (#28018) * Remove a commented out function (#28019) * Gotta go with the fro2.0 (#28010) * This doesn't do anything (#28020) * refactor another spawn cooldown (#28022) * Refactors another spawn cooldown var (#28023) * Refactor another spawn (#28024) * Refactor another spawn var (#28027) * woops * woops2 * atmos links! * unused * wew * ffs! * Forced updates * update * Update portals.dm * adjacent/atmospass checks * Create portals.dm * Update portals.dm * Update other_tools.dm * stuff * crossed * documentation * reee * no portal stacking! * woops
This commit is contained in:
@@ -1242,9 +1242,15 @@ proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types())
|
|||||||
#define QDEL_IN(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE)
|
#define QDEL_IN(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE)
|
||||||
#define QDEL_NULL(item) qdel(item); item = null
|
#define QDEL_NULL(item) qdel(item); item = null
|
||||||
#define QDEL_LIST(L) if(L) { for(var/I in L) qdel(I); L.Cut(); }
|
#define QDEL_LIST(L) if(L) { for(var/I in L) qdel(I); L.Cut(); }
|
||||||
|
#define QDEL_LIST_IN(L, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/______qdel_list_wrapper, L), time, TIMER_STOPPABLE)
|
||||||
#define QDEL_LIST_ASSOC(L) if(L) { for(var/I in L) { qdel(L[I]); qdel(I); } L.Cut(); }
|
#define QDEL_LIST_ASSOC(L) if(L) { for(var/I in L) { qdel(L[I]); qdel(I); } L.Cut(); }
|
||||||
#define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qel(L[I]); L.Cut(); }
|
#define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qel(L[I]); L.Cut(); }
|
||||||
|
|
||||||
|
/proc/______qdel_list_wrapper(list/L) //the underscores are to encourage people not to use this directly.
|
||||||
|
QDEL_LIST(L)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/proc/random_nukecode()
|
/proc/random_nukecode()
|
||||||
var/val = rand(0, 99999)
|
var/val = rand(0, 99999)
|
||||||
var/str = "[val]"
|
var/str = "[val]"
|
||||||
|
|||||||
@@ -67,8 +67,8 @@
|
|||||||
user.forceMove(get_turf(com.locked))
|
user.forceMove(get_turf(com.locked))
|
||||||
|
|
||||||
/obj/effect/portal/attack_ghost(mob/user)
|
/obj/effect/portal/attack_ghost(mob/user)
|
||||||
if(target)
|
if(linked)
|
||||||
user.forceMove(get_turf(target))
|
user.forceMove(get_turf(linked))
|
||||||
|
|
||||||
/obj/machinery/gateway/centerstation/attack_ghost(mob/user)
|
/obj/machinery/gateway/centerstation/attack_ghost(mob/user)
|
||||||
if(awaygate)
|
if(awaygate)
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
var/soundout //soundfile to play after 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/force_teleport = 1 //if false, teleport will use Move() proc (dense objects will prevent teleportation)
|
||||||
|
|
||||||
|
|
||||||
/datum/teleport/proc/start(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null)
|
/datum/teleport/proc/start(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null)
|
||||||
if(!initTeleport(arglist(args)))
|
if(!initTeleport(arglist(args)))
|
||||||
return 0
|
return 0
|
||||||
@@ -100,21 +99,7 @@
|
|||||||
|
|
||||||
var/turf/destturf
|
var/turf/destturf
|
||||||
var/turf/curturf = get_turf(teleatom)
|
var/turf/curturf = get_turf(teleatom)
|
||||||
if(precision)
|
destturf = get_teleport_turf(get_turf(destination), precision)
|
||||||
var/list/posturfs = list()
|
|
||||||
var/center = get_turf(destination)
|
|
||||||
if(!center)
|
|
||||||
center = destination
|
|
||||||
for(var/turf/T in range(precision,center))
|
|
||||||
if(T.is_transition_turf())
|
|
||||||
continue // Avoid picking these.
|
|
||||||
var/area/A = T.loc
|
|
||||||
if(!A.noteleport)
|
|
||||||
posturfs.Add(T)
|
|
||||||
|
|
||||||
destturf = safepick(posturfs)
|
|
||||||
else
|
|
||||||
destturf = get_turf(destination)
|
|
||||||
|
|
||||||
if(!destturf || !curturf || destturf.is_transition_turf())
|
if(!destturf || !curturf || destturf.is_transition_turf())
|
||||||
return 0
|
return 0
|
||||||
@@ -124,13 +109,16 @@
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
playSpecials(curturf,effectin,soundin)
|
playSpecials(curturf,effectin,soundin)
|
||||||
|
|
||||||
if(force_teleport)
|
if(force_teleport)
|
||||||
teleatom.forceMove(destturf)
|
teleatom.forceMove(destturf)
|
||||||
|
if(ismegafauna(teleatom))
|
||||||
|
message_admins("[teleatom] [ADMIN_FLW(teleatom)] has teleported from [ADMIN_COORDJMP(curturf)] to [ADMIN_COORDJMP(destturf)].")
|
||||||
playSpecials(destturf,effectout,soundout)
|
playSpecials(destturf,effectout,soundout)
|
||||||
else
|
else
|
||||||
if(teleatom.Move(destturf))
|
if(teleatom.Move(destturf))
|
||||||
playSpecials(destturf,effectout,soundout)
|
playSpecials(destturf,effectout,soundout)
|
||||||
|
if(ismegafauna(teleatom))
|
||||||
|
message_admins("[teleatom] [ADMIN_FLW(teleatom)] has teleported from [ADMIN_COORDJMP(curturf)] to [ADMIN_COORDJMP(destturf)].")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
/datum/teleport/proc/teleport()
|
/datum/teleport/proc/teleport()
|
||||||
@@ -225,3 +213,18 @@
|
|||||||
|
|
||||||
// DING! You have passed the gauntlet, and are "probably" safe.
|
// DING! You have passed the gauntlet, and are "probably" safe.
|
||||||
return F
|
return F
|
||||||
|
|
||||||
|
/proc/get_teleport_turfs(turf/center, precision = 0)
|
||||||
|
if(!precision)
|
||||||
|
return list(center)
|
||||||
|
var/list/posturfs = list()
|
||||||
|
for(var/turf/T in range(precision,center))
|
||||||
|
if(T.is_transition_turf())
|
||||||
|
continue // Avoid picking these.
|
||||||
|
var/area/A = T.loc
|
||||||
|
if(!A.noteleport)
|
||||||
|
posturfs.Add(T)
|
||||||
|
return posturfs
|
||||||
|
|
||||||
|
/proc/get_teleport_turf(turf/center, precision = 0)
|
||||||
|
return safepick(get_teleport_turfs(center, precision))
|
||||||
|
|||||||
@@ -213,7 +213,8 @@
|
|||||||
|
|
||||||
// Previously known as HasEntered()
|
// Previously known as HasEntered()
|
||||||
// This is automatically called when something enters your square
|
// This is automatically called when something enters your square
|
||||||
/atom/movable/Crossed(atom/movable/AM)
|
//oldloc = old location on atom, inserted when forceMove is called and ONLY when forceMove is called!
|
||||||
|
/atom/movable/Crossed(atom/movable/AM, oldloc)
|
||||||
return
|
return
|
||||||
|
|
||||||
/atom/movable/Bump(atom/A, yes) //the "yes" arg is to differentiate our Bump proc from byond's, without it every Bump() call would become a double Bump().
|
/atom/movable/Bump(atom/A, yes) //the "yes" arg is to differentiate our Bump proc from byond's, without it every Bump() call would become a double Bump().
|
||||||
@@ -249,7 +250,7 @@
|
|||||||
for(var/atom/movable/AM in destination)
|
for(var/atom/movable/AM in destination)
|
||||||
if(AM == src)
|
if(AM == src)
|
||||||
continue
|
continue
|
||||||
AM.Crossed(src)
|
AM.Crossed(src, oldloc)
|
||||||
|
|
||||||
Moved(oldloc, 0)
|
Moved(oldloc, 0)
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@@ -57,18 +57,12 @@
|
|||||||
var/turf/target_turf = pick(L)
|
var/turf/target_turf = pick(L)
|
||||||
if(!target_turf)
|
if(!target_turf)
|
||||||
return
|
return
|
||||||
var/obj/effect/portal/P = new /obj/effect/portal(get_turf(target))
|
var/list/obj/effect/portal/created = create_portal_pair(get_turf(src), target_turf, src, 300, 1, /obj/effect/portal/anom)
|
||||||
P.target = target_turf
|
|
||||||
P.creator = null
|
|
||||||
P.icon = 'icons/obj/objects.dmi'
|
|
||||||
P.icon_state = "anom"
|
|
||||||
P.name = "wormhole"
|
|
||||||
P.mech_sized = TRUE
|
|
||||||
var/turf/T = get_turf(target)
|
var/turf/T = get_turf(target)
|
||||||
message_admins("[ADMIN_LOOKUPFLW(chassis.occupant)] used a Wormhole Generator in [ADMIN_COORDJMP(T)]",0,1)
|
message_admins("[ADMIN_LOOKUPFLW(chassis.occupant)] used a Wormhole Generator in [ADMIN_COORDJMP(T)]",0,1)
|
||||||
log_game("[key_name(chassis.occupant)] used a Wormhole Generator in [COORD(T)]")
|
log_game("[key_name(chassis.occupant)] used a Wormhole Generator in [COORD(T)]")
|
||||||
src = null
|
src = null
|
||||||
QDEL_IN(P, rand(150,300))
|
QDEL_LIST_IN(created, rand(150,300))
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,42 @@
|
|||||||
|
|
||||||
|
/proc/create_portal_pair(turf/source, turf/destination, _creator = null, _lifespan = 300, accuracy = 0, newtype = /obj/effect/portal)
|
||||||
|
if(!istype(source) || !istype(destination))
|
||||||
|
return
|
||||||
|
var/turf/actual_destination = get_teleport_turf(destination, accuracy)
|
||||||
|
var/obj/effect/portal/P1 = new newtype(source, _creator, _lifespan, null, FALSE)
|
||||||
|
var/obj/effect/portal/P2 = new newtype(actual_destination, _creator, _lifespan, P1, TRUE)
|
||||||
|
if(!istype(P1)||!istype(P2))
|
||||||
|
return
|
||||||
|
P1.link_portal(P2)
|
||||||
|
P1.hardlinked = TRUE
|
||||||
|
return list(P1, P2)
|
||||||
|
|
||||||
/obj/effect/portal
|
/obj/effect/portal
|
||||||
name = "portal"
|
name = "portal"
|
||||||
desc = "Looks unstable. Best to test it with the clown."
|
desc = "Looks unstable. Best to test it with the clown."
|
||||||
icon = 'icons/obj/stationobjs.dmi'
|
icon = 'icons/obj/stationobjs.dmi'
|
||||||
icon_state = "portal"
|
icon_state = "portal"
|
||||||
density = 1
|
anchored = TRUE
|
||||||
var/obj/item/target = null
|
|
||||||
var/creator = null
|
|
||||||
anchored = 1
|
|
||||||
var/precision = 1 // how close to the portal you will teleport. 0 = on the portal, 1 = adjacent
|
|
||||||
var/mech_sized = FALSE
|
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/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.
|
||||||
|
var/turf/open/atmos_source //Atmos link source
|
||||||
|
var/turf/open/atmos_destination //Atmos link destination
|
||||||
|
|
||||||
/obj/effect/portal/Bumped(mob/M as mob|obj)
|
/obj/effect/portal/anom
|
||||||
teleport(M)
|
name = "wormhole"
|
||||||
|
icon = 'icons/obj/objects.dmi'
|
||||||
|
icon_state = "anom"
|
||||||
|
mech_sized = TRUE
|
||||||
|
|
||||||
/obj/effect/portal/attack_tk(mob/user)
|
/obj/effect/portal/Move(newloc)
|
||||||
return
|
for(var/T in newloc)
|
||||||
|
if(istype(T, /obj/effect/portal))
|
||||||
/obj/effect/portal/attack_hand(mob/user)
|
return FALSE
|
||||||
if(Adjacent(user))
|
return ..()
|
||||||
teleport(user)
|
|
||||||
|
|
||||||
/obj/effect/portal/attackby(obj/item/weapon/W, mob/user, params)
|
/obj/effect/portal/attackby(obj/item/weapon/W, mob/user, params)
|
||||||
if(user && Adjacent(user))
|
if(user && Adjacent(user))
|
||||||
@@ -28,42 +45,113 @@
|
|||||||
/obj/effect/portal/make_frozen_visual()
|
/obj/effect/portal/make_frozen_visual()
|
||||||
return
|
return
|
||||||
|
|
||||||
/obj/effect/portal/New(loc, turf/target, creator=null, lifespan=300)
|
/obj/effect/portal/Crossed(atom/movable/AM, oldloc)
|
||||||
..()
|
if(get_turf(oldloc) == get_turf(linked))
|
||||||
|
return ..()
|
||||||
|
if(!teleport(AM))
|
||||||
|
return ..()
|
||||||
|
|
||||||
|
/obj/effect/portal/attack_tk(mob/user)
|
||||||
|
return
|
||||||
|
|
||||||
|
/obj/effect/portal/attack_hand(mob/user)
|
||||||
|
if(Adjacent(user))
|
||||||
|
teleport(user)
|
||||||
|
|
||||||
|
/obj/effect/portal/Initialize(mapload, _creator, _lifespan = 300, obj/effect/portal/_linked, automatic_link = TRUE, hard_target_override, atmos_link_override)
|
||||||
|
. = ..()
|
||||||
GLOB.portals += src
|
GLOB.portals += src
|
||||||
src.target = target
|
if(!istype(_linked) && automatic_link)
|
||||||
src.creator = creator
|
. = INITIALIZE_HINT_QDEL
|
||||||
|
CRASH("Somebody fucked up.")
|
||||||
|
if(_lifespan > 0)
|
||||||
|
QDEL_IN(src, _lifespan)
|
||||||
|
if(!isnull(atmos_link_override))
|
||||||
|
atmos_link = atmos_link_override
|
||||||
|
link_portal(_linked)
|
||||||
|
hardlinked = automatic_link
|
||||||
|
creator = _creator
|
||||||
|
|
||||||
var/area/A = get_area(target)
|
/obj/effect/portal/proc/link_portal(obj/effect/portal/newlink)
|
||||||
if(A && A.noteleport) // No point in persisting if the target is unreachable.
|
linked = newlink
|
||||||
qdel(src)
|
if(atmos_link)
|
||||||
return
|
link_atmos()
|
||||||
if(lifespan > 0)
|
|
||||||
QDEL_IN(src, lifespan)
|
|
||||||
|
|
||||||
/obj/effect/portal/Destroy()
|
/obj/effect/portal/proc/link_atmos()
|
||||||
GLOB.portals -= src
|
if(atmos_source || atmos_destination)
|
||||||
if(istype(creator, /obj/item/weapon/hand_tele))
|
unlink_atmos()
|
||||||
var/obj/item/weapon/hand_tele/O = creator
|
if(!isopenturf(get_turf(src)))
|
||||||
O.active_portals--
|
return FALSE
|
||||||
else if(istype(creator, /obj/item/weapon/gun/energy/wormhole_projector))
|
if(linked)
|
||||||
var/obj/item/weapon/gun/energy/wormhole_projector/P = creator
|
if(isopenturf(get_turf(linked)))
|
||||||
P.portal_destroyed(src)
|
atmos_source = get_turf(src)
|
||||||
|
atmos_destination = get_turf(linked)
|
||||||
|
else if(hard_target)
|
||||||
|
if(isopenturf(hard_target))
|
||||||
|
atmos_source = get_turf(src)
|
||||||
|
atmos_destination = hard_target
|
||||||
|
else
|
||||||
|
return FALSE
|
||||||
|
if(!istype(atmos_source) || !istype(atmos_destination))
|
||||||
|
return FALSE
|
||||||
|
LAZYINITLIST(atmos_source.atmos_adjacent_turfs)
|
||||||
|
LAZYINITLIST(atmos_destination.atmos_adjacent_turfs)
|
||||||
|
if(atmos_source.atmos_adjacent_turfs[atmos_destination] || atmos_destination.atmos_adjacent_turfs[atmos_source]) //Already linked!
|
||||||
|
return FALSE
|
||||||
|
atmos_source.atmos_adjacent_turfs[atmos_destination] = TRUE
|
||||||
|
atmos_destination.atmos_adjacent_turfs[atmos_source] = TRUE
|
||||||
|
atmos_source.air_update_turf(FALSE)
|
||||||
|
atmos_destination.air_update_turf(FALSE)
|
||||||
|
|
||||||
|
/obj/effect/portal/proc/unlink_atmos()
|
||||||
|
if(istype(atmos_source))
|
||||||
|
if(istype(atmos_destination) && !atmos_source.Adjacent(atmos_destination) && !CANATMOSPASS(atmos_destination, atmos_source))
|
||||||
|
LAZYREMOVE(atmos_source.atmos_adjacent_turfs, atmos_destination)
|
||||||
|
atmos_source = null
|
||||||
|
if(istype(atmos_destination))
|
||||||
|
if(istype(atmos_source) && !atmos_destination.Adjacent(atmos_source) && !CANATMOSPASS(atmos_source, atmos_destination))
|
||||||
|
LAZYREMOVE(atmos_destination.atmos_adjacent_turfs, atmos_source)
|
||||||
|
atmos_destination = null
|
||||||
|
|
||||||
|
/obj/effect/portal/Destroy() //Calls on_portal_destroy(destroyed portal, location of destroyed portal) on creator if creator has such call.
|
||||||
|
if(creator && hascall(creator, "on_portal_destroy"))
|
||||||
|
call(creator, "on_portal_destroy")(src, src.loc)
|
||||||
creator = null
|
creator = null
|
||||||
|
GLOB.portals -= src
|
||||||
|
unlink_atmos()
|
||||||
|
if(hardlinked && !QDELETED(linked))
|
||||||
|
QDEL_NULL(linked)
|
||||||
|
else
|
||||||
|
linked = null
|
||||||
return ..()
|
return ..()
|
||||||
|
|
||||||
/obj/effect/portal/proc/teleport(atom/movable/M as mob|obj)
|
/obj/effect/portal/proc/teleport(atom/movable/M)
|
||||||
if(istype(M, /obj/effect)) //sparks don't teleport
|
if(!istype(M) || istype(M, /obj/effect) || (istype(M, /obj/mecha) && !mech_sized) || (!isobj(M) && !ismob(M))) //Things that shouldn't teleport.
|
||||||
return
|
return
|
||||||
if(M.anchored)
|
var/turf/real_target = get_link_target_turf()
|
||||||
if(!(istype(M, /obj/mecha) && mech_sized))
|
if(!istype(real_target))
|
||||||
|
return FALSE
|
||||||
|
if(ismegafauna(M))
|
||||||
|
message_admins("[M] has used a portal at [ADMIN_COORDJMP(src)] made by [usr].")
|
||||||
|
if(do_teleport(M, real_target, 0))
|
||||||
|
if(istype(M, /obj/item/projectile))
|
||||||
|
var/obj/item/projectile/P = M
|
||||||
|
P.ignore_source_check = TRUE
|
||||||
|
return TRUE
|
||||||
|
return FALSE
|
||||||
|
|
||||||
|
/obj/effect/portal/proc/get_link_target_turf()
|
||||||
|
var/turf/real_target
|
||||||
|
if(!istype(linked) || QDELETED(linked))
|
||||||
|
if(hardlinked)
|
||||||
|
qdel(src)
|
||||||
|
if(!istype(hard_target) || QDELETED(hard_target))
|
||||||
|
hard_target = null
|
||||||
return
|
return
|
||||||
if (!( target ))
|
else
|
||||||
qdel(src)
|
real_target = hard_target
|
||||||
return
|
linked = null
|
||||||
if (istype(M, /atom/movable))
|
else
|
||||||
if(ismegafauna(M))
|
real_target = get_turf(linked)
|
||||||
message_admins("[M] [ADMIN_FLW(M)] has teleported through [src].")
|
return real_target
|
||||||
do_teleport(M, target, precision) ///You will appear adjacent to the beacon
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
|
||||||
|
#define SOURCE_PORTAL 1
|
||||||
|
#define DESTINATION_PORTAL 2
|
||||||
|
|
||||||
/* Teleportation devices.
|
/* Teleportation devices.
|
||||||
* Contains:
|
* Contains:
|
||||||
* Locator
|
* Locator
|
||||||
@@ -136,7 +140,19 @@ Frequency:
|
|||||||
origin_tech = "magnets=3;bluespace=4"
|
origin_tech = "magnets=3;bluespace=4"
|
||||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 30, bio = 0, rad = 0, fire = 100, acid = 100)
|
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 30, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||||
var/active_portals = 0
|
var/list/active_portal_pairs
|
||||||
|
var/max_portal_pairs = 3
|
||||||
|
|
||||||
|
/obj/item/weapon/hand_tele/Initialize()
|
||||||
|
. = ..()
|
||||||
|
active_portal_pairs = list()
|
||||||
|
|
||||||
|
/obj/item/weapon/hand_tele/afterattack(atom/target, mob/user, proximity, params)
|
||||||
|
if(is_parent_of_portal(target))
|
||||||
|
qdel(target)
|
||||||
|
to_chat(user, "<span class='notice'>You dispel [target] remotely with \the [src]!</span>")
|
||||||
|
return ..()
|
||||||
|
|
||||||
|
|
||||||
/obj/item/weapon/hand_tele/attack_self(mob/user)
|
/obj/item/weapon/hand_tele/attack_self(mob/user)
|
||||||
var/turf/current_location = get_turf(user)//What turf is the user on?
|
var/turf/current_location = get_turf(user)//What turf is the user on?
|
||||||
@@ -169,7 +185,7 @@ Frequency:
|
|||||||
var/t1 = input(user, "Please select a teleporter to lock in on.", "Hand Teleporter") as null|anything in L
|
var/t1 = input(user, "Please select a teleporter to lock in on.", "Hand Teleporter") as null|anything in L
|
||||||
if (!t1 || user.get_active_held_item() != src || user.incapacitated())
|
if (!t1 || user.get_active_held_item() != src || user.incapacitated())
|
||||||
return
|
return
|
||||||
if(active_portals >= 3)
|
if(active_portal_pairs.len >= max_portal_pairs)
|
||||||
user.show_message("<span class='notice'>\The [src] is recharging!</span>")
|
user.show_message("<span class='notice'>\The [src] is recharging!</span>")
|
||||||
return
|
return
|
||||||
var/atom/T = L[t1]
|
var/atom/T = L[t1]
|
||||||
@@ -178,7 +194,22 @@ Frequency:
|
|||||||
to_chat(user, "<span class='notice'>\The [src] is malfunctioning.</span>")
|
to_chat(user, "<span class='notice'>\The [src] is malfunctioning.</span>")
|
||||||
return
|
return
|
||||||
user.show_message("<span class='notice'>Locked In.</span>", 2)
|
user.show_message("<span class='notice'>Locked In.</span>", 2)
|
||||||
var/obj/effect/portal/P = new /obj/effect/portal(get_turf(src), T, src)
|
var/list/obj/effect/portal/created = create_portal_pair(current_location, get_teleport_turf(get_turf(T)), src, 300, 1)
|
||||||
try_move_adjacent(P)
|
if(!(LAZYLEN(created) == 2))
|
||||||
active_portals++
|
return
|
||||||
|
try_move_adjacent(created[1])
|
||||||
|
active_portal_pairs[created[1]] = created[2]
|
||||||
add_fingerprint(user)
|
add_fingerprint(user)
|
||||||
|
|
||||||
|
/obj/item/weapon/hand_tele/proc/on_portal_destroy(obj/effect/portal/P)
|
||||||
|
active_portal_pairs -= P //If this portal pair is made by us it'll be erased along with the other portal by the portal.
|
||||||
|
|
||||||
|
/obj/item/weapon/hand_tele/proc/is_parent_of_portal(obj/effect/portal/P)
|
||||||
|
if(!istype(P))
|
||||||
|
return FALSE
|
||||||
|
if(active_portal_pairs[P])
|
||||||
|
return SOURCE_PORTAL
|
||||||
|
for(var/i in active_portal_pairs)
|
||||||
|
if(active_portal_pairs[i] == P)
|
||||||
|
return DESTINATION_PORTAL
|
||||||
|
return FALSE
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
for(var/i = 1, i <= number_of_wormholes, i++)
|
for(var/i = 1, i <= number_of_wormholes, i++)
|
||||||
var/turf/T = pick(pick_turfs)
|
var/turf/T = pick(pick_turfs)
|
||||||
wormholes += new /obj/effect/portal/wormhole(T, null, null, -1)
|
wormholes += new /obj/effect/portal/wormhole(T, null, 300, null, FALSE)
|
||||||
|
|
||||||
/datum/round_event/wormholes/announce()
|
/datum/round_event/wormholes/announce()
|
||||||
priority_announce("Space-time anomalies detected on the station. There is no additional data.", "Anomaly Alert", 'sound/ai/spanomalies.ogg')
|
priority_announce("Space-time anomalies detected on the station. There is no additional data.", "Anomaly Alert", 'sound/ai/spanomalies.ogg')
|
||||||
@@ -36,14 +36,10 @@
|
|||||||
for(var/obj/effect/portal/wormhole/O in wormholes)
|
for(var/obj/effect/portal/wormhole/O in wormholes)
|
||||||
var/turf/T = pick(pick_turfs)
|
var/turf/T = pick(pick_turfs)
|
||||||
if(T)
|
if(T)
|
||||||
O.loc = T
|
O.forceMove(T)
|
||||||
|
|
||||||
/datum/round_event/wormholes/end()
|
/datum/round_event/wormholes/end()
|
||||||
GLOB.portals.Remove(wormholes)
|
QDEL_LIST(wormholes)
|
||||||
for(var/obj/effect/portal/wormhole/O in wormholes)
|
|
||||||
O.loc = null
|
|
||||||
wormholes.Cut()
|
|
||||||
|
|
||||||
|
|
||||||
/obj/effect/portal/wormhole
|
/obj/effect/portal/wormhole
|
||||||
name = "wormhole"
|
name = "wormhole"
|
||||||
@@ -70,7 +66,7 @@
|
|||||||
if(GLOB.portals.len)
|
if(GLOB.portals.len)
|
||||||
var/obj/effect/portal/P = pick(GLOB.portals)
|
var/obj/effect/portal/P = pick(GLOB.portals)
|
||||||
if(P && isturf(P.loc))
|
if(P && isturf(P.loc))
|
||||||
target = P.loc
|
hard_target = P.loc
|
||||||
if(!target)
|
if(!target)
|
||||||
return
|
return
|
||||||
do_teleport(M, target, 1, 1, 0, 0) ///You will appear adjacent to the beacon
|
do_teleport(M, hard_target, 1, 1, 0, 0) ///You will appear adjacent to the beacon
|
||||||
@@ -53,8 +53,7 @@
|
|||||||
to_chat(user, "<span class='notice'>The [src.name] found no beacons in the world to anchor a wormhole to.</span>")
|
to_chat(user, "<span class='notice'>The [src.name] found no beacons in the world to anchor a wormhole to.</span>")
|
||||||
return
|
return
|
||||||
var/chosen_beacon = pick(L)
|
var/chosen_beacon = pick(L)
|
||||||
var/obj/effect/portal/wormhole/jaunt_tunnel/J = new /obj/effect/portal/wormhole/jaunt_tunnel(get_turf(src), chosen_beacon, lifespan=100)
|
var/obj/effect/portal/wormhole/jaunt_tunnel/J = new /obj/effect/portal/wormhole/jaunt_tunnel(get_turf(src), src, lifespan=100, null, FALSE, get_turf(chosen_beacon))
|
||||||
J.target = chosen_beacon
|
|
||||||
try_move_adjacent(J)
|
try_move_adjacent(J)
|
||||||
playsound(src,'sound/effects/sparks4.ogg',50,1)
|
playsound(src,'sound/effects/sparks4.ogg',50,1)
|
||||||
qdel(src)
|
qdel(src)
|
||||||
@@ -98,7 +97,7 @@
|
|||||||
return
|
return
|
||||||
|
|
||||||
if(istype(M, /atom/movable))
|
if(istype(M, /atom/movable))
|
||||||
if(do_teleport(M, target, 6))
|
if(do_teleport(M, hard_target, 6))
|
||||||
// KERPLUNK
|
// KERPLUNK
|
||||||
playsound(M,'sound/weapons/resonator_blast.ogg',50,1)
|
playsound(M,'sound/weapons/resonator_blast.ogg',50,1)
|
||||||
if(iscarbon(M))
|
if(iscarbon(M))
|
||||||
|
|||||||
@@ -172,8 +172,8 @@
|
|||||||
item_state = null
|
item_state = null
|
||||||
icon_state = "wormhole_projector"
|
icon_state = "wormhole_projector"
|
||||||
origin_tech = "combat=4;bluespace=6;plasmatech=4;engineering=4"
|
origin_tech = "combat=4;bluespace=6;plasmatech=4;engineering=4"
|
||||||
var/obj/effect/portal/blue
|
var/obj/effect/portal/p_blue
|
||||||
var/obj/effect/portal/orange
|
var/obj/effect/portal/p_orange
|
||||||
|
|
||||||
/obj/item/weapon/gun/energy/wormhole_projector/update_icon()
|
/obj/item/weapon/gun/energy/wormhole_projector/update_icon()
|
||||||
icon_state = "[initial(icon_state)][select]"
|
icon_state = "[initial(icon_state)][select]"
|
||||||
@@ -184,30 +184,44 @@
|
|||||||
..()
|
..()
|
||||||
select_fire()
|
select_fire()
|
||||||
|
|
||||||
/obj/item/weapon/gun/energy/wormhole_projector/proc/portal_destroyed(obj/effect/portal/P)
|
/obj/item/weapon/gun/energy/wormhole_projector/proc/on_portal_destroy(obj/effect/portal/P)
|
||||||
if(P.icon_state == "portal")
|
if(P == p_blue)
|
||||||
blue = null
|
p_blue = null
|
||||||
if(orange)
|
else if(P == p_orange)
|
||||||
orange.target = null
|
p_orange = null
|
||||||
else
|
|
||||||
orange = null
|
|
||||||
if(blue)
|
|
||||||
blue.target = null
|
|
||||||
|
|
||||||
/obj/item/weapon/gun/energy/wormhole_projector/proc/create_portal(obj/item/projectile/beam/wormhole/W)
|
/obj/item/weapon/gun/energy/wormhole_projector/proc/has_blue_portal()
|
||||||
var/obj/effect/portal/P = new /obj/effect/portal(get_turf(W), null, src)
|
if(istype(p_blue) && !QDELETED(p_blue))
|
||||||
P.precision = 0
|
return TRUE
|
||||||
if(W.name == "bluespace beam")
|
return FALSE
|
||||||
qdel(blue)
|
|
||||||
blue = P
|
/obj/item/weapon/gun/energy/wormhole_projector/proc/has_orange_portal()
|
||||||
else
|
if(istype(p_orange) && !QDELETED(p_orange))
|
||||||
qdel(orange)
|
return TRUE
|
||||||
|
return FALSE
|
||||||
|
|
||||||
|
/obj/item/weapon/gun/energy/wormhole_projector/proc/crosslink()
|
||||||
|
if(!has_blue_portal() && !has_orange_portal())
|
||||||
|
return
|
||||||
|
if(!has_blue_portal() && has_orange_portal())
|
||||||
|
p_orange.link_portal(null)
|
||||||
|
return
|
||||||
|
if(!has_orange_portal() && has_blue_portal())
|
||||||
|
p_blue.link_portal(null)
|
||||||
|
return
|
||||||
|
p_orange.link_portal(p_blue)
|
||||||
|
p_blue.link_portal(p_orange)
|
||||||
|
|
||||||
|
/obj/item/weapon/gun/energy/wormhole_projector/proc/create_portal(obj/item/projectile/beam/wormhole/W, turf/target)
|
||||||
|
var/obj/effect/portal/P = new /obj/effect/portal(target, src, 300, null, FALSE, null)
|
||||||
|
if(istype(W, /obj/item/projectile/beam/wormhole/orange))
|
||||||
|
qdel(p_orange)
|
||||||
|
p_orange = P
|
||||||
P.icon_state = "portal1"
|
P.icon_state = "portal1"
|
||||||
orange = P
|
else
|
||||||
if(orange && blue)
|
qdel(p_blue)
|
||||||
blue.target = get_turf(orange)
|
p_blue = P
|
||||||
orange.target = get_turf(blue)
|
crosslink()
|
||||||
|
|
||||||
|
|
||||||
/* 3d printer 'pseudo guns' for borgs */
|
/* 3d printer 'pseudo guns' for borgs */
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
var/ricochets = 0
|
var/ricochets = 0
|
||||||
var/ricochets_max = 2
|
var/ricochets_max = 2
|
||||||
var/ricochet_chance = 30
|
var/ricochet_chance = 30
|
||||||
|
var/ignore_source_check = FALSE
|
||||||
|
|
||||||
var/damage = 10
|
var/damage = 10
|
||||||
var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE are the only things that should be in here
|
var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE are the only things that should be in here
|
||||||
@@ -138,8 +139,9 @@
|
|||||||
if(check_ricochet() && check_ricochet_flag(A) && ricochets < ricochets_max)
|
if(check_ricochet() && check_ricochet_flag(A) && ricochets < ricochets_max)
|
||||||
ricochets++
|
ricochets++
|
||||||
if(A.handle_ricochet(src))
|
if(A.handle_ricochet(src))
|
||||||
|
ignore_source_check = TRUE
|
||||||
return FALSE
|
return FALSE
|
||||||
if(firer && !ricochets)
|
if(firer && !ignore_source_check)
|
||||||
if(A == firer || (A == firer.loc && istype(A, /obj/mecha))) //cannot shoot yourself or your mech
|
if(A == firer || (A == firer.loc && istype(A, /obj/mecha))) //cannot shoot yourself or your mech
|
||||||
loc = A.loc
|
loc = A.loc
|
||||||
return FALSE
|
return FALSE
|
||||||
|
|||||||
@@ -183,7 +183,7 @@
|
|||||||
return ..()
|
return ..()
|
||||||
if(!gun)
|
if(!gun)
|
||||||
qdel(src)
|
qdel(src)
|
||||||
gun.create_portal(src)
|
gun.create_portal(src, get_turf(src))
|
||||||
|
|
||||||
/obj/item/projectile/bullet/frag12
|
/obj/item/projectile/bullet/frag12
|
||||||
name ="explosive slug"
|
name ="explosive slug"
|
||||||
|
|||||||
Reference in New Issue
Block a user