From d1108df80cc7ea5437447677f767e8211a4f2062 Mon Sep 17 00:00:00 2001 From: kevinz000 Date: Tue, 20 Jun 2017 08:02:01 -0700 Subject: [PATCH] [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 --- code/__HELPERS/unsorted.dm | 6 + code/_onclick/observer.dm | 4 +- code/datums/helper_datums/teleport.dm | 37 ++-- code/game/atoms_movable.dm | 5 +- .../game/mecha/equipment/tools/other_tools.dm | 10 +- code/game/objects/effects/portals.dm | 174 +++++++++++++----- .../objects/items/weapons/teleportation.dm | 41 ++++- code/modules/events/wormholes.dm | 14 +- .../mining/equipment/wormhole_jaunter.dm | 5 +- .../projectiles/guns/energy/special.dm | 62 ++++--- code/modules/projectiles/projectile.dm | 4 +- .../modules/projectiles/projectile/special.dm | 2 +- 12 files changed, 249 insertions(+), 115 deletions(-) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 04ca4db3688..ab07f2e6553 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -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_NULL(item) qdel(item); item = null #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_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() var/val = rand(0, 99999) var/str = "[val]" diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index 784b5e0ee1b..2580e335e1c 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -67,8 +67,8 @@ user.forceMove(get_turf(com.locked)) /obj/effect/portal/attack_ghost(mob/user) - if(target) - user.forceMove(get_turf(target)) + if(linked) + user.forceMove(get_turf(linked)) /obj/machinery/gateway/centerstation/attack_ghost(mob/user) if(awaygate) diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index 07ed28b575b..d6f679c3314 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -15,7 +15,6 @@ 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/proc/start(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null) if(!initTeleport(arglist(args))) return 0 @@ -100,21 +99,7 @@ var/turf/destturf var/turf/curturf = get_turf(teleatom) - if(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) + destturf = get_teleport_turf(get_turf(destination), precision) if(!destturf || !curturf || destturf.is_transition_turf()) return 0 @@ -124,13 +109,16 @@ return 0 playSpecials(curturf,effectin,soundin) - if(force_teleport) 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) else if(teleatom.Move(destturf)) 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 /datum/teleport/proc/teleport() @@ -225,3 +213,18 @@ // DING! You have passed the gauntlet, and are "probably" safe. 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)) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 6a61416366e..e8aa62ed85c 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -213,7 +213,8 @@ // Previously known as HasEntered() // 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 /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) if(AM == src) continue - AM.Crossed(src) + AM.Crossed(src, oldloc) Moved(oldloc, 0) return 1 diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm index 6074fc932e8..089cfdf6254 100644 --- a/code/game/mecha/equipment/tools/other_tools.dm +++ b/code/game/mecha/equipment/tools/other_tools.dm @@ -57,18 +57,12 @@ var/turf/target_turf = pick(L) if(!target_turf) return - var/obj/effect/portal/P = new /obj/effect/portal(get_turf(target)) - 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/list/obj/effect/portal/created = create_portal_pair(get_turf(src), target_turf, src, 300, 1, /obj/effect/portal/anom) var/turf/T = get_turf(target) 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)]") src = null - QDEL_IN(P, rand(150,300)) + QDEL_LIST_IN(created, rand(150,300)) return 1 diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index 9e7dbe7fa9d..74556098373 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -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 name = "portal" desc = "Looks unstable. Best to test it with the clown." icon = 'icons/obj/stationobjs.dmi' icon_state = "portal" - density = 1 - 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 + anchored = TRUE 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) - teleport(M) +/obj/effect/portal/anom + name = "wormhole" + icon = 'icons/obj/objects.dmi' + icon_state = "anom" + mech_sized = TRUE -/obj/effect/portal/attack_tk(mob/user) - return - -/obj/effect/portal/attack_hand(mob/user) - if(Adjacent(user)) - teleport(user) +/obj/effect/portal/Move(newloc) + for(var/T in newloc) + if(istype(T, /obj/effect/portal)) + return FALSE + return ..() /obj/effect/portal/attackby(obj/item/weapon/W, mob/user, params) if(user && Adjacent(user)) @@ -28,42 +45,113 @@ /obj/effect/portal/make_frozen_visual() 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 - src.target = target - src.creator = creator + if(!istype(_linked) && automatic_link) + . = 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) - if(A && A.noteleport) // No point in persisting if the target is unreachable. - qdel(src) - return - if(lifespan > 0) - QDEL_IN(src, lifespan) +/obj/effect/portal/proc/link_portal(obj/effect/portal/newlink) + linked = newlink + if(atmos_link) + link_atmos() -/obj/effect/portal/Destroy() - GLOB.portals -= src - if(istype(creator, /obj/item/weapon/hand_tele)) - var/obj/item/weapon/hand_tele/O = creator - O.active_portals-- - else if(istype(creator, /obj/item/weapon/gun/energy/wormhole_projector)) - var/obj/item/weapon/gun/energy/wormhole_projector/P = creator - P.portal_destroyed(src) +/obj/effect/portal/proc/link_atmos() + if(atmos_source || atmos_destination) + unlink_atmos() + if(!isopenturf(get_turf(src))) + return FALSE + if(linked) + if(isopenturf(get_turf(linked))) + 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 + GLOB.portals -= src + unlink_atmos() + if(hardlinked && !QDELETED(linked)) + QDEL_NULL(linked) + else + linked = null return ..() -/obj/effect/portal/proc/teleport(atom/movable/M as mob|obj) - if(istype(M, /obj/effect)) //sparks don't teleport +/obj/effect/portal/proc/teleport(atom/movable/M) + if(!istype(M) || istype(M, /obj/effect) || (istype(M, /obj/mecha) && !mech_sized) || (!isobj(M) && !ismob(M))) //Things that shouldn't teleport. return - if(M.anchored) - if(!(istype(M, /obj/mecha) && mech_sized)) + var/turf/real_target = get_link_target_turf() + 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 - if (!( target )) - qdel(src) - return - if (istype(M, /atom/movable)) - if(ismegafauna(M)) - message_admins("[M] [ADMIN_FLW(M)] has teleported through [src].") - do_teleport(M, target, precision) ///You will appear adjacent to the beacon - + else + real_target = hard_target + linked = null + else + real_target = get_turf(linked) + return real_target diff --git a/code/game/objects/items/weapons/teleportation.dm b/code/game/objects/items/weapons/teleportation.dm index 87254406ffa..ecdf443b63d 100644 --- a/code/game/objects/items/weapons/teleportation.dm +++ b/code/game/objects/items/weapons/teleportation.dm @@ -1,3 +1,7 @@ + +#define SOURCE_PORTAL 1 +#define DESTINATION_PORTAL 2 + /* Teleportation devices. * Contains: * Locator @@ -136,7 +140,19 @@ Frequency: 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) 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, "You dispel [target] remotely with \the [src]!") + return ..() + /obj/item/weapon/hand_tele/attack_self(mob/user) 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 if (!t1 || user.get_active_held_item() != src || user.incapacitated()) return - if(active_portals >= 3) + if(active_portal_pairs.len >= max_portal_pairs) user.show_message("\The [src] is recharging!") return var/atom/T = L[t1] @@ -178,7 +194,22 @@ Frequency: to_chat(user, "\The [src] is malfunctioning.") return user.show_message("Locked In.", 2) - var/obj/effect/portal/P = new /obj/effect/portal(get_turf(src), T, src) - try_move_adjacent(P) - active_portals++ + var/list/obj/effect/portal/created = create_portal_pair(current_location, get_teleport_turf(get_turf(T)), src, 300, 1) + if(!(LAZYLEN(created) == 2)) + return + try_move_adjacent(created[1]) + active_portal_pairs[created[1]] = created[2] 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 diff --git a/code/modules/events/wormholes.dm b/code/modules/events/wormholes.dm index f0c8b02ffff..09dc1b802dc 100644 --- a/code/modules/events/wormholes.dm +++ b/code/modules/events/wormholes.dm @@ -26,7 +26,7 @@ for(var/i = 1, i <= number_of_wormholes, i++) 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() 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) var/turf/T = pick(pick_turfs) if(T) - O.loc = T + O.forceMove(T) /datum/round_event/wormholes/end() - GLOB.portals.Remove(wormholes) - for(var/obj/effect/portal/wormhole/O in wormholes) - O.loc = null - wormholes.Cut() - + QDEL_LIST(wormholes) /obj/effect/portal/wormhole name = "wormhole" @@ -70,7 +66,7 @@ if(GLOB.portals.len) var/obj/effect/portal/P = pick(GLOB.portals) if(P && isturf(P.loc)) - target = P.loc + hard_target = P.loc if(!target) return - do_teleport(M, target, 1, 1, 0, 0) ///You will appear adjacent to the beacon \ No newline at end of file + do_teleport(M, hard_target, 1, 1, 0, 0) ///You will appear adjacent to the beacon \ No newline at end of file diff --git a/code/modules/mining/equipment/wormhole_jaunter.dm b/code/modules/mining/equipment/wormhole_jaunter.dm index 3596125a2d6..59cb393c574 100644 --- a/code/modules/mining/equipment/wormhole_jaunter.dm +++ b/code/modules/mining/equipment/wormhole_jaunter.dm @@ -53,8 +53,7 @@ to_chat(user, "The [src.name] found no beacons in the world to anchor a wormhole to.") return 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) - J.target = chosen_beacon + 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)) try_move_adjacent(J) playsound(src,'sound/effects/sparks4.ogg',50,1) qdel(src) @@ -98,7 +97,7 @@ return if(istype(M, /atom/movable)) - if(do_teleport(M, target, 6)) + if(do_teleport(M, hard_target, 6)) // KERPLUNK playsound(M,'sound/weapons/resonator_blast.ogg',50,1) if(iscarbon(M)) diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 40c834ec1df..3c4d749678f 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -172,8 +172,8 @@ item_state = null icon_state = "wormhole_projector" origin_tech = "combat=4;bluespace=6;plasmatech=4;engineering=4" - var/obj/effect/portal/blue - var/obj/effect/portal/orange + var/obj/effect/portal/p_blue + var/obj/effect/portal/p_orange /obj/item/weapon/gun/energy/wormhole_projector/update_icon() icon_state = "[initial(icon_state)][select]" @@ -184,30 +184,44 @@ ..() select_fire() -/obj/item/weapon/gun/energy/wormhole_projector/proc/portal_destroyed(obj/effect/portal/P) - if(P.icon_state == "portal") - blue = null - if(orange) - orange.target = null - else - orange = null - if(blue) - blue.target = null +/obj/item/weapon/gun/energy/wormhole_projector/proc/on_portal_destroy(obj/effect/portal/P) + if(P == p_blue) + p_blue = null + else if(P == p_orange) + p_orange = null -/obj/item/weapon/gun/energy/wormhole_projector/proc/create_portal(obj/item/projectile/beam/wormhole/W) - var/obj/effect/portal/P = new /obj/effect/portal(get_turf(W), null, src) - P.precision = 0 - if(W.name == "bluespace beam") - qdel(blue) - blue = P - else - qdel(orange) +/obj/item/weapon/gun/energy/wormhole_projector/proc/has_blue_portal() + if(istype(p_blue) && !QDELETED(p_blue)) + return TRUE + return FALSE + +/obj/item/weapon/gun/energy/wormhole_projector/proc/has_orange_portal() + if(istype(p_orange) && !QDELETED(p_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" - orange = P - if(orange && blue) - blue.target = get_turf(orange) - orange.target = get_turf(blue) - + else + qdel(p_blue) + p_blue = P + crosslink() /* 3d printer 'pseudo guns' for borgs */ diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index b90129d9028..74d5018ed13 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -31,6 +31,7 @@ var/ricochets = 0 var/ricochets_max = 2 var/ricochet_chance = 30 + var/ignore_source_check = FALSE var/damage = 10 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) ricochets++ if(A.handle_ricochet(src)) + ignore_source_check = TRUE 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 loc = A.loc return FALSE diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm index 74a889c9fd9..1b00881106e 100644 --- a/code/modules/projectiles/projectile/special.dm +++ b/code/modules/projectiles/projectile/special.dm @@ -183,7 +183,7 @@ return ..() if(!gun) qdel(src) - gun.create_portal(src) + gun.create_portal(src, get_turf(src)) /obj/item/projectile/bullet/frag12 name ="explosive slug"