diff --git a/code/controllers/Processes/weather.dm b/code/controllers/Processes/weather.dm new file mode 100644 index 00000000000..999c6c51dc5 --- /dev/null +++ b/code/controllers/Processes/weather.dm @@ -0,0 +1,52 @@ +//Used for all kinds of weather, ex. lavaland ash storms. +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 + weather_master = src + + 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(src, "make_z_eligible", rand(3000, 6000) + W.weather_duration_upper, TRUE, Z) //Around 5-10 minutes between weathers + +/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/datums/weather/weather.dm b/code/datums/weather/weather.dm new file mode 100644 index 00000000000..7a073edc902 --- /dev/null +++ b/code/datums/weather/weather.dm @@ -0,0 +1,134 @@ +//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." + + var/telegraph_message = "The wind begins to pick up." //The message displayed in chat to foreshadow the weather's beginning + var/telegraph_duration = 300 //In deciseconds, how long from the beginning of the telegraph until the weather begins + var/telegraph_sound //The sound file played to everyone on an affected z-level + var/telegraph_overlay //The overlay applied to all tiles on the z-level + + var/weather_message = "The wind begins to blow ferociously!" //Displayed in chat once the weather begins in earnest + var/weather_duration = 1200 //In deciseconds, how long the weather lasts once it begins + var/weather_duration_lower = 1200 //See above - this is the lowest possible duration + var/weather_duration_upper = 1500 //See above - this is the highest possible duration + var/weather_sound + var/weather_overlay + + var/end_message = "The wind relents its assault." //Displayed once the wather is over + var/end_duration = 300 //In deciseconds, how long the "wind-down" graphic will appear before vanishing entirely + var/end_sound + var/end_overlay + + 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 = ZLEVEL_STATION //The z-level to affect + + 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/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 + +/datum/weather/New() + ..() + weather_master.existing_weather |= src + +/datum/weather/Destroy() + weather_master.existing_weather -= src + return ..() + +/datum/weather/proc/telegraph() + if(stage == STARTUP_STAGE) + return + stage = STARTUP_STAGE + for(var/V in get_areas(area_type)) + var/area/A = V + if(A.z == target_z) + impacted_areas |= A + weather_duration = rand(weather_duration_lower, weather_duration_upper) + update_areas() + for(var/V in player_list) + var/mob/M = V + if(M.z == target_z) + if(telegraph_message) + to_chat(M, telegraph_message) + if(telegraph_sound) + M << sound(telegraph_sound) + addtimer(src, "start", telegraph_duration) + +/datum/weather/proc/start() + if(stage >= MAIN_STAGE) + return + stage = MAIN_STAGE + update_areas() + for(var/V in player_list) + var/mob/M = V + if(M.z == target_z) + if(weather_message) + to_chat(M, weather_message) + if(weather_sound) + M << sound(weather_sound) + weather_master.processing_weather |= src + addtimer(src, "wind_down", weather_duration) + +/datum/weather/proc/wind_down() + if(stage >= WIND_DOWN_STAGE) + return + stage = WIND_DOWN_STAGE + update_areas() + for(var/V in player_list) + var/mob/M = V + if(M.z == target_z) + if(end_message) + to_chat(M, end_message) + if(end_sound) + M << sound(end_sound) + weather_master.processing_weather -= src + addtimer(src, "end", end_duration) + +/datum/weather/proc/end() + if(stage == END_STAGE) + return + stage = END_STAGE + update_areas() + +/datum/weather/proc/can_impact(mob/living/L) //Can this weather impact a mob? + if(L.z != target_z) + return + if(immunity_type in L.weather_immunities) + return + if(!(get_area(L) in impacted_areas)) + return + return 1 + +/datum/weather/proc/impact(mob/living/L) //What effect does this weather have on the hapless mob? + return + +/datum/weather/proc/update_areas() + for(var/V in impacted_areas) + var/area/N = V + N.layer = overlay_layer + N.icon = 'icons/effects/weather_effects.dmi' + N.invisibility = 0 + switch(stage) + if(STARTUP_STAGE) + N.icon_state = telegraph_overlay + if(MAIN_STAGE) + N.icon_state = weather_overlay + if(WIND_DOWN_STAGE) + N.icon_state = end_overlay + if(END_STAGE) + N.icon_state = initial(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.invisibility = INVISIBILITY_MAXIMUM + N.opacity = 0 diff --git a/code/datums/weather/weather_types.dm b/code/datums/weather/weather_types.dm new file mode 100644 index 00000000000..07735e85968 --- /dev/null +++ b/code/datums/weather/weather_types.dm @@ -0,0 +1,118 @@ +//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 = ZLEVEL_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 = ZLEVEL_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 + target_z = ZLEVEL_ASTEROID + + 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/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 948e11c23bc..3992f97fd0b 100644 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -29,6 +29,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station layer = 10 luminosity = 0 mouse_opacity = 0 + invisibility = INVISIBILITY_LIGHTING var/lightswitch = 1 var/eject = null diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 89690e7d1c7..43540f347de 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -43,6 +43,8 @@ power_change() // all machines set to current power level, also updates lighting icon + blend_mode = BLEND_MULTIPLY // Putting this in the constructor so that it stops the icons being screwed up in the map editor. + /area/proc/get_cameras() var/list/cameras = list() for(var/obj/machinery/camera/C in src) @@ -187,29 +189,25 @@ /area/proc/updateicon() if(radalert) // always show the radiation alert, regardless of power icon_state = "radiation" - blend_mode = BLEND_MULTIPLY + 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) icon_state = "red" - blend_mode = BLEND_MULTIPLY - /*else if(atmosalm && !fire && !eject && !party) - icon_state = "bluenew"*/ else if(!fire && eject && !party) icon_state = "red" - blend_mode = BLEND_MULTIPLY else if(party && !fire && !eject) icon_state = "party" - blend_mode = BLEND_MULTIPLY else icon_state = "blue-red" - blend_mode = BLEND_MULTIPLY + invisibility = INVISIBILITY_LIGHTING else // new lighting behaviour with obj lights icon_state = null - blend_mode = BLEND_DEFAULT + invisibility = INVISIBILITY_MAXIMUM /area/space/updateicon() icon_state = null + invisibility = INVISIBILITY_MAXIMUM /* @@ -242,8 +240,7 @@ /area/proc/power_change() for(var/obj/machinery/M in src) // for each machine in the area M.power_change() // reverify power status (to update icons etc.) - if(fire || eject || party) - updateicon() + updateicon() /area/proc/usage(var/chan) var/used = 0 diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm index 30817dd94d5..e2b6ab56d62 100644 --- a/code/modules/admin/secrets.dm +++ b/code/modules/admin/secrets.dm @@ -83,6 +83,9 @@ Security Level - Gamma   Security Level - Epsilon   Security Level - Delta
+ Create Weather
+ Weather - Ash Storm   + Weather - Advanced Darkness  
"} @@ -104,6 +107,7 @@ Dodgeball (TDM)!
Round-enders
The floor is lava! (DANGEROUS: extremely lame)
+ The floor is fake-lava! (non-harmful)
Turn all humans into monkeys
Make all items look like guns
Warp all Players to Prison
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 67d6bf6f49e..a7fc809aa88 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -2548,60 +2548,37 @@ L.fix() message_admins("[key_name_admin(usr)] fixed all lights", 1) if("floorlava") - if(floorIsLava) - to_chat(usr, "The floor is lava already.") + feedback_inc("admin_secrets_fun_used", 1) + feedback_add_details("admin_secrets_fun_used", "LF") + var/sure = alert(usr, "Are you sure you want to do this?", "Confirmation", "Yes", "No") + if(sure == "No") return - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","LF") - - //Options - var/length = input(usr, "How long will the lava last? (in seconds)", "Length", 180) as num - length = min(abs(length), 1200) - - var/damage = input(usr, "How deadly will the lava be?", "Damage", 2) as num - damage = min(abs(damage), 100) - - var/sure = alert(usr, "Are you sure you want to do this?", "Confirmation", "YES!", "Nah") - if(sure == "Nah") + weather_master.run_weather("the floor is lava") + message_admins("[key_name_admin(usr)] made the floor lava") + if("fakelava") + feedback_inc("admin_secrets_fun_used", 1) + feedback_add_details("admin_secrets_fun_used", "LZ") + var/sure = alert(usr, "Are you sure you want to do this?", "Confirmation", "Yes", "No") + if(sure == "No") return - floorIsLava = 1 - - message_admins("[key_name_admin(usr)] made the floor LAVA! It'll last [length] seconds and it will deal [damage] damage to everyone.", 1) - - for(var/turf/simulated/floor/F in world) - if((F.z in config.station_levels)) - F.name = "lava" - F.desc = "The floor is LAVA!" - F.overlays += "lava" - F.lava = 1 - - spawn(0) - for(var/i = i, i < length, i++) // 180 = 3 minutes - if(damage) - for(var/mob/living/carbon/L in living_mob_list) - if(istype(L.loc, /turf/simulated/floor)) // Are they on LAVA?! - var/turf/simulated/floor/F = L.loc - if(F.lava) - var/safe = 0 - 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! - safe = 1 - break - if(!safe) - L.adjustFireLoss(damage) - - - sleep(10) - - for(var/turf/simulated/floor/F in world) // Reset everything. - if((F.z in config.station_levels)) - F.name = initial(F.name) - F.desc = initial(F.desc) - F.overlays.Cut() - F.lava = 0 - F.update_icon() - floorIsLava = 0 - return + weather_master.run_weather("fake lava") + message_admins("[key_name_admin(usr)] made aesthetic lava on the floor") + if("weatherashstorm") + feedback_inc("admin_secrets_fun_used", 1) + feedback_add_details("admin_secrets_fun_used", "WA") + 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") + 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/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 28e39b53f6e..a13f7d31150 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -490,6 +490,16 @@ return if(RESIST_HEAT in mutations) return + var/thermal_protection = get_thermal_protection() + + if(thermal_protection >= FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT) + return + if(thermal_protection >= FIRE_SUIT_MAX_TEMP_PROTECT) + bodytemperature += 11 + else + bodytemperature += BODYTEMP_HEATING_MAX + +/mob/living/carbon/human/proc/get_thermal_protection() var/thermal_protection = 0 //Simple check to estimate how protected we are against multiple temperatures if(wear_suit) if(wear_suit.max_heat_protection_temperature >= FIRE_SUIT_MAX_TEMP_PROTECT) @@ -498,34 +508,9 @@ if(head.max_heat_protection_temperature >= FIRE_HELM_MAX_TEMP_PROTECT) thermal_protection += (head.max_heat_protection_temperature*THERMAL_PROTECTION_HEAD) thermal_protection = round(thermal_protection) - if(thermal_protection >= FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT) - return - if(thermal_protection >= FIRE_SUIT_MAX_TEMP_PROTECT) - bodytemperature += 11 - return - else - bodytemperature += BODYTEMP_HEATING_MAX - return -//END FIRE CODE + return thermal_protection - /* -/mob/living/carbon/human/proc/adjust_body_temperature(current, loc_temp, boost) - var/temperature = current - var/difference = abs(current-loc_temp) //get difference - var/increments// = difference/10 //find how many increments apart they are - if(difference > 50) - increments = difference/5 - else - increments = difference/10 - var/change = increments*boost // Get the amount to change by (x per increment) - var/temp_change - if(current < loc_temp) - temperature = min(loc_temp, temperature+change) - else if(current > loc_temp) - temperature = max(loc_temp, temperature-change) - temp_change = (temperature - current) - return temp_change - */ +//END FIRE CODE /mob/living/carbon/human/proc/stabilize_temperature_from_calories() if(bodytemperature <= species.cold_level_1) //260.15 is 310.15 - 50, the temperature where you start to feel effects. diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index d4e6d613d9c..6bd7c162308 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -54,6 +54,8 @@ var/list/butcher_results = null + var/list/weather_immunities = list() + var/list/surgeries = list() //a list of surgery datums. generally empty, they're added when the player wants them. var/gene_stability = DEFAULT_GENE_STABILITY diff --git a/goon/browserassets/css/browserOutput.css b/goon/browserassets/css/browserOutput.css index 9e875544250..3829cbd3f48 100644 --- a/goon/browserassets/css/browserOutput.css +++ b/goon/browserassets/css/browserOutput.css @@ -273,6 +273,7 @@ h1.alert, h2.alert {color: #000000;} .passive {color: #660000;} .warning {color: #ff0000; font-style: italic;} +.boldwarning {color: #ff0000; font-style: italic; font-weight: bold} .danger {color: #ff0000; font-weight: bold;} .userdanger {color: #ff0000; font-weight: bold; font-size: 120%;} .biggerdanger {color: #ff0000; font-weight: bold; font-size: 150%;} diff --git a/icons/effects/weather_effects.dmi b/icons/effects/weather_effects.dmi new file mode 100644 index 00000000000..215cf53556f Binary files /dev/null and b/icons/effects/weather_effects.dmi differ diff --git a/paradise.dme b/paradise.dme index 2e8a0d0200b..e2eb20894e0 100644 --- a/paradise.dme +++ b/paradise.dme @@ -180,6 +180,7 @@ #include "code\controllers\Processes\ticker.dm" #include "code\controllers\Processes\timer.dm" #include "code\controllers\Processes\vote.dm" +#include "code\controllers\Processes\weather.dm" #include "code\controllers\ProcessScheduler\core\process.dm" #include "code\controllers\ProcessScheduler\core\processScheduler.dm" #include "code\datums\ai_law_sets.dm" @@ -298,6 +299,8 @@ #include "code\datums\spells\trigger.dm" #include "code\datums\spells\turf_teleport.dm" #include "code\datums\spells\wizard.dm" +#include "code\datums\weather\weather.dm" +#include "code\datums\weather\weather_types.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 new file mode 100644 index 00000000000..f9b01453dda Binary files /dev/null and b/sound/lavaland/ash_storm_end.ogg differ diff --git a/sound/lavaland/ash_storm_start.ogg b/sound/lavaland/ash_storm_start.ogg new file mode 100644 index 00000000000..4b9bebffd08 Binary files /dev/null and b/sound/lavaland/ash_storm_start.ogg differ diff --git a/sound/lavaland/ash_storm_windup.ogg b/sound/lavaland/ash_storm_windup.ogg new file mode 100644 index 00000000000..a9f0fa3270e Binary files /dev/null and b/sound/lavaland/ash_storm_windup.ogg differ