diff --git a/code/_helpers/sorting/cmp.dm b/code/_helpers/sorting/cmp.dm index 201c49fa861..a921d158a90 100644 --- a/code/_helpers/sorting/cmp.dm +++ b/code/_helpers/sorting/cmp.dm @@ -86,3 +86,6 @@ var/cmp_field = "name" /proc/cmp_pda(obj/item/device/pda/A, obj/item/device/pda/B) return sorttext(B.owner, A.owner) + +/proc/cmp_planelayer(atom/A, atom/B) + return (B.plane - A.plane) || (B.layer - A.layer) diff --git a/code/controllers/subsystems/falling.dm b/code/controllers/subsystems/falling.dm index 510311da0e5..58f20b974c5 100644 --- a/code/controllers/subsystems/falling.dm +++ b/code/controllers/subsystems/falling.dm @@ -78,7 +78,7 @@ // Invokes fall_through() after the atom is moved to // its new destination this cycle. Immediately invokes fall_impact and // fall_collateral if the next turf is not open space. - if (isopenturf(victim.loc)) + if (isopenturf(victim.loc) && victim.loc:is_hole) victim.forceMove(below) if (locate(/obj/structure/stairs) in victim.loc) // If there's stairs, we're probably going down them. diff --git a/code/controllers/subsystems/openturf.dm b/code/controllers/subsystems/openturf.dm index e142fef663a..d76811c712b 100644 --- a/code/controllers/subsystems/openturf.dm +++ b/code/controllers/subsystems/openturf.dm @@ -2,7 +2,6 @@ #define OPENTURF_CAP_PLANE -70 // The multiplier goes here so it'll be on top of every other overlay. #define OPENTURF_MAX_DEPTH 10 // The maxiumum number of planes deep we'll go before we just dump everything on the same plane. #define SHADOWER_DARKENING_FACTOR 0.4 // The multiplication factor for openturf shadower darkness. Lighting will be multiplied by this. -#define SHADOWER_LAYER 0 /var/datum/controller/subsystem/openturf/SSopenturf @@ -123,23 +122,39 @@ if (depth > OPENTURF_MAX_DEPTH) depth = OPENTURF_MAX_DEPTH - // Update the openturf itself. - T.appearance = T.below - T.name = initial(T.name) - T.desc = "Below seems to be \a [T.below]." - T.opacity = FALSE - T.queue_ao() // No need to recalculate ajacencies, shouldn't have changed. + var/target_plane // Handle space parallax & starlight. if (T.is_above_space()) - T.plane = PLANE_SPACE_BACKGROUND + target_plane = PLANE_SPACE_BACKGROUND if (starlight_enabled && !T.light_range) T.set_light(config.starlight, 0.5) else - T.plane = OPENTURF_MAX_PLANE - depth + target_plane = OPENTURF_MAX_PLANE - depth if (starlight_enabled && T.light_range) T.set_light(0) + if (T.no_mutate) + // Some openturfs have icons, so we can't overwrite their appearance. + if (!T.below.bound_overlay) + T.below.bound_overlay = new(T) + var/atom/movable/openspace/turf_overlay/TO = T.below.bound_overlay + TO.appearance = T.below + TO.name = T.name + T.desc = TO.desc = "Below seems to be \a [T.below]." + TO.plane = target_plane + else + // This openturf doesn't care about its icon, so we can just overwrite it. + if (T.below.bound_overlay) + QDEL_NULL(T.below.bound_overlay) + T.appearance = T.below + T.name = initial(T.name) + T.opacity = FALSE + T.plane = target_plane + + T.desc = "Below seems to be \a [T.below]." + T.queue_ao() // No need to recalculate ajacencies, shouldn't have changed. + // Add everything below us to the update queue. for (var/thing in T.below) var/atom/movable/object = thing @@ -148,39 +163,7 @@ continue if (istype(object, /atom/movable/lighting_overlay)) // Special case. - var/atom/movable/openspace/multiplier/shadower = T.shadower - shadower.appearance = object - shadower.plane = OPENTURF_CAP_PLANE - shadower.layer = SHADOWER_LAYER - shadower.invisibility = 0 - if (shadower.icon_state == LIGHTING_BASE_ICON_STATE) - // We're using a color matrix, so just darken the colors. - var/list/c_list = shadower.color - c_list[CL_MATRIX_RR] *= SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_RG] *= SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_RB] *= SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_GR] *= SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_GG] *= SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_GB] *= SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_BR] *= SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_BG] *= SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_BB] *= SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_AR] *= SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_AG] *= SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_AB] *= SHADOWER_DARKENING_FACTOR - shadower.color = c_list - else - shadower.color = list( - SHADOWER_DARKENING_FACTOR, 0, 0, - 0, SHADOWER_DARKENING_FACTOR, 0, - 0, 0, SHADOWER_DARKENING_FACTOR - ) - - if (shadower.our_overlays || shadower.priority_overlays) - shadower.compile_overlays() - - if (shadower.bound_overlay) - shadower.update_above() + T.shadower.copy_lighting(object) else if (!object.bound_overlay) // Generate a new overlay if the atom doesn't already have one. object.bound_overlay = new(T) @@ -189,7 +172,7 @@ var/atom/movable/openspace/overlay/OO = object.bound_overlay // Cache our already-calculated depth so we don't need to re-calculate it a bunch of times. - OO.depth = depth + OO.depth = target_plane queued_overlays += OO @@ -231,13 +214,10 @@ // Actually update the overlay. OO.dir = OO.associated_atom.dir OO.appearance = OO.associated_atom - OO.plane = OPENTURF_MAX_PLANE - OO.depth + OO.plane = OO.depth OO.opacity = FALSE OO.queued = FALSE - if (istype(OO.associated_atom, /atom/movable/openspace/multiplier) && OO.plane < OPENTURF_MAX_PLANE) // Special case for multipliers. - OO.plane++ - if (OO.bound_overlay) // If we have a bound overlay, queue it too. OO.update_above() @@ -249,3 +229,39 @@ if (qo_idex > 1 && qo_idex <= curr_ov.len) curr_ov.Cut(1, qo_idex) qo_idex = 1 + + +/client/proc/analyze_openturf(turf/simulated/open/T) + set name = "Analyze Openturf" + set desc = "Show the layering of an openturf and everything it's mimicking." + set category = "Debug" + + if (!check_rights(R_DEBUG|R_DEV)) + return + + if (!istype(T)) + usr << "Invalid Selection." + return + + var/list/out = list( + "

