mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-12 16:44:43 +01:00
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:
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user