Ports new zmimic changes/bugfixes/etc from Bay/Nebula. (#14495)

This commit is contained in:
Matt Atlas
2022-08-02 17:56:01 +02:00
committed by GitHub
parent 06e5c811ac
commit af79eebb88
22 changed files with 625 additions and 302 deletions

View File

@@ -2,39 +2,17 @@
/atom/proc/update_above()
return
/**
* Used to check wether or not an atom can pass through a turf.
*
* @param A The atom that's moving either up or down from this turf or to it.
* @param direction The direction of the atom's movement in relation to its
* current position.
*
* @return TRUE if A can pass in the movement direction, FALSE if not.
*/
/turf/proc/CanZPass(atom/A, direction)
var/turf/T = get_turf(A)
if(z == T.z) //moving FROM this turf
return direction == UP //can't go below
else
if(direction == UP) //on a turf below, trying to enter
return FALSE
if(direction == DOWN) //on a turf above, trying to enter
return !density
/**
* Used to check whether or not the specific open turf eventually leads into spess.
*
* @return TRUE if the turf eventually leads into space. FALSE otherwise.
*/
/turf/proc/is_above_space()
var/turf/T = GetBelow(src)
while (T && (T.flags & MIMIC_BELOW))
while (T && (T.z_flags & ZM_MIMIC_BELOW))
T = GetBelow(T)
return isspaceturf(T)
return istype(T, /turf/space)
/turf/update_icon()
..()
if (above)
update_above()
/turf/simulated/open/CanZPass(atom, direction)
return TRUE
/turf/space/CanZPass(atom, direction)
return TRUE
/atom/movable/update_icon()
..()
UPDATE_OO_IF_PRESENT

View File

@@ -1,36 +1,41 @@
/atom/movable
var/tmp/atom/movable/openspace/overlay/bound_overlay // The overlay that is directly mirroring us that we proxy movement to.
var/no_z_overlay // If TRUE, this atom will not be drawn on open turfs.
/atom/movable/Destroy()
. = ..()
if (bound_overlay)
QDEL_NULL(bound_overlay)
/// The mimic (if any) that's *directly* copying us.
var/tmp/atom/movable/openspace/mimic/bound_overlay
/// If TRUE, this atom is ignored by Z-Mimic.
var/no_z_overlay
/atom/movable/forceMove(atom/dest)
. = ..(dest)
if (bound_overlay)
if (. && bound_overlay)
// The overlay will handle cleaning itself up on non-openspace turfs.
if (isturf(dest))
bound_overlay.forceMove(get_step(src, UP))
bound_overlay.set_dir(dir)
if (dir != bound_overlay.dir)
bound_overlay.set_dir(dir)
else // Not a turf, so we need to destroy immediately instead of waiting for the destruction timer to proc.
qdel(bound_overlay)
/atom/movable/Move()
. = ..()
if (. && bound_overlay)
bound_overlay.forceMove(get_step(src, UP))
if (bound_overlay.dir != dir)
bound_overlay.set_dir(dir)
/atom/movable/set_dir(ndir)
. = ..()
if (. && bound_overlay)
bound_overlay.set_dir(ndir)
/atom/movable/update_above()
if (!bound_overlay)
if (!bound_overlay || !isturf(loc))
return
var/turf/T = loc
if (TURF_IS_MIMICING(T.above))
if (!bound_overlay.queued)
SSzcopy.queued_overlays += bound_overlay
bound_overlay.queued = TRUE
SSzcopy.queued_overlays += bound_overlay
bound_overlay.queued += 1
else
qdel(bound_overlay)
@@ -55,6 +60,7 @@
// No blowing up abstract objects.
/atom/movable/openspace/ex_act(ex_sev)
SHOULD_CALL_PARENT(FALSE)
return
/atom/movable/openspace/singularity_act()
@@ -66,17 +72,16 @@
/atom/movable/openspace/singuloCanEat()
return
/atom/movable/openspace/shuttle_move()
return
// -- MULTIPLIER / SHADOWER --
// 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 = LIGHTING_LAYER
icon_state = "dark"
plane = OPENTURF_MAX_PLANE
layer = MIMICED_LIGHTING_LAYER
blend_mode = BLEND_MULTIPLY
color = list(
SHADOWER_DARKENING_FACTOR, 0, 0,
@@ -93,53 +98,65 @@
/atom/movable/openspace/multiplier/proc/copy_lighting(atom/movable/lighting_overlay/LO)
appearance = LO
layer = EFFECTS_ABOVE_LIGHTING_LAYER
plane = OPENTURF_CAP_PLANE
layer = MIMICED_LIGHTING_LAYER
plane = OPENTURF_MAX_PLANE
invisibility = 0
if (icon_state == LIGHTING_BASE_ICON_STATE)
blend_mode = BLEND_MULTIPLY
if (icon_state == null)
// We're using a color matrix, so just darken the colors across the board.
// Bay stores lights as inverted so the lighting PM can invert it for darksight, but
// we don't have a plane master, so invert it again.
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
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.
// Not a color matrix, so we just ignore the lighting values.
icon_state = "dark" // this is actually just a white sprite, which is what this blending needs
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 if (bound_overlay)
// compile_overlays() calls update_above().
var/turf/parent = loc
ASSERT(isturf(parent))
if (LAZYLEN(parent.ao_overlays_mimic))
overlays += parent.ao_overlays_mimic
if (bound_overlay)
update_above()
// -- OPENSPACE OVERLAY --
// todo: rename
// Object used to hold a mimiced atom's appearance.
/atom/movable/openspace/overlay
/atom/movable/openspace/mimic
plane = OPENTURF_MAX_PLANE
var/atom/movable/associated_atom
var/depth
var/queued = FALSE
var/queued = 0
var/destruction_timer
var/mimiced_type
var/original_z
var/override_depth
/atom/movable/openspace/overlay/New()
/atom/movable/openspace/mimic/New()
initialized = TRUE
SSzcopy.openspace_overlays += src
SSzcopy.openspace_overlays += 1
/atom/movable/openspace/overlay/Destroy()
SSzcopy.openspace_overlays -= src
/atom/movable/openspace/mimic/Destroy()
SSzcopy.openspace_overlays -= 1
if (associated_atom)
associated_atom.bound_overlay = null
@@ -150,44 +167,74 @@
return ..()
/atom/movable/openspace/overlay/attackby(obj/item/W, mob/user)
/atom/movable/openspace/mimic/attackby(obj/item/W, mob/user)
to_chat(user, SPAN_NOTICE("\The [src] is too far away."))
/atom/movable/openspace/overlay/attack_hand(mob/user as mob)
/atom/movable/openspace/mimic/attack_hand(mob/user)
to_chat(user, SPAN_NOTICE("You cannot reach \the [src] from here."))
/atom/movable/openspace/overlay/attack_generic(mob/user as mob)
to_chat(user, SPAN_NOTICE("You cannot reach \the [src] from here."))
/atom/movable/openspace/mimic/examine(...)
SHOULD_CALL_PARENT(FALSE)
. = associated_atom.examine(arglist(args)) // just pass all the args to the copied atom
/atom/movable/openspace/overlay/examine(mob/examiner)
associated_atom.examine(examiner)
/atom/movable/openspace/overlay/forceMove(turf/dest)
/atom/movable/openspace/mimic/forceMove(turf/dest)
. = ..()
if (TURF_IS_MIMICING(dest))
if (destruction_timer)
deltimer(destruction_timer)
destruction_timer = null
else if (!destruction_timer)
destruction_timer = addtimer(CALLBACK(GLOBAL_PROC, /proc/qdel, src), 10 SECONDS, TIMER_STOPPABLE)
destruction_timer = addtimer(CALLBACK(src, /datum/.proc/qdel_self), 10 SECONDS, TIMER_STOPPABLE)
// Called when the turf we're on is deleted/changed.
/atom/movable/openspace/overlay/proc/owning_turf_changed()
/atom/movable/openspace/mimic/proc/owning_turf_changed()
if (!destruction_timer)
destruction_timer = addtimer(CALLBACK(GLOBAL_PROC, /proc/qdel, src), 10 SECONDS, TIMER_STOPPABLE)
destruction_timer = addtimer(CALLBACK(src, /datum/.proc/qdel_self), 10 SECONDS, TIMER_STOPPABLE)
// This one's a little different because it's mimicing a turf.
/atom/movable/openspace/turf_overlay
// -- TURF PROXY --
// This thing holds the mimic appearance for non-OVERWRITE turfs.
/atom/movable/openspace/turf_proxy
plane = OPENTURF_MAX_PLANE
mouse_opacity = 0
no_z_overlay = TRUE // Only one of these should ever be visible at a time, the mimic logic will handle that.
/atom/movable/openspace/turf_overlay/attackby(obj/item/W, mob/user)
/atom/movable/openspace/turf_proxy/attackby(obj/item/W, mob/user)
loc.attackby(W, user)
/atom/movable/openspace/turf_overlay/attack_hand(mob/user as mob)
/atom/movable/openspace/turf_proxy/attack_hand(mob/user as mob)
loc.attack_hand(user)
/atom/movable/openspace/turf_overlay/attack_generic(mob/user as mob)
/atom/movable/openspace/turf_proxy/attack_generic(mob/user as mob)
loc.attack_generic(user)
/atom/movable/openspace/turf_overlay/examine(mob/examiner)
loc.examine(examiner)
/atom/movable/openspace/turf_proxy/examine(mob/examiner)
SHOULD_CALL_PARENT(FALSE)
. = loc.examine(examiner)
// -- TURF MIMIC --
// A type for copying non-overwrite turfs' self-appearance.
/atom/movable/openspace/turf_mimic
plane = OPENTURF_MAX_PLANE // These *should* only ever be at the top?
mouse_opacity = 0
var/turf/delegate
/atom/movable/openspace/turf_mimic/Initialize(mapload, ...)
. = ..()
ASSERT(isturf(loc))
delegate = loc:below
/atom/movable/openspace/turf_mimic/attackby(obj/item/W, mob/user)
loc.attackby(W, user)
/atom/movable/openspace/turf_mimic/attack_hand(mob/user as mob)
to_chat(user, SPAN_NOTICE("You cannot reach \the [src] from here."))
/atom/movable/openspace/turf_mimic/attack_generic(mob/user as mob)
to_chat(user, SPAN_NOTICE("You cannot reach \the [src] from here."))
/atom/movable/openspace/turf_mimic/examine(mob/examiner)
SHOULD_CALL_PARENT(FALSE)
. = delegate.examine(examiner)

View File

@@ -1,12 +1,26 @@
/turf
// Reference to any open turf that might be above us to speed up atom Entered() updates.
var/tmp/turf/above
var/tmp/turf/below
var/tmp/atom/movable/openspace/turf_overlay/bound_overlay
var/tmp/atom/movable/openspace/multiplier/shadower // Overlay used to multiply color of all OO overlays at once.
/// Reference to any open turf that might be above us to speed up atom Entered() updates.
/turf/var/tmp/turf/above
/turf/var/tmp/turf/below
/// If we're a non-overwrite z-turf, this holds the appearance of the bottom-most Z-turf in the z-stack.
/turf/var/tmp/atom/movable/openspace/turf_proxy/mimic_proxy
/// Overlay used to multiply color of all OO overlays at once.
/turf/var/tmp/atom/movable/openspace/multiplier/shadower
/// If this is a delegate (non-overwrite) Z-turf with a z-turf above, this is the delegate copy that's copying us.
/turf/var/tmp/atom/movable/openspace/turf_mimic/mimic_above_copy
/// If we're at the bottom of the stack, a proxy used to fake a below space turf.
/turf/var/tmp/atom/movable/openspace/turf_proxy/mimic_underlay
/// How many times this turf is currently queued - multiple queue occurrences are allowed to ensure update consistency.
/turf/var/tmp/z_queued = 0
/// If this Z-turf leads to space, uninterrupted.
/turf/var/tmp/z_eventually_space = FALSE
/turf/var/z_flags = 0
// debug
/turf/var/tmp/z_depth
/turf/var/tmp/z_generation = 0
/turf/Entered(atom/movable/thing, turf/oldLoc)
. = ..(thing, oldLoc)
. = ..()
if (thing.bound_overlay || thing.no_z_overlay || !TURF_IS_MIMICING(above))
return
above.update_mimic()
@@ -15,57 +29,59 @@
if (TURF_IS_MIMICING(above))
above.update_mimic()
/turf/proc/update_mimic(recurse = TRUE)
if (!(flags & MIMIC_BELOW))
/turf/proc/update_mimic()
if (!(z_flags & ZM_MIMIC_BELOW))
return
if (below && !(flags & MIMIC_QUEUED))
flags |= MIMIC_QUEUED
SSzcopy.queued_turfs += src
z_queued += 1
SSzcopy.queued_turfs += src
if (recurse)
update_above() // Even if we're already updating, the turf above us might not be.
// Enables Z-mimic for a turf that didn't already have it enabled.
/// Enables Z-mimic for a turf that didn't already have it enabled.
/turf/proc/enable_zmimic(additional_flags = 0)
if (flags & MIMIC_BELOW)
if (z_flags & ZM_MIMIC_BELOW)
return FALSE
flags |= MIMIC_BELOW | additional_flags
z_flags |= ZM_MIMIC_BELOW | additional_flags
setup_zmimic(FALSE)
return TRUE
// Disables Z-mimic for a turf.
/// Disables Z-mimic for a turf.
/turf/proc/disable_zmimic()
if (!(flags & MIMIC_BELOW))
if (!(z_flags & ZM_MIMIC_BELOW))
return FALSE
flags &= ~MIMIC_BELOW
z_flags &= ~ZM_MIMIC_BELOW
cleanup_zmimic()
return TRUE
// Sets up Z-mimic for this turf. You shouldn't call this directly 99% of the time.
/// Sets up Z-mimic for this turf. You shouldn't call this directly 99% of the time.
/turf/proc/setup_zmimic(mapload)
if (shadower)
CRASH("Attempt to enable Z-mimic on already-enabled turf!")
shadower = new(src)
SSzcopy.openspace_turfs += src
SSzcopy.openspace_turfs += 1
var/turf/under = GetBelow(src)
if (under)
below = under
below.above = src
if (!(z_flags & (ZM_MIMIC_OVERWRITE|ZM_NO_OCCLUDE)) && mouse_opacity)
mouse_opacity = 2
update_mimic(!mapload) // Only recursively update if the map isn't loading.
// Cleans up Z-mimic objects for this turf. You shouldn't call this directly 99% of the time.
/// Cleans up Z-mimic objects for this turf. You shouldn't call this directly 99% of the time.
/turf/proc/cleanup_zmimic()
SSzcopy.openspace_turfs -= src
if (flags & MIMIC_QUEUED)
SSzcopy.queued_turfs -= src
SSzcopy.openspace_turfs -= 1
// Don't remove ourselves from the queue, the subsystem will explode. We'll naturally fall out of the queue.
z_queued = 0
QDEL_NULL(shadower)
QDEL_NULL(mimic_above_copy)
QDEL_NULL(mimic_underlay)
for (var/atom/movable/openspace/overlay/OwO in src) // wats this~?
OwO.owning_turf_changed()
for (var/atom/movable/openspace/mimic/OO in src)
OO.owning_turf_changed()
if (above)
above.update_mimic()
@@ -73,19 +89,3 @@
if (below)
below.above = null
below = null
// Movable for mimicing turfs that don't allow appearance mutation.
/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)