diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm
index 58e2be31b01..3ad2900bfa1 100644
--- a/code/__DEFINES/layers.dm
+++ b/code/__DEFINES/layers.dm
@@ -7,23 +7,35 @@
#define PLANE_SPACE_PARALLAX -90
#define GAME_PLANE 0
+
#define SPACE_LAYER 1.8
//#define TURF_LAYER 2 //For easy recordkeeping; this is a byond define
#define MID_TURF_LAYER 2.02
#define HIGH_TURF_LAYER 2.03
+#define TURF_PLATING_DECAL_LAYER 2.031
+#define TURF_DECAL_LAYER 2.039 //Makes turf decals appear in DM how they will look inworld.
#define ABOVE_OPEN_TURF_LAYER 2.04
#define CLOSED_TURF_LAYER 2.05
+#define BULLET_HOLE_LAYER 2.06
#define ABOVE_NORMAL_TURF_LAYER 2.08
#define LATTICE_LAYER 2.2
#define DISPOSAL_PIPE_LAYER 2.3
-#define GAS_PIPE_LAYER 2.35
+#define GAS_PIPE_HIDDEN_LAYER 2.35
#define WIRE_LAYER 2.4
#define WIRE_TERMINAL_LAYER 2.45
+#define GAS_SCRUBBER_LAYER 2.46
+#define GAS_PIPE_VISIBLE_LAYER 2.47
+#define GAS_FILTER_LAYER 2.48
+#define GAS_PUMP_LAYER 2.49
#define LOW_OBJ_LAYER 2.5
+#define LOW_SIGIL_LAYER 2.52
+#define SIGIL_LAYER 2.54
+#define HIGH_SIGIL_LAYER 2.56
#define BELOW_OPEN_DOOR_LAYER 2.6
#define BLASTDOOR_LAYER 2.65
#define OPEN_DOOR_LAYER 2.7
+#define DOOR_HELPER_LAYER 2.71 //keep this above OPEN_DOOR_LAYER
#define PROJECTILE_HIT_THRESHHOLD_LAYER 2.75 //projectiles won't hit objects at or below this layer if possible
#define TABLE_LAYER 2.8
#define BELOW_OBJ_LAYER 2.9
@@ -52,9 +64,13 @@
#define SPACEVINE_LAYER 4.8
#define SPACEVINE_MOB_LAYER 4.9
//#define FLY_LAYER 5 //For easy recordkeeping; this is a byond define
+#define GASFIRE_LAYER 5.05
#define RIPPLE_LAYER 5.1
#define GHOST_LAYER 6
+#define LOW_LANDMARK_LAYER 9
+#define MID_LANDMARK_LAYER 9.1
+#define HIGH_LANDMARK_LAYER 9.2
#define AREA_LAYER 10
#define MASSIVE_OBJ_LAYER 11
#define POINT_LAYER 12
@@ -62,6 +78,26 @@
#define LIGHTING_PLANE 15
#define LIGHTING_LAYER 15
+#define ABOVE_LIGHTING_PLANE 16
+#define ABOVE_LIGHTING_LAYER 16
+
+#define BYOND_LIGHTING_PLANE 17
+#define BYOND_LIGHTING_LAYER 17
+
//HUD layer defines
+
+#define FULLSCREEN_PLANE 18
+#define FLASH_LAYER 18
+#define FULLSCREEN_LAYER 18.1
+#define UI_DAMAGE_LAYER 18.2
+#define BLIND_LAYER 18.3
+#define CRIT_LAYER 18.4
+#define CURSE_LAYER 18.5
+
+#define HUD_PLANE 19
#define HUD_LAYER 19
-#define HUD_PLANE 90
\ No newline at end of file
+#define ABOVE_HUD_PLANE 20
+#define ABOVE_HUD_LAYER 20
+
+#define SPLASHSCREEN_LAYER 21
+#define SPLASHSCREEN_PLANE 21
\ No newline at end of file
diff --git a/code/controllers/Processes/nanoui.dm b/code/controllers/Processes/nanoui.dm
deleted file mode 100644
index 1667af943da..00000000000
--- a/code/controllers/Processes/nanoui.dm
+++ /dev/null
@@ -1,19 +0,0 @@
-/datum/controller/process/nanoui/setup()
- name = "nanoui"
- schedule_interval = 20 // every 2 seconds
-
-/datum/controller/process/nanoui/statProcess()
- ..()
- stat(null, "[nanomanager.processing_uis.len] UIs")
-
-/datum/controller/process/nanoui/doWork()
- for(last_object in nanomanager.processing_uis)
- var/datum/nanoui/NUI = last_object
- if(istype(NUI) && isnull(NUI.gcDestroyed))
- try
- NUI.process()
- catch(var/exception/e)
- catchException(e, NUI)
- else
- catchBadType(NUI)
- nanomanager.processing_uis -= NUI
diff --git a/code/controllers/Processes/weather.dm b/code/controllers/Processes/weather.dm
deleted file mode 100644
index 919352313c6..00000000000
--- a/code/controllers/Processes/weather.dm
+++ /dev/null
@@ -1,54 +0,0 @@
-//Used for all kinds of weather, ex. lavaland ash storms.
-// TODO: This could probably be better-integrated with the space manager
-var/global/datum/controller/process/weather/weather_master
-
-/datum/controller/process/weather
- var/list/processing_weather = list()
- var/list/existing_weather = list()
- var/list/eligible_zlevels = list()
-
-/datum/controller/process/weather/setup()
- name = "weather"
- schedule_interval = 10
-
- for(var/V in subtypesof(/datum/weather))
- var/datum/weather/W = V
- existing_weather |= new W
-
-/datum/controller/process/weather/statProcess()
- ..()
- stat(null, "[processing_weather.len] weather")
-
-/datum/controller/process/weather/doWork()
- for(var/V in processing_weather)
- var/datum/weather/W = V
- if(W.aesthetic)
- continue
- for(var/mob/living/L in mob_list)
- if(W.can_impact(L))
- W.impact(L)
- SCHECK
- for(var/Z in eligible_zlevels)
- var/list/possible_weather_for_this_z = list()
- for(var/V in existing_weather)
- var/datum/weather/WE = V
- if(WE.target_z == Z && WE.probability) //Another check so that it doesn't run extra weather
- possible_weather_for_this_z[WE] = WE.probability
- var/datum/weather/W = pickweight(possible_weather_for_this_z)
- run_weather(W.name)
- eligible_zlevels -= Z
- addtimer(CALLBACK(src, .proc/make_z_eligible, Z), rand(3000, 6000) + W.weather_duration_upper, TIMER_UNIQUE) //Around 5-10 minutes between weathers
-
-DECLARE_GLOBAL_CONTROLLER(weather, weather_master)
-
-/datum/controller/process/weather/proc/run_weather(weather_name)
- if(!weather_name)
- return
- for(var/V in existing_weather)
- var/datum/weather/W = V
- if(W.name == weather_name)
- W.telegraph()
- SCHECK
-
-/datum/controller/process/weather/proc/make_z_eligible(zlevel)
- eligible_zlevels |= zlevel
diff --git a/code/controllers/subsystem/weather.dm b/code/controllers/subsystem/weather.dm
new file mode 100644
index 00000000000..4f5798e4ae4
--- /dev/null
+++ b/code/controllers/subsystem/weather.dm
@@ -0,0 +1,83 @@
+#define STARTUP_STAGE 1
+#define MAIN_STAGE 2
+#define WIND_DOWN_STAGE 3
+#define END_STAGE 4
+
+//Used for all kinds of weather, ex. lavaland ash storms.
+SUBSYSTEM_DEF(weather)
+ name = "Weather"
+ flags = SS_BACKGROUND
+ wait = 10
+ runlevels = RUNLEVEL_GAME
+ var/list/processing = list()
+ var/list/eligible_zlevels = list()
+ var/list/next_hit_by_zlevel = list() //Used by barometers to know when the next storm is coming
+
+/datum/controller/subsystem/weather/fire()
+ // process active weather
+ for(var/V in processing)
+ var/datum/weather/W = V
+ if(W.aesthetic || W.stage != MAIN_STAGE)
+ continue
+ for(var/i in living_mob_list)
+ var/mob/living/L = i
+ if(W.can_weather_act(L))
+ W.weather_act(L)
+
+ // start random weather on relevant levels
+ for(var/z in eligible_zlevels)
+ var/possible_weather = eligible_zlevels[z]
+ var/datum/weather/W = pickweight(possible_weather)
+ run_weather(W, list(text2num(z)))
+ eligible_zlevels -= z
+ var/randTime = rand(3000, 6000)
+ addtimer(CALLBACK(src, .proc/make_eligible, z, possible_weather), randTime + initial(W.weather_duration_upper), TIMER_UNIQUE) //Around 5-10 minutes between weathers
+ next_hit_by_zlevel["[z]"] = world.time + randTime + initial(W.telegraph_duration)
+
+/datum/controller/subsystem/weather/Initialize(start_timeofday)
+ for(var/V in subtypesof(/datum/weather))
+ var/datum/weather/W = V
+ var/probability = initial(W.probability)
+ var/target_trait = initial(W.target_trait)
+
+ // any weather with a probability set may occur at random
+ if(probability)
+ for(var/z in levels_by_trait(target_trait))
+ LAZYINITLIST(eligible_zlevels["[z]"])
+ eligible_zlevels["[z]"][W] = probability
+ ..()
+
+/datum/controller/subsystem/weather/proc/run_weather(datum/weather/weather_datum_type, z_levels)
+ if(istext(weather_datum_type))
+ for(var/V in subtypesof(/datum/weather))
+ var/datum/weather/W = V
+ if(initial(W.name) == weather_datum_type)
+ weather_datum_type = V
+ break
+ if(!ispath(weather_datum_type, /datum/weather))
+ CRASH("run_weather called with invalid weather_datum_type: [weather_datum_type || "null"]")
+ return
+
+ if(isnull(z_levels))
+ z_levels = levels_by_trait(initial(weather_datum_type.target_trait))
+ else if(isnum(z_levels))
+ z_levels = list(z_levels)
+ else if(!islist(z_levels))
+ CRASH("run_weather called with invalid z_levels: [z_levels || "null"]")
+ return
+
+ var/datum/weather/W = new weather_datum_type(z_levels)
+ W.telegraph()
+
+/datum/controller/subsystem/weather/proc/make_eligible(z, possible_weather)
+ eligible_zlevels[z] = possible_weather
+ next_hit_by_zlevel["[z]"] = null
+
+/datum/controller/subsystem/weather/proc/get_weather(z, area/active_area)
+ var/datum/weather/A
+ for(var/V in processing)
+ var/datum/weather/W = V
+ if((z in W.impacted_z_levels) && W.area_type == active_area.type)
+ A = W
+ break
+ return A
\ No newline at end of file
diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm
index 3315cafb399..4e9380e2fed 100644
--- a/code/controllers/verbs.dm
+++ b/code/controllers/verbs.dm
@@ -94,7 +94,7 @@
debug_variables(SStimer)
feedback_add_details("admin_verb","DTimer")
if("Weather")
- debug_variables(weather_master)
+ debug_variables(SSweather)
feedback_add_details("admin_verb","DWeather")
if("Space")
debug_variables(space_manager)
diff --git a/code/datums/looping_sounds/weather.dm b/code/datums/looping_sounds/weather.dm
new file mode 100644
index 00000000000..d355bc59c14
--- /dev/null
+++ b/code/datums/looping_sounds/weather.dm
@@ -0,0 +1,47 @@
+/datum/looping_sound/active_outside_ashstorm
+ mid_sounds = list(
+ 'sound/weather/ashstorm/outside/active_mid1.ogg' = 1,
+ 'sound/weather/ashstorm/outside/active_mid1.ogg' = 1,
+ 'sound/weather/ashstorm/outside/active_mid1.ogg' = 1
+ )
+ mid_length = 80
+ start_sound = 'sound/weather/ashstorm/outside/active_start.ogg'
+ start_length = 130
+ end_sound = 'sound/weather/ashstorm/outside/active_end.ogg'
+ volume = 80
+
+/datum/looping_sound/active_inside_ashstorm
+ mid_sounds = list(
+ 'sound/weather/ashstorm/inside/active_mid1.ogg' = 1,
+ 'sound/weather/ashstorm/inside/active_mid2.ogg' = 1,
+ 'sound/weather/ashstorm/inside/active_mid3.ogg' = 1
+ )
+ mid_length = 80
+ start_sound = 'sound/weather/ashstorm/inside/active_start.ogg'
+ start_length = 130
+ end_sound = 'sound/weather/ashstorm/inside/active_end.ogg'
+ volume = 60
+
+/datum/looping_sound/weak_outside_ashstorm
+ mid_sounds = list(
+ 'sound/weather/ashstorm/outside/weak_mid1.ogg' = 1,
+ 'sound/weather/ashstorm/outside/weak_mid2.ogg' = 1,
+ 'sound/weather/ashstorm/outside/weak_mid3.ogg' = 1
+ )
+ mid_length = 80
+ start_sound = 'sound/weather/ashstorm/outside/weak_start.ogg'
+ start_length = 130
+ end_sound = 'sound/weather/ashstorm/outside/weak_end.ogg'
+ volume = 50
+
+/datum/looping_sound/weak_inside_ashstorm
+ mid_sounds = list(
+ 'sound/weather/ashstorm/inside/weak_mid1.ogg' = 1,
+ 'sound/weather/ashstorm/inside/weak_mid2.ogg' = 1,
+ 'sound/weather/ashstorm/inside/weak_mid3.ogg' = 1
+ )
+ mid_length = 80
+ start_sound = 'sound/weather/ashstorm/inside/weak_start.ogg'
+ start_length = 130
+ end_sound = 'sound/weather/ashstorm/inside/weak_end.ogg'
+ volume = 30
diff --git a/code/datums/weather/weather.dm b/code/datums/weather/weather.dm
index 320cc137806..7ee152648c2 100644
--- a/code/datums/weather/weather.dm
+++ b/code/datums/weather/weather.dm
@@ -1,10 +1,5 @@
//The effects of weather occur across an entire z-level. For instance, lavaland has periodic ash storms that scorch most unprotected creatures.
-#define STARTUP_STAGE 1
-#define MAIN_STAGE 2
-#define WIND_DOWN_STAGE 3
-#define END_STAGE 4
-
/datum/weather
var/name = "space wind"
var/desc = "Heavy gusts of wind blanket the area, periodically knocking down anyone caught in the open."
@@ -29,24 +24,25 @@
var/area_type = /area/space //Types of area to affect
var/list/impacted_areas = list() //Areas to be affected by the weather, calculated when the weather begins
- var/target_z = MAIN_STATION //The z-level to affect
var/list/protected_areas = list()//Areas that are protected and excluded from the affected areas.
+ var/impacted_z_levels // The list of z-levels that this weather is actively affecting
- var/overlay_layer = 10 //Since it's above everything else, this is the layer used by default. 2 is below mobs and walls if you need to use that.
+ var/overlay_layer = AREA_LAYER //Since it's above everything else, this is the layer used by default. TURF_LAYER is below mobs and walls if you need to use that.
var/aesthetic = FALSE //If the weather has no purpose other than looks
var/immunity_type = "storm" //Used by mobs to prevent them from being affected by the weather
var/stage = END_STAGE //The stage of the weather, from 1-4
- var/probability = FALSE //Percent chance to happen if there are other possible weathers on the z-level
+ // These are read by the weather subsystem and used to determine when and where to run the weather.
+ var/probability = 0 // Weight amongst other eligible weather. If zero, will never happen randomly.
+ var/target_trait = STATION_LEVEL // The z-level trait to affect when run randomly or when not overridden.
-/datum/weather/New()
+ var/barometer_predictable = FALSE
+ var/next_hit_time = 0 //For barometers to know when the next storm will hit
+
+/datum/weather/New(z_levels)
..()
- weather_master.existing_weather |= src
-
-/datum/weather/Destroy()
- weather_master.existing_weather -= src
- return ..()
+ impacted_z_levels = z_levels
/datum/weather/proc/telegraph()
if(stage == STARTUP_STAGE)
@@ -59,17 +55,18 @@
affectareas -= get_areas(V)
for(var/V in affectareas)
var/area/A = V
- if(is_on_level_name(A,target_z))
+ if(A.z in impacted_z_levels)
impacted_areas |= A
weather_duration = rand(weather_duration_lower, weather_duration_upper)
+ START_PROCESSING(SSweather, src)
update_areas()
- for(var/V in player_list)
- var/mob/M = V
- if(is_on_level_name(M,target_z))
+ for(var/M in player_list)
+ var/turf/mob_turf = get_turf(M)
+ if(mob_turf && (mob_turf.z in impacted_z_levels))
if(telegraph_message)
to_chat(M, telegraph_message)
if(telegraph_sound)
- M << sound(telegraph_sound)
+ SEND_SOUND(M, sound(telegraph_sound))
addtimer(CALLBACK(src, .proc/start), telegraph_duration)
/datum/weather/proc/start()
@@ -77,14 +74,13 @@
return
stage = MAIN_STAGE
update_areas()
- for(var/V in player_list)
- var/mob/M = V
- if(is_on_level_name(M,target_z))
+ for(var/M in player_list)
+ var/turf/mob_turf = get_turf(M)
+ if(mob_turf && (mob_turf.z in impacted_z_levels))
if(weather_message)
to_chat(M, weather_message)
if(weather_sound)
- M << sound(weather_sound)
- weather_master.processing_weather |= src
+ SEND_SOUND(M, sound(weather_sound))
addtimer(CALLBACK(src, .proc/wind_down), weather_duration)
/datum/weather/proc/wind_down()
@@ -92,24 +88,25 @@
return
stage = WIND_DOWN_STAGE
update_areas()
- for(var/V in player_list)
- var/mob/M = V
- if(is_on_level_name(M,target_z))
+ for(var/M in player_list)
+ var/turf/mob_turf = get_turf(M)
+ if(mob_turf && (mob_turf.z in impacted_z_levels))
if(end_message)
to_chat(M, end_message)
if(end_sound)
- M << sound(end_sound)
- weather_master.processing_weather -= src
+ SEND_SOUND(M, sound(end_sound))
addtimer(CALLBACK(src, .proc/end), end_duration)
/datum/weather/proc/end()
if(stage == END_STAGE)
- return
+ return 1
stage = END_STAGE
+ STOP_PROCESSING(SSweather, src)
update_areas()
-/datum/weather/proc/can_impact(mob/living/L) //Can this weather impact a mob?
- if(!is_on_level_name(L,target_z))
+/datum/weather/proc/can_weather_act(mob/living/L) //Can this weather impact a mob?
+ var/turf/mob_turf = get_turf(L)
+ if(mob_turf && !(mob_turf.z in impacted_z_levels))
return
if(immunity_type in L.weather_immunities)
return
@@ -117,7 +114,7 @@
return
return 1
-/datum/weather/proc/impact(mob/living/L) //What effect does this weather have on the hapless mob?
+/datum/weather/proc/weather_act(mob/living/L) //What effect does this weather have on the hapless mob?
return
/datum/weather/proc/update_areas()
@@ -136,8 +133,8 @@
N.icon_state = end_overlay
if(END_STAGE)
N.color = null
- N.icon_state = initial(N.icon_state)
+ N.icon_state = ""
N.icon = 'icons/turf/areas.dmi'
- N.layer = 10 //Just default back to normal area stuff since I assume setting a var is faster than initial
+ N.layer = AREA_LAYER //Just default back to normal area stuff since I assume setting a var is faster than initial
N.invisibility = INVISIBILITY_MAXIMUM
- N.opacity = 0
+ N.set_opacity(FALSE)
diff --git a/code/datums/weather/weather_types.dm b/code/datums/weather/weather_types.dm
deleted file mode 100644
index 1581938bd96..00000000000
--- a/code/datums/weather/weather_types.dm
+++ /dev/null
@@ -1,118 +0,0 @@
-//Different types of weather.
-
-/datum/weather/floor_is_lava //The Floor is Lava: Makes all turfs damage anyone on them unless they're standing on a solid object.
- name = "the floor is lava"
- desc = "The ground turns into surprisingly cool lava, lightly damaging anything on the floor."
-
- telegraph_message = "Waves of heat emanate from the ground..."
- telegraph_duration = 150
-
- weather_message = "The floor is lava! Get on top of something!"
- weather_duration_lower = 300
- weather_duration_upper = 600
- weather_overlay = "lava"
-
- end_message = "The ground cools and returns to its usual form."
- end_duration = 0
-
- area_type = /area
- target_z = MAIN_STATION
-
- overlay_layer = 2 //Covers floors only
- immunity_type = "lava"
-
-/datum/weather/floor_is_lava/impact(mob/living/L)
- for(var/obj/structure/O in L.loc)
- if(O.density)
- return
- if(L.loc.density)
- return
- if(!L.client) //Only sentient people are going along with it!
- return
- L.adjustFireLoss(3)
-
-/datum/weather/floor_is_lava/fake
- name = "fake lava"
- aesthetic = TRUE
-
-/datum/weather/advanced_darkness //Advanced Darkness: Restricts the vision of all affected mobs to a single tile in the cardinal directions.
- name = "advanced darkness"
- desc = "Everything in the area is effectively blinded, unable to see more than a foot or so around itself."
-
- telegraph_message = "The lights begin to dim... is the power going out?"
- telegraph_duration = 150
-
- weather_message = "This isn't your everyday darkness... this is advanced darkness!"
- weather_duration_lower = 300
- weather_duration_upper = 300
-
- end_message = "At last, the darkness recedes."
- end_duration = 0
-
- area_type = /area
- target_z = MAIN_STATION
-
-/datum/weather/advanced_darkness/update_areas()
- for(var/V in impacted_areas)
- var/area/A = V
- if(stage == MAIN_STAGE)
- A.invisibility = 0
- A.opacity = 1
- A.layer = overlay_layer
- A.icon = 'icons/effects/weather_effects.dmi'
- A.icon_state = "darkness"
- else
- A.invisibility = INVISIBILITY_MAXIMUM
- A.opacity = 0
-
-
-/datum/weather/ash_storm //Ash Storms: Common happenings on lavaland. Heavily obscures vision and deals heavy fire damage to anyone caught outside.
- name = "ash storm"
- desc = "An intense atmospheric storm lifts ash off of the planet's surface and billows it down across the area, dealing intense fire damage to the unprotected."
-
- telegraph_message = "An eerie moan rises on the wind. Sheets of burning ash blacken the horizon. Seek shelter."
- telegraph_duration = 300
- telegraph_sound = 'sound/lavaland/ash_storm_windup.ogg'
- telegraph_overlay = "light_ash"
-
- weather_message = "Smoldering clouds of scorching ash billow down around you! Get inside!"
- weather_duration_lower = 600
- weather_duration_upper = 1500
- weather_sound = 'sound/lavaland/ash_storm_start.ogg'
- weather_overlay = "ash_storm"
-
- end_message = "The shrieking wind whips away the last of the ash falls to its usual murmur. It should be safe to go outside now."
- end_duration = 300
- end_sound = 'sound/lavaland/ash_storm_end.ogg'
- end_overlay = "light_ash"
-
- area_type = /area/mine/dangerous
- target_z = MINING
-
- immunity_type = "ash"
-
- probability = 90
-
-/datum/weather/ash_storm/impact(mob/living/L)
- if(istype(L.loc, /obj/mecha))
- return
- if(ishuman(L))
- var/mob/living/carbon/human/H = L
- var/thermal_protection = H.get_thermal_protection()
- if(thermal_protection >= FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT)
- return
- L.adjustFireLoss(4)
-
-/datum/weather/ash_storm/emberfall //Emberfall: An ash storm passes by, resulting in harmless embers falling like snow. 10% to happen in place of an ash storm.
- name = "emberfall"
- desc = "A passing ash storm blankets the area in harmless embers."
-
- weather_message = "Gentle embers waft down around you like grotesque snow. The storm seems to have passed you by..."
- weather_sound = 'sound/lavaland/ash_storm_windup.ogg'
- weather_overlay = "light_ash"
-
- end_message = "The emberfall slows, stops. Another layer of hardened soot to the basalt beneath your feet."
-
- aesthetic = TRUE
-
- probability = 10
diff --git a/code/datums/weather/weather_types/ash_storm.dm b/code/datums/weather/weather_types/ash_storm.dm
new file mode 100644
index 00000000000..3f4c57c4196
--- /dev/null
+++ b/code/datums/weather/weather_types/ash_storm.dm
@@ -0,0 +1,108 @@
+//Ash storms happen frequently on lavaland. They heavily obscure vision, and cause high fire damage to anyone caught outside.
+/datum/weather/ash_storm
+ name = "ash storm"
+ desc = "An intense atmospheric storm lifts ash off of the planet's surface and billows it down across the area, dealing intense fire damage to the unprotected."
+
+ telegraph_message = "An eerie moan rises on the wind. Sheets of burning ash blacken the horizon. Seek shelter."
+ telegraph_duration = 300
+ telegraph_overlay = "light_ash"
+
+ weather_message = "Smoldering clouds of scorching ash billow down around you! Get inside!"
+ weather_duration_lower = 600
+ weather_duration_upper = 1200
+ weather_overlay = "ash_storm"
+
+ end_message = "The shrieking wind whips away the last of the ash and falls to its usual murmur. It should be safe to go outside now."
+ end_duration = 300
+ end_overlay = "light_ash"
+
+ area_type = /area/mine/dangerous // /area/lavaland/surface/outdoors
+ target_trait = ORE_LEVEL
+
+ immunity_type = "ash"
+
+// probability = 90
+
+ barometer_predictable = TRUE
+
+ var/datum/looping_sound/active_outside_ashstorm/sound_ao = new(list(), FALSE, TRUE)
+ var/datum/looping_sound/active_inside_ashstorm/sound_ai = new(list(), FALSE, TRUE)
+ var/datum/looping_sound/weak_outside_ashstorm/sound_wo = new(list(), FALSE, TRUE)
+ var/datum/looping_sound/weak_inside_ashstorm/sound_wi = new(list(), FALSE, TRUE)
+
+/datum/weather/ash_storm/telegraph()
+ . = ..()
+ var/list/inside_areas = list()
+ var/list/outside_areas = list()
+ var/list/eligible_areas = list()
+ for(var/z in impacted_z_levels)
+ eligible_areas += space_manager.areas_in_z["[z]"]
+ for(var/i in 1 to eligible_areas.len)
+ var/area/place = eligible_areas[i]
+ if(place.outdoors)
+ outside_areas += place
+ else
+ inside_areas += place
+ CHECK_TICK
+
+ sound_ao.output_atoms = outside_areas
+ sound_ai.output_atoms = inside_areas
+ sound_wo.output_atoms = outside_areas
+ sound_wi.output_atoms = inside_areas
+
+ sound_wo.start()
+ sound_wi.start()
+
+/datum/weather/ash_storm/start()
+ . = ..()
+ sound_wo.stop()
+ sound_wi.stop()
+
+ sound_ao.start()
+ sound_ai.start()
+
+/datum/weather/ash_storm/wind_down()
+ . = ..()
+ sound_ao.stop()
+ sound_ai.stop()
+
+ sound_wo.start()
+ sound_wi.start()
+
+/datum/weather/ash_storm/end()
+ . = ..()
+ sound_wo.stop()
+ sound_wi.stop()
+
+/datum/weather/ash_storm/proc/is_ash_immune(atom/L)
+ while(L && !isturf(L))
+ if(ismecha(L)) //Mechs are immune
+ return TRUE
+ if(ishuman(L)) //Are you immune?
+ var/mob/living/carbon/human/H = L
+ var/thermal_protection = H.get_thermal_protection()
+ if(thermal_protection >= FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT)
+ return TRUE
+ L = L.loc //Matryoshka check
+ return FALSE //RIP you
+
+/datum/weather/ash_storm/weather_act(mob/living/L)
+ if(is_ash_immune(L))
+ return
+ L.adjustFireLoss(4)
+
+
+//Emberfalls are the result of an ash storm passing by close to the playable area of lavaland. They have a 10% chance to trigger in place of an ash storm.
+/datum/weather/ash_storm/emberfall
+ name = "emberfall"
+ desc = "A passing ash storm blankets the area in harmless embers."
+
+ weather_message = "Gentle embers waft down around you like grotesque snow. The storm seems to have passed you by..."
+ weather_overlay = "light_ash"
+
+ end_message = "The emberfall slows, stops. Another layer of hardened soot to the basalt beneath your feet."
+ end_sound = null
+
+ aesthetic = TRUE
+
+// probability = 10
\ No newline at end of file
diff --git a/code/datums/weather/weather_types/floor_is_lava.dm b/code/datums/weather/weather_types/floor_is_lava.dm
new file mode 100644
index 00000000000..fe7391ec9f0
--- /dev/null
+++ b/code/datums/weather/weather_types/floor_is_lava.dm
@@ -0,0 +1,39 @@
+//Causes fire damage to anyone not standing on a dense object.
+/datum/weather/floor_is_lava
+ name = "the floor is lava"
+ desc = "The ground turns into surprisingly cool lava, lightly damaging anything on the floor."
+
+ telegraph_message = "You feel the ground beneath you getting hot. Waves of heat distort the air."
+ telegraph_duration = 150
+
+ weather_message = "The floor is lava! Get on top of something!"
+ weather_duration_lower = 300
+ weather_duration_upper = 600
+ weather_overlay = "lava"
+
+ end_message = "The ground cools and returns to its usual form."
+ end_duration = 0
+
+ area_type = /area
+ protected_areas = list(/area/space)
+ target_trait = STATION_LEVEL
+
+ overlay_layer = ABOVE_OPEN_TURF_LAYER //Covers floors only
+ immunity_type = "lava"
+
+
+/datum/weather/floor_is_lava/weather_act(mob/living/L)
+ if(issilicon(L))
+ return
+ for(var/obj/structure/O in L.loc)
+ if(O.density || O.buckled_mob && istype(O, /obj/structure/stool/bed))
+ return
+ if(L.loc.density)
+ return
+ if(!L.client) //Only sentient people are going along with it!
+ return
+ L.adjustFireLoss(3)
+
+/datum/weather/floor_is_lava/fake
+ name = "the floor is lava (fake)"
+ aesthetic = TRUE
\ No newline at end of file
diff --git a/code/datums/weather/weather_types/radiation_storm.dm b/code/datums/weather/weather_types/radiation_storm.dm
new file mode 100644
index 00000000000..acd155e7560
--- /dev/null
+++ b/code/datums/weather/weather_types/radiation_storm.dm
@@ -0,0 +1,61 @@
+//Radiation storms occur when the station passes through an irradiated area, and irradiate anyone not standing in protected areas (maintenance, emergency storage, etc.)
+/datum/weather/rad_storm
+ name = "radiation storm"
+ desc = "A cloud of intense radiation passes through the area dealing rad damage to those who are unprotected."
+
+ telegraph_duration = 400
+ telegraph_message = "The air begins to grow warm."
+
+ weather_message = "You feel waves of heat wash over you! Find shelter!"
+ weather_overlay = "ash_storm"
+ weather_duration_lower = 600
+ weather_duration_upper = 1500
+ weather_color = "green"
+ weather_sound = 'sound/misc/bloblarm.ogg'
+
+ end_duration = 100
+ end_message = "The air seems to be cooling off again."
+
+ area_type = /area
+ protected_areas = list(/area/maintenance, /area/turret_protected/ai_upload, /area/turret_protected/ai_upload_foyer,
+ /area/turret_protected/ai, /area/storage/emergency, /area/storage/emergency2, /area/crew_quarters/sleep, /area/security/brig, /area/shuttle)
+ target_trait = STATION_LEVEL
+
+ immunity_type = "rad"
+
+/datum/weather/rad_storm/telegraph()
+ ..()
+ status_alarm(TRUE)
+ make_maint_all_access()
+
+
+/datum/weather/rad_storm/weather_act(mob/living/L)
+ var/resist = L.getarmor(null, "rad")
+ if(prob(40))
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ if(!(RADIMMUNE in H.species.species_traits))
+ if(prob(max(0, 100 - resist)))
+ randmuti(H) // Applies bad mutation
+ if(prob(50))
+ if(prob(90))
+ randmutb(H)
+ else
+ randmutg(H)
+ domutcheck(H, null, 1)
+
+ L.apply_effect(20, IRRADIATE, resist)
+
+/datum/weather/rad_storm/end()
+ if(..())
+ return
+ priority_announcement.Announce("The radiation threat has passed. Please return to your workplaces.", "Anomaly Alert")
+ status_alarm(FALSE)
+ revoke_maint_all_access()
+
+/datum/weather/rad_storm/proc/status_alarm(active) //Makes the status displays show the radiation warning for those who missed the announcement.
+ if(active)
+ post_status("alert", "radiation")
+ else
+ post_status("blank")
+ post_status("shuttle")
\ No newline at end of file
diff --git a/code/datums/weather/weather_types/snow_storm.dm b/code/datums/weather/weather_types/snow_storm.dm
new file mode 100644
index 00000000000..39ad0e8fa5d
--- /dev/null
+++ b/code/datums/weather/weather_types/snow_storm.dm
@@ -0,0 +1,28 @@
+/datum/weather/snow_storm
+ name = "snow storm"
+ desc = "Harsh snowstorms roam the topside of this arctic planet, burying any area unfortunate enough to be in its path."
+ probability = 90
+
+ telegraph_message = "Drifting particles of snow begin to dust the surrounding area.."
+ telegraph_duration = 300
+ telegraph_overlay = "light_snow"
+
+ weather_message = "Harsh winds pick up as dense snow begins to fall from the sky! Seek shelter!"
+ weather_overlay = "snow_storm"
+ weather_duration_lower = 600
+ weather_duration_upper = 1500
+
+ end_duration = 100
+ end_message = "The snowfall dies down, it should be safe to go outside again."
+
+// area_type = /area/awaymission/snowdin/outside
+ target_trait = AWAY_LEVEL
+
+ immunity_type = "snow"
+
+ barometer_predictable = TRUE
+
+
+/datum/weather/snow_storm/weather_act(mob/living/L)
+ L.adjust_bodytemperature(-rand(5, 15))
+
diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm
index 90b45a19170..e331376a0dc 100644
--- a/code/game/area/Space Station 13 areas.dm
+++ b/code/game/area/Space Station 13 areas.dm
@@ -20,13 +20,12 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
var/atmosalm = ATMOS_ALARM_NONE
var/poweralm = 1
var/party = null
- var/radalert = 0
var/report_alerts = 1 // Should atmos alerts notify the AI/computers
level = null
name = "Space"
icon = 'icons/turf/areas.dmi'
icon_state = "unknown"
- layer = 10
+ layer = AREA_LAYER
luminosity = 0
mouse_opacity = 0
invisibility = INVISIBILITY_LIGHTING
@@ -141,9 +140,6 @@ var/list/ghostteleportlocs = list()
/area/space/readyalert()
return
-/area/space/radiation_alert()
- return
-
/area/space/partyalert()
return
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 8a9a108c7b3..44a9ae7e522 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -22,7 +22,7 @@
..()
icon_state = ""
- layer = 10
+ layer = AREA_LAYER
uid = ++global_uid
all_areas += src
map_name = name // Save the initial (the name set in the map) name of the area.
@@ -45,7 +45,24 @@
blend_mode = BLEND_MULTIPLY // Putting this in the constructor so that it stops the icons being screwed up in the map editor.
/area/Initialize()
- ..()
+ . = ..()
+
+ if(contents.len)
+ var/list/areas_in_z = space_manager.areas_in_z
+ var/z
+ for(var/i in 1 to contents.len)
+ var/atom/thing = contents[i]
+ if(!thing)
+ continue
+ z = thing.z
+ break
+ if(!z)
+ WARNING("No z found for [src]")
+ return
+ if(!areas_in_z["[z]"])
+ areas_in_z["[z]"] = list()
+ areas_in_z["[z]"] += src
+
return INITIALIZE_HINT_LATELOAD
/area/LateInitialize()
@@ -160,16 +177,6 @@
eject = 0
updateicon()
-/area/proc/radiation_alert()
- if(!radalert)
- radalert = 1
- updateicon()
-
-/area/proc/reset_radiation_alert()
- if(radalert)
- radalert = 0
- updateicon()
-
/area/proc/partyalert()
if(!party)
party = 1
@@ -183,11 +190,8 @@
updateicon()
/area/proc/updateicon()
- if(radalert) // always show the radiation alert, regardless of power
- icon_state = "radiation"
- invisibility = INVISIBILITY_LIGHTING
- else if((fire || eject || party) && (!requires_power||power_environ))//If it doesn't require power, can still activate this proc.
- if(fire && !radalert && !eject && !party)
+ if((fire || eject || party) && (!requires_power||power_environ))//If it doesn't require power, can still activate this proc.
+ if(fire && !eject && !party)
icon_state = "red"
else if(!fire && eject && !party)
icon_state = "red"
@@ -197,9 +201,15 @@
icon_state = "blue-red"
invisibility = INVISIBILITY_LIGHTING
else
- // new lighting behaviour with obj lights
- icon_state = null
- invisibility = INVISIBILITY_MAXIMUM
+ var/weather_icon
+ for(var/V in SSweather.processing)
+ var/datum/weather/W = V
+ if(W.stage != END_STAGE && (src in W.impacted_areas))
+ W.update_areas()
+ weather_icon = TRUE
+ if(!weather_icon)
+ icon_state = null
+ invisibility = INVISIBILITY_MAXIMUM
/area/space/updateicon()
icon_state = null
@@ -384,4 +394,4 @@
for(var/obj/machinery/door/airlock/temp_airlock in src)
temp_airlock.prison_open()
for(var/obj/machinery/door/window/temp_windoor in src)
- temp_windoor.open()
+ temp_windoor.open()
\ No newline at end of file
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index fa582362308..054d4d441a3 100644
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -528,7 +528,8 @@
if("alert")
status_signal.data["picture_state"] = data1
- frequency.post_signal(src, status_signal)
+ spawn(0)
+ frequency.post_signal(src, status_signal)
/obj/machinery/computer/communications/Destroy()
diff --git a/code/game/machinery/computer/pod.dm b/code/game/machinery/computer/pod.dm
index 98d14c8ac30..4cbf105c100 100644
--- a/code/game/machinery/computer/pod.dm
+++ b/code/game/machinery/computer/pod.dm
@@ -205,8 +205,8 @@
if(href_list["dstele"])
var/choices = list(0)
var/list/reachable_levels = levels_by_trait(REACHABLE)
- for(var/datum/space_level/S in reachable_levels)
- choices += S.zpos
+ for(var/z in reachable_levels)
+ choices += z
var/obj/machinery/computer/pod/deathsquad/D = src
var/input = input("Enter the destination Z-Level. The mechs will arrive from the East. Leave 0 if you don't want to set a specific ZLevel", "Mass Driver Controls", 0) in choices
D.teleporter_dest = input
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 2a8e155dd06..9912957c2bb 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -313,6 +313,9 @@ REAGENT SCANNER
throw_range = 7
materials = list(MAT_METAL=30, MAT_GLASS=20)
origin_tech = "magnets=1;engineering=1"
+ var/cooldown = FALSE
+ var/cooldown_time = 250
+ var/accuracy // 0 is the best accuracy.
/obj/item/analyzer/attack_self(mob/user as mob)
@@ -366,6 +369,69 @@ REAGENT SCANNER
src.add_fingerprint(user)
return
+/obj/item/analyzer/AltClick(mob/user) //Barometer output for measuring when the next storm happens
+ ..()
+
+ if(!user.incapacitated() && Adjacent(user))
+
+ if(cooldown)
+ to_chat(user, "[src]'s barometer function is prepraring itself.")
+ return
+
+ var/turf/T = get_turf(user)
+ if(!T)
+ return
+
+ playsound(src, 'sound/effects/pop.ogg', 100)
+ var/area/user_area = T.loc
+ var/datum/weather/ongoing_weather = null
+
+ if(!user_area.outdoors)
+ to_chat(user, "[src]'s barometer function won't work indoors!")
+ return
+
+ for(var/V in SSweather.processing)
+ var/datum/weather/W = V
+ if(W.barometer_predictable && (T.z in W.impacted_z_levels) && W.area_type == user_area.type && !(W.stage == END_STAGE))
+ ongoing_weather = W
+ break
+
+ if(ongoing_weather)
+ if((ongoing_weather.stage == MAIN_STAGE) || (ongoing_weather.stage == WIND_DOWN_STAGE))
+ to_chat(user, "[src]'s barometer function can't trace anything while the storm is [ongoing_weather.stage == MAIN_STAGE ? "already here!" : "winding down."]")
+ return
+
+ to_chat(user, "The next [ongoing_weather] will hit in [butchertime(ongoing_weather.next_hit_time - world.time)].")
+ if(ongoing_weather.aesthetic)
+ to_chat(user, "[src]'s barometer function says that the next storm will breeze on by.")
+ else
+ var/next_hit = SSweather.next_hit_by_zlevel["[T.z]"]
+ var/fixed = next_hit ? next_hit - world.time : -1
+ if(fixed < 0)
+ to_chat(user, "[src]'s barometer function was unable to trace any weather patterns.")
+ else
+ to_chat(user, "[src]'s barometer function says a storm will land in approximately [butchertime(fixed)].")
+ cooldown = TRUE
+ addtimer(CALLBACK(src,/obj/item/analyzer/proc/ping), cooldown_time)
+
+/obj/item/analyzer/proc/ping()
+ if(isliving(loc))
+ var/mob/living/L = loc
+ to_chat(L, "[src]'s barometer function is ready!")
+ playsound(src, 'sound/machines/click.ogg', 100)
+ cooldown = FALSE
+
+/obj/item/analyzer/proc/butchertime(amount)
+ if(!amount)
+ return
+ if(accuracy)
+ var/inaccurate = round(accuracy * (1 / 3))
+ if(prob(50))
+ amount -= inaccurate
+ if(prob(50))
+ amount += inaccurate
+ return DisplayTimeText(max(1, amount))
+
/obj/item/mass_spectrometer
desc = "A hand-held mass spectrometer which identifies trace chemicals in a blood sample. Inject sample with syringe."
name = "mass-spectrometer"
diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm
index 611ff1656f3..2831894e3ea 100644
--- a/code/game/turfs/space/transit.dm
+++ b/code/game/turfs/space/transit.dm
@@ -94,8 +94,7 @@
var/max = world.maxx-TRANSITIONEDGE
var/min = 1+TRANSITIONEDGE
- var/datum/space_level/dest = pick(levels_by_trait(REACHABLE))
- var/_z = dest.zpos //select a random space zlevel
+ var/_z = pick(levels_by_trait(REACHABLE)) //select a random space zlevel
//now select coordinates for a border turf
var/_x
diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm
index 5039146b1c3..fe487ae6431 100644
--- a/code/modules/admin/secrets.dm
+++ b/code/modules/admin/secrets.dm
@@ -80,7 +80,6 @@
Security Level - Delta
Create Weather
Weather - Ash Storm
- Weather - Advanced Darkness
"}
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 1bd231ba5a9..ece60118fa0 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -2727,48 +2727,6 @@
for(var/mob/M in player_list)
if(M.stat != 2)
M.show_message(text("The chilling wind suddenly stops..."), 1)
-/* if("shockwave")
- ok = 1
- to_chat(world, "ALERT: STATION STRESS CRITICAL")
- sleep(60)
- to_chat(world, "ALERT: STATION STRESS CRITICAL. TOLERABLE LEVELS EXCEEDED!")
- sleep(80)
- to_chat(world, "ALERT: STATION STRUCTURAL STRESS CRITICAL. SAFETY MECHANISMS FAILED!")
- sleep(40)
- for(var/mob/M in world)
- shake_camera(M, 400, 1)
- for(var/obj/structure/window/W in world)
- spawn(0)
- sleep(rand(10,400))
- W.ex_act(rand(2,1))
- for(var/obj/structure/grille/G in world)
- spawn(0)
- sleep(rand(20,400))
- G.ex_act(rand(2,1))
- for(var/obj/machinery/door/D in world)
- spawn(0)
- sleep(rand(20,400))
- D.ex_act(rand(2,1))
- for(var/turf/station/floor/Floor in world)
- spawn(0)
- sleep(rand(30,400))
- Floor.ex_act(rand(2,1))
- for(var/obj/structure/cable/Cable in world)
- spawn(0)
- sleep(rand(30,400))
- Cable.ex_act(rand(2,1))
- for(var/obj/structure/closet/Closet in world)
- spawn(0)
- sleep(rand(30,400))
- Closet.ex_act(rand(2,1))
- for(var/obj/machinery/Machinery in world)
- spawn(0)
- sleep(rand(30,400))
- Machinery.ex_act(rand(1,3))
- for(var/turf/station/wall/Wall in world)
- spawn(0)
- sleep(rand(30,400))
- Wall.ex_act(rand(2,1)) */
if("lightout")
feedback_inc("admin_secrets_fun_used",1)
feedback_add_details("admin_secrets_fun_used","LO")
@@ -2793,7 +2751,7 @@
var/sure = alert(usr, "Are you sure you want to do this?", "Confirmation", "Yes", "No")
if(sure == "No")
return
- weather_master.run_weather("the floor is lava")
+ SSweather.run_weather(/datum/weather/floor_is_lava)
message_admins("[key_name_admin(usr)] made the floor lava")
if("fakelava")
feedback_inc("admin_secrets_fun_used", 1)
@@ -2801,7 +2759,7 @@
var/sure = alert(usr, "Are you sure you want to do this?", "Confirmation", "Yes", "No")
if(sure == "No")
return
- weather_master.run_weather("fake lava")
+ SSweather.run_weather(/datum/weather/floor_is_lava/fake)
message_admins("[key_name_admin(usr)] made aesthetic lava on the floor")
if("weatherashstorm")
feedback_inc("admin_secrets_fun_used", 1)
@@ -2809,16 +2767,8 @@
var/sure = alert(usr, "Are you sure you want to do this?", "Confirmation", "Yes", "No")
if(sure == "No")
return
- weather_master.run_weather("ash storm")
+ SSweather.run_weather(/datum/weather/ash_storm)
message_admins("[key_name_admin(usr)] spawned an ash storm on the mining asteroid")
- if("weatherdarkness")
- feedback_inc("admin_secrets_fun_used", 1)
- feedback_add_details("admin_secrets_fun_used", "WD")
- var/sure = alert(usr, "Are you sure you want to do this?", "Confirmation", "Yes", "No")
- if(sure == "No")
- return
- weather_master.run_weather("advanced darkness")
- message_admins("[key_name_admin(usr)] made the station go through advanced darkness")
if("retardify")
feedback_inc("admin_secrets_fun_used",1)
feedback_add_details("admin_secrets_fun_used","RET")
diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm
index 0f2da54818c..4b822dd718e 100644
--- a/code/modules/events/radiation_storm.dm
+++ b/code/modules/events/radiation_storm.dm
@@ -1,70 +1,11 @@
-/datum/event/radiation_storm
- announceWhen = 1
- var/safe_zones = list(
- /area/maintenance,
- /area/crew_quarters/sleep,
- /area/security/brig,
- /area/shuttle,
- /area/vox_station,
- /area/syndicate_station
- )
-
+/datum/event/radiation_storm/setup()
+ startWhen = 3
+ endWhen = startWhen + 1
+ announceWhen = 1
/datum/event/radiation_storm/announce()
- // Don't do anything, we want to pack the announcement with the actual event
-
-/datum/event/radiation_storm/proc/is_safe_zone(var/area/A)
- for(var/szt in safe_zones)
- if(istype(A, szt))
- return 1
- return 0
+ priority_announcement.Announce("High levels of radiation detected near the station. Maintenance is best shielded from radiation.", "Anomaly Alert", 'sound/ai/radiation.ogg')
+ //sound not longer matches the text, but an audible warning is probably good
/datum/event/radiation_storm/start()
- spawn()
- event_announcement.Announce("High levels of radiation detected near the station. Please evacuate into one of the shielded maintenance tunnels.", "Anomaly Alert", new_sound = 'sound/AI/radiation.ogg')
-
- for(var/area/A in world)
- if(!is_station_level(A.z) || is_safe_zone(A))
- continue
- A.radiation_alert()
-
- make_maint_all_access()
-
- sleep(600)
-
- event_announcement.Announce("The station has entered the radiation belt. Please remain in a sheltered area until we have passed the radiation belt.", "Anomaly Alert")
-
- for(var/i = 0, i < 10, i++)
- for(var/mob/living/carbon/human/H in living_mob_list)
- var/armor = H.getarmor(type = "rad")
- if((RADIMMUNE in H.species.species_traits) || armor >= 100) // Leave radiation-immune species/fully rad armored players completely unaffected
- continue
- var/turf/T = get_turf(H)
- if(!T)
- continue
- if(!is_station_level(T.z) || is_safe_zone(T.loc))
- continue
-
- if(istype(H,/mob/living/carbon/human))
- H.apply_effect((rand(15,35)),IRRADIATE,0)
- if(prob(5))
- H.apply_effect((rand(40,70)),IRRADIATE,0)
- if(prob(75))
- randmutb(H) // Applies bad mutation
- domutcheck(H,null,1)
- else
- randmutg(H) // Applies good mutation
- domutcheck(H,null,1)
-
- sleep(100)
-
- event_announcement.Announce("The station has passed the radiation belt. Please report to medbay if you experience any unusual symptoms. Maintenance will lose all access again shortly.", "Anomaly Alert")
-
- for(var/area/A in world)
- if(!is_station_level(A.z) || is_safe_zone(A))
- continue
- A.reset_radiation_alert()
-
- sleep(600) // Want to give them time to get out of maintenance.
-
- revoke_maint_all_access()
+ SSweather.run_weather(/datum/weather/rad_storm)
\ No newline at end of file
diff --git a/code/modules/mining/lavaland/loot/legion_loot.dm b/code/modules/mining/lavaland/loot/legion_loot.dm
index 210710db4d9..f11d6162f55 100644
--- a/code/modules/mining/lavaland/loot/legion_loot.dm
+++ b/code/modules/mining/lavaland/loot/legion_loot.dm
@@ -5,7 +5,6 @@
item_state = "staffofstorms"
icon = 'icons/obj/guns/magic.dmi'
slot_flags = SLOT_BACK
- item_state = "staffofstorms"
w_class = WEIGHT_CLASS_BULKY
force = 25
damtype = BURN
@@ -19,34 +18,36 @@
return
var/area/user_area = get_area(user)
+ var/turf/user_turf = get_turf(user)
+ if(!user_area || !user_turf)
+ to_chat(user, "Something is preventing you from using the staff here.")
+ return
var/datum/weather/A
- var/z_level_name = space_manager.levels_by_name[user.z]
- for(var/V in weather_master.existing_weather)
+ for(var/V in SSweather.processing)
var/datum/weather/W = V
- if(W.target_z == z_level_name && W.area_type == user_area.type)
+ if((user_turf.z in W.impacted_z_levels) && W.area_type == user_area.type)
A = W
break
- if(A)
+ if(A)
if(A.stage != END_STAGE)
if(A.stage == WIND_DOWN_STAGE)
to_chat(user, "The storm is already ending! It would be a waste to use the staff now.")
return
user.visible_message("[user] holds [src] skywards as an orange beam travels into the sky!", \
"You hold [src] skyward, dispelling the storm!")
- playsound(user, 'sound/magic/Staff_Change.ogg', 200, 0)
+ playsound(user, 'sound/magic/staff_change.ogg', 200, 0)
A.wind_down()
return
else
- A = new storm_type
+ A = new storm_type(list(user_turf.z))
A.name = "staff storm"
A.area_type = user_area.type
- A.target_z = z_level_name
A.telegraph_duration = 100
A.end_duration = 100
user.visible_message("[user] holds [src] skywards as red lightning crackles into the sky!", \
"You hold [src] skyward, calling down a terrible storm!")
- playsound(user, 'sound/magic/Staff_Change.ogg', 200, 0)
+ playsound(user, 'sound/magic/staff_change.ogg', 200, 0)
A.telegraph()
storm_cooldown = world.time + 200
diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm
index ace8ab1b621..1cb1bc5f3b0 100644
--- a/code/modules/mob/status_procs.dm
+++ b/code/modules/mob/status_procs.dm
@@ -208,3 +208,7 @@
/mob/proc/AdjustWeakened()
return
+
+/mob/proc/adjust_bodytemperature(amount, min_temp = 0, max_temp = INFINITY)
+ if(bodytemperature > min_temp && bodytemperature < max_temp)
+ bodytemperature = Clamp(bodytemperature + amount, min_temp, max_temp)
\ No newline at end of file
diff --git a/code/modules/space_management/level_traits.dm b/code/modules/space_management/level_traits.dm
index ae5d6447aae..39b584df64d 100644
--- a/code/modules/space_management/level_traits.dm
+++ b/code/modules/space_management/level_traits.dm
@@ -1,62 +1,63 @@
/proc/is_level_reachable(z)
- return check_level_trait(z, REACHABLE)
+ return check_level_trait(z, REACHABLE)
/proc/is_station_level(z)
- return check_level_trait(z, STATION_LEVEL)
+ return check_level_trait(z, STATION_LEVEL)
/proc/is_station_contact(z)
- return check_level_trait(z, STATION_CONTACT)
+ return check_level_trait(z, STATION_CONTACT)
/proc/is_teleport_allowed(z)
- return !check_level_trait(z, BLOCK_TELEPORT)
+ return !check_level_trait(z, BLOCK_TELEPORT)
/proc/is_admin_level(z)
- return check_level_trait(z, ADMIN_LEVEL)
+ return check_level_trait(z, ADMIN_LEVEL)
/proc/is_away_level(z)
- return check_level_trait(z, AWAY_LEVEL)
+ return check_level_trait(z, AWAY_LEVEL)
/proc/is_mining_level(z)
- return check_level_trait(z, ORE_LEVEL)
+ return check_level_trait(z, ORE_LEVEL)
/proc/is_ai_allowed(z)
- return check_level_trait(z, AI_OK)
+ return check_level_trait(z, AI_OK)
/proc/level_blocks_magic(z)
- return check_level_trait(z, IMPEDES_MAGIC)
+ return check_level_trait(z, IMPEDES_MAGIC)
/proc/level_boosts_signal(z)
- return check_level_trait(z, BOOSTS_SIGNAL)
+ return check_level_trait(z, BOOSTS_SIGNAL)
// Used for the nuke disk, or for checking if players survived through xenos
/proc/is_secure_level(z)
- var/secure = check_level_trait(z, STATION_LEVEL)
- if(!secure)
- // This is to allow further admin levels later, other than centcomm
- secure = (z == level_name_to_num(CENTCOMM))
- return secure
+ var/secure = check_level_trait(z, STATION_LEVEL)
+ if(!secure)
+ // This is to allow further admin levels later, other than centcomm
+ secure = (z == level_name_to_num(CENTCOMM))
+ return secure
var/list/default_map_traits = MAP_TRANSITION_CONFIG
+
/proc/check_level_trait(z, trait)
- if(!z)
- return 0 // If you're nowhere, you have no traits
- var/list/trait_list
- if(space_manager.initialized)
- var/datum/space_level/S = space_manager.get_zlev(z)
- trait_list = S.flags
- else
- trait_list = default_map_traits[z]
- trait_list = trait_list["attributes"]
- return (trait in trait_list)
+ if(!z)
+ return 0 // If you're nowhere, you have no traits
+ var/list/trait_list
+ if(space_manager.initialized)
+ var/datum/space_level/S = space_manager.get_zlev(z)
+ trait_list = S.flags
+ else
+ trait_list = default_map_traits[z]
+ trait_list = trait_list["attributes"]
+ return (trait in trait_list)
/proc/levels_by_trait(trait)
- var/list/result = list()
- for(var/A in space_manager.z_list)
- var/datum/space_level/S = space_manager.z_list[A]
- if(trait in S.flags)
- result |= S
- return result
+ var/list/result = list()
+ for(var/A in space_manager.z_list)
+ var/datum/space_level/S = space_manager.z_list[A]
+ if(trait in S.flags)
+ result |= S.zpos
+ return result
/proc/level_name_to_num(name)
- var/datum/space_level/S = space_manager.get_zlev_by_name(name)
- return S.zpos
+ var/datum/space_level/S = space_manager.get_zlev_by_name(name)
+ return S.zpos
\ No newline at end of file
diff --git a/code/modules/space_management/zlevel_manager.dm b/code/modules/space_management/zlevel_manager.dm
index 087a70657ed..acb1cf5c0a0 100644
--- a/code/modules/space_management/zlevel_manager.dm
+++ b/code/modules/space_management/zlevel_manager.dm
@@ -12,6 +12,8 @@ var/global/datum/zlev_manager/space_manager = new
var/datum/spacewalk_grid/linkage_map
var/initialized = 0
+ var/list/areas_in_z = list()
+
// Populate our space level list
// and prepare space transitions
/datum/zlev_manager/proc/initialize()
@@ -166,4 +168,4 @@ var/global/datum/zlev_manager/space_manager = new
var/datum/space_level/heap/heap = z_list["[C.zpos]"]
if(!istype(heap))
throw EXCEPTION("Attempted to free chunk at invalid z-level ([C.x],[C.y],[C.zpos]) [C.width]x[C.height]")
- heap.free(C)
+ heap.free(C)
\ No newline at end of file
diff --git a/icons/effects/weather_effects.dmi b/icons/effects/weather_effects.dmi
index 215cf53556f..da1523706e2 100644
Binary files a/icons/effects/weather_effects.dmi and b/icons/effects/weather_effects.dmi differ
diff --git a/icons/obj/status_display.dmi b/icons/obj/status_display.dmi
index b131da89349..81ccc415de1 100644
Binary files a/icons/obj/status_display.dmi and b/icons/obj/status_display.dmi differ
diff --git a/paradise.dme b/paradise.dme
index 8764c0e8a63..095e5ad2a78 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -198,7 +198,6 @@
#include "code\controllers\Processes\obj.dm"
#include "code\controllers\Processes\shuttles.dm"
#include "code\controllers\Processes\ticker.dm"
-#include "code\controllers\Processes\weather.dm"
#include "code\controllers\ProcessScheduler\core\process.dm"
#include "code\controllers\ProcessScheduler\core\processScheduler.dm"
#include "code\controllers\subsystem\air.dm"
@@ -213,6 +212,7 @@
#include "code\controllers\subsystem\sun.dm"
#include "code\controllers\subsystem\throwing.dm"
#include "code\controllers\subsystem\timer.dm"
+#include "code\controllers\subsystem\weather.dm"
#include "code\controllers\subsystem\processing\processing.dm"
#include "code\datums\action.dm"
#include "code\datums\ai_law_sets.dm"
@@ -313,6 +313,7 @@
#include "code\datums\helper_datums\topic_input.dm"
#include "code\datums\looping_sounds\looping_sound.dm"
#include "code\datums\looping_sounds\machinery_sounds.dm"
+#include "code\datums\looping_sounds\weather.dm"
#include "code\datums\outfits\outfit.dm"
#include "code\datums\outfits\outfit_admin.dm"
#include "code\datums\ruins\space.dm"
@@ -352,7 +353,10 @@
#include "code\datums\status_effects\status_effect.dm"
#include "code\datums\vr\level.dm"
#include "code\datums\weather\weather.dm"
-#include "code\datums\weather\weather_types.dm"
+#include "code\datums\weather\weather_types\ash_storm.dm"
+#include "code\datums\weather\weather_types\floor_is_lava.dm"
+#include "code\datums\weather\weather_types\radiation_storm.dm"
+#include "code\datums\weather\weather_types\snow_storm.dm"
#include "code\datums\wires\airlock.dm"
#include "code\datums\wires\alarm.dm"
#include "code\datums\wires\apc.dm"
diff --git a/sound/lavaland/ash_storm_end.ogg b/sound/lavaland/ash_storm_end.ogg
deleted file mode 100644
index f9b01453dda..00000000000
Binary files a/sound/lavaland/ash_storm_end.ogg and /dev/null differ
diff --git a/sound/lavaland/ash_storm_start.ogg b/sound/lavaland/ash_storm_start.ogg
deleted file mode 100644
index 4b9bebffd08..00000000000
Binary files a/sound/lavaland/ash_storm_start.ogg and /dev/null differ
diff --git a/sound/lavaland/ash_storm_windup.ogg b/sound/lavaland/ash_storm_windup.ogg
deleted file mode 100644
index a9f0fa3270e..00000000000
Binary files a/sound/lavaland/ash_storm_windup.ogg and /dev/null differ
diff --git a/sound/weather/ashstorm/inside/active_end.ogg b/sound/weather/ashstorm/inside/active_end.ogg
new file mode 100644
index 00000000000..959bf5773eb
Binary files /dev/null and b/sound/weather/ashstorm/inside/active_end.ogg differ
diff --git a/sound/weather/ashstorm/inside/active_mid1.ogg b/sound/weather/ashstorm/inside/active_mid1.ogg
new file mode 100644
index 00000000000..95244cd2b7c
Binary files /dev/null and b/sound/weather/ashstorm/inside/active_mid1.ogg differ
diff --git a/sound/weather/ashstorm/inside/active_mid2.ogg b/sound/weather/ashstorm/inside/active_mid2.ogg
new file mode 100644
index 00000000000..a45584b9f31
Binary files /dev/null and b/sound/weather/ashstorm/inside/active_mid2.ogg differ
diff --git a/sound/weather/ashstorm/inside/active_mid3.ogg b/sound/weather/ashstorm/inside/active_mid3.ogg
new file mode 100644
index 00000000000..be2e672fa0e
Binary files /dev/null and b/sound/weather/ashstorm/inside/active_mid3.ogg differ
diff --git a/sound/weather/ashstorm/inside/active_start.ogg b/sound/weather/ashstorm/inside/active_start.ogg
new file mode 100644
index 00000000000..3efab12ef26
Binary files /dev/null and b/sound/weather/ashstorm/inside/active_start.ogg differ
diff --git a/sound/weather/ashstorm/inside/weak_end.ogg b/sound/weather/ashstorm/inside/weak_end.ogg
new file mode 100644
index 00000000000..416b75a9b84
Binary files /dev/null and b/sound/weather/ashstorm/inside/weak_end.ogg differ
diff --git a/sound/weather/ashstorm/inside/weak_mid1.ogg b/sound/weather/ashstorm/inside/weak_mid1.ogg
new file mode 100644
index 00000000000..d3211c6b5fc
Binary files /dev/null and b/sound/weather/ashstorm/inside/weak_mid1.ogg differ
diff --git a/sound/weather/ashstorm/inside/weak_mid2.ogg b/sound/weather/ashstorm/inside/weak_mid2.ogg
new file mode 100644
index 00000000000..b6491a7afb8
Binary files /dev/null and b/sound/weather/ashstorm/inside/weak_mid2.ogg differ
diff --git a/sound/weather/ashstorm/inside/weak_mid3.ogg b/sound/weather/ashstorm/inside/weak_mid3.ogg
new file mode 100644
index 00000000000..95238c72d40
Binary files /dev/null and b/sound/weather/ashstorm/inside/weak_mid3.ogg differ
diff --git a/sound/weather/ashstorm/inside/weak_start.ogg b/sound/weather/ashstorm/inside/weak_start.ogg
new file mode 100644
index 00000000000..59abf1937dc
Binary files /dev/null and b/sound/weather/ashstorm/inside/weak_start.ogg differ
diff --git a/sound/weather/ashstorm/outside/active_end.ogg b/sound/weather/ashstorm/outside/active_end.ogg
new file mode 100644
index 00000000000..95149d846cc
Binary files /dev/null and b/sound/weather/ashstorm/outside/active_end.ogg differ
diff --git a/sound/weather/ashstorm/outside/active_mid1.ogg b/sound/weather/ashstorm/outside/active_mid1.ogg
new file mode 100644
index 00000000000..189528ab569
Binary files /dev/null and b/sound/weather/ashstorm/outside/active_mid1.ogg differ
diff --git a/sound/weather/ashstorm/outside/active_mid2.ogg b/sound/weather/ashstorm/outside/active_mid2.ogg
new file mode 100644
index 00000000000..92317f2e0a7
Binary files /dev/null and b/sound/weather/ashstorm/outside/active_mid2.ogg differ
diff --git a/sound/weather/ashstorm/outside/active_mid3.ogg b/sound/weather/ashstorm/outside/active_mid3.ogg
new file mode 100644
index 00000000000..34846bfd42c
Binary files /dev/null and b/sound/weather/ashstorm/outside/active_mid3.ogg differ
diff --git a/sound/weather/ashstorm/outside/active_start.ogg b/sound/weather/ashstorm/outside/active_start.ogg
new file mode 100644
index 00000000000..8b3acf1a153
Binary files /dev/null and b/sound/weather/ashstorm/outside/active_start.ogg differ
diff --git a/sound/weather/ashstorm/outside/weak_end.ogg b/sound/weather/ashstorm/outside/weak_end.ogg
new file mode 100644
index 00000000000..55db2fc3565
Binary files /dev/null and b/sound/weather/ashstorm/outside/weak_end.ogg differ
diff --git a/sound/weather/ashstorm/outside/weak_mid1.ogg b/sound/weather/ashstorm/outside/weak_mid1.ogg
new file mode 100644
index 00000000000..56faa9ad26c
Binary files /dev/null and b/sound/weather/ashstorm/outside/weak_mid1.ogg differ
diff --git a/sound/weather/ashstorm/outside/weak_mid2.ogg b/sound/weather/ashstorm/outside/weak_mid2.ogg
new file mode 100644
index 00000000000..0c836ad220a
Binary files /dev/null and b/sound/weather/ashstorm/outside/weak_mid2.ogg differ
diff --git a/sound/weather/ashstorm/outside/weak_mid3.ogg b/sound/weather/ashstorm/outside/weak_mid3.ogg
new file mode 100644
index 00000000000..f2cbfb0f4b9
Binary files /dev/null and b/sound/weather/ashstorm/outside/weak_mid3.ogg differ
diff --git a/sound/weather/ashstorm/outside/weak_start.ogg b/sound/weather/ashstorm/outside/weak_start.ogg
new file mode 100644
index 00000000000..1ac59c36f05
Binary files /dev/null and b/sound/weather/ashstorm/outside/weak_start.ogg differ