mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 18:53:06 +00:00
Replaced "area" shuttles with "landmark" shuttles.
Largely ported from the work done at Baystation in https://github.com/Baystation12/Baystation12/pull/17460 and later commits. - Shuttles no longer require a separate area for each location they jump to. Instead destinations are indicated by landmark objects, which are not necessarily exclusive to that shuttle. This means that more than one shuttle could use the same docking port (not at the same time of course). - Enhanced shuttle control computers to use nanoui if they didn't. - Organizes shuttle datum code a bit better so there is less re-inventing the wheel in subtypes. - Allows the possibility of shuttles (or destinations) that start on late-loaded maps. - Deprecate the "extra" shuttle areas that are no longer needed and update shuttle areas in unit tests This all required a bit of infrastructure improvements. - ChangeArea proc, for changing the area of a turf. - Fixed lighting overlays actually being able to be destroyed. - Added a few utility macros and procs. - Added "turf translation" procs which are like move_contents_to but more flexible.
This commit is contained in:
@@ -3,6 +3,57 @@
|
||||
//How far from the edge of overmap zlevel could randomly placed objects spawn
|
||||
#define OVERMAP_EDGE 7
|
||||
|
||||
|
||||
|
||||
//Dimension of overmap (squares 4 lyfe)
|
||||
var/global/list/map_sectors = list()
|
||||
|
||||
/area/overmap/
|
||||
name = "System Map"
|
||||
icon_state = "start"
|
||||
requires_power = 0
|
||||
base_turf = /turf/unsimulated/map
|
||||
|
||||
/turf/unsimulated/map
|
||||
icon = 'icons/turf/space.dmi'
|
||||
icon_state = "map"
|
||||
|
||||
/turf/unsimulated/map/edge
|
||||
opacity = 1
|
||||
density = 1
|
||||
|
||||
/turf/unsimulated/map/New()
|
||||
..()
|
||||
name = "[x]-[y]"
|
||||
var/list/numbers = list()
|
||||
|
||||
if(x == 1 || x == global.using_map.overmap_size)
|
||||
numbers += list("[round(y/10)]","[round(y%10)]")
|
||||
if(y == 1 || y == global.using_map.overmap_size)
|
||||
numbers += "-"
|
||||
if(y == 1 || y == global.using_map.overmap_size)
|
||||
numbers += list("[round(x/10)]","[round(x%10)]")
|
||||
|
||||
for(var/i = 1 to numbers.len)
|
||||
var/image/I = image('icons/effects/numbers.dmi',numbers[i])
|
||||
I.pixel_x = 5*i - 2
|
||||
I.pixel_y = world.icon_size/2 - 3
|
||||
if(y == 1)
|
||||
I.pixel_y = 3
|
||||
I.pixel_x = 5*i + 4
|
||||
if(y == global.using_map.overmap_size)
|
||||
I.pixel_y = world.icon_size - 9
|
||||
I.pixel_x = 5*i + 4
|
||||
if(x == 1)
|
||||
I.pixel_x = 5*i - 2
|
||||
if(x == global.using_map.overmap_size)
|
||||
I.pixel_x = 5*i + 2
|
||||
overlays += I
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//list used to track which zlevels are being 'moved' by the proc below
|
||||
var/list/moving_levels = list()
|
||||
//Proc to 'move' stars in spess
|
||||
@@ -35,6 +86,7 @@ proc/toggle_move_stars(zlevel, direction)
|
||||
AM.throw_at(get_step(T,reverse_direction(direction)), 5, 1)
|
||||
|
||||
|
||||
/*
|
||||
//list used to cache empty zlevels to avoid nedless map bloat
|
||||
var/list/cached_space = list()
|
||||
|
||||
@@ -99,3 +151,4 @@ proc/overmap_spacetravel(var/turf/space/T, var/atom/movable/A)
|
||||
testing("Catching [M] for future use")
|
||||
source.loc = null
|
||||
cached_space += source
|
||||
*/
|
||||
39
code/modules/overmap/overmap_object.dm
Normal file
39
code/modules/overmap/overmap_object.dm
Normal file
@@ -0,0 +1,39 @@
|
||||
/obj/effect/overmap
|
||||
name = "map object"
|
||||
icon = 'icons/obj/overmap.dmi'
|
||||
icon_state = "object"
|
||||
|
||||
var/known = 1 //shows up on nav computers automatically
|
||||
var/scannable //if set to TRUE will show up on ship sensors for detailed scans
|
||||
|
||||
//Overlay of how this object should look on other skyboxes
|
||||
/obj/effect/overmap/proc/get_skybox_representation()
|
||||
return
|
||||
|
||||
/obj/effect/overmap/proc/get_scan_data(mob/user)
|
||||
return desc
|
||||
|
||||
/obj/effect/overmap/Initialize()
|
||||
. = ..()
|
||||
if(!global.using_map.use_overmap)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
if(known)
|
||||
//layer = ABOVE_LIGHTING_LAYER
|
||||
plane = PLANE_LIGHTING_ABOVE
|
||||
// TODO - Leshana HELM
|
||||
// for(var/obj/machinery/computer/ship/helm/H in global.machines)
|
||||
// H.get_known_sectors()
|
||||
/*
|
||||
TODO - Leshana - No need for this, we don't have skyboxes
|
||||
/obj/effect/overmap/Crossed(var/obj/effect/overmap/visitable/other)
|
||||
if(istype(other))
|
||||
for(var/obj/effect/overmap/visitable/O in loc)
|
||||
SSskybox.rebuild_skyboxes(O.map_z)
|
||||
|
||||
/obj/effect/overmap/Uncrossed(var/obj/effect/overmap/visitable/other)
|
||||
if(istype(other))
|
||||
SSskybox.rebuild_skyboxes(other.map_z)
|
||||
for(var/obj/effect/overmap/visitable/O in loc)
|
||||
SSskybox.rebuild_skyboxes(O.map_z)
|
||||
*/
|
||||
@@ -1,124 +1,136 @@
|
||||
|
||||
//===================================================================================
|
||||
//Hook for building overmap
|
||||
//Overmap object representing zlevel(s)
|
||||
//===================================================================================
|
||||
var/global/list/map_sectors = list()
|
||||
|
||||
/hook/startup/proc/build_map()
|
||||
if(!config.use_overmap)
|
||||
return 1
|
||||
testing("Building overmap...")
|
||||
var/obj/effect/mapinfo/data
|
||||
for(var/level in 1 to world.maxz)
|
||||
data = locate("sector[level]")
|
||||
if (data)
|
||||
testing("Located sector \"[data.name]\" at [data.mapx],[data.mapy] corresponding to zlevel [level]")
|
||||
map_sectors["[level]"] = new data.obj_type(data)
|
||||
return 1
|
||||
|
||||
//===================================================================================
|
||||
//Metaobject for storing information about sector this zlevel is representing.
|
||||
//Should be placed only once on every zlevel.
|
||||
//===================================================================================
|
||||
/obj/effect/mapinfo/
|
||||
name = "map info metaobject"
|
||||
icon = 'icons/mob/screen1.dmi'
|
||||
icon_state = "x2"
|
||||
invisibility = 101
|
||||
var/obj_type //type of overmap object it spawns
|
||||
var/landing_area //type of area used as inbound shuttle landing, null if no shuttle landing area
|
||||
var/zlevel
|
||||
var/mapx //coordinates on the
|
||||
var/mapy //overmap zlevel
|
||||
var/known = 1
|
||||
|
||||
/obj/effect/mapinfo/New()
|
||||
tag = "sector[z]"
|
||||
zlevel = z
|
||||
loc = null
|
||||
|
||||
/obj/effect/mapinfo/sector
|
||||
name = "generic sector"
|
||||
obj_type = /obj/effect/map/sector
|
||||
|
||||
/obj/effect/mapinfo/ship
|
||||
name = "generic ship"
|
||||
obj_type = /obj/effect/map/ship
|
||||
|
||||
|
||||
//===================================================================================
|
||||
//Overmap object representing zlevel
|
||||
//===================================================================================
|
||||
|
||||
/obj/effect/map
|
||||
/obj/effect/overmap/visitable
|
||||
name = "map object"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "sheet-plasteel"
|
||||
var/map_z = 0
|
||||
var/area/shuttle/shuttle_landing
|
||||
var/always_known = 1
|
||||
scannable = TRUE
|
||||
|
||||
/obj/effect/map/New(var/obj/effect/mapinfo/data)
|
||||
map_z = data.zlevel
|
||||
name = data.name
|
||||
always_known = data.known
|
||||
if (data.icon != 'icons/mob/screen1.dmi')
|
||||
icon = data.icon
|
||||
icon_state = data.icon_state
|
||||
if(data.desc)
|
||||
desc = data.desc
|
||||
var/new_x = data.mapx ? data.mapx : rand(OVERMAP_EDGE, world.maxx - OVERMAP_EDGE)
|
||||
var/new_y = data.mapy ? data.mapy : rand(OVERMAP_EDGE, world.maxy - OVERMAP_EDGE)
|
||||
loc = locate(new_x, new_y, OVERMAP_ZLEVEL)
|
||||
var/list/map_z = list()
|
||||
|
||||
if(data.landing_area)
|
||||
shuttle_landing = locate(data.landing_area)
|
||||
var/list/initial_generic_waypoints //store landmark_tag of landmarks that should be added to the actual lists below on init.
|
||||
var/list/initial_restricted_waypoints //For use with non-automatic landmarks (automatic ones add themselves).
|
||||
|
||||
/obj/effect/map/CanPass(atom/movable/A)
|
||||
testing("[A] attempts to enter sector\"[name]\"")
|
||||
return 1
|
||||
var/list/generic_waypoints = list() //waypoints that any shuttle can use
|
||||
var/list/restricted_waypoints = list() //waypoints for specific shuttles
|
||||
var/docking_codes
|
||||
|
||||
/obj/effect/map/Crossed(atom/movable/A)
|
||||
testing("[A] has entered sector\"[name]\"")
|
||||
if (istype(A,/obj/effect/map/ship))
|
||||
var/obj/effect/map/ship/S = A
|
||||
S.current_sector = src
|
||||
var/start_x //Coordinates for self placing
|
||||
var/start_y //will use random values if unset
|
||||
|
||||
/obj/effect/map/Uncrossed(atom/movable/A)
|
||||
testing("[A] has left sector\"[name]\"")
|
||||
if (istype(A,/obj/effect/map/ship))
|
||||
var/obj/effect/map/ship/S = A
|
||||
S.current_sector = null
|
||||
var/base = 0 //starting sector, counts as station_levels
|
||||
var/in_space = 1 //can be accessed via lucky EVA
|
||||
|
||||
/obj/effect/map/sector
|
||||
var/hide_from_reports = FALSE
|
||||
|
||||
var/has_distress_beacon
|
||||
|
||||
/obj/effect/overmap/visitable/Initialize()
|
||||
. = ..()
|
||||
if(. == INITIALIZE_HINT_QDEL)
|
||||
return
|
||||
|
||||
find_z_levels() // This populates map_z and assigns z levels to the ship.
|
||||
register_z_levels() // This makes external calls to update global z level information.
|
||||
|
||||
if(!global.using_map.overmap_z)
|
||||
build_overmap()
|
||||
|
||||
start_x = start_x || rand(OVERMAP_EDGE, global.using_map.overmap_size - OVERMAP_EDGE)
|
||||
start_y = start_y || rand(OVERMAP_EDGE, global.using_map.overmap_size - OVERMAP_EDGE)
|
||||
|
||||
forceMove(locate(start_x, start_y, global.using_map.overmap_z))
|
||||
|
||||
docking_codes = "[ascii2text(rand(65,90))][ascii2text(rand(65,90))][ascii2text(rand(65,90))][ascii2text(rand(65,90))]"
|
||||
|
||||
testing("Located sector \"[name]\" at [start_x],[start_y], containing Z [english_list(map_z)]")
|
||||
|
||||
LAZYADD(SSshuttles.sectors_to_initialize, src) //Queued for further init. Will populate the waypoint lists; waypoints not spawned yet will be added in as they spawn.
|
||||
SSshuttles.process_init_queues()
|
||||
|
||||
//This is called later in the init order by SSshuttles to populate sector objects. Importantly for subtypes, shuttles will be created by then.
|
||||
/obj/effect/overmap/visitable/proc/populate_sector_objects()
|
||||
|
||||
// TODO - Leshana - Implement
|
||||
///obj/effect/overmap/visitable/proc/get_areas()
|
||||
// return get_filtered_areas(list(/proc/area_belongs_to_zlevels = map_z))
|
||||
|
||||
/obj/effect/overmap/visitable/proc/find_z_levels()
|
||||
map_z = GetConnectedZlevels(z)
|
||||
|
||||
/obj/effect/overmap/visitable/proc/register_z_levels()
|
||||
for(var/zlevel in map_z)
|
||||
map_sectors["[zlevel]"] = src
|
||||
|
||||
global.using_map.player_levels |= map_z
|
||||
if(!in_space)
|
||||
global.using_map.sealed_levels |= map_z
|
||||
if(base)
|
||||
global.using_map.station_levels |= map_z
|
||||
global.using_map.contact_levels |= map_z
|
||||
global.using_map.map_levels |= map_z
|
||||
|
||||
//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))
|
||||
return 1
|
||||
|
||||
//If shuttle_name is false, will add to generic waypoints; otherwise will add to restricted. Does not do checks.
|
||||
/obj/effect/overmap/visitable/proc/add_landmark(obj/effect/shuttle_landmark/landmark, shuttle_name)
|
||||
landmark.sector_set(src, shuttle_name)
|
||||
if(shuttle_name)
|
||||
LAZYADD(restricted_waypoints[shuttle_name], landmark)
|
||||
else
|
||||
generic_waypoints += landmark
|
||||
|
||||
/obj/effect/overmap/visitable/proc/remove_landmark(obj/effect/shuttle_landmark/landmark, shuttle_name)
|
||||
if(shuttle_name)
|
||||
var/list/shuttles = restricted_waypoints[shuttle_name]
|
||||
LAZYREMOVE(shuttles, landmark)
|
||||
else
|
||||
generic_waypoints -= landmark
|
||||
|
||||
/obj/effect/overmap/visitable/proc/get_waypoints(var/shuttle_name)
|
||||
. = list()
|
||||
for(var/obj/effect/overmap/visitable/contained in src)
|
||||
. += contained.get_waypoints(shuttle_name)
|
||||
for(var/thing in generic_waypoints)
|
||||
.[thing] = name
|
||||
if(shuttle_name in restricted_waypoints)
|
||||
for(var/thing in restricted_waypoints[shuttle_name])
|
||||
.[thing] = name
|
||||
|
||||
/obj/effect/overmap/visitable/proc/generate_skybox()
|
||||
return
|
||||
|
||||
/obj/effect/overmap/visitable/sector
|
||||
name = "generic sector"
|
||||
desc = "Sector with some stuff in it."
|
||||
icon_state = "sector"
|
||||
anchored = 1
|
||||
|
||||
//Space stragglers go here
|
||||
// Because of the way these are spawned, they will potentially have their invisibility adjusted by the turfs they are mapped on
|
||||
// prior to being moved to the overmap. This blocks that. Use set_invisibility to adjust invisibility as needed instead.
|
||||
/obj/effect/overmap/visitable/sector/hide()
|
||||
|
||||
/obj/effect/map/sector/temporary
|
||||
name = "Deep Space"
|
||||
icon_state = ""
|
||||
always_known = 0
|
||||
/proc/build_overmap()
|
||||
if(!global.using_map.use_overmap)
|
||||
return 1
|
||||
|
||||
/obj/effect/map/sector/temporary/New(var/nx, var/ny, var/nz)
|
||||
loc = locate(nx, ny, OVERMAP_ZLEVEL)
|
||||
map_z = nz
|
||||
map_sectors["[map_z]"] = src
|
||||
testing("Temporary sector at [x],[y] was created, corresponding zlevel is [map_z].")
|
||||
testing("Building overmap...")
|
||||
world.maxz++
|
||||
global.using_map.overmap_z = world.maxz
|
||||
|
||||
/obj/effect/map/sector/temporary/Destroy()
|
||||
map_sectors["[map_z]"] = null
|
||||
testing("Temporary sector at [x],[y] was deleted.")
|
||||
if (can_die())
|
||||
testing("Associated zlevel disappeared.")
|
||||
world.maxz--
|
||||
testing("Putting overmap on [global.using_map.overmap_z]")
|
||||
var/area/overmap/A = new
|
||||
for (var/square in block(locate(1,1,global.using_map.overmap_z), locate(global.using_map.overmap_size,global.using_map.overmap_size,global.using_map.overmap_z)))
|
||||
var/turf/T = square
|
||||
if(T.x == global.using_map.overmap_size || T.y == global.using_map.overmap_size)
|
||||
T = T.ChangeTurf(/turf/unsimulated/map/edge)
|
||||
else
|
||||
T = T.ChangeTurf(/turf/unsimulated/map)
|
||||
ChangeArea(T, A)
|
||||
|
||||
/obj/effect/map/sector/temporary/proc/can_die(var/mob/observer)
|
||||
testing("Checking if sector at [map_z] can die.")
|
||||
for(var/mob/M in player_list)
|
||||
if(M != observer && M.z == map_z)
|
||||
testing("There are people on it.")
|
||||
return 0
|
||||
global.using_map.sealed_levels |= global.using_map.overmap_z
|
||||
|
||||
testing("Overmap build complete.")
|
||||
return 1
|
||||
|
||||
114
code/modules/overmap/spacetravel.dm
Normal file
114
code/modules/overmap/spacetravel.dm
Normal file
@@ -0,0 +1,114 @@
|
||||
//list used to cache empty zlevels to avoid nedless map bloat
|
||||
var/list/cached_space = list()
|
||||
|
||||
//Space stragglers go here
|
||||
|
||||
/obj/effect/overmap/visitable/sector/temporary
|
||||
name = "Deep Space"
|
||||
invisibility = 101
|
||||
known = 0
|
||||
|
||||
/obj/effect/overmap/visitable/sector/temporary/New(var/nx, var/ny, var/nz)
|
||||
loc = locate(nx, ny, global.using_map.overmap_z)
|
||||
x = nx
|
||||
y = ny
|
||||
map_z += nz
|
||||
map_sectors["[nz]"] = src
|
||||
testing("Temporary sector at [x],[y] was created, corresponding zlevel is [nz].")
|
||||
|
||||
/obj/effect/overmap/visitable/sector/temporary/Destroy()
|
||||
map_sectors["[map_z]"] = null
|
||||
testing("Temporary sector at [x],[y] was deleted.")
|
||||
|
||||
/obj/effect/overmap/visitable/sector/temporary/proc/can_die(var/mob/observer)
|
||||
testing("Checking if sector at [map_z[1]] can die.")
|
||||
for(var/mob/M in global.player_list)
|
||||
if(M != observer && (M.z in map_z))
|
||||
testing("There are people on it.")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
proc/get_deepspace(x,y)
|
||||
var/obj/effect/overmap/visitable/sector/temporary/res = locate(x,y,global.using_map.overmap_z)
|
||||
if(istype(res))
|
||||
return res
|
||||
else if(cached_space.len)
|
||||
res = cached_space[cached_space.len]
|
||||
cached_space -= res
|
||||
res.x = x
|
||||
res.y = y
|
||||
return res
|
||||
else
|
||||
return new /obj/effect/overmap/visitable/sector/temporary(x, y, global.using_map.get_empty_zlevel())
|
||||
|
||||
/atom/movable/proc/lost_in_space()
|
||||
for(var/atom/movable/AM in contents)
|
||||
if(!AM.lost_in_space())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/mob/lost_in_space()
|
||||
return isnull(client)
|
||||
|
||||
/mob/living/carbon/human/lost_in_space()
|
||||
return isnull(client) && !key && stat == DEAD
|
||||
|
||||
proc/overmap_spacetravel(var/turf/space/T, var/atom/movable/A)
|
||||
if (!T || !A)
|
||||
return
|
||||
|
||||
var/obj/effect/overmap/visitable/M = map_sectors["[T.z]"]
|
||||
if (!M)
|
||||
return
|
||||
|
||||
if(A.lost_in_space())
|
||||
if(!QDELETED(A))
|
||||
qdel(A)
|
||||
return
|
||||
|
||||
var/nx = 1
|
||||
var/ny = 1
|
||||
var/nz = 1
|
||||
|
||||
if(T.x <= TRANSITIONEDGE)
|
||||
nx = world.maxx - TRANSITIONEDGE - 2
|
||||
ny = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2)
|
||||
|
||||
else if (A.x >= (world.maxx - TRANSITIONEDGE - 1))
|
||||
nx = TRANSITIONEDGE + 2
|
||||
ny = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2)
|
||||
|
||||
else if (T.y <= TRANSITIONEDGE)
|
||||
ny = world.maxy - TRANSITIONEDGE -2
|
||||
nx = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2)
|
||||
|
||||
else if (A.y >= (world.maxy - TRANSITIONEDGE - 1))
|
||||
ny = TRANSITIONEDGE + 2
|
||||
nx = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2)
|
||||
|
||||
testing("[A] spacemoving from [M] ([M.x], [M.y]).")
|
||||
|
||||
var/turf/map = locate(M.x,M.y,global.using_map.overmap_z)
|
||||
var/obj/effect/overmap/visitable/TM
|
||||
for(var/obj/effect/overmap/visitable/O in map)
|
||||
if(O != M && O.in_space && prob(50))
|
||||
TM = O
|
||||
break
|
||||
if(!TM)
|
||||
TM = get_deepspace(M.x,M.y)
|
||||
nz = pick(TM.map_z)
|
||||
|
||||
var/turf/dest = locate(nx,ny,nz)
|
||||
if(dest)
|
||||
A.forceMove(dest)
|
||||
if(ismob(A))
|
||||
var/mob/D = A
|
||||
if(D.pulling)
|
||||
D.pulling.forceMove(dest)
|
||||
|
||||
if(istype(M, /obj/effect/overmap/visitable/sector/temporary))
|
||||
var/obj/effect/overmap/visitable/sector/temporary/source = M
|
||||
if (source.can_die())
|
||||
testing("Caching [M] for future use")
|
||||
source.forceMove(null)
|
||||
cached_space += source
|
||||
Reference in New Issue
Block a user