diff --git a/code/__defines/_planes+layers.dm b/code/__defines/_planes+layers.dm
index 1a9c201ff6..a8e3951a3e 100644
--- a/code/__defines/_planes+layers.dm
+++ b/code/__defines/_planes+layers.dm
@@ -56,7 +56,6 @@ What is the naming convention for planes or layers?
#define OVER_OPENSPACE_PLANE -57
// Turf Planes
-#define SPACE_PLANE -82 // Space turfs themselves
#define PLATING_PLANE -44 // Plating
#define DISPOSAL_LAYER 2.1 // Under objects, even when planeswapped
#define PIPES_LAYER 2.2 // Under objects, even when planeswapped
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index f526a10d59..2ca0825c64 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -2,7 +2,7 @@
// Turf-only flags.
#define NOJAUNT 1 // This is used in literally one place, turf.dm, to block ethereal jaunt.
-#define TRANSITIONEDGE 7 // Distance from edge to move to another z-level.
+#define TRANSITIONEDGE 1 // Distance from edge to move to another z-level.
// Invisibility constants. These should only be used for TRUE invisibility, AKA nothing living players touch
#define INVISIBILITY_LIGHTING 20
diff --git a/code/controllers/subsystems/skybox.dm b/code/controllers/subsystems/skybox.dm
index 29529d3f7d..6f96830c56 100644
--- a/code/controllers/subsystems/skybox.dm
+++ b/code/controllers/subsystems/skybox.dm
@@ -4,12 +4,13 @@ SUBSYSTEM_DEF(skybox)
name = "Space skybox"
init_order = INIT_ORDER_SKYBOX
flags = SS_NO_FIRE
- var/list/skybox_cache = list()
+ var/static/list/skybox_cache = list()
- var/list/dust_cache = list()
- var/list/speedspace_cache = list()
- var/list/phase_shift_by_x = list()
- var/list/phase_shift_by_y = list()
+ var/static/list/dust_cache = list()
+ var/static/list/speedspace_cache = list()
+ var/static/list/mapedge_cache = list()
+ var/static/list/phase_shift_by_x = list()
+ var/static/list/phase_shift_by_y = list()
/datum/controller/subsystem/skybox/PreInit()
//Static
@@ -31,6 +32,29 @@ SUBSYSTEM_DEF(skybox)
im.plane = DUST_PLANE
im.blend_mode = BLEND_ADD
speedspace_cache["EW_[i]"] = im
+ //Over-the-edge images
+ for (var/dir in alldirs)
+ var/image/I = image('icons/turf/space.dmi', "white")
+ var/matrix/M = matrix()
+ var/horizontal = (dir & (WEST|EAST))
+ var/vertical = (dir & (NORTH|SOUTH))
+ M.Scale(horizontal ? 8 : 1, vertical ? 8 : 1)
+ I.transform = M
+ I.appearance_flags = KEEP_APART | TILE_BOUND
+ I.plane = SPACE_PLANE
+ I.layer = 0
+
+ if(dir & NORTH)
+ I.pixel_y = 112
+ else if(dir & SOUTH)
+ I.pixel_y = -112
+
+ if(dir & EAST)
+ I.pixel_x = 112
+ else if(dir & WEST)
+ I.pixel_x = -112
+
+ mapedge_cache["[dir]"] = I
//Shuffle some lists
phase_shift_by_x = get_cross_shift_list(15)
@@ -41,9 +65,6 @@ SUBSYSTEM_DEF(skybox)
/datum/controller/subsystem/skybox/Initialize()
. = ..()
-/datum/controller/subsystem/skybox/Recover()
- skybox_cache = SSskybox.skybox_cache
-
/datum/controller/subsystem/skybox/proc/get_skybox(z)
if(!skybox_cache["[z]"])
skybox_cache["[z]"] = generate_skybox(z)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 75e406da85..83166f8c0d 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -455,30 +455,33 @@
var/move_to_z = src.get_transit_zlevel()
if(move_to_z)
- z = move_to_z
+ var/new_z = move_to_z
+ var/new_x
+ var/new_y
if(x <= TRANSITIONEDGE)
- x = world.maxx - TRANSITIONEDGE - 2
- y = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2)
+ new_x = world.maxx - TRANSITIONEDGE - 2
+ new_y = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2)
else if (x >= (world.maxx - TRANSITIONEDGE + 1))
- x = TRANSITIONEDGE + 1
- y = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2)
+ new_x = TRANSITIONEDGE + 1
+ new_y = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2)
else if (y <= TRANSITIONEDGE)
- y = world.maxy - TRANSITIONEDGE -2
- x = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2)
+ new_y = world.maxy - TRANSITIONEDGE -2
+ new_x = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2)
else if (y >= (world.maxy - TRANSITIONEDGE + 1))
- y = TRANSITIONEDGE + 1
- x = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2)
+ new_y = TRANSITIONEDGE + 1
+ new_x = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2)
if(ticker && istype(ticker.mode, /datum/game_mode/nuclear)) //only really care if the game mode is nuclear
var/datum/game_mode/nuclear/G = ticker.mode
G.check_nuke_disks()
- spawn(0)
- if(loc) loc.Entered(src)
+ var/turf/T = locate(new_x, new_y, new_z)
+ if(istype(T))
+ forceMove(T)
//by default, transition randomly to another zlevel
/atom/movable/proc/get_transit_zlevel()
diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm
index 8169b64ad9..e2ca7f36f6 100644
--- a/code/game/turfs/space/space.dm
+++ b/code/game/turfs/space/space.dm
@@ -9,21 +9,23 @@
thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT
can_build_into_floor = TRUE
var/keep_sprite = FALSE
+ var/edge = 0
/turf/space/Initialize()
. = ..()
-
+
if(!keep_sprite)
icon_state = "white"
-
+
if(config.starlight)
update_starlight()
-
+
+ build_overedge() //Spread out over the edge of the map if we're an edge
toggle_transit() //Add static dust (not passing a dir)
/turf/space/proc/toggle_transit(var/direction)
cut_overlays()
-
+
if(!direction)
add_overlay(SSskybox.dust_cache["[((x + y) ^ ~(x * y) + z) % 25]"])
return
@@ -36,7 +38,7 @@
var/y_shift = SSskybox.phase_shift_by_y[src.y % (SSskybox.phase_shift_by_y.len - 1) + 1]
var/transit_state = ((direction & WEST ? world.maxx - src.x : src.x) + y_shift)%15
add_overlay(SSskybox.speedspace_cache["EW_[transit_state]"])
-
+
for(var/atom/movable/AM in src)
if (!AM.simulated)
continue
@@ -46,6 +48,22 @@
else if (istype(AM, /obj/effect))
qdel(AM) //No more space blood coming with the shuttle
+/turf/space/proc/build_overedge(var/forced_dirs)
+ if(y == world.maxy || forced_dirs & NORTH)
+ edge |= NORTH
+ else if(y == 1 || forced_dirs & SOUTH)
+ edge |= SOUTH
+
+ if(x == 1 || forced_dirs & WEST)
+ edge |= WEST
+ else if(x == world.maxx || forced_dirs & EAST)
+ edge |= EAST
+
+ if(!edge)
+ return
+
+ add_overlay(SSskybox.mapedge_cache["[edge]"], TRUE)
+
/turf/space/is_space()
return 1
@@ -117,24 +135,16 @@
// If that's changed, then you'll want to swipe the rest of the roofing code from code/game/turfs/simulated/floor_attackby.dm
return
-
-// Ported from unstable r355
-
-/turf/space/Entered(atom/movable/A as mob|obj)
- if(movement_disabled)
- to_chat(usr, "Movement is admin-disabled.") //This is to identify lag problems
- return
+/turf/space/Entered(var/atom/movable/A)
..()
- if ((!(A) || src != A.loc)) return
+
+ if (!A || src != A.loc)
+ return
inertial_drift(A)
- if(ticker && ticker.mode)
-
- // Okay, so let's make it so that people can travel z levels but not nuke disks!
- // if(ticker.mode.name == "mercenary") return
- if (A.x <= TRANSITIONEDGE || A.x >= (world.maxx - TRANSITIONEDGE + 1) || A.y <= TRANSITIONEDGE || A.y >= (world.maxy - TRANSITIONEDGE + 1))
- A.touch_map_edge()
+ if(edge && ticker?.mode)
+ A.touch_map_edge()
/turf/space/proc/Sandbox_Spacemove(atom/movable/A as mob|obj)
var/cur_x
diff --git a/code/modules/overmap/sectors.dm b/code/modules/overmap/sectors.dm
index 868de4d934..f437874609 100644
--- a/code/modules/overmap/sectors.dm
+++ b/code/modules/overmap/sectors.dm
@@ -74,6 +74,12 @@
global.using_map.contact_levels |= map_z
global.using_map.map_levels |= map_z
+/obj/effect/overmap/visitable/proc/get_space_zlevels()
+ if(in_space)
+ return map_z
+ else
+ return list()
+
//Helper for init.
/obj/effect/overmap/visitable/proc/check_ownership(obj/object)
if((object.z in map_z) && !(get_area(object) in SSshuttles.shuttle_areas))
diff --git a/code/modules/overmap/spacetravel.dm b/code/modules/overmap/spacetravel.dm
index 22de00d612..adb7e80269 100644
--- a/code/modules/overmap/spacetravel.dm
+++ b/code/modules/overmap/spacetravel.dm
@@ -96,10 +96,10 @@ proc/overmap_spacetravel(var/turf/space/T, var/atom/movable/A)
break
if(!TM)
TM = get_deepspace(M.x,M.y)
- nz = pick(TM.map_z)
+ nz = pick(TM.get_space_zlevels())
var/turf/dest = locate(nx,ny,nz)
- if(dest)
+ if(istype(dest))
A.forceMove(dest)
if(ismob(A))
var/mob/D = A
@@ -110,5 +110,5 @@ proc/overmap_spacetravel(var/turf/space/T, var/atom/movable/A)
var/obj/effect/overmap/visitable/sector/temporary/source = M
if (source.can_die())
testing("Caching [M] for future use")
- source.forceMove(null)
+ source.loc = null
cached_space += source
diff --git a/icons/turf/space.dmi b/icons/turf/space.dmi
index 361dd4d180..0263b8cb3c 100644
Binary files a/icons/turf/space.dmi and b/icons/turf/space.dmi differ
diff --git a/maps/submaps/_helpers.dm b/maps/submaps/_helpers.dm
new file mode 100644
index 0000000000..f3c79a7105
--- /dev/null
+++ b/maps/submaps/_helpers.dm
@@ -0,0 +1,124 @@
+//Acts like the map edge, can use this to divide up zlevels into 'fake' multiz areas.
+//Keep in mind that the entire zlevel 'moves' when the ship does, so don't try to make DIFFERENT ships share a zlevel.
+/turf/space/internal_edge
+ icon_state = "arrow"
+ opacity = 1
+ blocks_air = TRUE
+
+/turf/space/internal_edge/Initialize()
+ . = ..()
+ build_overedge(dir)
+
+/turf/space/internal_edge/top
+ dir = NORTH
+/turf/space/internal_edge/bottom
+ dir = SOUTH
+/turf/space/internal_edge/left
+ dir = WEST
+/turf/space/internal_edge/right
+ dir = EAST
+/turf/space/internal_edge/topleft
+ dir = NORTHWEST
+/turf/space/internal_edge/topright
+ dir = NORTHEAST
+/turf/space/internal_edge/bottomleft
+ dir = SOUTHWEST
+/turf/space/internal_edge/bottomright
+ dir = SOUTHEAST
+
+//These are fake stairs, that when you try to go up them, they shove you to
+// their 'connected' friend! Try to use the appropriate top/bottom ones for good looks.
+/obj/structure/fake_stairs
+ name = "use a subtype! - stairs"
+ icon = 'icons/obj/stairs.dmi'
+ density = 1
+ opacity = 0
+ anchored = 1
+ plane = TURF_PLANE
+ layer = ABOVE_TURF_LAYER
+ appearance_flags = PIXEL_SCALE|KEEP_TOGETHER
+
+ var/_stair_tag //Make this match another one and they'll connect!
+
+ var/obj/structure/fake_stairs/target //Don't set this manually, let it do it!
+ var/stepoff_dir
+
+/obj/structure/fake_stairs/Initialize(var/mapload)
+ . = ..()
+
+ for(var/obj/structure/fake_stairs/FS in world)
+ if(FS == src)
+ continue //hi
+ if(FS._stair_tag == _stair_tag)
+ target = FS
+ if(!target && mapload)
+ to_world("Fake stairs at [x],[y],[z] couldn't get a target!")
+
+/obj/structure/fake_stairs/Destroy()
+ if(target)
+ target.target = null
+ target = null
+ return ..()
+
+/obj/structure/fake_stairs/Bumped(var/atom/movable/AM)
+ if(!target)
+ return
+ target.take(AM)
+
+/obj/structure/fake_stairs/proc/take(var/atom/movable/AM)
+ var/dir_to_use = stepoff_dir ? stepoff_dir : dir
+ var/turf/T = get_step(src, dir_to_use)
+ if(!T)
+ log_debug("Fake stairs at [x],[y],[z] couldn't move someone to their destination.")
+ return
+ AM.forceMove(T)
+ spawn AM.set_dir(dir_to_use)
+ if(isliving(AM))
+ var/mob/living/L = AM
+ if(L.pulling)
+ L.pulling.forceMove(T)
+ spawn L.pulling.set_dir(dir_to_use)
+
+/obj/structure/fake_stairs/north/top
+ name = "stairs"
+ dir = NORTH
+ color = "#B0B0B0"
+ pixel_y = -32
+
+/obj/structure/fake_stairs/north/bottom
+ name = "stairs"
+ dir = NORTH
+ stepoff_dir = SOUTH
+ pixel_y = -32
+
+/obj/structure/fake_stairs/south/top
+ name = "stairs"
+ dir = SOUTH
+ color = "#B0B0B0"
+
+/obj/structure/fake_stairs/south/bottom
+ name = "stairs"
+ dir = SOUTH
+ stepoff_dir = NORTH
+
+/obj/structure/fake_stairs/east/top
+ name = "stairs"
+ dir = EAST
+ color = "#B0B0B0"
+ pixel_x = -32
+
+/obj/structure/fake_stairs/east/bottom
+ name = "stairs"
+ dir = EAST
+ stepoff_dir = WEST
+ pixel_x = -32
+
+/obj/structure/fake_stairs/west/top
+ name = "stairs"
+ dir = WEST
+ color = "#B0B0B0"
+
+/obj/structure/fake_stairs/west/bottom
+ name = "stairs"
+ dir = WEST
+ stepoff_dir = EAST
\ No newline at end of file
diff --git a/polaris.dme b/polaris.dme
index e6e3493986..60b8ca0937 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -2906,6 +2906,7 @@
#include "interface\interface.dm"
#include "interface\skin.dmf"
#include "maps\southern_cross\southern_cross.dm"
+#include "maps\submaps\_helpers.dm"
#include "maps\submaps\space_submaps\space.dm"
#include "maps\submaps\surface_submaps\mountains\mountains.dm"
#include "maps\submaps\surface_submaps\mountains\mountains_areas.dm"