diff --git a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_nt.dmm b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_nt.dmm index ab7240c8943..a1661f6fd1c 100644 --- a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_nt.dmm +++ b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_nt.dmm @@ -432,15 +432,10 @@ /turf/simulated/floor/lava/mapping_lava, /area/lavaland/surface/outdoors/outpost/catwalk) "cZ" = ( -/obj/effect/spawner/random/loot_crate, +/obj/machinery/radar, /obj/effect/mapping_helpers/no_lava, -/obj/structure/railing{ - dir = 4 - }, -/obj/structure/lattice/catwalk/mining, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating/asteroid/basalt/lava_land_surface, -/area/lavaland/surface/outdoors/targetable) +/turf/simulated/floor/engine/lavaland_air, +/area/lavaland/surface/outdoors/outpost/catwalk) "da" = ( /obj/effect/mapping_helpers/airlock/access/all/engineering/maintenance, /obj/machinery/door/airlock/maintenance, @@ -1164,6 +1159,12 @@ }, /turf/simulated/floor/plating, /area/mine/outpost/smith_workshop) +"gP" = ( +/obj/structure/lattice/catwalk/mining, +/obj/effect/decal/cleanable/dirt, +/obj/item/cigbutt, +/turf/simulated/floor/plating/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors/outpost/catwalk) "gQ" = ( /obj/effect/turf_decal/stripes/red/line, /obj/effect/turf_decal/stripes/red/line{ @@ -1504,6 +1505,13 @@ icon_state = "darkfull" }, /area/mine/outpost/hallway/west) +"iy" = ( +/obj/structure/railing{ + dir = 4 + }, +/obj/effect/mapping_helpers/no_lava, +/turf/simulated/floor/engine/lavaland_air, +/area/lavaland/surface/outdoors/outpost/catwalk) "iA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -1591,6 +1599,13 @@ icon_state = "barber" }, /area/mine/laborcamp) +"iY" = ( +/obj/structure/railing{ + dir = 9 + }, +/obj/effect/mapping_helpers/no_lava, +/turf/simulated/floor/engine/lavaland_air, +/area/lavaland/surface/outdoors/outpost/catwalk) "jc" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/rack, @@ -1797,6 +1812,14 @@ }, /turf/simulated/floor/plasteel, /area/mine/laborcamp) +"kf" = ( +/obj/structure/railing{ + dir = 4 + }, +/obj/item/screwdriver, +/obj/effect/mapping_helpers/no_lava, +/turf/simulated/floor/engine/lavaland_air, +/area/lavaland/surface/outdoors/outpost/catwalk) "kl" = ( /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors/explored) @@ -1817,6 +1840,14 @@ icon_state = "darkfull" }, /area/mine/outpost/engineering) +"kC" = ( +/obj/structure/lattice/catwalk/mining, +/obj/structure/railing, +/obj/structure/railing/corner{ + dir = 4 + }, +/turf/simulated/floor/lava/mapping_lava, +/area/lavaland/surface/outdoors/outpost/catwalk) "kG" = ( /obj/effect/turf_decal/stripes/red/line, /turf/simulated/floor/plasteel{ @@ -3118,6 +3149,10 @@ icon_state = "darkredyellowfull" }, /area/mine/laborcamp) +"re" = ( +/obj/effect/mapping_helpers/no_lava, +/turf/simulated/mineral/volcanic/lava_land_surface, +/area/lavaland/surface/gulag_rock) "rg" = ( /obj/structure/rack, /obj/item/screwdriver, @@ -4196,11 +4231,8 @@ /area/mine/outpost/maintenance/east) "wX" = ( /obj/structure/lattice/catwalk/mining, -/obj/structure/railing/corner{ - dir = 4 - }, /obj/structure/railing, -/turf/simulated/floor/lava/mapping_lava, +/turf/simulated/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors/outpost/catwalk) "xf" = ( /obj/machinery/computer/card/minor/qm, @@ -4510,10 +4542,12 @@ }, /area/mine/laborcamp) "zn" = ( -/obj/structure/marker_beacon/dock_marker/collision, +/obj/structure/railing{ + dir = 5 + }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/asteroid/basalt/lava_land_surface, -/area/lavaland/surface/outdoors/targetable) +/turf/simulated/floor/engine/lavaland_air, +/area/lavaland/surface/outdoors/outpost/catwalk) "zp" = ( /obj/structure/disposalpipe/segment{ dir = 8 @@ -4559,6 +4593,17 @@ dir = 8 }, /area/mine/outpost/mechbay) +"zA" = ( +/obj/structure/railing/corner{ + dir = 1 + }, +/obj/structure/railing/corner{ + dir = 1 + }, +/obj/effect/baseturf_helper/lava_land, +/obj/effect/mapping_helpers/no_lava, +/turf/simulated/floor/engine/lavaland_air, +/area/lavaland/surface/outdoors/outpost/catwalk) "zB" = ( /obj/effect/spawner/random/cobweb/left/frequent, /obj/machinery/alarm/directional/north, @@ -4962,9 +5007,10 @@ /turf/simulated/wall/r_wall, /area/mine/laborcamp) "BB" = ( -/obj/structure/sign/nanotrasen, -/turf/simulated/wall/mineral/iron, -/area/lavaland/surface/outdoors/targetable) +/obj/effect/spawner/random/trash, +/obj/effect/mapping_helpers/no_lava, +/turf/simulated/floor/engine/lavaland_air, +/area/lavaland/surface/outdoors/outpost/catwalk) "BE" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/extinguisher_cabinet{ @@ -5255,6 +5301,16 @@ "De" = ( /turf/template_noop, /area/template_noop) +"Df" = ( +/obj/structure/sign/nanotrasen{ + pixel_y = -32 + }, +/obj/structure/railing{ + dir = 1 + }, +/obj/effect/mapping_helpers/no_lava, +/turf/simulated/floor/engine/lavaland_air, +/area/lavaland/surface/outdoors/outpost/catwalk) "Dj" = ( /obj/structure/chair, /obj/item/cigbutt, @@ -6840,6 +6896,13 @@ }, /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors/outpost/catwalk) +"LJ" = ( +/obj/structure/railing{ + dir = 8 + }, +/obj/effect/mapping_helpers/no_lava, +/turf/simulated/floor/engine/lavaland_air, +/area/lavaland/surface/outdoors/outpost/catwalk) "LK" = ( /obj/machinery/door/airlock{ name = "Custodial Storage" @@ -7313,7 +7376,6 @@ /obj/structure/lattice/catwalk/mining, /obj/effect/decal/cleanable/dirt, /obj/structure/railing/corner, -/obj/item/cigbutt, /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors/outpost/catwalk) "Oq" = ( @@ -8720,6 +8782,10 @@ "Wn" = ( /turf/simulated/mineral/volcanic/lava_land_surface, /area/lavaland/surface/outdoors) +"Wq" = ( +/obj/effect/mapping_helpers/no_lava, +/turf/simulated/floor/engine/lavaland_air, +/area/lavaland/surface/outdoors/outpost/catwalk) "Ws" = ( /obj/structure/chair/stool/bar{ dir = 8 @@ -16873,8 +16939,8 @@ lR lR lR lR -lR -lR +re +re Yr Yr xt @@ -17034,9 +17100,9 @@ lR lR lR lR -lR -lR -lR +pB +re +re Yr Yr PH @@ -17195,13 +17261,13 @@ zP zP oO oO -Yh -Yh -Yh -Yr -Yr -Yr -PH +oO +IJ +iY +LJ +LJ +zA +gP gt gt gt @@ -17352,17 +17418,17 @@ lR lR lR lR -sb +IG zP zP oO oO -Yh -Yh -Yh -Yr -Yr -Yr +IJ +IJ +Df +Wq +Wq +Wq Ol gt oO @@ -17514,15 +17580,15 @@ sb sb sb sb -sb +IG zP zP oO oO IJ -Yh -Yh -Yr +IJ +Df +Wq cZ BB wX @@ -17676,18 +17742,18 @@ sb sb sb sb -sb +IG zP zP oO oO -Yh -IJ -zn -zn -IJ oO -dd +IJ +zn +iy +kf +iy +kC oO oO zP @@ -17842,14 +17908,14 @@ uv zP oO oO +Yh +Yh +Yh +Yh +IJ +IJ oO -Yh -Yr -Yr -Yh -Yh -oO -dd +VM oO oO oO diff --git a/_maps/map_files/templates/shelter_2.dmm b/_maps/map_files/templates/shelter_2.dmm index 521798561d9..da889651ccc 100644 --- a/_maps/map_files/templates/shelter_2.dmm +++ b/_maps/map_files/templates/shelter_2.dmm @@ -1,46 +1,41 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"a" = ( +"aa" = ( /turf/simulated/wall/mineral/titanium/survival, -/area/survivalpod) -"b" = ( +/area/survivalpod/luxurypod) +"ab" = ( /obj/structure/sign/mining/survival{ dir = 8 }, /turf/simulated/wall/mineral/titanium/survival, -/area/survivalpod) -"c" = ( +/area/survivalpod/luxurypod) +"ac" = ( /obj/machinery/smartfridge/survival_pod, /turf/simulated/floor/pod, -/area/survivalpod) -"d" = ( +/area/survivalpod/luxurypod) +"ad" = ( /turf/simulated/floor/pod, -/area/survivalpod) -"e" = ( +/area/survivalpod/luxurypod) +"ae" = ( /obj/machinery/door/window/survival_pod{ dir = 1 }, /turf/simulated/floor/carpet/black, -/area/survivalpod) -"f" = ( +/area/survivalpod/luxurypod) +"af" = ( /obj/machinery/light, /turf/simulated/floor/carpet/black, -/area/survivalpod) -"g" = ( +/area/survivalpod/luxurypod) +"ag" = ( /obj/structure/sign/mining/survival{ dir = 1 }, /turf/simulated/wall/mineral/titanium/survival, -/area/survivalpod) -"h" = ( +/area/survivalpod/luxurypod) +"ah" = ( /obj/structure/fans, /turf/simulated/floor/pod, -/area/survivalpod) -"i" = ( -/obj/machinery/sleeper/survival_pod, -/obj/machinery/economy/vending/wallmed/directional/west, -/turf/simulated/floor/pod, -/area/survivalpod) -"j" = ( +/area/survivalpod/luxurypod) +"aj" = ( /obj/structure/table/survival_pod, /obj/item/storage/firstaid/regular, /obj/item/storage/firstaid/brute{ @@ -48,8 +43,8 @@ pixel_y = -2 }, /turf/simulated/floor/pod, -/area/survivalpod) -"k" = ( +/area/survivalpod/luxurypod) +"ak" = ( /obj/structure/table/wood/fancy/black{ pixel_y = -9 }, @@ -58,26 +53,26 @@ }, /obj/machinery/kitchen_machine/microwave, /turf/simulated/floor/carpet/black, -/area/survivalpod) -"l" = ( +/area/survivalpod/luxurypod) +"al" = ( /obj/structure/sink/kitchen{ dir = 4; pixel_x = -11 }, /turf/simulated/floor/carpet/black, -/area/survivalpod) -"m" = ( +/area/survivalpod/luxurypod) +"am" = ( /obj/structure/sign/mining/survival, /turf/simulated/wall/mineral/titanium/survival, -/area/survivalpod) -"n" = ( +/area/survivalpod/luxurypod) +"an" = ( /obj/structure/curtain/black, /obj/machinery/shower{ pixel_y = 20 }, /turf/simulated/floor/pod, -/area/survivalpod) -"o" = ( +/area/survivalpod/luxurypod) +"ao" = ( /obj/structure/window/reinforced/survival_pod{ dir = 8; pixel_y = -8 @@ -86,32 +81,32 @@ dir = 1 }, /turf/simulated/floor/carpet/black, -/area/survivalpod) -"p" = ( +/area/survivalpod/luxurypod) +"aq" = ( /obj/structure/window/reinforced/survival_pod{ dir = 8; pixel_y = -8 }, /turf/simulated/floor/carpet/black, -/area/survivalpod) -"r" = ( +/area/survivalpod/luxurypod) +"ar" = ( /turf/simulated/floor/carpet/black, -/area/survivalpod) -"s" = ( +/area/survivalpod/luxurypod) +"as" = ( /obj/item/gps/computer, /turf/simulated/floor/pod, -/area/survivalpod) -"t" = ( +/area/survivalpod/luxurypod) +"at" = ( /obj/structure/bed/pod, /obj/item/bedsheet/brown, /turf/simulated/floor/pod, -/area/survivalpod) -"u" = ( +/area/survivalpod/luxurypod) +"au" = ( /obj/structure/tubes, /obj/item/kirbyplants/large, /turf/simulated/floor/pod, -/area/survivalpod) -"v" = ( +/area/survivalpod/luxurypod) +"av" = ( /obj/structure/window/reinforced/survival_pod{ dir = 1 }, @@ -124,25 +119,25 @@ /turf/simulated/floor/carpet/black{ dir = 1 }, -/area/survivalpod) -"w" = ( +/area/survivalpod/luxurypod) +"aw" = ( /obj/structure/fans/tiny, /obj/machinery/door/airlock/survival_pod/glass, /turf/simulated/floor/pod, -/area/survivalpod) -"x" = ( +/area/survivalpod/luxurypod) +"ax" = ( /obj/structure/sign/mining/survival{ dir = 4 }, /turf/simulated/wall/mineral/titanium/survival, -/area/survivalpod) -"y" = ( +/area/survivalpod/luxurypod) +"ay" = ( /obj/structure/toilet/secret{ pixel_y = 12 }, /turf/simulated/floor/pod, -/area/survivalpod) -"z" = ( +/area/survivalpod/luxurypod) +"az" = ( /obj/structure/window/reinforced/survival_pod{ dir = 1 }, @@ -152,8 +147,8 @@ name = "lusty xenomorph maid" }, /turf/simulated/floor/carpet/black, -/area/survivalpod) -"A" = ( +/area/survivalpod/luxurypod) +"aA" = ( /obj/structure/table/wood/fancy/black, /obj/machinery/light{ dir = 4 @@ -164,8 +159,8 @@ }, /obj/item/reagent_containers/drinks/bottle/wine, /turf/simulated/floor/carpet/black, -/area/survivalpod) -"B" = ( +/area/survivalpod/luxurypod) +"aB" = ( /obj/structure/table/wood/fancy/black, /obj/item/reagent_containers/drinks/drinkingglass{ pixel_x = -4; @@ -173,78 +168,83 @@ }, /obj/effect/spawner/random/food_or_drink/three_course_meal, /turf/simulated/floor/carpet/black, -/area/survivalpod) -"C" = ( +/area/survivalpod/luxurypod) +"aC" = ( /obj/structure/chair/comfy/black{ dir = 1 }, /turf/simulated/floor/carpet/black, -/area/survivalpod) -"D" = ( +/area/survivalpod/luxurypod) +"aD" = ( /obj/structure/sign/mining, /turf/simulated/wall/mineral/titanium/survival, -/area/survivalpod) +/area/survivalpod/luxurypod) +"aF" = ( +/obj/machinery/sleeper/survival_pod, +/obj/machinery/economy/vending/wallmed/directional/west, +/turf/simulated/floor/pod, +/area/survivalpod/luxurypod) (1,1,1) = {" -a -b -a -b -a -b -a +aa +ab +aa +ab +aa +ab +aa "} (2,1,1) = {" -g -h -i -j -k -l -m +ag +ah +aF +aj +ak +al +am "} (3,1,1) = {" -a -c -d -d -e -f -a +aa +ac +ad +ad +ae +af +aa "} (4,1,1) = {" -g -s -t -u -v -r -w +ag +as +at +au +av +ar +aw "} (5,1,1) = {" -a -n -o -p -r -r -a +aa +an +ao +aq +ar +ar +aa "} (6,1,1) = {" -g -y -z -A -B -C -D +ag +ay +az +aA +aB +aC +aD "} (7,1,1) = {" -a -x -a -x -a -x -a +aa +ax +aa +ax +aa +ax +aa "} diff --git a/code/__DEFINES/dcs/global_signals.dm b/code/__DEFINES/dcs/global_signals.dm index 350f1603e96..509f60b1f15 100644 --- a/code/__DEFINES/dcs/global_signals.dm +++ b/code/__DEFINES/dcs/global_signals.dm @@ -24,3 +24,6 @@ /// Used by admin-tooling to remove radiation #define COMSIG_ADMIN_DECONTAMINATE "admin_decontaminate" + +/// Used when a shelter capsule deploys +#define COMSIG_GLOB_SHELTER_PLACED "!shelter_placed" diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index 8ff538f3d37..b3c050d8081 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -146,6 +146,14 @@ return TRUE return FALSE +/proc/is_path_in_list(P, list/L) + if(!L || !length(L) || !P) + return FALSE + for(var/type in L) + if(ispath(P, type)) + return TRUE + return FALSE + //Checks for specific types in specifically structured (Assoc "type" = TRUE) lists ('typecaches') /proc/is_type_in_typecache(atom/A, list/L) if(!L || !length(L) || !A) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 73e7b673f06..10e9a730ad0 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1989,7 +1989,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) if(CHANNEL_FIREALARM) return "Fire Alarms" if(CHANNEL_ASH_STORM) - return "Ash Storms" + return "Weather" if(CHANNEL_RADIO_NOISE) return "Radio Noise" if(CHANNEL_BOSS_MUSIC) diff --git a/code/controllers/subsystem/SSweather.dm b/code/controllers/subsystem/SSweather.dm index b0dd088ebaf..eff570df97b 100644 --- a/code/controllers/subsystem/SSweather.dm +++ b/code/controllers/subsystem/SSweather.dm @@ -10,6 +10,7 @@ SUBSYSTEM_DEF(weather) var/list/processing = list() var/list/eligible_traits = list() var/list/next_hit_by_zlevel = list() //Used by barometers to know when the next storm is coming + var/list/next_weather_by_zlevel = list() // For the weather radar detection cpu_display = SS_CPUDISPLAY_LOW /datum/controller/subsystem/weather/get_metrics() @@ -28,6 +29,8 @@ SUBSYSTEM_DEF(weather) var/mob/living/L = i if(W.can_weather_act(L)) W.weather_act(L) + if(W.area_act == TRUE) + W.area_act() // start random weather on relevant levels while(length(eligible_traits)) @@ -39,6 +42,7 @@ SUBSYSTEM_DEF(weather) for(var/z in zlevels) addtimer(CALLBACK(src, PROC_REF(make_eligible), trait, possible_weathers), 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) + next_weather_by_zlevel["[z]"] = W run_weather(W, zlevels) eligible_traits.len-- @@ -68,17 +72,19 @@ SUBSYSTEM_DEF(weather) var/list/zlevels = levels_by_trait(weather_datum_type::target_trait) var/datum/weather/W = new weather_datum_type(zlevels) W.telegraph() + SSblackbox.record_feedback("tally", "weather_event", 1, "[weather_datum_type]") /datum/controller/subsystem/weather/proc/make_eligible(trait, list/possible_weathers) eligible_traits[trait] = possible_weathers for(var/zlevel in levels_by_trait(trait)) next_hit_by_zlevel["[zlevel]"] = null + next_weather_by_zlevel["[zlevel]"] = 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) + if((z in W.impacted_z_levels) && is_path_in_list(active_area, W.area_types)) A = W break return A diff --git a/code/datums/looping_sounds/weather_sounds.dm b/code/datums/looping_sounds/weather_sounds.dm index ccd7fa1a5ad..3a2e1fa2b72 100644 --- a/code/datums/looping_sounds/weather_sounds.dm +++ b/code/datums/looping_sounds/weather_sounds.dm @@ -4,7 +4,7 @@ 'sound/weather/ashstorm/outside/active_mid1.ogg' = 1, 'sound/weather/ashstorm/outside/active_mid1.ogg' = 1 ) - mid_length = 80 + mid_length = 65 start_sound = 'sound/weather/ashstorm/outside/active_start.ogg' start_length = 130 end_sound = 'sound/weather/ashstorm/outside/active_end.ogg' @@ -53,3 +53,44 @@ volume = 30 area_sound = TRUE channel = CHANNEL_ASH_STORM + +/datum/looping_sound/active_outside_acid + mid_sounds = 'sound/weather/acid/outside/active_mid1.ogg' + mid_length = 105 + start_sound = list('sound/weather/acid/outside/active_start.ogg' = 1) + start_length = 130 + end_sound = 'sound/weather/acid/outside/active_end.ogg' + volume = 65 + area_sound = TRUE + channel = CHANNEL_ASH_STORM + +/datum/looping_sound/weak_outside_acid + mid_sounds ='sound/weather/acid/outside/weak_mid1.ogg' + mid_length = 120 + start_sound = list('sound/weather/acid/outside/weak_start.ogg' = 1) + start_length = 130 + end_sound = 'sound/weather/acid/outside/weak_end.ogg' + volume = 60 + area_sound = TRUE + channel = CHANNEL_ASH_STORM + +/datum/looping_sound/active_inside_acid + mid_sounds = 'sound/weather/acid/inside/active_mid1.ogg' + mid_length = 105 + start_sound = list('sound/weather/acid/inside/active_start.ogg' = 1) + start_length = 130 + end_sound = 'sound/weather/acid/inside/active_end.ogg' + volume = 50 + area_sound = TRUE + channel = CHANNEL_ASH_STORM + +/datum/looping_sound/weak_inside_acid + mid_sounds = 'sound/weather/acid/inside/weak_mid1.ogg' + mid_length = 105 + start_sound = list('sound/weather/acid/inside/weak_start.ogg' = 1) + start_length = 130 + end_sound = 'sound/weather/acid/inside/weak_end.ogg' + volume = 50 + area_sound = TRUE + channel = CHANNEL_ASH_STORM + diff --git a/code/datums/weather/weather_datum.dm b/code/datums/weather/weather_datum.dm index adeceb51aba..60c1e9def20 100644 --- a/code/datums/weather/weather_datum.dm +++ b/code/datums/weather/weather_datum.dm @@ -1,5 +1,7 @@ //The effects of weather occur across an entire z-level. For instance, lavaland has periodic ash storms that scorch most unprotected creatures. +GLOBAL_LIST_EMPTY(all_shelter_pods) + /datum/weather var/name = "space wind" var/desc = "Heavy gusts of wind blanket the area, periodically knocking down anyone caught in the open." @@ -22,13 +24,15 @@ var/end_sound var/end_overlay - var/area_type = /area/space //Types of area to affect + var/area_types = list(/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/list/protected_areas = list()//Areas that are protected and excluded from the affected areas. var/impacted_z_levels // The list of z-levels that this weather is actively affecting var/overlay_layer = AREA_LAYER //Since it's above everything else, this is the layer used by default. TURF_LAYER is below mobs and walls if you need to use that. var/overlay_plane = AREA_PLANE + var/custom_overlay // Do we want to give it a non-standard weather effect + var/overlay_dir = NORTH 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 @@ -41,14 +45,27 @@ var/barometer_predictable = FALSE var/next_hit_time = 0 //For barometers to know when the next storm will hit + var/area_act = FALSE // Does this affect more than just mobs, or the landscape? + + var/list/inside_areas = list() // Any areas not in the outside terf + var/list/outside_areas = list() // Any areas listed as "outside" + var/list/eligible_areas = list() // For variable playing or not playing sounds for shuttles + /datum/weather/New(z_levels) ..() impacted_z_levels = z_levels + RegisterSignal(SSdcs, COMSIG_GLOB_SHELTER_PLACED, PROC_REF(on_shelter_placed)) + +/datum/weather/proc/on_shelter_placed(datum/source, turf/center) + SIGNAL_HANDLER // COMSIG_GLOB_SHELTER_PLACED + GLOB.all_shelter_pods += center + return /datum/weather/proc/generate_area_list() var/list/affectareas = list() - for(var/V in get_areas(area_type)) - affectareas += V + for(var/area_type in area_types) + for(var/V in get_areas(area_type)) + affectareas += V for(var/V in protected_areas) affectareas -= get_areas(V) for(var/V in affectareas) @@ -64,6 +81,8 @@ weather_duration = rand(weather_duration_lower, weather_duration_upper) START_PROCESSING(SSweather, src) update_areas() + update_eligible_areas() + update_audio() for(var/M in GLOB.player_list) var/turf/mob_turf = get_turf(M) if(mob_turf && (mob_turf.z in impacted_z_levels)) @@ -71,6 +90,7 @@ to_chat(M, telegraph_message) if(telegraph_sound) SEND_SOUND(M, sound(telegraph_sound)) + addtimer(CALLBACK(src, PROC_REF(start)), telegraph_duration) /datum/weather/proc/start() @@ -78,6 +98,7 @@ return stage = WEATHER_MAIN_STAGE update_areas() + update_audio() for(var/M in GLOB.player_list) var/turf/mob_turf = get_turf(M) if(mob_turf && (mob_turf.z in impacted_z_levels)) @@ -92,6 +113,7 @@ return stage = WEATHER_WIND_DOWN_STAGE update_areas() + update_audio() for(var/M in GLOB.player_list) var/turf/mob_turf = get_turf(M) if(mob_turf && (mob_turf.z in impacted_z_levels)) @@ -107,6 +129,7 @@ stage = WEATHER_END_STAGE STOP_PROCESSING(SSweather, src) update_areas() + update_audio() /datum/weather/proc/can_weather_act(mob/living/L) //Can this weather impact a mob? var/turf/mob_turf = get_turf(L) @@ -128,7 +151,12 @@ var/area/N = V N.layer = overlay_layer N.plane = overlay_plane - N.icon = 'icons/effects/weather_effects.dmi' + if(!custom_overlay) + N.icon = 'icons/effects/weather_effects.dmi' + else + N.icon = custom_overlay + if(overlay_dir) + N.dir = overlay_dir N.invisibility = 0 N.color = weather_color switch(stage) @@ -142,6 +170,43 @@ N.color = null N.icon_state = "" N.icon = 'icons/turf/areas.dmi' + N.dir = NORTH N.layer = initial(N.layer) N.plane = initial(N.plane) N.set_opacity(FALSE) + + +/datum/weather/proc/update_eligible_areas() + for(var/z in impacted_z_levels) + for(var/area/A in GLOB.space_manager.areas_in_z["[z]"]) + eligible_areas |= A + + // Don't play storm audio to shuttles that are not at lavaland + var/miningShuttleDocked = is_shuttle_docked("mining", "mining_away") + if(!miningShuttleDocked) + eligible_areas -= get_areas(/area/shuttle/mining) + + var/laborShuttleDocked = is_shuttle_docked("laborcamp", "laborcamp_away") + if(!laborShuttleDocked) + eligible_areas -= get_areas(/area/shuttle/siberia) + + var/golemShuttleOnPlanet = is_shuttle_docked("freegolem", "freegolem_lavaland") + if(!golemShuttleOnPlanet) + eligible_areas -= get_areas(/area/shuttle/freegolem) + + for(var/i in 1 to length(eligible_areas)) + var/area/place = eligible_areas[i] + if(place.outdoors) + outside_areas |= place + else + inside_areas |= place + +/datum/weather/proc/is_shuttle_docked(shuttleId, dockId) + var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId) + return M && M.getDockedId() == dockId + +/datum/weather/proc/area_act() + return + +/datum/weather/proc/update_audio() + return diff --git a/code/datums/weather/weather_types/ash_storm.dm b/code/datums/weather/weather_types/ash_storm.dm deleted file mode 100644 index af24f07e38f..00000000000 --- a/code/datums/weather/weather_types/ash_storm.dm +++ /dev/null @@ -1,148 +0,0 @@ -//Ash storms happen frequently on lavaland. They heavily obscure vision, and cause high fire damage to anyone caught outside. -/datum/weather/ash_storm - 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_overlay = "light_ash" - - weather_message = "Smoldering clouds of scorching ash billow down around you! Get inside!" - weather_duration_lower = 600 - weather_duration_upper = 1200 - weather_overlay = "ash_storm" - - end_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." - end_duration = 300 - end_overlay = "light_ash" - - area_type = /area/lavaland/surface/outdoors - target_trait = ORE_LEVEL - - immunity_type = "ash" - - 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) - var/datum/looping_sound/weak_inside_ashstorm/sound_wi = new(list(), FALSE, TRUE) - -/datum/weather/ash_storm/proc/is_shuttle_docked(shuttleId, dockId) - var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId) - return M && M.getDockedId() == dockId - -/datum/weather/ash_storm/proc/update_eligible_areas() - var/list/inside_areas = list() - var/list/outside_areas = list() - var/list/eligible_areas = list() - for(var/z in impacted_z_levels) - if("[z]" in GLOB.space_manager.areas_in_z) - eligible_areas += GLOB.space_manager.areas_in_z["[z]"] - - // Don't play storm audio to shuttles that are not at lavaland - var/miningShuttleDocked = is_shuttle_docked("mining", "mining_away") - if(!miningShuttleDocked) - eligible_areas -= get_areas(/area/shuttle/mining) - - var/laborShuttleDocked = is_shuttle_docked("laborcamp", "laborcamp_away") - if(!laborShuttleDocked) - eligible_areas -= get_areas(/area/shuttle/siberia) - - var/golemShuttleOnPlanet = is_shuttle_docked("freegolem", "freegolem_lavaland") - if(!golemShuttleOnPlanet) - eligible_areas -= get_areas(/area/shuttle/freegolem) - - while(length(eligible_areas)) - var/area/place = eligible_areas[length(eligible_areas)] - if(place.outdoors) - outside_areas += place - else - inside_areas += place - eligible_areas.len-- - - sound_ao.output_atoms = outside_areas - sound_ai.output_atoms = inside_areas - sound_wo.output_atoms = outside_areas - sound_wi.output_atoms = inside_areas - -/datum/weather/ash_storm/proc/update_audio() - switch(stage) - if(WEATHER_STARTUP_STAGE) - sound_wo.start() - sound_wi.start() - - if(WEATHER_MAIN_STAGE) - sound_wo.stop() - sound_wi.stop() - - sound_ao.start() - sound_ai.start() - - if(WEATHER_WIND_DOWN_STAGE) - sound_ao.stop() - sound_ai.stop() - - sound_wo.start() - sound_wi.start() - - if(WEATHER_END_STAGE) - sound_wo.stop() - sound_wi.stop() - -/datum/weather/ash_storm/generate_area_list() - . = ..() - // I'm a lazy fuck and it's either this or refactor procgen again - impacted_areas |= get_areas(/area/lavaland/surface/gulag_rock) - -/datum/weather/ash_storm/telegraph() - . = ..() - update_eligible_areas() - update_audio() - -/datum/weather/ash_storm/start() - . = ..() - update_audio() - -/datum/weather/ash_storm/wind_down() - . = ..() - update_audio() - -/datum/weather/ash_storm/end() - . = ..() - update_audio() - -/datum/weather/ash_storm/proc/is_ash_immune(atom/L) - while(L && !isturf(L)) - if(ismecha(L)) //Mechs are immune - return TRUE - if(ishuman(L)) //Are you immune? - var/mob/living/carbon/human/H = L - var/thermal_protection = H.get_thermal_protection() - if(thermal_protection >= FIRE_IMMUNITY_MAX_TEMP_PROTECT) - return TRUE - L = L.loc //Matryoshka check - return FALSE //RIP you - -/datum/weather/ash_storm/weather_act(mob/living/L) - if(is_ash_immune(L)) - return - L.adjustFireLoss(4) - - -//Emberfalls are the result of an ash storm passing by close to the playable area of lavaland. They have a 10% chance to trigger in place of an ash storm. -/datum/weather/ash_storm/emberfall - 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_overlay = "light_ash" - - end_message = "The emberfall slows, stops. Another layer of hardened soot to the basalt beneath your feet." - end_sound = null - - aesthetic = TRUE - - probability = 10 diff --git a/code/datums/weather/weather_types/floor_is_lava.dm b/code/datums/weather/weather_types/floor_is_lava.dm index 6cb2202593f..d0511f9faef 100644 --- a/code/datums/weather/weather_types/floor_is_lava.dm +++ b/code/datums/weather/weather_types/floor_is_lava.dm @@ -14,7 +14,7 @@ end_message = "The ground cools and returns to its usual form." end_duration = 0 - area_type = /area + area_types = list(/area) protected_areas = list(/area/space) target_trait = STATION_LEVEL diff --git a/code/datums/weather/weather_types/lavaland_weather.dm b/code/datums/weather/weather_types/lavaland_weather.dm new file mode 100644 index 00000000000..61aab08f1c9 --- /dev/null +++ b/code/datums/weather/weather_types/lavaland_weather.dm @@ -0,0 +1,470 @@ +#define ROCKFALL_DELAY 10 // For how long until the boulders hit the ground + +/// MARK: Ash Storm +//Ash storms happen frequently on lavaland. They heavily obscure vision, and cause high fire damage to anyone caught outside. +/datum/weather/ash_storm + 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_overlay = "light_ash" + + weather_message = "Smoldering clouds of scorching ash billow down around you! Get inside!" + weather_duration_lower = 600 + weather_duration_upper = 1200 + weather_overlay = "ash_storm" + + end_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." + end_duration = 300 + end_overlay = "light_ash" + + area_types = list(/area/lavaland/surface/outdoors, /area/lavaland/surface/gulag_rock) + target_trait = ORE_LEVEL + immunity_type = "ash" + probability = 25 + 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) + var/datum/looping_sound/weak_inside_ashstorm/sound_wi = new(list(), FALSE, TRUE) + +/datum/weather/ash_storm/update_eligible_areas() + . = ..() + sound_ao.output_atoms = outside_areas + sound_ai.output_atoms = inside_areas + sound_wo.output_atoms = outside_areas + sound_wi.output_atoms = inside_areas + +/datum/weather/ash_storm/update_audio() + switch(stage) + if(WEATHER_STARTUP_STAGE) + sound_wo.start() + sound_wi.start() + + if(WEATHER_MAIN_STAGE) + sound_wo.stop() + sound_wi.stop() + + sound_ao.start() + sound_ai.start() + + if(WEATHER_WIND_DOWN_STAGE) + sound_ao.stop() + sound_ai.stop() + + sound_wo.start() + sound_wi.start() + + if(WEATHER_END_STAGE) + sound_wo.stop() + sound_wi.stop() + +/datum/weather/ash_storm/on_shelter_placed(datum/source, turf/center) + . = ..() + if(center.z in impacted_z_levels) + var/area/A = get_area(center) + inside_areas |= A + sound_ai.output_atoms |= A + sound_wi.output_atoms |= A + +/datum/weather/ash_storm/proc/is_ash_immune(atom/L) + while(L && !isturf(L)) + if(ismecha(L)) //Mechs are immune + return TRUE + if(ishuman(L)) //Are you immune? + if(is_human_ash_immune(L)) + return TRUE + L = L.loc //Matryoshka check + return FALSE //RIP you + +/datum/weather/ash_storm/proc/is_human_ash_immune(mob/living/carbon/human/H) + var/thermal_protection = H.get_thermal_protection() + if(thermal_protection >= (FIRE_IMMUNITY_MAX_TEMP_PROTECT - 15)) + return TRUE + +/datum/weather/ash_storm/weather_act(mob/living/L) + if(is_ash_immune(L)) + return + L.adjustFireLoss(4) + + +/// MARK: Heavy Ash Storm +// Radar needed to detect the difference, but shouldnt matter much +/datum/weather/ash_storm/heavy + name = "Heavy ash storm" + desc = "An even more 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." + + //lasts longer + weather_duration_lower = 800 + weather_duration_upper = 1600 + + probability = 10 + +/datum/weather/ash_storm/heavy/is_human_ash_immune(mob/living/carbon/human/H) + var/thermal_protection = H.get_thermal_protection() + if(thermal_protection >= FIRE_IMMUNITY_MAX_TEMP_PROTECT) + return TRUE + +/datum/weather/ash_storm/heavy/weather_act(mob/living/L) + if(is_ash_immune(L)) + return + L.adjustFireLoss(6) // does more damage + +/// MARK: Emberfall +//Emberfalls are the result of an ash storm passing by close to the playable area of lavaland. They have a 10% chance to trigger in place of an ash storm. +/datum/weather/ash_storm/emberfall + 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_overlay = "light_ash" + + end_message = "The emberfall slows, stops. Another layer of hardened soot to the basalt beneath your feet." + end_sound = null + + aesthetic = TRUE + probability = 25 + +/// MARK: Volcano +/datum/weather/volcano + name = "Volcanic activity" + desc = "The shifting tectonic forces on the unstable planet have caused volcanic activity in the area. New rivers/chasms will form and chunks of rock will rain from the sky." + + telegraph_message = "The ground rumbles with an ominous strength, threatening to shift below you. Seek shelter." + telegraph_duration = 600 + telegraph_sound = 'sound/weather/volcano/lavaland_volcano_warning.ogg' + + weather_message = "A massive plume of smoke and magma can be seen billowing in the distance. The ground quakes and threatens to split. Find shelter now!." + weather_duration_lower = 600 + weather_duration_upper = 1200 + weather_sound = 'sound/weather/volcano/lavaland_volcano_eruption.ogg' + + // No end message. Radar will give you the safety message on this one, or your instincts + end_duration = 300 + end_message = "" + + area_types = list(/area/lavaland/surface/outdoors, /area/lavaland/surface/gulag_rock) + target_trait = ORE_LEVEL + probability = 5 + barometer_predictable = TRUE + area_act = TRUE + // The time until the next rock falls from the sky + var/next_rubble + // Has a river already been generated this storm? + var/generated_river = FALSE + // What tiles can we hit with a rock? + var/list/valid_targets = list() + +/datum/weather/volcano/New() + next_rubble = world.time + 10 SECONDS // Short delay + . = ..() + +/datum/weather/volcano/area_act() + if(prob(1) && !generated_river) + generated_river = TRUE + var/datum/river_spawner/new_river = new /datum/river_spawner(pick(levels_by_trait(ORE_LEVEL))) + new_river.generate(nodes = 4, ignore_bridges = TRUE, warning = TRUE) + if(world.time >= next_rubble) + next_rubble = world.time + rand(3 DECISECONDS, 2 SECONDS) + var/hits = 0 + var/target + for(var/turf/T in get_area_turfs(/area/lavaland/surface/outdoors)) + if(istype(T, /turf/simulated/floor/)) // dont waste our time hitting walls + valid_targets += T + while(hits <= 150) //sling a bunch of rocks around the map + if(!valid_targets) // god forbid we run out of spots to sling rocks + break + target = pick(valid_targets) + new /obj/effect/temp_visual/rock_target(target) + hits++ + valid_targets -= target + //just play the play from the last hit in the bundle, it reaches across the map anyways + INVOKE_ASYNC(src, PROC_REF(generate_boom), target) + +//lets just fake some booms +/datum/weather/volcano/proc/generate_boom(turf/target) + sleep(ROCKFALL_DELAY) + for(var/mob/M in GLOB.player_list) + var/turf/M_turf = get_turf(M) + if(M_turf.z == target.z) + M.playsound_local(target, 'sound/effects/explosionfar.ogg', 50, 1, get_rand_frequency(), distance_multiplier = 0) + shake_camera(M, 2, 4) + +/obj/effect/temp_visual/rockfall + icon = 'icons/obj/meteor.dmi' + icon_state = "clownish" // we shouldnt be seeing this + name = "Ejected boulder" + desc = "Get out of the way!" + layer = FLY_LAYER + randomdir = FALSE + duration = ROCKFALL_DELAY + pixel_z = 270 + +/obj/effect/temp_visual/rockfall/Initialize(mapload) + . = ..() + icon_state = pick("small","large", "sharp", "dust", "small1", "large1") + animate(src, pixel_z = 0, time = duration) + SpinAnimation() + +/obj/effect/temp_visual/rock_target + icon = 'icons/mob/actions/actions.dmi' + icon_state = "sniper_zoom" + layer = BELOW_MOB_LAYER + light_range = 2 + duration = ROCKFALL_DELAY + +/obj/effect/temp_visual/rock_target/ex_act() + return + +/obj/effect/temp_visual/rock_target/Initialize(mapload) + . = ..() + SpinAnimation() + INVOKE_ASYNC(src, PROC_REF(fall)) + +/obj/effect/temp_visual/rock_target/proc/fall() + var/turf/T = get_turf(src) + playsound(T,'sound/magic/fleshtostone.ogg', 100, TRUE) + new /obj/effect/temp_visual/rockfall(T) + sleep(duration) + T = get_turf(src) + var/turf_area = get_area(T) + if(ispath(turf_area, /area/shuttle)) //prevent hitting the shuttle when it moves + log_debug("we hit a shuttle area. breaking rock") + qdel(src) + return + playsound(T, 'sound/effects/break_stone.ogg', 80, TRUE) + playsound(T, get_sfx("explosion"), 80, TRUE) + for(var/mob/living/carbon/human/H in range(10, T)) + shake_camera(H, 3, 8) + if(T.contents) + for(var/mob/living/L in T.contents) // dont want to be crushing the hazards + if(ismegafauna(L)) + L.visible_message("[L.name] easily withstands the hit of the massive rock!") + return + else + L.visible_message("[L.name] is crushed under the massive impact of the boulder!", "You are crushed as a massive weight suddenly descends upon you!", "You hear wet splatters as something is hit with a massive object!") + L.gib() + if(!islava(T) && !istype(T, /turf/simulated/floor/chasm)) // Splash harmlessly into the lava pools + for(var/obj/structure/thing in T.contents) // dont cover the tendrils + if(thing.name == "necropolis tendril") + return + T.ChangeTurf(/turf/simulated/mineral/random/high_chance/volcanic) + + + + +/// MARK: Acid Rain +/datum/weather/acid + name = "Acidic rain" + desc = "Emissions of sulfur and carbon into the atmosphere results in the formation of acid particulate in the ashen clouds. Eventually, enough collects that it will fall back down as sulfuric acid rain. NT brand shelter pods capsules are not rated for this level of acid." + + telegraph_message = "The sound of tiny drops begins to splatter against the ground, sizzling against the ash and stone. Seek shelter." + telegraph_duration = 600 + telegraph_overlay = "light_ash" + + weather_message = "Acidic rain begins to pour down in thick sheets, melting rock and flesh alike. Get inside now!" + weather_duration_lower = 600 + weather_duration_upper = 1200 + weather_overlay = "acid_rain" + + end_message = "The pitter of acidic dropples slows to silence. It should be safe to go outside now." + end_duration = 300 + end_overlay = "light_ash" + + area_types = list(/area/lavaland/surface/outdoors, /area/lavaland/surface/gulag_rock) + target_trait = ORE_LEVEL + probability = 10 + barometer_predictable = TRUE + area_act = TRUE + // how long do you get before it melts a hole? + var/melt_delay = 5 SECONDS + + var/datum/looping_sound/active_outside_acid/sound_ao = new(list(), FALSE, TRUE) + var/datum/looping_sound/active_inside_acid/sound_ai = new(list(), FALSE, TRUE) + var/datum/looping_sound/weak_outside_acid/sound_wo = new(list(), FALSE, TRUE) + var/datum/looping_sound/weak_inside_acid/sound_wi = new(list(), FALSE, TRUE) + +/datum/weather/acid/update_eligible_areas() + . = ..() + sound_ao.output_atoms = outside_areas + sound_ai.output_atoms = inside_areas + sound_wo.output_atoms = outside_areas + sound_wi.output_atoms = inside_areas + +/datum/weather/acid/update_audio() + + switch(stage) + if(WEATHER_STARTUP_STAGE) + sound_wo.start() + sound_wi.start() + + if(WEATHER_MAIN_STAGE) + sound_wo.stop() + sound_wi.stop() + + sound_ao.start() + sound_ai.start() + + if(WEATHER_WIND_DOWN_STAGE) + sound_ao.stop() + sound_ai.stop() + + sound_wo.start() + sound_wi.start() + + if(WEATHER_END_STAGE) + sound_wo.stop() + sound_wi.stop() + +/datum/weather/acid/area_act() + if(!length(GLOB.all_shelter_pods)) // don't need to act if there's nothing in the list so we don't runtime + return + for(var/turf/current_turf in GLOB.all_shelter_pods) + if(!is_mining_level(current_turf.z)) // dont want to melt pods on other Z levels + continue + if(istype(get_area(current_turf), /area/survivalpod/luxurypod)) // luxury pods are immune to the storm + continue + if(prob(2)) + current_turf.visible_message("The ceiling begins to drip as acid starts eating holes in the roof!", "You hear droplets hitting the floor as acid leaks in through the roof.") + addtimer(CALLBACK(src, PROC_REF(melt_pod), current_turf), melt_delay) + +/datum/weather/acid/on_shelter_placed(datum/source, turf/center) + . = ..() + if(center.z in impacted_z_levels) + var/area/A = get_area(center) + inside_areas |= A + sound_ai.output_atoms |= A + sound_wi.output_atoms |= A + +// lets make some holes! +/datum/weather/acid/proc/melt_pod(turf/melt_this) + var/area/new_area = GLOB.all_unique_areas[/area/lavaland/surface/outdoors] || new /area/lavaland/surface/outdoors + for(var/turf/simulated/nearby_turf in RANGE_TURFS(3, melt_this)) // danger, but probably wont make the whole pod unusable unless you're VERY unlucky + var/area/turf_area = get_area(nearby_turf) + if(prob(70) && turf_area.type == /area/survivalpod) + new_area.contents.Add(nearby_turf) + if(isfloorturf(nearby_turf)) + nearby_turf.break_tile() + if(iswallturf(nearby_turf)) + nearby_turf.dismantle_wall() + for(var/obj/machinery/sleeper/survival_pod/pod in nearby_turf.contents) + pod.visible_message("The sleeper melts away into a useless heap of junk!", "You hear something nearby collapse from the acidic rain!") + pod.Destroy() + + impacted_areas.Cut() + generate_area_list() + update_areas() + update_eligible_areas() + +/datum/weather/acid/weather_act(atom/L) + while(L && !isturf(L)) + if(ismecha(L)) //Mechs are immune + return + if(!ishuman(L) || isgrey(L)) // greys and natural fauna shouldnt be affected by acid rain + return + var/mob/living/carbon/human/H = L + if(!H.wear_suit || !H.head) // No need to check further if they dont have clothing on + H.adjustFireLoss(2) + H.adjustBruteLoss(2) + return + if(!(H.head.resistance_flags & ACID_PROOF) && !(H.wear_suit.resistance_flags & ACID_PROOF)) + H.adjustFireLoss(2) + H.adjustBruteLoss(2) + L = L.loc //Matryoshka check + +/// MARK: Wind Storm +/datum/weather/wind + name = "High-velocity wind" + desc = "High-pressure barometrics in the area have caused a radical change in air pressure, resulting in high-speed winds in the immediate vicinity." + + telegraph_message = "The wind begins to pick up, whipping against your body with an ominous intensity. Seek shelter." + telegraph_duration = 600 + telegraph_overlay = "light_ash" + + weather_message = "The wind rises into a furious rage, kicking up dirt and ash in its wake. Get inside now!" + weather_duration_lower = 600 + weather_duration_upper = 1200 + weather_overlay = "wind" + + end_message = "The wind calms into its normal rhythms, dust settling back to the ashen surface. It should be safe to go outside now." + end_duration = 300 + end_overlay = "light_ash" + + area_types = list(/area/lavaland/surface/outdoors, /area/lavaland/surface/gulag_rock) + target_trait = ORE_LEVEL + probability = 25 + barometer_predictable = TRUE + var/wind_dir + var/next_dir_change + + 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) + var/datum/looping_sound/weak_inside_ashstorm/sound_wi = new(list(), FALSE, TRUE) + +/datum/weather/wind/update_eligible_areas() + . = ..() + sound_ao.output_atoms = outside_areas + sound_ai.output_atoms = inside_areas + sound_wo.output_atoms = outside_areas + sound_wi.output_atoms = inside_areas + +/datum/weather/wind/update_audio() + switch(stage) + if(WEATHER_STARTUP_STAGE) + sound_wo.start() + sound_wi.start() + + if(WEATHER_MAIN_STAGE) + sound_wo.stop() + sound_wi.stop() + + sound_ao.start() + sound_ai.start() + + if(WEATHER_WIND_DOWN_STAGE) + sound_ao.stop() + sound_ai.stop() + + sound_wo.start() + sound_wi.start() + + if(WEATHER_END_STAGE) + sound_wo.stop() + sound_wi.stop() + +/datum/weather/wind/on_shelter_placed(datum/source, turf/center) + . = ..() + if(center.z in impacted_z_levels) + var/area/A = get_area(center) + inside_areas |= A + sound_ai.output_atoms |= A + sound_wi.output_atoms |= A + +/datum/weather/wind/start() //give it our custom overlay + custom_overlay = 'icons/effects/tile_effects.dmi' + wind_dir = pick(GLOB.alldirs) + overlay_dir = wind_dir + next_dir_change = world.time + rand(10 SECONDS, 30 SECONDS) + . = ..() + +/datum/weather/wind/wind_down() // back to normal overlay + custom_overlay = null + overlay_dir = null + . = ..() + +/datum/weather/wind/weather_act(mob/living/L) + if(next_dir_change <= world.time) + next_dir_change = world.time + rand(10 SECONDS, 30 SECONDS) + wind_dir = pick(GLOB.alldirs) + overlay_dir = wind_dir + update_areas() + if(ismecha(L)) //Mechs are immune + return + if(ishuman(L)) // lets not push around lavaland mobs + L.air_push(wind_dir, MOVE_FORCE_NORMAL * 2) + +#undef ROCKFALL_DELAY + diff --git a/code/datums/weather/weather_types/radiation_storm.dm b/code/datums/weather/weather_types/radiation_storm.dm index 442e5950c44..9437aec9161 100644 --- a/code/datums/weather/weather_types/radiation_storm.dm +++ b/code/datums/weather/weather_types/radiation_storm.dm @@ -16,7 +16,7 @@ end_duration = 100 end_message = "The air seems to be cooling off again." var/pre_maint_all_access - area_type = /area + area_types = list(/area) protected_areas = list( /area/station/maintenance, /area/station/turret_protected/ai_upload, diff --git a/code/datums/weather/weather_types/solar_flare.dm b/code/datums/weather/weather_types/solar_flare.dm index eb0834dc246..3982c409035 100644 --- a/code/datums/weather/weather_types/solar_flare.dm +++ b/code/datums/weather/weather_types/solar_flare.dm @@ -14,7 +14,7 @@ end_duration = 10 // wind_down() does not do anything for this event, so we just trigger end() semi-immediately end_message = null - area_type = /area // read generate_area_list() as well below + area_types = list(/area) // read generate_area_list() as well below protected_areas = list(/area/shuttle/arrival/station) target_trait = REACHABLE_SPACE_ONLY immunity_type = "burn" diff --git a/code/game/machinery/radar.dm b/code/game/machinery/radar.dm new file mode 100644 index 00000000000..2e0273b09cb --- /dev/null +++ b/code/game/machinery/radar.dm @@ -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("[W.name] detected settling over the sector. No further action required.", name, "Supply") + else + radio.autosay("Ash Storm detected converging over the local sector. Please finish any surface excavations.", name, "Supply") + else + radio.autosay("[W.name] detected converging over the local sector. Please finish any surface excavations.", 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("Inclement weather has reached the local sector. Seek shelter immediately.", 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("Inclement weather has dispersed. It is now safe to resume surface excavations.", 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("Weather patterns successfully analyzed. Predicted weather event in [difference_rounded]: [next_weather.name] ", 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("Weather patterns successfully analyzed. Predicted weather event in [difference_rounded]: ash storm ", name, "Supply") + dont_announce = TRUE + correct_prediction = FALSE + else + radio.autosay("Weather patterns successfully analyzed. Predicted weather event in [difference_rounded]: [next_weather.name] ", 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) + . += "The framework is damaged, and needs welding." + if(RADAR_NEEDS_PLASTEEL) + . += "The framework needs new plasteel plating." + if(RADAR_NEEDS_WRENCH) + . += "The plating needs wrenching into place." + if(RADAR_NEEDS_SCREWDRIVER) + . += "The cover screws are loose." + +// 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, "You mend the damaged framework.") + 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, "You need 10 sheets of plasteel.") + return ITEM_INTERACT_COMPLETE + + to_chat(user, "You add new plating to the framework.") + 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, "You secure the plating to the framework.") + 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, "You screw the covers back into place.") + 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 diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 3bbf948cb05..6b0267a08b3 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -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 diff --git a/code/game/objects/structures/lavaland/necropolis_tendril.dm b/code/game/objects/structures/lavaland/necropolis_tendril.dm index 8550806b072..dfe5dc3f78e 100644 --- a/code/game/objects/structures/lavaland/necropolis_tendril.dm +++ b/code/game/objects/structures/lavaland/necropolis_tendril.dm @@ -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) diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index 8538d568f2f..0f088383be4 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -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) diff --git a/code/game/turfs/simulated/river.dm b/code/game/turfs/simulated/river.dm index 31c1b95d47b..2378579bf5b 100644 --- a/code/game/turfs/simulated/river.dm +++ b/code/game/turfs/simulated/river.dm @@ -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 diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm index 9c9d2ca3fb4..5f15ccb3a9f 100644 --- a/code/modules/mining/equipment/survival_pod.dm +++ b/code/modules/mining/equipment/survival_pod.dm @@ -73,14 +73,19 @@ log_admin("[key_name(usr)] activated a bluespace capsule away from the mining level at [T.x], [T.y], [T.z]") template.load(deploy_location, centered = TRUE) new /obj/effect/particle_effect/smoke(get_turf(src)) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_SHELTER_PLACED, T) qdel(src) /obj/item/survivalcapsule/luxury name = "luxury bluespace shelter capsule" - desc = "An exorbitantly expensive luxury suite stored within a pocket of bluespace." + desc = "An exorbitantly expensive luxury suite stored within a pocket of bluespace. It is made of durable materials more capable of withstanding harsh weather over standard capsules." origin_tech = "engineering=3;bluespace=4" template_id = "shelter_beta" +// for things that shouldnt affect specifically the luxury pods +/area/survivalpod/luxurypod + name = "\improper Luxury Shelter" + //Pod turfs and objects //Window diff --git a/code/modules/mining/lavaland/loot/legion_loot.dm b/code/modules/mining/lavaland/loot/legion_loot.dm index 4eef64984e4..01b1788c9fc 100644 --- a/code/modules/mining/lavaland/loot/legion_loot.dm +++ b/code/modules/mining/lavaland/loot/legion_loot.dm @@ -71,7 +71,7 @@ var/datum/weather/A for(var/V in SSweather.processing) var/datum/weather/W = V - if((user_turf.z in W.impacted_z_levels) && W.area_type == user_area.type) + if((user_turf.z in W.impacted_z_levels) && is_type_in_list(user_area, W.area_types)) A = W break @@ -119,7 +119,7 @@ var/power_boosted = FALSE for(var/V in SSweather.processing) var/datum/weather/W = V - if((target_turf.z in W.impacted_z_levels) && W.area_type == target_area.type) + if((target_turf.z in W.impacted_z_levels) && is_type_in_list(target_area, W.area_types)) power_boosted = TRUE break playsound(src, 'sound/magic/lightningshock.ogg', 10, TRUE, extrarange = SILENCED_SOUND_EXTRARANGE, falloff_distance = 0) diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index baf31a94e80..f19fe80adb6 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -570,14 +570,13 @@ mobile_port.loc = S1.loc mobile_port.dir = S1.dir - //update mining and labor shuttle ash storm audio + //update mining and labor shuttle weather audio if(mobile_port.id in list("mining", "laborcamp")) for(var/zlvl in levels_by_trait(ORE_LEVEL)) - var/datum/weather/ash_storm/W = SSweather.get_weather(zlvl, /area/lavaland/surface/outdoors) + var/datum/weather/W = SSweather.get_weather(zlvl, /area/lavaland/surface/outdoors) if(W) W.update_eligible_areas() W.update_audio() - mobile_port.unlockPortDoors(S1) /obj/docking_port/mobile/proc/is_turf_blacklisted_for_transit(turf/T) diff --git a/icons/effects/weather_effects.dmi b/icons/effects/weather_effects.dmi index c084ca04b5b..622153b2f2a 100644 Binary files a/icons/effects/weather_effects.dmi and b/icons/effects/weather_effects.dmi differ diff --git a/icons/obj/machines/doppler_tower.dmi b/icons/obj/machines/doppler_tower.dmi new file mode 100644 index 00000000000..1666493cbab Binary files /dev/null and b/icons/obj/machines/doppler_tower.dmi differ diff --git a/paradise.dme b/paradise.dme index 627db15476a..ca8be1fdd19 100644 --- a/paradise.dme +++ b/paradise.dme @@ -728,8 +728,8 @@ #include "code\datums\uplink_items\uplink_special.dm" #include "code\datums\uplink_items\uplink_traitor.dm" #include "code\datums\weather\weather_datum.dm" -#include "code\datums\weather\weather_types\ash_storm.dm" #include "code\datums\weather\weather_types\floor_is_lava.dm" +#include "code\datums\weather\weather_types\lavaland_weather.dm" #include "code\datums\weather\weather_types\radiation_storm.dm" #include "code\datums\weather\weather_types\snow_storm.dm" #include "code\datums\weather\weather_types\solar_flare.dm" @@ -943,6 +943,7 @@ #include "code\game\machinery\portable_tag_turret.dm" #include "code\game\machinery\portable_turret.dm" #include "code\game\machinery\quantum_pad.dm" +#include "code\game\machinery\radar.dm" #include "code\game\machinery\recharger.dm" #include "code\game\machinery\rechargestation.dm" #include "code\game\machinery\recycler.dm" diff --git a/sound/weather/acid/inside/active_end.ogg b/sound/weather/acid/inside/active_end.ogg new file mode 100644 index 00000000000..319a8a314ea Binary files /dev/null and b/sound/weather/acid/inside/active_end.ogg differ diff --git a/sound/weather/acid/inside/active_mid1.ogg b/sound/weather/acid/inside/active_mid1.ogg new file mode 100644 index 00000000000..5f172c534f8 Binary files /dev/null and b/sound/weather/acid/inside/active_mid1.ogg differ diff --git a/sound/weather/acid/inside/active_start.ogg b/sound/weather/acid/inside/active_start.ogg new file mode 100644 index 00000000000..680c3a7e58c Binary files /dev/null and b/sound/weather/acid/inside/active_start.ogg differ diff --git a/sound/weather/acid/inside/weak_end.ogg b/sound/weather/acid/inside/weak_end.ogg new file mode 100644 index 00000000000..0d4bf2b5fdb Binary files /dev/null and b/sound/weather/acid/inside/weak_end.ogg differ diff --git a/sound/weather/acid/inside/weak_mid1.ogg b/sound/weather/acid/inside/weak_mid1.ogg new file mode 100644 index 00000000000..75f539aebe4 Binary files /dev/null and b/sound/weather/acid/inside/weak_mid1.ogg differ diff --git a/sound/weather/acid/inside/weak_start.ogg b/sound/weather/acid/inside/weak_start.ogg new file mode 100644 index 00000000000..9822442b4f3 Binary files /dev/null and b/sound/weather/acid/inside/weak_start.ogg differ diff --git a/sound/weather/acid/outside/active_end.ogg b/sound/weather/acid/outside/active_end.ogg new file mode 100644 index 00000000000..59a57c41341 Binary files /dev/null and b/sound/weather/acid/outside/active_end.ogg differ diff --git a/sound/weather/acid/outside/active_mid1.ogg b/sound/weather/acid/outside/active_mid1.ogg new file mode 100644 index 00000000000..68b17ddccf7 Binary files /dev/null and b/sound/weather/acid/outside/active_mid1.ogg differ diff --git a/sound/weather/acid/outside/active_start.ogg b/sound/weather/acid/outside/active_start.ogg new file mode 100644 index 00000000000..c67d950250f Binary files /dev/null and b/sound/weather/acid/outside/active_start.ogg differ diff --git a/sound/weather/acid/outside/weak_end.ogg b/sound/weather/acid/outside/weak_end.ogg new file mode 100644 index 00000000000..980d7187544 Binary files /dev/null and b/sound/weather/acid/outside/weak_end.ogg differ diff --git a/sound/weather/acid/outside/weak_mid1.ogg b/sound/weather/acid/outside/weak_mid1.ogg new file mode 100644 index 00000000000..a598b712401 Binary files /dev/null and b/sound/weather/acid/outside/weak_mid1.ogg differ diff --git a/sound/weather/acid/outside/weak_start.ogg b/sound/weather/acid/outside/weak_start.ogg new file mode 100644 index 00000000000..9424a60c6dc Binary files /dev/null and b/sound/weather/acid/outside/weak_start.ogg differ diff --git a/sound/weather/volcano/lavaland_volcano_eruption.ogg b/sound/weather/volcano/lavaland_volcano_eruption.ogg new file mode 100644 index 00000000000..88ef0d04da0 Binary files /dev/null and b/sound/weather/volcano/lavaland_volcano_eruption.ogg differ diff --git a/sound/weather/volcano/lavaland_volcano_warning.ogg b/sound/weather/volcano/lavaland_volcano_warning.ogg new file mode 100644 index 00000000000..f0d4abfc35f Binary files /dev/null and b/sound/weather/volcano/lavaland_volcano_warning.ogg differ