Refactors weather into a subsystem (#19003)

Weather has been refactored from a weather control machine on the lavaland z-level into a subsystem. All existing weather has been changed to accommodate this change, and their code has been optimized by using addtimer() instead of sleep().

The new subsystem also supports adding weather to any z-level; for instance, if you made a weather called /datum/weather/rain_storm and made it target z-level 3 with a 100% probability, the rain storm would occur as much as possible with 5-10 minute intermissions. These intermissions take into account the weather's duration.
This commit is contained in:
Xhuis
2016-07-03 21:55:36 -04:00
committed by oranges
parent 1aa7a312c1
commit 2ab3f554d9
11 changed files with 322 additions and 275 deletions
+1 -2
View File
@@ -427,8 +427,7 @@
L.fix()
if("floorlava")
var/datum/weather/floor_is_lava/storm = new /datum/weather/floor_is_lava
storm.weather_start_up()
SSweather.run_weather("the floor is lava")
if("virus")
if(!check_rights(R_FUN))
@@ -13,5 +13,4 @@
/datum/round_event/wizard/darkness/start()
if(!started)
started = TRUE
var/datum/weather/advanced_darkness/darkness = new
darkness.weather_start_up()
SSweather.run_weather("advanced darkness")
+1 -2
View File
@@ -12,5 +12,4 @@
/datum/round_event/wizard/lava/start()
if(!started)
started = TRUE
var/datum/weather/floor_is_lava/LAVA = new /datum/weather/floor_is_lava
LAVA.weather_start_up()
SSweather.run_weather("the floor is lava")
-110
View File
@@ -1,110 +0,0 @@
#define STARTUP_STAGE 1
#define MAIN_STAGE 2
#define WIND_DOWN_STAGE 3
#define END_STAGE 4
/datum/weather
var/name = "storm"
var/start_up_time = 300 //30 seconds
var/start_up_message = "The wind begins to pick up."
var/start_up_sound
var/duration = 120 //2 minutes
var/duration_lower = 120
var/duration_upper = 120
var/duration_sound
var/duration_message = "A storm has started!"
var/wind_down = 300 // 30 seconds
var/wind_down_message = "The storm is passing."
var/wind_down_sound
var/target_z = 1
var/exclude_walls = TRUE
var/area_type = /area/space
var/stage = STARTUP_STAGE
var/start_up_overlay = "lava"
var/duration_overlay = "lava"
var/overlay_layer = AREA_LAYER //This is the default area layer, and above everything else. TURF_LAYER is floors/below walls and mobs.
var/purely_aesthetic = FALSE //If we just want gentle rain that doesn't hurt people
var/list/impacted_areas = list()
var/immunity_type = "storm"
/datum/weather/proc/weather_start_up()
for(var/area/N in get_areas(area_type))
if(N.z == target_z)
impacted_areas += N
duration = rand(duration_lower,duration_upper)
update_areas()
for(var/mob/M in player_list)
if(M.z == target_z)
M << "<span class='warning'><B>[start_up_message]</B></span>"
if(start_up_sound)
M << start_up_sound
sleep(start_up_time)
if(src && stage != MAIN_STAGE)
stage = MAIN_STAGE
weather_main()
/datum/weather/proc/weather_main()
update_areas()
for(var/mob/M in player_list)
if(M.z == target_z)
M << "<span class='userdanger'><i>[duration_message]</i></span>"
if(duration_sound)
M << duration_sound
if(purely_aesthetic)
sleep(duration*10)
else //Storm effects
for(var/i in 1 to duration-1)
for(var/mob/living/L in living_mob_list)
var/area/storm_area = get_area(L)
if(storm_area in impacted_areas)
storm_act(L)
sleep(10)
if(src && stage != WIND_DOWN_STAGE)
stage = WIND_DOWN_STAGE
weather_wind_down()
/datum/weather/proc/weather_wind_down()
update_areas()
for(var/mob/M in player_list)
if(M.z == target_z)
M << "<span class='danger'><B>[wind_down_message]</B></span>"
if(wind_down_sound)
M << wind_down_sound
sleep(wind_down)
if(src && stage != END_STAGE)
stage = END_STAGE
update_areas()
/datum/weather/proc/storm_act(mob/living/L)
if(immunity_type in L.weather_immunities)
return
/datum/weather/proc/update_areas()
for(var/area/N in impacted_areas)
N.layer = overlay_layer
N.icon = 'icons/effects/weather_effects.dmi'
N.invisibility = 0
switch(stage)
if(STARTUP_STAGE)
N.icon_state = start_up_overlay
if(MAIN_STAGE)
N.icon_state = duration_overlay
if(WIND_DOWN_STAGE)
N.icon_state = start_up_overlay
if(END_STAGE)
N.icon_state = initial(N.icon_state)
N.icon = 'icons/turf/areas.dmi'
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
@@ -1,108 +0,0 @@
///The floor is lava
/datum/weather/floor_is_lava
name = "floor is lava"
start_up_time = 30 //3 seconds
start_up_message = "The ground begins to bubble."
duration_lower = 45
duration_upper = 60 //1 minute
duration_message = "The floor is lava!"
wind_down = 30// 3 seconds
wind_down_message = "The ground begins to cool."
target_z = 1
exclude_walls = TRUE
area_type = /area
start_up_overlay = "lava"
duration_overlay = "lava"
overlay_layer = ABOVE_OPEN_TURF_LAYER //Covers floors only
immunity_type = "lava"
/datum/weather/floor_is_lava/storm_act(mob/living/L)
if(immunity_type in L.weather_immunities)
return
var/turf/F = get_turf(L)
for(var/obj/structure/O in F.contents)
if(O.level > F.level && !istype(O, /obj/structure/window)) // Something to stand on and it isn't under the floor!
return
L.adjustFireLoss(3)
/datum/weather/advanced_darkness
name = "advanced darkness"
start_up_time = 100 //10 seconds
start_up_message = "The lights begin to dim... is power going out?"
duration_lower = 45
duration_upper = 60 //1 minute
duration_message = "This isn't average everyday darkness... this is advanced darkness!"
wind_down = 100 // 10 seconds
wind_down_message = "The darkness recedes."
purely_aesthetic = TRUE
target_z = 1
exclude_walls = TRUE
area_type = /area
start_up_overlay = ""
duration_overlay = ""
overlay_layer = AREA_LAYER
/datum/weather/advanced_darkness/update_areas()
for(var/area/A in impacted_areas)
if(stage == MAIN_STAGE)
A.invisibility = 0
A.opacity = 1
A.layer = overlay_layer
A.icon = 'icons/effects/weather_effects.dmi'
A.icon_state = start_up_overlay
else
A.invisibility = INVISIBILITY_MAXIMUM
A.opacity = 0
//Ash storms
/datum/weather/ash_storm
name = "ash storm"
start_up_time = 300 //30 seconds
start_up_message = "An eerie moan rises on the wind. Sheets of burning ash blacken the horizon. Seek shelter."
start_up_sound = 'sound/lavaland/ash_storm_windup.ogg'
duration_lower = 60 //1 minute
duration_upper = 150 //2.5 minutes
duration_message = "Smoldering clouds of scorching ash billow down around you! Get inside!"
duration_sound = 'sound/lavaland/ash_storm_start.ogg'
wind_down = 300 // 30 seconds
wind_down_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."
wind_down_sound = 'sound/lavaland/ash_storm_end.ogg'
target_z = ZLEVEL_LAVALAND
area_type = /area/lavaland/surface/outdoors
start_up_overlay = "light_ash"
duration_overlay = "ash_storm"
overlay_layer = AREA_LAYER
immunity_type = "ash"
/datum/weather/ash_storm/false_alarm //No storm, just light ember fall
purely_aesthetic = TRUE
duration_overlay = "light_ash"
duration_message = "<span class='notice'>Gentle ashfall surrounds you like grotesque snow. The storm seems to have passed you by.</span>"
wind_down_message = "The ashfall quietly slows, then stops. Another layer of hardened soot to the volcanic rock beneath you."
/datum/weather/ash_storm/storm_act(mob/living/L)
if(immunity_type in L.weather_immunities)
return
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)
@@ -118,37 +118,38 @@
force = 25
damtype = BURN
hitsound = 'sound/weapons/sear.ogg'
var/obj/machinery/lavaland_controller/linked_machine
var/storm_cooldown = 0
/obj/item/weapon/staff_of_storms/attack_self(mob/user)
if(storm_cooldown > world.time)
user << "<span class='warning'>The staff is still recharging!</span>"
return
if(user.z != ZLEVEL_LAVALAND)
user << "<span class='warning'>You can't seem to control the weather here!</span>"
return
if(!linked_machine || linked_machine.z != user.z)
for(var/obj/machinery/lavaland_controller/controller in machines)
if(controller.z == user.z)
linked_machine = controller
break
var/datum/weather/ash_storm/A
for(var/V in SSweather.existing_weather)
var/datum/weather/W = V
if(W.name == "ash storm")
A = W
break
if(!A)
user << "<span class='warning'>How odd! The planet seems to have lost its atmosphere!</span>"
return
if(linked_machine && linked_machine.ongoing_weather)
if(linked_machine.ongoing_weather.stage == WIND_DOWN_STAGE || linked_machine.ongoing_weather.stage == END_STAGE)
user << "<span class='warning'>The storm is already ending. It would be a waste to use the staff now.</span>"
if(A.stage != END_STAGE)
if(A.stage == WIND_DOWN_STAGE)
user << "<span class='warning'>The storm is already ending! It would be a waste to use the staff now.</span>"
return
user.visible_message("<span class='warning'>[user] holds [src] skywards, causing its orb to flare!</span>", \
"<span class='notice'>With an appropriately dramatic flourish, you dispel the storm!</span>")
playsound(get_turf(src),'sound/magic/Staff_Change.ogg', 200, 0)
storm_cooldown = world.time + 600
linked_machine.ongoing_weather.stage = WIND_DOWN_STAGE
linked_machine.ongoing_weather.weather_wind_down()
else if (linked_machine && !linked_machine.ongoing_weather)
user.visible_message("<span class='warning'>[user] holds [src] skywards, causing its orb to flare!</span>", \
"<span class='danger'>You lift your staff skywards, calling down a terrible storm!</span>")
playsound(get_turf(src),'sound/magic/Staff_Chaos.ogg', 200, 0)
storm_cooldown = world.time + 600
linked_machine.weather_cooldown = 0
user.visible_message("<span class='warning'>[user] holds [src] skywards as an orange beam travels into the sky!</span>", \
"<span class='notice'>You hold [src] skyward, dispelling the ash storm!</span>")
playsound(user, 'sound/magic/Staff_Change.ogg', 200, 0)
A.wind_down()
else
user << "You can't seem to control the weather here."
user.visible_message("<span class='warning'>[user] holds [src] skywards as red lightning crackles into the sky!</span>", \
"<span class='notice'>You hold [src] skyward, calling down a terrible storm!</span>")
playsound(user, 'sound/magic/Staff_Chaos.ogg', 200, 0)
A.telegraph()
storm_cooldown = world.time + 600
+3 -25
View File
@@ -1,32 +1,10 @@
//If you're looking for spawners like ash walker eggs, check ghost_role_spawners.dm
/obj/machinery/lavaland_controller
name = "weather control machine"
desc = "Controls the weather."
name = "weather machine"
desc = "Controls the weather... when it's on, at any rate. A sticky note on the side proclaims \"DISABLED IN FAVOR OF AN ACTUAL ATMOSPHERE\"."
icon = 'icons/obj/machines/telecomms.dmi'
icon_state = "processor"
var/datum/weather/ongoing_weather = FALSE
var/weather_cooldown = 0
/obj/machinery/lavaland_controller/process()
if(ongoing_weather || weather_cooldown > world.time)
return
weather_cooldown = world.time + rand(3500, 6500)
var/datum/weather/ash_storm/LAVA
if(prob(10)) //10% chance for the ash storm to miss the area entirely
LAVA = new /datum/weather/ash_storm/false_alarm
else
LAVA = new /datum/weather/ash_storm
ongoing_weather = LAVA
LAVA.weather_start_up()
ongoing_weather = null
/obj/machinery/lavaland_controller/Destroy(force)
if(force)
. = ..()
else
return QDEL_HINT_LETMELIVE
icon_state = "processor_off"
/obj/structure/fans/tiny/invisible //For blocking air in ruin doorways
invisibility = INVISIBILITY_ABSTRACT