diff --git a/code/__HELPERS/_planes.dm b/code/__HELPERS/_planes.dm index 20f2f69ec9a..769c4283ea6 100644 --- a/code/__HELPERS/_planes.dm +++ b/code/__HELPERS/_planes.dm @@ -16,7 +16,8 @@ /// Takes a z reference that we are unsure of, sanity checks it /// Returns either its offset, or 0 if it's not a valid ref -#define GET_TURF_PLANE_OFFSET(z_reference) ((SSmapping.max_plane_offset && isatom(z_reference) && z_reference.z) ? GET_Z_PLANE_OFFSET(z_reference.z) : 0) +/// Will return the reference's PLANE'S offset if we can't get anything out of the z level. We do our best +#define GET_TURF_PLANE_OFFSET(z_reference) ((SSmapping.max_plane_offset && isatom(z_reference)) ? (z_reference.z ? GET_Z_PLANE_OFFSET(z_reference.z) : PLANE_TO_OFFSET(z_reference.plane)) : 0) /// Essentially just an unsafe version of GET_TURF_PLANE_OFFSET() /// Takes a z value we returns its offset with a list lookup /// Will runtime during parts of init. Be careful :) @@ -38,6 +39,7 @@ #define SET_PLANE_IMPLICIT(thing, new_value) SET_PLANE_EXPLICIT(thing, new_value, thing) // This is an unrolled and optimized version of SET_PLANE, for use anywhere where you are unsure of a source's "turfness" +// We do also try and guess at what the thing's z level is, even if it's not a z // The plane is cached to allow for fancy stuff to be eval'd once, rather then often #define SET_PLANE_EXPLICIT(thing, new_value, source) \ do {\ @@ -47,8 +49,11 @@ if(_our_turf){\ thing.plane = GET_NEW_PLANE(_cached_plane, GET_Z_PLANE_OFFSET(_our_turf.z));\ }\ + else if(source) {\ + thing.plane = GET_NEW_PLANE(_cached_plane, PLANE_TO_OFFSET(source.plane));\ + }\ else {\ - thing.plane = new_value;\ + thing.plane = _cached_plane;\ }\ }\ else {\ diff --git a/code/_onclick/hud/rendering/plane_master.dm b/code/_onclick/hud/rendering/plane_master.dm index 11c543ffab8..5edf9ee99dc 100644 --- a/code/_onclick/hud/rendering/plane_master.dm +++ b/code/_onclick/hud/rendering/plane_master.dm @@ -129,10 +129,28 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master) /// Returns TRUE if the call is allowed, FALSE otherwise /atom/movable/screen/plane_master/proc/show_to(mob/mymob) SHOULD_CALL_PARENT(TRUE) - if(force_hidden || is_outside_bounds) + if(force_hidden) return FALSE var/client/our_client = mymob?.client + // Alright, let's get this out of the way + // Mobs can move z levels without their client. If this happens, we need to ensure critical display settings are respected + // This is done here. Mild to severe pain but it's nessesary + if(check_outside_bounds()) + if(!(critical & PLANE_CRITICAL_DISPLAY)) + return FALSE + if(!our_client) + return TRUE + our_client.screen += src + + if(!(critical & PLANE_CRITICAL_NO_EMPTY_RELAY)) + our_client.screen += relays + return TRUE + for(var/atom/movable/render_plane_relay/relay as anything in relays) + if(relay.critical_target) + our_client.screen += relay + return TRUE + if(!our_client) return TRUE @@ -140,6 +158,11 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master) our_client.screen += relays return TRUE +/// Hook to allow planes to work around is_outside_bounds +/// Return false to allow a show, true otherwise +/atom/movable/screen/plane_master/proc/check_outside_bounds() + return is_outside_bounds + /// Hides a plane master from the passeed in mob /// Do your effect cleanup here /atom/movable/screen/plane_master/proc/hide_from(mob/oldmob) @@ -188,11 +211,10 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master) if(!(critical & PLANE_CRITICAL_NO_EMPTY_RELAY)) return var/client/our_client = relevant.client - if(!our_client) - return - for(var/atom/movable/render_plane_relay/relay as anything in relays) - if(!relay.critical_target) - our_client.screen -= relay + if(our_client) + for(var/atom/movable/render_plane_relay/relay as anything in relays) + if(!relay.critical_target) + our_client.screen -= relay // We here assume that your render target starts with * if(render_target) @@ -206,11 +228,10 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master) if(!(critical & PLANE_CRITICAL_NO_EMPTY_RELAY)) return var/client/our_client = relevant.client - if(!our_client) - return - for(var/atom/movable/render_plane_relay/relay as anything in relays) - if(!relay.critical_target) - our_client.screen += relay + if(our_client) + for(var/atom/movable/render_plane_relay/relay as anything in relays) + if(!relay.critical_target) + our_client.screen += relay // We here assume that your render target starts with * if(render_target) @@ -306,6 +327,11 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master) parent_parallax.add_relay_to(plane, BLEND_OVERLAY) return ..() +// Needs to handle rejoining on a lower z level, so we NEED to readd old planes +/atom/movable/screen/plane_master/parallax/check_outside_bounds() + // If we're outside bounds AND we're the 0th plane, we need to show cause parallax is hacked to hell + return offset != 0 && is_outside_bounds + /atom/movable/screen/plane_master/gravpulse name = "Gravpulse" documentation = "Ok so this one's fun. Basically, we want to be able to distort the game plane when a grav annom is around.\ diff --git a/code/_onclick/hud/rendering/render_plate.dm b/code/_onclick/hud/rendering/render_plate.dm index ccb4b809ee4..3fc1acb681e 100644 --- a/code/_onclick/hud/rendering/render_plate.dm +++ b/code/_onclick/hud/rendering/render_plate.dm @@ -45,8 +45,9 @@ return // Non 0 offset render plates will relay up to the transparent plane above them, assuming they're not on the same z level as their target of course var/datum/hud/hud = home.our_hud + // show_to can be called twice successfully with no hide_from call. Ensure no runtimes off the registers from this if(hud) - RegisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, PROC_REF(on_offset_change)) + RegisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, PROC_REF(on_offset_change), override = TRUE) offset_change(hud?.current_plane_offset || 0) /atom/movable/screen/plane_master/rendering_plate/master/hide_from(mob/oldmob) @@ -151,15 +152,19 @@ // Basically, we need something to brighten // unlit is perhaps less needed rn, it exists to provide a fullbright for things that can't see the lighting plane // but we don't actually use invisibility to hide the lighting plane anymore, so it's pointless - mymob.overlay_fullscreen("lighting_backdrop_lit", /atom/movable/screen/fullscreen/lighting_backdrop/lit) - mymob.overlay_fullscreen("lighting_backdrop_unlit", /atom/movable/screen/fullscreen/lighting_backdrop/unlit) + var/atom/movable/screen/backdrop = mymob.overlay_fullscreen("lighting_backdrop_lit#[offset]", /atom/movable/screen/fullscreen/lighting_backdrop/lit) + // Need to make sure they're on our plane, ALL the time. We always need a backdrop + SET_PLANE_EXPLICIT(backdrop, PLANE_TO_TRUE(backdrop.plane), src) + backdrop = mymob.overlay_fullscreen("lighting_backdrop_unlit#[offset]", /atom/movable/screen/fullscreen/lighting_backdrop/unlit) + SET_PLANE_EXPLICIT(backdrop, PLANE_TO_TRUE(backdrop.plane), src) // Sorry, this is a bit annoying // Basically, we only want the lighting plane we can actually see to attempt to render // If we don't our lower plane gets totally overriden by the black void of the upper plane var/datum/hud/hud = home.our_hud + // show_to can be called twice successfully with no hide_from call. Ensure no runtimes off the registers from this if(hud) - RegisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, PROC_REF(on_offset_change)) + RegisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, PROC_REF(on_offset_change), override = TRUE) offset_change(hud?.current_plane_offset || 0) set_alpha(mymob.lighting_alpha) diff --git a/code/datums/components/seethrough.dm b/code/datums/components/seethrough.dm index b5675904cdf..ba674f67471 100644 --- a/code/datums/components/seethrough.dm +++ b/code/datums/components/seethrough.dm @@ -102,13 +102,14 @@ for(var/atom/movable/screen/plane_master/seethrough in our_hud.get_true_plane_masters(SEETHROUGH_PLANE)) seethrough.unhide_plane(fool) - var/image/user_overlay = new(parent) - user_overlay.loc = parent + var/atom/atom_parent = parent + var/image/user_overlay = new(atom_parent) + user_overlay.loc = atom_parent user_overlay.override = TRUE if(clickthrough) //Special plane so we can click through the overlay - SET_PLANE_EXPLICIT(user_overlay, SEETHROUGH_PLANE, parent) + SET_PLANE_EXPLICIT(user_overlay, SEETHROUGH_PLANE, atom_parent) //These are inherited, but we already use the atom's loc so we end up at double the pixel offset user_overlay.pixel_x = 0 diff --git a/code/game/objects/effects/temporary_visuals/projectiles/projectile_effects.dm b/code/game/objects/effects/temporary_visuals/projectiles/projectile_effects.dm index 55b42dac00f..1e8577bbd3a 100644 --- a/code/game/objects/effects/temporary_visuals/projectiles/projectile_effects.dm +++ b/code/game/objects/effects/temporary_visuals/projectiles/projectile_effects.dm @@ -37,9 +37,9 @@ apply_vars(angle_override, p_x, p_y, color_override, scaling) return ..() -/obj/effect/projectile/proc/apply_vars(angle_override, p_x = 0, p_y = 0, color_override, scaling = 1, new_loc, increment = 0) +/obj/effect/projectile/proc/apply_vars(angle_override, p_x = 0, p_y = 0, color_override, scaling = 1, atom/new_loc, increment = 0) var/mutable_appearance/look = new(src) - SET_PLANE_EXPLICIT(look, plane, new_loc) + SET_PLANE_EXPLICIT(look, plane, new_loc || src) look.pixel_x = p_x look.pixel_y = p_y if(color_override) diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 1549ae2acb0..40a3d4adfbd 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -240,9 +240,10 @@ if(del_on_fail) qdel(I) return FALSE - I.forceMove(drop_location()) + var/atom/location = drop_location() + I.forceMove(location) I.layer = initial(I.layer) - SET_PLANE_EXPLICIT(I, initial(I.plane), drop_location()) + SET_PLANE_EXPLICIT(I, initial(I.plane), location) I.dropped(src) return FALSE @@ -307,7 +308,7 @@ //DO NOT CALL THIS PROC //use one of the above 3 helper procs //you may override it, but do not modify the args -/mob/proc/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE, silent = FALSE) //Force overrides TRAIT_NODROP for things like wizarditis and admin undress. +/mob/proc/doUnEquip(obj/item/I, force, atom/newloc, no_move, invdrop = TRUE, silent = FALSE) //Force overrides TRAIT_NODROP for things like wizarditis and admin undress. //Use no_move if the item is just gonna be immediately moved afterward //Invdrop is used to prevent stuff in pockets dropping. only set to false if it's going to immediately be replaced PROTECTED_PROC(TRUE) @@ -328,7 +329,7 @@ if(client) client.screen -= I I.layer = initial(I.layer) - SET_PLANE_EXPLICIT(I, initial(I.plane), drop_location()) + SET_PLANE_EXPLICIT(I, initial(I.plane), newloc) I.appearance_flags &= ~NO_CLIENT_COLOR if(!no_move && !(I.item_flags & DROPDEL)) //item may be moved/qdel'd immedietely, don't bother moving it if (isnull(newloc)) diff --git a/code/modules/shuttle/navigation_computer.dm b/code/modules/shuttle/navigation_computer.dm index e2c9811370b..b4f82b01f8c 100644 --- a/code/modules/shuttle/navigation_computer.dm +++ b/code/modules/shuttle/navigation_computer.dm @@ -191,12 +191,11 @@ QDEL_LIST(the_eye.placed_images) - for(var/V in the_eye.placement_images) - var/image/I = V + for(var/image/place_spots as anything in the_eye.placement_images) var/image/newI = image('icons/effects/alphacolors.dmi', the_eye.loc, "blue") - newI.loc = I.loc //It is highly unlikely that any landing spot including a null tile will get this far, but better safe than sorry. + newI.loc = place_spots.loc //It is highly unlikely that any landing spot including a null tile will get this far, but better safe than sorry. newI.layer = NAVIGATION_EYE_LAYER - SET_PLANE_EXPLICIT(newI, ABOVE_GAME_PLANE, V) + SET_PLANE_EXPLICIT(newI, ABOVE_GAME_PLANE, place_spots) newI.mouse_opacity = 0 the_eye.placed_images += newI