From dbebed0075d45644216ffc6687d1f88995721d9f Mon Sep 17 00:00:00 2001 From: Alberyk Date: Sat, 30 Oct 2021 09:22:18 -0300 Subject: [PATCH] Ports overmap hazards (#12581) --- .drone.yml | 4 +- .travis.yml | 2 +- aurorastation.dme | 3 +- code/__defines/lists.dm | 2 +- code/__defines/space_sectors.dm | 5 +- code/_helpers/functional.dm | 16 ++ code/controllers/subsystems/event.dm | 3 + code/game/gamemodes/events/dust.dm | 120 --------- code/game/gamemodes/meteor/meteor.dm | 123 ++++++--- code/game/gamemodes/meteor/meteors.dm | 345 ++++++++++++------------- code/game/turfs/space/space.dm | 4 +- code/game/turfs/turf.dm | 26 +- code/modules/events/carp_migration.dm | 21 +- code/modules/events/dust.dm | 23 -- code/modules/events/event_container.dm | 2 +- code/modules/events/grid_check.dm | 2 +- code/modules/events/meteors.dm | 166 ++++++++---- code/modules/events/radiation_storm.dm | 6 +- code/modules/events/rogue_drones.dm | 13 +- code/modules/events/wallrot.dm | 4 +- code/modules/overmap/_defines.dm | 3 + code/modules/overmap/events/event.dm | 297 +++++++++++++++++++++ icons/obj/overmap.dmi | Bin 2177 -> 39997 bytes icons/turf/space.dmi | Bin 34861 -> 40392 bytes maps/_common/mapsystem/map.dm | 25 ++ maps/aurora/code/aurora.dm | 1 + maps/exodus/code/exodus.dm | 1 + maps/runtime/code/runtime.dm | 3 + maps/runtime/runtime-1.dmm | 16 +- maps/runtime/runtime-2.dmm | 16 +- maps/runtime/runtime-3.dmm | 30 ++- 31 files changed, 800 insertions(+), 482 deletions(-) delete mode 100644 code/game/gamemodes/events/dust.dm delete mode 100644 code/modules/events/dust.dm create mode 100644 code/modules/overmap/events/event.dm diff --git a/.drone.yml b/.drone.yml index ce3c6f52a58..67e19d57d89 100644 --- a/.drone.yml +++ b/.drone.yml @@ -9,7 +9,7 @@ clone: environment: MACRO_COUNT: 0 GENDER_COUNT: 6 - TO_WORLD_COUNT: 211 + TO_WORLD_COUNT: 209 trigger: branch: @@ -175,6 +175,6 @@ steps: --- kind: signature -hmac: dff04fdff79e6ed2acdbe84a55f4c13f57655f345f56be03bf6d9c433cb65422 +hmac: aa5f81d300bb1f01656d04254a788970d593b10792ac97b91161ec95ce622b1a ... diff --git a/.travis.yml b/.travis.yml index 96bfa28da93..bf895556930 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ env: BYOND_MINOR="1517" MACRO_COUNT=0 GENDER_COUNT=6 - TO_WORLD_COUNT=211 + TO_WORLD_COUNT=209 FLYWAY_BUILD="5.2.4" NODE_VERSION=10 RUST_G_VERSION="0.4.2+a2" diff --git a/aurorastation.dme b/aurorastation.dme index 9c6cb19dac5..072763f8211 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -550,7 +550,6 @@ #include "code\game\gamemodes\endgame\supermatter_cascade\universe.dm" #include "code\game\gamemodes\events\black_hole.dm" #include "code\game\gamemodes\events\clang.dm" -#include "code\game\gamemodes\events\dust.dm" #include "code\game\gamemodes\events\power_failure.dm" #include "code\game\gamemodes\events\wormholes.dm" #include "code\game\gamemodes\events\holidays\Christmas.dm" @@ -1724,7 +1723,6 @@ #include "code\modules\events\ccia_general_notice.dm" #include "code\modules\events\comms_blackout.dm" #include "code\modules\events\communications_blackout.dm" -#include "code\modules\events\dust.dm" #include "code\modules\events\electrical_storm.dm" #include "code\modules\events\event.dm" #include "code\modules\events\event_container.dm" @@ -2509,6 +2507,7 @@ #include "code\modules\overmap\README.dm" #include "code\modules\overmap\sectors.dm" #include "code\modules\overmap\spacetravel.dm" +#include "code\modules\overmap\events\event.dm" #include "code\modules\overmap\ships\landable.dm" #include "code\modules\overmap\ships\ship.dm" #include "code\modules\overmap\ships\computers\engine_control.dm" diff --git a/code/__defines/lists.dm b/code/__defines/lists.dm index 0fd4677eb3f..2df9fdd950f 100644 --- a/code/__defines/lists.dm +++ b/code/__defines/lists.dm @@ -1,7 +1,7 @@ #define LAZYINITLIST(L) if (!L) L = list() #define UNSETEMPTY(L) if (L && !L.len) L = null -#define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } } +#define LAZYREMOVE(L, I) if(L) { L -= I; if(!length(L)) { L = null; } } #define LAZYADD(L, I) if(!L) { L = list(); } L += I; #define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null) #define LAZYLEN(L) length(L) diff --git a/code/__defines/space_sectors.dm b/code/__defines/space_sectors.dm index a9712a81b90..8fa686928c9 100644 --- a/code/__defines/space_sectors.dm +++ b/code/__defines/space_sectors.dm @@ -13,4 +13,7 @@ #define SECTOR_NRRAHRAHUL "Nrrahrahul" #define SECTOR_GAKAL "Gakal" #define SECTOR_UUEOAESA "Uueoa-Esa" -#define ALL_BADLAND_SECTORS list(SECTOR_VALLEY_HALE, SECTOR_BADLANDS, SECTOR_NEW_ANKARA, SECTOR_AEMAQ, SECTOR_SRANDMARR, SECTOR_NRRAHRAHUL, SECTOR_GAKAL, SECTOR_UUEOAESA) \ No newline at end of file +#define ALL_BADLAND_SECTORS list(SECTOR_VALLEY_HALE, SECTOR_BADLANDS, SECTOR_NEW_ANKARA, SECTOR_AEMAQ, SECTOR_SRANDMARR, SECTOR_NRRAHRAHUL, SECTOR_GAKAL, SECTOR_UUEOAESA) + + +#define ALL_POSSIBLE_SECTORS list(ALL_TAU_CETI_SECTORS, ALL_BADLAND_SECTORS) \ No newline at end of file diff --git a/code/_helpers/functional.dm b/code/_helpers/functional.dm index 5de219459db..7fbf9518337 100644 --- a/code/_helpers/functional.dm +++ b/code/_helpers/functional.dm @@ -29,5 +29,21 @@ if(LAZYLEN(extra_arguments)) {\ return TRUE return FALSE +/proc/can_not_locate(var/atom/container, var/container_thing) + return !(locate(container_thing) in container) // We could just do !can_locate(container, container_thing) but BYOND is pretty awful when it comes to deep proc calls + +/proc/where(var/list/list_to_filter, var/list/predicates, var/list/extra_predicate_input) + . = list() + for(var/entry in list_to_filter) + var/predicate_input + if(extra_predicate_input) + predicate_input = (list(entry) + extra_predicate_input) + else + predicate_input = entry + + if(all_predicates_true(predicate_input, predicates)) + . += entry + + #undef PREPARE_ARGUMENTS #undef PREPARE_INPUT diff --git a/code/controllers/subsystems/event.dm b/code/controllers/subsystems/event.dm index d045825c394..a36fb8a1afc 100644 --- a/code/controllers/subsystems/event.dm +++ b/code/controllers/subsystems/event.dm @@ -40,6 +40,9 @@ var/datum/controller/subsystem/events/SSevents ) initialized = TRUE + if(current_map.use_overmap) + overmap_event_handler.create_events(current_map.overmap_z, current_map.overmap_size, current_map.overmap_event_areas) + /datum/controller/subsystem/events/Recover() active_events = SSevents.active_events finished_events = SSevents.finished_events diff --git a/code/game/gamemodes/events/dust.dm b/code/game/gamemodes/events/dust.dm deleted file mode 100644 index 258ac9d6aff..00000000000 --- a/code/game/gamemodes/events/dust.dm +++ /dev/null @@ -1,120 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 - -/* -Space dust -Commonish random event that causes small clumps of "space dust" to hit the station at high speeds. -No command report on the common version of this event. -The "dust" will damage the hull of the station causin minor hull breaches. -*/ - -/proc/dust_swarm(var/strength = "weak") - var/numbers = 1 - switch(strength) - if("weak") - numbers = rand(2,4) - for(var/i = 0 to numbers) - new/obj/effect/space_dust/weak() - if("norm") - numbers = rand(5,10) - for(var/i = 0 to numbers) - new/obj/effect/space_dust() - if("strong") - numbers = rand(10,15) - for(var/i = 0 to numbers) - new/obj/effect/space_dust/strong() - if("super") - numbers = rand(15,25) - for(var/i = 0 to numbers) - new/obj/effect/space_dust/super() - return - - -/obj/effect/space_dust - name = "Space Dust" - desc = "Dust in space." - icon = 'icons/obj/meteor.dmi' - icon_state = "dust" - density = 1 - anchored = 1 - var/strength = 2 //ex_act severity number - var/life = 2 //how many things we hit before qdel(src) - - weak - strength = 3 - life = 1 - - strong - strength = 1 - life = 6 - - super - strength = 1 - life = 40 - - - New() - ..() - var/startx = 0 - var/starty = 0 - var/endy = 0 - var/endx = 0 - var/startside = pick(cardinal) - - switch(startside) - if(NORTH) - starty = world.maxy-(TRANSITIONEDGE+1) - startx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1)) - endy = TRANSITIONEDGE - endx = rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE) - if(EAST) - starty = rand((TRANSITIONEDGE+1),world.maxy-(TRANSITIONEDGE+1)) - startx = world.maxx-(TRANSITIONEDGE+1) - endy = rand(TRANSITIONEDGE, world.maxy-TRANSITIONEDGE) - endx = TRANSITIONEDGE - if(SOUTH) - starty = (TRANSITIONEDGE+1) - startx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1)) - endy = world.maxy-TRANSITIONEDGE - endx = rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE) - if(WEST) - starty = rand((TRANSITIONEDGE+1), world.maxy-(TRANSITIONEDGE+1)) - startx = (TRANSITIONEDGE+1) - endy = rand(TRANSITIONEDGE,world.maxy-TRANSITIONEDGE) - endx = world.maxx-TRANSITIONEDGE - var/z_level = pick(current_map.station_levels) - var/goal = locate(endx, endy, z_level) - src.x = startx - src.y = starty - src.z = z_level - spawn(0) - walk_towards(src, goal, 1) - return - - touch_map_edge() - qdel(src) - - Collide(atom/A) - . = ..() - spawn(0) - if(prob(50)) - for(var/mob/M in range(10, src)) - if(!M.stat && !istype(M, /mob/living/silicon/ai)) - shake_camera(M, 3, 1) - if (A) - playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1) - - if(ismob(A)) - A.ex_act(strength)//This should work for now I guess - else if(!istype(A,/obj/machinery/power/emitter) && !istype(A,/obj/machinery/field_generator)) //Protect the singularity from getting released every round! - A.ex_act(strength) //Changing emitter/field gen ex_act would make it immune to bombs and C4 - - life-- - if(life <= 0) - walk(src,0) - qdel(src) - return 0 - return - - ex_act(severity) - qdel(src) - return diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm index a3e99845cb3..aa8a5a3c193 100644 --- a/code/game/gamemodes/meteor/meteor.dm +++ b/code/game/gamemodes/meteor/meteor.dm @@ -1,45 +1,100 @@ -#define METEOR_DELAY 6000 +// The following four defines can be used to tweak the difficulty of the gamemode +#define METEOR_FAILSAFE_THRESHOLD 45 MINUTES // Failsafe that guarantees Severity will be at least 15 when the round hits this time. +// In general, a PVE oriented game mode. A middle ground between Extended and actual antagonist based rounds. /datum/game_mode/meteor name = "Meteor" - round_description = "The space station has been stuck in a major meteor shower." - extended_round_description = "The station is on an unavoidable collision course with an asteroid field. The station will be continuously slammed with meteors, venting hallways, rooms, and ultimately destroying a majority of the basic life functions of the entire structure. Coordinate with your fellow crew members to survive the inevitable destruction of the station and get back home in one piece!" + round_description = "You are about to enter an asteroid belt!" + extended_round_description = "We are on an unavoidable collision course with an asteroid field. You have only a moment to prepare before you are barraged by dust and meteors. As if it was not enough, all kinds of negative events seem to happen more frequently. Good Luck." config_tag = "meteor" - required_players = 0 + required_players = 15 // Definitely not good for low-pop votable = 0 - deny_respawn = 1 - var/next_wave = METEOR_DELAY + shuttle_delay = 2 + var/next_wave = INFINITY // Set in post_setup() correctly to take into account potential longer pre-start times. + var/alert_sent = 0 + var/meteor_severity = 1 // Slowly increases the tension at the beginning of meteor strikes. Prevents "tunguska on first wave" style problems. + var/failsafe_triggered = 0 + var/alert_title + var/alert_text + var/start_text + var/maximal_severity = 40 + var/meteor_wave_delay = 30 SECONDS //minimum wait between waves in tenths of seconds + var/meteor_grace_period = 15 MINUTES //waves will not arrive until this far into round + + // Moved these from defines to variables, to allow for in-round tweaking via varedit: + var/escalation_probability = 45 + var/send_admin_broadcasts = TRUE // Enables debugging/information mode, sending admin messages when waves occur and when severity escalates. + + event_delay_mod_moderate = 0.5 // As a bonus, more frequent events. + event_delay_mod_major = 0.3 + + +/datum/game_mode/meteor/proc/set_meteor_severity(value) + meteor_severity = Clamp(value, 0, maximal_severity) + +/datum/game_mode/meteor/proc/set_meteor_wave_delay(value) + meteor_wave_delay = max(10 SECONDS, value) + +/datum/game_mode/meteor/post_setup() + ..() + alert_title = "Automated Beacon AB-[rand(10, 99)]" + alert_text = "This is an automatic warning. Your facility: [current_map.full_name] is on a collision course with a nearby asteroid belt. Estimated time until impact is: [meteor_grace_period / 1200] MINUTES. Please perform necessary actions to secure your ship or station from the threat. Have a nice day." + start_text = "This is an automatic warning. Your facility: [current_map.full_name] has entered an asteroid belt. Estimated time until you leave the belt is: [rand(20,30)] HOURS and [rand(1, 59)] MINUTES. For your safety, please consider changing course or using protective equipment. Have a nice day." + next_wave = round_duration_in_ticks + meteor_grace_period + +/datum/game_mode/meteor/proc/on_meteor_warn() + alert_sent = 1 + command_announcement.Announce(alert_text, alert_title) + +/datum/game_mode/meteor/proc/on_enter_field() + alert_sent = 2 + command_announcement.Announce(start_text, alert_title) + if(current_map.use_overmap) + var/area/map = locate(/area/overmap) + for(var/turf/T in map) + T.overlays += image('icons/obj/overmap.dmi', "meteor[rand(1,4)]") + next_wave = round_duration_in_ticks + meteor_wave_delay /datum/game_mode/meteor/process() - if(world.time >= next_wave) - next_wave = world.time + meteor_wave_delay - spawn() spawn_meteors(6) + // Send an alert halfway through the round. + if((round_duration_in_ticks >= (next_wave / 2)) && !alert_sent) + on_meteor_warn() + // And then another one when the meteors start flying around. + if((round_duration_in_ticks >= next_wave) && (alert_sent == 1)) + on_enter_field() + if((round_duration_in_ticks >= METEOR_FAILSAFE_THRESHOLD) && (meteor_severity < 15) && !failsafe_triggered) + log_and_message_admins("Meteor mode severity failsafe triggered: Severity forced to 15.") + meteor_severity = 15 + failsafe_triggered = 1 -/datum/game_mode/meteor/declare_completion() - var/text - var/survivors = 0 - for(var/mob/living/player in player_list) - if(player.stat != DEAD) - var/turf/location = get_turf(player.loc) - if(!location) - continue - if(istype(location.loc.type, /area/shuttle/escape)) - text += "
[player.real_name] escaped on the emergency shuttle" - if(istype(location.loc.type, /area/shuttle/escape_pod)) - text += "
[player.real_name] escaped in a life pod." - else - text += "
[player.real_name] survived but is stranded without any hope of rescue." - survivors++ + if(round_duration_in_ticks >= next_wave) + next_wave = round_duration_in_ticks + meteor_wave_delay + // Starts as barely noticeable dust impact, ends as barrage of most severe meteor types the code has to offer. Have fun. + spawn() + spawn_meteors(meteor_severity, get_meteor_types(), pick(cardinal), pick(current_map.station_levels)) + var/escalated = FALSE + if(prob(escalation_probability) && (meteor_severity < maximal_severity)) + meteor_severity++ + escalated = TRUE + if(send_admin_broadcasts) + log_and_message_admins("Meteor: Wave fired. Escalation: [escalated ? "Yes" : "No"]. Severity: [meteor_severity]/[maximal_severity]") - if(survivors) - to_world("The following survived the meteor storm:[text]") - else - to_world("Nobody survived the meteor storm!") +/datum/game_mode/meteor/proc/get_meteor_types() + switch(meteor_severity) + if(1 to 9) + return meteors_dust + if(10 to 19) + return meteors_normal + if(20 to 29) + return meteors_threatening + if(30 to 34) + return meteors_catastrophic + if(35 to 39) + return meteors_armageddon + if(40 to INFINITY) + return meteors_cataclysm + // Just in case we /somehow/ get here (looking at you, varedit) + return meteors_normal - feedback_set_details("round_end_result","end - evacuation") - feedback_set("round_end_result",survivors) - ..() - return 1 - -#undef METEOR_DELAY +#undef METEOR_FAILSAFE_THRESHOLD diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm index ce44ea93f00..d30821024c9 100644 --- a/code/game/gamemodes/meteor/meteors.dm +++ b/code/game/gamemodes/meteor/meteors.dm @@ -1,158 +1,171 @@ -/var/const/meteor_wave_delay = 625 //minimum wait between waves in tenths of seconds -//set to at least 100 unless you want evarr ruining every round +//Meteor groups, used for various random events and the Meteor gamemode. -/var/const/meteors_in_wave = 50 -/var/const/meteors_in_small_wave = 10 +// Dust, used by space dust event and during earliest stages of meteor mode. +/var/list/meteors_dust = list(/obj/effect/meteor/dust) +// Standard meteors, used during early stages of the meteor gamemode. +/var/list/meteors_normal = list(\ + /obj/effect/meteor/medium=8,\ + /obj/effect/meteor/dust=3,\ + /obj/effect/meteor/irradiated=3,\ + /obj/effect/meteor/big=3,\ + /obj/effect/meteor/flaming=1,\ + /obj/effect/meteor/golden=1,\ + /obj/effect/meteor/silver=1\ + ) -/proc/spawn_meteors(var/number = meteors_in_small_wave) +// Threatening meteors, used during the meteor gamemode. +/var/list/meteors_threatening = list(\ + /obj/effect/meteor/big=10,\ + /obj/effect/meteor/medium=5,\ + /obj/effect/meteor/golden=3,\ + /obj/effect/meteor/silver=3,\ + /obj/effect/meteor/flaming=3,\ + /obj/effect/meteor/irradiated=3,\ + /obj/effect/meteor/emp=3\ + ) + +// Catastrophic meteors, pretty dangerous without shields and used during the meteor gamemode. +/var/list/meteors_catastrophic = list(\ + /obj/effect/meteor/big=75,\ + /obj/effect/meteor/flaming=10,\ + /obj/effect/meteor/irradiated=10,\ + /obj/effect/meteor/emp=10,\ + /obj/effect/meteor/medium=5,\ + /obj/effect/meteor/golden=4,\ + /obj/effect/meteor/silver=4 + ) + +// Armageddon meteors, very dangerous, and currently used only during the meteor gamemode. +/var/list/meteors_armageddon = list(\ + /obj/effect/meteor/big=25,\ + /obj/effect/meteor/flaming=10,\ + /obj/effect/meteor/irradiated=10,\ + /obj/effect/meteor/emp=10,\ + /obj/effect/meteor/medium=3,\ + /obj/effect/meteor/golden=2,\ + /obj/effect/meteor/silver=2\ + ) + +// Cataclysm meteor selection. Very very dangerous and effective even against shields. Used in late game meteor gamemode only. +/var/list/meteors_cataclysm = list(\ + /obj/effect/meteor/big=40,\ + /obj/effect/meteor/emp=20,\ + /obj/effect/meteor/irradiated=10,\ + /obj/effect/meteor/golden=10,\ + /obj/effect/meteor/silver=10,\ + /obj/effect/meteor/flaming=10,\ + /obj/effect/meteor/supermatter=1\ + ) + +/proc/spawn_meteors(var/number = 10, var/list/meteortypes, var/startSide, var/zlevel) for(var/i = 0; i < number; i++) - spawn(0) - spawn_meteor() + spawn_meteor(meteortypes, startSide, zlevel) -/proc/spawn_meteor(var/ship_debris_only = FALSE) - var/startx +/proc/spawn_meteor(var/list/meteortypes, var/startSide, var/zlevel) + var/turf/pickedstart = spaceDebrisStartLoc(startSide, zlevel) + var/turf/pickedgoal = spaceDebrisFinishLoc(startSide, zlevel) + + var/Me = pickweight(meteortypes) + var/obj/effect/meteor/M = new Me(pickedstart) + M.dest = pickedgoal + spawn(0) + walk_towards(M, M.dest, 3) + return + +/proc/spaceDebrisStartLoc(startSide, Z) var/starty - var/endx - var/endy - var/turf/pickedstart - var/turf/pickedgoal - var/max_i = 10//number of tries to spawn meteor. + var/startx + switch(startSide) + if(NORTH) + starty = world.maxy-(TRANSITIONEDGE+1) + startx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1)) + if(EAST) + starty = rand((TRANSITIONEDGE+1),world.maxy-(TRANSITIONEDGE+1)) + startx = world.maxx-(TRANSITIONEDGE+1) + if(SOUTH) + starty = (TRANSITIONEDGE+1) + startx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1)) + if(WEST) + starty = rand((TRANSITIONEDGE+1), world.maxy-(TRANSITIONEDGE+1)) + startx = (TRANSITIONEDGE+1) + var/turf/T = locate(startx, starty, Z) + return T - switch(pick(1,2,3,4)) - if(1) //NORTH - starty = world.maxy-(TRANSITIONEDGE+2) - startx = rand((TRANSITIONEDGE+2), world.maxx-(TRANSITIONEDGE+2)) +/proc/spaceDebrisFinishLoc(startSide, Z) + var/endy + var/endx + switch(startSide) + if(NORTH) endy = TRANSITIONEDGE endx = rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE) - if(2) //EAST - starty = rand((TRANSITIONEDGE+2),world.maxy-(TRANSITIONEDGE+1)) - startx = world.maxx-(TRANSITIONEDGE+2) + if(EAST) endy = rand(TRANSITIONEDGE, world.maxy-TRANSITIONEDGE) endx = TRANSITIONEDGE - if(3) //SOUTH - starty = (TRANSITIONEDGE+2) - startx = rand((TRANSITIONEDGE+2), world.maxx-(TRANSITIONEDGE+2)) + if(SOUTH) endy = world.maxy-TRANSITIONEDGE endx = rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE) - if(4) //WEST - starty = rand((TRANSITIONEDGE+2), world.maxy-(TRANSITIONEDGE+2)) - startx = (TRANSITIONEDGE+2) + if(WEST) endy = rand(TRANSITIONEDGE,world.maxy-TRANSITIONEDGE) endx = world.maxx-TRANSITIONEDGE - - pickedstart = locate(startx, starty, 6) - pickedgoal = locate(endx, endy, 6) - max_i-- - if(max_i<=0) return - - var/obj/effect/meteor/M - if(ship_debris_only) - M = new /obj/effect/meteor/ship_debris(pickedstart) - else - switch(rand(1, 100)) - if(1 to 10) - M = new /obj/effect/meteor/big(pickedstart) - if(11 to 50) - M = new /obj/effect/meteor(pickedstart) - if(51 to 55) - M = new /obj/effect/meteor/flaming(pickedstart) - if(56 to 59) - M = new /obj/effect/meteor/irradiated(pickedstart) - if(60 to 64) - M = new /obj/effect/meteor/golden(pickedstart) - if(65 to 69) - M = new /obj/effect/meteor/silver(pickedstart) - if(70 to 73) - M = new /obj/effect/meteor/emp(pickedstart) - if(74 to 76) - M = new /obj/effect/meteor/diamond(pickedstart) - if(77 to 78) - M = new /obj/effect/meteor/artifact(pickedstart) - if(79 to 80) - M = new /obj/effect/meteor/supermatter(pickedstart) - if(81 to 82) - M = new /obj/effect/meteor/meaty(pickedstart) - if(83 to 100) - M = new /obj/effect/meteor/small(pickedstart) - - M.dest = pickedgoal - spawn(1) - walk_towards(M, M.dest, 2) + var/turf/T = locate(endx, endy, Z) + return T /obj/effect/meteor name = "meteor" icon = 'icons/obj/meteor.dmi' icon_state = "large" - density = 1 - anchored = 1.0 - var/hits = 3 - var/detonation_chance = 50 - var/power = 2 - var/power_step = 0.75 - var/dest - var/shieldsoundrange = 260 // The maximum number of tiles away the sound can be heard, falls off over distance, so it will be quiet near the limit + density = TRUE + anchored = TRUE pass_flags = PASSTABLE - var/done = 0//This is set to 1 when the meteor is done colliding, and is used to ignore additional bumps while waiting for deletion + + var/hits = 4 + var/hitpwr = 2 //Level of ex_act to be called on hit. + var/dest + var/heavy = FALSE + var/z_original + var/meteor_loot = list(/obj/item/ore/iron) //the thing that the meteors will drop when it explodes var/dropamt = 3 //amount of said thing -/obj/effect/meteor/small - name = "small meteor" - icon_state = "small" - pass_flags = PASSTABLE | PASSGRILLE - power = 1 - power_step = 0.5 - hits = 2 - detonation_chance = 30 - shieldsoundrange = 160 - dropamt = 1 /obj/effect/meteor/Destroy() walk(src,0) //this cancels the walk_towards() proc return ..() /obj/effect/meteor/Collide(atom/A) - if (!done) - spawn(0) + ..() + if(A && !QDELETED(src)) // Prevents explosions and other effects when we were deleted by whatever we Bumped() - currently used by shields. + ram_turf(get_turf(A)) + get_hit() //should only get hit once per move attempt - if (A) - A.ex_act(2) - playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1) - make_debris() - meteor_effect() +/obj/effect/meteor/proc/ram_turf(var/turf/T) + //first bust whatever is in the turf + for(var/atom/A in T) + if(A != src && !A.CanPass(src, src.loc, 0.5, 0)) //only ram stuff that would actually block us + A.ex_act(hitpwr) - if (istype(A, /obj/effect/energy_field))//If a normal/small meteor impacts an energy field, then it makes a widely audible impact sound and qdels - done = 1 - hits = 0 - power *= 0.5 - power_step *= 0.5 - var/turf/T = src.loc - if (!T) - T = A.loc + //then, ram the turf if it still exists + if(T && !T.CanPass(src, src.loc, 0.5, 0)) + T.ex_act(hitpwr) - if (T)//We have a double safety check on T to prevent runtime errors - meteor_shield_impact_sound(T, shieldsoundrange) - msg_admin_attack("Meteor impacted energy field at coords (JMP)") - spawn()//Delaying the Qdel a frame provides a little more safety - qdel(src) +/obj/effect/meteor/proc/get_hit() + hits-- + if(hits <= 0) + make_debris() + meteor_effect() + qdel(src) - if (--src.hits == 0 && !done) - //Prevent meteors from blowing up the singularity's containment. - //Changing emitter and generator ex_act would result in them being bomb and C4 proof. - done = 1 - if(!istype(A,/obj/machinery/power/emitter) && \ - !istype(A,/obj/machinery/field_generator) && \ - prob(detonation_chance)) - explosion(loc, power, power + power_step, power + power_step * 2, power + power_step * 3, 0) - msg_admin_attack("Meteor exploded at coords (JMP)") - else - msg_admin_attack("Meteor dissipated without exploding at coords (JMP)") - spawn() - qdel(src) +/obj/effect/meteor/proc/meteor_effect() + if(heavy) + for(var/mob/M in player_list) + var/turf/T = get_turf(M) + if(!T || T.z != src.z) + continue + var/dist = get_dist(M.loc, src.loc) + shake_camera(M, dist > 20 ? 3 : 5, dist > 20 ? 1 : 3) /obj/effect/meteor/ex_act(severity) - if (severity < 4) qdel(src) return @@ -173,93 +186,58 @@ S.update_icon() O.throw_at(dest, 5, 10) -/obj/effect/meteor/proc/meteor_effect() - return +/obj/effect/meteor/touch_map_edge() + qdel(src) + +/obj/effect/meteor/medium + name = "meteor" + dropamt = 2 + +/obj/effect/meteor/medium/meteor_effect() + ..() + explosion(src.loc, 0, 1, 2, 3, 0) + msg_admin_attack("Meteor exploded at coords (JMP)") /obj/effect/meteor/big - name = "big meteor" - hits = 5 - power = 4 - power_step = 1 - detonation_chance = 60 - shieldsoundrange = 310//This can be set larger than the dimensions of the map, to allow it to remain louder at extreme distance - dropamt = 5 + name = "large meteor" + icon_state = "large" + hits = 6 + heavy = 1 + dropamt = 3 - ex_act(severity) - return - - Collide(atom/A) - if (!done) - spawn(0) - //Prevent meteors from blowing up the singularity's containment. - //Changing emitter and generator ex_act would result in them being bomb and C4 proof - if(!istype(A,/obj/machinery/power/emitter) && \ - !istype(A,/obj/machinery/field_generator)) - if(--src.hits <= 0) - qdel(src) //Dont blow up singularity containment if we get stuck there. - - if (istype(A, /obj/effect/energy_field))//If a big meteor impacts an energy field, then it detonates immediately with reduced power - done = 1 - hits = 0 - power *= 0.5 - power_step *= 0.5 - for(var/mob/M in player_list) - var/turf/T = get_turf(M) - if(!T || T.z != src.z) - continue - shake_camera(M, 3, get_dist(M.loc, src.loc) > 20 ? 1 : 3) - var/turf/T = src.loc - if (!T) - T = A.loc - - if (T) - meteor_shield_impact_sound(T, shieldsoundrange) - explosion(loc, power, power + power_step, power + power_step * 2, power + power_step * 3, 0) - msg_admin_attack("Large Meteor impacted energy field and then exploded at coords (JMP)") - spawn()//Have to delay the qdel a little, or the playsound will throw a runtime - qdel(src) - - else if (A) - for(var/mob/M in player_list) - var/turf/T = get_turf(M) - if(!T || T.z != src.z) - continue - shake_camera(M, 3, get_dist(M.loc, src.loc) > 20 ? 1 : 3) - playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1) - explosion(src.loc, 0, 1, 2, 3, 0) - make_debris() - meteor_effect() - - if (--src.hits == 0 && !done) - done = 1 - if(prob(detonation_chance) && !istype(A, /obj/structure/grille)) - explosion(loc, power, power + power_step, power + power_step * 2, power + power_step * 3, 0) - msg_admin_attack("Large Meteor exploded at coords (JMP)") - else - msg_admin_attack("Large Meteor dissipated without a final explosion at coords (JMP)") - spawn() - qdel(src) +/obj/effect/meteor/big/meteor_effect() + ..() + explosion(src.loc, 1, 2, 3, 4, 0) + msg_admin_attack("Meteor exploded at coords (JMP)") /obj/effect/meteor/dust name = "space dust" icon_state = "dust" pass_flags = PASSTABLE | PASSGRILLE - hits = 1 meteor_loot = list(/obj/item/ore/glass) dropamt = 1 + hits = 1 + hitpwr = 3 + /obj/effect/meteor/flaming name = "flaming meteor" icon_state = "flaming" hits = 3 meteor_loot = list(/obj/item/ore/phoron) +/obj/effect/meteor/flaming/meteor_effect() + ..() + explosion(src.loc, 1, 2, 3, 4, 0, 0, 5) + msg_admin_attack("Meteor exploded at coords (JMP)") + /obj/effect/meteor/irradiated name = "glowing meteor" icon_state = "glowing" meteor_loot = list(/obj/item/ore/uranium) /obj/effect/meteor/irradiated/meteor_effect() + explosion(src.loc, 0, 0, 4, 3, 0) new /obj/effect/decal/cleanable/greenglow(get_turf(src)) for(var/mob/living/L in view(5, src)) L.apply_damage(40, IRRADIATE, damage_flags = DAM_DISPERSED) @@ -308,6 +286,7 @@ explosion(src.loc, 1, 2, 3, 4, 0) for(var/obj/machinery/power/apc/A in range(rand(12, 20), src)) A.energy_fail(round(10 * rand(8, 12))) + msg_admin_attack("Meteor exploded at coords (JMP)") /obj/effect/meteor/meaty name = "meaty ore" diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index 841667d6a25..c5719f2d877 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -130,7 +130,7 @@ var/list/y_arr if(src.x <= 1) - if(istype(A, /obj/effect/meteor)||istype(A, /obj/effect/space_dust)) + if(istype(A, /obj/effect/meteor)) qdel(A) return @@ -187,7 +187,7 @@ A.loc.Entered(A) else if (src.y >= world.maxy) - if(istype(A, /obj/effect/meteor)||istype(A, /obj/effect/space_dust)) + if(istype(A, /obj/effect/meteor)) qdel(A) return var/list/cur_pos = src.get_global_map_pos() diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index b17157cbb1f..b315356b3c0 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -341,20 +341,22 @@ var/const/enterloopsanity = 100 for(var/obj/O in src) O.hide(O.hides_under_flooring() && !is_plating()) -/turf/proc/AdjacentTurfs() - var/L[] = new() - for(var/turf/simulated/t in oview(src,1)) - if(!t.density) - if(!LinkBlocked(src, t) && !TurfBlockedNonWindow(t)) - L.Add(t) - return L +/turf/proc/AdjacentTurfs(var/check_blockage = TRUE) + . = list() + for(var/turf/t in oview(src,1)) + if(check_blockage) + if(!t.density) + if(!LinkBlocked(src, t) && !TurfBlockedNonWindow(t)) + . += t + else + . += t -/turf/proc/CardinalTurfs() - var/L[] = new() - for(var/turf/simulated/T in AdjacentTurfs()) +/turf/proc/CardinalTurfs(var/check_blockage = TRUE) + . = list() + for(var/ad in AdjacentTurfs(check_blockage)) + var/turf/T = ad if(T.x == src.x || T.y == src.y) - L.Add(T) - return L + . += T /turf/proc/Distance(turf/t) if(get_dist(src,t) == 1) diff --git a/code/modules/events/carp_migration.dm b/code/modules/events/carp_migration.dm index 12d10b95620..11295714468 100644 --- a/code/modules/events/carp_migration.dm +++ b/code/modules/events/carp_migration.dm @@ -12,6 +12,7 @@ ) ic_name = "biological entities" + var/deploy_drones = TRUE /datum/event/carp_migration/setup() announceWhen = rand(40, 60) @@ -21,7 +22,7 @@ /datum/event/carp_migration/announce() var/announcement = "" var/soundfile = 'sound/AI/spacecarp.ogg' - if(severity == EVENT_LEVEL_MAJOR) + if(severity == EVENT_LEVEL_MAJOR && deploy_drones) announcement = "Massive migration of unknown biological entities has been detected near [station_name()], please stand-by. The NDV Icarus has dispatched combat drones to assist." soundfile = 'sound/AI/massivespacecarp.ogg' else @@ -30,11 +31,11 @@ /datum/event/carp_migration/start() if(severity == EVENT_LEVEL_MAJOR) - spawn_fish(length(landmarks_list), spawn_drones = TRUE) - spawn_caverndweller(length(landmarks_list), spawn_drones = TRUE) + spawn_fish(length(landmarks_list), spawn_drones = deploy_drones) + spawn_caverndweller(length(landmarks_list), spawn_drones = deploy_drones) else if(severity == EVENT_LEVEL_MODERATE) - spawn_fish(rand(4, 6), spawn_drones = TRUE) //12 to 30 carp, in small groups - spawn_caverndweller(rand(1, 2), spawn_drones = TRUE) //less of those, also don't happen in the regular event + spawn_fish(rand(4, 6), spawn_drones = deploy_drones) //12 to 30 carp, in small groups + spawn_caverndweller(rand(1, 2), spawn_drones = deploy_drones) //less of those, also don't happen in the regular event else spawn_fish(rand(1, 3), 1, 2) //1 to 6 carp, alone or in pairs @@ -119,4 +120,12 @@ for(var/j = 1, j <= group_size, j++) var/mob/living/simple_animal/cosmozoan/cozmo = new(spawn_locations[i]) spawned_carp += WEAKREF(cozmo) - i++ \ No newline at end of file + i++ + +/datum/event/carp_migration/overmap + despawn_turfs = list(/turf/space) + deploy_drones = FALSE + +/datum/event/carp_migration/overmap/setup() + announceWhen = 1 + despawn_turfs = typecacheof(despawn_turfs) \ No newline at end of file diff --git a/code/modules/events/dust.dm b/code/modules/events/dust.dm deleted file mode 100644 index ec9fc7c37bb..00000000000 --- a/code/modules/events/dust.dm +++ /dev/null @@ -1,23 +0,0 @@ -/datum/event/dust - startWhen = 10 - endWhen = 30 - ic_name = "space dust" - -/datum/event/dust/announce() - command_announcement.Announce("The station is now passing through a belt of space dust.", "Dust Alert", new_sound = 'sound/AI/spacedust.ogg') - -/datum/event/dust/start() - dust_swarm(get_severity()) - -/datum/event/dust/end() - command_announcement.Announce("The station has now passed through the belt of space dust.", "Dust Notice") - -/datum/event/dust/proc/get_severity() - switch(severity) - if(EVENT_LEVEL_MUNDANE) - return "weak" - if(EVENT_LEVEL_MODERATE) - return prob(80) ? "norm" : "strong" - if(EVENT_LEVEL_MAJOR) - return "super" - return "weak" diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index 9958013cdca..e1c66ab262e 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -158,7 +158,7 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT new /datum/event_meta(EVENT_LEVEL_MODERATE, "Electrical Storm", /datum/event/electrical_storm, 50, list(ASSIGNMENT_ENGINEER = 15, ASSIGNMENT_JANITOR = 20)), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Gravity Failure", /datum/event/gravity, 100), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Ion Storm", /datum/event/ionstorm, 0, list(ASSIGNMENT_AI = 45, ASSIGNMENT_CYBORG = 25, ASSIGNMENT_ENGINEER = 6, ASSIGNMENT_SCIENTIST = 6)), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Meteor Shower", /datum/event/meteor_wave/shower, 40, list(ASSIGNMENT_ENGINEER = 13)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Meteor Shower", /datum/event/meteor_wave , 40, list(ASSIGNMENT_ENGINEER = 13)), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Prison Break", /datum/event/prison_break, 0, list(ASSIGNMENT_SECURITY = 15, ASSIGNMENT_CYBORG = 20),1), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Containment Error - Xenobiology", /datum/event/prison_break/xenobiology, 0, list(ASSIGNMENT_SCIENTIST = 15, ASSIGNMENT_CYBORG = 20),1), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Containment Error - Bridge", /datum/event/prison_break/bridge, 0, list(ASSIGNMENT_ENGINEER = 15, ASSIGNMENT_CYBORG = 20),1), diff --git a/code/modules/events/grid_check.dm b/code/modules/events/grid_check.dm index 77d62f5dc49..5e252ff817f 100644 --- a/code/modules/events/grid_check.dm +++ b/code/modules/events/grid_check.dm @@ -6,4 +6,4 @@ power_failure(0, severity) /datum/event/grid_check/announce() - command_announcement.Announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Automated Grid Check", new_sound = 'sound/AI/poweroff.ogg') \ No newline at end of file + command_announcement.Announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the power will be shut off for an indeterminate duration.", "Automated Grid Check", new_sound = 'sound/AI/poweroff.ogg') \ No newline at end of file diff --git a/code/modules/events/meteors.dm b/code/modules/events/meteors.dm index 6c93ebf59a5..5dc318accf4 100644 --- a/code/modules/events/meteors.dm +++ b/code/modules/events/meteors.dm @@ -2,93 +2,147 @@ startWhen = 86 endWhen = 9999//safety value, will be set during ticks - var/wave_delay = 13//Note, wave delay is in procs. actual time is equal to wave_delay * 2.1 - var/min_waves = 11 - var/max_waves = 16 - var/min_meteors = 1 - var/max_meteors = 2 - var/duration = 340//Total duration in seconds that the storm will last after it starts + var/next_meteor = 40 + var/waves = 1 + var/start_side + var/next_meteor_lower = 10 + var/next_meteor_upper = 20 - var/downed_ship = FALSE - - var/waves = 8 - var/next_wave = 86 ic_name = "a meteor storm" /datum/event/meteor_wave/setup() - startWhen += rand(-15,15)//slightly randomised start time - waves = rand(min_waves,max_waves) - next_wave = startWhen - wave_delay = round(((duration - 10)/waves)/2.1, 1) + waves = 0 + for(var/n in 1 to severity) + waves += rand(5,15) + + start_side = pick(cardinal) + endWhen = worst_case_end() /datum/event/meteor_wave/announce() - command_announcement.Announce("A heavy meteor storm has been detected on collision course with the station. Estimated three minutes until impact, please activate station shields, and seek shelter in the central ring.", "Meteor Alert", new_sound = 'sound/AI/meteors.ogg') + command_announcement.Announce(current_map.meteors_detected_message, "Meteor Alert", new_sound = 'sound/AI/meteors.ogg') /datum/event/meteor_wave/start() - command_announcement.Announce("Contact with meteor wave imminent, all hands brace for impact.", "Meteor Alert") - -/datum/event/meteor_wave/tick() - if(activeFor >= next_wave) - var/amount = rand(min_meteors,max_meteors) - - event_meteor_wave(amount) - next_wave += wave_delay - waves-- - if(waves <= 0) - endWhen = activeFor + 1 - else - endWhen = next_wave + wave_delay + command_announcement.Announce(current_map.meteor_contact_message, "Meteor Alert") /datum/event/meteor_wave/end(var/faked) if(faked) return spawn(100)//We give 10 seconds before announcing, for the last wave of meteors to hit the station - command_announcement.Announce("The station has survived the meteor storm, it is now safe to commence repairs.", "Meteor Alert") + command_announcement.Announce(current_map.meteor_end_message, "Meteor Alert") -/datum/event/meteor_wave/shower - wave_delay = 6 - min_waves = 7 - max_waves = 9 - min_meteors = 0 - max_meteors = 1 - duration = 180 //Total duration in seconds that the storm will last after it starts +/datum/event/meteor_wave/tick() - waves = 4//this is randomised - next_wave = 86 + if(waves && activeFor >= next_meteor) + send_wave() -/datum/event/meteor_wave/shower/announce() - command_announcement.Announce("A meteor shower is approaching the station, estimated contact in three minutes. Crew are recommended to stay away from the outer areas of the station.", "Meteor Alert") +/datum/event/meteor_wave/proc/worst_case_end() + return activeFor + ((30 / severity) * waves) + 30 -/datum/event/meteor_wave/shower/start() - command_announcement.Announce("Meteors have reached the station. Please stay away from outer areas until the shower has passed.", "Meteor Alert") +/datum/event/meteor_wave/proc/send_wave() + var/pick_side = prob(80) ? start_side : (prob(50) ? turn(start_side, 90) : turn(start_side, -90)) + spawn() spawn_meteors(get_wave_size(), get_meteors(), pick_side, pick(current_map.meteor_levels)) + next_meteor += rand(next_meteor_lower, next_meteor_upper) / severity + waves-- + endWhen = worst_case_end() +/datum/event/meteor_wave/proc/get_wave_size() + return severity * rand(2,4) -/datum/event/meteor_wave/shower/end(var/faked) - if(faked) - return - spawn(100) - command_announcement.Announce("The station has cleared the meteor shower, please return to your stations.", "Meteor Alert") +/datum/event/meteor_wave/proc/get_meteors() + switch(severity) + if(EVENT_LEVEL_MAJOR) + return meteors_major + if(EVENT_LEVEL_MODERATE) + return meteors_moderate + else + return meteors_minor +/var/list/meteors_minor = list( + /obj/effect/meteor/medium = 80, + /obj/effect/meteor/dust = 30, + /obj/effect/meteor/irradiated = 30, + /obj/effect/meteor/big = 30, + /obj/effect/meteor/flaming = 10, + /obj/effect/meteor/golden = 10, + /obj/effect/meteor/silver = 10 +) -//An event specific version of the meteor wave proc, to bypass the delays -/datum/event/meteor_wave/proc/event_meteor_wave(var/number = meteors_in_wave) - for(var/i = 0 to number) - spawn(rand(10, 80)) - spawn_meteor(downed_ship) +/var/list/meteors_moderate = list( + /obj/effect/meteor/medium = 80, + /obj/effect/meteor/big = 30, + /obj/effect/meteor/dust = 30, + /obj/effect/meteor/irradiated = 30, + /obj/effect/meteor/flaming = 10, + /obj/effect/meteor/golden = 10, + /obj/effect/meteor/silver = 10, + /obj/effect/meteor/emp = 10 +) + +/var/list/meteors_major = list( + /obj/effect/meteor/medium = 80, + /obj/effect/meteor/big = 30, + /obj/effect/meteor/dust = 30, + /obj/effect/meteor/irradiated = 30, + /obj/effect/meteor/emp = 30, + /obj/effect/meteor/flaming = 10, + /obj/effect/meteor/golden = 10, + /obj/effect/meteor/silver = 10 +) + +/var/list/downed_ship_meteors = list( + /obj/effect/meteor/ship_debris = 90, + /obj/effect/meteor/dust = 10 +) /datum/event/meteor_wave/downed_ship - downed_ship = TRUE ic_name = "a downed vessel" no_fake = TRUE +/datum/event/meteor_wave/downed_ship/get_meteors() + return downed_ship_meteors + /datum/event/meteor_wave/downed_ship/announce() - command_announcement.Announce("The NDV Icarus reports that it has downed an unknown vessel that was approaching your station. Prepare for debris impact - please evacuate the surface level if needed.", "Ship Debris Alert", new_sound = 'sound/AI/unknownvesseldowned.ogg') + command_announcement.Announce(current_map.ship_meteor_end_message, "Ship Debris Alert", new_sound = 'sound/AI/unknownvesseldowned.ogg') /datum/event/meteor_wave/downed_ship/start() - command_announcement.Announce("Ship debris colliding now, all hands brace for impact.", "Ship Debris Alert") + command_announcement.Announce(current_map.ship_meteor_contact_message, "Ship Debris Alert") /datum/event/meteor_wave/downed_ship/end(var/faked) if(faked) return spawn(100)//We give 10 seconds before announcing, for the last wave of meteors to hit the station - command_announcement.Announce("The last of the ship debris has hit or passed by the station, it is now safe to commence repairs.", "Ship Debris Alert") \ No newline at end of file + command_announcement.Announce(current_map.ship_meteor_end_message, "Ship Debris Alert") + +/datum/event/meteor_wave/overmap + next_meteor_lower = 5 + next_meteor_upper = 10 + next_meteor = 0 + +/datum/event/meteor_wave/overmap/announce() + return + +/datum/event/meteor_wave/dust + ic_name = "a dust belt" + +/datum/event/meteor_wave/dust/announce() + command_announcement.Announce(current_map.dust_detected_message, "Dust Belt Alert") + +/datum/event/meteor_wave/dust/start() + command_announcement.Announce(current_map.dust_contact_message, "Dust Belt Alert") + +/datum/event/meteor_wave/dust/end(var/faked) + if(faked) + return + spawn(100)//We give 10 seconds before announcing, for the last wave of meteors to hit the station + command_announcement.Announce(current_map.dust_end_message, "Dust Belt Alert") + +/datum/event/meteor_wave/dust/get_meteors() + return meteors_dust + +/datum/event/meteor_wave/dust/overmap + next_meteor_lower = 5 + next_meteor_upper = 10 + next_meteor = 0 + +/datum/event/meteor_wave/dust/overmap/announce() + return diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm index fc70ffb1d7c..4be1c2c2cb1 100644 --- a/code/modules/events/radiation_storm.dm +++ b/code/modules/events/radiation_storm.dm @@ -11,7 +11,7 @@ ic_name = "radiation" /datum/event/radiation_storm/announce() - command_announcement.Announce("High levels of radiation detected near the station. Please evacuate into one of the shielded maintenance tunnels.", "Anomaly Alert", new_sound = 'sound/AI/radiation.ogg') + command_announcement.Announce(current_map.radiation_detected_message, "Anomaly Alert", new_sound = 'sound/AI/radiation.ogg') /datum/event/radiation_storm/start() make_maint_all_access() @@ -19,7 +19,7 @@ /datum/event/radiation_storm/tick() if(activeFor == enterBelt) - command_announcement.Announce("The station has entered the radiation belt. Please remain in a sheltered area until we have passed the radiation belt.", "Anomaly Alert") + command_announcement.Announce(current_map.radiation_contact_message, "Anomaly Alert") radiate() if(activeFor >= enterBelt && activeFor <= leaveBelt) @@ -30,7 +30,7 @@ radiate() else if(activeFor == leaveBelt) - command_announcement.Announce("The station has passed the radiation belt. Please report to medbay if you experience any unusual symptoms. Maintenance will lose all-access again shortly.", "Anomaly Alert") + command_announcement.Announce(current_map.radiation_end_message, "Anomaly Alert") lights() /datum/event/radiation_storm/proc/radiate() diff --git a/code/modules/events/rogue_drones.dm b/code/modules/events/rogue_drones.dm index e3a5bb3b8c2..6d49cc27208 100644 --- a/code/modules/events/rogue_drones.dm +++ b/code/modules/events/rogue_drones.dm @@ -18,14 +18,7 @@ D.disabled = rand(15, 60) /datum/event/rogue_drone/announce() - var/msg - if(prob(33)) - msg = "A combat drone wing operating out of the NDV Icarus has failed to return from a sweep of this sector, if any are sighted approach with caution." - else if(prob(50)) - msg = "Contact has been lost with a combat drone wing operating out of the NDV Icarus. If any are sighted in the area, approach with caution." - else - msg = "Unidentified hackers have targetted a combat drone wing deployed from the NDV Icarus. If any are sighted in the area, approach with caution." - command_announcement.Announce(msg, "Rogue drone alert", new_sound = 'sound/AI/combatdrones.ogg') + command_announcement.Announce(pick(current_map.rogue_drone_detected_messages), "Rogue drone alert", new_sound = 'sound/AI/combatdrones.ogg') /datum/event/rogue_drone/end(var/faked) var/num_recovered = 0 @@ -37,6 +30,6 @@ if(!faked) if(num_recovered > length(drones_list) * 0.75) - command_announcement.Announce("Icarus drone control reports the malfunctioning wing has been recovered safely.", "Rogue drone alert") + command_announcement.Announce(current_map.rogue_drone_end_message, "Rogue drone alert") else - command_announcement.Announce("Icarus drone control registers disappointment at the loss of the drones, but the survivors have been recovered.", "Rogue drone alert") + command_announcement.Announce(current_map.rogue_drone_destroyed_message, "Rogue drone alert") diff --git a/code/modules/events/wallrot.dm b/code/modules/events/wallrot.dm index ef0409ae2e3..fa48f19d687 100644 --- a/code/modules/events/wallrot.dm +++ b/code/modules/events/wallrot.dm @@ -6,7 +6,7 @@ endWhen = announceWhen + 1 /datum/event/wallrot/announce() - command_announcement.Announce("Harmful fungi detected at coordinates ([origin_turf.x], [origin_turf.y], [origin_turf.z]). Station structures may be contaminated.", "Biohazard Alert", new_sound = pick('sound/AI/fungi.ogg', 'sound/AI/funguy.ogg', 'sound/AI/fun_guy.ogg', 'sound/AI/fun_gi.ogg')) + command_announcement.Announce("Harmful fungi detected at coordinates ([origin_turf.x], [origin_turf.y], [origin_turf.z]). The structure may be contaminated.", "Biohazard Alert", new_sound = pick('sound/AI/fungi.ogg', 'sound/AI/funguy.ogg', 'sound/AI/fun_guy.ogg', 'sound/AI/fun_gi.ogg')) /datum/event/wallrot/start() set waitfor = FALSE @@ -25,7 +25,7 @@ // Have a chance to rot lots of other walls. var/rotcount = 0 var/actual_severity = severity * rand(10, 20) - for(var/turf/simulated/wall/W in range(12, origin_turf)) + for(var/turf/simulated/wall/W in range(12, origin_turf)) if(prob(30)) W.rot() rotcount++ diff --git a/code/modules/overmap/_defines.dm b/code/modules/overmap/_defines.dm index 30c69c318f6..22d0efab087 100644 --- a/code/modules/overmap/_defines.dm +++ b/code/modules/overmap/_defines.dm @@ -20,6 +20,9 @@ var/global/list/map_sectors = list() /turf/unsimulated/map/Initialize(mapload) . = ..() + + icon_state = "map_[rand(1,6)]" + name = "[x]-[y]" var/list/numbers = list() diff --git a/code/modules/overmap/events/event.dm b/code/modules/overmap/events/event.dm new file mode 100644 index 00000000000..bf2f5b98b33 --- /dev/null +++ b/code/modules/overmap/events/event.dm @@ -0,0 +1,297 @@ +/var/decl/overmap_event_handler/overmap_event_handler = new() + +/decl/overmap_event_handler + var/list/hazard_by_turf + var/list/datum/event/ship_events + +/decl/overmap_event_handler/New() + ..() + hazard_by_turf = list() + ship_events = list() + +/decl/overmap_event_handler/proc/create_events(var/z_level, var/overmap_size, var/number_of_events) + // Acquire the list of not-yet utilized overmap turfs on this Z-level + var/list/candidate_turfs = block(locate(OVERMAP_EDGE, OVERMAP_EDGE, z_level),locate(overmap_size - OVERMAP_EDGE, overmap_size - OVERMAP_EDGE,z_level)) + candidate_turfs = where(candidate_turfs, /proc/can_not_locate, /obj/effect/overmap/visitable) + + for(var/i = 1 to number_of_events) + if(!candidate_turfs.len) + break + var/overmap_event_type = pick(subtypesof(/datum/overmap_event)) + var/datum/overmap_event/datum_spawn = new overmap_event_type + + var/list/event_turfs = acquire_event_turfs(datum_spawn.count, datum_spawn.radius, candidate_turfs, datum_spawn.continuous) + candidate_turfs -= event_turfs + + for(var/event_turf in event_turfs) + var/type = pick(datum_spawn.hazards) + new type(event_turf) + + qdel(datum_spawn)//idk help how do I do this better? + +/decl/overmap_event_handler/proc/acquire_event_turfs(var/number_of_turfs, var/distance_from_origin, var/list/candidate_turfs, var/continuous = TRUE) + number_of_turfs = min(number_of_turfs, candidate_turfs.len) + candidate_turfs = candidate_turfs.Copy() // Not this proc's responsibility to adjust the given lists + + var/origin_turf = pick(candidate_turfs) + var/list/selected_turfs = list(origin_turf) + var/list/selection_turfs = list(origin_turf) + candidate_turfs -= origin_turf + + while(selection_turfs.len && selected_turfs.len < number_of_turfs) + var/selection_turf = pick(selection_turfs) + var/random_neighbour = get_random_neighbour(selection_turf, candidate_turfs, continuous, distance_from_origin) + + if(random_neighbour) + candidate_turfs -= random_neighbour + selected_turfs += random_neighbour + if(get_dist(origin_turf, random_neighbour) < distance_from_origin) + selection_turfs += random_neighbour + else + selection_turfs -= selection_turf + + return selected_turfs + +/decl/overmap_event_handler/proc/get_random_neighbour(var/turf/origin_turf, var/list/candidate_turfs, var/continuous = TRUE, var/range) + var/fitting_turfs + if(continuous) + fitting_turfs = origin_turf.CardinalTurfs(FALSE) + else + fitting_turfs = oview(range, origin_turf) + fitting_turfs = shuffle(fitting_turfs) + for(var/turf/T in fitting_turfs) + if(T in candidate_turfs) + return T + +/decl/overmap_event_handler/proc/start_hazard(var/obj/effect/overmap/visitable/ship/ship, var/obj/effect/overmap/event/hazard)//make these accept both hazards or events + if(!(ship in ship_events)) + ship_events += ship + + for(var/event_type in hazard.events) + if(is_event_active(ship,event_type, hazard.difficulty))//event's already active, don't bother + continue + var/datum/event_meta/EM = new(hazard.difficulty, "Overmap event - [hazard.name]", event_type, add_to_queue = FALSE, is_one_shot = TRUE) + var/datum/event/E = new event_type(EM) + E.startWhen = 0 + E.endWhen = INFINITY + if("victim" in E.vars)//for meteors and other overmap events that uses ships//might need a better solution + E.vars["victim"] = ship + LAZYADD(ship_events[ship], E) + +/decl/overmap_event_handler/proc/stop_hazard(var/obj/effect/overmap/visitable/ship/ship, var/obj/effect/overmap/event/hazard) + for(var/event_type in hazard.events) + var/datum/event/E = is_event_active(ship,event_type,hazard.difficulty) + if(E) + E.kill() + LAZYREMOVE(ship_events[ship], E) + +/decl/overmap_event_handler/proc/is_event_active(var/ship, var/event_type, var/severity) + if(!ship_events[ship]) + return + var/list/active_ship_events = ship_events[ship] + for(var/datum/event/E as anything in active_ship_events) + if(E.type == event_type && E.severity == severity) + return E + +/decl/overmap_event_handler/proc/on_turf_entered(var/turf/new_loc, var/obj/effect/overmap/visitable/ship/ship, var/old_loc) + if(!istype(ship)) + return + if(new_loc == old_loc) + return + + for(var/obj/effect/overmap/event/E in hazard_by_turf[new_loc]) + start_hazard(ship, E) + +/decl/overmap_event_handler/proc/on_turf_exited(var/turf/old_loc, var/obj/effect/overmap/visitable/ship/ship, var/new_loc) + if(!istype(ship)) + return + if(new_loc == old_loc) + return + + for(var/obj/effect/overmap/event/E in hazard_by_turf[old_loc]) + if(is_event_included(hazard_by_turf[new_loc],E)) + continue + stop_hazard(ship,E) + +/decl/overmap_event_handler/proc/update_hazards(var/turf/T)//catch all updater + if(!istype(T)) + return + + var/list/active_hazards = list() + for(var/obj/effect/overmap/event/E in T) + if(is_event_included(active_hazards, E, TRUE)) + continue + active_hazards += E + + if(!active_hazards.len) + hazard_by_turf -= T + entered_event.unregister(T, src, /decl/overmap_event_handler/proc/on_turf_entered) + exited_event.unregister(T, src, /decl/overmap_event_handler/proc/on_turf_exited) + else + hazard_by_turf |= T + hazard_by_turf[T] = active_hazards + entered_event.register(T, src,/decl/overmap_event_handler/proc/on_turf_entered) + exited_event.register(T, src, /decl/overmap_event_handler/proc/on_turf_exited) + + for(var/obj/effect/overmap/visitable/ship/ship in T) + var/list/active_ship_events = ship_events[ship] + for(var/datum/event/E as anything in active_ship_events) + if(is_event_in_turf(E,T)) + continue + E.kill() + LAZYREMOVE(ship_events[ship], E) + + for(var/obj/effect/overmap/event/E in active_hazards) + start_hazard(ship,E) + +/decl/overmap_event_handler/proc/is_event_in_turf(var/datum/event/E, var/turf/T) + for(var/obj/effect/overmap/event/hazard in hazard_by_turf[T]) + if(E in hazard.events && E.severity == hazard.difficulty) + return TRUE + +/decl/overmap_event_handler/proc/is_event_included(var/list/hazards, var/obj/effect/overmap/event/E, var/equal_or_better)//this proc is only used so it can break out of 2 loops cleanly + for(var/obj/effect/overmap/event/A in hazards) + if(istype(A,E.type) || istype(E,A.type)) + if(same_entries(A.events, E.events)) + if(equal_or_better) + if(A.difficulty >= E.difficulty) + return TRUE + else + hazards -= A + else + if(A.difficulty == E.difficulty) + return TRUE + +// We don't subtype /obj/effect/overmap/visitable because that'll create sections one can travel to +// And with them "existing" on the overmap Z-level things quickly get odd. +/obj/effect/overmap/event + name = "event" + icon = 'icons/obj/overmap.dmi' + icon_state = "event" + opacity = 1 + var/list/events + var/list/event_icon_states = list("event") + var/difficulty = EVENT_LEVEL_MODERATE + var/list/victims //basically cached events on which Z level + +/obj/effect/overmap/event/Initialize() + . = ..() + icon_state = pick(event_icon_states) + overmap_event_handler.update_hazards(loc) + +/obj/effect/overmap/event/Move() + var/turf/old_loc = loc + . = ..() + if(.) + overmap_event_handler.update_hazards(old_loc) + overmap_event_handler.update_hazards(loc) + +/obj/effect/overmap/event/forceMove(atom/destination) + var/old_loc = loc + . = ..() + if(.) + overmap_event_handler.update_hazards(old_loc) + overmap_event_handler.update_hazards(loc) + +/obj/effect/overmap/event/Destroy()//takes a look at this one as well, make sure everything is A-OK + var/turf/T = loc + . = ..() + overmap_event_handler.update_hazards(T) + +/obj/effect/overmap/event/meteor + name = "asteroid field" + events = list(/datum/event/meteor_wave/overmap) + event_icon_states = list("meteor1", "meteor2", "meteor3", "meteor4") + difficulty = EVENT_LEVEL_MAJOR + +/obj/effect/overmap/event/electric + name = "electrical storm" + events = list(/datum/event/electrical_storm) + opacity = 0 + event_icon_states = list("electrical1", "electrical2") + difficulty = EVENT_LEVEL_MAJOR + +/obj/effect/overmap/event/dust + name = "dust cloud" + events = list(/datum/event/meteor_wave/dust/overmap) + event_icon_states = list("dust1", "dust2", "dust3", "dust4") + +/obj/effect/overmap/event/ion + name = "ion cloud" + events = list(/datum/event/ionstorm) + opacity = 0 + event_icon_states = list("ion1", "ion2", "ion3", "ion4") + difficulty = EVENT_LEVEL_MAJOR + +/obj/effect/overmap/event/carp + name = "carp shoal" + events = list(/datum/event/carp_migration/overmap) + opacity = 0 + difficulty = EVENT_LEVEL_MODERATE + event_icon_states = list("carp") + +/obj/effect/overmap/event/carp/major + name = "carp school" + difficulty = EVENT_LEVEL_MAJOR + +/obj/effect/overmap/event/gravity + name = "dark matter influx" + events = list(/datum/event/gravity) + opacity = 0 + +//These now are basically only used to spawn hazards. Will be useful when we need to spawn group of moving hazards +/datum/overmap_event + var/name = "map event" + var/radius = 2 + var/count = 6 + var/hazards + var/opacity = 1 + var/continuous = TRUE //if it should form continous blob, or can have gaps + +/datum/overmap_event/meteor + name = "asteroid field" + count = 15 + radius = 4 + continuous = FALSE + hazards = /obj/effect/overmap/event/meteor + +/datum/overmap_event/electric + name = "electrical storm" + count = 11 + radius = 3 + opacity = 0 + hazards = /obj/effect/overmap/event/electric + +/datum/overmap_event/dust + name = "dust cloud" + count = 16 + radius = 4 + hazards = /obj/effect/overmap/event/dust + +/datum/overmap_event/ion + name = "ion cloud" + count = 8 + radius = 3 + opacity = 0 + hazards = /obj/effect/overmap/event/ion + +/datum/overmap_event/carp + name = "carp shoal" + count = 8 + radius = 3 + opacity = 0 + continuous = FALSE + hazards = /obj/effect/overmap/event/carp + +/datum/overmap_event/carp/major + name = "carp school" + count = 5 + radius = 4 + hazards = /obj/effect/overmap/event/carp/major + +/datum/overmap_event/gravity + name = "dark matter influx" + count = 12 + radius = 4 + opacity = 0 + hazards = /obj/effect/overmap/event/gravity \ No newline at end of file diff --git a/icons/obj/overmap.dmi b/icons/obj/overmap.dmi index 002377325f2022ff529489dfe4fde8b3c9d27ce6..507179a221efa40702454f4ff84630c7d4dff04f 100644 GIT binary patch literal 39997 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 literal 2177 zcmV-{2!8j8P)2?Zo)7S z1>kjj3JbPX#h+9*-5^lKqFkXe$uu@{Vq_0N+`eN#3SB+#W~49Hdx_$y-t4~i2fh8? ztAS#2q1T^!^*&S8)irEoSuRv%$+earOJc($<0M&ko~WvEG08et)o(N%J?4MtrwfDY z+tIFHteoDEH@7^#tzRCbnnQ%=hvP{gWF0YuI4^XILboh*E9hvT9=B*NiE)RlaD%LH z{;Uepd-(>@)yCs=qs19Vi<6EP=WTsB5>&N`XWS<%+$1a9AuF6-{!tuD5KbishZ2M{ zC3|7^_?JQPs*^4Zba000LZNkl=mBl9@lr#r^t!A|G?);<)`S96>*13ls5*kC_=)%}Hf^*n2y1_Z$Gt%Fo zXLKHL=ouZ30eVJ<^8!8N4*>Lv(5=L7Gj=;tw<~uCQ-3%=^w5t|w`UmuVC$(r576dh zIS(+m=E8a&U~SG_@iahNgt>9|lG?|HU=W%sw?|kS_vPwj>I#kfY}-G(KcGon{XvvA z-0TnLg~k~{#^rK<5CP&ihf&7ma({3IpjU)$C3c(fisSf}BVBRb(71o4AD}oKdin#p z8hiQ!%1R^dK0ZcX!`F2!ncglimd~{(tfN)K6II2jnt#QAqJ1hEG&J4vnyV5s^vOHq3w zAgT@sU=o0NBfKWZ1Tcy#kb5908*x#0IDSrfTWIsnNt8> ztt$XC)&O5bXaS(F0NP3foIe2g4v@_@(V%9`e!yk~jO(pi0JjA&4%Bfn2kJh?02d*3eI2>ZMLTc2f7Qjw0MTr@}tIkFRASEsvCGLc?b6Ws!k7DQc>7Z8tnjY>x zbE4CT9#L4Oj_)hLM^=vW#f(YTl$M)Yz|Xqy)Y$(QnO~U~;r21+vj^CWC{s&!vG!ZB z*abP-hwT!BqA-vF&@yA`%A){`jz=lPUSsfmefl>f!W%qzr=?k53#-hZ)}BXUB3g89U`DATq| zx+G?8>mJ4~+TjSUFiIxl)WJpfxO>`iL{ptu6$ zZDTI@j>Xy7H+L6$6hP2w)N;=%DvNX?KYT$@r43Tv9;38*i^42 z2aEoT!Ou$#z`GByocPw~F(X2dbOpiM9?(e?uV$oKwQZbvt&uThjyNhaW>3@4B03Nb zOlB|I@OCs05qq{iU*}j3H@$E4=~){hglB-oE!&Mk;-Dfq$$kq51F4Y!1_%&*1>l5f zBfavRB3`K0c{39@L=~Vfd@;8vSYHju9PsvusxyQ6sDfyTv~GScb3o;lKK(PX4wj@6 z;=nJY1lmWb6qr@Dc=Zl z)w@NhTz7B~UG%Ic?I29QzkCOH2B41v@SQrKAnyXGkFl>)*YX400< z4ghJQZ_}Vn^lh5Ym-k%``T!n!=ntp%uSGAs*!`oP=C4IJk%!*_c0|bi)Xq7@5#`qm z>bQi-uEsw9vitgbh!aJWQ|7eW9~_kL`Ss=v#rk?L&3XL**F_MWBoVGE5#$_tyzQxK z$o>BMz>&9 z^ii(=bAZnyjf?crG+m_6w(TPIH;(!89tRIS^as$tT1-#VCU|&g00000NkvXXu0mjf D@zDGV diff --git a/icons/turf/space.dmi b/icons/turf/space.dmi index cb3fb8f47e47d9d9dc6bc1c91f1f2a6762d61284..c9e127d43039a102e536ae3d174915624a43a202 100644 GIT binary patch delta 10759 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 P^<|`Iu3M|~;MxBH7&wp| delta 5179 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 diff --git a/maps/_common/mapsystem/map.dm b/maps/_common/mapsystem/map.dm index 49a15a9bd5e..c2db26ae105 100644 --- a/maps/_common/mapsystem/map.dm +++ b/maps/_common/mapsystem/map.dm @@ -11,6 +11,7 @@ var/list/sealed_levels = list() // Z-levels that don't allow random transit at edge var/list/restricted_levels = list() // Z-levels that dont allow ghosts to randomly move around var/list/empty_levels = null // Empty Z-levels that may be used for various things (currently used by bluespace jump) + var/list/meteor_levels = list() //What z-levels the meteors can hit var/list/map_levels // Z-levels available to various consoles, such as the crew monitor. Defaults to station_levels if unset. @@ -80,6 +81,30 @@ var/list/map_shuttles = list() // A list of all our shuttles. var/default_sector = SECTOR_ROMANOVICH //What is the default space sector for this map + //event messages + + var/meteors_detected_message = "A meteor storm has been detected on collision course with the station. Estimated three minutes until impact, please activate station shields, and seek shelter in the central ring." + var/meteor_contact_message = "Contact with meteor wave imminent, all hands brace for impact." + var/meteor_end_message = "The station has cleared the meteor shower, please return to your stations." + + var/ship_detected_end_message = "The NDV Icarus reports that it has downed an unknown vessel that was approaching your station. Prepare for debris impact - please evacuate the surface level if needed." + var/ship_meteor_contact_message = "Ship debris colliding now, all hands brace for impact." + var/ship_meteor_end_message = "The last of the ship debris has hit or passed by the station, it is now safe to commence repairs." + + var/dust_detected_message = "A belt of space dust is approaching the station." + var/dust_contact_message = "The station is now passing through a belt of space dust." + var/dust_end_message = "The station has now passed through the belt of space dust." + + var/radiation_detected_message = "High levels of radiation detected near the station. Please evacuate into one of the shielded maintenance tunnels." + var/radiation_contact_message = "The station has entered the radiation belt. Please remain in a sheltered area until we have passed the radiation belt." + var/radiation_end_message = "The station has passed the radiation belt. Please report to medbay if you experience any unusual symptoms. Maintenance will lose all-access again shortly." + + var/list/rogue_drone_detected_messages = list("A combat drone wing operating out of the NDV Icarus has failed to return from a sweep of this sector, if any are sighted approach with caution.", + "Contact has been lost with a combat drone wing operating out of the NDV Icarus. If any are sighted in the area, approach with caution.", + "Unidentified hackers have targetted a combat drone wing deployed from the NDV Icarus. If any are sighted in the area, approach with caution.") + var/rogue_drone_end_message = "Icarus drone control reports the malfunctioning wing has been recovered safely." + var/rogue_drone_destroyed_message = "Icarus drone control registers disappointment at the loss of the drones, but the survivors have been recovered." + /datum/map/New() if(!map_levels) map_levels = station_levels.Copy() diff --git a/maps/aurora/code/aurora.dm b/maps/aurora/code/aurora.dm index ea900e09474..33210f3a5e4 100644 --- a/maps/aurora/code/aurora.dm +++ b/maps/aurora/code/aurora.dm @@ -16,6 +16,7 @@ player_levels = list(2, 3, 4, 5, 6, 7, 8) restricted_levels = list() accessible_z_levels = list("2" = 60, "6" = 20, "7" = 20) + meteor_levels = list(6) base_turf_by_z = list( "1" = /turf/space, "2" = /turf/space, diff --git a/maps/exodus/code/exodus.dm b/maps/exodus/code/exodus.dm index 7e1f18b3773..cb35dc1e8a8 100644 --- a/maps/exodus/code/exodus.dm +++ b/maps/exodus/code/exodus.dm @@ -49,6 +49,7 @@ contact_levels = list(1, 5) player_levels = list(1, 3, 4, 5, 6) accessible_z_levels = list("1" = 5, "3" = 10, "4" = 15, "5" = 10, "6" = 60) + meteor_levels = list(1) map_shuttles = list( /datum/shuttle/autodock/ferry/escape_pod/pod/escape_pod1, diff --git a/maps/runtime/code/runtime.dm b/maps/runtime/code/runtime.dm index d84611046aa..88e7ffede15 100644 --- a/maps/runtime/code/runtime.dm +++ b/maps/runtime/code/runtime.dm @@ -13,6 +13,9 @@ contact_levels = list(1, 2, 3) player_levels = list(1, 2, 3) accessible_z_levels = list(1, 2, 3) + meteor_levels = list(1, 2, 3) + + overmap_event_areas = 10 station_name = "NSV Runtime" station_short = "Runtime" diff --git a/maps/runtime/runtime-1.dmm b/maps/runtime/runtime-1.dmm index ba0d328b712..8ea80b118d4 100644 --- a/maps/runtime/runtime-1.dmm +++ b/maps/runtime/runtime-1.dmm @@ -1772,6 +1772,12 @@ /obj/turbolift_map_holder/runtime, /turf/simulated/floor/plating, /area/turbolift/main_station) +"Yc" = ( +/obj/effect/landmark{ + name = "carpspawn" + }, +/turf/template_noop, +/area/template_noop) "YP" = ( /obj/effect/floor_decal/corner/blue{ dir = 10 @@ -2032,7 +2038,7 @@ aa aa aa aa -aa +Yc aa aa aa @@ -2542,7 +2548,7 @@ aa aa aa aa -aa +Yc aa aa "} @@ -3038,7 +3044,7 @@ aa aa aa aa -aa +Yc aa aa ab @@ -3783,7 +3789,7 @@ aa aa aa aa -aa +Yc aa aa aa @@ -4296,7 +4302,7 @@ aa aa aa aa -aa +Yc aa aa aa diff --git a/maps/runtime/runtime-2.dmm b/maps/runtime/runtime-2.dmm index fab75070d8b..3320b27215a 100644 --- a/maps/runtime/runtime-2.dmm +++ b/maps/runtime/runtime-2.dmm @@ -133,6 +133,12 @@ temperature = 278 }, /area/turret_protected/ai_upload_foyer) +"fr" = ( +/obj/effect/landmark{ + name = "carpspawn" + }, +/turf/template_noop, +/area/template_noop) "gD" = ( /obj/structure/cable{ d1 = 1; @@ -1401,7 +1407,7 @@ iR iR iR iR -iR +fr iR iR iR @@ -1535,7 +1541,7 @@ iR iR iR iR -iR +fr iR iR iR @@ -2605,7 +2611,7 @@ iR iR iR iR -iR +fr iR iR iR @@ -3749,7 +3755,7 @@ iR iR iR iR -iR +fr iR iR iR @@ -3995,7 +4001,7 @@ iR iR iR iR -iR +fr iR iR iR diff --git a/maps/runtime/runtime-3.dmm b/maps/runtime/runtime-3.dmm index f0070322c6d..9c5af899360 100644 --- a/maps/runtime/runtime-3.dmm +++ b/maps/runtime/runtime-3.dmm @@ -47,8 +47,8 @@ "i" = ( /obj/machinery/light{ brightness_range = 16; - must_start_working = 1; - dir = 8 + dir = 8; + must_start_working = 1 }, /obj/effect/floor_decal/industrial/warning{ dir = 4 @@ -70,8 +70,8 @@ "l" = ( /obj/machinery/light{ brightness_range = 16; - must_start_working = 1; - dir = 4 + dir = 4; + must_start_working = 1 }, /obj/effect/floor_decal/industrial/warning{ dir = 8 @@ -187,11 +187,17 @@ }, /turf/simulated/wall/r_wall, /area/construction/hallway) +"I" = ( +/obj/effect/landmark{ + name = "carpspawn" + }, +/turf/template_noop, +/area/template_noop) "J" = ( /obj/machinery/light{ brightness_range = 16; - must_start_working = 1; - dir = 8 + dir = 8; + must_start_working = 1 }, /obj/effect/floor_decal/industrial/warning{ dir = 4 @@ -536,7 +542,7 @@ b b b b -b +I b b b @@ -620,7 +626,7 @@ b b b b -b +I b b b @@ -1205,7 +1211,7 @@ b b b b -b +I b b b @@ -2177,7 +2183,7 @@ b b b b -b +I b b b @@ -2726,7 +2732,7 @@ b b b b -b +I b b b @@ -2807,7 +2813,7 @@ b b b b -b +I b b b