From ea0fa299c49e01a700734ace2609a88d342ab382 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Thu, 7 Aug 2025 01:13:05 +0200 Subject: [PATCH] Fixes topdown emissives/emissive blockers and blood trail rendering (#92430) ## About The Pull Request Fixes this zen_Mhqh2OqiU4 This code is mildly bad, but this is the best way we can fix FLOAT_LAYER topdown emissives/blockers rendering ontop of everything else. Also added logging/unit testing for blood trails spawned outside of holders, mappers can use holders to spawn trails (which is the right way to add them to your maps) ## Changelog :cl: fix: Fixed blood/glass floor glow going over objects /:cl: --- code/__DEFINES/layers.dm | 7 +++++- code/__HELPERS/lighting.dm | 23 +++++++++++++++++-- .../objects/effects/decals/cleanable/blood.dm | 21 ++++++++++++++++- code/modules/unit_tests/unit_test.dm | 4 +++- code/modules/unit_tests/washing.dm | 2 +- 5 files changed, 51 insertions(+), 6 deletions(-) diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index b1069ed6b08..298248c51f2 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -153,6 +153,9 @@ // NOTICE: we break from the pattern of increasing in steps of like 0.01 here // Because TOPDOWN_LAYER is 10000 and that's enough to floating point our modifications away +// Must be equal to the offset of the highest topdown layer +#define TOPDOWN_LAYER_COUNT 18 + //lower than LOW_FLOOR_LAYER, for turfs with stuff on the edge that should be covered by other turfs #define LOWER_FLOOR_LAYER (1 + TOPDOWN_LAYER) #define LOW_FLOOR_LAYER (2 + TOPDOWN_LAYER) @@ -172,7 +175,7 @@ #define ABOVE_OPEN_TURF_LAYER (15 + TOPDOWN_LAYER) #define LOWER_RUNE_LAYER (16 + TOPDOWN_LAYER) #define RUNE_LAYER (17 + TOPDOWN_LAYER) -#define CLEANABLE_FLOOR_OBJECT_LAYER (21 + TOPDOWN_LAYER) +#define CLEANABLE_FLOOR_OBJECT_LAYER (18 + TOPDOWN_LAYER) //Placeholders in case the game plane and possibly other things between it and the floor plane are ever made into topdown planes @@ -188,6 +191,8 @@ // GAME_PLANE layers #define BULLET_HOLE_LAYER 2.06 #define ABOVE_NORMAL_TURF_LAYER 2.08 +#define FLOOR_EMISSIVE_START_LAYER 2.09 +#define FLOOR_EMISSIVE_END_LAYER 2.26 #define GAS_PIPE_HIDDEN_LAYER 2.35 //layer = initial(layer) + piping_layer / 1000 in atmospherics/update_icon() to determine order of pipe overlap #define WIRE_BRIDGE_LAYER 2.44 #define WIRE_TERMINAL_LAYER 2.45 diff --git a/code/__HELPERS/lighting.dm b/code/__HELPERS/lighting.dm index 0cc3f8ef5ea..4ab6737655f 100644 --- a/code/__HELPERS/lighting.dm +++ b/code/__HELPERS/lighting.dm @@ -1,5 +1,13 @@ +#define TOPDOWN_TO_EMISSIVE_LAYER(layer) LERP(FLOOR_EMISSIVE_START_LAYER, FLOOR_EMISSIVE_END_LAYER, (layer - (TOPDOWN_LAYER + 1)) / TOPDOWN_LAYER_COUNT) + /// Produces a mutable appearance glued to the [EMISSIVE_PLANE] dyed to be the [EMISSIVE_COLOR]. -/proc/emissive_appearance(icon, icon_state = "", atom/offset_spokesman, layer = FLOAT_LAYER, alpha = 255, appearance_flags = NONE, offset_const, apply_bloom = TRUE) +/proc/emissive_appearance(icon, icon_state = "", atom/offset_spokesman, layer, alpha = 255, appearance_flags = NONE, offset_const, apply_bloom = TRUE) + if (isnull(layer)) + if(IS_TOPDOWN_PLANE(offset_spokesman.plane)) + layer = TOPDOWN_TO_EMISSIVE_LAYER(offset_spokesman.layer) + else + layer = FLOAT_LAYER + var/mutable_appearance/appearance = mutable_appearance(icon, icon_state, layer, offset_spokesman, EMISSIVE_PLANE, 255, appearance_flags | EMISSIVE_APPEARANCE_FLAGS, offset_const) if(alpha == 255) if (apply_bloom) @@ -27,6 +35,10 @@ blocker.icon = make_blocker.icon blocker.icon_state = make_blocker.icon_state // blocker.layer = FLOAT_LAYER // Implied, FLOAT_LAYER is default for appearances + // If we keep this on a FLOAT_LAYER on a topdown object it'll render ontop of everything + // So we need to force it to render at a saner layer + if(IS_TOPDOWN_PLANE(make_blocker.plane)) + blocker.layer = TOPDOWN_TO_EMISSIVE_LAYER(make_blocker.layer) blocker.appearance_flags |= make_blocker.appearance_flags | EMISSIVE_APPEARANCE_FLAGS blocker.dir = make_blocker.dir if(make_blocker.alpha == 255) @@ -41,7 +53,12 @@ return blocker /// Produces a mutable appearance glued to the [EMISSIVE_PLANE] dyed to be the [EM_BLOCK_COLOR]. -/proc/emissive_blocker(icon, icon_state = "", atom/offset_spokesman, layer = FLOAT_LAYER, alpha = 255, appearance_flags = NONE, offset_const) +/proc/emissive_blocker(icon, icon_state = "", atom/offset_spokesman, layer, alpha = 255, appearance_flags = NONE, offset_const) + if (isnull(layer)) + if(IS_TOPDOWN_PLANE(offset_spokesman.plane)) + layer = TOPDOWN_TO_EMISSIVE_LAYER(offset_spokesman.layer) + else + layer = FLOAT_LAYER var/mutable_appearance/appearance = mutable_appearance(icon, icon_state, layer, offset_spokesman, EMISSIVE_PLANE, alpha, appearance_flags | EMISSIVE_APPEARANCE_FLAGS, offset_const) if(alpha == 255) appearance.color = GLOB.em_block_color @@ -77,3 +94,5 @@ var/atom/movable/vis_cast = make_blocker vis_cast.vis_contents += hand_back return hand_back + +#undef TOPDOWN_TO_EMISSIVE_LAYER diff --git a/code/game/objects/effects/decals/cleanable/blood.dm b/code/game/objects/effects/decals/cleanable/blood.dm index b5ae997f816..bd7e550293f 100644 --- a/code/game/objects/effects/decals/cleanable/blood.dm +++ b/code/game/objects/effects/decals/cleanable/blood.dm @@ -119,7 +119,7 @@ . += blood_emissive(icon, icon_state) /obj/effect/decal/cleanable/blood/proc/blood_emissive(icon_to_use, icon_state_to_use) - return emissive_appearance(icon_to_use, icon_state_to_use, src, layer, 255 * emissive_alpha / alpha) + return emissive_appearance(icon_to_use, icon_state_to_use, src, alpha = 255 * emissive_alpha / alpha) /obj/effect/decal/cleanable/blood/lazy_init_reagents() if (reagents) @@ -459,6 +459,25 @@ /// Beyond a threshold we change to a bloodier icon state var/very_bloody = FALSE +/obj/effect/decal/cleanable/blood/trail/Initialize(mapload, list/datum/disease/diseases, list/blood_or_dna) + . = ..() + // Despite having VIS_INHERIT_PLANE, our emissives still inherit our plane offset, so we need to inherit our parent's offset to have them render correctly + if(istype(loc, /obj/effect/decal/cleanable/blood/trail_holder)) + SET_PLANE_EXPLICIT(src, initial(plane), loc) + if (emissive_alpha && !dried) + update_appearance() // correct our emissive + return + + +#ifndef UNIT_TESTS + if (mapload) + log_mapping("[src] spawned outside of a trail holder at [AREACOORD(src)]!") + return INITIALIZE_HINT_QDEL +#endif + + stack_trace("[src] spawned outside of a trail holder at [AREACOORD(src)]!") + return INITIALIZE_HINT_QDEL + /obj/effect/decal/cleanable/blood/trail/update_desc(updates) . = ..() desc = "A [dried ? "dried " : ""]trail of [get_blood_string()]." diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm index 1ed5c73ed48..49ee85862be 100644 --- a/code/modules/unit_tests/unit_test.dm +++ b/code/modules/unit_tests/unit_test.dm @@ -276,8 +276,10 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests()) /obj/effect/bug_moving, //The abstract grown item expects a seed, but doesn't have one /obj/item/food/grown, - ///Single use case holder atom requiring a user + //Single use case holder atom requiring a user /atom/movable/looking_holder, + //Should not exist outside of holders + /obj/effect/decal/cleanable/blood/trail, ) // Everything that follows is a typesof() check. diff --git a/code/modules/unit_tests/washing.dm b/code/modules/unit_tests/washing.dm index c593b7dfc3b..795c66d018f 100644 --- a/code/modules/unit_tests/washing.dm +++ b/code/modules/unit_tests/washing.dm @@ -10,7 +10,7 @@ VAR_PRIVATE/clean_sig_caught = 0 /datum/unit_test/washing/Run() - for(var/i in subtypesof(/obj/effect/decal/cleanable) + cleanable_bonus_list) + for(var/i in subtypesof(/obj/effect/decal/cleanable) + cleanable_bonus_list - uncreatables) var/atom/movable/to_clean = allocate(i) var/mopable = HAS_TRAIT(to_clean, TRAIT_MOPABLE)