From d9624bdf973e23bd435cbe3933082d677dd5cb26 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 19 Sep 2023 19:26:14 +0200 Subject: [PATCH] [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> --- .../lazy_templates/abductor_ships.dmm | 518 ++++++++++++++++++ .../dcs/signals/signals_lazy_templates.dm | 2 + code/__DEFINES/flags.dm | 3 + code/__DEFINES/multiz.dm | 8 +- code/_globalvars/bitfields.dm | 1 + code/_globalvars/lists/mapping.dm | 3 + code/controllers/subsystem/mapping.dm | 34 +- code/controllers/subsystem/shuttle.dm | 19 +- code/datums/diseases/advance/symptoms/heal.dm | 6 +- .../elements/openspace_item_click_handler.dm | 2 +- code/datums/elements/turf_transparency.dm | 10 +- code/datums/lazy_template.dm | 57 +- .../effects/decals/cleanable/aliens.dm | 5 +- .../effects/decals/cleanable/humans.dm | 5 +- .../effects/decals/cleanable/robots.dm | 5 +- code/game/objects/effects/phased_mob.dm | 2 +- code/game/objects/items/climbingrope.dm | 8 +- code/game/turfs/change_turf.dm | 2 + code/game/turfs/open/asteroid.dm | 3 +- code/game/turfs/open/openspace.dm | 2 +- code/game/turfs/open/space/transit.dm | 2 +- code/game/world.dm | 18 +- code/modules/admin/admin_verbs.dm | 2 +- .../ruins/spaceruin_code/hilbertshotel.dm | 76 ++- code/modules/mapping/map_template.dm | 19 +- code/modules/mapping/reader.dm | 213 +++++-- code/modules/mapping/ruins.dm | 4 +- .../space_management/multiz_helpers.dm | 19 +- .../space_management/space_reservation.dm | 140 ++++- .../modules/mob/living/silicon/ai/multicam.dm | 2 +- code/modules/photography/camera/camera.dm | 2 +- .../camera/camera_image_capturing.dm | 9 +- .../mapGenerators/repair.dm | 13 +- code/modules/recycling/disposal/multiz.dm | 6 +- code/modules/shuttle/shuttle.dm | 13 +- .../unit_tests/chain_pull_through_space.dm | 9 +- .../modules/liquids/code/ocean_turfs.dm | 2 +- tgstation.dme | 1 + 38 files changed, 1054 insertions(+), 191 deletions(-) create mode 100644 code/__DEFINES/dcs/signals/signals_lazy_templates.dm diff --git a/_maps/templates/lazy_templates/abductor_ships.dmm b/_maps/templates/lazy_templates/abductor_ships.dmm index 0e33b8d3922..4c7d2e172ff 100644 --- a/_maps/templates/lazy_templates/abductor_ships.dmm +++ b/_maps/templates/lazy_templates/abductor_ships.dmm @@ -1,4 +1,10 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/turf/open/water, +/area/awaymission/beach) +"ab" = ( +/turf/open/lava, +/area/awaymission/caves) "bX" = ( /turf/closed/indestructible/abductor{ icon_state = "alien11" @@ -592,3 +598,515 @@ bX Zf Xy "} + +(1,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(2,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(3,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(4,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(5,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(6,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(7,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(8,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(9,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(10,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(11,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(12,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(13,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(14,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(15,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} + +(1,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(2,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(3,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(4,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(5,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(6,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(7,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(8,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(9,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(10,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(11,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(12,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(13,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(14,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(15,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} diff --git a/code/__DEFINES/dcs/signals/signals_lazy_templates.dm b/code/__DEFINES/dcs/signals/signals_lazy_templates.dm new file mode 100644 index 00000000000..556ad6c886f --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_lazy_templates.dm @@ -0,0 +1,2 @@ +/// Fired on the lazy template datum when the template is finished loading. (list/loaded_atoms) +#define COMSIG_LAZY_TEMPLATE_LOADED "lazy_template_loaded" diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index f509b740d26..849b3a28b9c 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -88,7 +88,10 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 //TURF FLAGS /// If a turf cant be jaunted through. #define NOJAUNT (1<<0) +/// If a turf is an usused reservation turf awaiting assignment #define UNUSED_RESERVATION_TURF (1<<1) +/// If a turf is a reserved turf +#define RESERVATION_TURF (1<<2) /// Blocks lava rivers being generated on the turf. #define NO_LAVA_GEN (1<<3) /// Blocks ruins spawning on the turf. diff --git a/code/__DEFINES/multiz.dm b/code/__DEFINES/multiz.dm index 9d167495fa8..370eaa8ba45 100644 --- a/code/__DEFINES/multiz.dm +++ b/code/__DEFINES/multiz.dm @@ -1,4 +1,8 @@ /// Attempt to get the turf below the provided one according to Z traits -#define GET_TURF_BELOW(turf) ((!(turf) || !length(SSmapping.multiz_levels) || !SSmapping.multiz_levels[(turf).z][Z_LEVEL_DOWN]) ? null : get_step((turf), DOWN)) +#define GET_TURF_BELOW(turf) ( \ + (turf.turf_flags & RESERVATION_TURF) ? SSmapping.get_reservation_from_turf(turf)?.get_turf_below(turf) : \ + (!(turf) || !length(SSmapping.multiz_levels) || !SSmapping.multiz_levels[(turf).z][Z_LEVEL_DOWN]) ? null : get_step((turf), DOWN)) /// Attempt to get the turf above the provided one according to Z traits -#define GET_TURF_ABOVE(turf) ((!(turf) || !length(SSmapping.multiz_levels) || !SSmapping.multiz_levels[(turf).z][Z_LEVEL_UP]) ? null : get_step((turf), UP)) +#define GET_TURF_ABOVE(turf) ( \ + (turf.turf_flags & RESERVATION_TURF) ? SSmapping.get_reservation_from_turf(turf)?.get_turf_above(turf) : \ + (!(turf) || !length(SSmapping.multiz_levels) || !SSmapping.multiz_levels[(turf).z][Z_LEVEL_UP]) ? null : get_step((turf), UP)) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 795ba64292c..fad0deb0bd8 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -75,6 +75,7 @@ DEFINE_BITFIELD(turf_flags, list( "NOJAUNT" = NOJAUNT, "IS_SOLID" = IS_SOLID, "UNUSED_RESERVATION_TURF" = UNUSED_RESERVATION_TURF, + "RESERVATION_TURF" = RESERVATION_TURF, )) DEFINE_BITFIELD(car_traits, list( diff --git a/code/_globalvars/lists/mapping.dm b/code/_globalvars/lists/mapping.dm index be439d8217f..8ac2f0d3ddf 100644 --- a/code/_globalvars/lists/mapping.dm +++ b/code/_globalvars/lists/mapping.dm @@ -127,6 +127,9 @@ GLOBAL_LIST_EMPTY(emergencyresponseteamspawn) GLOBAL_LIST_EMPTY(ruin_landmarks) GLOBAL_LIST_EMPTY(bar_areas) +/// List of all the maps that have been cached for /proc/load_map +GLOBAL_LIST_EMPTY(cached_maps) + /// Away missions GLOBAL_LIST_EMPTY(vr_spawnpoints) diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index 396d736ac3f..681658caa3b 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -190,7 +190,7 @@ SUBSYSTEM_DEF(mapping) unused_turfs["[T.z]"] |= T var/area/old_area = T.loc old_area.turfs_to_uncontain += T - T.flags_1 |= UNUSED_RESERVATION_TURF + T.turf_flags = UNUSED_RESERVATION_TURF world_contents += T world_turf_contents += T packet.len-- @@ -309,6 +309,10 @@ SUBSYSTEM_DEF(mapping) returning += M qdel(T, TRUE) +/datum/controller/subsystem/mapping/proc/get_reservation_from_turf(turf/T) + RETURN_TYPE(/datum/turf_reservation) + return used_turfs[T] + /* Nuke threats, for making the blue tiles on the station go RED Used by the AI doomsday and the self-destruct nuke. */ @@ -695,26 +699,34 @@ GLOBAL_LIST_EMPTY(the_station_areas) num_of_res_levels++ return add_new_zlevel("Transit/Reserved #[num_of_res_levels]", list(ZTRAIT_RESERVED = TRUE)) -/datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override) - UNTIL((!z || reservation_ready["[z]"]) && !clearing_reserved_turfs) - var/datum/turf_reservation/reserve = new type - if(turf_type_override) +/// Requests a /datum/turf_reservation based on the given width, height, and z_size. You can specify a z_reservation to use a specific z level, or leave it null to use any z level. +/datum/controller/subsystem/mapping/proc/request_turf_block_reservation( + width, + height, + z_size = 1, + z_reservation = null, + reservation_type = /datum/turf_reservation, + turf_type_override = null, +) + UNTIL((!z_reservation || reservation_ready["[z_reservation]"]) && !clearing_reserved_turfs) + var/datum/turf_reservation/reserve = new reservation_type + if(!isnull(turf_type_override)) reserve.turf_type = turf_type_override - if(!z) + if(!z_reservation) for(var/i in levels_by_trait(ZTRAIT_RESERVED)) - if(reserve.Reserve(width, height, i)) + if(reserve.reserve(width, height, z_size, i)) return reserve //If we didn't return at this point, theres a good chance we ran out of room on the exisiting reserved z levels, so lets try a new one var/datum/space_level/newReserved = add_reservation_zlevel() initialize_reserved_level(newReserved.z_value) - if(reserve.Reserve(width, height, newReserved.z_value)) + if(reserve.reserve(width, height, z_size, newReserved.z_value)) return reserve else - if(!level_trait(z, ZTRAIT_RESERVED)) + if(!level_trait(z_reservation, ZTRAIT_RESERVED)) qdel(reserve) return else - if(reserve.Reserve(width, height, z)) + if(reserve.reserve(width, height, z_size, z_reservation)) return reserve QDEL_NULL(reserve) @@ -732,7 +744,7 @@ GLOBAL_LIST_EMPTY(the_station_areas) var/block = block(A, B) for(var/turf/T as anything in block) // No need to empty() these, because they just got created and are already /turf/open/space/basic. - T.flags_1 |= UNUSED_RESERVATION_TURF + T.turf_flags = UNUSED_RESERVATION_TURF CHECK_TICK // Gotta create these suckers if we've not done so already diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 56dbd35a996..0e5ed6ca685 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -617,12 +617,18 @@ SUBSYSTEM_DEF(shuttle) if(WEST) transit_path = /turf/open/space/transit/west - var/datum/turf_reservation/proposal = SSmapping.RequestBlockReservation(transit_width, transit_height, null, /datum/turf_reservation/transit, transit_path) + var/datum/turf_reservation/proposal = SSmapping.request_turf_block_reservation( + transit_width, + transit_height, + 1, + reservation_type = /datum/turf_reservation/transit, + turf_type_override = transit_path, + ) if(!istype(proposal)) return FALSE - var/turf/bottomleft = locate(proposal.bottom_left_coords[1], proposal.bottom_left_coords[2], proposal.bottom_left_coords[3]) + var/turf/bottomleft = proposal.bottom_left_turfs[1] // Then create a transit docking port in the middle var/coords = M.return_coords(0, 0, dock_dir) /* 0------2 @@ -893,10 +899,15 @@ SUBSYSTEM_DEF(shuttle) /datum/controller/subsystem/shuttle/proc/load_template(datum/map_template/shuttle/loading_template) . = FALSE // Load shuttle template to a fresh block reservation. - preview_reservation = SSmapping.RequestBlockReservation(loading_template.width, loading_template.height, type = /datum/turf_reservation/transit) + preview_reservation = SSmapping.request_turf_block_reservation( + loading_template.width, + loading_template.height, + 1, + reservation_type = /datum/turf_reservation/transit, + ) if(!preview_reservation) CRASH("failed to reserve an area for shuttle template loading") - var/turf/bottom_left = TURF_FROM_COORDS_LIST(preview_reservation.bottom_left_coords) + var/turf/bottom_left = preview_reservation.bottom_left_turfs[1] loading_template.load(bottom_left, centered = FALSE, register = FALSE) var/affected = loading_template.get_affected_turfs(bottom_left, centered=FALSE) diff --git a/code/datums/diseases/advance/symptoms/heal.dm b/code/datums/diseases/advance/symptoms/heal.dm index d9345d0107c..8754eb3b71d 100644 --- a/code/datums/diseases/advance/symptoms/heal.dm +++ b/code/datums/diseases/advance/symptoms/heal.dm @@ -75,7 +75,7 @@ /datum/symptom/heal/starlight/proc/CanTileHealDirectional(turf/turf_to_check, direction) if(direction == UP) - turf_to_check = turf_to_check.above() + turf_to_check = GET_TURF_ABOVE(turf_to_check) if(!turf_to_check) return STARLIGHT_CANNOT_HEAL var/area/area_to_check = get_area(turf_to_check) @@ -98,9 +98,9 @@ if(istransparentturf(turf_to_check) || istype(turf_to_check, /turf/open/openspace)) // Check above or below us if(direction == UP) - turf_to_check = turf_to_check.above() + turf_to_check = GET_TURF_ABOVE(turf_to_check) else - turf_to_check = turf_to_check.below() + turf_to_check = GET_TURF_BELOW(turf_to_check) // If we found a turf above or below us, // then we can rerun the loop on the newly found turf / area diff --git a/code/datums/elements/openspace_item_click_handler.dm b/code/datums/elements/openspace_item_click_handler.dm index 43c7a60d1ef..c9de01f381c 100644 --- a/code/datums/elements/openspace_item_click_handler.dm +++ b/code/datums/elements/openspace_item_click_handler.dm @@ -21,7 +21,7 @@ return var/turf/checked_turf = get_turf(target) while(!isnull(checked_turf)) - checked_turf = checked_turf.above() + checked_turf = GET_TURF_ABOVE(checked_turf) if(checked_turf?.z == user.z) INVOKE_ASYNC(source, TYPE_PROC_REF(/obj/item, handle_openspace_click), checked_turf, user, user.CanReach(checked_turf, source), click_parameters) break diff --git a/code/datums/elements/turf_transparency.dm b/code/datums/elements/turf_transparency.dm index ab3a17dc40d..b050dd0866f 100644 --- a/code/datums/elements/turf_transparency.dm +++ b/code/datums/elements/turf_transparency.dm @@ -103,7 +103,7 @@ GLOBAL_LIST_EMPTY(pillars_by_z) if(!holding) return - var/turf/visual_target = to_display.above() + var/turf/visual_target = GET_TURF_ABOVE(to_display) /// Basically, if we used to be under a non transparent turf, but are no longer in that position /// Then we add to the transparent turf we're now under, and nuke the old object if(!istransparentturf(visual_target)) @@ -120,7 +120,7 @@ GLOBAL_LIST_EMPTY(pillars_by_z) turf_sources[to_display] = sources sources |= source - var/turf/visual_target = to_display.above() + var/turf/visual_target = GET_TURF_ABOVE(to_display) if(istransparentturf(visual_target) || isopenspaceturf(visual_target)) visual_target.vis_contents += to_display else @@ -142,7 +142,7 @@ GLOBAL_LIST_EMPTY(pillars_by_z) if(holding) qdel(holding) else - var/turf/visual_target = to_hide.above() + var/turf/visual_target = GET_TURF_ABOVE(to_hide) visual_target.vis_contents -= to_hide if(!length(turf_sources) && !QDELETED(src)) @@ -201,7 +201,7 @@ GLOBAL_LIST_EMPTY(pillars_by_z) ///Updates the viscontents or underlays below this tile. /datum/element/turf_z_transparency/proc/update_multi_z(turf/our_turf) - var/turf/below_turf = our_turf.below() + var/turf/below_turf = GET_TURF_BELOW(our_turf) if(below_turf) // If we actually have something below us, display it. for(var/turf/partner in range(1, below_turf)) // We use our z here to ensure the pillar is actually on our level @@ -228,7 +228,7 @@ GLOBAL_LIST_EMPTY(pillars_by_z) return TRUE /datum/element/turf_z_transparency/proc/clear_multiz(turf/our_turf) - var/turf/below_turf = our_turf.below() + var/turf/below_turf = GET_TURF_BELOW(our_turf) if(below_turf) // If we actually have something below us, we need to clear ourselves from it for(var/turf/partner in range(1, below_turf)) // We use our z here to ensure the pillar is actually on our level diff --git a/code/datums/lazy_template.dm b/code/datums/lazy_template.dm index ad50a12e5d7..ba2a7c42e9f 100644 --- a/code/datums/lazy_template.dm +++ b/code/datums/lazy_template.dm @@ -10,8 +10,6 @@ var/key var/map_dir = "_maps/templates/lazy_templates" var/map_name - var/map_width - var/map_height /datum/lazy_template/New() reservations = list() @@ -46,25 +44,64 @@ if(!load_path || !fexists(load_path)) CRASH("lazy template [type] has an invalid load_path: '[load_path]', check directory and map name!") - var/datum/map_template/loading = new(path = load_path, cache = TRUE) - if(!loading.cached_map) + var/datum/parsed_map/parsed_template = load_map( + file(load_path), + measure_only = TRUE, + ) + if(isnull(parsed_template.parsed_bounds)) CRASH("Failed to cache lazy template for loading: '[key]'") - var/datum/turf_reservation/reservation = SSmapping.RequestBlockReservation(loading.width, loading.height) + var/width = parsed_template.parsed_bounds[MAP_MAXX] - parsed_template.parsed_bounds[MAP_MINX] + 1 + var/height = parsed_template.parsed_bounds[MAP_MAXY] - parsed_template.parsed_bounds[MAP_MINY] + 1 + var/datum/turf_reservation/reservation = SSmapping.request_turf_block_reservation( + width, + height, + parsed_template.parsed_bounds[MAP_MAXZ], + ) if(!reservation) CRASH("Failed to reserve a block for lazy template: '[key]'") - if(!loading.load(coords2turf(reservation.bottom_left_coords))) - CRASH("Failed to load lazy template: '[key]'") - reservations += reservation + var/list/my_loaded_atoms = list() + for(var/z_idx in parsed_template.parsed_bounds[MAP_MAXZ] to 1 step -1) + var/turf/bottom_left = reservation.bottom_left_turfs[z_idx] + var/turf/top_right = reservation.top_right_turfs[z_idx] + load_map( + file(load_path), + bottom_left.x, + bottom_left.y, + bottom_left.z, + z_upper = z_idx, + z_lower = z_idx, + ) + var/list/to_init = list() + // turfs can never be duplicated so keep them out of the below list to optimize O(n) + var/list/turfs = list() + // areas can be duplicated but lets keep them seperate for efficiency + var/list/areas = list() + // everything else that can be duplicated, such as areas or large objects + var/list/not_turfs = list() + for(var/turf/turf as anything in block(bottom_left, top_right)) + turfs += turf + areas |= get_area(turf) + for(var/thing in turf.get_all_contents()) + // atoms can actually be in the contents of two or more turfs based on its icon/bound size + // see https://www.byond.com/docs/ref/index.html#/atom/var/contents + not_turfs |= thing + + SSatoms.InitializeAtoms(to_init) + // we don't need to check for duplicates here + my_loaded_atoms += not_turfs + my_loaded_atoms += turfs + my_loaded_atoms += areas + + SEND_SIGNAL(src, COMSIG_LAZY_TEMPLATE_LOADED, my_loaded_atoms) + reservations += reservation return reservation /datum/lazy_template/nukie_base key = LAZY_TEMPLATE_KEY_NUKIEBASE map_name = "nukie_base" - map_width = 89 - map_height = 100 /datum/lazy_template/wizard_dem key = LAZY_TEMPLATE_KEY_WIZARDDEN diff --git a/code/game/objects/effects/decals/cleanable/aliens.dm b/code/game/objects/effects/decals/cleanable/aliens.dm index e113eec5a36..4f4b2543792 100644 --- a/code/game/objects/effects/decals/cleanable/aliens.dm +++ b/code/game/objects/effects/decals/cleanable/aliens.dm @@ -40,8 +40,9 @@ return if(mapload) for (var/i in 1 to range) - if(!isgroundlessturf(loc) || GET_TURF_BELOW(loc)) - new /obj/effect/decal/cleanable/xenoblood/xsplatter(loc) + var/turf/my_turf = get_turf(src) + if(!isgroundlessturf(my_turf) || GET_TURF_BELOW(my_turf)) + new /obj/effect/decal/cleanable/xenoblood/xsplatter(my_turf) if (!step_to(src, get_step(src, direction), 0)) break return diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index fc07a229251..d329de34a5f 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -159,8 +159,9 @@ return if(mapload) for (var/i in 1 to range) - if(!isgroundlessturf(loc) || GET_TURF_BELOW(loc)) - new /obj/effect/decal/cleanable/blood/splatter(loc) + var/turf/my_turf = get_turf(src) + if(!isgroundlessturf(my_turf) || GET_TURF_BELOW(my_turf)) + new /obj/effect/decal/cleanable/blood/splatter(my_turf) if (!step_to(src, get_step(src, direction), 0)) break return diff --git a/code/game/objects/effects/decals/cleanable/robots.dm b/code/game/objects/effects/decals/cleanable/robots.dm index 65e6cc3900c..d248b5e691d 100644 --- a/code/game/objects/effects/decals/cleanable/robots.dm +++ b/code/game/objects/effects/decals/cleanable/robots.dm @@ -25,8 +25,9 @@ return if(mapload) for (var/i in 1 to range) - if(prob(40) && (!isgroundlessturf(loc) || GET_TURF_BELOW(loc))) - new /obj/effect/decal/cleanable/oil/streak(loc) + var/turf/my_turf = get_turf(src) + if(prob(40) && (!isgroundlessturf(my_turf) || GET_TURF_BELOW(my_turf))) + new /obj/effect/decal/cleanable/oil/streak(my_turf) if (!step_to(src, get_step(src, direction), 0)) break return diff --git a/code/game/objects/effects/phased_mob.dm b/code/game/objects/effects/phased_mob.dm index 7a0317c4c77..273a4c772a5 100644 --- a/code/game/objects/effects/phased_mob.dm +++ b/code/game/objects/effects/phased_mob.dm @@ -83,7 +83,7 @@ return var/area/destination_area = newloc.loc movedelay = world.time + movespeed - if(newloc.flags_1 & NOJAUNT) + if(newloc.turf_flags & NOJAUNT) to_chat(user, span_warning("Some strange aura is blocking the way.")) return if(destination_area.area_flags & NOTELEPORT || SSmapping.level_trait(newloc.z, ZTRAIT_NOPHASE)) diff --git a/code/game/objects/items/climbingrope.dm b/code/game/objects/items/climbingrope.dm index c26f96d1349..2c96d1844b1 100644 --- a/code/game/objects/items/climbingrope.dm +++ b/code/game/objects/items/climbingrope.dm @@ -34,11 +34,11 @@ return if(target.is_blocked_turf(exclude_mobs = TRUE)) return - var/turf/above = GET_TURF_ABOVE(user) + var/turf/user_turf = get_turf(user) + var/turf/above = GET_TURF_ABOVE(user_turf) if(!isopenspaceturf(above) || !above.Adjacent(target)) //are we below a hole, is the target blocked, is the target adjacent to our hole balloon_alert(user, "blocked!") return - var/turf/user_turf = get_turf(user) var/away_dir = get_dir(above, target) user.visible_message(span_notice("[user] begins climbing upwards with [src]."), span_notice("You get to work on properly hooking [src] and going upwards.")) playsound(target, 'sound/effects/picaxe1.ogg', 50) //plays twice so people above and below can hear @@ -47,11 +47,11 @@ if(do_after(user, climb_time, target)) user.Move(target) uses-- - + if(uses <= 0) user.visible_message(span_warning("[src] snaps and tears apart!")) qdel(src) - + QDEL_LIST(effects) /obj/item/climbing_hook/emergency diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm index 6a7f533e4de..f5b40238ed6 100644 --- a/code/game/turfs/change_turf.dm +++ b/code/game/turfs/change_turf.dm @@ -105,7 +105,9 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( //We do this here so anything that doesn't want to persist can clear itself var/list/old_listen_lookup = _listen_lookup?.Copy() var/list/old_signal_procs = _signal_procs?.Copy() + var/carryover_turf_flags = (RESERVATION_TURF | UNUSED_RESERVATION_TURF) & turf_flags var/turf/new_turf = new path(src) + new_turf.turf_flags |= carryover_turf_flags // WARNING WARNING // Turfs DO NOT lose their signals when they get replaced, REMEMBER THIS diff --git a/code/game/turfs/open/asteroid.dm b/code/game/turfs/open/asteroid.dm index cf7e07e75f3..c15261a9880 100644 --- a/code/game/turfs/open/asteroid.dm +++ b/code/game/turfs/open/asteroid.dm @@ -235,7 +235,8 @@ GLOBAL_LIST_EMPTY(dug_up_basalt) turf_flags = CAN_BE_DIRTY_1 | IS_SOLID | NO_RUST | NO_RUINS /turf/open/misc/asteroid/snow/icemoon/do_not_scrape - turf_flags = CAN_BE_DIRTY_1 | IS_SOLID | NO_RUST | NO_CLEARING + flags_1 = CAN_BE_DIRTY_1 + turf_flags = IS_SOLID | NO_RUST | NO_CLEARING /turf/open/lava/plasma/ice_moon initial_gas_mix = ICEMOON_DEFAULT_ATMOS diff --git a/code/game/turfs/open/openspace.dm b/code/game/turfs/open/openspace.dm index 12c7ade160c..91437e727a7 100644 --- a/code/game/turfs/open/openspace.dm +++ b/code/game/turfs/open/openspace.dm @@ -179,7 +179,7 @@ /turf/open/openspace/icemoon/Initialize(mapload) . = ..() - var/turf/T = below() + var/turf/T = GET_TURF_BELOW(src) //I wonder if I should error here if(!T) return diff --git a/code/game/turfs/open/space/transit.dm b/code/game/turfs/open/space/transit.dm index 3e3f7b0c55e..02d56a3be1e 100644 --- a/code/game/turfs/open/space/transit.dm +++ b/code/game/turfs/open/space/transit.dm @@ -4,7 +4,7 @@ icon_state = "black" dir = SOUTH baseturfs = /turf/open/space/transit - flags_1 = NOJAUNT //This line goes out to every wizard that ever managed to escape the den. I'm sorry. + turf_flags = NOJAUNT //This line goes out to every wizard that ever managed to escape the den. I'm sorry. explosive_resistance = INFINITY /turf/open/space/transit/Initialize(mapload) diff --git a/code/game/world.dm b/code/game/world.dm index 380448d9fcf..e851bb992d4 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -399,31 +399,35 @@ GLOBAL_VAR(restart_counter) else hub_password = "SORRYNOPASSWORD" -// If this is called as a part of maploading you cannot call it on the newly loaded map zs, because those get handled later on in the pipeline -/world/proc/increaseMaxX(new_maxx, max_zs_to_load = maxz) +/** + * Handles incresing the world's maxx var and intializing the new turfs and assigning them to the global area. + * If map_load_z_cutoff is passed in, it will only load turfs up to that z level, inclusive. + * This is because maploading will handle the turfs it loads itself. + */ +/world/proc/increase_max_x(new_maxx, map_load_z_cutoff = maxz) if(new_maxx <= maxx) return var/old_max = world.maxx maxx = new_maxx - if(!max_zs_to_load) + if(!map_load_z_cutoff) return var/area/global_area = GLOB.areas_by_type[world.area] // We're guaranteed to be touching the global area, so we'll just do this var/list/to_add = block( locate(old_max + 1, 1, 1), - locate(maxx, maxy, max_zs_to_load)) + locate(maxx, maxy, map_load_z_cutoff)) global_area.contained_turfs += to_add -/world/proc/increaseMaxY(new_maxy, max_zs_to_load = maxz) +/world/proc/increase_max_y(new_maxy, map_load_z_cutoff = maxz) if(new_maxy <= maxy) return var/old_maxy = maxy maxy = new_maxy - if(!max_zs_to_load) + if(!map_load_z_cutoff) return var/area/global_area = GLOB.areas_by_type[world.area] // We're guarenteed to be touching the global area, so we'll just do this var/list/to_add = block( locate(1, old_maxy + 1, 1), - locate(maxx, maxy, max_zs_to_load)) + locate(maxx, maxy, map_load_z_cutoff)) global_area.contained_turfs += to_add /world/proc/incrementMaxZ() diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 913a0c55e53..34e855230cb 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -1059,7 +1059,7 @@ GLOBAL_PROTECT(admin_verbs_poll) if(!isobserver(usr)) admin_ghost() - usr.forceMove(coords2turf(reservation.bottom_left_coords)) + usr.forceMove(reservation.bottom_left_turfs[1]) message_admins("[key_name_admin(usr)] has loaded lazy template '[choice]'") to_chat(usr, span_boldnicegreen("Template loaded, you have been moved to the bottom left of the reservation.")) diff --git a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm index 6ab0ed2f387..424e1db299e 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm @@ -112,9 +112,10 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) if(!storageTurf) //Blame subsystems for not allowing this to be in Initialize if(!GLOB.hhStorageTurf) var/datum/map_template/hilbertshotelstorage/storageTemp = new() - var/datum/turf_reservation/storageReservation = SSmapping.RequestBlockReservation(3, 3) - storageTemp.load(locate(storageReservation.bottom_left_coords[1], storageReservation.bottom_left_coords[2], storageReservation.bottom_left_coords[3])) - GLOB.hhStorageTurf = locate(storageReservation.bottom_left_coords[1]+1, storageReservation.bottom_left_coords[2]+1, storageReservation.bottom_left_coords[3]) + var/datum/turf_reservation/storageReservation = SSmapping.request_turf_block_reservation(1, 1, 1) + var/turf/storage_turf = storageReservation.bottom_left_turfs[1] + storageTemp.load(storage_turf) + GLOB.hhStorageTurf = storage_turf else storageTurf = GLOB.hhStorageTurf if(tryActiveRoom(chosenRoomNumber, target)) @@ -127,20 +128,30 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) if(activeRooms["[roomNumber]"]) var/datum/turf_reservation/roomReservation = activeRooms["[roomNumber]"] do_sparks(3, FALSE, get_turf(user)) - user.forceMove(locate(roomReservation.bottom_left_coords[1] + hotelRoomTemp.landingZoneRelativeX, roomReservation.bottom_left_coords[2] + hotelRoomTemp.landingZoneRelativeY, roomReservation.bottom_left_coords[3])) + var/turf/room_bottom_left = roomReservation.bottom_left_turfs[1] + user.forceMove(locate( + room_bottom_left.x + hotelRoomTemp.landingZoneRelativeX, + room_bottom_left.y + hotelRoomTemp.landingZoneRelativeY, + room_bottom_left.z, + )) return TRUE return FALSE /obj/item/hilbertshotel/proc/tryStoredRoom(roomNumber, mob/user) if(storedRooms["[roomNumber]"]) - var/datum/turf_reservation/roomReservation = SSmapping.RequestBlockReservation(hotelRoomTemp.width, hotelRoomTemp.height) - hotelRoomTempEmpty.load(locate(roomReservation.bottom_left_coords[1], roomReservation.bottom_left_coords[2], roomReservation.bottom_left_coords[3])) + var/datum/turf_reservation/roomReservation = SSmapping.request_turf_block_reservation(hotelRoomTemp.width, hotelRoomTemp.height, 1) + var/turf/room_turf = roomReservation.bottom_left_turfs[1] + hotelRoomTempEmpty.load(room_turf) var/turfNumber = 1 for(var/x in 0 to hotelRoomTemp.width-1) for(var/y in 0 to hotelRoomTemp.height-1) for(var/atom/movable/A in storedRooms["[roomNumber]"][turfNumber]) if(istype(A.loc, /obj/item/abstracthotelstorage))//Don't want to recall something thats been moved - A.forceMove(locate(roomReservation.bottom_left_coords[1] + x, roomReservation.bottom_left_coords[2] + y, roomReservation.bottom_left_coords[3])) + A.forceMove(locate( + room_turf.x + x, + room_turf.y + y, + room_turf.z, + )) turfNumber++ for(var/obj/item/abstracthotelstorage/S in storageTurf) if((S.roomNumber == roomNumber) && (S.parentSphere == src)) @@ -149,29 +160,39 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) activeRooms["[roomNumber]"] = roomReservation linkTurfs(roomReservation, roomNumber) do_sparks(3, FALSE, get_turf(user)) - user.forceMove(locate(roomReservation.bottom_left_coords[1] + hotelRoomTemp.landingZoneRelativeX, roomReservation.bottom_left_coords[2] + hotelRoomTemp.landingZoneRelativeY, roomReservation.bottom_left_coords[3])) + user.forceMove(locate( + room_turf.x + hotelRoomTemp.landingZoneRelativeX, + room_turf.y + hotelRoomTemp.landingZoneRelativeY, + room_turf.z, + )) return TRUE return FALSE -/obj/item/hilbertshotel/proc/sendToNewRoom(roomNumber, mob/user, chosen_room) //SKYRAT EDIT ADDITION - GHOST HOTEL UPDATE. Was sendToNewRoom(chosenRoomNumber, target) - var/datum/turf_reservation/roomReservation = SSmapping.RequestBlockReservation(hotelRoomTemp.width, hotelRoomTemp.height) +/obj/item/hilbertshotel/proc/sendToNewRoom(roomNumber, mob/user, chosen_room) //SKYRAT EDIT ADDITION - GHOST HOTEL UPDATE. Was sendToNewRoom(roomNumber, mob/user) + var/datum/turf_reservation/roomReservation = SSmapping.request_turf_block_reservation(hotelRoomTemp.width, hotelRoomTemp.height, 1) + var/turf/bottom_left = roomReservation.bottom_left_turfs[1] + var/datum/map_template/load_from = hotelRoomTemp + if(ruinSpawned && roomNumber == GLOB.hhMysteryRoomNumber) - hotelRoomTempLore.load(locate(roomReservation.bottom_left_coords[1], roomReservation.bottom_left_coords[2], roomReservation.bottom_left_coords[3])) - else - //SKYRAT EDIT ADDITION - GHOST HOTEL UPDATE - switch(chosen_room) - if("Apartment") - ghost_cafe_rooms_apartment.load(locate(roomReservation.bottom_left_coords[1], roomReservation.bottom_left_coords[2], roomReservation.bottom_left_coords[3])) - else - //SKYRAT EDIT END - hotelRoomTemp.load(locate(roomReservation.bottom_left_coords[1], roomReservation.bottom_left_coords[2], roomReservation.bottom_left_coords[3])) + load_from = hotelRoomTempLore + //SKYRAT EDIT ADDITION START - GHOST HOTEL UPDATE + else if(chosen_room == "Apartment") + load_from = ghost_cafe_rooms_apartment + //SKYRAT EDIT ADDITION END + + load_from.load(bottom_left) activeRooms["[roomNumber]"] = roomReservation linkTurfs(roomReservation, roomNumber) do_sparks(3, FALSE, get_turf(user)) - user.forceMove(locate(roomReservation.bottom_left_coords[1] + hotelRoomTemp.landingZoneRelativeX, roomReservation.bottom_left_coords[2] + hotelRoomTemp.landingZoneRelativeY, roomReservation.bottom_left_coords[3])) + user.forceMove(locate( + bottom_left.x + hotelRoomTemp.landingZoneRelativeX, + bottom_left.y + hotelRoomTemp.landingZoneRelativeY, + bottom_left.z, + )) /obj/item/hilbertshotel/proc/linkTurfs(datum/turf_reservation/currentReservation, currentRoomnumber) - var/area/misc/hilbertshotel/currentArea = get_area(locate(currentReservation.bottom_left_coords[1], currentReservation.bottom_left_coords[2], currentReservation.bottom_left_coords[3])) + var/turf/room_bottom_left = currentReservation.bottom_left_turfs[1] + var/area/misc/hilbertshotel/currentArea = get_area(room_bottom_left) currentArea.name = "Hilbert's Hotel Room [currentRoomnumber]" currentArea.parentSphere = src currentArea.storageTurf = storageTurf @@ -187,9 +208,10 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) if(activeRooms.len) for(var/x in activeRooms) var/datum/turf_reservation/room = activeRooms[x] + var/turf/room_bottom_left = room.bottom_left_turfs[1] for(var/i in 0 to hotelRoomTemp.width-1) for(var/j in 0 to hotelRoomTemp.height-1) - for(var/atom/movable/A in locate(room.bottom_left_coords[1] + i, room.bottom_left_coords[2] + j, room.bottom_left_coords[3])) + for(var/atom/movable/A in locate(room_bottom_left.x + i, room_bottom_left.y + j, room_bottom_left.z)) if(ismob(A)) var/mob/M = A if(M.mind) @@ -271,7 +293,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) icon_state = "bluespace" base_icon_state = "bluespace" baseturfs = /turf/open/space/bluespace - flags_1 = NOJAUNT + turf_flags = NOJAUNT explosive_resistance = INFINITY var/obj/item/hilbertshotel/parentSphere @@ -437,7 +459,11 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) storeRoom() /area/misc/hilbertshotel/proc/storeRoom() - var/roomSize = (reservation.top_right_coords[1]-reservation.bottom_left_coords[1]+1)*(reservation.top_right_coords[2]-reservation.bottom_left_coords[2]+1) + var/turf/room_bottom_left = reservation.bottom_left_turfs[1] + var/turf/room_top_right = reservation.top_right_turfs[1] + var/roomSize = \ + ((room_top_right.x - room_bottom_left.x) + 1) * \ + ((room_top_right.y - room_bottom_left.y) + 1) var/storage[roomSize] var/turfNumber = 1 var/obj/item/abstracthotelstorage/storageObj = new(storageTurf) @@ -447,7 +473,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) for(var/x in 0 to parentSphere.hotelRoomTemp.width-1) for(var/y in 0 to parentSphere.hotelRoomTemp.height-1) var/list/turfContents = list() - for(var/atom/movable/A in locate(reservation.bottom_left_coords[1] + x, reservation.bottom_left_coords[2] + y, reservation.bottom_left_coords[3])) + for(var/atom/movable/A in locate(room_bottom_left.x + x, room_bottom_left.y + y, room_bottom_left.z)) if(ismob(A) && !isliving(A)) continue //Don't want to store ghosts turfContents += A diff --git a/code/modules/mapping/map_template.dm b/code/modules/mapping/map_template.dm index 30477657ab5..237ae9f2d52 100644 --- a/code/modules/mapping/map_template.dm +++ b/code/modules/mapping/map_template.dm @@ -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 diff --git a/code/modules/mapping/reader.dm b/code/modules/mapping/reader.dm index 96b555457d7..14a8fdf6b94 100644 --- a/code/modules/mapping/reader.dm +++ b/code/modules/mapping/reader.dm @@ -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) diff --git a/code/modules/mapping/ruins.dm b/code/modules/mapping/ruins.dm index 01a91a10c2a..a7b9480a34e 100644 --- a/code/modules/mapping/ruins.dm +++ b/code/modules/mapping/ruins.dm @@ -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)) diff --git a/code/modules/mapping/space_management/multiz_helpers.dm b/code/modules/mapping/space_management/multiz_helpers.dm index f2331eb5146..b0e2ff7fa06 100644 --- a/code/modules/mapping/space_management/multiz_helpers.dm +++ b/code/modules/mapping/space_management/multiz_helpers.dm @@ -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) diff --git a/code/modules/mapping/space_management/space_reservation.dm b/code/modules/mapping/space_management/space_reservation.dm index 52ac76e343a..2809ae65e6c 100644 --- a/code/modules/mapping/space_management/space_reservation.dm +++ b/code/modules/mapping/space_management/space_reservation.dm @@ -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) diff --git a/code/modules/mob/living/silicon/ai/multicam.dm b/code/modules/mob/living/silicon/ai/multicam.dm index e5bcd813b7e..45924e2fe98 100644 --- a/code/modules/mob/living/silicon/ai/multicam.dm +++ b/code/modules/mob/living/silicon/ai/multicam.dm @@ -86,7 +86,7 @@ name = "" icon = 'icons/misc/pic_in_pic.dmi' icon_state = "room_background" - flags_1 = NOJAUNT + turf_flags = NOJAUNT /turf/open/ai_visible/Initialize(mapload) . = ..() diff --git a/code/modules/photography/camera/camera.dm b/code/modules/photography/camera/camera.dm index 33c22c66aef..1c0e360ed75 100644 --- a/code/modules/photography/camera/camera.dm +++ b/code/modules/photography/camera/camera.dm @@ -187,7 +187,7 @@ var/list/turfs = list() var/list/mobs = list() var/blueprints = FALSE - var/clone_area = SSmapping.RequestBlockReservation(size_x * 2 + 1, size_y * 2 + 1) + var/clone_area = SSmapping.request_turf_block_reservation(size_x * 2 + 1, size_y * 2 + 1, 1) var/width = size_x * 2 + 1 var/height = size_y * 2 + 1 diff --git a/code/modules/photography/camera/camera_image_capturing.dm b/code/modules/photography/camera/camera_image_capturing.dm index 6b48e29da52..d928164ff01 100644 --- a/code/modules/photography/camera/camera_image_capturing.dm +++ b/code/modules/photography/camera/camera_image_capturing.dm @@ -16,13 +16,14 @@ var/wipe_atoms = FALSE if(istype(clone_area) && total_x == clone_area.width && total_y == clone_area.height && size_x >= 0 && size_y > 0) - var/cloned_center_x = round(clone_area.bottom_left_coords[1] + ((total_x - 1) / 2)) - var/cloned_center_y = round(clone_area.bottom_left_coords[2] + ((total_y - 1) / 2)) + var/turf/bottom_left = clone_area.bottom_left_turfs[1] + var/cloned_center_x = round(bottom_left.x + ((total_x - 1) / 2)) + var/cloned_center_y = round(bottom_left.y + ((total_y - 1) / 2)) for(var/t in turfs) var/turf/T = t var/offset_x = T.x - center.x var/offset_y = T.y - center.y - var/turf/newT = locate(cloned_center_x + offset_x, cloned_center_y + offset_y, clone_area.bottom_left_coords[3]) + var/turf/newT = locate(cloned_center_x + offset_x, cloned_center_y + offset_y, bottom_left.z) if(!(newT in clone_area.reserved_turfs)) //sanity check so we don't overwrite other areas somehow continue atoms += new /obj/effect/appearance_clone(newT, T) @@ -34,7 +35,7 @@ atoms += new /obj/effect/appearance_clone(newT, A) skip_normal = TRUE wipe_atoms = TRUE - center = locate(cloned_center_x, cloned_center_y, clone_area.bottom_left_coords[3]) + center = locate(cloned_center_x, cloned_center_y, bottom_left.z) if(!skip_normal) for(var/i in turfs) diff --git a/code/modules/procedural_mapping/mapGenerators/repair.dm b/code/modules/procedural_mapping/mapGenerators/repair.dm index c9df8496389..505dc36f02c 100644 --- a/code/modules/procedural_mapping/mapGenerators/repair.dm +++ b/code/modules/procedural_mapping/mapGenerators/repair.dm @@ -28,7 +28,18 @@ var/z_offset = SSmapping.station_start var/list/bounds for (var/path in SSmapping.config.GetFullMapPaths()) - var/datum/parsed_map/parsed = load_map(file(path), 1, 1, z_offset, measureOnly = FALSE, no_changeturf = FALSE, cropMap=TRUE, x_lower = mother1.x_low, y_lower = mother1.y_low, x_upper = mother1.x_high, y_upper = mother1.y_high) + var/datum/parsed_map/parsed = load_map( + file(path), + 1, + 1, + z_offset, + no_changeturf = FALSE, + crop_map = TRUE, + x_lower = mother1.x_low, + y_lower = mother1.y_low, + x_upper = mother1.x_high, + y_upper = mother1.y_high, + ) bounds = parsed?.bounds z_offset += bounds[MAP_MAXZ] - bounds[MAP_MINZ] + 1 diff --git a/code/modules/recycling/disposal/multiz.dm b/code/modules/recycling/disposal/multiz.dm index a4b914d66b8..06f4e52a31c 100644 --- a/code/modules/recycling/disposal/multiz.dm +++ b/code/modules/recycling/disposal/multiz.dm @@ -21,11 +21,11 @@ return ..() //Are we a trunk that goes up? Or down? - var/turf/target = null + var/turf/target = get_turf(src) if(multiz_dir == MULTIZ_PIPE_UP) - target = GET_TURF_ABOVE(get_turf(src)) + target = GET_TURF_ABOVE(target) if(multiz_dir == MULTIZ_PIPE_DOWN) - target = GET_TURF_BELOW(get_turf(src)) + target = GET_TURF_BELOW(target) if(!target) //Nothing located. return diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index aa8d4e97732..4ae1c241d06 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -382,8 +382,17 @@ /// This should be a unit test, but too much of our other code breaks during shuttle movement, so not yet, not yet. /proc/test_whiteship_sizes() var/obj/docking_port/stationary/port_type = /obj/docking_port/stationary/picked/whiteship - var/datum/turf_reservation/docking_yard = SSmapping.RequestBlockReservation(initial(port_type.width), initial(port_type.height)) - var/turf/spawnpoint = locate(docking_yard.bottom_left_coords[1] + initial(port_type.dwidth), docking_yard.bottom_left_coords[2] + initial(port_type.dheight), docking_yard.bottom_left_coords[3]) + var/datum/turf_reservation/docking_yard = SSmapping.request_turf_block_reservation( + initial(port_type.width), + initial(port_type.height), + 1, + ) + var/turf/bottom_left = docking_yard.bottom_left_turfs[1] + var/turf/spawnpoint = locate( + bottom_left.x + initial(port_type.dwidth), + bottom_left.y + initial(port_type.dheight), + bottom_left.z, + ) var/obj/docking_port/stationary/picked/whiteship/port = new(spawnpoint) var/list/ids = port.shuttlekeys diff --git a/code/modules/unit_tests/chain_pull_through_space.dm b/code/modules/unit_tests/chain_pull_through_space.dm index 86b0cc69d1c..b767b010495 100644 --- a/code/modules/unit_tests/chain_pull_through_space.dm +++ b/code/modules/unit_tests/chain_pull_through_space.dm @@ -11,15 +11,16 @@ ..() //reserve a tile that is always empty for our z destination - reserved = SSmapping.RequestBlockReservation(5,5) + reserved = SSmapping.request_turf_block_reservation(5, 5, 1) // Create a space tile that goes to another z-level claimed_tile = run_loc_floor_bottom_left.type space_tile = run_loc_floor_bottom_left.ChangeTurf(/turf/open/space) - space_tile.destination_x = round(reserved.bottom_left_coords[1] + (reserved.width-1) / 2) - space_tile.destination_y = round(reserved.bottom_left_coords[2] + (reserved.height-1) / 2) - space_tile.destination_z = reserved.bottom_left_coords[3] + var/turf/bottom_left = reserved.bottom_left_turfs[1] + space_tile.destination_x = round(bottom_left.x + (reserved.width-1) / 2) + space_tile.destination_y = round(bottom_left.y + (reserved.height-1) / 2) + space_tile.destination_z = bottom_left.z // Create our list of humans, all adjacent to one another alice = new(locate(run_loc_floor_bottom_left.x + 2, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z)) diff --git a/modular_skyrat/modules/liquids/code/ocean_turfs.dm b/modular_skyrat/modules/liquids/code/ocean_turfs.dm index dc25e69d7dd..35066f09857 100644 --- a/modular_skyrat/modules/liquids/code/ocean_turfs.dm +++ b/modular_skyrat/modules/liquids/code/ocean_turfs.dm @@ -9,7 +9,7 @@ for(var/obj/structure/flora/plant in contents) qdel(plant) - var/turf/T = below() + var/turf/T = GET_TURF_BELOW(src) if(T) if(T.turf_flags & NO_RUINS) ChangeTurf(replacement_turf, null, CHANGETURF_IGNORE_AIR) diff --git a/tgstation.dme b/tgstation.dme index a7efaf7782a..0850981fe74 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -300,6 +300,7 @@ #include "code\__DEFINES\dcs\signals\signals_janitor.dm" #include "code\__DEFINES\dcs\signals\signals_key.dm" #include "code\__DEFINES\dcs\signals\signals_ladder.dm" +#include "code\__DEFINES\dcs\signals\signals_lazy_templates.dm" #include "code\__DEFINES\dcs\signals\signals_leash.dm" #include "code\__DEFINES\dcs\signals\signals_lift.dm" #include "code\__DEFINES\dcs\signals\signals_light_eater.dm"