diff --git a/code/_helpers/game.dm b/code/_helpers/game.dm index 3179e933e39..904a07a876b 100644 --- a/code/_helpers/game.dm +++ b/code/_helpers/game.dm @@ -90,8 +90,9 @@ return dist /proc/circlerangeturfs(center=usr,radius=3) - var/turf/centerturf = get_turf(center) + if(radius == 1) + return list(centerturf) var/list/turfs = new/list() var/rsq = radius * (radius+0.5) diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index 90415738e2b..b273a698a83 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -1,7 +1,6 @@ //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 diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index 50e258f2a7a..9a7760bf224 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -1,6 +1,6 @@ /obj/effect/portal name = "portal" - desc = "Looks unstable. Best to test it carefully." + desc = "A bluespace tear in space, reaching directly to another point within this region. Looks unstable. Best to test it carefully." icon = 'icons/obj/stationobjs.dmi' icon_state = "portal" density = TRUE @@ -8,61 +8,69 @@ var/does_teleport = TRUE // Some portals might just be visual var/has_lifespan = TRUE // Whether we want to directly control the lifespan or not var/failchance = 5 + var/has_failed = FALSE var/obj/target var/creator - var/precision = TRUE + var/precision = 1 anchored = TRUE -/obj/effect/portal/CollidedWith(mob/M as mob|obj) - set waitfor = FALSE - - if(does_teleport) - src.teleport(M) - -/obj/effect/portal/Crossed(AM as mob|obj) - set waitfor = FALSE - - if(does_teleport) - src.teleport(AM) - -/obj/effect/portal/attack_hand(mob/user as mob) - set waitfor = FALSE - - if(does_teleport) - src.teleport(user) - -/obj/effect/portal/New(loc, turf/target, creator=null, lifespan=300, precise = 1) - ..() - if(target) - src.target = target - if(creator) - src.creator = creator +/obj/effect/portal/Initialize(mapload, turf/set_target, set_creator, lifespan = 300, precise = 1) + . = ..() + if(set_target) + target = set_target + if(set_creator) + creator = set_creator if(has_lifespan && lifespan > 0) QDEL_IN(src, lifespan) + if(prob(failchance)) + has_failed = TRUE precision = precise -/obj/effect/portal/proc/teleport(atom/movable/M as mob|obj) +/obj/effect/portal/CollidedWith(mob/M) + set waitfor = FALSE + + if(does_teleport) + teleport(M) + +/obj/effect/portal/Crossed(AM) + set waitfor = FALSE + + if(does_teleport) + teleport(AM) + +/obj/effect/portal/attack_hand(mob/user) + set waitfor = FALSE + + if(does_teleport) + teleport(user) + +/obj/effect/portal/proc/teleport(atom/movable/M) if(!does_teleport) // just to be safe return if(istype(M, /obj/effect)) //sparks don't teleport return - if (icon_state == "portal1") - return - if (!( target )) + if(!target) qdel(src) return - if (istype(M, /atom/movable)) - if(prob(failchance)) //oh dear a problem, put em in deep space - src.icon_state = "portal1" + if(istype(M, /atom/movable)) + if(has_failed) //oh dear a problem, put em in deep space + icon_state = "portal1" // only tell people the portal failed after a teleport has been done + desc = "A bluespace tear in space, reaching directly to another point within this region. Definitely unstable." do_teleport(M, locate(rand(5, world.maxx - 5), rand(5, world.maxy -5), 3), 0) else do_teleport(M, target, precision) +/obj/effect/portal/Destroy() + if(istype(creator, /obj/item/hand_tele)) + var/obj/item/hand_tele/HT = creator + HT.remove_portal(src) + return ..() + /obj/effect/portal/spawner name = "portal" - desc = "Looks like a one-way portal, don't come too close." + desc = "A bluespace tear in space, reaching directly to another point within this region. This one looks like a one-way portal to here, don't come too close." desc_info = "This portal is a spawner portal. You cannot enter it to teleport, but it will periodically spawn things." does_teleport = FALSE has_lifespan = FALSE diff --git a/code/game/objects/items/weapons/syndie.dm b/code/game/objects/items/weapons/syndie.dm index 14cc47d182b..160e1eec5e4 100644 --- a/code/game/objects/items/weapons/syndie.dm +++ b/code/game/objects/items/weapons/syndie.dm @@ -164,4 +164,4 @@ /obj/item/syndie/teleporter/pickup() ..() - addtimer(CALLBACK(src, .proc/check_maptext), 1) + addtimer(CALLBACK(src, .proc/check_maptext), 1) // invoke async does not work here diff --git a/code/game/objects/items/weapons/teleportation.dm b/code/game/objects/items/weapons/teleportation.dm index e0c19e49e07..2eba0834109 100644 --- a/code/game/objects/items/weapons/teleportation.dm +++ b/code/game/objects/items/weapons/teleportation.dm @@ -125,7 +125,7 @@ Frequency: */ /obj/item/hand_tele name = "hand tele" - desc = "A portable item using blue-space technology." + desc = "A hand-held bluespace teleporter that can rip open portals to a random nearby location, or lock onto a teleporter with a selected teleportation beacon." icon = 'icons/obj/device.dmi' icon_state = "hand_tele" item_state = "electronic" @@ -135,62 +135,85 @@ Frequency: throw_range = 5 origin_tech = list(TECH_MAGNET = 1, TECH_BLUESPACE = 3) matter = list(DEFAULT_WALL_MATERIAL = 10000) + var/list/active_teleporters = list() + var/held_maptext = "Ready" -/obj/item/hand_tele/attack_self(mob/user as mob) +/obj/item/hand_tele/Initialize() + . = ..() + if(ismob(loc) || ismob(loc.loc)) + maptext = held_maptext + +/obj/item/hand_tele/attack_self(mob/user) var/turf/current_location = get_turf(user)//What turf is the user on? - if(!current_location||current_location.z==2||current_location.z>=7)//If turf was not found or they're on z level 2 or >7 which does not currently exist. - to_chat(user, "\The [src] is malfunctioning.") + if(!current_location || isNotStationLevel(current_location.z)) + to_chat(user, SPAN_WARNING("\The [src] can't get a bearing on anything right now.")) return - var/list/L = list( ) + + var/list/teleport_options = list() for(var/obj/machinery/teleport/hub/R in SSmachinery.all_machines) - var/obj/machinery/computer/teleporter/com = locate(/obj/machinery/computer/teleporter, locate(R.x - 2, R.y, R.z)) - if (istype(com, /obj/machinery/computer/teleporter) && com.locked && !com.one_time_use) + var/obj/machinery/computer/teleporter/com = R.com + if(com?.locked && !com.one_time_use) if(R.icon_state == "tele1") - L["[com.id] (Active)"] = com.locked + teleport_options["[com.id] (Active)"] = com.locked else - L["[com.id] (Inactive)"] = com.locked - var/list/turfs = list( ) + teleport_options["[com.id] (Inactive)"] = com.locked + var/list/potential_turfs = list() for(var/turf/T in orange(10)) - if(T.x>world.maxx-8 || T.x<8) + if(T.x > world.maxx-8 || T.x < 8) continue //putting them at the edge is dumb - - if(T.y>world.maxy-8 || T.y<8) + if(T.y > world.maxy-8 || T.y < 8) continue - - if(T.density) + if(T.density || turf_contains_dense_objects(T)) continue + potential_turfs += T - var/breakcheck = 0 - for(var/atom/movable/A in T) - if(A.density && A.opacity && A.anchored) - breakcheck = 1 - break + if(length(potential_turfs)) + teleport_options["None (Dangerous)"] = pick(potential_turfs) - if(breakcheck) - continue - - turfs += T - - if(turfs.len) - L["None (Dangerous)"] = pick(turfs) - var/t1 = input(user, "Please select a teleporter to lock in on.", "Hand Teleporter") in L - if ((user.get_active_hand() != src || user.stat || user.restrained())) + var/teleport_choice = input(user, "Please select a teleporter to lock in on.", "Hand Teleporter") as null|anything in teleport_options + if(!teleport_choice || user.get_active_hand() != src || use_check_and_message(user)) return - var/count = 0 //num of portals from this teleport in world - for(var/obj/effect/portal/PO in world) - if(PO.creator == src) count++ - if(count >= 3) - user.show_message("\The [src] is recharging!") + + if(length(active_teleporters) >= 3) + user.show_message(SPAN_WARNING("\The [src] is recharging!")) return - var/T = L[t1] - for(var/mob/O in hearers(user, null)) - O.show_message("Locked In.", 2) - var/obj/effect/portal/P = new /obj/effect/portal( get_turf(src) ) - P.target = T - P.creator = src - src.add_fingerprint(user) - return + + var/T = teleport_options[teleport_choice] + audible_message(SPAN_NOTICE("Locked in."), hearing_distance = 3) + var/obj/effect/portal/P = new /obj/effect/portal(get_turf(src), T, src) + active_teleporters += P + if(length(active_teleporters) >= 3) + check_maptext("Charge") + add_fingerprint(user) + +/obj/item/hand_tele/proc/remove_portal(var/obj/effect/portal/P) + active_teleporters -= P + if(length(active_teleporters) < 3) + check_maptext("Ready") + +/obj/item/hand_tele/proc/check_maptext(var/new_maptext) + if(new_maptext) + held_maptext = new_maptext + if(ismob(loc) || ismob(loc.loc)) + maptext = held_maptext + else + maptext = "" + +/obj/item/hand_tele/throw_at() + ..() + check_maptext() + +/obj/item/hand_tele/dropped() + ..() + check_maptext() + +/obj/item/hand_tele/on_give() + check_maptext() + +/obj/item/hand_tele/pickup() + ..() + addtimer(CALLBACK(src, .proc/check_maptext), 1) // invoke async does not work here /obj/item/closet_teleporter name = "closet teleporter" diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index 6550ceb8675..79cd9cb751c 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -744,7 +744,7 @@ to_chat(user, SPAN_NOTICE("\The [src] 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) + var/obj/effect/portal/wormhole/jaunt_tunnel/J = new /obj/effect/portal/wormhole/jaunt_tunnel(get_turf(src), chosen_beacon, null, 100) J.target = chosen_beacon playsound(src,'sound/effects/sparks4.ogg', 50, 1) qdel(src) diff --git a/html/changelogs/geeves-teleport_safety.yml b/html/changelogs/geeves-teleport_safety.yml new file mode 100644 index 00000000000..1a9d3bdce97 --- /dev/null +++ b/html/changelogs/geeves-teleport_safety.yml @@ -0,0 +1,8 @@ +author: Geeves + +delete-after: True + +changes: + - rscadd: "Hand-teleporters have been made safer to use, they no longer teleport you in a radius around a beacon, but on top of it." + - rscadd: "Hand-teles now have a text based indicator that shows you when it's ready for use." + - tweak: "Portals no longer have a random chance of failing per teleport, but have a random chance of starting destabilized. It will only be visually apparent after the first teleport."