mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-26 06:29:23 +01:00
[MIRROR] Multi-Z Support for Lazy Templates | Cleans up some turf flag misuse [MDB IGNORE] (#23794)
* Multi-Z Support for Lazy Templates | Cleans up some turf flag misuse * Update hilbertshotel.dm * Modular proc ref --------- Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com>
This commit is contained in:
co-authored by
Zephyr
Bloop
parent
4fa7c51670
commit
d9624bdf97
@@ -133,7 +133,15 @@
|
||||
var/y = round((world.maxy - height) * 0.5) + 1
|
||||
|
||||
var/datum/space_level/level = SSmapping.add_new_zlevel(name, secret ? ZTRAITS_AWAY_SECRET : ZTRAITS_AWAY, contain_turfs = FALSE)
|
||||
var/datum/parsed_map/parsed = load_map(file(mappath), x, y, level.z_value, no_changeturf=(SSatoms.initialized == INITIALIZATION_INSSATOMS), placeOnTop=should_place_on_top, new_z = TRUE)
|
||||
var/datum/parsed_map/parsed = load_map(
|
||||
file(mappath),
|
||||
x,
|
||||
y,
|
||||
level.z_value,
|
||||
no_changeturf = (SSatoms.initialized == INITIALIZATION_INSSATOMS),
|
||||
place_on_top = should_place_on_top,
|
||||
new_z = TRUE,
|
||||
)
|
||||
var/list/bounds = parsed.bounds
|
||||
if(!bounds)
|
||||
return FALSE
|
||||
@@ -177,7 +185,14 @@
|
||||
|
||||
UNSETEMPTY(turf_blacklist)
|
||||
parsed.turf_blacklist = turf_blacklist
|
||||
if(!parsed.load(T.x, T.y, T.z, cropMap=TRUE, no_changeturf=(SSatoms.initialized == INITIALIZATION_INSSATOMS), placeOnTop=should_place_on_top))
|
||||
if(!parsed.load(
|
||||
T.x,
|
||||
T.y,
|
||||
T.z,
|
||||
crop_map = TRUE,
|
||||
no_changeturf = (SSatoms.initialized == INITIALIZATION_INSSATOMS),
|
||||
place_on_top = should_place_on_top,
|
||||
))
|
||||
return
|
||||
|
||||
var/list/bounds = parsed.bounds
|
||||
|
||||
+159
-54
@@ -114,26 +114,72 @@
|
||||
var/turfsSkipped = 0
|
||||
#endif
|
||||
|
||||
/datum/parsed_map/proc/copy()
|
||||
// Avoids duped work just in case
|
||||
build_cache()
|
||||
var/datum/parsed_map/newfriend = new()
|
||||
newfriend.original_path = original_path
|
||||
newfriend.map_format = map_format
|
||||
newfriend.key_len = key_len
|
||||
newfriend.line_len = line_len
|
||||
newfriend.grid_models = grid_models.Copy()
|
||||
newfriend.gridSets = gridSets.Copy()
|
||||
newfriend.modelCache = modelCache.Copy()
|
||||
newfriend.parsed_bounds = parsed_bounds.Copy()
|
||||
// Copy parsed bounds to reset to initial values
|
||||
newfriend.bounds = parsed_bounds.Copy()
|
||||
newfriend.turf_blacklist = turf_blacklist?.Copy()
|
||||
return newfriend
|
||||
|
||||
//text trimming (both directions) helper macro
|
||||
#define TRIM_TEXT(text) (trim_reduced(text))
|
||||
|
||||
/// Shortcut function to parse a map and apply it to the world.
|
||||
///
|
||||
/// - `dmm_file`: A .dmm file to load (Required).
|
||||
/// - `x_offset`, `y_offset`, `z_offset`: Positions representign where to load the map (Optional).
|
||||
/// - `cropMap`: When true, the map will be cropped to fit the existing world dimensions (Optional).
|
||||
/// - `measureOnly`: When true, no changes will be made to the world (Optional).
|
||||
/// - `no_changeturf`: When true, [/turf/proc/AfterChange] won't be called on loaded turfs
|
||||
/// - `x_lower`, `x_upper`, `y_lower`, `y_upper`: Coordinates (relative to the map) to crop to (Optional).
|
||||
/// - `placeOnTop`: Whether to use [/turf/proc/PlaceOnTop] rather than [/turf/proc/ChangeTurf] (Optional).
|
||||
/proc/load_map(dmm_file as file, x_offset as num, y_offset as num, z_offset as num, cropMap as num, measureOnly as num, no_changeturf as num, x_lower = -INFINITY as num, x_upper = INFINITY as num, y_lower = -INFINITY as num, y_upper = INFINITY as num, placeOnTop = FALSE as num, new_z)
|
||||
var/datum/parsed_map/parsed = new(dmm_file, x_lower, x_upper, y_lower, y_upper, measureOnly)
|
||||
if(parsed.bounds && !measureOnly)
|
||||
parsed.load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, new_z = new_z)
|
||||
return parsed
|
||||
/**
|
||||
* Helper and recommened way to load a map file
|
||||
* - dmm_file: The path to the map file
|
||||
* - x_offset: The x offset to load the map at
|
||||
* - y_offset: The y offset to load the map at
|
||||
* - z_offset: The z offset to load the map at
|
||||
* - crop_map: If true, the map will be cropped to the world bounds
|
||||
* - measure_only: If true, the map will not be loaded, but the bounds will be calculated
|
||||
* - no_changeturf: If true, the map will not call /turf/AfterChange
|
||||
* - x_lower: The minimum x coordinate to load
|
||||
* - x_upper: The maximum x coordinate to load
|
||||
* - y_lower: The minimum y coordinate to load
|
||||
* - y_upper: The maximum y coordinate to load
|
||||
* - z_lower: The minimum z coordinate to load
|
||||
* - z_upper: The maximum z coordinate to load
|
||||
* - place_on_top: Whether to use /turf/proc/PlaceOnTop rather than /turf/proc/ChangeTurf
|
||||
* - new_z: If true, a new z level will be created for the map
|
||||
*/
|
||||
/proc/load_map(
|
||||
dmm_file,
|
||||
x_offset = 0,
|
||||
y_offset = 0,
|
||||
z_offset = 0,
|
||||
crop_map = FALSE,
|
||||
measure_only = FALSE,
|
||||
no_changeturf = FALSE,
|
||||
x_lower = -INFINITY,
|
||||
x_upper = INFINITY,
|
||||
y_lower = -INFINITY,
|
||||
y_upper = INFINITY,
|
||||
z_lower = -INFINITY,
|
||||
z_upper = INFINITY,
|
||||
place_on_top = FALSE,
|
||||
new_z = FALSE,
|
||||
)
|
||||
if(!(dmm_file in GLOB.cached_maps))
|
||||
GLOB.cached_maps[dmm_file] = new /datum/parsed_map(dmm_file)
|
||||
|
||||
var/datum/parsed_map/parsed_map = GLOB.cached_maps[dmm_file]
|
||||
parsed_map = parsed_map.copy()
|
||||
if(!measure_only && !isnull(parsed_map.bounds))
|
||||
parsed_map.load(x_offset, y_offset, z_offset, crop_map, no_changeturf, x_lower, x_upper, y_lower, y_upper, z_lower, z_upper, place_on_top, new_z)
|
||||
return parsed_map
|
||||
|
||||
/// Parse a map, possibly cropping it.
|
||||
/datum/parsed_map/New(tfile, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper=INFINITY, measureOnly=FALSE)
|
||||
/datum/parsed_map/New(tfile, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper=INFINITY, z_lower = -INFINITY, z_upper=INFINITY, measureOnly=FALSE)
|
||||
// This proc sleeps for like 6 seconds. why?
|
||||
// Is it file accesses? if so, can those be done ahead of time, async to save on time here? I wonder.
|
||||
// Love ya :)
|
||||
@@ -184,20 +230,26 @@
|
||||
CRASH("Coords before model definition in DMM")
|
||||
|
||||
var/curr_x = text2num(regexOutput[3])
|
||||
|
||||
if(curr_x < x_lower || curr_x > x_upper)
|
||||
continue
|
||||
|
||||
var/curr_y = text2num(regexOutput[4])
|
||||
if(curr_y < y_lower || curr_y > y_upper)
|
||||
continue
|
||||
|
||||
var/curr_z = text2num(regexOutput[5])
|
||||
if(curr_z < z_lower || curr_z > z_upper)
|
||||
continue
|
||||
|
||||
var/datum/grid_set/gridSet = new
|
||||
|
||||
gridSet.xcrd = curr_x
|
||||
//position of the currently processed square
|
||||
gridSet.ycrd = text2num(regexOutput[4])
|
||||
gridSet.zcrd = text2num(regexOutput[5])
|
||||
gridSet.ycrd = curr_y
|
||||
gridSet.zcrd = curr_z
|
||||
|
||||
bounds[MAP_MINX] = min(bounds[MAP_MINX], curr_x)
|
||||
bounds[MAP_MINZ] = min(bounds[MAP_MINZ], gridSet.zcrd)
|
||||
bounds[MAP_MAXZ] = max(bounds[MAP_MAXZ], gridSet.zcrd)
|
||||
bounds[MAP_MINZ] = min(bounds[MAP_MINZ], curr_y)
|
||||
bounds[MAP_MAXZ] = max(bounds[MAP_MAXZ], curr_z)
|
||||
|
||||
var/list/gridLines = splittext(regexOutput[6], "\n")
|
||||
gridSet.gridLines = gridLines
|
||||
@@ -238,16 +290,29 @@
|
||||
bounds[MAP_MAXX] = clamp(bounds[MAP_MAXX], x_lower, x_upper)
|
||||
bounds[MAP_MINY] = clamp(bounds[MAP_MINY], y_lower, y_upper)
|
||||
bounds[MAP_MAXY] = clamp(bounds[MAP_MAXY], y_lower, y_upper)
|
||||
bounds[MAP_MINZ] = clamp(bounds[MAP_MINZ], z_lower, z_upper)
|
||||
bounds[MAP_MAXZ] = clamp(bounds[MAP_MAXZ], z_lower, z_upper)
|
||||
|
||||
parsed_bounds = src.bounds
|
||||
src.key_len = key_len
|
||||
src.line_len = line_len
|
||||
|
||||
/// Load the parsed map into the world. See [/proc/load_map] for arguments.
|
||||
/datum/parsed_map/proc/load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, whitelist = FALSE, new_z)
|
||||
/// Iterates over all grid sets and returns ones with z values within the given bounds. Inclusive
|
||||
/datum/parsed_map/proc/filter_grid_sets_based_on_z_bounds(lower_z, upper_z)
|
||||
var/list/filtered_sets = list()
|
||||
for(var/datum/grid_set/grid_set as anything in gridSets)
|
||||
if(grid_set.zcrd < lower_z)
|
||||
continue
|
||||
if(grid_set.zcrd > upper_z)
|
||||
continue
|
||||
filtered_sets += grid_set
|
||||
return filtered_sets
|
||||
|
||||
/// Load the parsed map into the world. You probably want [/proc/load_map]. Keep the signature the same.
|
||||
/datum/parsed_map/proc/load(x_offset = 0, y_offset = 0, z_offset = 0, crop_map = FALSE, no_changeturf = FALSE, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper = INFINITY, z_lower = -INFINITY, z_upper = INFINITY, place_on_top = FALSE, new_z = FALSE)
|
||||
//How I wish for RAII
|
||||
Master.StartLoadingMap()
|
||||
. = _load_impl(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, new_z)
|
||||
. = _load_impl(x_offset, y_offset, z_offset, crop_map, no_changeturf, x_lower, x_upper, y_lower, y_upper, z_lower, z_upper, place_on_top, new_z)
|
||||
Master.StopLoadingMap()
|
||||
|
||||
#define MAPLOADING_CHECK_TICK \
|
||||
@@ -262,7 +327,7 @@
|
||||
}
|
||||
|
||||
// Do not call except via load() above.
|
||||
/datum/parsed_map/proc/_load_impl(x_offset = 1, y_offset = 1, z_offset = world.maxz + 1, cropMap = FALSE, no_changeturf = FALSE, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper = INFINITY, placeOnTop = FALSE, new_z = FALSE)
|
||||
/datum/parsed_map/proc/_load_impl(x_offset, y_offset, z_offset, crop_map, no_changeturf, x_lower, x_upper, y_lower, y_upper, z_lower, z_upper, place_on_top, new_z)
|
||||
PRIVATE_PROC(TRUE)
|
||||
// Tell ss atoms that we're doing maploading
|
||||
// We'll have to account for this in the following tick_checks so it doesn't overflow
|
||||
@@ -275,9 +340,9 @@
|
||||
var/sucessful = FALSE
|
||||
switch(map_format)
|
||||
if(MAP_TGM)
|
||||
sucessful = _tgm_load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, new_z)
|
||||
sucessful = _tgm_load(x_offset, y_offset, z_offset, crop_map, no_changeturf, x_lower, x_upper, y_lower, y_upper, z_lower, z_upper, place_on_top, new_z)
|
||||
else
|
||||
sucessful = _dmm_load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, new_z)
|
||||
sucessful = _dmm_load(x_offset, y_offset, z_offset, crop_map, no_changeturf, x_lower, x_upper, y_lower, y_upper, z_lower, z_upper, place_on_top, new_z)
|
||||
|
||||
// And we are done lads, call it off
|
||||
SSatoms.map_loader_stop(REF(src))
|
||||
@@ -309,7 +374,7 @@
|
||||
// In the tgm format, each gridset contains 255 lines, each line representing one tile, with 255 total gridsets
|
||||
// In the dmm format, each gridset contains 255 lines, each line representing one row of tiles, containing 255 * line length characters, with one gridset per z
|
||||
// You can think of dmm as storing maps in rows, whereas tgm stores them in columns
|
||||
/datum/parsed_map/proc/_tgm_load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, new_z)
|
||||
/datum/parsed_map/proc/_tgm_load(x_offset, y_offset, z_offset, crop_map, no_changeturf, x_lower, x_upper, y_lower, y_upper, z_lower, z_upper, place_on_top, new_z)
|
||||
// setup
|
||||
var/list/modelCache = build_cache(no_changeturf)
|
||||
var/space_key = modelCache[SPACE_KEY]
|
||||
@@ -330,12 +395,12 @@
|
||||
var/relative_y = first_column.ycrd
|
||||
var/highest_y = relative_y + y_relative_to_absolute
|
||||
|
||||
if(!cropMap && highest_y > world.maxy)
|
||||
if(!crop_map && highest_y > world.maxy)
|
||||
if(new_z)
|
||||
// Need to avoid improperly loaded area/turf_contents
|
||||
world.increaseMaxY(highest_y, max_zs_to_load = z_offset - 1)
|
||||
world.increase_max_y(highest_y, map_load_z_cutoff = z_offset - 1)
|
||||
else
|
||||
world.increaseMaxY(highest_y)
|
||||
world.increase_max_y(highest_y)
|
||||
expanded_y = TRUE
|
||||
|
||||
// Skip Y coords that are above the smallest of the three params
|
||||
@@ -345,7 +410,6 @@
|
||||
var/y_starting_skip = relative_y - y_skip_above
|
||||
highest_y -= y_starting_skip
|
||||
|
||||
|
||||
// Y is the LOWEST it will ever be here, so we can easily set a threshold for how low to go
|
||||
var/line_count = length(first_column.gridLines)
|
||||
var/lowest_y = relative_y - (line_count - 1) // -1 because we decrement at the end of the loop, not the start
|
||||
@@ -353,7 +417,7 @@
|
||||
|
||||
// X setup
|
||||
var/x_delta_with = x_upper
|
||||
if(cropMap)
|
||||
if(crop_map)
|
||||
// Take our smaller crop threshold yes?
|
||||
x_delta_with = min(x_delta_with, world.maxx)
|
||||
|
||||
@@ -367,33 +431,51 @@
|
||||
// If our relative x is greater then X upper, well then we've gotta limit our expansion
|
||||
var/delta = max(final_x - x_delta_with, 0)
|
||||
final_x -= delta
|
||||
if(final_x > world.maxx && !cropMap)
|
||||
if(final_x > world.maxx && !crop_map)
|
||||
if(new_z)
|
||||
// Need to avoid improperly loaded area/turf_contents
|
||||
world.increaseMaxX(final_x, max_zs_to_load = z_offset - 1)
|
||||
world.increase_max_x(final_x, map_load_z_cutoff = z_offset - 1)
|
||||
else
|
||||
world.increaseMaxX(final_x)
|
||||
world.increase_max_x(final_x)
|
||||
expanded_x = TRUE
|
||||
|
||||
var/lowest_x = max(x_lower, 1 - x_relative_to_absolute)
|
||||
|
||||
// Amount we offset the grid zcrd to get the true zcrd
|
||||
var/grid_z_offset = z_offset - 1
|
||||
var/z_upper_set = z_upper < INFINITY
|
||||
var/z_lower_set = z_lower > -INFINITY
|
||||
|
||||
// We make the assumption that the last block of turfs will have the highest embedded z in it
|
||||
var/highest_z = last_column.zcrd + z_offset - 1 // Lets not just make a new z level each time we increment maxz
|
||||
// true max zcrd
|
||||
var/map_bounds_z_max = last_column.zcrd
|
||||
var/z_upper_parsed = map_bounds_z_max + z_offset - 1
|
||||
if(z_upper_set)
|
||||
z_upper_parsed -= map_bounds_z_max - z_upper
|
||||
if(z_lower_set)
|
||||
var/offset_amount = z_lower - 1
|
||||
z_upper_parsed -= offset_amount
|
||||
grid_z_offset -= offset_amount
|
||||
|
||||
var/list/target_grid_sets = gridSets
|
||||
if(z_lower_set || z_upper_set) // bounds are set, filter out gridsets for z levels we don't want
|
||||
target_grid_sets = filter_grid_sets_based_on_z_bounds(z_lower, z_upper)
|
||||
|
||||
var/z_threshold = world.maxz
|
||||
if(highest_z > z_threshold && cropMap)
|
||||
for(var/i in z_threshold + 1 to highest_z) //create a new z_level if needed
|
||||
if(z_upper_parsed > z_threshold && crop_map)
|
||||
for(var/i in z_threshold + 1 to z_upper_parsed) //create a new z_level if needed
|
||||
world.incrementMaxZ()
|
||||
if(!no_changeturf)
|
||||
WARNING("Z-level expansion occurred without no_changeturf set, this may cause problems when /turf/AfterChange is called")
|
||||
|
||||
for(var/datum/grid_set/gset as anything in gridSets)
|
||||
for(var/datum/grid_set/gset as anything in target_grid_sets)
|
||||
var/true_xcrd = gset.xcrd + x_relative_to_absolute
|
||||
|
||||
// any cutoff of x means we just shouldn't iterate this gridset
|
||||
if(final_x < true_xcrd || lowest_x > gset.xcrd)
|
||||
continue
|
||||
|
||||
var/zcrd = gset.zcrd + z_offset - 1
|
||||
var/zcrd = gset.zcrd + grid_z_offset
|
||||
// If we're using changeturf, we disable it if we load into a z level we JUST created
|
||||
var/no_afterchange = no_changeturf || zcrd > z_threshold
|
||||
|
||||
@@ -420,7 +502,7 @@
|
||||
if(!cache)
|
||||
SSatoms.map_loader_stop(REF(src))
|
||||
CRASH("Undefined model key in DMM: [gset.gridLines[i]]")
|
||||
build_coordinate(cache, locate(true_xcrd, ycrd, zcrd), no_afterchange, placeOnTop, new_z)
|
||||
build_coordinate(cache, locate(true_xcrd, ycrd, zcrd), no_afterchange, place_on_top, new_z)
|
||||
|
||||
// only bother with bounds that actually exist
|
||||
if(!first_found)
|
||||
@@ -444,7 +526,7 @@
|
||||
/// Stanrdard loading, not used in production
|
||||
/// Doesn't take advantage of any tgm optimizations, which makes it slower but also more general
|
||||
/// Use this if for some reason your map format is messy
|
||||
/datum/parsed_map/proc/_dmm_load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, new_z)
|
||||
/datum/parsed_map/proc/_dmm_load(x_offset, y_offset, z_offset, crop_map, no_changeturf, x_lower, x_upper, y_lower, y_upper, z_lower, z_upper, place_on_top, new_z)
|
||||
// setup
|
||||
var/list/modelCache = build_cache(no_changeturf)
|
||||
var/space_key = modelCache[SPACE_KEY]
|
||||
@@ -455,23 +537,46 @@
|
||||
var/y_relative_to_absolute = y_offset - 1
|
||||
var/x_relative_to_absolute = x_offset - 1
|
||||
var/line_len = src.line_len
|
||||
for(var/datum/grid_set/gset as anything in gridSets)
|
||||
|
||||
// Amount we offset the grid zcrd to get the true zcrd
|
||||
var/grid_z_offset = z_offset - 1
|
||||
var/z_upper_set = z_upper < INFINITY
|
||||
var/z_lower_set = z_lower > -INFINITY
|
||||
|
||||
// we now need to find the maximum z, fun!
|
||||
var/map_bounds_z_max = 1
|
||||
for(var/datum/grid_set/grid_set as anything in gridSets)
|
||||
map_bounds_z_max = max(map_bounds_z_max, grid_set.zcrd)
|
||||
|
||||
var/z_upper_parsed = map_bounds_z_max + z_offset - 1
|
||||
if(z_upper_set)
|
||||
z_upper_parsed -= map_bounds_z_max - z_upper
|
||||
if(z_lower_set)
|
||||
var/offset_amount = z_lower - 1
|
||||
z_upper_parsed -= offset_amount
|
||||
grid_z_offset -= offset_amount
|
||||
|
||||
var/list/target_grid_sets = gridSets
|
||||
if(z_lower_set || z_upper_set) // bounds are set, filter out gridsets for z levels we don't want
|
||||
target_grid_sets = filter_grid_sets_based_on_z_bounds(z_lower, z_upper)
|
||||
|
||||
for(var/datum/grid_set/gset as anything in target_grid_sets)
|
||||
var/relative_x = gset.xcrd
|
||||
var/relative_y = gset.ycrd
|
||||
var/true_xcrd = relative_x + x_relative_to_absolute
|
||||
var/ycrd = relative_y + y_relative_to_absolute
|
||||
var/zcrd = gset.zcrd + z_offset - 1
|
||||
if(!cropMap && ycrd > world.maxy)
|
||||
var/zcrd = gset.zcrd + grid_z_offset
|
||||
if(!crop_map && ycrd > world.maxy)
|
||||
if(new_z)
|
||||
// Need to avoid improperly loaded area/turf_contents
|
||||
world.increaseMaxY(ycrd, max_zs_to_load = z_offset - 1)
|
||||
world.increase_max_y(ycrd, map_load_z_cutoff = z_offset - 1)
|
||||
else
|
||||
world.increaseMaxY(ycrd)
|
||||
world.increase_max_y(ycrd)
|
||||
expanded_y = TRUE
|
||||
var/zexpansion = zcrd > world.maxz
|
||||
var/no_afterchange = no_changeturf
|
||||
if(zexpansion)
|
||||
if(cropMap)
|
||||
if(crop_map)
|
||||
continue
|
||||
else
|
||||
while (zcrd > world.maxz) //create a new z_level if needed
|
||||
@@ -508,7 +613,7 @@
|
||||
var/x_step_count = ROUND_UP(x_target / key_len)
|
||||
var/final_x = relative_x + (x_step_count - 1)
|
||||
var/x_delta_with = x_upper
|
||||
if(cropMap)
|
||||
if(crop_map)
|
||||
// Take our smaller crop threshold yes?
|
||||
x_delta_with = min(x_delta_with, world.maxx)
|
||||
if(final_x > x_delta_with)
|
||||
@@ -517,12 +622,12 @@
|
||||
x_step_count -= delta
|
||||
final_x -= delta
|
||||
x_target = x_step_count * key_len
|
||||
if(final_x > world.maxx && !cropMap)
|
||||
if(final_x > world.maxx && !crop_map)
|
||||
if(new_z)
|
||||
// Need to avoid improperly loaded area/turf_contents
|
||||
world.increaseMaxX(final_x, max_zs_to_load = z_offset - 1)
|
||||
world.increase_max_x(final_x, map_load_z_cutoff = z_offset - 1)
|
||||
else
|
||||
world.increaseMaxX(final_x)
|
||||
world.increase_max_x(final_x)
|
||||
expanded_x = TRUE
|
||||
|
||||
// We're gonna track the first and last pairs of coords we find
|
||||
@@ -553,7 +658,7 @@
|
||||
if(!cache)
|
||||
SSatoms.map_loader_stop(REF(src))
|
||||
CRASH("Undefined model key in DMM: [model_key]")
|
||||
build_coordinate(cache, locate(xcrd, ycrd, zcrd), no_afterchange, placeOnTop, new_z)
|
||||
build_coordinate(cache, locate(xcrd, ycrd, zcrd), no_afterchange, place_on_top, new_z)
|
||||
|
||||
// only bother with bounds that actually exist
|
||||
if(!first_found)
|
||||
|
||||
@@ -51,10 +51,10 @@
|
||||
return central_turf
|
||||
|
||||
/datum/map_template/ruin/proc/place_on_isolated_level(z)
|
||||
var/datum/turf_reservation/reservation = SSmapping.RequestBlockReservation(width, height, z) //Make the new level creation work with different traits.
|
||||
var/datum/turf_reservation/reservation = SSmapping.request_turf_block_reservation(width, height, 1, z) //Make the new level creation work with different traits.
|
||||
if(!reservation)
|
||||
return
|
||||
var/turf/placement = locate(reservation.bottom_left_coords[1],reservation.bottom_left_coords[2],reservation.bottom_left_coords[3])
|
||||
var/turf/placement = reservation.bottom_left_turfs[1]
|
||||
load(placement)
|
||||
loaded++
|
||||
for(var/turf/T in get_affected_turfs(placement))
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/proc/get_step_multiz(ref, dir)
|
||||
var/turf/us = get_turf(ref)
|
||||
if(dir & UP)
|
||||
dir &= ~UP
|
||||
return get_step(GET_TURF_ABOVE(get_turf(ref)), dir)
|
||||
return get_step(GET_TURF_ABOVE(us), dir)
|
||||
if(dir & DOWN)
|
||||
dir &= ~DOWN
|
||||
return get_step(GET_TURF_BELOW(get_turf(ref)), dir)
|
||||
return get_step(GET_TURF_BELOW(us), dir)
|
||||
return get_step(ref, dir)
|
||||
|
||||
/proc/get_dir_multiz(turf/us, turf/them)
|
||||
@@ -15,27 +16,21 @@
|
||||
if(us.z == them.z)
|
||||
return get_dir(us, them)
|
||||
else
|
||||
var/turf/T = us.above()
|
||||
var/turf/T = GET_TURF_ABOVE(us)
|
||||
var/dir = NONE
|
||||
if(T && (T.z == them.z))
|
||||
dir = UP
|
||||
else
|
||||
T = us.below()
|
||||
T = GET_TURF_BELOW(us)
|
||||
if(T && (T.z == them.z))
|
||||
dir = DOWN
|
||||
else
|
||||
return get_dir(us, them)
|
||||
return (dir | get_dir(us, them))
|
||||
|
||||
/turf/proc/above()
|
||||
return GET_TURF_ABOVE(src)
|
||||
|
||||
/turf/proc/below()
|
||||
return GET_TURF_BELOW(src)
|
||||
|
||||
/proc/get_lowest_turf(atom/ref)
|
||||
var/turf/us = get_turf(ref)
|
||||
var/next = GET_TURF_BELOW(us)
|
||||
var/turf/next = GET_TURF_BELOW(us)
|
||||
while(next)
|
||||
us = next
|
||||
next = GET_TURF_BELOW(us)
|
||||
@@ -44,7 +39,7 @@
|
||||
// I wish this was lisp
|
||||
/proc/get_highest_turf(atom/ref)
|
||||
var/turf/us = get_turf(ref)
|
||||
var/next = GET_TURF_ABOVE(us)
|
||||
var/turf/next = GET_TURF_ABOVE(us)
|
||||
while(next)
|
||||
us = next
|
||||
next = GET_TURF_ABOVE(us)
|
||||
|
||||
@@ -1,16 +1,33 @@
|
||||
//Yes, they can only be rectangular.
|
||||
//Yes, I'm sorry.
|
||||
/datum/turf_reservation
|
||||
/// All turfs that we've reserved
|
||||
var/list/reserved_turfs = list()
|
||||
///Turfs around the reservation for cordoning
|
||||
|
||||
/// Turfs around the reservation for cordoning
|
||||
var/list/cordon_turfs = list()
|
||||
///Area of turfs next to the cordon to fill with pre_cordon_area's
|
||||
|
||||
/// Area of turfs next to the cordon to fill with pre_cordon_area's
|
||||
var/list/pre_cordon_turfs = list()
|
||||
|
||||
/// The width of the reservation
|
||||
var/width = 0
|
||||
|
||||
/// The height of the reservation
|
||||
var/height = 0
|
||||
var/bottom_left_coords[3]
|
||||
var/top_right_coords[3]
|
||||
|
||||
/// The z stack size of the reservation. Note that reservations are ALWAYS reserved from the bottom up
|
||||
var/z_size = 0
|
||||
|
||||
/// List of the bottom left turfs. Indexed by what their z index for this reservation is
|
||||
var/list/bottom_left_turfs = list()
|
||||
|
||||
/// List of the top right turfs. Indexed by what their z index for this reservation is
|
||||
var/list/top_right_turfs = list()
|
||||
|
||||
/// The turf type the reservation is initially made with
|
||||
var/turf_type = /turf/open/space
|
||||
|
||||
///Distance away from the cordon where we can put a "sort-cordon" and run some extra code (see make_repel). 0 makes nothing happen
|
||||
var/pre_cordon_distance = 0
|
||||
|
||||
@@ -19,6 +36,9 @@
|
||||
pre_cordon_distance = 7
|
||||
|
||||
/datum/turf_reservation/proc/Release()
|
||||
bottom_left_turfs.Cut()
|
||||
top_right_turfs.Cut()
|
||||
|
||||
var/list/reserved_copy = reserved_turfs.Copy()
|
||||
SSmapping.used_turfs -= reserved_turfs
|
||||
reserved_turfs = list()
|
||||
@@ -36,20 +56,20 @@
|
||||
INVOKE_ASYNC(SSmapping, TYPE_PROC_REF(/datum/controller/subsystem/mapping, reserve_turfs), release_turfs)
|
||||
|
||||
/// Attempts to calaculate and store a list of turfs around the reservation for cordoning. Returns whether a valid cordon was calculated
|
||||
/datum/turf_reservation/proc/calculate_cordon_turfs(turf/BL, turf/TR)
|
||||
if(BL.x < 2 || BL.y < 2 || TR.x > (world.maxx - 2) || TR.y > (world.maxy - 2))
|
||||
/datum/turf_reservation/proc/calculate_cordon_turfs(turf/bottom_left, turf/top_right)
|
||||
if(bottom_left.x < 2 || bottom_left.y < 2 || top_right.x > (world.maxx - 2) || top_right.y > (world.maxy - 2))
|
||||
return FALSE // no space for a cordon here
|
||||
|
||||
var/list/possible_turfs = CORNER_OUTLINE(BL, width, height)
|
||||
var/list/possible_turfs = CORNER_OUTLINE(bottom_left, width, height)
|
||||
// if they're our cordon turfs, accept them
|
||||
possible_turfs -= cordon_turfs
|
||||
for(var/turf/cordon_turf as anything in possible_turfs)
|
||||
if(!(cordon_turf.flags_1 & UNUSED_RESERVATION_TURF))
|
||||
if(!(cordon_turf.turf_flags & UNUSED_RESERVATION_TURF))
|
||||
return FALSE
|
||||
cordon_turfs = possible_turfs
|
||||
|
||||
pre_cordon_turfs.Cut()
|
||||
cordon_turfs |= possible_turfs
|
||||
|
||||
if(pre_cordon_distance)
|
||||
var/turf/offset_turf = locate(BL.x + pre_cordon_distance, BL.y + pre_cordon_distance, BL.z)
|
||||
var/turf/offset_turf = locate(bottom_left.x + pre_cordon_distance, bottom_left.y + pre_cordon_distance, bottom_left.z)
|
||||
var/list/to_add = CORNER_OUTLINE(offset_turf, width - pre_cordon_distance * 2, height - pre_cordon_distance * 2) //we step-by-stop move inwards from the outer cordon
|
||||
for(var/turf/turf_being_added as anything in to_add)
|
||||
pre_cordon_turfs |= turf_being_added //add one by one so we can filter out duplicates
|
||||
@@ -64,10 +84,11 @@
|
||||
old_area.turfs_to_uncontain += cordon_turf
|
||||
cordon_area.contained_turfs += cordon_turf
|
||||
cordon_area.contents += cordon_turf
|
||||
// Its no longer unused, but its also not "used"
|
||||
cordon_turf.turf_flags &= ~UNUSED_RESERVATION_TURF
|
||||
cordon_turf.ChangeTurf(/turf/cordon, /turf/cordon)
|
||||
|
||||
cordon_turf.flags_1 &= ~UNUSED_RESERVATION_TURF
|
||||
SSmapping.unused_turfs["[cordon_turf.z]"] -= cordon_turf
|
||||
// still gets linked to us though
|
||||
SSmapping.used_turfs[cordon_turf] = src
|
||||
|
||||
//swap the area with the pre-cordoning area
|
||||
@@ -113,7 +134,8 @@
|
||||
if(!HAS_TRAIT(enterer, TRAIT_FREE_HYPERSPACE_SOFTCORDON_MOVEMENT))
|
||||
space_dump(source, enterer)
|
||||
|
||||
/datum/turf_reservation/proc/Reserve(width, height, zlevel)
|
||||
/// Internal proc which handles reserving the area for the reservation.
|
||||
/datum/turf_reservation/proc/_reserve_area(width, height, zlevel)
|
||||
src.width = width
|
||||
src.height = height
|
||||
if(width > world.maxx || height > world.maxy || width < 1 || height < 1)
|
||||
@@ -126,12 +148,12 @@
|
||||
for(var/i in avail)
|
||||
CHECK_TICK
|
||||
BL = i
|
||||
if(!(BL.flags_1 & UNUSED_RESERVATION_TURF))
|
||||
if(!(BL.turf_flags & UNUSED_RESERVATION_TURF))
|
||||
continue
|
||||
if(BL.x + width > world.maxx || BL.y + height > world.maxy)
|
||||
continue
|
||||
TR = locate(BL.x + width - 1, BL.y + height - 1, BL.z)
|
||||
if(!(TR.flags_1 & UNUSED_RESERVATION_TURF))
|
||||
if(!(TR.turf_flags & UNUSED_RESERVATION_TURF))
|
||||
continue
|
||||
final = block(BL, TR)
|
||||
if(!final)
|
||||
@@ -139,7 +161,7 @@
|
||||
passing = TRUE
|
||||
for(var/I in final)
|
||||
var/turf/checking = I
|
||||
if(!(checking.flags_1 & UNUSED_RESERVATION_TURF))
|
||||
if(!(checking.turf_flags & UNUSED_RESERVATION_TURF))
|
||||
passing = FALSE
|
||||
break
|
||||
if(passing) // found a potentially valid area, now try to calculate its cordon
|
||||
@@ -149,18 +171,94 @@
|
||||
break
|
||||
if(!passing || !istype(BL) || !istype(TR))
|
||||
return FALSE
|
||||
bottom_left_coords = list(BL.x, BL.y, BL.z)
|
||||
top_right_coords = list(TR.x, TR.y, TR.z)
|
||||
for(var/i in final)
|
||||
var/turf/T = i
|
||||
reserved_turfs |= T
|
||||
T.flags_1 &= ~UNUSED_RESERVATION_TURF
|
||||
SSmapping.unused_turfs["[T.z]"] -= T
|
||||
SSmapping.used_turfs[T] = src
|
||||
T.turf_flags = (T.turf_flags | RESERVATION_TURF) & ~UNUSED_RESERVATION_TURF
|
||||
T.ChangeTurf(turf_type, turf_type)
|
||||
|
||||
bottom_left_turfs += BL
|
||||
top_right_turfs += TR
|
||||
return TRUE
|
||||
|
||||
/datum/turf_reservation/proc/reserve(width, height, z_size, z_reservation)
|
||||
src.z_size = z_size
|
||||
var/failed_reservation = FALSE
|
||||
for(var/_ in 1 to z_size)
|
||||
if(!_reserve_area(width, height, z_reservation))
|
||||
failed_reservation = TRUE
|
||||
break
|
||||
|
||||
if(failed_reservation)
|
||||
Release()
|
||||
return FALSE
|
||||
|
||||
generate_cordon()
|
||||
return TRUE
|
||||
|
||||
/// Calculates the effective bounds information for the given turf. Returns a list of the information, or null if not applicable.
|
||||
/datum/turf_reservation/proc/calculate_turf_bounds_information(turf/target)
|
||||
for(var/z_idx in 1 to z_size)
|
||||
var/turf/bottom_left = bottom_left_turfs[z_idx]
|
||||
var/turf/top_right = top_right_turfs[z_idx]
|
||||
var/bl_x = bottom_left.x
|
||||
var/bl_y = bottom_left.y
|
||||
var/tr_x = top_right.x
|
||||
var/tr_y = top_right.y
|
||||
|
||||
if(target.x < bl_x)
|
||||
continue
|
||||
|
||||
if(target.y < bl_y)
|
||||
continue
|
||||
|
||||
if(target.x > tr_x)
|
||||
continue
|
||||
|
||||
if(target.y > tr_y)
|
||||
continue
|
||||
|
||||
var/list/return_information = list()
|
||||
return_information["z_idx"] = z_idx
|
||||
return_information["offset_x"] = target.x - bl_x
|
||||
return_information["offset_y"] = target.y - bl_y
|
||||
return return_information
|
||||
return null
|
||||
|
||||
/// Gets the turf below the given target. Returns null if there is no turf below the target
|
||||
/datum/turf_reservation/proc/get_turf_below(turf/target)
|
||||
var/list/bounds_info = calculate_turf_bounds_information(target)
|
||||
if(isnull(bounds_info))
|
||||
return null
|
||||
|
||||
var/z_idx = bounds_info["z_idx"]
|
||||
// check what z level, if its the max, then there is no turf below
|
||||
if(z_idx == z_size)
|
||||
return null
|
||||
|
||||
var/offset_x = bounds_info["offset_x"]
|
||||
var/offset_y = bounds_info["offset_y"]
|
||||
var/turf/bottom_left = bottom_left_turfs[z_idx + 1]
|
||||
return locate(bottom_left.x + offset_x, bottom_left.y + offset_y, bottom_left.z)
|
||||
|
||||
/// Gets the turf above the given target. Returns null if there is no turf above the target
|
||||
/datum/turf_reservation/proc/get_turf_above(turf/target)
|
||||
var/list/bounds_info = calculate_turf_bounds_information(target)
|
||||
if(isnull(bounds_info))
|
||||
return null
|
||||
|
||||
var/z_idx = bounds_info["z_idx"]
|
||||
// check what z level, if its the min, then there is no turf above
|
||||
if(z_idx == 1)
|
||||
return null
|
||||
|
||||
var/offset_x = bounds_info["offset_x"]
|
||||
var/offset_y = bounds_info["offset_y"]
|
||||
var/turf/bottom_left = bottom_left_turfs[z_idx - 1]
|
||||
return locate(bottom_left.x + offset_x, bottom_left.y + offset_y, bottom_left.z)
|
||||
|
||||
/datum/turf_reservation/New()
|
||||
LAZYADD(SSmapping.turf_reservations, src)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user