From 03a22ca16d95bd5e7f45c0a087d457726cad3d82 Mon Sep 17 00:00:00 2001 From: CitadelStationBot Date: Mon, 18 Jun 2018 13:51:02 -0500 Subject: [PATCH] [MIRROR] Transit space refactor (#7130) * Transit space refactor * Update bitfields.dm --- code/__DEFINES/flags.dm | 12 +- code/__DEFINES/maps.dm | 4 +- code/__HELPERS/level_traits.dm | 2 +- code/_globalvars/bitfields.dm | 4 +- code/controllers/subsystem/mapping.dm | 103 +++++++++++- code/controllers/subsystem/shuttle.dm | 151 ++++-------------- code/datums/components/stationloving.dm | 2 +- code/game/area/areas/shuttles.dm | 1 + code/game/atoms.dm | 2 +- .../game/machinery/computer/communications.dm | 2 +- code/modules/admin/verbs/debug.dm | 10 +- code/modules/antagonists/nukeop/nukeop.dm | 3 +- code/modules/events/pirates.dm | 2 +- .../space_management/space_reservation.dm | 70 ++++++++ .../mining/equipment/wormhole_jaunter.dm | 2 +- .../mining/lavaland/necropolis_chests.dm | 2 +- code/modules/shuttle/docking.dm | 6 +- code/modules/shuttle/shuttle.dm | 25 +-- tgstation.dme | 1 + 19 files changed, 241 insertions(+), 163 deletions(-) create mode 100644 code/modules/mapping/space_management/space_reservation.dm diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index f566492ec3..43cdbcb646 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -30,12 +30,12 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define ADMIN_SPAWNED_1 (1<<15) //was this spawned by an admin? used for stat tracking stuff. //turf-only flags -#define NOJAUNT_1 (1<<0) -#define UNUSED_TRANSIT_TURF_1 (1<<1) -#define CAN_BE_DIRTY_1 (1<<2) // If a turf can be made dirty at roundstart. This is also used in areas. -#define NO_DEATHRATTLE_1 (1<<4) // Do not notify deadchat about any deaths that occur on this turf. -#define NO_RUINS_1 (1<<5) //Blocks ruins spawning on the turf -#define NO_LAVA_GEN_1 (1<<6) //Blocks lava rivers being generated on the turf +#define NOJAUNT_1 (1<<0) +#define UNUSED_RESERVATION_TURF_1 (1<<1) +#define CAN_BE_DIRTY_1 (1<<2) // If a turf can be made dirty at roundstart. This is also used in areas. +#define NO_DEATHRATTLE_1 (1<<4) // Do not notify deadchat about any deaths that occur on this turf. +#define NO_RUINS_1 (1<<5) //Blocks ruins spawning on the turf +#define NO_LAVA_GEN_1 (1<<6) //Blocks lava rivers being generated on the turf /* These defines are used specifically with the atom/pass_flags bitmask diff --git a/code/__DEFINES/maps.dm b/code/__DEFINES/maps.dm index c86e47709c..98d022d27e 100644 --- a/code/__DEFINES/maps.dm +++ b/code/__DEFINES/maps.dm @@ -33,7 +33,7 @@ require only minor tweaks. #define ZTRAIT_STATION "Station" #define ZTRAIT_MINING "Mining" #define ZTRAIT_REEBE "Reebe" -#define ZTRAIT_TRANSIT "Transit" +#define ZTRAIT_RESERVED "Transit/Reserved" #define ZTRAIT_AWAY "Away Mission" #define ZTRAIT_SPACE_RUINS "Space Ruins" #define ZTRAIT_LAVA_RUINS "Lava Ruins" @@ -76,6 +76,8 @@ require only minor tweaks. #define CAMERA_LOCK_CENTCOM 4 #define CAMERA_LOCK_REEBE 8 +//Reserved/Transit turf type +#define RESERVED_TURF_TYPE /turf/open/space/basic //What the turf is when not being used //Ruin Generation diff --git a/code/__HELPERS/level_traits.dm b/code/__HELPERS/level_traits.dm index 4d20c9b513..b73a0aa83d 100644 --- a/code/__HELPERS/level_traits.dm +++ b/code/__HELPERS/level_traits.dm @@ -9,7 +9,7 @@ #define is_reebe(z) SSmapping.level_trait(z, ZTRAIT_REEBE) -#define is_transit_level(z) SSmapping.level_trait(z, ZTRAIT_TRANSIT) +#define is_reserved_level(z) SSmapping.level_trait(z, ZTRAIT_RESERVED) #define is_away_level(z) SSmapping.level_trait(z, ZTRAIT_AWAY) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 5ef8dc6d1b..aa872fa75e 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -111,8 +111,8 @@ GLOBAL_LIST_INIT(bitfields, list( ), "flags_1" = list( "NOJAUNT_1" = NOJAUNT_1, - "NODROP_1 / UNUSED_TRANSIT_TURF_1 (turfs)" = NODROP_1, - "NOBLUDGEON_1 / CAN_BE_DIRTY_1 (turfs)" = NOBLUDGEON_1, + "UNUSED_RESERVATION_TURF_1" = UNUSED_RESERVATION_TURF_1, + "CAN_BE_DIRTY_1" = CAN_BE_DIRTY_1, "HEAR_1 / NO_DEATHRATTLE_1 (turfs)" = HEAR_1, "CHECK_RICOCHET_1 / NO_RUINS_1 (turfs)" = CHECK_RICOCHET_1, "CONDUCT_1 / NO_LAVA_GEN_1" = CONDUCT_1, diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index 2d99012881..e2698670e9 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -21,6 +21,11 @@ SUBSYSTEM_DEF(mapping) var/list/areas_in_z = list() var/loading_ruins = FALSE + var/list/turf/unused_turfs = list() //Not actually unused turfs they're unused but reserved for use for whatever requests them. "[zlevel_of_turf]" = list(turfs) + var/list/datum/turf_reservations //list of turf reservations + var/list/used_turfs = list() //list of turf = datum/turf_reservation + + var/clearing_reserved_turfs = FALSE // Z-manager stuff var/station_start // should only be used for maploading-related tasks @@ -41,6 +46,8 @@ SUBSYSTEM_DEF(mapping) /datum/controller/subsystem/mapping/Initialize(timeofday) + if(initialized) + return if(config.defaulted) to_chat(world, "Unable to load next map config, defaulting to Box Station") loader = new @@ -58,12 +65,13 @@ SUBSYSTEM_DEF(mapping) ++space_levels_so_far empty_space = add_new_zlevel("Empty Area [space_levels_so_far]", list(ZTRAIT_LINKAGE = CROSSLINKED)) // and the transit level - transit = add_new_zlevel("Transit", list(ZTRAIT_TRANSIT = TRUE)) + transit = add_new_zlevel("Transit/Reserved", list(ZTRAIT_RESERVED = TRUE)) // Pick a random away mission. if(CONFIG_GET(flag/roundstart_away)) createRandomZlevel() + // Generate mining ruins loading_ruins = TRUE var/list/lava_ruins = levels_by_trait(ZTRAIT_LAVA_RUINS) @@ -83,12 +91,42 @@ SUBSYSTEM_DEF(mapping) setup_map_transitions() generate_station_area_list() QDEL_NULL(loader) + initialize_reserved_level() ..() /* Nuke threats, for making the blue tiles on the station go RED Used by the AI doomsday and the self destruct nuke. */ +/datum/controller/subsystem/mapping/proc/wipe_reservations(wipe_safety_delay = 100) + if(clearing_reserved_turfs || !initialized) //in either case this is just not needed. + return + clearing_reserved_turfs = TRUE + SSshuttle.transit_requesters.Cut() + message_admins("Clearing dynamic reservation space.") + var/list/obj/docking_port/mobile/in_transit = list() + for(var/i in SSshuttle.transit) + var/obj/docking_port/stationary/transit/T = i + if(!istype(T)) + continue + in_transit[T] = T.get_docked() + var/go_ahead = world.time + wipe_safety_delay + if(in_transit.len) + message_admins("Shuttles in transit detected. Attempting to fast travel. Timeout is [wipe_safety_delay/10] seconds.") + var/list/cleared = list() + for(var/i in in_transit) + INVOKE_ASYNC(src, .proc/safety_clear_transit_dock, i, in_transit[i], cleared) + UNTIL((go_ahead < world.time) || (cleared.len == in_transit.len)) + do_wipe_turf_reservations() + clearing_reserved_turfs = FALSE + +/datum/controller/subsystem/mapping/proc/safety_clear_transit_dock(obj/docking_port/stationary/transit/T, obj/docking_port/mobile/M, list/returning) + M.setTimer(0) + var/error = M.initiate_docking(M.destination, M.preferred_direction) + if(!error) + returning += M + qdel(T, TRUE) + /datum/controller/subsystem/mapping/proc/add_nuke_threat(datum/nuke) nuke_threats[nuke] = TRUE check_nuke_threats() @@ -108,16 +146,22 @@ SUBSYSTEM_DEF(mapping) /datum/controller/subsystem/mapping/Recover() flags |= SS_NO_INIT + initialized = SSmapping.initialized map_templates = SSmapping.map_templates ruins_templates = SSmapping.ruins_templates space_ruins_templates = SSmapping.space_ruins_templates lava_ruins_templates = SSmapping.lava_ruins_templates shuttle_templates = SSmapping.shuttle_templates shelter_templates = SSmapping.shelter_templates + unused_turfs = SSmapping.unused_turfs + turf_reservations = SSmapping.turf_reservations + used_turfs = SSmapping.used_turfs config = SSmapping.config next_map_config = SSmapping.next_map_config + clearing_reserved_turfs = SSmapping.clearing_reserved_turfs + z_list = SSmapping.z_list #define INIT_ANNOUNCE(X) to_chat(world, "[X]"); log_world(X) @@ -328,7 +372,6 @@ GLOBAL_LIST_EMPTY(the_station_areas) shelter_templates[S.shelter_id] = S map_templates[S.shelter_id] = S - //Manual loading of away missions. /client/proc/admin_away() set name = "Load Away Mission" @@ -381,4 +424,58 @@ GLOBAL_LIST_EMPTY(the_station_areas) break //Link station gate with away gate and remove wait time. GLOB.the_gateway.awaygate = new_gate - GLOB.the_gateway.wait = world.time \ No newline at end of file + GLOB.the_gateway.wait = world.time + +/datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override) + UNTIL(initialized && !clearing_reserved_turfs) + var/datum/turf_reservation/reserve = new type + if(turf_type_override) + reserve.turf_type = turf_type_override + if(!z) + for(var/i in levels_by_trait(ZTRAIT_RESERVED)) + if(reserve.Reserve(width, height, i)) + return reserve + else + if(!level_trait(z, ZTRAIT_RESERVED)) + qdel(reserve) + return + else + if(reserve.Reserve(width, height, z)) + return reserve + QDEL_NULL(reserve) + +//This is not for wiping reserved levels, use wipe_reservations() for that. +/datum/controller/subsystem/mapping/proc/initialize_reserved_level() + UNTIL(!clearing_reserved_turfs) //regardless, lets add a check just in case. + clearing_reserved_turfs = TRUE //This operation will likely clear any existing reservations, so lets make sure nothing tries to make one while we're doing it. + for(var/i in levels_by_trait(ZTRAIT_RESERVED)) + var/turf/A = get_turf(locate(SHUTTLE_TRANSIT_BORDER,SHUTTLE_TRANSIT_BORDER,i)) + var/turf/B = get_turf(locate(world.maxx - SHUTTLE_TRANSIT_BORDER,world.maxy - SHUTTLE_TRANSIT_BORDER,i)) + reserve_turfs(block(A, B)) + clearing_reserved_turfs = FALSE + +/datum/controller/subsystem/mapping/proc/reserve_turfs(list/turfs) + for(var/i in turfs) + var/turf/T = i + T.empty(RESERVED_TURF_TYPE, RESERVED_TURF_TYPE, null, TRUE) + LAZYINITLIST(unused_turfs["[T.z]"]) + unused_turfs["[T.z]"] |= T + T.flags_1 |= UNUSED_RESERVATION_TURF_1 + CHECK_TICK + +//DO NOT CALL THIS PROC DIRECTLY, CALL wipe_reservations(). +/datum/controller/subsystem/mapping/proc/do_wipe_turf_reservations() + UNTIL(initialized) //This proc is for AFTER init, before init turf reservations won't even exist and using this will likely break things. + for(var/i in turf_reservations) + var/datum/turf_reservation/TR = i + if(!QDELETED(TR)) + qdel(TR, TRUE) + UNSETEMPTY(turf_reservations) + var/list/clearing = list() + for(var/l in unused_turfs) //unused_turfs is a assoc list by z = list(turfs) + if(islist(unused_turfs[l])) + clearing |= unused_turfs[l] + clearing |= used_turfs //used turfs is an associative list, BUT, reserve_turfs() can still handle it. If the code above works properly, this won't even be needed as the turfs would be freed already. + unused_turfs.Cut() + used_turfs.Cut() + reserve_turfs(clearing) diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index fe57bca354..d67ef40597 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -1,4 +1,3 @@ -#define HIGHLIGHT_DYNAMIC_TRANSIT 0 #define MAX_TRANSIT_REQUEST_RETRIES 10 SUBSYSTEM_DEF(shuttle) @@ -14,10 +13,8 @@ SUBSYSTEM_DEF(shuttle) var/list/stationary = list() var/list/transit = list() - var/list/turf/transit_turfs = list() var/list/transit_requesters = list() var/list/transit_request_failures = list() - var/clear_transit = FALSE //emergency shuttle stuff var/obj/docking_port/mobile/emergency/emergency @@ -67,15 +64,8 @@ SUBSYSTEM_DEF(shuttle) continue supply_packs[P.type] = P - if(!transit_turfs.len) - setup_transit_zone() - initial_load() -#ifdef HIGHLIGHT_DYNAMIC_TRANSIT - color_space() -#endif - if(!arrivals) WARNING("No /obj/docking_port/mobile/arrivals placed on the map!") if(!emergency) @@ -95,33 +85,6 @@ SUBSYSTEM_DEF(shuttle) S.load_roundstart() CHECK_TICK -/datum/controller/subsystem/shuttle/proc/setup_transit_zone() - // transit zone - var/z = SSmapping.transit.z_value - var/turf/A = get_turf(locate(SHUTTLE_TRANSIT_BORDER,SHUTTLE_TRANSIT_BORDER,z)) - var/turf/B = get_turf(locate(world.maxx - SHUTTLE_TRANSIT_BORDER,world.maxy - SHUTTLE_TRANSIT_BORDER,z)) - for(var/i in block(A, B)) - var/turf/T = i - T.ChangeTurf(/turf/open/space) - transit_turfs += T - T.flags_1 |= UNUSED_TRANSIT_TURF_1 - -#ifdef HIGHLIGHT_DYNAMIC_TRANSIT -/datum/controller/subsystem/shuttle/proc/color_space() - var/z = SSmapping.transit.z_value - var/turf/A = get_turf(locate(SHUTTLE_TRANSIT_BORDER,SHUTTLE_TRANSIT_BORDER,z)) - var/turf/B = get_turf(locate(world.maxx - SHUTTLE_TRANSIT_BORDER,world.maxy - SHUTTLE_TRANSIT_BORDER,z)) - for(var/i in block(A, B)) - var/turf/T = i - // Only dying the "pure" space, not the transit tiles - if(istype(T, /turf/open/space/transit) || !isspaceturf(T)) - continue - if((T.x == A.x) || (T.x == B.x) || (T.y == A.y) || (T.y == B.y)) - T.color = "#ffff00" - else - T.color = "#00ffff" -#endif - /datum/controller/subsystem/shuttle/fire() for(var/thing in mobile) if(!thing) @@ -129,12 +92,10 @@ SUBSYSTEM_DEF(shuttle) continue var/obj/docking_port/mobile/P = thing P.check() - var/changed_transit = FALSE for(var/thing in transit) var/obj/docking_port/stationary/transit/T = thing if(!T.owner) qdel(T, force=TRUE) - changed_transit = TRUE // This next one removes transit docks/zones that aren't // immediately being used. This will mean that the zone creation // code will be running a lot. @@ -145,32 +106,21 @@ SUBSYSTEM_DEF(shuttle) var/not_in_use = (!T.get_docked()) if(idle && not_centcom_evac && not_in_use) qdel(T, force=TRUE) - changed_transit = TRUE - if(clear_transit) - transit_requesters.Cut() - for(var/i in transit) - qdel(i, force=TRUE) - setup_transit_zone() - clear_transit = FALSE - changed_transit = TRUE -#ifdef HIGHLIGHT_DYNAMIC_TRANSIT - if(changed_transit) - color_space() -#endif CheckAutoEvac() - while(transit_requesters.len) - var/requester = popleft(transit_requesters) - var/success = generate_transit_dock(requester) - if(!success) // BACK OF THE QUEUE - transit_request_failures[requester]++ - if(transit_request_failures[requester] < MAX_TRANSIT_REQUEST_RETRIES) - transit_requesters += requester - else - var/obj/docking_port/mobile/M = requester - M.transit_failure() - if(MC_TICK_CHECK) - break + if(!SSmapping.clearing_reserved_turfs) + while(transit_requesters.len) + var/requester = popleft(transit_requesters) + var/success = generate_transit_dock(requester) + if(!success) // BACK OF THE QUEUE + transit_request_failures[requester]++ + if(transit_request_failures[requester] < MAX_TRANSIT_REQUEST_RETRIES) + transit_requesters += requester + else + var/obj/docking_port/mobile/M = requester + M.transit_failure() + if(MC_TICK_CHECK) + break /datum/controller/subsystem/shuttle/proc/CheckAutoEvac() if(emergencyNoEscape || emergencyNoRecall || !emergency || !SSticker.HasRoundStarted()) @@ -475,43 +425,29 @@ SUBSYSTEM_DEF(shuttle) if(EAST, WEST) transit_width += M.height transit_height += M.width + /* to_chat(world, "The attempted transit dock will be [transit_width] width, and \) [transit_height] in height. The travel dir is [travel_dir]." */ - // Then find a place to put the zone + var/transit_path = /turf/open/space/transit + switch(travel_dir) + if(NORTH) + transit_path = /turf/open/space/transit/north + if(SOUTH) + transit_path = /turf/open/space/transit/south + if(EAST) + transit_path = /turf/open/space/transit/east + if(WEST) + transit_path = /turf/open/space/transit/west - var/list/proposed_zone + var/datum/turf_reservation/proposal = SSmapping.RequestBlockReservation(transit_width, transit_height, null, /datum/turf_reservation/transit, transit_path) - base: - for(var/i in transit_turfs) - CHECK_TICK - var/turf/topleft = i - if(!(topleft.flags_1 & UNUSED_TRANSIT_TURF_1)) - continue - var/turf/bottomright = locate(topleft.x + transit_width, - topleft.y + transit_height, topleft.z) - if(!bottomright) - continue - if(!(bottomright.flags_1 & UNUSED_TRANSIT_TURF_1)) - continue - - proposed_zone = block(topleft, bottomright) - if(!proposed_zone) - continue - for(var/j in proposed_zone) - var/turf/T = j - if(!T) - continue base - if(!(T.flags_1 & UNUSED_TRANSIT_TURF_1)) - continue base - break base - - if((!proposed_zone) || (!proposed_zone.len)) + if(!istype(proposal)) return FALSE - var/turf/topleft = proposed_zone[1] + var/turf/bottomleft = locate(proposal.bottom_left_coords[1], proposal.bottom_left_coords[2], proposal.bottom_left_coords[3]) // Then create a transit docking port in the middle var/coords = M.return_coords(0, 0, dock_dir) /* 0------2 @@ -530,41 +466,24 @@ SUBSYSTEM_DEF(shuttle) var/y2 = min(y0, y1) // Then invert the numbers - var/transit_x = topleft.x + SHUTTLE_TRANSIT_BORDER + abs(x2) - var/transit_y = topleft.y + SHUTTLE_TRANSIT_BORDER + abs(y2) + var/transit_x = bottomleft.x + SHUTTLE_TRANSIT_BORDER + abs(x2) + var/transit_y = bottomleft.y + SHUTTLE_TRANSIT_BORDER + abs(y2) - var/transit_path = /turf/open/space/transit - switch(travel_dir) - if(NORTH) - transit_path = /turf/open/space/transit/north - if(SOUTH) - transit_path = /turf/open/space/transit/south - if(EAST) - transit_path = /turf/open/space/transit/east - if(WEST) - transit_path = /turf/open/space/transit/west - - var/turf/midpoint = locate(transit_x, transit_y, topleft.z) + var/turf/midpoint = locate(transit_x, transit_y, bottomleft.z) if(!midpoint) return FALSE var/area/shuttle/transit/A = new() A.parallax_movedir = travel_dir - A.contents = proposed_zone + A.contents = proposal.reserved_turfs var/obj/docking_port/stationary/transit/new_transit_dock = new(midpoint) - new_transit_dock.assigned_turfs = proposed_zone + new_transit_dock.reserved_area = proposal new_transit_dock.name = "Transit for [M.id]/[M.name]" new_transit_dock.owner = M new_transit_dock.assigned_area = A - // Add 180, because ports point inwards, rather than outwards new_transit_dock.setDir(angle2dir(dock_angle)) - for(var/i in new_transit_dock.assigned_turfs) - var/turf/T = i - T.ChangeTurf(transit_path) - T.flags_1 &= ~(UNUSED_TRANSIT_TURF_1) - M.assigned_transit = new_transit_dock return new_transit_dock @@ -575,9 +494,6 @@ SUBSYSTEM_DEF(shuttle) stationary = SSshuttle.stationary if (istype(SSshuttle.transit)) transit = SSshuttle.transit - - if (istype(SSshuttle.transit_turfs)) - transit_turfs = SSshuttle.transit_turfs if (istype(SSshuttle.transit_requesters)) transit_requesters = SSshuttle.transit_requesters if (istype(SSshuttle.transit_request_failures)) @@ -615,9 +531,6 @@ SUBSYSTEM_DEF(shuttle) if (istype(SSshuttle.shuttle_purchase_requirements_met)) shuttle_purchase_requirements_met = SSshuttle.shuttle_purchase_requirements_met - if (clear_transit) - WARNING("The shuttle subsystem crashed and was recovered while clearing transit.") - centcom_message = SSshuttle.centcom_message ordernum = SSshuttle.ordernum points = SSshuttle.points diff --git a/code/datums/components/stationloving.dm b/code/datums/components/stationloving.dm index 2e1ee72a74..99e99f6465 100644 --- a/code/datums/components/stationloving.dm +++ b/code/datums/components/stationloving.dm @@ -59,7 +59,7 @@ return FALSE if (is_station_level(T.z) || is_centcom_level(T.z)) return TRUE - if (is_transit_level(T.z)) + if (is_reserved_level(T.z)) if (is_type_in_typecache(A, allowed_shuttles)) return TRUE diff --git a/code/game/area/areas/shuttles.dm b/code/game/area/areas/shuttles.dm index 073e7714b2..90a6bbd3b6 100644 --- a/code/game/area/areas/shuttles.dm +++ b/code/game/area/areas/shuttles.dm @@ -67,6 +67,7 @@ /area/shuttle/transit name = "Hyperspace" desc = "Weeeeee" + dynamic_lighting = DYNAMIC_LIGHTING_DISABLED /area/shuttle/custom name = "Custom player shuttle" diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 95ca007031..f81da22d7f 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -112,7 +112,7 @@ if(!T) return FALSE - if(is_transit_level(T.z)) + if(is_reserved_level(T.z)) for(var/A in SSshuttle.mobile) var/obj/docking_port/mobile/M = A if(M.launch_status == ENDGAME_TRANSIT) diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 61dc3ad919..445ed389b7 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -51,7 +51,7 @@ /obj/machinery/computer/communications/Topic(href, href_list) if(..()) return - if(!is_station_level(z) && !is_transit_level(z)) //Can only use in transit and on SS13 + if(!is_station_level(z) && !is_reserved_level(z)) //Can only use in transit and on SS13 to_chat(usr, "Unable to establish a connection: \black You're too far away from the station!") return usr.set_machine(src) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index e6ddd72e3a..d34e1ebd42 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -961,15 +961,17 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention) /client/proc/clear_dynamic_transit() set category = "Debug" - set name = "Clear Dynamic Transit" - set desc = "Deallocates all transit space, restoring it to round start conditions." + set name = "Clear Dynamic Turf Reservations" + set desc = "Deallocates all reserved space, restoring it to round start conditions." if(!holder) return - SSshuttle.clear_transit = TRUE + var/answer = alert("WARNING: THIS WILL WIPE ALL RESERVED SPACE TO A CLEAN SLATE! ANY MOVING SHUTTLES, ELEVATORS, OR IN-PROGRESS PHOTOGRAPHY WILL BE DELETED!", "Really wipe dynamic turfs?", "YES", "NO") + if(answer != "YES") + return message_admins("[key_name_admin(src)] cleared dynamic transit space.") SSblackbox.record_feedback("tally", "admin_verb", 1, "Clear Dynamic Transit") // If... log_admin("[key_name(src)] cleared dynamic transit space.") - + SSmapping.wipe_reservations() //this goes after it's logged, incase something horrible happens. /client/proc/toggle_medal_disable() set category = "Debug" diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm index 1796227f9c..3df9d1d9ca 100644 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ b/code/modules/antagonists/nukeop/nukeop.dm @@ -258,7 +258,8 @@ /datum/team/nuclear/proc/syndies_escaped() var/obj/docking_port/mobile/S = SSshuttle.getShuttle("syndicate") - return S && (is_centcom_level(S.z) || is_transit_level(S.z)) + var/obj/docking_port/stationary/transit/T = locate() in S.loc + return S && (is_centcom_level(S.z) || T) /datum/team/nuclear/proc/get_result() var/evacuation = SSshuttle.emergency.mode == SHUTTLE_ENDGAME diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm index 8a9df2f58f..8b904ae9b8 100644 --- a/code/modules/events/pirates.dm +++ b/code/modules/events/pirates.dm @@ -209,7 +209,7 @@ /obj/docking_port/mobile/pirate/initiate_docking(obj/docking_port/stationary/new_dock, movement_direction, force=FALSE) . = ..() - if(. == DOCKING_SUCCESS && !is_transit_level(new_dock.z)) + if(. == DOCKING_SUCCESS && !is_reserved_level(new_dock.z)) engines_cooling = TRUE addtimer(CALLBACK(src,.proc/reset_cooldown),engine_cooldown,TIMER_UNIQUE) diff --git a/code/modules/mapping/space_management/space_reservation.dm b/code/modules/mapping/space_management/space_reservation.dm new file mode 100644 index 0000000000..38e7e4ecad --- /dev/null +++ b/code/modules/mapping/space_management/space_reservation.dm @@ -0,0 +1,70 @@ + +//Yes, they can only be rectangular. +//Yes, I'm sorry. +/datum/turf_reservation + var/list/reserved_turfs = list() + var/bottom_left_coords[3] + var/top_right_coords[3] + var/wipe_reservation_on_release = TRUE + var/turf_type = /turf/open/space + +/datum/turf_reservation/transit + turf_type = /turf/open/space/transit + +/datum/turf_reservation/proc/Release() + var/v = reserved_turfs.Copy() + for(var/i in reserved_turfs) + reserved_turfs -= i + SSmapping.used_turfs -= i + SSmapping.reserve_turfs(v) + +/datum/turf_reservation/proc/Reserve(width, height, zlevel) + if(width > world.maxx || height > world.maxy) + return FALSE + var/list/avail = SSmapping.unused_turfs["[zlevel]"] + var/turf/BL + var/turf/TR + var/list/turf/final = list() + var/passing = FALSE + for(var/i in avail) + CHECK_TICK + BL = i + if(!(BL.flags_1 & UNUSED_RESERVATION_TURF_1)) + continue + if(BL.x + width > world.maxx || BL.y + height > world.maxy) + continue + TR = locate(BL.x + width, BL.y + height, BL.z) + if(!(TR.flags_1 & UNUSED_RESERVATION_TURF_1)) + continue + final = block(BL, TR) + if(!final) + continue + passing = TRUE + for(var/I in final) + var/turf/checking = I + if(!(checking.flags_1 & UNUSED_RESERVATION_TURF_1)) + passing = FALSE + break + if(!passing) + continue + 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_1 + SSmapping.unused_turfs["[T.z]"] -= T + SSmapping.used_turfs[T] = src + T.ChangeTurf(turf_type, turf_type) + return TRUE + +/datum/turf_reservation/New() + LAZYADD(SSmapping.turf_reservations, src) + +/datum/turf_reservation/Destroy() + Release() + LAZYREMOVE(SSmapping.turf_reservations, src) + return ..() diff --git a/code/modules/mining/equipment/wormhole_jaunter.dm b/code/modules/mining/equipment/wormhole_jaunter.dm index 437d6fb26f..9cb3f5c323 100644 --- a/code/modules/mining/equipment/wormhole_jaunter.dm +++ b/code/modules/mining/equipment/wormhole_jaunter.dm @@ -20,7 +20,7 @@ /obj/item/wormhole_jaunter/proc/turf_check(mob/user) var/turf/device_turf = get_turf(user) - if(!device_turf || is_centcom_level(device_turf.z) || is_transit_level(device_turf.z)) + if(!device_turf || is_centcom_level(device_turf.z) || is_reserved_level(device_turf.z)) to_chat(user, "You're having difficulties getting the [src.name] to work.") return FALSE return TRUE diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 17476c1618..bcb186a776 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -595,7 +595,7 @@ to_chat(user, "You unfold the ladder. It extends much farther than you were expecting.") var/last_ladder = null for(var/i in 1 to world.maxz) - if(is_centcom_level(i) || is_transit_level(i) || is_reebe(i) || is_away_level(i)) + if(is_centcom_level(i) || is_reserved_level(i) || is_reebe(i) || is_away_level(i)) continue var/turf/T2 = locate(ladder_x, ladder_y, i) last_ladder = new /obj/structure/ladder/unbreakable/jacob(T2, null, last_ladder) diff --git a/code/modules/shuttle/docking.dm b/code/modules/shuttle/docking.dm index c0052845c7..fa78c8cb99 100644 --- a/code/modules/shuttle/docking.dm +++ b/code/modules/shuttle/docking.dm @@ -16,7 +16,7 @@ // The area that gets placed under where the shuttle moved from var/underlying_area_type = SHUTTLE_DEFAULT_UNDERLYING_AREA - + if(old_dock) //Dock overwrites underlying_area_type = old_dock.area_type @@ -105,7 +105,7 @@ list/areas_to_move, rotation, ) - + for(var/i in 1 to old_turfs.len) CHECK_TICK var/turf/oldT = old_turfs[i] @@ -173,7 +173,7 @@ movement_direction, area/underlying_old_area, ) - + underlying_old_area.afterShuttleMove() // Parallax handling diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 363b4408b2..92fb95c00e 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -202,7 +202,7 @@ /obj/docking_port/stationary/transit name = "In Transit" - var/list/turf/assigned_turfs = list() + var/datum/turf_reservation/reserved_area var/area/shuttle/transit/assigned_area var/obj/docking_port/mobile/owner @@ -210,14 +210,6 @@ . = ..() SSshuttle.transit += src -/obj/docking_port/stationary/transit/proc/dezone() - for(var/i in 1 to assigned_turfs.len) - var/turf/T = assigned_turfs[i] - if(istype(T, /turf/open/space/transit)) - T.ChangeTurf(/turf/open/space) - T.assemble_baseturfs(initial(T.baseturfs)) - T.flags_1 |= UNUSED_TRANSIT_TURF_1 - /obj/docking_port/stationary/transit/Destroy(force=FALSE) if(force) if(get_docked()) @@ -227,11 +219,10 @@ if(owner.assigned_transit == src) owner.assigned_transit = null owner = null - if(assigned_turfs) - dezone() - assigned_turfs.Cut() - assigned_turfs = null - . = ..() + if(!QDELETED(reserved_area)) + qdel(reserved_area) + reserved_area = null + return ..() /obj/docking_port/mobile name = "shuttle" @@ -282,7 +273,7 @@ SSshuttle.mobile -= src destination = null previous = null - assigned_transit = null + QDEL_NULL(assigned_transit) //don't need it where we're goin'! shuttle_areas = null remove_ripples() . = ..() @@ -433,7 +424,7 @@ underlying_area_type = current_dock.area_type var/list/old_turfs = return_ordered_turfs(x, y, z, dir) - + var/area/underlying_area for(var/i in GLOB.sortedAreas) var/area/place = i @@ -451,7 +442,7 @@ underlying_area.contents += oldT oldT.change_area(old_area, underlying_area) oldT.empty(FALSE) - + // Here we locate the bottomost shuttle boundary and remove all turfs above it var/list/baseturf_cache = oldT.baseturfs for(var/k in 1 to length(baseturf_cache)) diff --git a/tgstation.dme b/tgstation.dme index 527db71b8c..39ecf1a066 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -1752,6 +1752,7 @@ #include "code\modules\mapping\reader.dm" #include "code\modules\mapping\ruins.dm" #include "code\modules\mapping\space_management\space_level.dm" +#include "code\modules\mapping\space_management\space_reservation.dm" #include "code\modules\mapping\space_management\space_transition.dm" #include "code\modules\mapping\space_management\traits.dm" #include "code\modules\mapping\space_management\zlevel_manager.dm"