Files
John Willard fd752f043d Easy multi-z support for alarm console (+spawn changes) (#93198)
## About The Pull Request

Station alarm consoles now register to all Station Z levels+Areas if
they were created on a station Z level (this doesn't include mining, but
station ones will see mining areas), otherwise will be a "local" console
to that Z level only.

Mostly the same applies for Cyborg/AI, but if they were built on a
non-station Z level then they have their Z level added on top of Station
Z levels, so example Nukie saboteur borgs will see alarms they might
need, while a Golem/Oldstation AI will also be able to see their own
alarms.

Because of how alarms and spawning in worked, Cyborgs/AIs had CentCom's
Z level as something it would detect, so we simply create the mob at the
spawn location rather than on the title screen during Initialization,
fixing that issue as well.

## Why It's Good For The Game

Adds easy multi-z support for station alarms and removes the previous
bandaid of having to deconstruct your board and multitool it or map in
every single station alarm console to allow station alerts (which is
quite silly) which was done in
https://github.com/tgstation/tgstation/pull/88343.

Closes https://github.com/tgstation/tgstation/issues/61592
Closes https://github.com/tgstation/tgstation/issues/83042
Closes https://github.com/tgstation/tgstation/issues/69314

I find this solution better since it catches pretty much all use cases
without the need for special subtypes and needing players to actually
know the difference between these things.

## Changelog

🆑
fix: Cyborgs and AIs will now see alerts of the whole station rather
than solely the Z level they were spawned on.
fix: Cyborgs and AIs will no longer get alerts about Thunderdome.
/🆑
2025-10-02 18:12:57 +02:00

56 lines
2.1 KiB
Plaintext

/// Look up levels[z].traits[trait]
/datum/controller/subsystem/mapping/proc/level_trait(z, trait)
if (!isnum(z) || z < 1)
return null
if (z_list)
if (z > z_list.len)
stack_trace("Unmanaged z-level [z]! maxz = [world.maxz], z_list.len = [z_list.len]")
return list()
var/datum/space_level/S = z_list[z]
return S.traits[trait]
else
var/list/default = DEFAULT_MAP_TRAITS
if (z > default.len)
stack_trace("Unmanaged z-level [z]! maxz = [world.maxz], default.len = [default.len]")
return list()
return default[z][DL_TRAITS][trait]
/// Check if levels[z] has any of the specified traits
/datum/controller/subsystem/mapping/proc/level_has_any_trait(z, list/traits)
var/datum/space_level/level_to_check = z_list[z]
if (length(level_to_check.traits & traits))
return TRUE
return FALSE
/// Check if levels[z] has all of the specified traits
/datum/controller/subsystem/mapping/proc/level_has_all_traits(z, list/traits)
var/datum/space_level/level_to_check = z_list[z]
if (length(level_to_check.traits & traits) == length(traits))
return TRUE
return FALSE
/// Get a list of all z which have the specified trait
/datum/controller/subsystem/mapping/proc/levels_by_trait(trait) as /list
return z_trait_levels[trait] || list()
/// Get a list of all z which have any of the specified traits
/datum/controller/subsystem/mapping/proc/levels_by_any_trait(list/traits)
var/list/final_return = list()
for (var/trait in traits)
if (z_trait_levels[trait])
final_return |= z_trait_levels[trait]
return final_return
/// Get a list of all z which have all of the specified traits
/datum/controller/subsystem/mapping/proc/levels_by_all_traits(list/traits)
var/list/final_return = list()
for(var/datum/space_level/level as anything in z_list)
if(level_has_all_traits(level.z_value, traits))
final_return += level.z_value
return final_return
/// Prefer not to use this one too often
/datum/controller/subsystem/mapping/proc/get_station_center()
var/station_z = levels_by_trait(ZTRAIT_STATION)[1]
return locate(round(world.maxx * 0.5, 1), round(world.maxy * 0.5, 1), station_z)