Lavaland weather types: Dying is Fun edition (#28600)

* ddsadsa

ddsadsa

* beginning

* more progress

* oops saved

* radar workin now

* bugfixing and tweaks

* working on volcano

* tweaking

* ill figure this out later

* testing still

* MORE testing

* gunna cry

* PROGRESS!!!

* volcano DONE

* starting the acid rain

* acid rain code complete

* starting windstorm

* more bugfixing...

* its finished! need to bugtest

* bugfixing

* bugfixing

* forgot prob values

* spacing fix for linter

* linter fix

* undefining things

* Update code/datums/weather/weather_types/lavaland_weather.dm

Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/datums/weather/weather_types/lavaland_weather.dm

Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/game/machinery/radar.dm

Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/datums/weather/weather_types/lavaland_weather.dm

Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/game/machinery/radar.dm

Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/game/machinery/radar.dm

Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* misc fixes/changes

* updated the doppler tower

* small tweaks

* still trying to get pods to work

* better support for sound transition to newly placed shelters

* minor fixes

* this didnt take oops

* nudged the probabilities

* deconflicting

* Update code/datums/weather/weather_types/lavaland_weather.dm

Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/game/machinery/radar.dm

Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/game/machinery/radar.dm

Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/game/machinery/radar.dm

Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* applied requested fixes

* master update

* updates

* this should be here

* Apply suggestions from code review

Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* requested fixes

* sound tweaks

* remove debug message

* turned down ash storm sound

* fix gulag weather and attempt to fix sound overlap

* blackbox weather and title-case ash storms

* change up probabilities and bump acid rain melt chance

* another title case

* starting on issues

* revert some changes

* tiny tweak

* reworked acid rain a bit

* small tweaks to sleepers

* moderate again

* revert

* ups the rocks

* bug fixes

---------

Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>
Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
This commit is contained in:
Kyani
2025-04-18 20:18:38 +00:00
committed by GitHub
co-authored by warriorstar-orion
parent 21b6dcbe64
commit d2c761821a
38 changed files with 1171 additions and 344 deletions
+256
View File
@@ -0,0 +1,256 @@
#define RADAR_NEEDS_WELDING 0
#define RADAR_NEEDS_PLASTEEL 1
#define RADAR_NEEDS_WRENCH 2
#define RADAR_NEEDS_SCREWDRIVER 3
/obj/machinery/radar
name = "Doppler Radar"
desc = "An age-tested technology for measuring and predicting weather patterns. This one has been loaded with information of the local expected conditions."
icon = 'icons/obj/machines/doppler_tower.dmi'
icon_state = "base"
density = TRUE
anchored = TRUE
layer = ABOVE_ALL_MOB_LAYER
power_state = NO_POWER_USE // going to be used outside
interact_offline = TRUE
idle_power_consumption = 0
pixel_x = -32
armor = list(MELEE = 80, BULLET = 10, LASER = 30, ENERGY = 30, BOMB = 50, RAD = 0, FIRE = 100, ACID = 100)
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
/// Time between callouts
var/check_time
/// Internal radio to handle announcements over supply
var/obj/item/radio/radio
/// For checking what was the last weather stage an alert was sent out
var/last_stage
/// How accurate are we based off parts?
var/accuracy_coeff
/// Base Inaccuracy
var/inaccuracy = 5 MINUTES
/// What is our current prediction?
var/prediction
/// Don't want constant updates
var/dont_announce = TRUE
/// For fakeout calls
var/correct_prediction
/// Are we broken?
var/construction_state = RADAR_NEEDS_WELDING
luminosity = 1
/obj/machinery/radar/Initialize(mapload)
. = ..()
component_parts = list()
component_parts += new /obj/item/circuitboard/machine/radar(null)
component_parts += new /obj/item/stock_parts/scanning_module(null)
component_parts += new /obj/item/stock_parts/scanning_module(null)
component_parts += new /obj/item/stock_parts/scanning_module(null)
component_parts += new /obj/item/stock_parts/scanning_module(null)
component_parts += new /obj/item/stack/cable_coil(null, 10)
RefreshParts()
set_light(5, 2, "#e2db98") // so the machine isnt pitch black
AddComponent(/datum/component/multitile, list(
list(1, 1),
list(1, MACH_CENTER),
))
radio = new(src)
radio.listening = FALSE
radio.follow_target = src
radio.config(list("Supply" = 0))
AddComponent(/datum/component/largetransparency, -1, 2, 0, 1)
update_appearance(UPDATE_OVERLAYS)
/obj/machinery/radar/update_overlays()
. = ..()
if(stat & BROKEN)
icon_state = "broken"
else
icon_state = "base"
. += "chicken"
. += "screen"
/obj/machinery/radar/process()
if(stat & BROKEN)
return
if(check_time > world.time)
return
for(var/datum/weather/W in SSweather.processing)
if(!W)
break
if(W.barometer_predictable && is_path_in_list(/area/lavaland/surface/outdoors, W.area_types))
switch(W.stage)
if(WEATHER_STARTUP_STAGE)
if(last_stage == WEATHER_STARTUP_STAGE)
return
if(W.aesthetic)
if(correct_prediction) // unupgraded machines should still scare the poor bastards
radio.autosay("<b>[W.name] detected settling over the sector. No further action required.</b>", name, "Supply")
else
radio.autosay("<b>Ash Storm detected converging over the local sector. Please finish any surface excavations.</b>", name, "Supply")
else
radio.autosay("<b>[W.name] detected converging over the local sector. Please finish any surface excavations.</b>", name, "Supply")
last_stage = WEATHER_STARTUP_STAGE
check_time = world.time + W.telegraph_duration + 5 SECONDS
return
if(WEATHER_MAIN_STAGE)
if(last_stage == WEATHER_MAIN_STAGE)
return
radio.autosay("<b>Inclement weather has reached the local sector. Seek shelter immediately.</b>", name, "Supply")
last_stage = WEATHER_MAIN_STAGE
check_time = world.time + (W.weather_duration / 2)
return
if(WEATHER_WIND_DOWN_STAGE)
if(last_stage == WEATHER_WIND_DOWN_STAGE)
return
radio.autosay("<b>Inclement weather has dispersed. It is now safe to resume surface excavations.</b>", name, "Supply")
last_stage = WEATHER_WIND_DOWN_STAGE
dont_announce = FALSE
return
if(dont_announce)
return
var/datum/weather/next_weather = SSweather.next_weather_by_zlevel["3"]
var/next_hit = SSweather.next_hit_by_zlevel["3"]
var/next_difference = next_hit - world.time
var/difference_rounded = DisplayTimeText(max(1, next_difference))
if(next_weather == "0" || next_weather == null)
return
if(accuracy_coeff >= 4) //perfect accuracy
if(next_difference <= (3 MINUTES))
radio.autosay("<b>Weather patterns successfully analyzed. Predicted weather event in [difference_rounded]: [next_weather.name] </b>", name, "Supply")
dont_announce = TRUE
correct_prediction = TRUE
else if(prob(accuracy_coeff) && next_difference <= 3 MINUTES && next_difference >= 30 SECONDS)
if(next_weather == "emberfall" && !prob(10 * accuracy_coeff)) // fake callout
radio.autosay("<b>Weather patterns successfully analyzed. Predicted weather event in [difference_rounded]: ash storm </b>", name, "Supply")
dont_announce = TRUE
correct_prediction = FALSE
else
radio.autosay("<b>Weather patterns successfully analyzed. Predicted weather event in [difference_rounded]: [next_weather.name] </b>", name, "Supply")
dont_announce = TRUE
correct_prediction = TRUE
/obj/machinery/radar/examine(mob/user)
. = ..()
if(!(stat & BROKEN))
return
switch(construction_state)
if(RADAR_NEEDS_WELDING)
. += "<span class='notice'>The framework is damaged, and needs welding.</span>"
if(RADAR_NEEDS_PLASTEEL)
. += "<span class='notice'>The framework needs new plasteel plating.</span>"
if(RADAR_NEEDS_WRENCH)
. += "<span class='notice'>The plating needs wrenching into place.</span>"
if(RADAR_NEEDS_SCREWDRIVER)
. += "<span class='notice'>The cover screws are loose.</span>"
// Interaction
// REPAIRS //
// Step 1
// (stolen from gav gen teehee)
/obj/machinery/radar/welder_act(mob/user, obj/item/I)
if(construction_state != RADAR_NEEDS_WELDING)
return
. = TRUE
if(!I.use_tool(src, user, null, 1, I.tool_volume))
return
to_chat(user, "<span class='notice'>You mend the damaged framework.</span>")
construction_state = RADAR_NEEDS_PLASTEEL
// Step 2
/obj/machinery/radar/item_interaction(mob/living/user, obj/item/used, list/modifiers)
if(construction_state != RADAR_NEEDS_PLASTEEL)
return ..()
if(istype(used, /obj/item/stack/sheet/plasteel))
var/obj/item/stack/sheet/plasteel/PS = used
if(PS.amount < 10)
to_chat(user, "<span class='warning'>You need 10 sheets of plasteel.</span>")
return ITEM_INTERACT_COMPLETE
to_chat(user, "<span class='notice'>You add new plating to the framework.</span>")
construction_state = RADAR_NEEDS_WRENCH
update_icon()
return ITEM_INTERACT_COMPLETE
return ..()
// Step 3
/obj/machinery/radar/wrench_act(mob/living/user, obj/item/I)
if(construction_state != RADAR_NEEDS_WRENCH)
return
. = TRUE
if(!I.use_tool(src, user, volume = I.tool_volume))
return
to_chat(user, "<span class='notice'>You secure the plating to the framework.</span>")
construction_state = RADAR_NEEDS_SCREWDRIVER
// Step 4
/obj/machinery/radar/screwdriver_act(mob/living/user, obj/item/I)
if(!(stat & BROKEN)) // Not actually broken
return
if(construction_state != RADAR_NEEDS_SCREWDRIVER)
return
. = TRUE
if(!I.use_tool(src, user, volume = I.tool_volume))
return
to_chat(user, "<span class='notice'>You screw the covers back into place.</span>")
set_fixed()
/obj/machinery/radar/RefreshParts()
accuracy_coeff = 0
for(var/obj/item/stock_parts/scanning_module/C in component_parts)
accuracy_coeff += C.rating
accuracy_coeff = (accuracy_coeff / 4) //average all the parts
// We dont want them to rebuild this in random places. but if it does somehow delete, we should log it
/obj/machinery/radar/Destroy()
investigate_log("was destroyed!", "radar")
qdel(radio)
component_parts -= /obj/item/circuitboard/machine/radar // dont let them get the board
new /obj/item/circuitboard/machine/radar/broken(src)
. = ..()
/obj/machinery/radar/ex_act(severity)
if(severity == EXPLODE_DEVASTATE) // Very sturdy.
set_broken()
/obj/machinery/radar/proc/set_broken()
stat |= BROKEN
investigate_log("has broken down.", "radar")
update_icon()
/obj/machinery/radar/proc/set_fixed()
stat &= ~BROKEN
construction_state = initial(construction_state)
update_icon()
/obj/item/circuitboard/machine/radar
board_name = "Doppler Radar"
icon_state = "supply"
build_path = /obj/machinery/radar
board_type = "machine"
origin_tech = "engineering=2"
req_components = list(
/obj/item/stack/cable_coil = 5,
/obj/item/stack/sheet/glass = 10,
/obj/item/stock_parts/scanning_module = 4,
)
/obj/item/circuitboard/machine/radar/broken
board_name = "Doppler Radar"
desc = "Bits of char, plastic, and ash cling to the boards surface. How it was working before was nothing short of a miracle. It's probably not going to work again."
icon_state = "command_broken"
#undef RADAR_NEEDS_WELDING
#undef RADAR_NEEDS_PLASTEEL
#undef RADAR_NEEDS_WRENCH
#undef RADAR_NEEDS_SCREWDRIVER
+1 -1
View File
@@ -653,7 +653,7 @@ SLIME SCANNER
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 == WEATHER_END_STAGE))
if(W.barometer_predictable && (T.z in W.impacted_z_levels) && is_type_in_list(user_area, W.area_types) && !(W.stage == WEATHER_END_STAGE))
ongoing_weather = W
break
@@ -36,6 +36,8 @@ GLOBAL_LIST_EMPTY(tendrils)
if(ismineralturf(F))
var/turf/simulated/mineral/M = F
M.ChangeTurf(M.turf_type, FALSE, FALSE, TRUE)
var/turf/no_lava = F
no_lava.flags |= NO_LAVA_GEN
/obj/structure/spawner/lavaland/deconstruct(disassembled)
new /obj/effect/collapse(loc)
@@ -317,6 +317,13 @@
toxins = 10
atmos_mode = ATMOS_MODE_NO_DECAY
/turf/simulated/floor/engine/lavaland_air
oxygen = LAVALAND_OXYGEN
nitrogen = LAVALAND_NITROGEN
temperature = LAVALAND_TEMPERATURE
atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT
atmos_environment = ENVIRONMENT_LAVALAND
/turf/simulated/floor/engine/singularity_pull(S, current_size)
if(current_size >= STAGE_FIVE)
if(floor_tile)
+58 -12
View File
@@ -4,6 +4,10 @@
#define RIVER_MIN_X 50
#define RIVER_MIN_Y 50
#define WARNING_DELAY (4 SECONDS) // the warning time that a warning will be deisplayed before the lava conversion occurs
#define BRIDGE_PROB 2 // the percent probability of a bridge to spawn for every tile forward the river travels
GLOBAL_LIST_EMPTY(river_waypoint_presets)
/obj/effect/landmark/river_waypoint
@@ -30,6 +34,12 @@ GLOBAL_LIST_EMPTY(river_waypoint_presets)
var/whitelist_turf_type = /turf/simulated/mineral
/// The turf used when a spread of the tile stops.
var/shoreline_turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface
/// To hold all the found turfs to convert to the lava type
var/list/collected_turfs = list()
/// Does the lava generate a warning beforehand
var/warning
/// Do we ignore building any bridges?
var/ignore_bridges
/datum/river_spawner/New(target_z_, spread_prob_ = 25, spread_prob_loss_ = 11)
target_z = target_z_
@@ -42,7 +52,9 @@ GLOBAL_LIST_EMPTY(river_waypoint_presets)
/// `nodes` is the number of unique points in those bounds the river will
/// connect to. Note that `nodes` says little about the resultant size of the
/// river due to its ability to detour far away from the direct path between them.
/datum/river_spawner/proc/generate(nodes = 4, min_x = RIVER_MIN_X, min_y = RIVER_MIN_Y, max_x = RIVER_MAX_X, max_y = RIVER_MAX_Y)
/// set ignore_bridges TRUE to not spawn any new bridges, and set warning to TRUE to
/// allow for the new generations to have a telegraphed icon first
/datum/river_spawner/proc/generate(nodes = 4, min_x = RIVER_MIN_X, min_y = RIVER_MIN_Y, max_x = RIVER_MAX_X, max_y = RIVER_MAX_Y, ignore_bridges = FALSE, warning = FALSE)
var/list/river_nodes = list()
var/num_spawned = 0
@@ -72,7 +84,9 @@ GLOBAL_LIST_EMPTY(river_waypoint_presets)
W.connected = TRUE
var/turf/cur_turf = get_turf(W)
if(istype(get_area(cur_turf), whitelist_area_type) && !(cur_turf.flags & NO_LAVA_GEN))
cur_turf.ChangeTurf(river_turf_type, ignore_air = TRUE)
collected_turfs += cur_turf
else if(ignore_bridges && (cur_turf.flags & LAVA_BRIDGE))
collected_turfs += cur_turf
var/turf/target_turf = get_turf(pick(river_nodes - W))
if(!target_turf)
break
@@ -93,6 +107,7 @@ GLOBAL_LIST_EMPTY(river_waypoint_presets)
cur_dir = turn(cur_dir, -45)
else
cur_dir = get_dir(cur_turf, target_turf)
// we may veer off the map entirely, returning a null turf; if so, go back and try again
while(get_step(cur_turf, cur_dir) == null && attempts-- > 0)
@@ -107,15 +122,14 @@ GLOBAL_LIST_EMPTY(river_waypoint_presets)
cur_turf = get_step(cur_turf, cur_dir)
continue
else
var/turf/river_turf = cur_turf.ChangeTurf(river_turf_type, ignore_air = TRUE)
if(prob(1))
new /obj/effect/spawner/dynamic_bridge(river_turf)
spread_turf(river_turf, spread_prob, spread_prob_loss, whitelist_area_type)
collected_turfs += cur_turf
handle_change(warning, ignore_bridges)
for(var/WP in river_nodes)
qdel(WP)
/datum/river_spawner/proc/spread_turf(turf/start_turf, probability = 30, prob_loss = 25, whitelisted_area)
/datum/river_spawner/proc/spread_turf(turf/start_turf, probability = 30, prob_loss = 25, whitelisted_area, ignore_bridges)
if(probability <= 0)
return
var/list/cardinal_turfs = list()
@@ -124,7 +138,9 @@ GLOBAL_LIST_EMPTY(river_waypoint_presets)
for(var/F in RANGE_TURFS(1, start_turf) - start_turf)
var/turf/T = F
var/area/new_area = get_area(T)
if(!T || (T.density && !istype(T, whitelist_turf_type)) || istype(T, /turf/simulated/floor/indestructible) || (whitelisted_area && !istype(new_area, whitelisted_area)) || (T.flags & NO_LAVA_GEN))
if(!ignore_bridges && (T.flags & LAVA_BRIDGE))
continue
else if(!T || (T.density && !istype(T, whitelist_turf_type)) || istype(T, /turf/simulated/floor/indestructible) || (whitelisted_area && !istype(new_area, whitelisted_area)) || (T.flags & NO_LAVA_GEN))
continue
if(get_dir(start_turf, F) in GLOB.cardinal)
@@ -136,8 +152,6 @@ GLOBAL_LIST_EMPTY(river_waypoint_presets)
var/turf/T = F
if(!istype(T, start_turf.type) && T.ChangeTurf(start_turf.type, ignore_air = TRUE) && prob(probability))
spread_turf(T, probability - prob_loss, prob_loss, whitelisted_area)
if(prob(1))
new /obj/effect/spawner/dynamic_bridge(T)
for(var/F in diagonal_turfs) //diagonal turfs only sometimes change, but will always spread if changed
var/turf/T = F
@@ -145,8 +159,40 @@ GLOBAL_LIST_EMPTY(river_waypoint_presets)
spread_turf(T, probability - prob_loss, prob_loss, whitelisted_area)
else if(istype(T, whitelist_turf_type) && !istype(T, start_turf.type))
T.ChangeTurf(shoreline_turf_type, ignore_air = TRUE)
if(prob(1))
new /obj/effect/spawner/dynamic_bridge(T)
/// handles changing the lava turfs, and if it should delay it and place warnings
/datum/river_spawner/proc/handle_change(warning, ignore_bridges)
var/lava_counter = 0
for(var/turf/listed_turf in collected_turfs)
var/affected_turf = get_turf(listed_turf)
if(warning)
if(lava_counter++ >= 2)
new /obj/effect/temp_visual/river_warning(affected_turf)
lava_counter = 0
addtimer(CALLBACK(src, PROC_REF(convert_turf), affected_turf), WARNING_DELAY)
else
convert_turf(affected_turf, ignore_bridges)
collected_turfs.Cut()
/// actually convert the turf
/datum/river_spawner/proc/convert_turf(turf/cur_turf, ignore_bridges)
var/turf/river_turf = cur_turf.ChangeTurf(river_turf_type, ignore_air = TRUE)
spread_turf(river_turf, spread_prob, spread_prob_loss, whitelist_area_type, ignore_bridges)
if(prob(BRIDGE_PROB) && !ignore_bridges)
new /obj/effect/spawner/dynamic_bridge(cur_turf)
/obj/effect/temp_visual/river_warning
icon = 'icons/effects/96x96.dmi'
icon_state = "warning"
layer = BELOW_MOB_LAYER
duration = WARNING_DELAY
randomdir = FALSE
pixel_x = -32
pixel_y = -32
#undef WARNING_DELAY
#undef BRIDGE_PROB
#undef RIVER_MAX_X
#undef RIVER_MAX_Y