Weather planes from The Wallening to fix multi-z weather overlays (#86733)

## About The Pull Request

I started doing this for Yogstation, but ended up doing all my testing
on TG code since there's more debug tools to use, and @LemonInTheDark
said I should upstream it when I was done. So I'm just gonna start here.
The whole point of this is to stop multi-z maps from stacking weather
overlay effects like

![dreamseeker_FBUu3nPLCJ](https://github.com/user-attachments/assets/52559dfc-68d2-403d-8148-b410750f78c4)
Old pic I know, but you get the point

Now it behaves as expected


https://github.com/user-attachments/assets/6d737eae-2493-4b48-8870-e4ac73dcbbeb



https://github.com/user-attachments/assets/b253aa97-c90d-4049-a97d-940b0ec386d0


<details>

<summary>Note: this does not fix the issue of areas out of your view not
updating their appearance. 90% sure that's a Byond™️ issue</summary>


https://github.com/user-attachments/assets/3db5ce28-2623-4d3e-a5f4-bd561d96010a

</details>



## Why It's Good For The Game

Isolating weather to its own planes is good for having better control
over how it behaves. Since weather overlays are tied to areas it makes
them kinda hacky to begin with, but this is a step in reigning them in.

## Changelog
🆑
fix: fixed multi-z weather overlays stacking and not hiding overlays
above you
/🆑
This commit is contained in:
Chubbygummibear
2024-10-02 22:49:09 -07:00
committed by GitHub
parent a85f71e9a4
commit 22d319fa86
10 changed files with 197 additions and 21 deletions

View File

@@ -1,5 +1,7 @@
/// Sent from /datum/hud/proc/on_eye_change(): (atom/old_eye, atom/new_eye)
#define COMSIG_HUD_EYE_CHANGED "hud_eye_changed"
/// Sent from /datum/hud/proc/eye_z_changed() : (new_z)
#define COMSIG_HUD_Z_CHANGED "hud_z_changed"
/// Sent from /datum/hud/proc/eye_z_changed() : (old_offset, new_offset)
#define COMSIG_HUD_OFFSET_CHANGED "hud_offset_changed"
/// Sent from /atom/movable/screen/lobby/button/collapse/proc/collapse_buttons() : ()

View File

@@ -0,0 +1,2 @@
/// from /datum/plane_master_group/proc/set_hud(): (datum/hud/new_hud)
#define COMSIG_GROUP_HUD_CHANGED "group_hud_changed"

View File

@@ -32,6 +32,7 @@
#define DEFAULT_PLANE 0 //Marks out the default plane, even if we don't use it
#define WEATHER_PLANE 1
#define AREA_PLANE 2
#define MASSIVE_OBJ_PLANE 3
#define GHOST_PLANE 4
@@ -65,6 +66,8 @@
///Things that should render ignoring lighting
#define ABOVE_LIGHTING_PLANE 17
#define WEATHER_GLOW_PLANE 18
///---------------- MISC -----------------------
///Pipecrawling images

View File

@@ -198,6 +198,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
SIGNAL_HANDLER
update_parallax_pref() // If your eye changes z level, so should your parallax prefs
var/turf/eye_turf = get_turf(eye)
SEND_SIGNAL(src, COMSIG_HUD_Z_CHANGED, eye_turf.z)
var/new_offset = GET_TURF_PLANE_OFFSET(eye_turf)
if(current_plane_offset == new_offset)
return

View File

@@ -24,10 +24,23 @@
build_plane_masters(0, SSmapping.max_plane_offset)
/datum/plane_master_group/Destroy()
orphan_hud()
set_hud(null)
QDEL_LIST_ASSOC_VAL(plane_masters)
return ..()
/datum/plane_master_group/proc/set_hud(datum/hud/new_hud)
if(new_hud == our_hud)
return
if(our_hud)
our_hud.master_groups -= key
hide_hud()
our_hud = new_hud
if(new_hud)
our_hud.master_groups[key] = src
show_hud()
build_planes_offset(our_hud, active_offset)
SEND_SIGNAL(src, COMSIG_GROUP_HUD_CHANGED, our_hud)
/// Display a plane master group to some viewer, so show all our planes to it
/datum/plane_master_group/proc/attach_to(datum/hud/viewing_hud)
if(viewing_hud.master_groups[key])
@@ -42,18 +55,11 @@
relay_loc = "1,1"
rebuild_plane_masters()
our_hud = viewing_hud
set_hud(viewing_hud)
our_hud.master_groups[key] = src
show_hud()
build_planes_offset(our_hud, active_offset)
/// Hide the plane master from its current hud, fully clear it out
/datum/plane_master_group/proc/orphan_hud()
if(our_hud)
our_hud.master_groups -= key
hide_hud()
our_hud = null
/// Well, refresh our group, mostly useful for plane specific updates
/datum/plane_master_group/proc/refresh_hud()
hide_hud()

View File

@@ -243,6 +243,18 @@
documentation = "Holds the areas themselves, which ends up meaning it holds any overlays/effects we apply to areas. NOT snow or rad storms, those go on above lighting"
plane = AREA_PLANE
/atom/movable/screen/plane_master/weather
name = "Weather"
documentation = "Holds the main tiling 32x32 sprites of weather. We mask against walls that are on the edge of weather effects."
plane = WEATHER_PLANE
start_hidden = TRUE
/atom/movable/screen/plane_master/weather/set_home(datum/plane_master_group/home)
. = ..()
if(!.)
return
home.AddComponent(/datum/component/hide_weather_planes, src)
/atom/movable/screen/plane_master/massive_obj
name = "Massive object"
documentation = "Huge objects need to render above everything else on the game plane, otherwise they'd well, get clipped and look not that huge. This does that."
@@ -285,6 +297,18 @@
documentation = "Anything on the game plane that needs a space to draw on that will be above the lighting plane.\
<br>Mostly little alerts and effects, also sometimes contains things that are meant to look as if they glow."
/atom/movable/screen/plane_master/weather_glow
name = "Weather Glow"
documentation = "Holds the glowing parts of the main tiling 32x32 sprites of weather."
plane = WEATHER_GLOW_PLANE
start_hidden = TRUE
/atom/movable/screen/plane_master/weather_glow/set_home(datum/plane_master_group/home)
. = ..()
if(!.)
return
home.AddComponent(/datum/component/hide_weather_planes, src)
/**
* Handles emissive overlays and emissive blockers.
*/

View File

@@ -345,7 +345,7 @@
if(!.)
return
RegisterSignal(mymob, COMSIG_MOB_SIGHT_CHANGE, PROC_REF(handle_sight))
RegisterSignal(mymob, COMSIG_MOB_SIGHT_CHANGE, PROC_REF(handle_sight), override = TRUE)
handle_sight(mymob, mymob.sight, NONE)
/atom/movable/screen/plane_master/rendering_plate/light_mask/hide_from(mob/oldmob)

View File

@@ -0,0 +1,136 @@
/**
* Component that manages a list of plane masters that are dependent on weather
* Force hides/shows them depending on the weather activity of their z stack
* Transparency is achieved by manipulating the alpha of the planes that are visible
* Applied to the plane master group that owns them
*/
/datum/component/hide_weather_planes
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/list/datum/weather/active_weather = list()
var/list/atom/movable/screen/plane_master/plane_masters = list()
/datum/component/hide_weather_planes/Initialize(atom/movable/screen/plane_master/care_about)
if(!istype(parent, /datum/plane_master_group))
return COMPONENT_INCOMPATIBLE
var/datum/plane_master_group/home = parent
plane_masters += care_about
RegisterSignal(care_about, COMSIG_QDELETING, PROC_REF(plane_master_deleted))
var/list/starting_signals = list()
var/list/ending_signals = list()
for(var/datum/weather/weather_type as anything in typesof(/datum/weather))
starting_signals += COMSIG_WEATHER_TELEGRAPH(weather_type)
ending_signals += COMSIG_WEATHER_END(weather_type)
RegisterSignals(SSdcs, starting_signals, PROC_REF(weather_started))
RegisterSignals(SSdcs, ending_signals, PROC_REF(weather_finished))
if(home.our_hud)
attach_hud(home.our_hud)
else
RegisterSignal(home, COMSIG_GROUP_HUD_CHANGED, PROC_REF(new_hud_attached))
/datum/component/hide_weather_planes/Destroy(force)
hide_planes()
active_weather = null
plane_masters = null
return ..()
/datum/component/hide_weather_planes/InheritComponent(datum/component/new_comp, i_am_original, atom/movable/screen/plane_master/care_about)
if(!i_am_original)
return
var/datum/plane_master_group/home = parent
var/mob/our_lad = home.our_hud?.mymob
var/our_offset = GET_TURF_PLANE_OFFSET(our_lad)
plane_masters += care_about
RegisterSignal(care_about, COMSIG_QDELETING, PROC_REF(plane_master_deleted))
if(length(active_weather))
//If there's weather to care about we unhide our new plane and adjust its alpha
care_about.unhide_plane(our_lad)
if(care_about.offset >= our_offset)
care_about.enable_alpha()
else
care_about.disable_alpha()
else
care_about.hide_plane(our_lad)
/datum/component/hide_weather_planes/proc/new_hud_attached(datum/source, datum/hud/new_hud)
SIGNAL_HANDLER
attach_hud(new_hud)
/datum/component/hide_weather_planes/proc/attach_hud(datum/hud/new_hud)
RegisterSignal(new_hud, COMSIG_HUD_Z_CHANGED, PROC_REF(z_changed))
var/mob/eye = new_hud?.mymob?.client?.eye
var/turf/eye_location = get_turf(eye)
z_changed(new_hud, eye_location?.z)
/datum/component/hide_weather_planes/proc/plane_master_deleted(atom/movable/screen/plane_master/source)
SIGNAL_HANDLER
plane_masters -= source
/**
* Unhides the relevant planes for the weather to be visible and manipulated.
* Also updates the alpha of the planes so enabled planes are either fully opaque or fully transparent
*/
/datum/component/hide_weather_planes/proc/display_planes()
var/datum/plane_master_group/home = parent
var/mob/our_lad = home.our_hud?.mymob
var/our_offset = GET_TURF_PLANE_OFFSET(our_lad)
for(var/atom/movable/screen/plane_master/weather_concious as anything in plane_masters)
//If the plane is hidden, unhide it
if(weather_concious.force_hidden)
weather_concious.unhide_plane(our_lad)
//Now we update the alpha of the plane based on our offset. Weather above us (lower offset) are transparent, weather at or below us (higher offset) are opaque.
if(weather_concious.offset >= our_offset)
weather_concious.enable_alpha()
else
weather_concious.disable_alpha()
///Hides the planes from the mob when no weather is occuring
/datum/component/hide_weather_planes/proc/hide_planes()
var/datum/plane_master_group/home = parent
var/mob/our_lad = home.our_hud?.mymob
for(var/atom/movable/screen/plane_master/weather_concious as anything in plane_masters)
weather_concious.hide_plane(our_lad)
/datum/component/hide_weather_planes/proc/z_changed(datum/source, new_z)
SIGNAL_HANDLER
active_weather = list()
if(!SSmapping.initialized)
return
var/list/connected_levels = SSmapping.get_connected_levels(new_z)
for(var/datum/weather/active as anything in SSweather.processing)
if(length(connected_levels & active.impacted_z_levels))
active_weather += WEAKREF(active)
if(length(active_weather))
display_planes()
else
hide_planes()
/datum/component/hide_weather_planes/proc/weather_started(datum/source, datum/weather/starting)
SIGNAL_HANDLER
var/datum/plane_master_group/home = parent
var/mob/eye = home.our_hud?.mymob?.client?.eye
var/turf/viewing_from = get_turf(eye)
if(!viewing_from)
return
var/list/connected_levels = SSmapping.get_connected_levels(viewing_from)
if(length(connected_levels & starting.impacted_z_levels))
active_weather += WEAKREF(starting)
if(!length(active_weather))
return
display_planes()
/datum/component/hide_weather_planes/proc/weather_finished(datum/source, datum/weather/stopping)
SIGNAL_HANDLER
active_weather -= WEAKREF(stopping)
if(length(active_weather))
return
hide_planes()

View File

@@ -59,7 +59,7 @@
/// Since it's above everything else, this is the layer used by default.
var/overlay_layer = AREA_LAYER
/// Plane for the overlay
var/overlay_plane = AREA_PLANE
var/overlay_plane = WEATHER_PLANE
/// If the weather has no purpose other than looks
var/aesthetic = FALSE
/// Used by mobs (or movables containing mobs, such as enviro bags) to prevent them from being affected by the weather.
@@ -99,7 +99,7 @@
/datum/weather/proc/telegraph()
if(stage == STARTUP_STAGE)
return
SEND_GLOBAL_SIGNAL(COMSIG_WEATHER_TELEGRAPH(type))
SEND_GLOBAL_SIGNAL(COMSIG_WEATHER_TELEGRAPH(type), src)
stage = STARTUP_STAGE
var/list/affectareas = list()
for(var/V in get_areas(area_type))
@@ -129,14 +129,14 @@
/datum/weather/proc/start()
if(stage >= MAIN_STAGE)
return
SEND_GLOBAL_SIGNAL(COMSIG_WEATHER_START(type))
SEND_GLOBAL_SIGNAL(COMSIG_WEATHER_START(type), src)
stage = MAIN_STAGE
update_areas()
send_alert(weather_message, weather_sound)
if(!perpetual)
addtimer(CALLBACK(src, PROC_REF(wind_down)), weather_duration)
for(var/area/impacted_area as anything in impacted_areas)
SEND_SIGNAL(impacted_area, COMSIG_WEATHER_BEGAN_IN_AREA(type))
SEND_SIGNAL(impacted_area, COMSIG_WEATHER_BEGAN_IN_AREA(type), src)
/**
* Weather enters the winding down phase, stops effects
@@ -148,7 +148,7 @@
/datum/weather/proc/wind_down()
if(stage >= WIND_DOWN_STAGE)
return
SEND_GLOBAL_SIGNAL(COMSIG_WEATHER_WINDDOWN(type))
SEND_GLOBAL_SIGNAL(COMSIG_WEATHER_WINDDOWN(type), src)
stage = WIND_DOWN_STAGE
update_areas()
send_alert(end_message, end_sound)
@@ -164,12 +164,12 @@
/datum/weather/proc/end()
if(stage == END_STAGE)
return
SEND_GLOBAL_SIGNAL(COMSIG_WEATHER_END(type))
SEND_GLOBAL_SIGNAL(COMSIG_WEATHER_END(type), src)
stage = END_STAGE
SSweather.processing -= src
update_areas()
for(var/area/impacted_area as anything in impacted_areas)
SEND_SIGNAL(impacted_area, COMSIG_WEATHER_ENDED_IN_AREA(type))
SEND_SIGNAL(impacted_area, COMSIG_WEATHER_ENDED_IN_AREA(type), src)
// handles sending all alerts
/datum/weather/proc/send_alert(alert_msg, alert_sfx)
@@ -260,12 +260,12 @@
// I prefer it to creating 2 extra plane masters however, so it's a cost I'm willing to pay
// LU
if(use_glow)
var/mutable_appearance/glow_overlay = mutable_appearance('icons/effects/glow_weather.dmi', weather_state, overlay_layer, null, ABOVE_LIGHTING_PLANE, 100, offset_const = offset)
var/mutable_appearance/glow_overlay = mutable_appearance('icons/effects/glow_weather.dmi', weather_state, overlay_layer, null, WEATHER_GLOW_PLANE, 100, offset_const = offset)
glow_overlay.color = weather_color
gen_overlay_cache += glow_overlay
var/mutable_appearance/weather_overlay = mutable_appearance('icons/effects/weather_effects.dmi', weather_state, overlay_layer, plane = overlay_plane, offset_const = offset)
weather_overlay.color = weather_color
gen_overlay_cache += weather_overlay
var/mutable_appearance/new_weather_overlay = mutable_appearance('icons/effects/weather_effects.dmi', weather_state, overlay_layer, plane = overlay_plane, offset_const = offset)
new_weather_overlay.color = weather_color
gen_overlay_cache += new_weather_overlay
return gen_overlay_cache

View File

@@ -344,6 +344,7 @@
#include "code\__DEFINES\dcs\signals\signals_operating_computer.dm"
#include "code\__DEFINES\dcs\signals\signals_operatives.dm"
#include "code\__DEFINES\dcs\signals\signals_painting.dm"
#include "code\__DEFINES\dcs\signals\signals_plane_master_group.dm"
#include "code\__DEFINES\dcs\signals\signals_proxmonitor.dm"
#include "code\__DEFINES\dcs\signals\signals_radiation.dm"
#include "code\__DEFINES\dcs\signals\signals_reagent.dm"
@@ -1134,6 +1135,7 @@
#include "code\datums\components\heart_eater.dm"
#include "code\datums\components\heirloom.dm"
#include "code\datums\components\hide_highest_offset.dm"
#include "code\datums\components\hide_weather_planes.dm"
#include "code\datums\components\holderloving.dm"
#include "code\datums\components\igniter.dm"
#include "code\datums\components\infective.dm"