diff --git a/_maps/lambdastation.json b/_maps/lambdastation.json index 997f6b152eb7..98a03d4eba7f 100644 --- a/_maps/lambdastation.json +++ b/_maps/lambdastation.json @@ -16,7 +16,7 @@ "Up":1 }, { - "Down":-1 + "Down":1 } ] } diff --git a/_maps/layeniastation.json b/_maps/layeniastation.json index 8b1ea690476e..54040eb68145 100644 --- a/_maps/layeniastation.json +++ b/_maps/layeniastation.json @@ -16,7 +16,7 @@ "Linkage": "Cross" }, { - "Down": -1, + "Down": 1, "Baseturf": "/turf/open/openspace", "Linkage": "Cross" } diff --git a/_maps/smexistation.json b/_maps/smexistation.json index 7ccae36adc88..110ada67cc75 100644 --- a/_maps/smexistation.json +++ b/_maps/smexistation.json @@ -25,7 +25,7 @@ "Baseturf":"/turf/open/lava/plasma/ice_moon" }, { - "Down":-1, + "Down":1, "Up":1, "Mining":true, "Linkage":null, @@ -34,7 +34,7 @@ "Baseturf":"/turf/open/openspace/icemoon" }, { - "Down":-1, + "Down":1, "Mining":true, "Linkage":null, "Gravity":true, diff --git a/_maps/snaxi.json b/_maps/snaxi.json index ae8f8309c8ef..44bf05fa0d85 100644 --- a/_maps/snaxi.json +++ b/_maps/snaxi.json @@ -26,7 +26,7 @@ "Baseturf":"/turf/open/lava/plasma/ice_moon" }, { - "Down":-1, + "Down":1, "Up":1, "Station":0, "Mining":true, @@ -36,7 +36,7 @@ "Baseturf":"/turf/open/openspace/icemoon" }, { - "Down":-1, + "Down":1, "Mining":true, "Linkage":null, "Gravity":true, diff --git a/code/__DEFINES/maps.dm b/code/__DEFINES/maps.dm index c00da6a7e123..1c3eb712c57e 100644 --- a/code/__DEFINES/maps.dm +++ b/code/__DEFINES/maps.dm @@ -53,7 +53,7 @@ require only minor tweaks. // number - default gravity if there's no gravity generators or area overrides present #define ZTRAIT_GRAVITY "Gravity" -// numeric offsets - e.g. {"Down": -1} means that chasms will fall to z - 1 rather than oblivion +// numeric offsets - e.g. {"Down": 1} means that chasms will fall to z - 1 rather than oblivion #define ZTRAIT_UP "Up" #define ZTRAIT_DOWN "Down" diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index f54e2766fe14..6695aa6a76e8 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -40,13 +40,21 @@ SUBSYSTEM_DEF(mapping) // Z-manager stuff var/station_start // should only be used for maploading-related tasks var/space_levels_so_far = 0 - var/list/z_list + ///list of all z level datums in the order of their z (z level 1 is at index 1, etc.) + var/list/datum/space_level/z_list + ///list of all z level indices that form multiz connections and whether theyre linked up or down + ///list of lists, inner lists are of the form: list("up or down link direction" = TRUE) + var/list/multiz_levels = list() var/datum/space_level/transit var/datum/space_level/empty_space var/num_of_res_levels = 1 /// Lookup for zlevel to station z. text = num. var/list/z_to_station_z_index + ///shows the default gravity value for each z level. recalculated when gravity generators change. + ///associative list of the form: list("[z level num]" = max generator gravity in that z level OR the gravity level trait) + var/list/gravity_by_z_level = list() + var/stat_map_name = "Loading..." /// Lookup list for random generated IDs. @@ -155,8 +163,46 @@ SUBSYSTEM_DEF(mapping) setup_map_transitions() generate_station_area_list() initialize_reserved_level(transit.z_value) + generate_z_level_linkages() + calculate_default_z_level_gravities() return ..() +/datum/controller/subsystem/mapping/proc/calculate_default_z_level_gravities() + for(var/z_level in 1 to length(z_list)) + calculate_z_level_gravity(z_level) + +/datum/controller/subsystem/mapping/proc/generate_z_level_linkages() + for(var/z_level in 1 to length(z_list)) + generate_linkages_for_z_level(z_level) + +/datum/controller/subsystem/mapping/proc/generate_linkages_for_z_level(z_level) + if(!isnum(z_level) || z_level <= 0) + return FALSE + + if(multiz_levels.len < z_level) + multiz_levels.len = z_level + + var/linked_down = level_trait(z_level, ZTRAIT_DOWN) + var/linked_up = level_trait(z_level, ZTRAIT_UP) + multiz_levels[z_level] = list() + if(linked_down) + multiz_levels[z_level]["[DOWN]"] = TRUE + if(linked_up) + multiz_levels[z_level]["[UP]"] = TRUE + +/datum/controller/subsystem/mapping/proc/calculate_z_level_gravity(z_level_number) + if(!isnum(z_level_number) || z_level_number < 1) + return FALSE + + var/max_gravity = 0 + + for(var/obj/machinery/gravity_generator/main/grav_gen as anything in GLOB.gravity_generators["[z_level_number]"]) + max_gravity = max(grav_gen.setting, max_gravity) + + max_gravity = max_gravity || level_trait(z_level_number, ZTRAIT_GRAVITY) || 0//just to make sure no nulls + gravity_by_z_level["[z_level_number]"] = max_gravity + return max_gravity + /* Nuke threats, for making the blue tiles on the station go RED Used by the AI doomsday and the self destruct nuke. */ @@ -229,6 +275,7 @@ SUBSYSTEM_DEF(mapping) clearing_reserved_turfs = SSmapping.clearing_reserved_turfs z_list = SSmapping.z_list + multiz_levels = SSmapping.multiz_levels /datum/controller/subsystem/mapping/proc/LoadGroup(list/errorList, name, path, files, list/traits, list/default_traits, silent = FALSE, orientation = SOUTH) . = list() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 07492922888a..63d288ff707c 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1425,6 +1425,8 @@ * Sends signals COMSIG_ATOM_HAS_GRAVITY and COMSIG_TURF_HAS_GRAVITY, both can force gravity with * the forced gravity var * + * micro-optimized to hell because this proc is very hot, being called several times per movement every movement. + * * Gravity situations: * * No gravity if you're not in a turf * * No gravity if this atom is in is a space turf @@ -1433,37 +1435,28 @@ * * Gravity if the Z level has an SSMappingTrait for ZTRAIT_GRAVITY * * otherwise no gravity */ -/atom/proc/has_gravity(turf/T) - if(!T || !isturf(T)) - T = get_turf(src) +/atom/proc/has_gravity(turf/gravity_turf) + if(!isturf(gravity_turf)) + gravity_turf = get_turf(src) - if(!T) + if(!gravity_turf)//no gravity in nullspace return 0 - var/list/forced_gravity = list() - SEND_SIGNAL(src, COMSIG_ATOM_HAS_GRAVITY, T, forced_gravity) - if(!forced_gravity.len) - SEND_SIGNAL(T, COMSIG_TURF_HAS_GRAVITY, src, forced_gravity) - if(forced_gravity.len) - var/max_grav - for(var/i in forced_gravity) + //the list isnt created every time as this proc is very hot, its only accessed if anything is actually listening to the signal too + var/static/list/forced_gravity = list() + if(SEND_SIGNAL(src, COMSIG_ATOM_HAS_GRAVITY, gravity_turf, forced_gravity)) + if(!length(forced_gravity)) + SEND_SIGNAL(gravity_turf, COMSIG_TURF_HAS_GRAVITY, src, forced_gravity) + + var/max_grav = 0 + for(var/i in forced_gravity)//our gravity is the strongest return forced gravity we get max_grav = max(max_grav, i) + forced_gravity.Cut() + //cut so we can reuse the list, this is ok since forced gravity movers are exceedingly rare compared to all other movement return max_grav - if(isspaceturf(T)) // Turf never has gravity - return 0 - - var/area/A = get_area(T) - if(A.has_gravity) // Areas which always has gravity - return A.has_gravity - else - // There's a gravity generator on our z level - if(GLOB.gravity_generators["[T.z]"]) - var/max_grav = 0 - for(var/obj/machinery/gravity_generator/main/G in GLOB.gravity_generators["[T.z]"]) - max_grav = max(G.setting,max_grav) - return max_grav - return SSmapping.level_trait(T.z, ZTRAIT_GRAVITY) + var/area/turf_area = gravity_turf.loc + return !gravity_turf.force_no_gravity && (SSmapping.gravity_by_z_level["[gravity_turf.z]"] || turf_area.has_gravity) /** * Causes effects when the atom gets hit by a rust effect from heretics diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm index 0e32c170d739..abc411898a85 100644 --- a/code/game/turfs/open.dm +++ b/code/game/turfs/open.dm @@ -223,7 +223,10 @@ air.copy_from_turf(src) update_air_ref(planetary_atmos ? 1 : 2) - ImmediateCalculateAdjacentTurfs() + if(times_fired) + init_immediate_calculate_adjacent_turfs() + else + ImmediateCalculateAdjacentTurfs() /turf/open/proc/GetHeatCapacity() . = air.heat_capacity() diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 85fbbc5c77f6..361d22be9742 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -36,6 +36,9 @@ GLOBAL_LIST_EMPTY(station_turfs) var/tiled_dirt = FALSE // use smooth tiled dirt decal + ///whether or not this turf forces movables on it to have no gravity (unless they themselves have forced gravity) + var/force_no_gravity = FALSE + /turf/vv_edit_var(var_name, new_value) var/static/list/banned_edits = list("x", "y", "z") if(var_name in banned_edits) diff --git a/code/modules/atmospherics/environmental/LINDA_system.dm b/code/modules/atmospherics/environmental/LINDA_system.dm index 117d70509e49..2a9346b12525 100644 --- a/code/modules/atmospherics/environmental/LINDA_system.dm +++ b/code/modules/atmospherics/environmental/LINDA_system.dm @@ -39,12 +39,67 @@ /atom/movable/proc/BlockThermalConductivity() // Objects that don't let heat through. return FALSE +/// This proc is a more deeply optimized version of immediate_calculate_adjacent_turfs +/// It contains dumbshit, and also stuff I just can't do at runtime +/// If you're not editing behavior, just read that proc. It's less bad +/turf/proc/init_immediate_calculate_adjacent_turfs() + //Basic optimization, if we can't share why bother asking other people ya feel? + // You know it's gonna be stupid when they include a unit test in the atmos code + // Yes, inlining the string concat does save 0.1 seconds + #ifdef UNIT_TESTS + ASSERT(UP == 16) + ASSERT(DOWN == 32) + #endif + LAZYINITLIST(src.atmos_adjacent_turfs) + var/list/atmos_adjacent_turfs = src.atmos_adjacent_turfs + var/blocks_air = src.blocks_air + var/canpass = CANATMOSPASS(src, src) + var/canvpass = CANVERTICALATMOSPASS(src, src) + // I am essentially inlineing two get_dir_multizs here, because they're way too slow on their own. I'm sorry brother + var/list/z_traits = SSmapping.multiz_levels[z] + for(var/direction in GLOB.cardinals_multiz) + // Yes this is a reimplementation of get_step_multiz. It's faster tho. fuck you + var/turf/current_turf = (direction & (UP|DOWN)) ? \ + (direction & UP) ? \ + (z_traits["16"]) ? \ + (get_step(locate(x, y, z + z_traits["16"]), NONE)) : \ + (null) : \ + (z_traits["32"]) ? \ + (get_step(locate(x, y, z + z_traits["32"]), NONE)) : \ + (null) : \ + (get_step(src, direction)) + + if(!isopenturf(current_turf)) // not interested in you brother + continue + + //Can you and me form a deeper relationship, or is this just a passing wind + // (direction & (UP | DOWN)) is just "is this vertical" by the by + if((direction & (UP|DOWN) ? (canvpass && CANVERTICALATMOSPASS(current_turf, src)) : (canpass && CANATMOSPASS(current_turf, src))) && !(blocks_air || current_turf.blocks_air)) + LAZYINITLIST(current_turf.atmos_adjacent_turfs) + atmos_adjacent_turfs[current_turf] = TRUE + current_turf.atmos_adjacent_turfs[src] = TRUE + else + atmos_adjacent_turfs -= current_turf + if (current_turf.atmos_adjacent_turfs) + current_turf.atmos_adjacent_turfs -= src + UNSETEMPTY(current_turf.atmos_adjacent_turfs) + current_turf.set_sleeping(current_turf.blocks_air) + // This was originally (isspaceturf(T.get_z_base_turf()), -1), but we don't have space, so + // we just pass FALSE to save time. + current_turf?.__update_auxtools_turf_adjacency_info(FALSE, -1) + + UNSETEMPTY(atmos_adjacent_turfs) + src.atmos_adjacent_turfs = atmos_adjacent_turfs + set_sleeping(blocks_air) + __update_auxtools_turf_adjacency_info(FALSE) + /turf/proc/ImmediateCalculateAdjacentTurfs() + var/list/atmos_adjacent_turfs = src.atmos_adjacent_turfs // save ourselves a bunch of datum var accesses var/canpass = CANATMOSPASS(src, src) var/canvpass = CANVERTICALATMOSPASS(src, src) for(var/direction in GLOB.cardinals_multiz) var/turf/T = get_step_multiz(src, direction) - if(!istype(T)) + if(!T) continue if(isopenturf(T) && !(blocks_air || T.blocks_air) && ((direction & (UP|DOWN))? (canvpass && CANVERTICALATMOSPASS(T, src)) : (canpass && CANATMOSPASS(T, src))) ) LAZYINITLIST(atmos_adjacent_turfs) diff --git a/code/modules/mapping/space_management/multiz_helpers.dm b/code/modules/mapping/space_management/multiz_helpers.dm index b949ac67e694..31db653b647a 100644 --- a/code/modules/mapping/space_management/multiz_helpers.dm +++ b/code/modules/mapping/space_management/multiz_helpers.dm @@ -12,7 +12,7 @@ var/other_z = center_z var/offset while((offset = SSmapping.level_trait(other_z, ZTRAIT_DOWN))) - other_z += offset + other_z -= offset if(other_z in .) break // no infinite loops . += other_z diff --git a/code/modules/mapping/space_management/traits.dm b/code/modules/mapping/space_management/traits.dm index 9ba8d96d5e1c..967a274732a8 100644 --- a/code/modules/mapping/space_management/traits.dm +++ b/code/modules/mapping/space_management/traits.dm @@ -51,18 +51,18 @@ // Attempt to get the turf below the provided one according to Z traits /datum/controller/subsystem/mapping/proc/get_turf_below(turf/T) - if (!T) + if (!T || !initialized) return - var/offset = level_trait(T.z, ZTRAIT_DOWN) + var/offset = multiz_levels[T.z]["[DOWN]"] if (!offset) return - return locate(T.x, T.y, T.z + offset) + return locate(T.x, T.y, T.z - offset) // Attempt to get the turf above the provided one according to Z traits /datum/controller/subsystem/mapping/proc/get_turf_above(turf/T) - if (!T) + if (!T || !initialized) return - var/offset = level_trait(T.z, ZTRAIT_UP) + var/offset = multiz_levels[T.z]["[UP]"] if (!offset) return return locate(T.x, T.y, T.z + offset) diff --git a/code/modules/mapping/space_management/zlevel_manager.dm b/code/modules/mapping/space_management/zlevel_manager.dm index 6129c5fd2b6a..4e17dd6fab15 100644 --- a/code/modules/mapping/space_management/zlevel_manager.dm +++ b/code/modules/mapping/space_management/zlevel_manager.dm @@ -25,6 +25,8 @@ // TODO: sleep here if the Z level needs to be cleared var/datum/space_level/S = new z_type(new_z, name, traits) z_list += S + generate_linkages_for_z_level(new_z) + calculate_z_level_gravity(new_z) return S /datum/controller/subsystem/mapping/proc/get_level(z) diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 08a804550e99..5a61f4bf5c87 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -389,6 +389,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne GLOB.gravity_generators["[z]"] |= src else GLOB.gravity_generators["[z]"] -= src + SSmapping.calculate_z_level_gravity(z) /obj/machinery/gravity_generator/main/proc/change_setting(value) if(value != setting)