Files
Bubberstation/code/__HELPERS/level_traits.dm
SkyratBot 6b00484526 [MIRROR] Fixes is_station_level() sometimes behaving erratically if the value provided is more complex than just a variable [MDB IGNORE] (#21270)
* Fixes is_station_level() sometimes behaving erratically if the value provided is more complex than just a variable (#75489)

## About The Pull Request
I have been debugging this stupid macro for the past nearly five hours,
to finally figure out why it was breaking. If you had something like `a
|| 0` in what you called the macro with, it would somehow manage to
break the cache. This makes it far more foolproof, and will ensure that
it doesn't break here anymore, because debugging this has to be one of
the biggest pains in my ass I've ever had.

## Why It's Good For The Game
So shit like this

![image](https://github.com/tgstation/tgstation/assets/58045821/455122b0-34eb-4ec0-92dd-2775c1f0f878)

Doesn't end up breaking your CI (or even worse, the game in prod), in
places unrelated. At least now it shouldn't be overwriting values in the
cache.

It shouldn't have to do verification that you're doing the right thing,
that should be left on the person using the macro because it was meant
to be faster than a proc call, adding too much verification overhead
kind of just loses some of that speed.

## Changelog

🆑 GoldenAlpharex
fix: Makes checks for the station z level more robust against coders
doing less intuitive stuff, thus protecting it from breaking in weirdly
difficult and seemingly unrelated places (I'm looking at you, nuke
cinematic unit test).
/🆑

* Fixes is_station_level() sometimes behaving erratically if the value provided is more complex than just a variable

---------

Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com>
2023-05-18 13:17:39 -07:00

31 lines
1.2 KiB
Plaintext

// Helpers for checking whether a z-level conforms to a specific requirement
// Basic levels
#define is_centcom_level(z) SSmapping.level_trait(z, ZTRAIT_CENTCOM)
GLOBAL_LIST_EMPTY(station_levels_cache)
// Used to prevent z from being re-evaluated
GLOBAL_VAR(station_level_z_scratch)
// Called a lot, somewhat slow, so has its own cache
#define is_station_level(z_level) \
( \
(z_level) && \
( \
/* The right hand side of this guarantees that we'll have the space to fill later on, while also not failing the condition */ \
(GLOB.station_levels_cache.len < (GLOB.station_level_z_scratch = (z_level)) && (GLOB.station_levels_cache.len = GLOB.station_level_z_scratch)) \
|| isnull(GLOB.station_levels_cache[GLOB.station_level_z_scratch]) \
) \
? (GLOB.station_levels_cache[GLOB.station_level_z_scratch] = !!SSmapping.level_trait(GLOB.station_level_z_scratch, ZTRAIT_STATION)) \
: GLOB.station_levels_cache[GLOB.station_level_z_scratch] \
)
#define is_mining_level(z) SSmapping.level_trait(z, ZTRAIT_MINING)
#define is_reserved_level(z) SSmapping.level_trait(z, ZTRAIT_RESERVED)
#define is_away_level(z) SSmapping.level_trait(z, ZTRAIT_AWAY)
#define is_secret_level(z) SSmapping.level_trait(z, ZTRAIT_SECRET)