Merge pull request #5496 from Citadel-Station-13/upstream-merge-35339

[MIRROR] Support stations with multiple z-levels
This commit is contained in:
deathride58
2018-02-17 21:24:48 +00:00
committed by GitHub
27 changed files with 278 additions and 196869 deletions
+2 -7
View File
@@ -1,16 +1,11 @@
//#define LOWMEMORYMODE //uncomment this to load centcom and runtime station and thats it.
#include "map_files\generic\CentCom.dmm"
#include "map_files\generic\SpaceStation.dmm"
#ifndef LOWMEMORYMODE
#include "map_files\generic\Space.dmm"
#include "map_files\generic\Space2.dmm"
#include "map_files\Mining\Lavaland.dmm"
#include "map_files\generic\City_of_Cogs.dmm"
#ifdef ALL_MAPS
#include "map_files\Mining\Lavaland.dmm"
#include "map_files\generic\City_of_Cogs.dmm"
#include "map_files\debug\runtimestation.dmm"
#include "map_files\Deltastation\DeltaStation2.dmm"
#include "map_files\MetaStation\MetaStation.dmm"
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+48 -48
View File
@@ -1,46 +1,32 @@
/*
The /tg/ codebase currently requires you to have 11 z-levels of the same size dimensions.
z-level order is important, the order you put them in inside the map config.dm will determine what z level number they are assigned ingame.
Names of z-level do not matter, but order does greatly, for instances such as checking alive status of revheads on z1
The /tg/ codebase allows mixing of hardcoded and dynamically-loaded z-levels.
Z-levels can be reordered as desired and their properties are set by "traits".
See map_config.dm for how a particular station's traits may be chosen.
The list DEFAULT_MAP_TRAITS at the bottom of this file should correspond to
the maps that are hardcoded, as set in _maps/_basemap.dm. SSmapping is
responsible for loading every non-hardcoded z-level.
current as of september 17, 2017
z1 = station
z2 = centcom
z5 = mining
z6 = city of cogs
Everything else = randomized space
Last space-z level = empty
As of 2018-02-04, the typical z-levels for a single-level station are:
1: CentCom
2: Station
3-4: Randomized space
5: Mining
6: City of Cogs
7-11: Randomized space
12: Empty space
13: Transit space
Multi-Z stations are supported and multi-Z mining and away missions would
require only minor tweaks.
*/
#define CROSSLINKED 2
#define SELFLOOPING 1
#define UNAFFECTED 0
#define MAIN_STATION "Main Station"
#define CENTCOM "CentCom"
#define CITY_OF_COGS "City of Cogs"
#define EMPTY_AREA_1 "Empty Area 1"
#define EMPTY_AREA_2 "Empty Area 2"
#define MINING_ASTEROID "Mining Asteroid"
#define EMPTY_AREA_3 "Empty Area 3"
#define EMPTY_AREA_4 "Empty Area 4"
#define EMPTY_AREA_5 "Empty Area 5"
#define EMPTY_AREA_6 "Empty Area 6"
#define EMPTY_AREA_7 "Empty Area 7"
#define EMPTY_AREA_8 "Empty Area 8"
#define AWAY_MISSION "Away Mission"
//for modifying jobs
// helpers for modifying jobs, used in various job_changes.dm files
#define MAP_JOB_CHECK if(SSmapping.config.map_name != JOB_MODIFICATION_MAP_NAME) { return; }
#define MAP_JOB_CHECK_BASE if(SSmapping.config.map_name != JOB_MODIFICATION_MAP_NAME) { return ..(); }
#define MAP_REMOVE_JOB(jobpath) /datum/job/##jobpath/map_check() { return (SSmapping.config.map_name != JOB_MODIFICATION_MAP_NAME) && ..() }
//zlevel defines, can be overridden for different maps in the appropriate _maps file.
#define ZLEVEL_STATION_PRIMARY 2
#define ZLEVEL_EMPTY_SPACE 12
#define SPACERUIN_MAP_EDGE_PAD 15
#define ZLEVEL_SPACE_RUIN_COUNT 5
#define ZLEVEL_SPACE_RUIN_COUNT 7
// traits
// boolean - marks a level as having that property if present
@@ -52,26 +38,40 @@ Last space-z level = empty
#define ZTRAIT_AWAY "Away Mission"
#define ZTRAIT_SPACE_RUINS "Space Ruins"
#define ZTRAIT_LAVA_RUINS "Lava Ruins"
// number - bombcap is multiplied by this before being applied to bombs
#define ZTRAIT_BOMBCAP_MULTIPLIER "Bombcap Multiplier"
// trait definitions
#define DL_NAME "name"
#define DL_LINKAGE "linkage"
#define DL_TRAITS "traits"
// numeric offsets - e.g. {"Down": -1} means that chasms will fall to z - 1 rather than oblivion
#define ZTRAIT_UP "Up"
#define ZTRAIT_DOWN "Down"
#define DECLARE_LEVEL(NAME, LINKAGE, TRAITS) list(DL_NAME = NAME, DL_LINKAGE = LINKAGE, DL_TRAITS = TRAITS)
// corresponds to basemap.dm
// enum - how space transitions should affect this level
#define ZTRAIT_LINKAGE "Linkage"
// UNAFFECTED if absent - no space transitions
#define UNAFFECTED null
// SELFLOOPING - space transitions always self-loop
#define SELFLOOPING "Self"
// CROSSLINKED - mixed in with the cross-linked space pool
#define CROSSLINKED "Cross"
// default trait definitions, used by SSmapping
#define ZTRAITS_CENTCOM list(ZTRAIT_LINKAGE = SELFLOOPING, ZTRAIT_CENTCOM = TRUE)
#define ZTRAITS_STATION list(ZTRAIT_LINKAGE = CROSSLINKED, ZTRAIT_STATION = TRUE)
#define ZTRAITS_SPACE list(ZTRAIT_LINKAGE = CROSSLINKED, ZTRAIT_SPACE_RUINS = TRUE)
#define ZTRAITS_LAVALAND list(ZTRAIT_MINING = TRUE, ZTRAIT_LAVA_RUINS = TRUE, ZTRAIT_BOMBCAP_MULTIPLIER = 2)
#define ZTRAITS_REEBE list(ZTRAIT_REEBE = TRUE, ZTRAIT_BOMBCAP_MULTIPLIER = 0.5)
#define DL_NAME "name"
#define DL_TRAITS "traits"
#define DECLARE_LEVEL(NAME, TRAITS) list(DL_NAME = NAME, DL_TRAITS = TRAITS)
// must correspond to _basemap.dm for things to work correctly
#define DEFAULT_MAP_TRAITS list(\
DECLARE_LEVEL("CentCom", SELFLOOPING, list(ZTRAIT_CENTCOM = TRUE)),\
DECLARE_LEVEL("Main Station", CROSSLINKED, list(ZTRAIT_STATION = TRUE)),\
DECLARE_LEVEL("Empty Area 1", CROSSLINKED, list(ZTRAIT_SPACE_RUINS = TRUE)),\
DECLARE_LEVEL("Empty Area 2", CROSSLINKED, list(ZTRAIT_SPACE_RUINS = TRUE)),\
DECLARE_LEVEL("Lavaland", UNAFFECTED, list(ZTRAIT_MINING = TRUE, ZTRAIT_LAVA_RUINS = TRUE, ZTRAIT_BOMBCAP_MULTIPLIER = 2)),\
DECLARE_LEVEL("Reebe", UNAFFECTED, list(ZTRAIT_REEBE = TRUE, ZTRAIT_BOMBCAP_MULTIPLIER = 0.5)),\
DECLARE_LEVEL("CentCom", ZTRAITS_CENTCOM),\
)
//Camera lock flags
// Camera lock flags
#define CAMERA_LOCK_STATION 1
#define CAMERA_LOCK_MINING 2
#define CAMERA_LOCK_CENTCOM 4
@@ -85,4 +85,4 @@ Last space-z level = empty
#define PLACE_DEFAULT "random"
#define PLACE_SAME_Z "same"
#define PLACE_SPACE_RUIN "space"
#define PLACE_LAVA_RUIN "lavaland"
#define PLACE_LAVA_RUIN "lavaland"
@@ -17,11 +17,11 @@
var/petcount = target_amount
for(var/mob/living/simple_animal/pet/P in GLOB.mob_list)
if(!(P.stat == DEAD))
if(P.z == ZLEVEL_STATION_PRIMARY || SSshuttle.emergency.shuttle_areas[get_area(P)])
if(P.z == SSmapping.station_start || SSshuttle.emergency.shuttle_areas[get_area(P)])
petcount--
for(var/mob/living/carbon/human/H in GLOB.mob_list)
if(!(H.stat == DEAD))
if(H.z == ZLEVEL_STATION_PRIMARY || SSshuttle.emergency.shuttle_areas[get_area(H)])
if(H.z == SSmapping.station_start || SSshuttle.emergency.shuttle_areas[get_area(H)])
if(istype(H.wear_neck, /obj/item/clothing/neck/petcollar))
petcount--
if(petcount <= 0)
@@ -65,7 +65,7 @@
/datum/objective/crew/responsibility/check_completion()
for(var/mob/living/carbon/human/H in GLOB.mob_list)
if(H.stat == DEAD && H.drunkenness >= 80)
if(H.z == ZLEVEL_STATION_PRIMARY || SSshuttle.emergency.shuttle_areas[get_area(H)])
if(H.z == SSmapping.station_start || SSshuttle.emergency.shuttle_areas[get_area(H)])
return FALSE
return TRUE
@@ -6,7 +6,7 @@
/datum/objective/crew/morgue/check_completion()
for(var/mob/living/carbon/human/H in GLOB.mob_list)
if(H.stat == DEAD && H.z == ZLEVEL_STATION_PRIMARY)
if(H.stat == DEAD && H.z == SSmapping.station_start)
if(get_area(H) != /area/medical/morgue)
return FALSE
return TRUE
@@ -80,7 +80,7 @@
/datum/objective/crew/noinfections/check_completion()
for(var/mob/living/carbon/human/H in GLOB.mob_list)
if(!H.stat == DEAD)
if(H.z == ZLEVEL_STATION_PRIMARY || SSshuttle.emergency.shuttle_areas[get_area(H)])
if(H.z == SSmapping.station_start || SSshuttle.emergency.shuttle_areas[get_area(H)])
if(H.check_virus() == 2)
return FALSE
return TRUE
@@ -236,7 +236,7 @@
switch (command)
if ("map")
currentmap = new ("_maps/[data].json")
currentmap = load_map_config("_maps/[data].json")
if(currentmap.defaulted)
log_config("Failed to load map config for [data]!")
currentmap = null
+78 -24
View File
@@ -23,15 +23,19 @@ SUBSYSTEM_DEF(mapping)
var/loading_ruins = FALSE
// Z-manager stuff
var/station_start // should only be used for maploading-related tasks
var/space_levels_so_far = 0
var/list/z_list
var/datum/space_level/transit
var/datum/space_level/empty_space
var/dmm_suite/loader
/datum/controller/subsystem/mapping/PreInit()
if(!config)
#ifdef FORCE_MAP
config = new(FORCE_MAP)
config = load_map_config(FORCE_MAP)
#else
config = new(error_if_missing = FALSE)
config = load_map_config(error_if_missing = FALSE)
#endif
return ..()
@@ -39,16 +43,20 @@ SUBSYSTEM_DEF(mapping)
/datum/controller/subsystem/mapping/Initialize(timeofday)
if(config.defaulted)
to_chat(world, "<span class='boldannounce'>Unable to load next map config, defaulting to Box Station</span>")
loader = new
loadWorld()
repopulate_sorted_areas()
process_teleport_locs() //Sets up the wizard teleport locations
preloadTemplates()
#ifndef LOWMEMORYMODE
// Create space levels
for(var/I in 1 to ZLEVEL_SPACE_RUIN_COUNT)
add_new_zlevel("Empty Area [2 + I]", CROSSLINKED, list(ZTRAIT_SPACE_RUINS = TRUE))
add_new_zlevel("Empty Area [3 + ZLEVEL_SPACE_RUIN_COUNT]", CROSSLINKED, list()) // no ruins
transit = add_new_zlevel("Transit", UNAFFECTED, list(ZTRAIT_TRANSIT = TRUE))
// Create space ruin levels
while (space_levels_so_far < ZLEVEL_SPACE_RUIN_COUNT)
++space_levels_so_far
add_new_zlevel("Empty Area [space_levels_so_far]", ZTRAITS_SPACE)
// and one level with no ruins
empty_space = add_new_zlevel("Empty Area [1 + space_levels_so_far]", list(ZTRAIT_LINKAGE = CROSSLINKED))
// and the transit level
transit = add_new_zlevel("Transit", list(ZTRAIT_TRANSIT = TRUE))
// Pick a random away mission.
createRandomZlevel()
@@ -71,6 +79,7 @@ SUBSYSTEM_DEF(mapping)
// Set up Z-level transitions.
setup_map_transitions()
generate_station_area_list()
QDEL_NULL(loader)
..()
/* Nuke threats, for making the blue tiles on the station go RED
@@ -108,32 +117,77 @@ SUBSYSTEM_DEF(mapping)
z_list = SSmapping.z_list
/datum/controller/subsystem/mapping/proc/TryLoadZ(filename, errorList, forceLevel, last)
var/static/dmm_suite/loader
if(!loader)
loader = new
if(!loader.load_map(file(filename), 0, 0, forceLevel, no_changeturf = TRUE))
errorList |= filename
if(last)
QDEL_NULL(loader)
#define INIT_ANNOUNCE(X) to_chat(world, "<span class='boldannounce'>[X]</span>"); log_world(X)
/datum/controller/subsystem/mapping/proc/LoadGroup(list/errorList, name, path, files, list/traits, list/default_traits)
var/start_time = REALTIMEOFDAY
if (!islist(files)) // handle single-level maps
files = list(files)
// check that the total z count of all maps matches the list of traits
var/total_z = 0
for (var/file in files)
var/full_path = "_maps/[path]/[file]"
var/bounds = loader.load_map(file(full_path), 1, 1, 1, cropMap=FALSE, measureOnly=TRUE)
files[file] = total_z // save the start Z of this file
total_z += bounds[MAP_MAXZ] - bounds[MAP_MINZ] + 1
if (!length(traits)) // null or empty - default
for (var/i in 1 to total_z)
traits += list(default_traits)
else if (total_z != traits.len) // mismatch
INIT_ANNOUNCE("WARNING: [traits.len] trait sets specified for [total_z] z-levels in [path]!")
if (total_z < traits.len) // ignore extra traits
traits.Cut(total_z + 1)
while (total_z > traits.len) // fall back to defaults on extra levels
traits += list(default_traits)
// preload the relevant space_level datums
var/start_z = world.maxz + 1
var/i = 0
for (var/level in traits)
add_new_zlevel("[name][i ? " [i + 1]" : ""]", level)
++i
// load the maps
for (var/file in files)
var/full_path = "_maps/[path]/[file]"
if(!loader.load_map(file(full_path), 0, 0, start_z + files[file], no_changeturf = TRUE))
errorList |= full_path
INIT_ANNOUNCE("Loaded [name] in [(REALTIMEOFDAY - start_time)/10]s!")
/datum/controller/subsystem/mapping/proc/loadWorld()
//if any of these fail, something has gone horribly, HORRIBLY, wrong
var/list/FailedZs = list()
var/start_time = REALTIMEOFDAY
INIT_ANNOUNCE("Loading [config.map_name]...")
TryLoadZ(config.GetFullMapPath(), FailedZs, ZLEVEL_STATION_PRIMARY)
// ensure we have space_level datums for compiled-in maps
InitializeDefaultZLevels()
INIT_ANNOUNCE("Loaded station in [(REALTIMEOFDAY - start_time)/10]s!")
// load the station
station_start = world.maxz + 1
INIT_ANNOUNCE("Loading [config.map_name]...")
LoadGroup(FailedZs, "Station", config.map_path, config.map_file, config.traits, ZTRAITS_STATION)
if(SSdbcore.Connect())
var/datum/DBQuery/query_round_map_name = SSdbcore.NewQuery("UPDATE [format_table_name("round")] SET map_name = '[config.map_name]' WHERE id = [GLOB.round_id]")
query_round_map_name.Execute()
if(config.minetype != "lavaland")
INIT_ANNOUNCE("WARNING: A map without lavaland set as its minetype was loaded! This is being ignored! Update the maploader code!")
#ifndef LOWMEMORYMODE
// TODO: remove this when the DB is prepared for the z-levels getting reordered
while (world.maxz < (5 - 1) && space_levels_so_far < ZLEVEL_SPACE_RUIN_COUNT)
++space_levels_so_far
add_new_zlevel("Empty Area [space_levels_so_far]", ZTRAITS_SPACE)
// load mining
if(config.minetype == "lavaland")
LoadGroup(FailedZs, "Lavaland", "map_files/Mining", "Lavaland.dmm", default_traits = ZTRAITS_LAVALAND)
else if (!isnull(config.minetype))
INIT_ANNOUNCE("WARNING: An unknown minetype '[config.minetype]' was set! This is being ignored! Update the maploader code!")
// load Reebe
LoadGroup(FailedZs, "Reebe", "map_files/generic", "City_of_Cogs.dmm", default_traits = ZTRAITS_REEBE)
#endif
if(LAZYLEN(FailedZs)) //but seriously, unless the server's filesystem is messed up this will never happen
var/msg = "RED ALERT! The following map files failed to load: [FailedZs[1]]"
@@ -209,7 +263,7 @@ GLOBAL_LIST_EMPTY(the_station_areas)
/datum/controller/subsystem/mapping/proc/changemap(var/datum/map_config/VM)
if(!VM.MakeNextMap())
next_map_config = new(default_to_box = TRUE)
next_map_config = load_map_config(default_to_box = TRUE)
message_admins("Failed to set new map with next_map.json for [VM.map_name]! Using default as backup!")
return
+4 -1
View File
@@ -9,7 +9,10 @@ SUBSYSTEM_DEF(minimap)
/datum/controller/subsystem/minimap/Initialize(timeofday)
z_levels = SSmapping.levels_by_trait(ZTRAIT_STATION)
var/hash = md5(SSmapping.config.GetFullMapPath())
var/list/hashlist = list()
for (var/file in SSmapping.config.GetFullMapPaths())
hashlist += md5(file2text(file))
var/hash = hashlist.Join("\n")
if(CONFIG_GET(flag/generate_minimaps))
if(hash == trim(file2text(hash_path())))
for(var/z in z_levels) //We have these files cached, let's register them
+3 -3
View File
@@ -56,7 +56,7 @@ SUBSYSTEM_DEF(persistence)
old_secret_satchels.Cut(pos, pos+1 % old_secret_satchels.len)
F.x = old_secret_satchels[pos]["x"]
F.y = old_secret_satchels[pos]["y"]
F.z = ZLEVEL_STATION_PRIMARY
F.z = SSmapping.station_start
path = text2path(old_secret_satchels[pos]["saved_obj"])
if(F)
@@ -67,7 +67,7 @@ SUBSYSTEM_DEF(persistence)
spawned_objects[spawned_item] = TRUE
placed_satchel++
var/free_satchels = 0
for(var/turf/T in shuffle(block(locate(TRANSITIONEDGE,TRANSITIONEDGE,ZLEVEL_STATION_PRIMARY), locate(world.maxx-TRANSITIONEDGE,world.maxy-TRANSITIONEDGE,ZLEVEL_STATION_PRIMARY)))) //Nontrivially expensive but it's roundstart only
for(var/turf/T in shuffle(block(locate(TRANSITIONEDGE,TRANSITIONEDGE,SSmapping.station_start), locate(world.maxx-TRANSITIONEDGE,world.maxy-TRANSITIONEDGE,SSmapping.station_start)))) //Nontrivially expensive but it's roundstart only
if(isfloorturf(T) && !isplatingturf(T))
new /obj/item/storage/backpack/satchel/flat/secret(T)
free_satchels++
@@ -189,7 +189,7 @@ SUBSYSTEM_DEF(persistence)
var/list/satchels_to_add = list()
for(var/A in new_secret_satchels)
var/obj/item/storage/backpack/satchel/flat/F = A
if(QDELETED(F) || F.z != ZLEVEL_STATION_PRIMARY || F.invisibility != INVISIBILITY_MAXIMUM)
if(QDELETED(F) || F.z != SSmapping.station_start || F.invisibility != INVISIBILITY_MAXIMUM)
continue
var/list/savable_obj = list()
for(var/obj/O in F)
+65 -102
View File
@@ -4,46 +4,42 @@
// -Cyberboss
/datum/map_config
// Metadata
var/config_filename = "_maps/boxstation.json"
var/defaulted = TRUE // set to FALSE by LoadConfig() succeeding
// Config from maps.txt
var/config_max_users = 0
var/config_min_users = 0
var/voteweight = 1
// Config actually from the JSON - should default to Box
var/map_name = "Box Station"
var/map_path = "map_files/BoxStation"
var/map_file = "BoxStation.dmm"
var/traits = null
var/minetype = "lavaland"
var/allow_custom_shuttles = TRUE
var/shuttles = list(
"cargo" = "cargo_box",
"ferry" = "ferry_fancy",
"whiteship" = "whiteship_box",
"emergency" = "emergency_box")
//Order matters here.
var/list/transition_config = list(CENTCOM = SELFLOOPING,
MAIN_STATION = CROSSLINKED,
EMPTY_AREA_1 = CROSSLINKED,
EMPTY_AREA_2 = CROSSLINKED,
MINING = SELFLOOPING,
CITY_OF_COGS = SELFLOOPING,
EMPTY_AREA_3 = CROSSLINKED,
EMPTY_AREA_4 = CROSSLINKED,
EMPTY_AREA_5 = CROSSLINKED,
EMPTY_AREA_6 = CROSSLINKED,
EMPTY_AREA_7 = CROSSLINKED,
EMPTY_AREA_8 = CROSSLINKED)
var/defaulted = TRUE //if New failed
var/config_max_users = 0
var/config_min_users = 0
var/voteweight = 1
var/allow_custom_shuttles = TRUE
/datum/map_config/New(filename = "data/next_map.json", default_to_box, delete_after, error_if_missing = TRUE)
if(default_to_box)
return
LoadConfig(filename, error_if_missing)
if(delete_after)
/proc/load_map_config(filename = "data/next_map.json", default_to_box, delete_after, error_if_missing = TRUE)
var/datum/map_config/config = new
if (default_to_box)
return config
if (!config.LoadConfig(filename, error_if_missing))
qdel(config)
config = new /datum/map_config // Fall back to Box
if (delete_after)
fdel(filename)
return config
#define CHECK_EXISTS(X) if(!istext(json[X])) { log_world("[##X] missing from json!"); return; }
/datum/map_config/proc/LoadConfig(filename, error_if_missing)
if(!fexists(filename))
if(error_if_missing)
@@ -65,99 +61,66 @@
log_world("map_config is not json: [filename]")
return
if(!ValidateJSON(json))
log_world("map_config failed to validate for above reason: [filename]")
return
config_filename = filename
CHECK_EXISTS("map_name")
map_name = json["map_name"]
CHECK_EXISTS("map_path")
map_path = json["map_path"]
map_file = json["map_file"]
if(islist(json["shuttles"]))
map_file = json["map_file"]
// "map_file": "BoxStation.dmm"
if (istext(map_file))
if (!fexists("_maps/[map_path]/[map_file]"))
log_world("Map file ([map_path]/[map_file]) does not exist!")
return
// "map_file": ["Lower.dmm", "Upper.dmm"]
else if (islist(map_file))
for (var/file in map_file)
if (!fexists("_maps/[map_path]/[file]"))
log_world("Map file ([map_path]/[file]) does not exist!")
return
else
log_world("map_file missing from json!")
return
if (islist(json["shuttles"]))
var/list/L = json["shuttles"]
for(var/key in L)
var/value = L[key]
shuttles[key] = value
minetype = json["minetype"] || minetype
allow_custom_shuttles = json["allow_custom_shuttles"] != FALSE
var/jtcl = json["transition_config"]
if(jtcl && jtcl != "default")
transition_config.Cut()
for(var/I in jtcl)
transition_config[TransitionStringToEnum(I)] = TransitionStringToEnum(jtcl[I])
defaulted = FALSE
#define CHECK_EXISTS(X) if(!istext(json[X])) { log_world("[##X] missing from json!"); return; }
/datum/map_config/proc/ValidateJSON(list/json)
CHECK_EXISTS("map_name")
CHECK_EXISTS("map_path")
CHECK_EXISTS("map_file")
var/shuttles = json["shuttles"]
if(shuttles && !islist(shuttles))
log_world("json\[shuttles\] is not a list!")
var/path = GetFullMapPath(json["map_path"], json["map_file"])
if(!fexists(path))
log_world("Map file ([path]) does not exist!")
else if ("shuttles" in json)
log_world("map_config shuttles is not a list!")
return
var/tc = json["transition_config"]
if(tc != null && tc != "default")
if(!islist(tc))
log_world("transition_config is not a list!")
return
traits = json["traits"]
// "traits": [{"Linkage": "Cross"}, {"Space Ruins": true}]
if (islist(traits))
// "Station" is set by default, but it's assumed if you're setting
// traits you want to customize which level is cross-linked
for (var/level in traits)
if (!(ZTRAIT_STATION in level))
level[ZTRAIT_STATION] = TRUE
// "traits": null or absent -> default
else if (!isnull(traits))
log_world("map_config traits is not a list!")
return
for(var/I in tc)
if(isnull(TransitionStringToEnum(I)))
log_world("Invalid transition_config option: [I]!")
if(isnull(TransitionStringToEnum(tc[I])))
log_world("Invalid transition_config option: [I]!")
if ("minetype" in json)
minetype = json["minetype"]
allow_custom_shuttles = json["allow_custom_shuttles"] != FALSE
defaulted = FALSE
return TRUE
#undef CHECK_EXISTS
/datum/map_config/proc/TransitionStringToEnum(string)
switch(string)
if("CROSSLINKED")
return CROSSLINKED
if("SELFLOOPING")
return SELFLOOPING
if("UNAFFECTED")
return UNAFFECTED
if("MAIN_STATION")
return MAIN_STATION
if("CENTCOM")
return CENTCOM
if("CITY_OF_COGS")
return CITY_OF_COGS
if("MINING")
return MINING
if("EMPTY_AREA_1")
return EMPTY_AREA_1
if("EMPTY_AREA_2")
return EMPTY_AREA_2
if("EMPTY_AREA_3")
return EMPTY_AREA_3
if("EMPTY_AREA_4")
return EMPTY_AREA_4
if("EMPTY_AREA_5")
return EMPTY_AREA_5
if("EMPTY_AREA_6")
return EMPTY_AREA_6
if("EMPTY_AREA_7")
return EMPTY_AREA_7
if("EMPTY_AREA_8")
return EMPTY_AREA_8
/datum/map_config/proc/GetFullMapPath(mp = map_path, mf = map_file)
return "_maps/[mp]/[mf]"
/datum/map_config/proc/GetFullMapPaths()
if (istext(map_file))
return list("_maps/[map_path]/[map_file]")
. = list()
for (var/file in map_file)
. += "_maps/[map_path]/[file]"
/datum/map_config/proc/MakeNextMap()
return config_filename == "data/next_map.json" || fcopy(config_filename, "data/next_map.json")
+5 -4
View File
@@ -35,19 +35,20 @@
/obj/structure/ladder/LateInitialize()
// By default, discover ladders above and below us vertically
var/turf/T = get_turf(src)
var/obj/structure/ladder/L
if (!down)
for (var/obj/structure/ladder/L in locate(T.x, T.y, T.z - 1))
L = locate() in SSmapping.get_turf_below(T)
if (L)
down = L
L.up = src // Don't waste effort looping the other way
L.update_icon()
break
if (!up)
for (var/obj/structure/ladder/L in locate(T.x, T.y, T.z + 1))
L = locate() in SSmapping.get_turf_above(T)
if (L)
up = L
L.down = src // Don't waste effort looping the other way
L.update_icon()
break
update_icon()
+1 -18
View File
@@ -11,7 +11,7 @@
/turf/open/chasm/Initialize()
. = ..()
AddComponent(/datum/component/chasm, null)
AddComponent(/datum/component/chasm, SSmapping.get_turf_below(src))
/turf/open/chasm/proc/set_target(turf/target)
GET_COMPONENT(chasm_component, /datum/component/chasm)
@@ -64,16 +64,6 @@
/turf/open/chasm/CanPass(atom/movable/mover, turf/target)
return 1
// Naive "down" which just subtracts a z-level
/turf/open/chasm/straight_down
baseturfs = /turf/open/chasm/straight_down
/turf/open/chasm/straight_down/Initialize()
. = ..()
set_target(locate(x, y, z - 1))
// Chasms for Lavaland, with planetary atmos and lava glow
/turf/open/chasm/lavaland
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
@@ -95,10 +85,3 @@
underlay_appearance.icon = 'icons/turf/floors.dmi'
underlay_appearance.icon_state = "dirt"
return TRUE
/turf/open/chasm/jungle/straight_down
baseturfs = /turf/open/chasm/jungle/straight_down
/turf/open/chasm/jungle/straight_down/Initialize(mapload)
. = ..()
set_target(locate(x, y, z - 1))
@@ -3,7 +3,7 @@
desc = "Upon closer examination, it's still dirt."
icon = 'icons/turf/floors.dmi'
icon_state = "dirt"
baseturfs = /turf/open/chasm/jungle/straight_down
baseturfs = /turf/open/chasm/jungle
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
planetary_atmos = TRUE
attachment_holes = FALSE
+4 -6
View File
@@ -40,12 +40,10 @@
var/min = 1+TRANSITIONEDGE
var/list/possible_transtitons = list()
var/k = 1
var/list/config_list = SSmapping.config.transition_config
for(var/a in config_list)
if(config_list[a] == CROSSLINKED) // Only pick z-levels connected to station space
possible_transtitons += k
k++
for(var/A in SSmapping.z_list)
var/datum/space_level/D = A
if (D.linkage == CROSSLINKED)
possible_transtitons += D.z_value
var/_z = pick(possible_transtitons)
//now select coordinates for a border turf
@@ -26,7 +26,7 @@
for(var/obj/machinery/atmospherics/components/unary/vent_pump/temp_vent in GLOB.machines)
if(QDELETED(temp_vent))
continue
if(temp_vent.loc.z == ZLEVEL_STATION_PRIMARY && !temp_vent.welded)
if(temp_vent.loc.z == SSmapping.station_start && !temp_vent.welded)
var/datum/pipeline/temp_vent_parent = temp_vent.parents[1]
if(temp_vent_parent.other_atmosmch.len > 20)
vents += temp_vent
+1 -1
View File
@@ -60,7 +60,7 @@
var/datum/map_template/pirate_event_ship/ship = new
var/x = rand(TRANSITIONEDGE,world.maxx - TRANSITIONEDGE - ship.width)
var/y = rand(TRANSITIONEDGE,world.maxy - TRANSITIONEDGE - ship.height)
var/z = ZLEVEL_EMPTY_SPACE
var/z = SSmapping.empty_space.z_value
var/turf/T = locate(x,y,z)
if(!T)
CRASH("Pirate event found no turf to load in")
+1 -1
View File
@@ -52,7 +52,7 @@
var/x = round((world.maxx - width)/2)
var/y = round((world.maxy - height)/2)
var/datum/space_level/level = SSmapping.add_new_zlevel(name, UNAFFECTED, list(ZTRAIT_AWAY = TRUE))
var/datum/space_level/level = SSmapping.add_new_zlevel(name, list(ZTRAIT_AWAY = TRUE))
var/list/bounds = maploader.load_map(file(mappath), x, y, level.z_value, no_changeturf=(SSatoms.initialized == INITIALIZATION_INSSATOMS), placeOnTop=TRUE)
if(!bounds)
return FALSE
+1 -1
View File
@@ -94,7 +94,7 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new)
var/zcrd = text2num(dmmRegex.group[5]) + z_offset - 1
var/zexpansion = zcrd > world.maxz
if(zexpansion)
if(zexpansion && !measureOnly)
if(cropMap)
continue
else
@@ -1,5 +1,5 @@
/datum/space_level
var/name = "Your config settings failed, you need to fix this for the datum space levels to work"
var/name = "NAME MISSING"
var/list/neigbours = list()
var/list/traits
var/z_value = 1 //actual z placement
@@ -7,8 +7,8 @@
var/xi
var/yi //imaginary placements on the grid
/datum/space_level/New(new_z, new_name, new_linkage = SELFLOOPING, list/new_traits = list())
/datum/space_level/New(new_z, new_name, list/new_traits = list())
z_value = new_z
name = new_name
traits = new_traits
set_linkage(new_linkage)
set_linkage(new_traits[ZTRAIT_LINKAGE])
@@ -1,9 +1,8 @@
/datum/space_level/proc/set_linkage(new_linkage)
linkage = new_linkage
if(linkage == SELFLOOPING)
neigbours = list()
var/list/L = list(TEXT_NORTH,TEXT_SOUTH,TEXT_EAST,TEXT_WEST)
for(var/A in L)
neigbours = list(TEXT_NORTH,TEXT_SOUTH,TEXT_EAST,TEXT_WEST)
for(var/A in neigbours)
neigbours[A] = src
/datum/space_level/proc/set_neigbours(list/L)
@@ -1,15 +1,19 @@
// Look up levels[z].traits[trait]
/datum/controller/subsystem/mapping/proc/level_trait(z, trait)
if (!z)
if (!isnum(z) || z < 1)
return null
var/list/trait_list
if (z_list)
if (z > z_list.len)
stack_trace("Unmanaged z-level [z]! maxz = [world.maxz], z_list.len = [z_list.len]")
return list()
var/datum/space_level/S = get_level(z)
trait_list = S.traits
return S.traits[trait]
else
var/list/default_map_traits = DEFAULT_MAP_TRAITS
trait_list = default_map_traits[z][DL_TRAITS]
return trait_list[trait]
var/list/default = DEFAULT_MAP_TRAITS
if (z > default.len)
stack_trace("Unmanaged z-level [z]! maxz = [world.maxz], default.len = [default.len]")
return list()
return default[z][DL_TRAITS][trait]
// Check if levels[z] has any of the specified traits
/datum/controller/subsystem/mapping/proc/level_has_any_trait(z, list/traits)
@@ -45,6 +49,24 @@
. += S.z_value
break
// Attempt to get the turf below the provided one according to Z traits
/datum/controller/subsystem/mapping/proc/get_turf_below(turf/T)
if (!T)
return
var/offset = level_trait(T.z, ZTRAIT_DOWN)
if (!offset)
return
return locate(T.x, T.y, T.z + offset)
// Attempt to get the turf above the provided one according to Z traits
/datum/controller/subsystem/mapping/proc/get_turf_above(turf/T)
if (!T)
return
var/offset = level_trait(T.z, ZTRAIT_UP)
if (!offset)
return
return locate(T.x, T.y, T.z + offset)
// Prefer not to use this one too often
/datum/controller/subsystem/mapping/proc/get_station_center()
var/station_z = levels_by_trait(ZTRAIT_STATION)[1]
@@ -13,20 +13,20 @@
for (var/I in 1 to default_map_traits.len)
var/list/features = default_map_traits[I]
var/datum/space_level/S = new(I, features[DL_NAME], features[DL_LINKAGE], features[DL_TRAITS])
var/datum/space_level/S = new(I, features[DL_NAME], features[DL_TRAITS])
z_list += S
/datum/controller/subsystem/mapping/proc/add_new_zlevel(name, linkage = SELFLOOPING, traits = list(), z_type = /datum/space_level)
/datum/controller/subsystem/mapping/proc/add_new_zlevel(name, traits = list(), z_type = /datum/space_level)
var/new_z = z_list.len + 1
if (world.maxz < new_z)
world.incrementMaxZ()
CHECK_TICK
// TODO: sleep here if the Z level needs to be cleared
var/datum/space_level/S = new z_type(new_z, name, linkage, traits)
var/datum/space_level/S = new z_type(new_z, name, traits)
z_list += S
return S
/datum/controller/subsystem/mapping/proc/get_level(z)
. = z_list[z]
if (!.)
CRASH("Unmanaged z-level: '[z]'")
if (z_list && z >= 1 && z <= z_list.len)
return z_list[z]
CRASH("Unmanaged z-level [z]! maxz = [world.maxz], z_list.len = [z_list ? z_list.len : "null"]")
@@ -20,11 +20,15 @@
if(!istype(mother, /datum/mapGenerator/repair/reload_station_map))
return
var/datum/mapGenerator/repair/reload_station_map/mother1 = mother
if(!is_station_level(mother1.z))
return //This is only for reloading station blocks!
GLOB.reloading_map = TRUE
var/static/dmm_suite/reloader = new
var/list/bounds = reloader.load_map(file(SSmapping.config.GetFullMapPath()),measureOnly = FALSE, no_changeturf = FALSE,x_offset = 0, y_offset = 0, z_offset = ZLEVEL_STATION_PRIMARY, cropMap=TRUE, lower_crop_x = mother1.x_low, lower_crop_y = mother1.y_low, upper_crop_x = mother1.x_high, upper_crop_y = mother1.y_high)
// This is kind of finicky on multi-Z maps but the reader would need to be
// changed to allow Z cropping and that's a mess
var/z_offset = SSmapping.station_start
var/list/bounds
for (var/path in SSmapping.config.GetFullMapPaths())
bounds = reloader.load_map(file(path), measureOnly = FALSE, no_changeturf = FALSE,x_offset = 0, y_offset = 0, z_offset = z_offset, cropMap=TRUE, lower_crop_x = mother1.x_low, lower_crop_y = mother1.y_low, upper_crop_x = mother1.x_high, upper_crop_y = mother1.y_high)
z_offset += bounds[MAP_MAXZ] - bounds[MAP_MINZ] + 1
var/list/obj/machinery/atmospherics/atmos_machines = list()
var/list/obj/structure/cable/cables = list()
@@ -32,8 +36,8 @@
repopulate_sorted_areas()
for(var/L in block(locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]),
locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ])))
for(var/L in block(locate(bounds[MAP_MINX], bounds[MAP_MINY], SSmapping.station_start),
locate(bounds[MAP_MAXX], bounds[MAP_MAXY], z_offset - 1)))
set waitfor = FALSE
var/turf/B = L
atoms += B
@@ -93,7 +97,7 @@
y_low = min(start.y, end.y)
x_high = max(start.x, end.x)
y_high = max(start.y, end.y)
z = ZLEVEL_STATION_PRIMARY
z = SSmapping.station_start
GLOBAL_VAR_INIT(reloading_map, FALSE)
@@ -100,9 +100,16 @@
/obj/structure/mirror/magic/pride/curse(mob/user)
user.visible_message("<span class='danger'><B>The ground splits beneath [user] as [user.p_their()] hand leaves the mirror!</B></span>", \
"<span class='notice'>Perfect. Much better! Now <i>nobody</i> will be able to resist yo-</span>")
var/turf/T = get_turf(user)
T.ChangeTurf(/turf/open/chasm/straight_down)
var/list/levels = SSmapping.levels_by_trait(ZTRAIT_SPACE_RUINS)
var/turf/dest
if (levels.len)
dest = locate(T.x, T.y, pick(levels))
T.ChangeTurf(/turf/open/chasm)
var/turf/open/chasm/C = T
C.set_target(dest)
C.drop(user)
//can't be bothered to do sloth right now, will make later