diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm index 3abd79708f7a..de7eb672e87b 100644 --- a/code/__DEFINES/atmospherics.dm +++ b/code/__DEFINES/atmospherics.dm @@ -23,6 +23,8 @@ #define T0C 273.15 // 0degC #define T20C 293.15 // 20degC +#define T90C 363.15 // 90degC +#define T120C 393.15 // 120degC #define TCMB 2.7 // -270.3degC #define ICE_COLONY_TEMPERATURE 223 //-50degC #define SOROKYNE_TEMPERATURE 223 // Same as Ice for now diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm index 032a1891a808..dc5e70fcd5ec 100644 --- a/code/__DEFINES/dcs/signals/signals_global.dm +++ b/code/__DEFINES/dcs/signals/signals_global.dm @@ -60,8 +60,11 @@ #define COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING "!groundside_forsaken_handling" /// From -#define COMSIG_GLOB_YAUTJA_ARMORY_OPENED "yautja_armory_opened" +#define COMSIG_GLOB_YAUTJA_ARMORY_OPENED "!yautja_armory_opened" /// From /proc/biohazard_lockdown() -#define COMSIG_GLOB_RESEARCH_LOCKDOWN "research_lockdown_closed" -#define COMSIG_GLOB_RESEARCH_LIFT "research_lockdown_opened" +#define COMSIG_GLOB_RESEARCH_LOCKDOWN "!research_lockdown_closed" +#define COMSIG_GLOB_RESEARCH_LIFT "!research_lockdown_opened" + +/// From /obj/structure/machinery/power/fusion_engine/proc/set_overloading() : (set_overloading) +#define COMSIG_GLOB_GENERATOR_SET_OVERLOADING "!generator_set_overloading" diff --git a/code/__DEFINES/hijack.dm b/code/__DEFINES/hijack.dm new file mode 100644 index 000000000000..85d4c227ae70 --- /dev/null +++ b/code/__DEFINES/hijack.dm @@ -0,0 +1,13 @@ +#define EVACUATION_TYPE_NONE 0 +#define EVACUATION_TYPE_ADDITIVE 1 +#define EVACUATION_TYPE_MULTIPLICATIVE 2 + +#define HIJACK_ANNOUNCE "ARES Emergency Procedures" +#define XENO_HIJACK_ANNOUNCE "You sense something unusual..." + +#define EVACUATION_STATUS_NOT_INITIATED 0 +#define EVACUATION_STATUS_INITIATED 1 + +#define HIJACK_OBJECTIVES_NOT_STARTED 0 +#define HIJACK_OBJECTIVES_STARTED 1 +#define HIJACK_OBJECTIVES_COMPLETE 2 diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index ac9cfd3e12d2..301ca0409655 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -115,6 +115,7 @@ #define SS_INIT_INFLUXDRIVER 28 #define SS_INIT_GARBAGE 24 #define SS_INIT_EVENTS 23.5 +#define SS_INIT_HIJACK 22.6 #define SS_INIT_REDIS 22.5 #define SS_INIT_REAGENTS 22.1 #define SS_INIT_MAPPING 22 @@ -177,6 +178,7 @@ #define SS_PRIORITY_FAST_OBJECTS 105 #define SS_PRIORITY_OBJECTS 104 #define SS_PRIORITY_DECORATOR 99 +#define SS_PRIORITY_HIJACK 97 #define SS_PRIORITY_POWER 95 #define SS_PRIORITY_EFFECTS 92 #define SS_PRIORITY_MACHINERY 90 diff --git a/code/controllers/subsystem/hijack.dm b/code/controllers/subsystem/hijack.dm new file mode 100644 index 000000000000..55b5aa75caf8 --- /dev/null +++ b/code/controllers/subsystem/hijack.dm @@ -0,0 +1,429 @@ +SUBSYSTEM_DEF(hijack) + name = "Hijack" + wait = 2 SECONDS + flags = SS_KEEP_TIMING + priority = SS_PRIORITY_HIJACK + init_order = SS_INIT_HIJACK + + ///Required progress to evacuate safely via lifeboats + var/required_progress = 100 + + ///Current progress towards evacuating safely via lifeboats + var/current_progress = 0 + + /// How much progress is required to early launch + var/early_launch_required_progress = 25 + + ///The estimated time left to get to the safe evacuation point + var/estimated_time_left = 0 + + ///Areas that are marked as having progress, assoc list that is progress_area = boolean, the boolean indicating if it was progressing or not on the last fire() + var/list/area/progress_areas = list() + + ///The areas that need cycled through currently + var/list/area/current_run = list() + + ///The progress of the current run that needs to be added at the end of the current run + var/current_run_progress_additive = 0 + + ///Holds what the current_run_progress_additive should be multiplied by at the end of the current run + var/current_run_progress_multiplicative = 1 + + ///Holds the progress change from last run + var/last_run_progress_change = 0 + + ///Holds the next % point progress should be announced, increments on itself + var/announce_checkpoint = 25 + + ///What stage of evacuation we are currently on + var/evac_status = EVACUATION_STATUS_NOT_INITIATED + + ///What stage of hijack are we currently on + var/hijack_status = HIJACK_OBJECTIVES_NOT_STARTED + + ///Whether or not evacuation has been disabled by admins + var/evac_admin_denied = FALSE + + /// If TRUE, self destruct has been unlocked and is possible with a hold of reactor + var/sd_unlocked = FALSE + + /// Admin var to manually prevent self destruct from occurring + var/admin_sd_blocked = FALSE + + /// Maximum amount of fusion generators that can be overloaded at once for a time benefit + var/maximum_overload_generators = 18 + + /// How many generators are currently overloaded + var/overloaded_generators = 0 + + /// How long the manual self destruct will take on the high end + var/sd_max_time = 15 MINUTES + + /// How long the manual self destruct will take on the low end + var/sd_min_time = 5 MINUTES + + /// How much time left until SD detonates + var/sd_time_remaining = 0 + + /// Roughly what % of the SD countdown remains + var/percent_completion_remaining = 100 + + /// If the engine room has been heated, occurs at 33% SD completion + var/engine_room_heated = FALSE + + /// If the engine room has been superheated, occurs at 66% SD completion + var/engine_room_superheated = FALSE + + /// If the self destruct has/is detonating + var/sd_detonated = FALSE + + /// If a generator has ever been overloaded in the past this round + var/generator_ever_overloaded = FALSE + + /// If ARES has announced the 50% point yet for SD + var/ares_sd_announced = FALSE + +/datum/controller/subsystem/hijack/Initialize(timeofday) + RegisterSignal(SSdcs, COMSIG_GLOB_GENERATOR_SET_OVERLOADING, PROC_REF(on_generator_overload)) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/hijack/stat_entry(msg) + if(!SSticker?.mode?.is_in_endgame) + msg = " Not Hijack" + return ..() + + if(current_progress >= required_progress) + msg = " Complete" + return ..() + + msg = " Progress: [current_progress]% | Last run: [last_run_progress_change]" + return ..() + +/datum/controller/subsystem/hijack/fire(resumed = FALSE) + if(!SSticker?.mode?.is_in_endgame) + return + + if(hijack_status < HIJACK_OBJECTIVES_STARTED) + hijack_status = HIJACK_OBJECTIVES_STARTED + + if(current_progress >= required_progress) + if(hijack_status < HIJACK_OBJECTIVES_COMPLETE) + hijack_status = HIJACK_OBJECTIVES_COMPLETE + + if(sd_unlocked && overloaded_generators) + sd_time_remaining -= wait + if(!engine_room_heated && (sd_time_remaining <= (max((1 - round(overloaded_generators / maximum_overload_generators, 0.01)) * sd_max_time, sd_min_time) * 0.66))) + heat_engine_room() + + if(!ares_sd_announced && (sd_time_remaining <= (max((1 - round(overloaded_generators / maximum_overload_generators, 0.01)) * sd_max_time, sd_min_time) * 0.5))) + announce_sd_halfway() + + if(!engine_room_superheated && (sd_time_remaining <= (max((1 - round(overloaded_generators / maximum_overload_generators, 0.01)) * sd_max_time, sd_min_time) * 0.33))) + superheat_engine_room() + + if((sd_time_remaining <= 0) && !sd_detonated) + detonate_sd() + + return + + if(!resumed) + current_run = progress_areas.Copy() + + for(var/area/almayer/cycled_area as anything in current_run) + current_run -= cycled_area + + if(progress_areas[cycled_area] != cycled_area.power_equip) + progress_areas[cycled_area] = !progress_areas[cycled_area] + announce_area_power_change(cycled_area) + + if(progress_areas[cycled_area]) + switch(cycled_area.hijack_evacuation_type) + if(EVACUATION_TYPE_ADDITIVE) + current_run_progress_additive += cycled_area.hijack_evacuation_weight + if(EVACUATION_TYPE_MULTIPLICATIVE) + current_run_progress_multiplicative *= cycled_area.hijack_evacuation_weight + + if (MC_TICK_CHECK) + return + + last_run_progress_change = current_run_progress_additive * current_run_progress_multiplicative + current_progress += last_run_progress_change + + if(last_run_progress_change) + estimated_time_left = ((required_progress - current_progress) / last_run_progress_change) * wait + else + estimated_time_left = INFINITY + + if(current_progress >= announce_checkpoint) + announce_progress() + announce_checkpoint += initial(announce_checkpoint) + + current_run_progress_additive = 0 + current_run_progress_multiplicative = 1 + +///Called when the xeno dropship crashes into the Almayer and announces the current status of various objectives to marines +/datum/controller/subsystem/hijack/proc/announce_status_on_crash() + var/message = "" + + for(var/area/cycled_area as anything in progress_areas) + message += "[cycled_area] - [cycled_area.power_equip ? "Online" : "Offline"]\n" + progress_areas[cycled_area] = cycled_area.power_equip + + message += "\nDue to low orbit, extra fuel is required for non-surface evacuations.\nMaintain fueling functionality for optimal evacuation conditions." + + marine_announcement(message, HIJACK_ANNOUNCE) + +///Called when an area power status is changed to announce that it has been changed +/datum/controller/subsystem/hijack/proc/announce_area_power_change(area/changed_area) + var/message = "[changed_area] - [changed_area.power_equip ? "Online" : "Offline"]" + + marine_announcement(message, HIJACK_ANNOUNCE) + +///Called to announce to xenos the state of evacuation progression +/datum/controller/subsystem/hijack/proc/announce_progress() + var/announce = announce_checkpoint / initial(announce_checkpoint) + + var/marine_warning_areas = "" + var/xeno_warning_areas = "" + + for(var/area/cycled_area as anything in progress_areas) + if(cycled_area.power_equip) + xeno_warning_areas += "[cycled_area], " + continue + marine_warning_areas += "[cycled_area], " + + if(xeno_warning_areas) + xeno_warning_areas = copytext(xeno_warning_areas, 1, -2) + + if(marine_warning_areas) + marine_warning_areas = copytext(marine_warning_areas, 1, -2) + + var/datum/hive_status/hive + for(var/hivenumber in GLOB.hive_datum) + hive = GLOB.hive_datum[hivenumber] + if(!length(hive.totalXenos)) + continue + + switch(announce) + if(1) + xeno_announcement(SPAN_XENOANNOUNCE("The talls are a quarter of the way towards their goals. Disable the following areas: [xeno_warning_areas]"), hive.hivenumber, XENO_HIJACK_ANNOUNCE) + if(2) + xeno_announcement(SPAN_XENOANNOUNCE("The talls are half way towards their goals. Disable the following areas: [xeno_warning_areas]"), hive.hivenumber, XENO_HIJACK_ANNOUNCE) + if(3) + xeno_announcement(SPAN_XENOANNOUNCE("The talls are three quarters of the way towards their goals. Disable the following areas: [xeno_warning_areas]"), hive.hivenumber, XENO_HIJACK_ANNOUNCE) + if(4) + xeno_announcement(SPAN_XENOANNOUNCE("The talls have completed their goals!"), hive.hivenumber, XENO_HIJACK_ANNOUNCE) + + switch(announce) + if(1) + marine_announcement("Emergency fuel replenishment at 25 percent. Lifeboat emergency early launch now available.[marine_warning_areas ? "\nTo increase speed restore power to the following areas: [marine_warning_areas]" : " All fueling areas operational."]", HIJACK_ANNOUNCE) + if(2) + marine_announcement("Emergency fuel replenishment at 50 percent.[marine_warning_areas ? "\nTo increase speed restore power to the following areas: [marine_warning_areas]" : " All fueling areas operational."]", HIJACK_ANNOUNCE) + if(3) + marine_announcement("Emergency fuel replenishment at 75 percent.[marine_warning_areas ? "\nTo increase speed restore power to the following areas: [marine_warning_areas]" : " All fueling areas operational."]", HIJACK_ANNOUNCE) + if(4) + marine_announcement("Emergency fuel replenishment at 100 percent. Safe utilization of lifeboats now possible.", HIJACK_ANNOUNCE) + if(!admin_sd_blocked) + addtimer(CALLBACK(src, PROC_REF(unlock_self_destruct)), 8 SECONDS) + +/// Passes the ETA for status panels +/datum/controller/subsystem/hijack/proc/get_evac_eta() + switch(hijack_status) + if(HIJACK_OBJECTIVES_STARTED) + if(estimated_time_left == INFINITY) + return "Never" + return "[duration2text_sec(estimated_time_left)]" + + if(HIJACK_OBJECTIVES_COMPLETE) + return "Complete" + +/datum/controller/subsystem/hijack/proc/get_sd_eta() + if(!sd_time_remaining) + return "Complete" + + if(overloaded_generators <= 0) + return "Never" + + return "[duration2text_sec(sd_time_remaining)]" + +//~~~~~~~~~~~~~~~~~~~~~~~~ EVAC STUFF ~~~~~~~~~~~~~~~~~~~~~~~~// + +/// Initiates evacuation by announcing and then prepping all lifepods/lifeboats +/datum/controller/subsystem/hijack/proc/initiate_evacuation() + if(evac_status == EVACUATION_STATUS_NOT_INITIATED && !(evac_admin_denied & FLAGS_EVACUATION_DENY)) + evac_status = EVACUATION_STATUS_INITIATED + ai_announcement("Attention. Emergency. All personnel must evacuate immediately.", 'sound/AI/evacuate.ogg') + + for(var/obj/structure/machinery/status_display/cycled_status_display in machines) + if(is_mainship_level(cycled_status_display.z)) + cycled_status_display.set_picture("evac") + for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile) + shuttle.prepare_evac() + activate_lifeboats() + return TRUE + +/// Cancels evacuation, tells lifepods/lifeboats and status_displays +/datum/controller/subsystem/hijack/proc/cancel_evacuation() + if(evac_status == EVACUATION_STATUS_INITIATED) + evac_status = EVACUATION_STATUS_NOT_INITIATED + deactivate_lifeboats() + ai_announcement("Evacuation has been cancelled.", 'sound/AI/evacuate_cancelled.ogg') + + for(var/obj/structure/machinery/status_display/cycled_status_display in machines) + if(is_mainship_level(cycled_status_display.z)) + cycled_status_display.set_sec_level_picture() + + for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile) + shuttle.cancel_evac() + return TRUE + +/// Opens the lifeboat doors and gets them ready to launch +/datum/controller/subsystem/hijack/proc/activate_lifeboats() + for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks) + var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked() + if(lifeboat && lifeboat.available) + lifeboat.status = LIFEBOAT_ACTIVE + lifeboat_dock.open_dock() + +/// Turns off ability to manually take off lifeboats +/datum/controller/subsystem/hijack/proc/deactivate_lifeboats() + for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks) + var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked() + if(lifeboat && lifeboat.available) + lifeboat.status = LIFEBOAT_INACTIVE + + +/// Once refueling is done, marines can optionally hold SD for a time for a stalemate instead of a xeno minor +/datum/controller/subsystem/hijack/proc/unlock_self_destruct() + sd_time_remaining = sd_max_time + sd_unlocked = TRUE + marine_announcement("Fuel reserves full. Manual detonation of fuel reserves by overloading the on-board fusion reactors now possible.", HIJACK_ANNOUNCE) + +/datum/controller/subsystem/hijack/proc/on_generator_overload(obj/structure/machinery/power/fusion_engine/source, new_overloading) + SIGNAL_HANDLER + + if(!generator_ever_overloaded) + generator_ever_overloaded = TRUE + var/datum/hive_status/hive + for(var/hivenumber in GLOB.hive_datum) + hive = GLOB.hive_datum[hivenumber] + if(!length(hive.totalXenos)) + continue + + xeno_announcement(SPAN_XENOANNOUNCE("The talls may be attempting to take their ship down with them in Engineering, stop them!"), hive.hivenumber, XENO_HIJACK_ANNOUNCE) + + adjust_generator_overload_count(new_overloading ? 1 : -1) + +/datum/controller/subsystem/hijack/proc/adjust_generator_overload_count(amount = 1) + var/generator_overload_percent = round(overloaded_generators / maximum_overload_generators, 0.01) + var/old_required_time = sd_min_time + ((1 - generator_overload_percent) * (sd_max_time - sd_min_time)) + percent_completion_remaining = sd_time_remaining / old_required_time + overloaded_generators = clamp(overloaded_generators + amount, 0, maximum_overload_generators) + generator_overload_percent = round(overloaded_generators / maximum_overload_generators, 0.01) + var/new_required_time = sd_min_time + ((1 - generator_overload_percent) * (sd_max_time - sd_min_time)) + sd_time_remaining = percent_completion_remaining * new_required_time + +/datum/controller/subsystem/hijack/proc/heat_engine_room() + engine_room_heated = TRUE + var/area/engine_room = GLOB.areas_by_type[/area/almayer/engineering/engine_core] + engine_room.firealert() + engine_room.temperature = T90C + for(var/mob/current_mob as anything in GLOB.mob_list) + var/area/mob_area = get_area(current_mob) + if(istype(mob_area, /area/almayer/engineering/engine_core)) + to_chat(current_mob, SPAN_BOLDWARNING("You feel the heat of the room increase as the fusion engines whirr louder.")) + +/datum/controller/subsystem/hijack/proc/superheat_engine_room() + engine_room_superheated = TRUE + var/area/engine_room = GLOB.areas_by_type[/area/almayer/engineering/engine_core] + engine_room.firealert() + engine_room.temperature = T120C //slowly deals burn at this temp + for(var/mob/current_mob as anything in GLOB.mob_list) + var/area/mob_area = get_area(current_mob) + if(istype(mob_area, /area/almayer/engineering/engine_core)) + to_chat(current_mob, SPAN_BOLDWARNING("The room feels incredibly hot, you can't take much more of this!")) + +/datum/controller/subsystem/hijack/proc/announce_sd_halfway() + ares_sd_announced = TRUE + marine_announcement("ALERT: Fusion reactor meltdown has reached fifty percent.", HIJACK_ANNOUNCE) + +/datum/controller/subsystem/hijack/proc/detonate_sd() + set waitfor = FALSE + sd_detonated = TRUE + var/creak_picked = pick('sound/effects/creak1.ogg', 'sound/effects/creak2.ogg', 'sound/effects/creak3.ogg') + for(var/mob/current_mob as anything in GLOB.mob_list) + var/turf/current_turf = get_turf(current_mob) + if(!current_mob?.loc || !current_mob.client || !current_turf || !is_mainship_level(current_turf.z)) + continue + + to_chat(current_mob, SPAN_BOLDWARNING("The ship's deck worryingly creaks underneath you.")) + playsound_client(current_mob.client, creak_picked, vol = 50) + + sleep(7 SECONDS) + shakeship(2, 10, TRUE) + + marine_announcement("ALERT: Fusion reactors dangerously overloaded. Runaway meltdown in reactor core imminent.", HIJACK_ANNOUNCE) + sleep(5 SECONDS) + + var/sound_picked = pick('sound/theme/nuclear_detonation1.ogg','sound/theme/nuclear_detonation2.ogg') + for(var/client/player as anything in GLOB.clients) + playsound_client(player, sound_picked, 90) + + var/list/alive_mobs = list() //Everyone who will be destroyed on the zlevel(s). + var/list/dead_mobs = list() //Everyone who only needs to see the cinematic. + for(var/mob/current_mob as anything in GLOB.mob_list) //This only does something cool for the people about to die, but should prove pretty interesting. + var/turf/current_turf = get_turf(current_mob) + if(!current_mob?.loc || !current_turf) + continue + + if(current_mob.stat == DEAD) + dead_mobs |= current_mob + continue + + if(is_mainship_level(current_turf.z)) + alive_mobs |= current_mob + shake_camera(current_mob, 110, 4) + + + sleep(10 SECONDS) + /*Hardcoded for now, since this was never really used for anything else. + Would ideally use a better system for showing cutscenes.*/ + var/atom/movable/screen/cinematic/explosion/explosive_cinematic = new() + + for(var/mob/current_mob as anything in (alive_mobs + dead_mobs)) + if(current_mob?.loc && current_mob.client) + current_mob.client.add_to_screen(explosive_cinematic) //They may have disconnected in the mean time. + + sleep(1.5 SECONDS) //Extra 1.5 seconds to look at the ship. + flick("intro_nuke", explosive_cinematic) + + sleep(3.5 SECONDS) + for(var/mob/current_mob as anything in alive_mobs) + var/turf/current_mob_turf = get_turf(current_mob) + if(!current_mob?.loc || !current_mob_turf) //Who knows, maybe they escaped, or don't exist anymore. + continue + + if(is_mainship_level(current_mob_turf.z)) + if(istype(current_mob.loc, /obj/structure/closet/secure_closet/freezer/fridge)) + continue + + current_mob.death(create_cause_data("nuclear explosion")) + else + current_mob.client.remove_from_screen(explosive_cinematic) //those who managed to escape the z level at last second shouldn't have their view obstructed. + + flick("ship_destroyed", explosive_cinematic) + explosive_cinematic.icon_state = "summary_destroyed" + + for(var/client/player as anything in GLOB.clients) + playsound_client(player, 'sound/effects/explosionfar.ogg', 90) + + + sleep(0.5 SECONDS) + if(SSticker.mode) + SSticker.mode.check_win() + + if(!SSticker.mode) //Just a safety, just in case a mode isn't running, somehow. + to_world(SPAN_ROUNDBODY("Resetting in 30 seconds!")) + sleep(30 SECONDS) + log_game("Rebooting due to nuclear detonation.") + world.Reboot() diff --git a/code/game/area/almayer.dm b/code/game/area/almayer.dm index 6ced81a22b15..742ae7a1addb 100644 --- a/code/game/area/almayer.dm +++ b/code/game/area/almayer.dm @@ -13,6 +13,21 @@ ambience_exterior = AMBIENCE_ALMAYER ceiling_muffle = FALSE + ///Whether this area is used for hijack evacuation progress + var/hijack_evacuation_area = FALSE + + ///The weight this area gives towards hijack evacuation progress + var/hijack_evacuation_weight = 0 + + ///Whether this area is additive or multiplicative towards evacuation progress + var/hijack_evacuation_type = EVACUATION_TYPE_NONE + +/area/almayer/Initialize(mapload, ...) + . = ..() + + if(hijack_evacuation_area) + SShijack.progress_areas[src] = power_equip + /area/shuttle/almayer/elevator_maintenance/upperdeck name = "\improper Maintenance Elevator" icon_state = "shuttle" @@ -160,6 +175,9 @@ fake_zlevel = 2 // lowerdeck soundscape_playlist = SCAPE_PL_ENG soundscape_interval = 15 + hijack_evacuation_area = TRUE + hijack_evacuation_weight = 0.2 + hijack_evacuation_type = EVACUATION_TYPE_ADDITIVE /area/almayer/engineering/starboard_atmos name = "\improper Atmospherics Starboard" @@ -183,6 +201,9 @@ name = "\improper Astronavigational Deck" icon_state = "astronavigation" fake_zlevel = 2 // lowerdeck + hijack_evacuation_area = TRUE + hijack_evacuation_weight = 1.1 + hijack_evacuation_type = EVACUATION_TYPE_MULTIPLICATIVE /area/almayer/shipboard/panic name = "\improper Hangar Panic Room" @@ -712,6 +733,9 @@ icon_state = "lifeboat_pump" requires_power = 1 fake_zlevel = 1 + hijack_evacuation_area = TRUE + hijack_evacuation_weight = 0.1 + hijack_evacuation_type = EVACUATION_TYPE_ADDITIVE /area/almayer/lifeboat_pumps/north1 name = "North West Lifeboat Fuel Pump" diff --git a/code/game/gamemodes/cm_self_destruct.dm b/code/game/gamemodes/cm_self_destruct.dm deleted file mode 100644 index 07c9c43a4768..000000000000 --- a/code/game/gamemodes/cm_self_destruct.dm +++ /dev/null @@ -1,478 +0,0 @@ -/* -TODO -Look into animation screen not showing on self-destruct and other weirdness -Intergrate distress into this controller. -Finish nanoui conversion for comm console. -Make sure people who get nuked and wake up from SSD don't live. -Add flashing lights to evac. //DEFERRED TO BETTER LIGHTING -Finish the game mode announcement thing. -Fix escape doors to work properly. -*/ - -/* -How this works: - -First: All of the linking is done automatically on world start, so nothing needs to be done on that end other than making -sure that objects are actually placed in the game world. If not, the game will error and let you know about it. But you -don't need to modify variables or worry about area placement. It's all done for you. -The rods, for example, configure the time per activation based on their number. Shuttles link their own machines via area. -Nothing in this controller is linked to game mode, so it's stand alone, more or less, but it's best used during a game mode. -Admins have a lot of tools in their disposal via the check antagonist panel, and devs can access the VV of this controller -through that panel. - -Second: The communication console handles most of the IC triggers for activating these functions, the rest is handled elsewhere. -Check communications.dm for that. shuttle_controller.dm handles the set up for the escape pods. escape_pods.dm handles most of the -functions of the escape pods themselves. This file would likely need to be broken down into individual parts at some point in the -future. - -Evacuation takes place when sufficient alert level is reaised and a distress beacon was launched. All of the evac pods come online -and open their doors to allow entry inside. Characters may then get inside of the cryo units to before the shuttles automatically launch. -If wanted, a nearby controller object may launch each individual shuttle early. Only three people may ride on a shuttle to escape, -otherwise the launch will fail and the shuttle will become inoperable. -Any launched shuttles are taken out of the game. If the evacuation is canceled, any persons inside of the cryo tubes will be ejected. -They may temporarily open the door to exit if they are stuck inside after evac is canceled. - -When the self-destruct is enabled, the console comes online. This usually happens during an evacuation. Once the console is -interacted with, it fires up the self-destruct sequence. Several rods rise and must be interacted with in order to arm the system. -Once that happens, the console must be interacted with again to trigger the self-destruct. The self-destruct may also be -canceled from the console. - -The self-destruct may also happen if a nuke is detonated on the ship's zlevel; if it is detonated elsewhere, the ship will not blow up. -Regardless of where it's detonated, or how, a successful detonation will end the round or automatically restart the game. - -All of the necessary difines are stored under mode.dm in defines. -*/ - -var/global/datum/authority/branch/evacuation/EvacuationAuthority //This is initited elsewhere so that the world has a chance to load in. - -/datum/authority/branch/evacuation - var/name = "Evacuation Authority" - var/evac_time //Time the evacuation was initiated. - var/evac_status = EVACUATION_STATUS_STANDING_BY //What it's doing now? It can be standing by, getting ready to launch, or finished. - - var/obj/structure/machinery/self_destruct/console/dest_master //The main console that does the brunt of the work. - var/dest_rods[] //Slave devices to make the explosion work. - var/dest_cooldown //How long it takes between rods, determined by the amount of total rods present. - var/dest_index = 1 //What rod the thing is currently on. - var/dest_status = NUKE_EXPLOSION_INACTIVE - var/dest_started_at = 0 - - var/flags_scuttle = NO_FLAGS - -/datum/authority/branch/evacuation/New() - ..() - dest_master = locate() - if(!dest_master) - log_debug("ERROR CODE SD1: could not find master self-destruct console") - to_world(SPAN_DEBUG("ERROR CODE SD1: could not find master self-destruct console")) - return FALSE - dest_rods = new - for(var/obj/structure/machinery/self_destruct/rod/I in dest_master.loc.loc) dest_rods += I - if(!dest_rods.len) - log_debug("ERROR CODE SD2: could not find any self-destruct rods") - to_world(SPAN_DEBUG("ERROR CODE SD2: could not find any self-destruct rods")) - QDEL_NULL(dest_master) - return FALSE - dest_cooldown = SELF_DESTRUCT_ROD_STARTUP_TIME / dest_rods.len - dest_master.desc = "The main operating panel for a self-destruct system. It requires very little user input, but the final safety mechanism is manually unlocked.\nAfter the initial start-up sequence, [dest_rods.len] control rods must be armed, followed by manually flipping the detonation switch." - -/** - * This proc returns the ship's z level list (or whatever specified), - * when an evac/self-destruct happens. - */ -/datum/authority/branch/evacuation/proc/get_affected_zlevels() - //Nuke is not in progress, end the round on ship only. - if(dest_status < NUKE_EXPLOSION_IN_PROGRESS && SSticker?.mode.is_in_endgame) - . = SSmapping.levels_by_any_trait(list(ZTRAIT_MARINE_MAIN_SHIP)) - return - -//========================================================================================= -//========================================================================================= -//=====================================EVACUATION========================================== -//========================================================================================= -//========================================================================================= - - -/datum/authority/branch/evacuation/proc/initiate_evacuation(force=0) //Begins the evacuation procedure. - if(force || (evac_status == EVACUATION_STATUS_STANDING_BY && !(flags_scuttle & FLAGS_EVACUATION_DENY))) - evac_time = world.time - evac_status = EVACUATION_STATUS_INITIATING - ai_announcement("Attention. Emergency. All personnel must evacuate immediately. You have [round(EVACUATION_ESTIMATE_DEPARTURE/60,1)] minute\s until departure.", 'sound/AI/evacuate.ogg') - xeno_message_all("A wave of adrenaline ripples through the hive. The fleshy creatures are trying to escape!") - - for(var/obj/structure/machinery/status_display/SD in machines) - if(is_mainship_level(SD.z)) - SD.set_picture("evac") - for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile) - shuttle.prepare_evac() - activate_lifeboats() - process_evacuation() - return TRUE - -/datum/authority/branch/evacuation/proc/cancel_evacuation() //Cancels the evac procedure. Useful if admins do not want the marines leaving. - if(evac_status == EVACUATION_STATUS_INITIATING) - evac_time = null - evac_status = EVACUATION_STATUS_STANDING_BY - deactivate_lifeboats() - ai_announcement("Evacuation has been cancelled.", 'sound/AI/evacuate_cancelled.ogg') - - if(get_security_level() == "red") - for(var/obj/structure/machinery/status_display/SD in machines) - if(is_mainship_level(SD.z)) - SD.set_picture("redalert") - - for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile) - shuttle.cancel_evac() - return TRUE - -/datum/authority/branch/evacuation/proc/begin_launch() //Launches the pods. - if(evac_status == EVACUATION_STATUS_INITIATING) - evac_status = EVACUATION_STATUS_IN_PROGRESS //Cannot cancel at this point. All shuttles are off. - spawn() //One of the few times spawn() is appropriate. No need for a new proc. - ai_announcement("WARNING: Evacuation order confirmed. Launching escape pods.", 'sound/AI/evacuation_confirmed.ogg') - addtimer(CALLBACK(src, PROC_REF(launch_lifeboats)), 10 SECONDS) // giving some time to board lifeboats - - for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile) - shuttle.evac_launch() - sleep(50) - - sleep(300) //Sleep 30 more seconds to make sure everyone had a chance to leave. - var/lifesigns = 0 - // lifesigns += P.passengers - var/obj/docking_port/mobile/crashable/lifeboat/lifeboat1 = SSshuttle.getShuttle(MOBILE_SHUTTLE_LIFEBOAT_PORT) - lifeboat1.check_for_survivors() - lifesigns += lifeboat1.survivors - var/obj/docking_port/mobile/crashable/lifeboat/lifeboat2 = SSshuttle.getShuttle(MOBILE_SHUTTLE_LIFEBOAT_STARBOARD) - lifeboat2.check_for_survivors() - lifesigns += lifeboat2.survivors - ai_announcement("ATTENTION: Evacuation complete. Outbound lifesigns detected: [lifesigns ? lifesigns : "none"].", 'sound/AI/evacuation_complete.ogg') - evac_status = EVACUATION_STATUS_COMPLETE - return TRUE - -/datum/authority/branch/evacuation/proc/process_evacuation() //Process the timer. - set background = 1 - - spawn while(evac_status == EVACUATION_STATUS_INITIATING) //If it's not departing, no need to process. - if(world.time >= evac_time + EVACUATION_AUTOMATIC_DEPARTURE) begin_launch() - sleep(10) //One second. - -/datum/authority/branch/evacuation/proc/get_status_panel_eta() - switch(evac_status) - if(EVACUATION_STATUS_INITIATING) - var/eta = EVACUATION_ESTIMATE_DEPARTURE - . = "[(eta / 60) % 60]:[add_zero(num2text(eta % 60), 2)]" - if(EVACUATION_STATUS_IN_PROGRESS) . = "NOW" - -// LIFEBOATS CORNER -/datum/authority/branch/evacuation/proc/activate_lifeboats() - for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks) - var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked() - if(lifeboat && lifeboat.available) - lifeboat.status = LIFEBOAT_ACTIVE - lifeboat_dock.open_dock() - - -/datum/authority/branch/evacuation/proc/deactivate_lifeboats() - for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks) - var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked() - if(lifeboat && lifeboat.available) - lifeboat.status = LIFEBOAT_INACTIVE - -/datum/authority/branch/evacuation/proc/launch_lifeboats() - for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks) - var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked() - if(lifeboat && lifeboat.available) - lifeboat.evac_launch() - -//========================================================================================= -//========================================================================================= -//=====================================SELF DETRUCT======================================== -//========================================================================================= -//========================================================================================= - -/datum/authority/branch/evacuation/proc/enable_self_destruct(force=0) - if(force || (dest_status == NUKE_EXPLOSION_INACTIVE && !(flags_scuttle & FLAGS_SELF_DESTRUCT_DENY))) - dest_status = NUKE_EXPLOSION_ACTIVE - dest_master.lock_or_unlock() - dest_started_at = world.time - set_security_level(SEC_LEVEL_DELTA) //also activate Delta alert, to open the SD shutters. - spawn(0) - for(var/obj/structure/machinery/door/poddoor/shutters/almayer/D in machines) - if(D.id == "sd_lockdown") - D.open() - return TRUE - -//Override is for admins bypassing normal player restrictions. -/datum/authority/branch/evacuation/proc/cancel_self_destruct(override) - if(dest_status == NUKE_EXPLOSION_ACTIVE) - var/obj/structure/machinery/self_destruct/rod/I - var/i - for(i in EvacuationAuthority.dest_rods) - I = i - if(I.active_state == SELF_DESTRUCT_MACHINE_ARMED && !override) - dest_master.state(SPAN_WARNING("WARNING: Unable to cancel detonation. Please disarm all control rods.")) - return FALSE - - dest_status = NUKE_EXPLOSION_INACTIVE - dest_master.in_progress = 1 - dest_started_at = 0 - for(i in dest_rods) - I = i - if(I.active_state == SELF_DESTRUCT_MACHINE_ACTIVE || (I.active_state == SELF_DESTRUCT_MACHINE_ARMED && override)) I.lock_or_unlock(1) - dest_master.lock_or_unlock(1) - dest_index = 1 - ai_announcement("The emergency destruct system has been deactivated.", 'sound/AI/selfdestruct_deactivated.ogg') - if(evac_status == EVACUATION_STATUS_STANDING_BY) //the evac has also been cancelled or was never started. - set_security_level(SEC_LEVEL_RED, TRUE) //both SD and evac are inactive, lowering the security level. - return TRUE - -/datum/authority/branch/evacuation/proc/initiate_self_destruct(override) - if(dest_status < NUKE_EXPLOSION_IN_PROGRESS) - var/obj/structure/machinery/self_destruct/rod/I - var/i - for(i in dest_rods) - I = i - if(I.active_state != SELF_DESTRUCT_MACHINE_ARMED && !override) - dest_master.state(SPAN_WARNING("WARNING: Unable to trigger detonation. Please arm all control rods.")) - return FALSE - dest_master.in_progress = !dest_master.in_progress - for(i in EvacuationAuthority.dest_rods) - I = i - I.in_progress = 1 - ai_announcement("DANGER. DANGER. Self-destruct system activated. DANGER. DANGER. Self-destruct in progress. DANGER. DANGER.") - trigger_self_destruct(,,override) - return TRUE - -/datum/authority/branch/evacuation/proc/trigger_self_destruct(list/z_levels = SSmapping.levels_by_trait(ZTRAIT_MARINE_MAIN_SHIP), origin = dest_master, override = FALSE, end_type = NUKE_EXPLOSION_FINISHED, play_anim = TRUE, end_round = TRUE) - set waitfor = 0 - if(dest_status < NUKE_EXPLOSION_IN_PROGRESS) //One more check for good measure, in case it's triggered through a bomb instead of the destruct mechanism/admin panel. - dest_status = NUKE_EXPLOSION_IN_PROGRESS - playsound(origin, 'sound/machines/Alarm.ogg', 75, 0, 30) - world << pick('sound/theme/nuclear_detonation1.ogg','sound/theme/nuclear_detonation2.ogg') - - var/ship_status = 1 - for(var/i in z_levels) - if(is_mainship_level(i)) - ship_status = 0 //Destroyed. - break - - var/list/alive_mobs = list() //Everyone who will be destroyed on the zlevel(s). - var/list/dead_mobs = list() //Everyone who only needs to see the cinematic. - for(var/mob/current_mob as anything in GLOB.mob_list) //This only does something cool for the people about to die, but should prove pretty interesting. - var/turf/current_turf = get_turf(current_mob) - if(!current_mob || !current_mob.loc || !current_turf) - continue //In case something changes when we sleep(). - if(current_mob.stat == DEAD) - dead_mobs |= current_mob - continue - if(current_turf.z in z_levels) - alive_mobs |= current_mob - shake_camera(current_mob, 110, 4) - - - sleep(100) - /*Hardcoded for now, since this was never really used for anything else. - Would ideally use a better system for showing cutscenes.*/ - var/atom/movable/screen/cinematic/explosion/C = new - - if(play_anim) - for(var/mob/current_mob as anything in alive_mobs + dead_mobs) - if(current_mob && current_mob.loc && current_mob.client) - current_mob.client.add_to_screen(C) //They may have disconnected in the mean time. - - sleep(15) //Extra 1.5 seconds to look at the ship. - flick(override ? "intro_override" : "intro_nuke", C) - sleep(35) - for(var/mob/current_mob in alive_mobs) - if(current_mob && current_mob.loc) //Who knows, maybe they escaped, or don't exist anymore. - var/turf/current_mob_turf = get_turf(current_mob) - if(!current_mob_turf) - continue - if(current_mob_turf.z in z_levels) - if(istype(current_mob.loc, /obj/structure/closet/secure_closet/freezer/fridge)) - continue - current_mob.death(create_cause_data("nuclear explosion")) - else - if(play_anim) - current_mob.client.remove_from_screen(C) //those who managed to escape the z level at last second shouldn't have their view obstructed. - if(play_anim) - flick(ship_status ? "ship_spared" : "ship_destroyed", C) - C.icon_state = ship_status ? "summary_spared" : "summary_destroyed" - world << sound('sound/effects/explosionfar.ogg') - - if(end_round) - dest_status = end_type - - sleep(5) - if(SSticker.mode) - SSticker.mode.check_win() - - if(!SSticker.mode) //Just a safety, just in case a mode isn't running, somehow. - to_world(SPAN_ROUNDBODY("Resetting in 30 seconds!")) - sleep(300) - log_game("Rebooting due to nuclear detonation.") - world.Reboot() - return TRUE - -/datum/authority/branch/evacuation/proc/process_self_destruct() - set background = 1 - - spawn while(dest_master && dest_master.loc && dest_master.active_state == SELF_DESTRUCT_MACHINE_ARMED && dest_status == NUKE_EXPLOSION_ACTIVE && dest_index <= dest_rods.len) - var/obj/structure/machinery/self_destruct/rod/I = dest_rods[dest_index] - if(world.time >= dest_cooldown + I.activate_time) - I.lock_or_unlock() //Unlock it. - if(++dest_index <= dest_rods.len) - I = dest_rods[dest_index]//Start the next sequence. - I.activate_time = world.time - sleep(10) //Checks every second. Could integrate into another controller for better tracking. - -//Generic parent base for the self_destruct items. -/obj/structure/machinery/self_destruct - icon = 'icons/obj/structures/machinery/self_destruct.dmi' - icon_state = "console_1" - var/base_icon_state = "console" - use_power = USE_POWER_NONE //Runs unpowered, may need to change later. - density = FALSE - anchored = TRUE //So it doesn't go anywhere. - unslashable = TRUE - unacidable = TRUE //Cannot C4 it either. - mouse_opacity = FALSE //No need to click or interact with this initially. - var/in_progress = 0 //Cannot interact with while it's doing something, like an animation. - var/active_state = SELF_DESTRUCT_MACHINE_INACTIVE //What step of the process it's on. - -/obj/structure/machinery/self_destruct/Initialize(mapload, ...) - . = ..() - icon_state = "[base_icon_state]_1" - -/obj/structure/machinery/self_destruct/Destroy() - . = ..() - machines -= src - operator = null - -/obj/structure/machinery/self_destruct/ex_act(severity) - return FALSE - -/obj/structure/machinery/self_destruct/attack_hand() - if(..() || in_progress) - return FALSE //This check is backward, ugh. - return TRUE - -//Add sounds. -/obj/structure/machinery/self_destruct/proc/lock_or_unlock(lock) - set waitfor = 0 - in_progress = 1 - flick("[base_icon_state]" + (lock? "_5" : "_2"),src) - sleep(9) - mouse_opacity = !mouse_opacity - icon_state = "[base_icon_state]" + (lock? "_1" : "_3") - in_progress = 0 - active_state = active_state > SELF_DESTRUCT_MACHINE_INACTIVE ? SELF_DESTRUCT_MACHINE_INACTIVE : SELF_DESTRUCT_MACHINE_ACTIVE - -/obj/structure/machinery/self_destruct/console - name = "self-destruct control panel" - icon_state = "console_1" - base_icon_state = "console" - req_one_access = list(ACCESS_MARINE_CO, ACCESS_MARINE_SENIOR) - -/obj/structure/machinery/self_destruct/console/Destroy() - . = ..() - EvacuationAuthority.dest_master = null - EvacuationAuthority.dest_rods = null - -/obj/structure/machinery/self_destruct/console/lock_or_unlock(lock) - playsound(src, 'sound/machines/hydraulics_1.ogg', 25, 1) - ..() - -//TODO: Add sounds. -/obj/structure/machinery/self_destruct/console/attack_hand(mob/user) - if(inoperable()) - return - - tgui_interact(user) - -/obj/structure/machinery/self_destruct/console/tgui_interact(mob/user, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "SelfDestructConsole", name) - ui.open() - -/obj/structure/machinery/sleep_console/ui_status(mob/user, datum/ui_state/state) - . = ..() - if(inoperable()) - return UI_CLOSE - - -/obj/structure/machinery/self_destruct/console/ui_data(mob/user) - var/list/data = list() - - data["dest_status"] = active_state - - return data - -/obj/structure/machinery/self_destruct/console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) - . = ..() - if(.) - return - - switch(action) - if("dest_start") - to_chat(usr, SPAN_NOTICE("You press a few keys on the panel.")) - to_chat(usr, SPAN_NOTICE("The system must be booting up the self-destruct sequence now.")) - playsound(src.loc, 'sound/items/rped.ogg', 25, TRUE) - sleep(2 SECONDS) - ai_announcement("Danger. The emergency destruct system is now activated. The ship will detonate in T-minus 20 minutes. Automatic detonation is unavailable. Manual detonation is required.", 'sound/AI/selfdestruct.ogg') - active_state = SELF_DESTRUCT_MACHINE_ARMED //Arm it here so the process can execute it later. - var/obj/structure/machinery/self_destruct/rod/I = EvacuationAuthority.dest_rods[EvacuationAuthority.dest_index] - I.activate_time = world.time - EvacuationAuthority.process_self_destruct() - . = TRUE - - if("dest_trigger") - EvacuationAuthority.initiate_self_destruct() - . = TRUE - - if("dest_cancel") - if(!allowed(usr)) - to_chat(usr, SPAN_WARNING("You don't have the necessary clearance to cancel the emergency destruct system!")) - return - EvacuationAuthority.cancel_self_destruct() - . = TRUE - -/obj/structure/machinery/self_destruct/rod - name = "self-destruct control rod" - desc = "It is part of a complicated self-destruct sequence, but relatively simple to operate. Twist to arm or disarm." - icon_state = "rod_1" - base_icon_state = "rod" - layer = BELOW_OBJ_LAYER - var/activate_time - -/obj/structure/machinery/self_destruct/rod/Destroy() - . = ..() - if(EvacuationAuthority && EvacuationAuthority.dest_rods) - EvacuationAuthority.dest_rods -= src - -/obj/structure/machinery/self_destruct/rod/lock_or_unlock(lock) - playsound(src, 'sound/machines/hydraulics_2.ogg', 25, 1) - ..() - if(lock) - activate_time = null - density = FALSE - layer = initial(layer) - else - density = TRUE - layer = ABOVE_OBJ_LAYER - -/obj/structure/machinery/self_destruct/rod/attack_hand(mob/user) - if(..()) - switch(active_state) - if(SELF_DESTRUCT_MACHINE_ACTIVE) - to_chat(user, SPAN_NOTICE("You twist and release the control rod, arming it.")) - playsound(src, 'sound/machines/switch.ogg', 25, 1) - icon_state = "rod_4" - active_state = SELF_DESTRUCT_MACHINE_ARMED - if(SELF_DESTRUCT_MACHINE_ARMED) - to_chat(user, SPAN_NOTICE("You twist and release the control rod, disarming it.")) - playsound(src, 'sound/machines/switch.ogg', 25, 1) - icon_state = "rod_3" - active_state = SELF_DESTRUCT_MACHINE_ACTIVE - else to_chat(user, SPAN_WARNING("The control rod is not ready.")) diff --git a/code/game/gamemodes/colonialmarines/colonialmarines.dm b/code/game/gamemodes/colonialmarines/colonialmarines.dm index df04873ac140..7b1c695ade2b 100644 --- a/code/game/gamemodes/colonialmarines/colonialmarines.dm +++ b/code/game/gamemodes/colonialmarines/colonialmarines.dm @@ -297,29 +297,25 @@ if(SSticker.current_state != GAME_STATE_PLAYING) return - var/living_player_list[] = count_humans_and_xenos(EvacuationAuthority.get_affected_zlevels()) + var/living_player_list[] = count_humans_and_xenos(get_affected_zlevels()) var/num_humans = living_player_list[1] var/num_xenos = living_player_list[2] if(force_end_at && world.time > force_end_at) round_finished = MODE_INFESTATION_X_MINOR - if(EvacuationAuthority.dest_status == NUKE_EXPLOSION_FINISHED) - round_finished = MODE_GENERIC_DRAW_NUKE //Nuke went off, ending the round. - if(EvacuationAuthority.dest_status == NUKE_EXPLOSION_GROUND_FINISHED) - round_finished = MODE_INFESTATION_M_MINOR //Nuke went off, ending the round. - if(EvacuationAuthority.dest_status < NUKE_EXPLOSION_IN_PROGRESS) //If the nuke ISN'T in progress. We do not want to end the round before it detonates. - if(!num_humans && num_xenos) //No humans remain alive. - round_finished = MODE_INFESTATION_X_MAJOR //Evacuation did not take place. Everyone died. - else if(num_humans && !num_xenos) - if(SSticker.mode && SSticker.mode.is_in_endgame) - round_finished = MODE_INFESTATION_X_MINOR //Evacuation successfully took place. - else - SSticker.roundend_check_paused = TRUE - round_finished = MODE_INFESTATION_M_MAJOR //Humans destroyed the xenomorphs. - ares_conclude() - addtimer(VARSET_CALLBACK(SSticker, roundend_check_paused, FALSE), MARINE_MAJOR_ROUND_END_DELAY) - else if(!num_humans && !num_xenos) - round_finished = MODE_INFESTATION_DRAW_DEATH //Both were somehow destroyed. + + if(!num_humans && num_xenos) //No humans remain alive. + round_finished = MODE_INFESTATION_X_MAJOR //Evacuation did not take place. Everyone died. + else if(num_humans && !num_xenos) + if(SSticker.mode && SSticker.mode.is_in_endgame) + round_finished = MODE_INFESTATION_X_MINOR //Evacuation successfully took place. + else + SSticker.roundend_check_paused = TRUE + round_finished = MODE_INFESTATION_M_MAJOR //Humans destroyed the xenomorphs. + ares_conclude() + addtimer(VARSET_CALLBACK(SSticker, roundend_check_paused, FALSE), MARINE_MAJOR_ROUND_END_DELAY) + else if(!num_humans && !num_xenos) + round_finished = MODE_INFESTATION_DRAW_DEATH //Both were somehow destroyed. /datum/game_mode/colonialmarines/check_queen_status(hivenumber) set waitfor = 0 @@ -367,7 +363,7 @@ round_statistics.current_map.total_marine_victories++ round_statistics.current_map.total_marine_majors++ if(MODE_INFESTATION_X_MINOR) - var/list/living_player_list = count_humans_and_xenos(EvacuationAuthority.get_affected_zlevels()) + var/list/living_player_list = count_humans_and_xenos(get_affected_zlevels()) if(living_player_list[1] && !living_player_list[2]) // If Xeno Minor but Xenos are dead and Humans are alive, see which faction is the last standing var/headcount = count_per_faction() var/living = headcount["total_headcount"] diff --git a/code/game/gamemodes/extended/infection.dm b/code/game/gamemodes/extended/infection.dm index 04e0545361aa..a6b909022aef 100644 --- a/code/game/gamemodes/extended/infection.dm +++ b/code/game/gamemodes/extended/infection.dm @@ -95,7 +95,7 @@ possible_survivors -= new_survivor //either we drafted a survivor, or we're skipping over someone, either or - remove them /datum/game_mode/infection/check_win() - var/living_player_list[] = count_humans_and_xenos(EvacuationAuthority.get_affected_zlevels()) + var/list/living_player_list = count_humans_and_xenos(get_affected_zlevels()) var/num_humans = living_player_list[1] var/zed = living_player_list[2] diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 5382d80f37a2..e467631c915e 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -111,6 +111,10 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki log_game("Server IP: [world.internet_address]:[world.port]") return TRUE +/datum/game_mode/proc/get_affected_zlevels() + if(is_in_endgame) + . = SSmapping.levels_by_any_trait(list(ZTRAIT_MARINE_MAIN_SHIP)) + return ///process() ///Called by the gameticker @@ -119,8 +123,7 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki /datum/game_mode/proc/check_finished() //to be called by ticker - if(EvacuationAuthority.dest_status == NUKE_EXPLOSION_FINISHED || EvacuationAuthority.dest_status == NUKE_EXPLOSION_GROUND_FINISHED ) - return TRUE + return /datum/game_mode/proc/cleanup() //This is called when the round has ended but not the game, if any cleanup would be necessary in that case. return diff --git a/code/game/machinery/ARES/ARES_interface.dm b/code/game/machinery/ARES/ARES_interface.dm index 64755897bc8e..0e45d5ee171b 100644 --- a/code/game/machinery/ARES/ARES_interface.dm +++ b/code/game/machinery/ARES/ARES_interface.dm @@ -79,7 +79,7 @@ data["access_level"] = authentication data["alert_level"] = security_level - data["evac_status"] = EvacuationAuthority.evac_status + data["evac_status"] = SShijack.evac_status data["worldtime"] = world.time data["access_log"] = datacore.interface_access_list @@ -397,12 +397,12 @@ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE - if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY) + if(SShijack.evac_admin_denied) to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods.")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE - if(!EvacuationAuthority.initiate_evacuation()) + if(!SShijack.initiate_evacuation()) to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE diff --git a/code/game/machinery/computer/almayer_control.dm b/code/game/machinery/computer/almayer_control.dm index 145d0d278cb6..fb9f7a0375d9 100644 --- a/code/game/machinery/computer/almayer_control.dm +++ b/code/game/machinery/computer/almayer_control.dm @@ -81,9 +81,9 @@ data["worldtime"] = world.time - data["evac_status"] = EvacuationAuthority.evac_status - if(EvacuationAuthority.evac_status == EVACUATION_STATUS_INITIATING) - data["evac_eta"] = EvacuationAuthority.get_status_panel_eta() + data["evac_status"] = SShijack.evac_status + if(SShijack.evac_status == EVACUATION_STATUS_INITIATED) + data["evac_eta"] = SShijack.get_evac_eta() if(!messagetitle.len) data["messages"] = null @@ -120,11 +120,11 @@ to_chat(usr, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures.")) return FALSE - if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY) + if(SShijack.evac_admin_denied) to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods.")) return FALSE - if(!EvacuationAuthority.initiate_evacuation()) + if(!SShijack.initiate_evacuation()) to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!")) return FALSE @@ -134,12 +134,10 @@ . = TRUE if("evacuation_cancel") - if(!EvacuationAuthority.cancel_evacuation()) + if(!SShijack.cancel_evacuation()) to_chat(usr, SPAN_WARNING("You are unable to cancel the evacuation right now!")) return FALSE - addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/structure/machinery/computer/almayer_control, cancel_evac)), 4 SECONDS) - log_game("[key_name(usr)] has canceled the emergency evacuation.") message_admins("[key_name_admin(usr)] has canceled the emergency evacuation.") log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.") @@ -276,10 +274,3 @@ // end tgui interact \\ // end tgui \\ - -/obj/structure/machinery/computer/almayer_control/proc/cancel_evac() - if(EvacuationAuthority.evac_status == EVACUATION_STATUS_STANDING_BY)//nothing changed during the wait - //if the self_destruct is active we try to cancel it (which includes lowering alert level to red) - if(!EvacuationAuthority.cancel_self_destruct(1)) - //if SD wasn't active (likely canceled manually in the SD room), then we lower the alert level manually. - set_security_level(SEC_LEVEL_RED, TRUE) //both SD and evac are inactive, lowering the security level. diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index d4d45de8db4e..3332577683fe 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -138,11 +138,11 @@ to_chat(usr, SPAN_WARNING("The ship must be under delta alert in order to enact evacuation procedures.")) return FALSE - if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY) + if(SShijack.evac_admin_denied) to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods.")) return FALSE - if(!EvacuationAuthority.initiate_evacuation()) + if(!SShijack.initiate_evacuation()) to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!")) return FALSE @@ -155,17 +155,10 @@ if("evacuation_cancel") if(state == STATE_EVACUATION_CANCEL) - if(!EvacuationAuthority.cancel_evacuation()) + if(!SShijack.cancel_evacuation()) to_chat(usr, SPAN_WARNING("You are unable to cancel the evacuation right now!")) return FALSE - spawn(35)//some time between AI announcements for evac cancel and SD cancel. - if(EvacuationAuthority.evac_status == EVACUATION_STATUS_STANDING_BY)//nothing changed during the wait - //if the self_destruct is active we try to cancel it (which includes lowering alert level to red) - if(!EvacuationAuthority.cancel_self_destruct(1)) - //if SD wasn't active (likely canceled manually in the SD room), then we lower the alert level manually. - set_security_level(SEC_LEVEL_RED, TRUE) //both SD and evac are inactive, lowering the security level. - log_game("[key_name(usr)] has canceled the emergency evacuation.") message_admins("[key_name_admin(usr)] has canceled the emergency evacuation.") log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.") @@ -327,8 +320,8 @@ user.set_interaction(src) var/dat = "