mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-11 10:11:09 +00:00
Support stations with multiple z-levels (#35339)
* Remove ZLEVEL_STATION_PRIMARY * Add Up and Down traits for use by ladders and chasms * Give map_config creation its own proc * Combine LoadConfig and ValidateJSON and remove transition_config * Make space linkage a z-level trait * Remove ZLEVEL_EMPTY_SPACE * Update uses of GetFullMapPath * Handle multi-Z stations and load Lavaland and Reebe at runtime * Remove unused space maps * Fix inappropriate z-expansion in map reader, improve logging * Update comments relating to z-level configuration * Add Lavaland and Reebe to ALL_MAPS
This commit is contained in:
@@ -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
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user