diff --git a/code/controllers/subsystem/weather.dm b/code/controllers/subsystem/weather.dm index 7c220cf1c2..0d5a68f027 100644 --- a/code/controllers/subsystem/weather.dm +++ b/code/controllers/subsystem/weather.dm @@ -11,6 +11,7 @@ SUBSYSTEM_DEF(weather) 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 @@ -29,7 +30,9 @@ SUBSYSTEM_DEF(weather) var/datum/weather/W = pickweight(possible_weather) run_weather(W, list(text2num(z))) eligible_zlevels -= z - addtimer(CALLBACK(src, .proc/make_eligible, z, possible_weather), rand(3000, 6000) + initial(W.weather_duration_upper), TIMER_UNIQUE) //Around 5-10 minutes between weathers + 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)) @@ -68,3 +71,13 @@ SUBSYSTEM_DEF(weather) /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 diff --git a/code/datums/weather/weather.dm b/code/datums/weather/weather.dm index b26d5f45c8..9f4d8f891f 100644 --- a/code/datums/weather/weather.dm +++ b/code/datums/weather/weather.dm @@ -37,6 +37,9 @@ var/probability = 0 // Weight amongst other eligible weather. If zero, will never happen randomly. var/target_trait = ZTRAIT_STATION // The z-level trait to affect when run randomly or when not overridden. + var/barometer_predictable = FALSE + var/next_hit_time = 0 //For barometers to know when the next storm will hit + /datum/weather/New(z_levels) ..() impacted_z_levels = z_levels diff --git a/code/datums/weather/weather_types/acid_rain.dm b/code/datums/weather/weather_types/acid_rain.dm index 3b43e47815..93e5c2556e 100644 --- a/code/datums/weather/weather_types/acid_rain.dm +++ b/code/datums/weather/weather_types/acid_rain.dm @@ -22,6 +22,8 @@ immunity_type = "acid" // temp + barometer_predictable = TRUE + /datum/weather/acid_rain/weather_act(mob/living/L) var/resist = L.getarmor(null, "acid") diff --git a/code/datums/weather/weather_types/ash_storm.dm b/code/datums/weather/weather_types/ash_storm.dm index 79f0a963bd..2a00f51314 100644 --- a/code/datums/weather/weather_types/ash_storm.dm +++ b/code/datums/weather/weather_types/ash_storm.dm @@ -23,6 +23,8 @@ 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) diff --git a/code/datums/weather/weather_types/snow_storm.dm b/code/datums/weather/weather_types/snow_storm.dm index 0b2a1780cf..a8d627bbca 100644 --- a/code/datums/weather/weather_types/snow_storm.dm +++ b/code/datums/weather/weather_types/snow_storm.dm @@ -20,6 +20,8 @@ immunity_type = "snow" + barometer_predictable = TRUE + /datum/weather/snow_storm/weather_act(mob/living/L) L.bodytemperature -=(rand(5,15)) diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 3c778818a5..f5c14db8a8 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -334,7 +334,7 @@ GAS ANALYZER advanced = TRUE /obj/item/device/analyzer - desc = "A hand-held environmental scanner which reports current gas levels." + desc = "A hand-held environmental scanner which reports current gas levels. Alt-Click to use the built in barometer function." name = "analyzer" icon_state = "atmos" item_state = "analyzer" @@ -348,6 +348,9 @@ GAS ANALYZER throw_range = 7 materials = list(MAT_METAL=30, MAT_GLASS=20) grind_results = list("mercury" = 5, "iron" = 5, "silicon" = 5) + var/cooldown = FALSE + var/cooldown_time = 250 + var/accuracy // 0 is the best accuracy. /obj/item/device/analyzer/suicide_act(mob/living/carbon/user) user.visible_message("[user] begins to analyze [user.p_them()]self with [src]! The display shows that [user.p_theyre()] dead!") @@ -412,6 +415,70 @@ GAS ANALYZER to_chat(user, "[env_gases[id][GAS_META][META_GAS_NAME]]: [round(gas_concentration*100, 0.01)] %") to_chat(user, "Temperature: [round(environment.temperature-T0C)] °C") +/obj/item/device/analyzer/AltClick(mob/user) //Barometer output for measuring when the next storm happens + ..() + + if(user.canUseTopic(src)) + + 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 + 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] can't trace anything while the storm is [ongoing_weather.stage == MAIN_STAGE ? "already here!" : "winding down."]") + return + + var/time = butchertime((ongoing_weather.next_hit_time - world.time)/10) + to_chat(user, "The next [ongoing_weather] will hit in [round(time)] seconds.") + if(ongoing_weather.aesthetic) + to_chat(user, "[src] says that the next storm will breeze on by.") + else if(user_area.outdoors) + 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] was unable to trace any weather patterns.") + else + fixed = butchertime(round(fixed / 10)) + to_chat(user, "A storm will land in approximately [fixed] seconds.") + else + to_chat(user, "[src]'s barometer function won't work indoors!") + cooldown = TRUE + addtimer(src, /obj/item/device/analyzer/proc/ping, cooldown_time) + +/obj/item/device/analyzer/proc/ping() + if(isliving(loc)) + var/mob/living/L = loc + to_chat(L, "[src] is ready!") + playsound(src, 'sound/machines/click.ogg', 100) + cooldown = FALSE + +/obj/item/device/analyzer/proc/butchertime(amount) + if(!amount) + return + if(accuracy) + var/time = amount + var/inaccurate = round(accuracy*(1/3)) + if(prob(50)) + time -= inaccurate + if(prob(50)) + time += inaccurate + return time + else + return amount /obj/item/device/slime_scanner name = "slime scanner" diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index b8fb490a3f..2e7a9219aa 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