Analysis of [T] at [T.x],[T.y],[T.z]

", + "Queued for update: [T.updating ? "Yes" : "No"]", + "Appearance Type: [T.no_mutate ? "Movable Copy" : "Turf Overwrite"]", + "Has Shadower: [T.shadower ? "Yes" : "No"]", + "Below: [!T.below ? "(nothing)" : "[T.below] at [T.below.x],[T.below.y],[T.below.z]"]", + "" + + usr << browse(out.Join("
"), "window=openturfanalysis-\ref[T]") diff --git a/code/modules/admin/verbs/bluespacetech.dm b/code/modules/admin/verbs/bluespacetech.dm index e0cc6b2805c..03eda5b289b 100644 --- a/code/modules/admin/verbs/bluespacetech.dm +++ b/code/modules/admin/verbs/bluespacetech.dm @@ -134,6 +134,7 @@ /mob/living/carbon/human/bst universal_understand = 1 status_flags = GODMODE + var/fall_override = TRUE /mob/living/carbon/human/bst/can_inject(var/mob/user, var/error_msg, var/target_zone) user << span("alert", "The [src] disarms you before you can inject them.") @@ -290,6 +291,18 @@ key = null suicide() +/mob/living/carbon/human/bst/verb/antigrav() + set name = "Toggle Gravity" + set desc = "Toggles on/off falling for you." + set category = "BST" + + if (fall_override) + fall_override = FALSE + to_chat(usr, "You will now fall normally.") + else + fall_override = TRUE + to_chat(usr, "You will no longer fall.") + /mob/living/carbon/human/bst/verb/bstwalk() set name = "Ruin Everything" set desc = "Uses bluespace technology to phase through solid matter and move quickly." diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 8a94fa03e73..850b175a21d 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -125,46 +125,47 @@ var/intercom_range_display_status = 0 feedback_add_details("admin_verb","mIRD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! var/list/debug_verbs = list ( - /client/proc/do_not_use_these - ,/client/proc/camera_view - ,/client/proc/sec_camera_report - ,/client/proc/intercom_view - ,/client/proc/Cell - ,/client/proc/atmosscan - ,/client/proc/powerdebug - ,/client/proc/count_objects_on_z_level - ,/client/proc/count_objects_all - ,/client/proc/cmd_assume_direct_control - ,/client/proc/jump_to_dead_group - ,/client/proc/startSinglo - ,/client/proc/ticklag - ,/client/proc/cmd_admin_grantfullaccess - ,/client/proc/kaboom - ,/client/proc/splash - ,/client/proc/cmd_admin_areatest - ,/client/proc/cmd_admin_rejuvenate - ,/datum/admins/proc/show_traitor_panel - ,/client/proc/print_jobban_old - ,/client/proc/print_jobban_old_filter - ,/client/proc/forceEvent - ,/client/proc/break_all_air_groups - ,/client/proc/regroup_all_air_groups - ,/client/proc/kill_pipe_processing - ,/client/proc/kill_air_processing - ,/client/proc/disable_communication - ,/client/proc/disable_movement - ,/client/proc/Zone_Info - ,/client/proc/Test_ZAS_Connection - //,/client/proc/ZoneTick - ,/client/proc/rebootAirMaster - ,/client/proc/hide_debug_verbs - ,/client/proc/testZAScolors - ,/client/proc/testZAScolors_remove - ,/datum/admins/proc/setup_supermatter - ,/client/proc/atmos_toggle_debug - ,/client/proc/spawn_tanktransferbomb - ,/client/proc/get_bad_fdoors - ,/client/proc/get_bad_doors + /client/proc/do_not_use_these + ,/client/proc/camera_view + ,/client/proc/sec_camera_report + ,/client/proc/intercom_view + ,/client/proc/Cell + ,/client/proc/atmosscan + ,/client/proc/powerdebug + ,/client/proc/count_objects_on_z_level + ,/client/proc/count_objects_all + ,/client/proc/cmd_assume_direct_control + ,/client/proc/jump_to_dead_group + ,/client/proc/startSinglo + ,/client/proc/ticklag + ,/client/proc/cmd_admin_grantfullaccess + ,/client/proc/kaboom + ,/client/proc/splash + ,/client/proc/cmd_admin_areatest + ,/client/proc/cmd_admin_rejuvenate + ,/datum/admins/proc/show_traitor_panel + ,/client/proc/print_jobban_old + ,/client/proc/print_jobban_old_filter + ,/client/proc/forceEvent + ,/client/proc/break_all_air_groups + ,/client/proc/regroup_all_air_groups + ,/client/proc/kill_pipe_processing + ,/client/proc/kill_air_processing + ,/client/proc/disable_communication + ,/client/proc/disable_movement + ,/client/proc/Zone_Info + ,/client/proc/Test_ZAS_Connection + //,/client/proc/ZoneTick + ,/client/proc/rebootAirMaster + ,/client/proc/hide_debug_verbs + ,/client/proc/testZAScolors + ,/client/proc/testZAScolors_remove + ,/datum/admins/proc/setup_supermatter + ,/client/proc/atmos_toggle_debug + ,/client/proc/spawn_tanktransferbomb + ,/client/proc/get_bad_fdoors + ,/client/proc/get_bad_doors + ,/client/proc/analyze_openturf ) diff --git a/code/modules/multiz/movement.dm b/code/modules/multiz/movement.dm index b291eacdad8..5c590d0277a 100644 --- a/code/modules/multiz/movement.dm +++ b/code/modules/multiz/movement.dm @@ -192,7 +192,7 @@ * this cycle. */ /atom/movable/proc/can_fall(turf/below, turf/simulated/open/dest = src.loc) - if (!istype(dest)) + if (!istype(dest) || !dest.is_hole) return FALSE // Anchored things don't fall. @@ -202,11 +202,11 @@ // Lattices, ladders, and stairs stop things from falling. if(locate(/obj/structure/lattice, dest) || locate(/obj/structure/stairs, dest) || locate(/obj/structure/ladder, dest)) return FALSE + //Ladders too if(below && locate(/obj/structure/ladder) in below) return FALSE - // The var/climbers API is implemented here. if (LAZYLEN(dest.climbers) && (src in dest.climbers)) return FALSE @@ -238,6 +238,9 @@ if (LAZYLEN(dest.climbers) && (src in dest.climbers)) return FALSE + if (!dest.is_hole) + return FALSE + // See if something prevents us from falling. for(var/atom/A in below) if(!A.CanPass(src, dest)) @@ -258,7 +261,7 @@ return ..() /mob/living/carbon/human/bst/can_fall() - return FALSE + return fall_override ? FALSE : ..() /mob/eye/can_fall() return FALSE diff --git a/code/modules/multiz/openspace.dm b/code/modules/multiz/openspace.dm index d655cd29cbd..f61981fc112 100644 --- a/code/modules/multiz/openspace.dm +++ b/code/modules/multiz/openspace.dm @@ -1,9 +1,20 @@ +/* + +== Openspace == + +This file contains the openspace movable types, including interactrion code and openspace helpers. +Most openspace appearance code is in code/controllers/subsystems/openturf.dm. +*/ + + +// Updates whatever openspace components may be mimicing us. On turfs this queues an openturf update on the above openturf, on movables this updates their bound movable (if present). Meaningless on any type other than `/turf` or `/atom/movable` (incl. children). /atom/proc/update_above() + return /turf // Reference to any open turf that might be above us to speed up atom Entered() updates. var/tmp/turf/simulated/open/above - //var/tmp/oo_light_set // If the turf has had a light set by starlight. + var/tmp/atom/movable/openspace/turf_overlay/bound_overlay /turf/Entered(atom/movable/thing, atom/oldLoc) . = ..() @@ -12,6 +23,8 @@ /turf/Destroy() above = null + if (bound_overlay) + QDEL_NULL(bound_overlay) return ..() /turf/update_above() @@ -53,6 +66,7 @@ else qdel(bound_overlay) +// Grabs a list of every openspace object that's directly or indirectly mimicing this object. Returns an empty list if none found. /atom/movable/proc/get_above_oo() . = list() var/atom/movable/curr = src @@ -87,14 +101,14 @@ /atom/movable/openspace/shuttle_move() return -// Used to darken the atoms on the openturf without fucking up colors. +// Holder object used for dimming openspaces & copying lighting of below turf. /atom/movable/openspace/multiplier name = "openspace multiplier" desc = "You shouldn't see this." icon = 'icons/effects/lighting_overlay.dmi' icon_state = "blank" plane = OPENTURF_CAP_PLANE - layer = SHADOWER_LAYER + layer = LIGHTING_LAYER blend_mode = BLEND_MULTIPLY color = list( SHADOWER_DARKENING_FACTOR, 0, 0, @@ -109,7 +123,41 @@ return ..() -// The visual representation of an atom under an openspace turf. +/atom/movable/openspace/multiplier/proc/copy_lighting(atom/movable/lighting_overlay/LO) + appearance = LO + plane = OPENTURF_CAP_PLANE + invisibility = 0 + if (icon_state == LIGHTING_BASE_ICON_STATE) + // We're using a color matrix, so just darken the colors across the board. + var/list/c_list = color + c_list[CL_MATRIX_RR] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_RG] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_RB] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_GR] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_GG] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_GB] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_BR] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_BG] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_BB] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_AR] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_AG] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_AB] *= SHADOWER_DARKENING_FACTOR + color = c_list + else + // Not a color matrix, so we can just use the color var ourselves. + color = list( + SHADOWER_DARKENING_FACTOR, 0, 0, + 0, SHADOWER_DARKENING_FACTOR, 0, + 0, 0, SHADOWER_DARKENING_FACTOR + ) + + if (our_overlays || priority_overlays) + compile_overlays() + else + // compile_overlays() calls update_above(). + update_above() + +// Object used to hold a mimiced atom's appearance. /atom/movable/openspace/overlay plane = OPENTURF_MAX_PLANE var/atom/movable/associated_atom @@ -158,3 +206,19 @@ /atom/movable/openspace/overlay/proc/owning_turf_changed() if (!destruction_timer) destruction_timer = addtimer(CALLBACK(GLOBAL_PROC, /proc/qdel, src), 10 SECONDS, TIMER_STOPPABLE) + +// This one's a little different because it's mimicing a turf. +/atom/movable/openspace/turf_overlay + plane = OPENTURF_MAX_PLANE + +/atom/movable/openspace/turf_overlay/attackby(obj/item/W, mob/user) + loc.attackby(W, user) + +/atom/movable/openspace/turf_overlay/attack_hand(mob/user as mob) + loc.attack_hand(user) + +/atom/movable/openspace/turf_overlay/attack_generic(mob/user as mob) + loc.attack_generic(user) + +/atom/movable/openspace/turf_overlay/examine(mob/examiner) + loc.examine(examiner) diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf.dm index 664adb40afa..6735026eede 100644 --- a/code/modules/multiz/turf.dm +++ b/code/modules/multiz/turf.dm @@ -47,6 +47,8 @@ var/tmp/list/climbers // A lazy list to contain a list of mobs who are currently scaling // up this turf. Used in human/can_fall. + var/no_mutate = FALSE // If TRUE, SSopenturf will not modify the appearance of this turf. + // An override of turf/Enter() to make it so that magboots allow you to stop // falling off the damned rock. /turf/simulated/open/Enter(mob/living/carbon/human/mover, atom/oldloc) @@ -63,14 +65,16 @@ // centralizes control to SSfalling. /turf/simulated/open/Entered(atom/movable/mover) ..() - ADD_FALLING_ATOM(mover) + if (is_hole) + ADD_FALLING_ATOM(mover) // Override to deny a climber exit if they're set to adhere to CLIMBER_NO_EXIT /turf/simulated/open/Exit(atom/movable/mover, atom/newloc) var/flags = remove_climber(mover) if (flags & CLIMBER_NO_EXIT) - ADD_FALLING_ATOM(mover) + if (is_hole) + ADD_FALLING_ATOM(mover) return FALSE return ..() @@ -112,12 +116,10 @@ */ /turf/simulated/open/proc/is_above_space() var/turf/T = GetBelow(src) - while (T && T.is_hole) - if (istype(T, /turf/space)) - return TRUE + while (isopenturf(T)) T = GetBelow(T) - return FALSE + return istype(T, /turf/space) /** * Used to add a climber to the climbers list. Climbers do not fall down this specific tile. @@ -169,6 +171,9 @@ icon_state = "" // Clear out the debug icon. SSopenturf.openspace_turfs += src shadower = new(src) + if (no_mutate && plane == PLANE_SPACE_BACKGROUND) + // If the plane is default and we're a no_mutate turf, force it to 0 so the icon works properly. + plane = 0 update() /** @@ -182,8 +187,9 @@ below.above = src levelupdate() - for (var/atom/movable/A in src) - ADD_FALLING_ATOM(A) + if (is_hole) + for (var/atom/movable/A in src) + ADD_FALLING_ATOM(A) update_icon() /turf/simulated/open/update_dirt()