diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index c465c357c148..a1233b0479a4 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -1369,19 +1369,6 @@ }, /turf/open/floor/iron, /area/centcom/tdome/observation) -"dY" = ( -/obj/effect/turf_decal/siding/thinplating_new/dark{ - dir = 8 - }, -/obj/structure/table/glass/plasmaglass, -/obj/item/folder/white, -/obj/item/pen{ - pixel_x = 6; - pixel_y = 5 - }, -/obj/machinery/light/cold/directional/west, -/turf/open/floor/mineral/plastitanium, -/area/centcom/syndicate_mothership/control) "dZ" = ( /obj/item/kirbyplants{ icon_state = "plant-21" @@ -5646,16 +5633,6 @@ }, /turf/open/floor/iron, /area/centcom/central_command_areas/supplypod/loading/ert) -"pY" = ( -/obj/item/gun/energy/pulse/carbine, -/obj/item/flashlight/seclite, -/obj/structure/table/reinforced, -/obj/machinery/airalarm/directional/south, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/turf/open/floor/iron, -/area/centcom/central_command_areas/admin/storage) "pZ" = ( /obj/effect/turf_decal/tile/bar, /obj/effect/turf_decal/tile/bar{ @@ -5932,6 +5909,10 @@ }, /turf/open/floor/iron/dark, /area/centcom/central_command_areas/supplypod) +"qJ" = ( +/obj/structure/filingcabinet/chestdrawer, +/turf/open/floor/iron/dark, +/area/centcom/central_command_areas/ferry) "qK" = ( /obj/machinery/air_sensor{ chamber_id = "nukiebase"; @@ -6714,6 +6695,12 @@ }, /turf/open/floor/wood, /area/centcom/central_command_areas/admin) +"tm" = ( +/obj/machinery/light/directional/south, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/status_display/evac/directional/south, +/turf/open/floor/iron/dark, +/area/centcom/central_command_areas/ferry) "tn" = ( /obj/machinery/power/apc/auto_name/directional/south, /obj/structure/cable/smart_cable/color/yellow, @@ -7003,15 +6990,6 @@ /obj/effect/turf_decal/siding/thinplating_new/dark, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bioterrorism) -"um" = ( -/obj/machinery/computer/communications{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 5 - }, -/turf/open/floor/iron, -/area/centcom/central_command_areas/ferry) "uo" = ( /obj/machinery/light/floor/has_bulb, /turf/open/floor/catwalk_floor/titanium, @@ -8126,17 +8104,6 @@ /obj/machinery/vending/snack, /turf/open/floor/engine/cult, /area/centcom/wizard_station) -"xy" = ( -/obj/structure/table/reinforced, -/obj/item/paper/fluff/stations/centcom/disk_memo{ - pixel_x = -6; - pixel_y = -7 - }, -/obj/item/taperecorder{ - pixel_y = 15 - }, -/turf/open/floor/carpet, -/area/centcom/syndicate_mothership/control) "xz" = ( /obj/structure/table/wood/fancy, /obj/item/storage/photo_album, @@ -8719,6 +8686,17 @@ }, /turf/open/misc/asteroid/snow/airless, /area/centcom/syndicate_mothership) +"zv" = ( +/obj/structure/table/reinforced, +/obj/item/paper/fluff/stations/centcom/disk_memo{ + pixel_x = -6; + pixel_y = -7 + }, +/obj/item/taperecorder{ + pixel_y = 15 + }, +/turf/open/floor/carpet, +/area/centcom/syndicate_mothership/control) "zw" = ( /obj/structure/sign/nanotrasen, /turf/closed/indestructible/reinforced/centcom, @@ -9466,13 +9444,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/centcom/tdome/administration) -"By" = ( -/obj/machinery/light/directional/south, -/obj/structure/filingcabinet/chestdrawer, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/machinery/status_display/evac/directional/south, -/turf/open/floor/iron/dark, -/area/centcom/central_command_areas/ferry) "Bz" = ( /obj/effect/light_emitter{ set_cap = 1; @@ -11853,18 +11824,6 @@ }, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/expansion_chemicalwarfare) -"Ir" = ( -/obj/machinery/computer/emergency_shuttle{ - dir = 1 - }, -/obj/machinery/newscaster{ - pixel_y = -32 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 9 - }, -/turf/open/floor/iron, -/area/centcom/central_command_areas/ferry) "Is" = ( /obj/machinery/igniter/on, /obj/effect/turf_decal/delivery, @@ -13310,6 +13269,18 @@ /obj/item/reagent_containers/food/drinks/trophy/gold_cup, /turf/open/floor/iron/grimy, /area/centcom/tdome/observation) +"Nf" = ( +/obj/machinery/newscaster{ + pixel_y = -32 + }, +/obj/machinery/computer/communications{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/end{ + dir = 1 + }, +/turf/open/floor/iron, +/area/centcom/central_command_areas/ferry) "Ng" = ( /obj/item/storage/box/ids{ pixel_x = 3; @@ -14409,6 +14380,19 @@ /obj/structure/flora/grass/both, /turf/open/misc/asteroid/snow, /area/centcom/syndicate_mothership/control) +"Qt" = ( +/obj/effect/turf_decal/siding/thinplating_new/dark{ + dir = 8 + }, +/obj/structure/table/glass/plasmaglass, +/obj/item/folder/white, +/obj/item/pen{ + pixel_x = 6; + pixel_y = 5 + }, +/obj/machinery/light/cold/directional/west, +/turf/open/floor/mineral/plastitanium, +/area/centcom/syndicate_mothership/control) "Qu" = ( /obj/structure/window/paperframe{ can_atmos_pass = 4 @@ -17321,6 +17305,16 @@ "Ya" = ( /turf/closed/indestructible/reinforced/centcom, /area/centcom/central_command_areas/armory) +"Yb" = ( +/obj/item/gun/energy/pulse/carbine, +/obj/item/flashlight/seclite, +/obj/structure/table/reinforced, +/obj/machinery/airalarm/directional/south, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/iron, +/area/centcom/central_command_areas/admin/storage) "Yc" = ( /obj/structure/fireplace, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -25612,7 +25606,7 @@ ng VX XE od -dY +Qt Sr nz br @@ -37183,7 +37177,7 @@ nz HN gJ dy -xy +zv nt HJ VJ @@ -52858,7 +52852,7 @@ oe rm ss tq -Ir +Nf mD vA oe @@ -53115,7 +53109,7 @@ oe rn st tr -um +qJ mD vB oe @@ -53372,7 +53366,7 @@ mD WY su ts -By +tm mD vC wr @@ -58511,7 +58505,7 @@ XA Sx Nn yi -pY +Yb YU vb oe diff --git a/_maps/multiz_debug.json b/_maps/multiz_debug.json index 4ffc3abd519e..f8ce1a3e1db2 100644 --- a/_maps/multiz_debug.json +++ b/_maps/multiz_debug.json @@ -3,6 +3,9 @@ "map_name": "MultiZ Debug", "map_path": "map_files/debug", "map_file": "multiz.dmm", + "evacuation_controllers": [ + "/datum/evacuation_controller/emergency_shuttle" + ], "traits": [ { "Up": 1, diff --git a/_maps/runtimestation.json b/_maps/runtimestation.json index 6b77a7321f21..db37c0ce3300 100644 --- a/_maps/runtimestation.json +++ b/_maps/runtimestation.json @@ -3,6 +3,9 @@ "map_name": "Runtime Station", "map_path": "map_files/debug", "map_file": "runtimestation.dmm", + "evacuation_controllers": [ + "/datum/evacuation_controller/emergency_shuttle" + ], "space_ruin_levels": 1, "shuttles": { "cargo": "cargo_delta" diff --git a/_maps/shuttles/emergency_bar.dmm b/_maps/shuttles/emergency_bar.dmm index 8891aaa82e72..2036966585ab 100644 --- a/_maps/shuttles/emergency_bar.dmm +++ b/_maps/shuttles/emergency_bar.dmm @@ -555,19 +555,6 @@ }, /turf/open/floor/mineral/titanium, /area/shuttle/escape) -"bV" = ( -/obj/structure/table/wood/shuttle_bar{ - boot_dir = 8 - }, -/obj/effect/fun_balloon/sentience/emergency_shuttle{ - group_name = "bar staff on the Emergency Escape Bar" - }, -/obj/effect/turf_decal/tile/bar, -/obj/effect/turf_decal/tile/bar{ - dir = 1 - }, -/turf/open/floor/iron, -/area/shuttle/escape) "bW" = ( /obj/machinery/light/small/directional/east, /turf/open/floor/iron/grimy, @@ -810,7 +797,7 @@ bG aE aO aR -bV +aR aR aR aR diff --git a/_maps/shuttles/emergency_cruise.dmm b/_maps/shuttles/emergency_cruise.dmm index 5a24b869a06b..165f61f57200 100644 --- a/_maps/shuttles/emergency_cruise.dmm +++ b/_maps/shuttles/emergency_cruise.dmm @@ -1069,9 +1069,6 @@ /obj/item/reagent_containers/glass/rag{ pixel_y = 7 }, -/obj/effect/fun_balloon/sentience/emergency_shuttle{ - group_name = "bar staff on the NTSS Independence" - }, /turf/open/floor/wood, /area/shuttle/escape) "Vk" = ( diff --git a/_maps/shuttles/emergency_narnar.dmm b/_maps/shuttles/emergency_narnar.dmm index ec5d26d3bd8a..95e6452f1e40 100644 --- a/_maps/shuttles/emergency_narnar.dmm +++ b/_maps/shuttles/emergency_narnar.dmm @@ -171,10 +171,6 @@ /area/shuttle/escape) "I" = ( /obj/effect/rune/narsie, -/obj/effect/fun_balloon/sentience/emergency_shuttle{ - effect_range = 5; - group_name = "horrible monsters on Shuttle 667" - }, /turf/open/floor/cult, /area/shuttle/escape) "J" = ( diff --git a/_maps/shuttles/emergency_rollerdome.dmm b/_maps/shuttles/emergency_rollerdome.dmm index 9be037940ed4..a445c8b0fbe2 100644 --- a/_maps/shuttles/emergency_rollerdome.dmm +++ b/_maps/shuttles/emergency_rollerdome.dmm @@ -70,13 +70,6 @@ /obj/machinery/vending/games, /turf/open/floor/eighties, /area/shuttle/escape) -"ns" = ( -/obj/structure/table/wood/shuttle_bar, -/obj/effect/fun_balloon/sentience/emergency_shuttle{ - group_name = "snack bar drone at Uncle Pete's Rollerdome" - }, -/turf/open/floor/wood, -/area/shuttle/escape) "nw" = ( /obj/structure/table, /obj/machinery/chem_dispenser/drinks{ @@ -464,7 +457,7 @@ dJ Cg Cg ce -ns +Ky Qv JR KJ diff --git a/_maps/theseus.json b/_maps/theseus.json index cf1b931f4e6a..82609fc799f8 100644 --- a/_maps/theseus.json +++ b/_maps/theseus.json @@ -4,6 +4,9 @@ "map_path": "map_files/Theseus", "map_file": "Theseus.dmm", "webmap_id": "Theseus", + "evacuation_controllers": [ + "/datum/evacuation_controller/emergency_shuttle" + ], "shuttles": { "cargo": "cargo_box", "ferry": "ferry_fancy", diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 1ed5a60e97aa..c6b7c004d872 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -38,14 +38,6 @@ #define DEATHSQUAD "ds" #define DEATHSQUAD_LEADER "ds_leader" -//Shuttle elimination hijacking -/// Does not stop elimination hijacking but itself won't elimination hijack -#define ELIMINATION_NEUTRAL 0 -/// Needs to be present for shuttle to be elimination hijacked -#define ELIMINATION_ENABLED 1 -/// Prevents elimination hijack same way as non-antags -#define ELIMINATION_PREVENT 2 - //Syndicate Contracts #define CONTRACT_STATUS_INACTIVE 1 #define CONTRACT_STATUS_ACTIVE 2 @@ -125,12 +117,6 @@ /// JSON string file for all of our heretic influence flavors #define HERETIC_INFLUENCE_FILE "antagonist_flavor/heretic_influences.json" -///employers who hire agents to do the hijack -GLOBAL_LIST_INIT(hijack_employers, list( - "Legal Trouble", - "Gone Postal", -)) - ///employers who hire agents to do a task and escape... GLOBAL_LIST_INIT(normal_employers, list( "Legal Trouble", diff --git a/code/__DEFINES/dcs/signals/signals_evacuation.dm b/code/__DEFINES/dcs/signals/signals_evacuation.dm new file mode 100644 index 000000000000..e2a0bd09ef34 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_evacuation.dm @@ -0,0 +1,8 @@ +///from emergency shuttle when arriving at station : () +#define COMSIG_EMERGENCYSHUTTLE_ARRIVAL "emergencyshuttle_arrival" +///from emergency shuttle when making departing sound : () +#define COMSIG_EMERGENCYSHUTTLE_ANNOUNCE "emergencyshuttle_announce" +///from emergency shuttle when departing from station : () +#define COMSIG_EMERGENCYSHUTTLE_DEPARTING "emergencyshuttle_departing" +///from emergency shuttle when returning to CentCom : () +#define COMSIG_EMERGENCYSHUTTLE_RETURNED "emergencyshuttle_returned" diff --git a/code/__DEFINES/dcs/signals/signals_global_object.dm b/code/__DEFINES/dcs/signals/signals_global_object.dm index 452be16f8391..1212217440fe 100644 --- a/code/__DEFINES/dcs/signals/signals_global_object.dm +++ b/code/__DEFINES/dcs/signals/signals_global_object.dm @@ -6,7 +6,7 @@ ///from SSsun when the sun changes position : (azimuth) #define COMSIG_SUN_MOVED "sun_moved" -///from SSsecurity_level when the security level changes : (new_level) +///from SSsecurity_level when the security level changes : (old_level, new_level) #define COMSIG_SECURITY_LEVEL_CHANGED "security_level_changed" ///from SSshuttle when the supply shuttle starts spawning orders : () diff --git a/code/__DEFINES/evacuation.dm b/code/__DEFINES/evacuation.dm new file mode 100644 index 000000000000..d9f3803e71be --- /dev/null +++ b/code/__DEFINES/evacuation.dm @@ -0,0 +1,13 @@ +// States for the evacuation controller +#define EVACUATION_STATE_IDLE 0 +#define EVACUATION_STATE_INITIATED 1 // Evacuation has begun, but it can be cancelled +#define EVACUATION_STATE_AWAITING 2 // Awaiting players to board the shuttle/pods/etc, can't be cancelled but can be delayed +#define EVACUATION_STATE_EVACUATED 3 // Shuttle/pods/etc have departed, can't be cancelled nor delayed +#define EVACUATION_STATE_FINISHED 4 + +// Reasons for automatic evacuation +#define EVACUATION_REASON_CREW_DEATH "crew_death" +#define EVACUATION_REASON_LONG_ROUND "long_round" +#define EVACUATION_REASON_VOTE "vote" +#define EVACUATION_REASON_CONSOLE_DESTROYED "console_destroyed" +#define EVACUATION_REASON_AI_DESTROYED "ai_destroyed" diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm index 447ef1cc165a..8b9f6fbbe145 100644 --- a/code/__DEFINES/hud.dm +++ b/code/__DEFINES/hud.dm @@ -160,7 +160,7 @@ #define ui_ai_crew_manifest "SOUTH:6,WEST+5" #define ui_ai_alerts "SOUTH:6,WEST+6" #define ui_ai_announcement "SOUTH:6,WEST+7" -#define ui_ai_shuttle "SOUTH:6,WEST+8" +#define ui_ai_evac "SOUTH:6,WEST+8" #define ui_ai_state_laws "SOUTH:6,WEST+9" #define ui_ai_mod_int "SOUTH:6,WEST+10" #define ui_ai_take_picture "SOUTH:6,WEST+11" diff --git a/code/__DEFINES/roundend.dm b/code/__DEFINES/roundend.dm index bf3367510219..384cdb35ebc3 100644 --- a/code/__DEFINES/roundend.dm +++ b/code/__DEFINES/roundend.dm @@ -1,7 +1,7 @@ //Endgame Results /// Nuke was detonated in space on same z-level as station #define NUKE_NEAR_MISS 1 -/// Nuke was detonated on another z-level +/// Nuke was detonated on another z-level #define NUKE_MISS_STATION 2 /// Nuke was detonated on the syndicate base #define NUKE_SYNDICATE_BASE 3 @@ -35,9 +35,7 @@ #define WIZARD_KILLED 19 /// The station was destroyed by it's own self-destruct nuclear device #define STATION_NUKED 20 -/// The emergency shuttle was successfully hijacked -#define SHUTTLE_HIJACK 24 /// The gangs on the station were thwarted #define GANG_DESTROYED 25 // Looks like it was deprecated at some point - Jan 2022 /// The gangs on the station still exist -#define GANG_OPERATING 26 +#define GANG_OPERATING 26 diff --git a/code/__DEFINES/shuttles.dm b/code/__DEFINES/shuttles.dm index 5b906d97bf30..3201602eddaa 100644 --- a/code/__DEFINES/shuttles.dm +++ b/code/__DEFINES/shuttles.dm @@ -11,11 +11,6 @@ #define SHUTTLE_RECHARGING "recharging" #define SHUTTLE_PREARRIVAL "landing" -#define EMERGENCY_IDLE_OR_RECALLED (SSshuttle.emergency && ((SSshuttle.emergency.mode == SHUTTLE_IDLE) || (SSshuttle.emergency.mode == SHUTTLE_RECALL))) -#define EMERGENCY_ESCAPED_OR_ENDGAMED (SSshuttle.emergency && ((SSshuttle.emergency.mode == SHUTTLE_ESCAPE) || (SSshuttle.emergency.mode == SHUTTLE_ENDGAME))) -#define EMERGENCY_AT_LEAST_DOCKED (SSshuttle.emergency && SSshuttle.emergency.mode != SHUTTLE_IDLE && SSshuttle.emergency.mode != SHUTTLE_RECALL && SSshuttle.emergency.mode != SHUTTLE_CALL) -#define EMERGENCY_PAST_POINT_OF_NO_RETURN ((SSshuttle.emergency && SSshuttle.emergency.mode == SHUTTLE_CALL && !SSshuttle.canRecall()) || EMERGENCY_AT_LEAST_DOCKED) - // Shuttle return values #define SHUTTLE_CAN_DOCK "can_dock" #define SHUTTLE_NOT_A_DOCKING_PORT "not a docking port" @@ -53,7 +48,7 @@ #define HYPERSPACE_LAUNCH 2 #define HYPERSPACE_END 3 -#define CALL_SHUTTLE_REASON_LENGTH 12 +#define EVAC_REASON_LENGTH 12 //Engine related #define ENGINE_COEFF_MIN 0.5 diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 9b5e215a2d60..38f59f76a6dd 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -165,6 +165,7 @@ #define INIT_ORDER_STICKY_BAN -10 #define INIT_ORDER_LIGHTING -20 #define INIT_ORDER_SHUTTLE -21 +#define INIT_ORDER_EVACUATION -22 #define INIT_ORDER_MINOR_MAPPING -40 #define INIT_ORDER_PATH -50 #define INIT_ORDER_DECAY -61 diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm index 9ca782860b77..65debbf934b2 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/_logging.dm @@ -249,6 +249,10 @@ GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global")) if (CONFIG_GET(flag/log_shuttle)) WRITE_LOG(GLOB.world_shuttle_log, "SHUTTLE: [text]") +/proc/log_evacuation(text) + if (CONFIG_GET(flag/log_evacuation)) + WRITE_LOG(GLOB.world_evacuation_log, "EVACUATION: [text]") + /proc/log_topic(text) WRITE_LOG(GLOB.world_game_log, "TOPIC: [text]") diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index 5a25fb2cc491..008cce1c08e9 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -1,6 +1,6 @@ #define POPCOUNT_SURVIVORS "survivors" //Not dead at roundend #define POPCOUNT_ESCAPEES "escapees" //Not dead and on centcom/shuttles marked as escaped -#define POPCOUNT_SHUTTLE_ESCAPEES "shuttle_escapees" //Emergency shuttle only. +#define POPCOUNT_EVAC_ESCAPEES "evac_escapees" //Evac means shuttle only. #define POPCOUNT_ESCAPEES_HUMANONLY "human_escapees" #define PERSONAL_LAST_ROUND "personal last round" #define SERVER_LAST_ROUND "server last round" @@ -17,9 +17,7 @@ var/num_shuttle_escapees = 0 //Above and on escape shuttle var/list/list_of_human_escapees = list() //References to all escaped humans var/list/list_of_mobs_on_shuttle = list() - var/list/area/shuttle_areas - if(SSshuttle?.emergency) - shuttle_areas = SSshuttle.emergency.shuttle_areas + var/list/area/evac_areas = SSevacuation.get_endgame_areas() for(var/mob/M in GLOB.mob_list) var/list/mob_data = list() @@ -38,13 +36,13 @@ list_of_mobs_on_shuttle += M if(M.stat != DEAD && !isbrain(M) && !iscameramob(M)) num_survivors++ - if(EMERGENCY_ESCAPED_OR_ENDGAMED && (M.onCentCom() || M.onSyndieBase())) + if(M.onCentCom() || M.onSyndieBase() || evac_areas[get_area(M)]) num_escapees++ if(ishuman(M)) num_human_escapees++ list_of_human_escapees += M escape_status = "escapees" - if(shuttle_areas[get_area(M)]) + if(evac_areas[get_area(M)]) num_shuttle_escapees++ if(isliving(M)) var/mob/living/L = M @@ -110,7 +108,7 @@ .[POPCOUNT_SURVIVORS] = num_survivors .[POPCOUNT_ESCAPEES] = num_escapees .[POPCOUNT_ESCAPEES_HUMANONLY] = num_human_escapees - .[POPCOUNT_SHUTTLE_ESCAPEES] = num_shuttle_escapees + .[POPCOUNT_EVAC_ESCAPEES] = num_shuttle_escapees .["all_mobs_on_shuttle"] = list_of_mobs_on_shuttle .["human_escapees_list"] = list_of_human_escapees .["station_integrity"] = station_integrity @@ -330,7 +328,6 @@ /datum/controller/subsystem/ticker/proc/survivor_report(popcount) var/list/parts = list() - var/station_evacuated = EMERGENCY_ESCAPED_OR_ENDGAMED if(GLOB.round_id) var/statspage = CONFIG_GET(string/roundstatsurl) @@ -341,9 +338,8 @@ var/total_players = GLOB.joined_player_list.len if(total_players) parts+= "[FOURSPACES]Total Population: [total_players]" - if(station_evacuated) - parts += "
[FOURSPACES]Evacuation Rate: [popcount[POPCOUNT_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_ESCAPEES]/total_players)]%)" - parts += "[FOURSPACES](on emergency shuttle): [popcount[POPCOUNT_SHUTTLE_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_SHUTTLE_ESCAPEES]/total_players)]%)" + parts += "
[FOURSPACES]Evacuation Rate: [popcount[POPCOUNT_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_ESCAPEES]/total_players)]%)" + parts += "[FOURSPACES](on means of evacuation): [popcount[POPCOUNT_EVAC_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_EVAC_ESCAPEES]/total_players)]%)" parts += "[FOURSPACES]Survival Rate: [popcount[POPCOUNT_SURVIVORS]] ([PERCENT(popcount[POPCOUNT_SURVIVORS]/total_players)]%)" if(SSblackbox.first_death) var/list/ded = SSblackbox.first_death @@ -421,8 +417,9 @@ var/mob/M = C.mob if(M.mind && !isnewplayer(M)) if(M.stat != DEAD && !isbrain(M)) - if(EMERGENCY_ESCAPED_OR_ENDGAMED) - if(!M.onCentCom() && !M.onSyndieBase()) + if(SSevacuation.evacuation_finished()) + var/list/area/evac_areas = SSevacuation.get_endgame_areas() + if(!M.onCentCom() && !M.onSyndieBase() && !evac_areas[get_area(M)]) parts += "
" parts += "You managed to survive, but were marooned on [station_name()]..." else diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm index 6328be2ec463..1b3a23a8e20f 100644 --- a/code/_globalvars/logging.dm +++ b/code/_globalvars/logging.dm @@ -55,6 +55,8 @@ GLOBAL_VAR(tgui_log) GLOBAL_PROTECT(tgui_log) GLOBAL_VAR(world_shuttle_log) GLOBAL_PROTECT(world_shuttle_log) +GLOBAL_VAR(world_evacuation_log) +GLOBAL_PROTECT(world_evacuation_log) GLOBAL_VAR(filter_log) GLOBAL_PROTECT(filter_log) diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm index 0b3c4ebcabae..7cd2a650a10d 100644 --- a/code/_onclick/hud/ai.dm +++ b/code/_onclick/hud/ai.dm @@ -103,15 +103,15 @@ var/mob/living/silicon/ai/AI = usr AI.announcement() -/atom/movable/screen/ai/call_shuttle - name = "Call Emergency Shuttle" +/atom/movable/screen/ai/call_evac + name = "Start Evacuation" icon_state = "call_shuttle" -/atom/movable/screen/ai/call_shuttle/Click() +/atom/movable/screen/ai/call_evac/Click() if(..()) return var/mob/living/silicon/ai/AI = usr - AI.ai_call_shuttle() + AI.ai_start_evacuation() /atom/movable/screen/ai/state_laws name = "State Laws" @@ -232,9 +232,9 @@ using.screen_loc = ui_ai_announcement static_inventory += using -//Shuttle - using = new /atom/movable/screen/ai/call_shuttle(null, src) - using.screen_loc = ui_ai_shuttle +//Evac + using = new /atom/movable/screen/ai/call_evac(null, src) + using.screen_loc = ui_ai_evac static_inventory += using //Laws diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index 87c37194aa69..a1abf0541210 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -344,6 +344,15 @@ min_val = 0 max_val = 1 integer = FALSE + deprecated_by = /datum/config_entry/number/evacuation_autocall_threshold + +/datum/config_entry/number/emergency_shuttle_autocall_threshold/DeprecationUpdate(value) + return value + +/datum/config_entry/number/evacuation_autocall_threshold + min_val = 0 + max_val = 1 + integer = FALSE /datum/config_entry/flag/roundstart_traits diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index ca5d58a8364b..78a0fd982333 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -158,6 +158,9 @@ /// log shuttle related actions, ie shuttle computers, shuttle manipulator, emergency console /datum/config_entry/flag/log_shuttle +/// log evacuation related actions, ie when triggered, reasons, etc +/datum/config_entry/flag/log_evacuation + /// logs all timers in buckets on automatic bucket reset (Useful for timer debugging) /datum/config_entry/flag/log_timers_on_bucket_reset diff --git a/modular_pariah/modules/autotransfer/code/autotransfer.dm b/code/controllers/subsystem/autotransfer.dm similarity index 94% rename from modular_pariah/modules/autotransfer/code/autotransfer.dm rename to code/controllers/subsystem/autotransfer.dm index 82f16a076444..a33c81fc31cf 100644 --- a/modular_pariah/modules/autotransfer/code/autotransfer.dm +++ b/code/controllers/subsystem/autotransfer.dm @@ -36,6 +36,6 @@ SUBSYSTEM_DEF(autotransfer) targettime = targettime + voteinterval curvotes++ else - SSshuttle.autoEnd() + SSevacuation.trigger_auto_evac(EVACUATION_REASON_LONG_ROUND) #undef NO_MAXVOTES_CAP diff --git a/code/controllers/subsystem/evacuation.dm b/code/controllers/subsystem/evacuation.dm new file mode 100644 index 000000000000..c7f68548acc8 --- /dev/null +++ b/code/controllers/subsystem/evacuation.dm @@ -0,0 +1,246 @@ +#define CREW_DEATH_MESSAGE "Automatically starting evacuation sequence due to crew death." + +SUBSYSTEM_DEF(evacuation) + name = "Evacuation" + wait = 1 SECONDS + init_order = INIT_ORDER_EVACUATION + flags = SS_KEEP_TIMING + runlevels = RUNLEVEL_GAME + /// Controllers that handle the evacuation of the station + var/list/datum/evacuation_controller/controllers = list() + /// A list of things blocking evacuation + var/list/evacuation_blockers = list() + /// Whether you can cancel evacuation. Used by automatic evacuation + var/cancel_blocked = FALSE + +/datum/controller/subsystem/evacuation/Initialize(start_timeofday) + for(var/path in SSmapping.config.evacuation_controllers) + var/datum/evacuation_controller/controller = new path + controllers[controller.id] = controller + return ..() + +/datum/controller/subsystem/evacuation/fire(resumed) + if(!SSticker.HasRoundStarted() || length(evacuation_blockers)) + return + + var/threshold = CONFIG_GET(number/evacuation_autocall_threshold) + if(!threshold) + return + + var/alive = 0 + for(var/mob/M as anything in GLOB.player_list) + if(M.stat != DEAD) + ++alive + + var/total = length(GLOB.joined_player_list) + if(total <= 0) + return + + if(alive / total > threshold) + return + + message_admins(CREW_DEATH_MESSAGE) + log_evacuation("[CREW_DEATH_MESSAGE] Alive: [alive], Roundstart: [total], Threshold: [threshold]") + priority_announce("Catastrophic casualties detected: crisis evacuation protocols activated - blocking recall signals across all channels.") + trigger_auto_evac(EVACUATION_REASON_CREW_DEATH) + +/datum/controller/subsystem/evacuation/proc/trigger_auto_evac(reason) + cancel_blocked = TRUE + for(var/identifier in controllers) + if(controllers[identifier].state != EVACUATION_STATE_IDLE) + return + if(controllers[identifier].start_automatic_evacuation(reason)) + return + +/datum/controller/subsystem/evacuation/proc/can_evac(mob/caller, controller_id) + var/datum/evacuation_controller/controller = controllers[controller_id] + if(!controller) + stack_trace("Invalid controller ID") + return "Error 500. Please contact your system administrator." + for(var/identifier in controllers) + if(controllers[identifier].state >= EVACUATION_STATE_AWAITING) + return "Evacuation is already in progress." + return controller.can_evac(caller) + +/datum/controller/subsystem/evacuation/proc/request_evacuation(mob/caller, reason, controller_id, admin = FALSE) + var/datum/evacuation_controller/controller = controllers[controller_id] + if(!controller) + CRASH("Evacuation was requested for an invalid controller \"[controller_id]\"") + for(var/identifier in controllers) + if(controllers[identifier].state >= EVACUATION_STATE_AWAITING) + to_chat(caller, "Evacuation is already in progress.") + return + return controller.trigger_evacuation(caller, reason, admin) + +/datum/controller/subsystem/evacuation/proc/can_cancel(mob/caller, controller_id) + var/datum/evacuation_controller/controller = controllers[controller_id] + if(!controller) + stack_trace("can_cancel() was passed an invalid controller ID") + return "Error 500. Please contact your system administrator." + return controller.can_cancel(caller) + +/datum/controller/subsystem/evacuation/proc/request_cancel(mob/caller, controller_id) + var/datum/evacuation_controller/controller = controllers[controller_id] + if(!controller) + CRASH("Evacuation cancel was requested for an invalid controller \"[controller_id]\"") + controller.trigger_cancel_evacuation(caller) + +/datum/controller/subsystem/evacuation/proc/add_evacuation_blocker(datum/bad) + evacuation_blockers += bad + if(length(evacuation_blockers) == 1) + for(var/identifier in controllers) + controllers[identifier].evacuation_blocked() + +/datum/controller/subsystem/evacuation/proc/remove_evacuation_blocker(datum/bad) + evacuation_blockers -= bad + if(!length(evacuation_blockers)) + for(var/identifier in controllers) + controllers[identifier].evacuation_unblocked() + +/datum/controller/subsystem/evacuation/proc/disable_evacuation(controller_id) + if(!controllers[controller_id]) + CRASH("Tried to disable evacuation for an invalid controller \"[controller_id]\"") + controllers[controller_id].disable_evacuation() + +/datum/controller/subsystem/evacuation/proc/enable_evacuation(controller_id) + if(!controllers[controller_id]) + CRASH("Tried to enable evacuation for an invalid controller \"[controller_id]\"") + controllers[controller_id].enable_evacuation() + +/datum/controller/subsystem/evacuation/proc/block_cancel(controller_id) + if(!controllers[controller_id]) + CRASH("Tried to block cancel for an invalid controller \"[controller_id]\"") + controllers[controller_id].block_cancel() + +/datum/controller/subsystem/evacuation/proc/unblock_cancel(controller_id) + if(!controllers[controller_id]) + CRASH("Tried to unblock cancel for an invalid controller \"[controller_id]\"") + controllers[controller_id].unblock_cancel() + +//Perhaps move it to SShuttle? +/datum/controller/subsystem/evacuation/proc/get_customizable_shuttles() + var/list/shuttles = list() + for(var/identifier in controllers) + shuttles += controllers[identifier].get_customizable_shuttles() + return shuttles + +/datum/controller/subsystem/evacuation/proc/get_endgame_areas() + var/list/areas = list() + for(var/identifier in controllers) + var/datum/evacuation_controller/controller = controllers[identifier] + // We only want to add the areas if the controller is in a state where evacuation has finished + if(controller.state >= EVACUATION_STATE_EVACUATED) + areas += controller.get_endgame_areas() + return areas + +/datum/controller/subsystem/evacuation/proc/get_stat_data() + var/list/data = list() + for(var/identifier in controllers) + data += controllers[identifier].get_stat_data() + return data + +/datum/controller/subsystem/evacuation/proc/get_world_topic_status() + var/list/status = list() + for(var/identifier in controllers) + status += controllers[identifier].get_world_topic_status() + return status + +/datum/controller/subsystem/evacuation/proc/evacuation_in_progress() + for(var/identifier in controllers) + if(controllers[identifier].state == EVACUATION_STATE_AWAITING) + return TRUE + return FALSE + +/datum/controller/subsystem/evacuation/proc/evacuation_can_be_cancelled() + for(var/identifier in controllers) + if(!controllers[identifier].can_cancel(null)) + return FALSE + return TRUE + +/datum/controller/subsystem/evacuation/proc/station_evacuated() + for(var/identifier in controllers) + if(controllers[identifier].state >= EVACUATION_STATE_EVACUATED) + return TRUE + return FALSE + +/datum/controller/subsystem/evacuation/proc/evacuation_finished() + for(var/identifier in controllers) + if(controllers[identifier].state >= EVACUATION_STATE_FINISHED) + return TRUE + return FALSE + +/datum/controller/subsystem/evacuation/proc/delay_evacuation(controller_id, delay) + if(!controllers[controller_id]) + CRASH("Tried to delay evacuation for an invalid controller \"[controller_id]\"") + controllers[controller_id].delay_evacuation(delay) + +/datum/controller/subsystem/evacuation/proc/get_controllers_names(active_only = FALSE) + var/list/names = list() + for(var/identifier in controllers) + if(!active_only || controllers[identifier].state >= EVACUATION_STATE_AWAITING) + names[controllers[identifier].name] = identifier + return names + +/datum/controller/subsystem/evacuation/proc/get_controllers_list_ai() + var/list/names = list() + for(var/identifier in controllers) + names["[controllers[identifier].name] | [controllers[identifier].get_state()]"] = identifier + return names + +/datum/controller/subsystem/evacuation/proc/get_initiated_controller() + for(var/identifier in controllers) + if(controllers[identifier].state == EVACUATION_STATE_INITIATED) + return identifier + return null + +/datum/controller/subsystem/evacuation/proc/get_discord_status() + . = "" + for(var/identifier in controllers) + if(controllers[identifier].state != EVACUATION_STATE_IDLE) + . += "\n" + controllers[identifier].get_discord_status() + return . + +/datum/controller/subsystem/evacuation/proc/emergency_status_display_process(obj/machinery/status_display/evac/display) + for(var/identifier in controllers) + if(controllers[identifier].state != EVACUATION_STATE_IDLE) + . = controllers[identifier].emergency_status_display_process(display) + if(.) + return . + return list("", "") + +/datum/controller/subsystem/evacuation/proc/status_display_examine(mob/user, obj/machinery/status_display/evac/display) + . = list() + for(var/identifier in controllers) + . += controllers[identifier].status_display_examine(user, display) + return . + +/datum/controller/subsystem/evacuation/proc/centcom_recall(identifier, message) + if(controllers[identifier]) + if(controllers[identifier].state != EVACUATION_STATE_INITIATED) + return + controllers[identifier].centcom_recall(message) + +/datum/controller/subsystem/evacuation/proc/get_evac_ui_data(mob/user) + var/list/data = list() + for(var/identifier in controllers) + data += list(controllers[identifier].get_evac_ui_data(user)) + return data + +/datum/controller/subsystem/evacuation/proc/panel_act(list/href_list) + if(href_list["evac_controller"]) + controllers[href_list["evac_controller"]]?.panel_act(href_list) + +/datum/controller/subsystem/evacuation/proc/admin_panel() + var/list/dat = list("Evacuation Panel

Evacuation Panel

") + for(var/identifier in controllers) + dat += "
" + dat += "

[controllers[identifier].name]


" + dat += controllers[identifier].admin_panel() + usr << browse(dat.Join(), "window=evac_panel;size=500x500") + return + +/datum/controller/subsystem/evacuation/proc/escape_shuttle_replaced() + for(var/identifier in controllers) + controllers[identifier].escape_shuttle_replaced() + +#undef CREW_DEATH_MESSAGE diff --git a/code/controllers/subsystem/security_level.dm b/code/controllers/subsystem/security_level.dm index b8a3e79796d6..f576f0465600 100644 --- a/code/controllers/subsystem/security_level.dm +++ b/code/controllers/subsystem/security_level.dm @@ -22,7 +22,8 @@ SUBSYSTEM_DEF(security_level) * * new_level The new security level that will become our current level */ /datum/controller/subsystem/security_level/proc/set_level(new_level) + var/old_level = SSsecurity_level.current_level SSsecurity_level.current_level = new_level - SEND_SIGNAL(src, COMSIG_SECURITY_LEVEL_CHANGED, new_level) + SEND_SIGNAL(src, COMSIG_SECURITY_LEVEL_CHANGED, old_level, new_level) SSnightshift.check_nightshift() SSblackbox.record_feedback("tally", "security_level_changes", 1, get_security_level()) diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 3926be7f3cfb..a226672f7264 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -26,39 +26,8 @@ SUBSYSTEM_DEF(shuttle) /// An associative list of the mobile docking ports that have failed a transit request, with the amount of times they've actually failed that transit request, up to MAX_TRANSIT_REQUEST_RETRIES var/list/transit_request_failures = list() - /** - * Emergency shuttle stuff - */ - - /// The mobile docking port of the emergency shuttle. - var/obj/docking_port/mobile/emergency/emergency /// The mobile docking port of the arrivals shuttle. var/obj/docking_port/mobile/arrivals/arrivals - /// The mobile docking port of the backup emergency shuttle. - var/obj/docking_port/mobile/emergency/backup/backup_shuttle - /// Time taken for emergency shuttle to reach the station when called (in deciseconds). - var/emergency_call_time = 10 MINUTES - /// Time taken for emergency shuttle to leave again once it has docked (in deciseconds). - var/emergency_dock_time = 3 MINUTES - /// Time taken for emergency shuttle to reach a safe distance after leaving station (in deciseconds). - var/emergency_escape_time = 2 MINUTES - /// Where was the emergency shuttle last called from? - var/area/emergency_last_call_loc - /// How many times was the escape shuttle called? - var/emergencyCallAmount = 0 - /// Is the departure of the shuttle currently prevented? FALSE for no, any other number for yes (thanks shuttle code). - var/emergency_no_escape = FALSE - /// Do we prevent the recall of the shuttle? - var/emergency_no_recall = FALSE - /// Did admins force-prevent the recall of the shuttle? - var/admin_emergency_no_recall = FALSE - /// Previous mode of the shuttle before it was forcefully disabled by admins. - var/last_mode = SHUTTLE_IDLE - /// Previous time left to the call, only useful for disabling and re-enabling the shuttle for admins so it doesn't have to start the whole timer again. - var/last_call_time = 10 MINUTES - - /// Things blocking escape shuttle from leaving. - var/list/hostile_environments = list() /** * Supply shuttle stuff @@ -106,8 +75,6 @@ SUBSYSTEM_DEF(shuttle) /// The current shuttle loan event, if any. var/datum/round_event/shuttle_loan/shuttle_loan - /// If the event happens where the crew can purchase shuttle insurance, catastrophe can't run. - var/shuttle_insurance = FALSE // If the station has purchased a replacement escape shuttle this round. var/shuttle_purchased = SHUTTLEPURCHASE_PURCHASABLE /// For keeping track of ingame events that would unlock new shuttles, such as defeating a boss or discovering a secret item. @@ -158,10 +125,6 @@ SUBSYSTEM_DEF(shuttle) if(!arrivals) log_mapping("No /obj/docking_port/mobile/arrivals placed on the map!") - if(!emergency) - log_mapping("No /obj/docking_port/mobile/emergency placed on the map!") - if(!backup_shuttle) - log_mapping("No /obj/docking_port/mobile/emergency/backup placed on the map!") if(!supply) log_mapping("No /obj/docking_port/mobile/supply placed on the map!") @@ -196,7 +159,6 @@ SUBSYSTEM_DEF(shuttle) var/not_in_use = (!T.get_docked()) if(idle && not_centcom_evac && not_in_use) qdel(T, force=TRUE) - CheckAutoEvac() if(!SSmapping.clearing_reserved_turfs) while(transit_requesters.len) @@ -212,47 +174,6 @@ SUBSYSTEM_DEF(shuttle) if(MC_TICK_CHECK) break -/datum/controller/subsystem/shuttle/proc/CheckAutoEvac() - if(emergency_no_escape || admin_emergency_no_recall || emergency_no_recall || !emergency || !SSticker.HasRoundStarted()) - return - - var/threshold = CONFIG_GET(number/emergency_shuttle_autocall_threshold) - if(!threshold) - return - - var/alive = 0 - for(var/I in GLOB.player_list) - var/mob/M = I - if(M.stat != DEAD) - ++alive - - var/total = GLOB.joined_player_list.len - if(total <= 0) - return //no players no autoevac - - if(alive / total <= threshold) - var/msg = "Automatically dispatching emergency shuttle due to crew death." - message_admins(msg) - log_shuttle("[msg] Alive: [alive], Roundstart: [total], Threshold: [threshold]") - emergency_no_recall = TRUE - priority_announce("Catastrophic casualties detected: crisis shuttle protocols activated - jamming recall signals across all frequencies.") - if(emergency.timeLeft(1) > emergency_call_time * 0.4) - emergency.request(null, set_coefficient = 0.4) - -/datum/controller/subsystem/shuttle/proc/block_recall(lockout_timer) - if(admin_emergency_no_recall) - priority_announce("Error!", sub_title = "Emergency Shuttle Uplink Alert", sound_type = 'sound/misc/announce_dig.ogg') - addtimer(CALLBACK(src, PROC_REF(unblock_recall)), lockout_timer) - return - emergency_no_recall = TRUE - addtimer(CALLBACK(src, PROC_REF(unblock_recall)), lockout_timer) - -/datum/controller/subsystem/shuttle/proc/unblock_recall() - if(admin_emergency_no_recall) - priority_announce("Error!", sub_title = "Emergency Shuttle Uplink Alert", sound_type = 'sound/misc/announce_dig.ogg') - return - emergency_no_recall = FALSE - /datum/controller/subsystem/shuttle/proc/getShuttle(id) for(var/obj/docking_port/mobile/M in mobile_docking_ports) if(M.id == id) @@ -265,170 +186,6 @@ SUBSYSTEM_DEF(shuttle) return S WARNING("couldn't find dock with id: [id]") -/// Check if we can call the evac shuttle. -/// Returns TRUE if we can. Otherwise, returns a string detailing the problem. -/datum/controller/subsystem/shuttle/proc/canEvac(mob/user) - var/srd = CONFIG_GET(number/shuttle_refuel_delay) - if(world.time - SSticker.round_start_time < srd) - return "The emergency shuttle is refueling. Please wait [DisplayTimeText(srd - (world.time - SSticker.round_start_time))] before attempting to call." - - switch(emergency.mode) - if(SHUTTLE_RECALL) - return "The emergency shuttle may not be called while returning to CentCom." - if(SHUTTLE_CALL) - return "The emergency shuttle is already on its way." - if(SHUTTLE_DOCKED) - return "The emergency shuttle is already here." - if(SHUTTLE_IGNITING) - return "The emergency shuttle is firing its engines to leave." - if(SHUTTLE_ESCAPE) - return "The emergency shuttle is moving away to a safe distance." - if(SHUTTLE_STRANDED) - return "The emergency shuttle has been disabled by CentCom." - - return TRUE - -/datum/controller/subsystem/shuttle/proc/requestEvac(mob/user, call_reason) - if(!emergency) - WARNING("requestEvac(): There is no emergency shuttle, but the \ - shuttle was called. Using the backup shuttle instead.") - if(!backup_shuttle) - CRASH("requestEvac(): There is no emergency shuttle, \ - or backup shuttle! The game will be unresolvable. This is \ - possibly a mapping error, more likely a bug with the shuttle \ - manipulation system, or badminry. It is possible to manually \ - resolve this problem by loading an emergency shuttle template \ - manually, and then calling register() on the mobile docking port. \ - Good luck.") - emergency = backup_shuttle - - var/can_evac_or_fail_reason = SSshuttle.canEvac(user) - if(can_evac_or_fail_reason != TRUE) - to_chat(user, span_alert("[can_evac_or_fail_reason]")) - return - - call_reason = trim(html_encode(call_reason)) - - if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH && seclevel2num(get_security_level()) > SEC_LEVEL_GREEN) - to_chat(user, span_alert("You must provide a reason.")) - return - - var/area/signal_origin = get_area(user) - var/emergency_reason = "\nNature of emergency:\n\n[call_reason]" - var/security_num = seclevel2num(get_security_level()) - switch(security_num) - if(SEC_LEVEL_RED,SEC_LEVEL_DELTA) - emergency.request(null, signal_origin, html_decode(emergency_reason), 1) //There is a serious threat we gotta move no time to give them five minutes. - else - emergency.request(null, signal_origin, html_decode(emergency_reason), 0) - - var/datum/radio_frequency/frequency = SSpackets.return_frequency(FREQ_STATUS_DISPLAYS) - - if(!frequency) - return - - var/datum/signal/status_signal = new(src, list("command" = "update")) // Start processing shuttle-mode displays to display the timer - frequency.post_signal(status_signal) - - var/area/A = get_area(user) - - log_shuttle("[key_name(user)] has called the emergency shuttle.") - deadchat_broadcast(" has called the shuttle at [span_name("[A.name]")].", span_name("[user.real_name]"), user, message_type=DEADCHAT_ANNOUNCEMENT) - if(call_reason) - SSblackbox.record_feedback("text", "shuttle_reason", 1, "[call_reason]") - log_shuttle("Shuttle call reason: [call_reason]") - SSticker.emergency_reason = call_reason - message_admins("[ADMIN_LOOKUPFLW(user)] has called the shuttle. (TRIGGER CENTCOM RECALL)") - -/datum/controller/subsystem/shuttle/proc/centcom_recall(old_timer, admiral_message) - if(emergency.mode != SHUTTLE_CALL || emergency.timer != old_timer) - return - emergency.cancel() - - if(!admiral_message) - admiral_message = pick(GLOB.admiral_messages) - var/intercepttext = "Daedalus Industries Update: Request For Shuttle.
\ - To whom it may concern:

\ - We have taken note of the situation upon [station_name()] and have come to the \ - conclusion that it does not warrant the abandonment of the station.
\ - If you do not agree with our opinion we suggest that you open a direct \ - line with us and explain the nature of your crisis.

\ - This message has been automatically generated based upon readings from long \ - range diagnostic tools. To assure the quality of your request every finalized report \ - is reviewed by an on-call rear admiral.
\ - Rear Admiral's Notes: \ - [admiral_message]" - print_command_report(intercepttext, announce = TRUE) - -// Called when an emergency shuttle mobile docking port is -// destroyed, which will only happen with admin intervention -/datum/controller/subsystem/shuttle/proc/emergencyDeregister() - // When a new emergency shuttle is created, it will override the - // backup shuttle. - src.emergency = src.backup_shuttle - -/datum/controller/subsystem/shuttle/proc/cancelEvac(mob/user) - if(canRecall()) - emergency.cancel(get_area(user)) - log_shuttle("[key_name(user)] has recalled the shuttle.") - message_admins("[ADMIN_LOOKUPFLW(user)] has recalled the shuttle.") - deadchat_broadcast(" has recalled the shuttle from [span_name("[get_area_name(user, TRUE)]")].", span_name("[user.real_name]"), user, message_type=DEADCHAT_ANNOUNCEMENT) - return 1 - -/datum/controller/subsystem/shuttle/proc/canRecall() - if(!emergency || emergency.mode != SHUTTLE_CALL || admin_emergency_no_recall || emergency_no_recall) - return - var/security_num = seclevel2num(get_security_level()) - switch(security_num) - if(SEC_LEVEL_GREEN) - if(emergency.timeLeft(1) < emergency_call_time) - return - if(SEC_LEVEL_BLUE) - if(emergency.timeLeft(1) < emergency_call_time * 0.5) - return - else - if(emergency.timeLeft(1) < emergency_call_time * 0.25) - return - return 1 - -/datum/controller/subsystem/shuttle/proc/autoEvac() - if (!SSticker.IsRoundInProgress()) - return - - var/callShuttle = TRUE - - for(var/thing in INSTANCES_OF(TRACKING_KEY_SHUTTLE_CALLER)) - if(isAI(thing)) - var/mob/living/silicon/ai/AI = thing - if(AI.deployed_shell && !AI.deployed_shell.client) - continue - if(AI.stat || !AI.client) - continue - else if(istype(thing, /obj/machinery/computer/communications)) - var/obj/machinery/computer/communications/C = thing - if(C.machine_stat & BROKEN) - continue - - var/turf/T = get_turf(thing) - if(T && is_station_level(T.z)) - callShuttle = FALSE - break - - if(callShuttle) - if(EMERGENCY_IDLE_OR_RECALLED) - emergency.request(null, set_coefficient = 2.5) - log_shuttle("There is no means of calling the emergency shuttle anymore. Shuttle automatically called.") - message_admins("All the communications consoles were destroyed and all AIs are inactive. Shuttle called.") - -/datum/controller/subsystem/shuttle/proc/registerHostileEnvironment(datum/bad) - hostile_environments[bad] = TRUE - checkHostileEnvironment() - -/datum/controller/subsystem/shuttle/proc/clearHostileEnvironment(datum/bad) - hostile_environments -= bad - checkHostileEnvironment() - - /datum/controller/subsystem/shuttle/proc/registerTradeBlockade(datum/bad) trade_blockade[bad] = TRUE checkTradeBlockade() @@ -437,7 +194,6 @@ SUBSYSTEM_DEF(shuttle) trade_blockade -= bad checkTradeBlockade() - /datum/controller/subsystem/shuttle/proc/checkTradeBlockade() for(var/datum/d in trade_blockade) if(!istype(d) || QDELETED(d)) @@ -452,32 +208,6 @@ SUBSYSTEM_DEF(shuttle) supply.mode = SHUTTLE_DOCKED //Make all cargo consoles speak up -/datum/controller/subsystem/shuttle/proc/checkHostileEnvironment() - for(var/datum/d in hostile_environments) - if(!istype(d) || QDELETED(d)) - hostile_environments -= d - emergency_no_escape = hostile_environments.len - - if(emergency_no_escape && (emergency.mode == SHUTTLE_IGNITING)) - emergency.mode = SHUTTLE_STRANDED - emergency.timer = null - emergency.sound_played = FALSE - priority_announce("Hostile environment detected. \ - Departure has been postponed indefinitely pending \ - conflict resolution.", - "LRSV Icarus Announcement", - do_not_modify = TRUE - ) - if(!emergency_no_escape && (emergency.mode == SHUTTLE_STRANDED)) - emergency.mode = SHUTTLE_DOCKED - emergency.setTimer(emergency_dock_time) - priority_announce("Hostile environment resolved. \ - You have 3 minutes to board the Emergency Shuttle.", - "LRSV Icarus Announcement", - sound_type = ANNOUNCER_SHUTTLEDOCK, - do_not_modify = TRUE - ) - //try to move/request to dock_home if possible, otherwise dock_away. Mainly used for admin buttons /datum/controller/subsystem/shuttle/proc/toggleShuttle(shuttle_id, dock_home, dock_away, timed) var/obj/docking_port/mobile/shuttle_port = getShuttle(shuttle_id) @@ -622,18 +352,8 @@ SUBSYSTEM_DEF(shuttle) if (istype(SSshuttle.transit_request_failures)) transit_request_failures = SSshuttle.transit_request_failures - if (istype(SSshuttle.emergency)) - emergency = SSshuttle.emergency if (istype(SSshuttle.arrivals)) arrivals = SSshuttle.arrivals - if (istype(SSshuttle.backup_shuttle)) - backup_shuttle = SSshuttle.backup_shuttle - - if (istype(SSshuttle.emergency_last_call_loc)) - emergency_last_call_loc = SSshuttle.emergency_last_call_loc - - if (istype(SSshuttle.hostile_environments)) - hostile_environments = SSshuttle.hostile_environments if (istype(SSshuttle.supply)) supply = SSshuttle.supply @@ -658,8 +378,6 @@ SUBSYSTEM_DEF(shuttle) centcom_message = SSshuttle.centcom_message order_number = SSshuttle.order_number points = D.account_balance - emergency_no_escape = SSshuttle.emergency_no_escape - emergencyCallAmount = SSshuttle.emergencyCallAmount shuttle_purchased = SSshuttle.shuttle_purchased lockdown = SSshuttle.lockdown @@ -997,11 +715,9 @@ SUBSYSTEM_DEF(shuttle) shuttle_loading = FALSE if("replace") - if(existing_shuttle == backup_shuttle) - // TODO make the load button disabled - WARNING("The shuttle that the selected shuttle will replace \ - is the backup shuttle. Backup shuttle is required to be \ - intact for round sanity.") + if(existing_shuttle == GLOB.backup_shuttle) + WARNING("The shuttle to be replaced is marked as important. \ + Replacing it may cause issues with the round.") else if(S && !shuttle_loading) . = TRUE shuttle_loading = TRUE @@ -1013,7 +729,7 @@ SUBSYSTEM_DEF(shuttle) log_admin("[key_name(usr)] load/replaced [mdp] with the shuttle manipulator.") SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[mdp.name]") shuttle_loading = FALSE - if(emergency == mdp) //you just changed the emergency shuttle, there are events in game + captains that can change your snowflake choice. + if(istype(mdp, /obj/docking_port/mobile/emergency)) //you just changed the emergency shuttle, there are events in game + captains that can change your snowflake choice. var/set_purchase = tgui_alert(usr, "Do you want to also disable shuttle purchases/random events that would change the shuttle?", "Butthurt Admin Prevention", list("Yes, disable purchases/events", "No, I want to possibly get owned")) if(set_purchase == "Yes, disable purchases/events") SSshuttle.shuttle_purchased = SHUTTLEPURCHASE_FORCED diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index f22d003385d4..4ede6cc4cab0 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -37,10 +37,7 @@ SUBSYSTEM_DEF(statpanels) "Players Playing/Connected: [get_active_player_count()]/[length(GLOB.clients)]" ) - if(SSshuttle.emergency) - var/ETA = SSshuttle.emergency.getModeStr() - if(ETA) - global_data += "[ETA] [SSshuttle.emergency.getTimerStr()]" + global_data += SSevacuation.get_stat_data() src.currentrun = GLOB.clients.Copy() mc_data = null diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index dd81d82d3c50..70520b4863e2 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -601,8 +601,6 @@ SUBSYSTEM_DEF(ticker) news_message = "Tensions have flared with the Space Wizard Federation following the death of one of their members aboard [decoded_station_name]." if(STATION_NUKED) news_message = "[decoded_station_name] activated its self-destruct device for unknown reasons. Attempts to clone the Captain for arrest and execution are underway." - if(SHUTTLE_HIJACK) - news_message = "During routine evacuation procedures, the emergency shuttle of [decoded_station_name] had its navigation protocols corrupted and went off course, but was recovered shortly after." if(GANG_OPERATING) news_message = "The company would like to state that any rumors of criminal organizing on board stations such as [decoded_station_name] are falsehoods, and not to be emulated." if(GANG_DESTROYED) diff --git a/code/datums/evacuation_controllers/emergency_shuttle.dm b/code/datums/evacuation_controllers/emergency_shuttle.dm new file mode 100644 index 000000000000..bd70f07aa2f8 --- /dev/null +++ b/code/datums/evacuation_controllers/emergency_shuttle.dm @@ -0,0 +1,316 @@ +//Shouldn't be used anywhere but here +GLOBAL_DATUM(emergency_shuttle, /obj/docking_port/mobile/emergency) +GLOBAL_DATUM(backup_shuttle, /obj/docking_port/mobile/emergency) + +/datum/evacuation_controller/emergency_shuttle + name = "Emergency Shuttle" + id = "emergency_shuttle" + var/obj/docking_port/mobile/emergency/emergency + var/obj/docking_port/mobile/emergency/backup + var/emergency_call_time = 10 MINUTES + var/emergency_escape_time = 3 MINUTES + var/emergency_dock_time = 2 MINUTES + var/last_mode + var/last_call_time + +/datum/evacuation_controller/emergency_shuttle/New() + if(GLOB.backup_shuttle) + backup = GLOB.backup_shuttle + else + log_evacuation("Somehow backup shuttle is missing.") + + if(GLOB.emergency_shuttle) + emergency = GLOB.emergency_shuttle + else + log_evacuation("Somehow emergency shuttle is missing. Using backup shuttle.") + GLOB.emergency_shuttle = backup + + RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED, PROC_REF(sec_level_updated)) + + emergency.call_time = emergency_call_time * get_sec_level_modifier() + emergency.escape_time = emergency_escape_time + emergency.dock_time = emergency_dock_time + +/datum/evacuation_controller/emergency_shuttle/proc/on_emergency_shuttle_deleted() + log_evacuation("Emergency shuttle has been deleted. Using backup shuttle.") + emergency = backup + emergency.call_time = emergency_call_time * get_sec_level_modifier() + emergency.escape_time = emergency_escape_time + emergency.dock_time = emergency_dock_time + +/datum/evacuation_controller/emergency_shuttle/proc/get_sec_level_modifier(level = null) + if(isnull(level)) + level = SSsecurity_level.current_level + + switch(level) + if(SEC_LEVEL_GREEN) + return 2 + if(SEC_LEVEL_BLUE) + return 1 + if(SEC_LEVEL_RED, SEC_LEVEL_DELTA) + return 0.5 + +/datum/evacuation_controller/emergency_shuttle/proc/sec_level_updated(datum/source, old_level, new_level) + var/modifier_result = get_sec_level_modifier(new_level) / get_sec_level_modifier(old_level) + if(modifier_result != 1) + emergency.call_time *= modifier_result + emergency.modTimer(modifier_result) + +/datum/evacuation_controller/emergency_shuttle/get_state() + switch(state) + if(EVACUATION_STATE_IDLE) + return "Emergency shuttle is idle at CentCom" + if(EVACUATION_STATE_INITIATED) + return "Emergency shuttle is on the way to the station. ETA: [emergency.getTimerStr()]" + if(EVACUATION_STATE_AWAITING) + return "Emergency shuttle is docked at the station. Awaiting crew. ETD: [emergency.getTimerStr()]" + if(EVACUATION_STATE_EVACUATED) + return "Emergency shuttle has left the station. ETA: [emergency.getTimerStr()]" + if(EVACUATION_STATE_FINISHED) + return "Emergency shuttle has arrived at CentCom" + +/datum/evacuation_controller/emergency_shuttle/can_evac(mob/user) + var/srd = CONFIG_GET(number/shuttle_refuel_delay) + if(world.time - SSticker.round_start_time < srd) + return "The emergency shuttle is refueling. Please wait [DisplayTimeText(srd - (world.time - SSticker.round_start_time))] before attempting to call." + + if(state >= EVACUATION_STATE_IDLE) + switch(emergency.mode) + if(SHUTTLE_CALL) + return "The emergency shuttle is already on its way." + if(SHUTTLE_RECALL) + return "The emergency shuttle may not be called while returning to CentCom." + if(SHUTTLE_DOCKED) + return "The emergency shuttle is already here." + if(SHUTTLE_IGNITING) + return "The emergency shuttle is firing its engines to leave." + if(SHUTTLE_ESCAPE) + return "The emergency shuttle is moving away to a safe distance." + if(SHUTTLE_STRANDED) + return "The emergency shuttle has been disabled by CentCom." + + if(evacuation_disabled) + return "The emergency shuttle has been disabled by CentCom." + + return ..() + +/datum/evacuation_controller/emergency_shuttle/start_evacuation(mob/user, call_reason, area/signal_origin) + evac_calls_count++ + + var/message = "The emergency shuttle has been called." + if(seclevel2num(get_security_level()) >= SEC_LEVEL_RED) + message += " Red Alert state confirmed: Dispatching priority shuttle." + + RegisterSignal(emergency, COMSIG_EMERGENCYSHUTTLE_ARRIVAL, PROC_REF(on_emergency_shuttle_arrived)) + state = EVACUATION_STATE_INITIATED + emergency.request(null) + + message += " It will arrive in [emergency.timeLeft(600)] minutes.\nNature of emergency:\n\n[call_reason]" + + if(last_evac_call_loc) + message += "\n\nCall signal traced. Results can be viewed on any communications console." + + if(cancel_disabled) + message += "\n\nWarning: Shuttle recall subroutines disabled; Recall not possible." + + priority_announce(message, FLAVOR_CENTCOM_NAME, sound_type = ANNOUNCER_SHUTTLECALLED) + + var/datum/radio_frequency/frequency = SSpackets.return_frequency(FREQ_STATUS_DISPLAYS) + var/datum/signal/status_signal = new(src, list("command" = "update")) // Start processing shuttle -mode displays to display the timer + frequency.post_signal(status_signal) + +/datum/evacuation_controller/emergency_shuttle/start_automatic_evacuation(reason) + switch(reason) + if(EVACUATION_REASON_CREW_DEATH) + RegisterSignal(emergency, COMSIG_EMERGENCYSHUTTLE_ARRIVAL, PROC_REF(on_emergency_shuttle_arrived)) + state = EVACUATION_STATE_INITIATED + UnregisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED) + emergency.call_time = emergency_call_time * 0.5 + emergency.request(null) + if(EVACUATION_REASON_VOTE, EVACUATION_REASON_LONG_ROUND, EVACUATION_REASON_CONSOLE_DESTROYED) + RegisterSignal(emergency, COMSIG_EMERGENCYSHUTTLE_ARRIVAL, PROC_REF(on_emergency_shuttle_arrived)) + state = EVACUATION_STATE_INITIATED + emergency.request(null) + priority_announce("The shift has come to an end and the shuttle called. [SSsecurity_level.current_level == SEC_LEVEL_RED ? "Red Alert state confirmed: Dispatching priority shuttle. " : "" ]It will arrive in [emergency.timeLeft(600)] minutes.", FLAVOR_CENTCOM_NAME, sound_type = ANNOUNCER_SHUTTLECALLED) + +/datum/evacuation_controller/emergency_shuttle/proc/on_emergency_shuttle_arrived(datum/source) + state = EVACUATION_STATE_AWAITING + UnregisterSignal(emergency, COMSIG_EMERGENCYSHUTTLE_ARRIVAL) + RegisterSignal(emergency, COMSIG_EMERGENCYSHUTTLE_ANNOUNCE, PROC_REF(on_emergency_shuttle_announce)) + RegisterSignal(emergency, COMSIG_EMERGENCYSHUTTLE_DEPARTING, PROC_REF(on_emergency_shuttle_departed)) + send2adminchat("Server", "The Emergency Shuttle has docked with the station.") + priority_announce("The Icarus has docked with the station. You have [emergency.timeLeft(600)] minutes to board before departure.", "LRSV Icarus Announcement", sound_type = ANNOUNCER_SHUTTLEDOCK) + +/datum/evacuation_controller/emergency_shuttle/proc/on_emergency_shuttle_announce(datum/source) + priority_announce("Engines spooling up. Prepare for resonance jump.", "LRSV Icarus Announcement", do_not_modify = TRUE) + +/datum/evacuation_controller/emergency_shuttle/proc/on_emergency_shuttle_departed(datum/source) + state = EVACUATION_STATE_EVACUATED + UnregisterSignal(emergency, list(COMSIG_EMERGENCYSHUTTLE_DEPARTING, COMSIG_EMERGENCYSHUTTLE_ANNOUNCE)) + RegisterSignal(emergency, COMSIG_EMERGENCYSHUTTLE_RETURNED, PROC_REF(on_emergency_shuttle_returned)) + priority_announce("The Icarus has entered the resonance gate and is enroute to it's destination. Estimate [emergency.timeLeft(600)] minutes until the shuttle docks at Sector Control.", "LRSV Icarus Announcement") + INVOKE_ASYNC(SSticker, TYPE_PROC_REF(/datum/controller/subsystem/ticker, poll_hearts)) + SSmapping.mapvote() //If no map vote has been run yet, start one. + +/datum/evacuation_controller/emergency_shuttle/proc/on_emergency_shuttle_returned(datum/source) + state = EVACUATION_STATE_FINISHED + UnregisterSignal(emergency, COMSIG_EMERGENCYSHUTTLE_RETURNED) + +/datum/evacuation_controller/emergency_shuttle/can_cancel(mob/user) + // Point of no return after 50% of the time has passed + if(emergency.timeLeft(1) < emergency_call_time * get_sec_level_modifier() * 0.5) + return FALSE + return ..() + +/datum/evacuation_controller/emergency_shuttle/cancel_evacuation(mob/user) + state = EVACUATION_STATE_IDLE + emergency.cancel() + //TODO: Signal changes here + priority_announce("The emergency shuttle has been recalled.[last_evac_call_loc ? " Recall signal traced. Results can be viewed on any communications console." : "" ]", FLAVOR_CENTCOM_NAME, sound_type = ANNOUNCER_SHUTTLERECALLED) + +/datum/evacuation_controller/emergency_shuttle/get_customizable_shuttles() + return list(emergency) + +/datum/evacuation_controller/emergency_shuttle/get_endgame_areas() + return emergency.shuttle_areas + +/datum/evacuation_controller/emergency_shuttle/evacuation_blocked() + if(emergency.mode != SHUTTLE_DOCKED) + return + emergency.mode = SHUTTLE_STRANDED + emergency.timer = null + emergency.sound_played = FALSE + priority_announce("Hostile environment detected. \ + Departure has been postponed indefinitely pending \ + conflict resolution.", + "LRSV Icarus Announcement", + do_not_modify = TRUE + ) + +/datum/evacuation_controller/emergency_shuttle/evacuation_unblocked() + if(emergency.mode != SHUTTLE_STRANDED) + return + emergency.mode = SHUTTLE_DOCKED + emergency.setTimer(emergency_dock_time) + priority_announce("Hostile environment resolved. \ + You have 3 minutes to board the Emergency Shuttle.", + "LRSV Icarus Announcement", + sound_type = ANNOUNCER_SHUTTLEDOCK, + do_not_modify = TRUE + ) + +/datum/evacuation_controller/emergency_shuttle/disable_evacuation() + if(!..()) + return FALSE + last_mode = emergency.mode + last_call_time = emergency.timeLeft(1) + emergency.setTimer(0) + emergency.mode = SHUTTLE_DISABLED + priority_announce( + "Warning: Emergency Shuttle uplink failure, shuttle disabled until further notice.", + "LRSV Icarus Announcement", + "Emergency Shuttle Uplink Alert", + 'sound/misc/announce_dig.ogg' + ) + return TRUE + +/datum/evacuation_controller/emergency_shuttle/enable_evacuation() + if(!..()) + return FALSE + emergency.mode = last_mode + if(last_call_time < 10 SECONDS && last_mode != SHUTTLE_IDLE) + last_call_time = 10 SECONDS //Make sure no insta departures. + emergency.setTimer(last_call_time) + priority_announce("Warning: Emergency Shuttle uplink reestablished, shuttle enabled.", "LRSV Icarus Announcement", "Emergency Shuttle Uplink Alert", 'sound/misc/announce_dig.ogg') + return TRUE + +/datum/evacuation_controller/emergency_shuttle/delay_evacuation(delay) + ..() + emergency.setTimer(emergency.timeLeft(1) + delay) + +/datum/evacuation_controller/emergency_shuttle/centcom_recall(message) + emergency.cancel() + //TODO: Signal changes here + + if(!message) + message = pick(GLOB.admiral_messages) + var/intercepttext = "Daedalus Industries Update: Request For Shuttle.
\ + To whom it may concern:

\ + We have taken note of the situation upon [station_name()] and have come to the \ + conclusion that it does not warrant the abandonment of the station.
\ + If you do not agree with our opinion we suggest that you open a direct \ + line with us and explain the nature of your crisis.

\ + This message has been automatically generated based upon readings from long \ + range diagnostic tools. To assure the quality of your request every finalized report \ + is reviewed by an on-call rear admiral.
\ + Rear Admiral's Notes: \ + [message]" + print_command_report(intercepttext, announce = TRUE) + +/datum/evacuation_controller/emergency_shuttle/get_stat_data() + var/ETA = emergency.getModeStr() + if(ETA) + return list("[ETA] [emergency.getTimerStr()]") + return list() + +/datum/evacuation_controller/emergency_shuttle/get_world_topic_status() + return list( + "shuttle_mode" = emergency.mode, + "shuttle_timer" = emergency.timeLeft() + ) + +/datum/evacuation_controller/emergency_shuttle/get_discord_status() + if(emergency.getModeStr()) + . = "[emergency.getModeStr()]: [emergency.getTimerStr()]" + if(SSticker.emergency_reason) + . += ", Shuttle call reason: [SSticker.emergency_reason]" + return . + return "" + +/datum/evacuation_controller/emergency_shuttle/emergency_status_display_process(obj/machinery/status_display/evac/display) + return list("-[emergency.getModeStr()]-", emergency.getTimerStr()) + +/datum/evacuation_controller/emergency_shuttle/status_display_examine(mob/user, obj/machinery/status_display/evac/display) + return list( + display.examine_shuttle(user, emergency) + ) + +/datum/evacuation_controller/emergency_shuttle/get_evac_ui_data(mob/user) + .=..() + .["icon"] = "space-shuttle" + if(state != EVACUATION_STATE_IDLE) + .["actionName"] = "Recall Emergency Shuttle" + else + .["actionName"] = "Call Emergency Shuttle" + +/datum/evacuation_controller/emergency_shuttle/admin_panel() + var/list/dat = list() + if(state == EVACUATION_STATE_IDLE) + dat += "Call Shuttle
" + else + dat += "[emergency.getModeStr()]: [emergency.getTimerStr()]
" + if(state == EVACUATION_STATE_INITIATED) + dat += "Recall Shuttle
" + return dat + +/datum/evacuation_controller/emergency_shuttle/panel_act(list/href_list) + if(!check_rights(R_ADMIN)) + return + + if(href_list["call_shuttle"] && state == EVACUATION_STATE_IDLE) + SSevacuation.request_evacuation(usr, null, id, admin = TRUE) + + if(href_list["recall_shuttle"] && state != EVACUATION_STATE_IDLE) + SSevacuation.request_cancel(usr, id) + + if(href_list["edit_shuttle_time"]) + var/timer = input("Enter new shuttle duration (seconds):","Edit Shuttle Timeleft", emergency.timeLeft() ) as num|null + if(!timer) + return + emergency.setTimer(timer SECONDS) + log_evacuation("[key_name(usr)] edited the Emergency Shuttle's timeleft to [timer] seconds.") + minor_announce("The emergency shuttle will reach its destination in [DisplayTimeText(timer SECONDS)].") + message_admins(span_adminnotice("[key_name_admin(usr)] edited the Emergency Shuttle's timeleft to [timer] seconds.")) + +/datum/evacuation_controller/emergency_shuttle/escape_shuttle_replaced() + emergency = GLOB.emergency_shuttle diff --git a/code/datums/evacuation_controllers/evacuation_controller.dm b/code/datums/evacuation_controllers/evacuation_controller.dm new file mode 100644 index 000000000000..383db78dd398 --- /dev/null +++ b/code/datums/evacuation_controllers/evacuation_controller.dm @@ -0,0 +1,216 @@ +/datum/evacuation_controller + /// Name of the evacuation controller + var/name = "Evacuation Controller" + /// The type of the evacuation controller + var/id = "evacuation_controller" + /// The current state of the evacuation + var/state = EVACUATION_STATE_IDLE + /// How many times was evacuation triggered + var/evac_calls_count = 0 + /// Where was the last evacuation call + var/area/last_evac_call_loc + /// Did admins block the recall of evacuation + var/cancel_disabled = FALSE + /// Did admins block the evacuation + var/evacuation_disabled = FALSE + /// The time until the evacuation is delayed. + /// Used to prevent canceling to reset the timer + var/delayed_until = 0 + +/// Returns the current state of the evacuation +/datum/evacuation_controller/proc/get_state() + switch(state) + if(EVACUATION_STATE_IDLE) + return "Idle" + if(EVACUATION_STATE_INITIATED) + return "Initiadited" + if(EVACUATION_STATE_AWAITING) + return "Awaiting crew" + if(EVACUATION_STATE_EVACUATED) + return "Past point of no return" + if(EVACUATION_STATE_FINISHED) + return "Finished" + +/// Whether we can trigger evacuation sequence at the moment. +/// Returns either TRUE or a string with the reason why it's not possible +/datum/evacuation_controller/proc/can_evac(mob/user) + if(evacuation_disabled) + return "Evacuation is disabled" + if(state != EVACUATION_STATE_IDLE) + return "Evacuation is already in progress" + return TRUE + +/// Triggers the evacuation sequence, if possible +/datum/evacuation_controller/proc/trigger_evacuation(mob/user, call_reason, admin) + var/can_evac_or_fail_reason = can_evac(user) + if(can_evac_or_fail_reason != TRUE) + to_chat(user, span_alert("[can_evac_or_fail_reason]")) + return FALSE + log_evacuation("[key_name(user)] has start the evacuation.") + + var/area/signal_origin = get_area(user) + if(!admin && prob(70)) + last_evac_call_loc = signal_origin + else + last_evac_call_loc = null + start_evacuation(user, call_reason) + + deadchat_broadcast(" has started the evacuation at [span_name("[signal_origin.name]")].", span_name("[user.real_name]"), user, message_type=DEADCHAT_ANNOUNCEMENT) + if(call_reason) + SSblackbox.record_feedback("text", "shuttle_reason", 1, "[call_reason]") + log_evacuation("Evacuation reason: [call_reason]") + SSticker.emergency_reason = call_reason + message_admins("[ADMIN_LOOKUPFLW(user)] has started the evacuation. (TRIGGER CENTCOM RECALL)") + return TRUE + +/// Starts the evacuation sequence. Should not be called directly, use trigger_evacuation instead +/datum/evacuation_controller/proc/start_evacuation(mob/user, call_reason) + CRASH("start_evacuation not implemented. Type: [type]") + +/// Starts the automatic evacuation sequence +/// Called when round is going for too long, when most of the crew is dead, etc. +/datum/evacuation_controller/proc/start_automatic_evacuation(reason) + CRASH("start_automatic_evacuation not implemented. Type: [type]") + +/// Whether we can cancel the evacuation sequence at the moment +/datum/evacuation_controller/proc/can_cancel(mob/user) + if(SSevacuation.cancel_blocked || cancel_disabled) + return FALSE + if(delayed_until > world.time) + return FALSE + if(state == EVACUATION_STATE_IDLE || state >= EVACUATION_STATE_EVACUATED) + return FALSE + return TRUE + +/// Cancels the evacuation sequence, if possible +/datum/evacuation_controller/proc/trigger_cancel_evacuation(mob/user, admin) + if(!can_cancel(user)) + return FALSE + log_evacuation("[key_name(user)] has canceled the evacuation.") + var/area/signal_origin = get_area(user) + if(!admin && prob(70)) + last_evac_call_loc = signal_origin + else + last_evac_call_loc = null + cancel_evacuation(user) + SSticker.emergency_reason = null + message_admins("[ADMIN_LOOKUPFLW(user)] has canceled the evacuation.") + deadchat_broadcast(" has canceled the evacuation from [span_name("[signal_origin.name]")].", span_name("[user.real_name]"), user, message_type=DEADCHAT_ANNOUNCEMENT) + return TRUE + +/// Cancels the evacuation sequence. Should not be called directly, use trigger_cancel_evacuation instead +/datum/evacuation_controller/proc/cancel_evacuation(mob/user) + CRASH("trigger_cancel_evacuation not implemented. Type: [type]") + +/// Returns a list of shuttles that can be replaced with a custom shuttle +/datum/evacuation_controller/proc/get_customizable_shuttles() + return list() + +/// Returns assoc list of evac areas = TRUE. E.g. escape pods, shuttles, etc. Doesn't include CentCom +/datum/evacuation_controller/proc/get_endgame_areas() + return list() + +/// Called when the evacuation is blocked for some reason +/datum/evacuation_controller/proc/evacuation_blocked() + return + +/// Called when the evacuation is unblocked +/datum/evacuation_controller/proc/evacuation_unblocked() + return + +/// Called when admins force-disable evacuation +/datum/evacuation_controller/proc/disable_evacuation() + if(evacuation_disabled) + return FALSE + evacuation_disabled = TRUE + return TRUE + +/// Called when admins re-enable evacuation +/datum/evacuation_controller/proc/enable_evacuation() + if(!evacuation_disabled) + return FALSE + evacuation_disabled = FALSE + return TRUE + +/// Called when admins force-disable evacuation cancellation +/datum/evacuation_controller/proc/block_cancel() + if(cancel_disabled) + return FALSE + cancel_disabled = TRUE + return TRUE + +/// Called when admins allow cancellation of evacuation +/datum/evacuation_controller/proc/unblock_cancel() + if(!cancel_disabled) + return FALSE + cancel_disabled = FALSE + return TRUE + +/// Called when you need to delay the evacuation for some reason. +/datum/evacuation_controller/proc/delay_evacuation(delay) + if(delayed_until > world.time) + delayed_until = world.time + delay + else + delayed_until += delay + +/// Called when admin cancels the evacuation through CentCom for RP reasons +/datum/evacuation_controller/proc/centcom_recall(message) + return + +/// Returns a list of strings to display in the evacuation status panel +/datum/evacuation_controller/proc/get_stat_data() + return list() + +/// Returns assoc list of world status +/datum/evacuation_controller/proc/get_world_topic_status() + return list() + +/// Returns a string with the current state of the evacuation for the Discord message +/datum/evacuation_controller/proc/get_discord_status() + return "" + +/// Returns a string with the current state of the evacuation for the status display +/datum/evacuation_controller/proc/emergency_status_display_process(obj/machinery/status_display/evac/display) + return // should return list with 2 strings + +/// Returns a list of strigns to display when examining the status display during evacuation +/datum/evacuation_controller/proc/status_display_examine(mob/user, obj/machinery/status_display/evac/display) + return list() + +/// Returns data for the communication console +/datum/evacuation_controller/proc/get_evac_ui_data(mob/user) + . = list( + "id" = id, // unique identifier for the evacuation + "started" = null, // if the evacuation has started + "actionName" = null, // name for the button to call or recall + "canEvacOrRecall" = null, // whether the user can call or recall the evacuation. If not, the reason + "status" = null, // current status of the evacuation + "traceString" = null, // string to display if last evacuation call was traced + "icon" = null, + ) + + if(state != EVACUATION_STATE_IDLE) + .["started"] = TRUE + .["actionName"] = "Cancel Evacuation ([name]})" + .["canEvacOrRecall"] = can_cancel(user) + .["status"] = get_state() + else + .["started"] = FALSE + .["actionName"] = "Start Evacuation [name]" + .["canEvacOrRecall"] = can_evac(user) + + if(last_evac_call_loc) + .["traceString"] = "Last evacuation call was traced to [last_evac_call_loc]" + else if(evac_calls_count > 0) + .["traceString"] = "Unable to trace last evacuation call" + + return . + +/datum/evacuation_controller/proc/admin_panel() + return list() + +/datum/evacuation_controller/proc/panel_act(list/href_list) + return + +/datum/evacuation_controller/proc/escape_shuttle_replaced() + return diff --git a/code/datums/map_config.dm b/code/datums/map_config.dm index 8cc705af3023..8d5e576959da 100644 --- a/code/datums/map_config.dm +++ b/code/datums/map_config.dm @@ -32,6 +32,10 @@ "whiteship" = "whiteship_box", "emergency" = "emergency_box") + var/evacuation_controllers = list( + /datum/evacuation_controller/emergency_shuttle + ) + /// Dictionary of job sub-typepath to template changes dictionary var/job_changes = list() /// List of additional areas that count as a part of the library @@ -193,6 +197,23 @@ continue library_areas += path + evacuation_controllers = list() + if("evacuation_controllers" in json) + if(!islist(json["evacuation_controllers"])) + log_world("map_config \"evacuation_controllers\" field is missing or invalid!") + return + + for(var/path_as_text in json["evacuation_controllers"]) + var/path = text2path(path_as_text) + if(!ispath(path, /datum/evacuation_controller)) + stack_trace("Invalid path in mapping config for evacuation controllers: \[[path_as_text]\]") + continue + evacuation_controllers += path + + if(!length(evacuation_controllers)) + log_world("map_config \"evacuation_controllers\" field is empty!") + return + defaulted = FALSE return TRUE #undef CHECK_EXISTS diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 6ab6f6425a3b..5bd0208dd7c8 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -843,12 +843,6 @@ if(G) G.reenter_corpse() -/// Sets our can_hijack to the fastest speed our antag datums allow. -/datum/mind/proc/get_hijack_speed() - . = 0 - for(var/datum/antagonist/A in antag_datums) - . = max(., A.hijack_speed()) - /datum/mind/proc/has_objective(objective_type) for(var/datum/antagonist/A in antag_datums) for(var/O in A.objectives) diff --git a/code/datums/status_effects/debuffs/drunk.dm b/code/datums/status_effects/debuffs/drunk.dm index 9bdef49a61e3..4a54cb975d3e 100644 --- a/code/datums/status_effects/debuffs/drunk.dm +++ b/code/datums/status_effects/debuffs/drunk.dm @@ -191,7 +191,7 @@ owner.adjustToxLoss(1) if(owner.stat == CONSCIOUS && prob(20)) // Don't put us in a deep sleep if the shuttle's here. QoL, mainly. - if(SSshuttle.emergency.mode == SHUTTLE_DOCKED && is_station_level(owner.z)) + if(SSevacuation.evacuation_in_progress() && is_station_level(owner.z)) to_chat(owner, span_warning("You're so tired... but you can't miss that shuttle...")) else diff --git a/code/datums/vote.dm b/code/datums/vote.dm index f69f680cb34e..bc698e40993f 100644 --- a/code/datums/vote.dm +++ b/code/datums/vote.dm @@ -167,7 +167,9 @@ if(!(real_winner == INITIATE_TRANSFER)) return - SSshuttle.autoEnd() + SSevacuation.trigger_auto_evac(EVACUATION_REASON_VOTE) + log_game("Round end vote passed. Shuttle has been auto-called.") + message_admins("Round end vote passed. Shuttle has been auto-called.") var/obj/machinery/computer/communications/C = locate() in INSTANCES_OF(/obj/machinery/computer/communications) if(C) C.post_status("shuttle") diff --git a/code/datums/world_topic.dm b/code/datums/world_topic.dm index f47b4b9e7ea3..c289390e4a8b 100644 --- a/code/datums/world_topic.dm +++ b/code/datums/world_topic.dm @@ -230,11 +230,7 @@ .["popcap"] = max(CONFIG_GET(number/soft_popcap), CONFIG_GET(number/hard_popcap), CONFIG_GET(number/extreme_popcap)) //generalized field for this concept for use across ss13 codebases .["bunkered"] = CONFIG_GET(flag/panic_bunker) || FALSE .["interviews"] = CONFIG_GET(flag/panic_bunker_interview) || FALSE - if(SSshuttle?.emergency) - .["shuttle_mode"] = SSshuttle.emergency.mode - // Shuttle status, see /__DEFINES/stat.dm - .["shuttle_timer"] = SSshuttle.emergency.timeLeft() - // Shuttle timer, in seconds + . += SSevacuation.get_world_topic_status() //Status Cog Support Code /datum/world_topic/whois diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index a94b59897c13..e07bb2335207 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -616,7 +616,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) midround_injection_cooldown = (round(clamp(EXP_DISTRIBUTION(midround_injection_cooldown_middle), midround_delay_min, midround_delay_max)) + world.time) // Time to inject some threat into the round - if(EMERGENCY_PAST_POINT_OF_NO_RETURN) // Unless the shuttle is past the point of no return + if(SSevacuation.station_evacuated()) // Unless the shuttle is past the point of no return return message_admins("DYNAMIC: Checking for midround injection.") @@ -701,7 +701,8 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) /datum/game_mode/dynamic/make_antag_chance(mob/living/carbon/human/newPlayer) if (GLOB.dynamic_forced_extended) return - if(EMERGENCY_ESCAPED_OR_ENDGAMED) // No more rules after the shuttle has left + // No more rules after the game ended + if(!SSticker.IsRoundInProgress()) return if (forced_latejoin_rule) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm index 5f0985765ecf..518edbb08122 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -143,7 +143,7 @@ new_head = M.mind.add_antag_datum(new_head, revolution) revolution.update_objectives() revolution.update_heads() - SSshuttle.registerHostileEnvironment(revolution) + SSevacuation.add_evacuation_blocker(revolution) return TRUE else log_game("DYNAMIC: [ruletype] [name] discarded [M.name] from head revolutionary due to ineligibility.") diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index 0c72e22d7976..aa2646d86ac1 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -541,7 +541,7 @@ if(revolution.members.len) revolution.update_objectives() revolution.update_heads() - SSshuttle.registerHostileEnvironment(revolution) + SSevacuation.add_evacuation_blocker(revolution) return TRUE log_game("DYNAMIC: [ruletype] [name] failed to get any eligible headrevs. Refunding [cost] threat.") return FALSE diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index cc22a5cf58ff..5f1e05c7ed8c 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -59,7 +59,7 @@ /datum/game_mode/proc/check_finished(force_ending) //to be called by SSticker if(!SSticker.setup_done) return FALSE - if(SSshuttle.emergency && (SSshuttle.emergency.mode == SHUTTLE_ENDGAME)) + if(SSevacuation.evacuation_finished()) return TRUE if(GLOB.station_was_nuked) return TRUE @@ -196,10 +196,8 @@ SSticker.mode_result = "undefined" if(GLOB.station_was_nuked) SSticker.news_report = STATION_DESTROYED_NUKE - if(EMERGENCY_ESCAPED_OR_ENDGAMED) + if(SSevacuation.evacuation_finished()) SSticker.news_report = STATION_EVACUATED - if(SSshuttle.emergency.is_hijacked()) - SSticker.news_report = SHUTTLE_HIJACK /// Mode specific admin panel. /datum/game_mode/proc/admin_panel() diff --git a/code/game/gamemodes/objectives/_objective.dm b/code/game/gamemodes/objectives/_objective.dm index e597ea18c69d..a09db350181c 100644 --- a/code/game/gamemodes/objectives/_objective.dm +++ b/code/game/gamemodes/objectives/_objective.dm @@ -72,13 +72,14 @@ GLOBAL_LIST_EMPTY(objectives) //PARIAH EDIT return TRUE if(SSticker.force_ending || GLOB.station_was_nuked) // Just let them win. return TRUE - if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME) + if(SSevacuation.evacuation_finished()) return FALSE var/area/current_area = get_area(M.current) if(!current_area || istype(current_area, /area/shuttle/escape/brig)) // Fails if they are in the shuttle brig return FALSE var/turf/current_turf = get_turf(M.current) - return current_turf.onCentCom() || current_turf.onSyndieBase() + var/list/area/evac_areas = SSevacuation.get_endgame_areas() + return current_turf.onCentCom() || current_turf.onSyndieBase() || evac_areas[current_area] /datum/objective/proc/check_completion() return completed @@ -260,60 +261,6 @@ GLOBAL_LIST_EMPTY(objectives) //PARIAH EDIT else explanation_text = "Free Objective" -/datum/objective/hijack - name = "hijack" - explanation_text = "Hijack the emergency shuttle by hacking its navigational protocols through the control console (alt click emergency shuttle console)." - team_explanation_text = "Hijack the emergency shuttle by hacking its navigational protocols through the control console (alt click emergency shuttle console). Leave no team member behind." - - /// Overrides the hijack speed of any antagonist datum it is on ONLY, no other datums are impacted. - var/hijack_speed_override = 1 - -/datum/objective/hijack/check_completion() // Requires all owners to escape. - if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME) - return FALSE - var/list/datum/mind/owners = get_owners() - for(var/datum/mind/M in owners) - if(!considered_alive(M) || !SSshuttle.emergency.shuttle_areas[get_area(M.current)]) - return FALSE - return SSshuttle.emergency.is_hijacked() - -/datum/objective/elimination - name = "elimination" - explanation_text = "Slaughter all loyalist crew aboard the shuttle. You, and any likeminded individuals, must be the only remaining people on the shuttle." - team_explanation_text = "Slaughter all loyalist crew aboard the shuttle. You, and any likeminded individuals, must be the only remaining people on the shuttle. Leave no team member behind." - -/datum/objective/elimination/check_completion() - if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME) - return FALSE - var/list/datum/mind/owners = get_owners() - for(var/datum/mind/M in owners) - if(!considered_alive(M, enforce_human = FALSE) || !SSshuttle.emergency.shuttle_areas[get_area(M.current)]) - return FALSE - return SSshuttle.emergency.elimination_hijack() - -/datum/objective/elimination/highlander - name="highlander elimination" - explanation_text = "Escape on the shuttle alone. Ensure that nobody else makes it out." - -/datum/objective/elimination/highlander/check_completion() - if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME) - return FALSE - var/list/datum/mind/owners = get_owners() - for(var/datum/mind/M in owners) - if(!considered_alive(M, enforce_human = FALSE) || !SSshuttle.emergency.shuttle_areas[get_area(M.current)]) - return FALSE - return SSshuttle.emergency.elimination_hijack(filter_by_human = FALSE, solo_hijack = TRUE) - -/datum/objective/purge/check_completion() - if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME) - return TRUE - for(var/mob/living/player in GLOB.player_list) - if((get_area(player) in SSshuttle.emergency.shuttle_areas) && player.mind && player.stat != DEAD && ishuman(player)) - var/mob/living/carbon/human/H = player - if(H.dna.species.id != SPECIES_HUMAN) - return FALSE - return TRUE - /// Escape. Should not be given to anyone straight up. Exists for Escape with Identity. /datum/objective/escape name = "escape" diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 2ef1bbb42358..1ae5dd7ffc20 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -173,13 +173,13 @@ return message.answered = answer_index message.answer_callback.InvokeAsync() - if ("callShuttle") + if ("startEvac") if (!authenticated(usr) || syndicate) return var/reason = trim(params["reason"], MAX_MESSAGE_LEN) - if (length(reason) < CALL_SHUTTLE_REASON_LENGTH) + if (length(reason) < EVAC_REASON_LENGTH) return - SSshuttle.requestEvac(usr, reason) + SSevacuation.request_evacuation(usr, reason, params["evacController"]) post_status("shuttle") if ("changeSecurityLevel") if (!authenticated_as_silicon_or_captain(usr)) @@ -275,13 +275,13 @@ if (bank_account.account_balance < shuttle.credit_cost) return SSshuttle.shuttle_purchased = SHUTTLEPURCHASE_PURCHASED - for(var/datum/round_event_control/shuttle_insurance/insurance_event in SSevents.control) - insurance_event.weight *= 20 SSshuttle.unload_preview() - SSshuttle.existing_shuttle = SSshuttle.emergency + SSshuttle.existing_shuttle = GLOB.emergency_shuttle SSshuttle.action_load(shuttle, replace = TRUE) bank_account.adjust_money(-shuttle.credit_cost) + SSevacuation.escape_shuttle_replaced() + var/purchaser_name = (obj_flags & EMAGGED) ? scramble_message_replace_chars("AUTHENTICATION FAILURE: CVE-2018-17107", 60) : usr.real_name minor_announce("[purchaser_name] has purchased [shuttle.name] for [shuttle.credit_cost] credits.[shuttle.extra_desc ? " [shuttle.extra_desc]" : ""]" , "Shuttle Purchase") @@ -289,11 +289,11 @@ log_shuttle("[key_name(usr)] has purchased [shuttle.name].") SSblackbox.record_feedback("text", "shuttle_purchase", 1, shuttle.name) state = STATE_MAIN - if ("recallShuttle") + if ("cancelEvac") // AIs cannot recall the shuttle if (!authenticated(usr) || issilicon(usr) || syndicate) return - SSshuttle.cancelEvac(usr) + SSevacuation.request_cancel(usr, params["evacController"]) if ("requestNukeCodes") if (!authenticated_as_non_silicon_captain(usr)) return @@ -509,21 +509,18 @@ data["canBuyShuttles"] = can_buy_shuttles(user) data["canMakeAnnouncement"] = FALSE data["canMessageAssociates"] = FALSE - data["canRecallShuttles"] = !issilicon(user) + data["canRecallEvac"] = !issilicon(user) data["canRequestNuke"] = FALSE data["canSendToSectors"] = FALSE data["canSetAlertLevel"] = FALSE data["canToggleEmergencyAccess"] = FALSE data["importantActionReady"] = COOLDOWN_FINISHED(src, important_action_cooldown) - data["shuttleCalled"] = FALSE - data["shuttleLastCalled"] = FALSE + data["evacStarted"] = FALSE + data["evacLastCalled"] = FALSE data["aprilFools"] = SSevents.holidays && SSevents.holidays[APRIL_FOOLS] data["alertLevel"] = get_security_level() data["authorizeName"] = authorize_name data["canLogOut"] = !issilicon(user) - data["shuttleCanEvacOrFailReason"] = SSshuttle.canEvac(user) - if(syndicate) - data["shuttleCanEvacOrFailReason"] = "You cannot summon the shuttle from this console!" if (authenticated_as_non_silicon_captain(user)) data["canMessageAssociates"] = TRUE @@ -552,14 +549,9 @@ else if(syndicate) data["canMakeAnnouncement"] = TRUE - if (SSshuttle.emergency.mode != SHUTTLE_IDLE && SSshuttle.emergency.mode != SHUTTLE_RECALL) - data["shuttleCalled"] = TRUE - data["shuttleRecallable"] = SSshuttle.canRecall() || syndicate + data["canRequestEvac"] = !syndicate + data["evacOptions"] = SSevacuation.get_evac_ui_data(user) - if (SSshuttle.emergencyCallAmount) - data["shuttleCalledPreviously"] = TRUE - if (SSshuttle.emergency_last_call_loc) - data["shuttleLastCalled"] = format_text(SSshuttle.emergency_last_call_loc.name) if (STATE_MESSAGES) data["messages"] = list() @@ -573,6 +565,7 @@ "possibleAnswers" = message.possible_answers, )) if (STATE_BUYING_SHUTTLE) + data["shuttleToReplace"] = SSevacuation.get_customizable_shuttles() var/datum/bank_account/bank_account = SSeconomy.department_accounts_by_id[ACCOUNT_CAR] var/list/shuttles = list() @@ -611,7 +604,7 @@ /obj/machinery/computer/communications/ui_static_data(mob/user) return list( - "callShuttleReasonMinLength" = CALL_SHUTTLE_REASON_LENGTH, + "callShuttleReasonMinLength" = EVAC_REASON_LENGTH, "maxStatusLineLength" = MAX_STATUS_LINE_LENGTH, "maxMessageLength" = MAX_MESSAGE_LEN, ) @@ -669,8 +662,8 @@ if (!has_access) return FALSE - if (SSshuttle.emergency.mode != SHUTTLE_RECALL && SSshuttle.emergency.mode != SHUTTLE_IDLE) - return "The shuttle is already in transit." + //if (SSevacuation.controller.state != EVACUATION_STATE_IDLE) + // return "The shuttle is already in transit." if (SSshuttle.shuttle_purchased == SHUTTLEPURCHASE_PURCHASED) return "A replacement shuttle has already been purchased." if (SSshuttle.shuttle_purchased == SHUTTLEPURCHASE_FORCED) @@ -755,7 +748,7 @@ /obj/machinery/computer/communications/Destroy() UNSET_TRACKING(__TYPE__) UNSET_TRACKING(TRACKING_KEY_SHUTTLE_CALLER) - SSshuttle.autoEvac() + SSevacuation.trigger_auto_evac(EVACUATION_REASON_CONSOLE_DESTROYED) return ..() /// Override the cooldown for special actions diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index bbe099954574..919434033d90 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -193,7 +193,7 @@ DEFINE_INTERACTABLE(/obj/machinery/door) * * source The datum source of the signal * * new_level The new security level that is in effect */ -/obj/machinery/door/proc/check_security_level(datum/source, new_level) +/obj/machinery/door/proc/check_security_level(datum/source, old_level, new_level) SIGNAL_HANDLER if(new_level <= SEC_LEVEL_BLUE) diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index 0855ae5b1dba..3625ce9d5726 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -176,7 +176,7 @@ DEFINE_INTERACTABLE(/obj/machinery/firealarm) * * source The datum source of the signal * * new_level The new security level that is in effect */ -/obj/machinery/firealarm/proc/check_security_level(datum/source, new_level) +/obj/machinery/firealarm/proc/check_security_level(datum/source, old_level, new_level) SIGNAL_HANDLER if(is_station_level(z)) diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 360c94d96b9a..69d230c7c1b3 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -322,7 +322,11 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/status_display/evac, 32) return PROCESS_KILL if(SD_EMERGENCY) - return display_shuttle_status(SSshuttle.emergency) + . = SSevacuation.emergency_status_display_process(src) + if(!.) + set_messages("eva?#","") + return PROCESS_KILL + set_messages(copytext(.[1], CHARS_PER_LINE+1), copytext(.[2], CHARS_PER_LINE+1)) if(SD_MESSAGE) return PROCESS_KILL @@ -334,7 +338,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/status_display/evac, 32) /obj/machinery/status_display/evac/examine(mob/user) . = ..() if(current_mode == SD_EMERGENCY) - . += examine_shuttle(user, SSshuttle.emergency) + . += SSevacuation.status_display_examine(user, src) else if(!message1 && !message2) . += "The display is blank." diff --git a/code/game/world.dm b/code/game/world.dm index bd7abbdd4294..68145a5bc295 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -43,7 +43,7 @@ GLOBAL_VAR(restart_counter) make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once) - GLOB.config_error_log = GLOB.world_manifest_log = GLOB.world_pda_log = GLOB.world_job_debug_log = GLOB.sql_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = GLOB.world_econ_log = GLOB.world_shuttle_log = "data/logs/config_error.[GUID()].log" //temporary file used to record errors with loading config, moved to log directory once logging is set bl + GLOB.config_error_log = GLOB.world_manifest_log = GLOB.world_pda_log = GLOB.world_job_debug_log = GLOB.sql_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = GLOB.world_econ_log = GLOB.world_shuttle_log = GLOB.world_evacuation_log = "data/logs/config_error.[GUID()].log" //temporary file used to record errors with loading config, moved to log directory once logging is set bl #ifdef REFERENCE_DOING_IT_LIVE GLOB.harddel_log = GLOB.world_game_log #endif @@ -158,6 +158,7 @@ GLOBAL_VAR(restart_counter) GLOB.world_paper_log = "[GLOB.log_directory]/paper.log" GLOB.tgui_log = "[GLOB.log_directory]/tgui.log" GLOB.world_shuttle_log = "[GLOB.log_directory]/shuttle.log" + GLOB.world_evacuation_log = "[GLOB.log_directory]/evacuation.log" GLOB.filter_log = "[GLOB.log_directory]/filters.log" GLOB.demo_log = "[GLOB.log_directory]/demo.log" @@ -186,6 +187,7 @@ GLOBAL_VAR(restart_counter) start_log(GLOB.world_job_debug_log) start_log(GLOB.tgui_log) start_log(GLOB.world_shuttle_log) + start_log(GLOB.world_evacuation_log) var/latest_changelog = file("[global.config.directory]/../html/changelogs/archive/" + time2text(world.timeofday, "YYYY-MM") + ".yml") GLOB.changelog_hash = fexists(latest_changelog) ? md5(latest_changelog) : 0 //for telling if the changelog has changed recently diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 9a58e38085e3..4c09780f82c2 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -30,6 +30,7 @@ dat += "
" if(SSticker.IsRoundInProgress()) dat += "(Game Mode Panel)
" + dat += "(Evacuation Panel)
" dat += {"
Create Object
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 2322eac3cc33..fc3cded38d46 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -63,8 +63,8 @@ GLOBAL_PROTECT(admin_verbs_admin) /client/proc/jumptoturf, /*allows us to jump to a specific turf*/ /client/proc/admin_call_shuttle, /*allows us to call the emergency shuttle*/ /client/proc/admin_cancel_shuttle, /*allows us to cancel the emergency shuttle, sending it back to centcom*/ - /client/proc/admin_disable_shuttle, /*allows us to disable the emergency shuttle admin-wise so that it cannot be called*/ - /client/proc/admin_enable_shuttle, /*undoes the above*/ + /client/proc/admin_disable_evac, /*allows us to disable the emergency shuttle admin-wise so that it cannot be called*/ + /client/proc/admin_enable_evac, /*undoes the above*/ /client/proc/cmd_admin_direct_narrate, /*send text directly to a player with no padding. Useful for narratives and fluff-text*/ /client/proc/cmd_admin_world_narrate, /*sends text to all players with no padding*/ /client/proc/cmd_admin_local_narrate, /*sends text to all mobs within view of atom*/ diff --git a/code/modules/admin/check_antagonists.dm b/code/modules/admin/check_antagonists.dm index fe6a13643bd9..140ec05e6370 100644 --- a/code/modules/admin/check_antagonists.dm +++ b/code/modules/admin/check_antagonists.dm @@ -124,19 +124,9 @@ tgui_alert(usr, "The game hasn't started yet!") return var/list/dat = list("Round Status

Round Status

") - if(IS_DYNAMIC_GAME_MODE) // Currently only used by dynamic. If more start using this, find a better way. - dat += "Game Mode Panel
" + dat += "Game Mode Panel
" dat += "Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]
" - dat += "Emergency shuttle
" - if(EMERGENCY_IDLE_OR_RECALLED) - dat += "Call Shuttle
" - else - var/timeleft = SSshuttle.emergency.timeLeft() - if(SSshuttle.emergency.mode == SHUTTLE_CALL) - dat += "ETA: [(timeleft / 60) % 60]:[add_leading(num2text(timeleft % 60), 2, "0")]
" - dat += "Send Back
" - else - dat += "ETA: [(timeleft / 60) % 60]:[add_leading(num2text(timeleft % 60), 2, "0")]
" + dat += "Evacuation Panel
" dat += "End Round Now
" if(SSticker.delay_end) dat += "End Round Normally
" diff --git a/code/modules/admin/fun_balloon.dm b/code/modules/admin/fun_balloon.dm index a6e343229ac1..23650a0573d0 100644 --- a/code/modules/admin/fun_balloon.dm +++ b/code/modules/admin/fun_balloon.dm @@ -98,16 +98,6 @@ body.key = C.key new /obj/effect/temp_visual/gravpush(get_turf(body)) -// ----------- Emergency Shuttle Balloon -/obj/effect/fun_balloon/sentience/emergency_shuttle - name = "shuttle sentience fun balloon" - var/trigger_time = 60 - -/obj/effect/fun_balloon/sentience/emergency_shuttle/check() - . = FALSE - if(SSshuttle.emergency && (SSshuttle.emergency.timeLeft() <= trigger_time) && (SSshuttle.emergency.mode == SHUTTLE_CALL)) - . = TRUE - // ----------- Scatter Balloon /obj/effect/fun_balloon/scatter name = "scatter fun balloon" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 109780f5efe6..6a44fcb920c7 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -93,50 +93,25 @@ return SSticker.mode.admin_panel() - else if(href_list["call_shuttle"]) + else if(href_list["evac_panel"]) if(!check_rights(R_ADMIN)) return + SSevacuation.admin_panel() - - switch(href_list["call_shuttle"]) - if("1") - if(EMERGENCY_AT_LEAST_DOCKED) - return - SSshuttle.emergency.request() - log_admin("[key_name(usr)] called the Emergency Shuttle.") - message_admins(span_adminnotice("[key_name_admin(usr)] called the Emergency Shuttle to the station.")) - - if("2") - if(EMERGENCY_AT_LEAST_DOCKED) - return - switch(SSshuttle.emergency.mode) - if(SHUTTLE_CALL) - SSshuttle.emergency.cancel() - log_admin("[key_name(usr)] sent the Emergency Shuttle back.") - message_admins(span_adminnotice("[key_name_admin(usr)] sent the Emergency Shuttle back.")) - else - SSshuttle.emergency.cancel() - log_admin("[key_name(usr)] called the Emergency Shuttle.") - message_admins(span_adminnotice("[key_name_admin(usr)] called the Emergency Shuttle to the station.")) - - - - else if(href_list["edit_shuttle_time"]) - if(!check_rights(R_SERVER)) + else if(href_list["evac_controller"]) + if(!check_rights(R_ADMIN)) return + SSevacuation.panel_act(href_list) - var/timer = input("Enter new shuttle duration (seconds):","Edit Shuttle Timeleft", SSshuttle.emergency.timeLeft() ) as num|null - if(!timer) - return - SSshuttle.emergency.setTimer(timer SECONDS) - log_admin("[key_name(usr)] edited the Emergency Shuttle's timeleft to [timer] seconds.") - minor_announce("The emergency shuttle will reach its destination in [DisplayTimeText(timer SECONDS)].") - message_admins(span_adminnotice("[key_name_admin(usr)] edited the Emergency Shuttle's timeleft to [timer] seconds.")) else if(href_list["trigger_centcom_recall"]) if(!check_rights(R_ADMIN)) return - usr.client.trigger_centcom_recall() + usr.client.trigger_centcom_recall(href_list["trigger_centcom_recall"]) + + else if(href_list["start_evac"]) + if(!check_rights(R_ADMIN)) + return else if(href_list["move_shuttle"]) if(!check_rights(R_ADMIN)) @@ -156,6 +131,7 @@ return shuttle_console.admin_controlled = !shuttle_console.admin_controlled to_chat(usr, "[shuttle_console] was [shuttle_console.admin_controlled ? "locked" : "unlocked"].", confidential = TRUE) + else if(href_list["delay_round_end"]) if(!check_rights(R_SERVER)) return @@ -178,6 +154,7 @@ log_admin("[key_name(usr)] delayed the round end for reason: [SSticker.admin_delay_notice]") message_admins("[key_name_admin(usr)] delayed the round end for reason: [SSticker.admin_delay_notice]") + else if(href_list["undelay_round_end"]) if(!check_rights(R_SERVER)) return @@ -193,6 +170,7 @@ message_admins("[key_name_admin(usr)] undelayed the round end. You must now manually Reboot World to start the next shift.") else message_admins("[key_name_admin(usr)] undelayed the round end.") + else if(href_list["end_round"]) if(!check_rights(R_ADMIN)) return diff --git a/code/modules/admin/verbs/admin.dm b/code/modules/admin/verbs/admin.dm index 648b7329611b..8198e8ed5eef 100644 --- a/code/modules/admin/verbs/admin.dm +++ b/code/modules/admin/verbs/admin.dm @@ -70,7 +70,7 @@ msg += "" src << browse(msg.Join(), "window=Player_playtime_check") -/client/proc/trigger_centcom_recall() +/client/proc/trigger_centcom_recall(identifier) if(!check_rights(R_ADMIN)) return var/message = pick(GLOB.admiral_messages) @@ -81,7 +81,7 @@ message_admins("[key_name_admin(usr)] triggered a CentCom recall, with the admiral message of: [message]") log_game("[key_name(usr)] triggered a CentCom recall, with the message of: [message]") - SSshuttle.centcom_recall(SSshuttle.emergency.timer, message) + SSevacuation.centcom_recall(identifier, message) /datum/admins/proc/cmd_show_exp_panel(client/client_to_check) if(!check_rights(R_ADMIN)) diff --git a/code/modules/admin/verbs/adminevents.dm b/code/modules/admin/verbs/adminevents.dm index 47516da16328..099a840d017b 100644 --- a/code/modules/admin/verbs/adminevents.dm +++ b/code/modules/admin/verbs/adminevents.dm @@ -149,12 +149,13 @@ /client/proc/admin_call_shuttle() set category = "Admin.Events" - set name = "Call Shuttle" + set name = "Start Evacuation" - if(EMERGENCY_AT_LEAST_DOCKED) + if(!check_rights(R_ADMIN)) return - if(!check_rights(R_ADMIN)) + var/identifier = tgui_input_list(usr, "Choose evacuation option", "Evacuation", SSevacuation.get_controllers_names()) + if(identifier == null) return var/confirm = tgui_alert(usr, "You sure?", "Confirm", list("Yes", "Yes (No Recall)", "No")) @@ -162,89 +163,68 @@ if(null, "No") return if("Yes (No Recall)") - SSshuttle.admin_emergency_no_recall = TRUE - SSshuttle.emergency.mode = SHUTTLE_IDLE + SSevacuation.block_cancel(identifier) - SSshuttle.emergency.request() + SSevacuation.request_evacuation(usr, null, identifier, admin = TRUE) SSblackbox.record_feedback("tally", "admin_verb", 1, "Call Shuttle") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - log_admin("[key_name(usr)] admin-called the emergency shuttle.") - message_admins(span_adminnotice("[key_name_admin(usr)] admin-called the emergency shuttle[confirm == "Yes (No Recall)" ? " (non-recallable)" : ""].")) + log_admin("[key_name(usr)] admin-started the evacuation.") + message_admins(span_adminnotice("[key_name_admin(usr)] admin-started the evacuation[confirm == "Yes (No Recall)" ? " (non-recallable)" : ""].")) return /client/proc/admin_cancel_shuttle() set category = "Admin.Events" - set name = "Cancel Shuttle" + set name = "Cancel Evacuation" + if(!check_rights(0)) return - if(tgui_alert(usr, "You sure?", "Confirm", list("Yes", "No")) != "Yes") - return - if(SSshuttle.admin_emergency_no_recall) - SSshuttle.admin_emergency_no_recall = FALSE + var/identifier = tgui_input_list(usr, "Choose evacuation option", "Evacuation", SSevacuation.get_controllers_names(TRUE)) + if(identifier == null) + return - if(EMERGENCY_AT_LEAST_DOCKED) + if(tgui_alert(usr, "You sure?", "Confirm", list("Yes", "No")) != "Yes") return - SSshuttle.emergency.cancel() + SSevacuation.unblock_cancel(identifier) + SSevacuation.request_cancel(usr, identifier) SSblackbox.record_feedback("tally", "admin_verb", 1, "Cancel Shuttle") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! log_admin("[key_name(usr)] admin-recalled the emergency shuttle.") message_admins(span_adminnotice("[key_name_admin(usr)] admin-recalled the emergency shuttle.")) return -/client/proc/admin_disable_shuttle() +/client/proc/admin_disable_evac() set category = "Admin.Events" - set name = "Disable Shuttle" + set name = "Disable Evacuation" if(!check_rights(R_ADMIN)) return - if(SSshuttle.emergency.mode == SHUTTLE_DISABLED) - to_chat(usr, span_warning("Error, shuttle is already disabled.")) + var/identifier = tgui_input_list(usr, "Choose evacuation option", "Evacuation", SSevacuation.get_controllers_names()) + if(identifier == null) return if(tgui_alert(usr, "You sure?", "Confirm", list("Yes", "No")) != "Yes") return - message_admins(span_adminnotice("[key_name_admin(usr)] disabled the shuttle.")) + message_admins(span_adminnotice("[key_name_admin(usr)] disabled the [identifier] evacuation option.")) + SSevacuation.disable_evacuation(identifier) - SSshuttle.last_mode = SSshuttle.emergency.mode - SSshuttle.last_call_time = SSshuttle.emergency.timeLeft(1) - SSshuttle.admin_emergency_no_recall = TRUE - SSshuttle.emergency.setTimer(0) - SSshuttle.emergency.mode = SHUTTLE_DISABLED - priority_announce( - "Warning: Emergency Shuttle uplink failure, shuttle disabled until further notice.", - "LRSV Icarus Announcement", - "Emergency Shuttle Uplink Alert", - 'sound/misc/announce_dig.ogg' - ) - -/client/proc/admin_enable_shuttle() +/client/proc/admin_enable_evac() set category = "Admin.Events" - set name = "Enable Shuttle" + set name = "Enable Evacuation" if(!check_rights(R_ADMIN)) return - if(SSshuttle.emergency.mode != SHUTTLE_DISABLED) - to_chat(usr, span_warning("Error, shuttle not disabled.")) + var/identifier = tgui_input_list(usr, "Choose evacuation option", "Evacuation", SSevacuation.get_controllers_names()) + if(identifier == null) return if(tgui_alert(usr, "You sure?", "Confirm", list("Yes", "No")) != "Yes") return - message_admins(span_adminnotice("[key_name_admin(usr)] enabled the emergency shuttle.")) - SSshuttle.admin_emergency_no_recall = FALSE - SSshuttle.emergency_no_recall = FALSE - if(SSshuttle.last_mode == SHUTTLE_DISABLED) //If everything goes to shit, fix it. - SSshuttle.last_mode = SHUTTLE_IDLE - - SSshuttle.emergency.mode = SSshuttle.last_mode - if(SSshuttle.last_call_time < 10 SECONDS && SSshuttle.last_mode != SHUTTLE_IDLE) - SSshuttle.last_call_time = 10 SECONDS //Make sure no insta departures. - SSshuttle.emergency.setTimer(SSshuttle.last_call_time) - priority_announce("Warning: Emergency Shuttle uplink reestablished, shuttle enabled.", "LRSV Icarus Announcement", "Emergency Shuttle Uplink Alert", 'sound/misc/announce_dig.ogg') + SSevacuation.enable_evacuation(identifier) /client/proc/toggle_nuke(obj/machinery/nuclearbomb/N in INSTANCES_OF(/obj/machinery/nuclearbomb)) set category = "Admin.Events" diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 17cb13dda57d..28bfb3856203 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -255,10 +255,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) round_state = "Round has not started" if(GAME_STATE_PLAYING) round_state = "Round is ongoing." - if(SSshuttle.emergency.getModeStr()) - round_state += "\n[SSshuttle.emergency.getModeStr()]: [SSshuttle.emergency.getTimerStr()]" - if(SSticker.emergency_reason) - round_state += ", Shuttle call reason: [SSticker.emergency_reason]" + round_state += SSevacuation.get_discord_status() if(GAME_STATE_FINISHED) round_state = "Round has ended" var/list/admin_counts = get_admin_counts(R_BAN) diff --git a/code/modules/admin/verbs/highlander_datum.dm b/code/modules/admin/verbs/highlander_datum.dm index bd0a60a848da..89e4ed301a0a 100644 --- a/code/modules/admin/verbs/highlander_datum.dm +++ b/code/modules/admin/verbs/highlander_datum.dm @@ -36,7 +36,6 @@ GLOBAL_DATUM(highlander_controller, /datum/highlander_controller) robot.gib() continue robot.make_scottish() - addtimer(CALLBACK(SSshuttle.emergency, TYPE_PROC_REF(/obj/docking_port/mobile/emergency, request), null, 1), 50) /datum/highlander_controller/Destroy(force, ...) . = ..() diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index 51157258efe3..278ad27ff032 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -26,10 +26,6 @@ GLOBAL_LIST_EMPTY(antagonists) var/antag_memory = "" ///typepath of moodlet that the mob will gain when granted this antagonist type. var/antag_moodlet - ///If these antags are alone when a shuttle elimination happens. - var/can_elimination_hijack = ELIMINATION_NEUTRAL - ///If above 0, this is the multiplier for the speed at which we hijack the shuttle. Do not directly read, use hijack_speed(). - var/hijack_speed = 0 ///The antag hud's icon file var/hud_icon = 'icons/mob/huds/antag_hud.dmi' ///Name of the antag hud we provide to this mob. @@ -384,14 +380,6 @@ GLOBAL_LIST_EMPTY(antagonists) return antag_memory = new_memo -/** - * Gets how fast we can hijack the shuttle, return 0 for can not hijack. - * Defaults to hijack_speed var, override for custom stuff like buffing hijack speed for hijack objectives or something. - */ -/datum/antagonist/proc/hijack_speed() - var/datum/objective/hijack/H = locate() in objectives - return H?.hijack_speed_override || hijack_speed - /// Adds a HUD that will show you other members with the same antagonist. /// If an antag typepath is passed to `antag_to_check`, will check that, otherwise will use the source type. /datum/antagonist/proc/add_team_hud(mob/target, antag_to_check) diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm index 90e8ccee9c9e..4142bd9896cc 100644 --- a/code/modules/antagonists/blob/overmind.dm +++ b/code/modules/antagonists/blob/overmind.dm @@ -64,7 +64,7 @@ GLOBAL_LIST_EMPTY(blob_nodes) color = blobstrain.complementary_color if(blob_core) blob_core.update_appearance() - SSshuttle.registerHostileEnvironment(src) + SSevacuation.add_evacuation_blocker(src) . = ..() START_PROCESSING(SSobj, src) @@ -219,7 +219,7 @@ GLOBAL_LIST_EMPTY(blob_nodes) GLOB.overminds -= src QDEL_LIST_ASSOC_VAL(strain_choices) - SSshuttle.clearHostileEnvironment(src) + SSevacuation.remove_evacuation_blocker(src) STOP_PROCESSING(SSobj, src) return ..() diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm index 8932e9763fe4..551bd96c59c6 100644 --- a/code/modules/antagonists/brother/brother.dm +++ b/code/modules/antagonists/brother/brother.dm @@ -4,7 +4,6 @@ job_rank = ROLE_BROTHER var/special_role = ROLE_BROTHER antag_hud_name = "brother" - hijack_speed = 0.5 ui_name = "AntagInfoBrother" suicide_cry = "FOR MY BROTHER!!" var/datum/team/brother_team/team diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index 8eb234e63055..9f3e75a5ba40 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -12,7 +12,6 @@ antagpanel_category = "Changeling" job_rank = ROLE_CHANGELING antag_hud_name = "changeling" - hijack_speed = 0.5 ui_name = "AntagInfoChangeling" suicide_cry = "FOR THE HIVE!!" /// Whether to give this changeling objectives or not diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index 71f49aa2df7c..7a3faba055c9 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -513,13 +513,15 @@ Striking a noncultist, however, will tear their flesh."} list_reagents = list(/datum/reagent/fuel/unholywater = 50) ///how many times can the shuttle be cursed? -#define MAX_SHUTTLE_CURSES 3 +#define MAX_EVAC_CURSES 3 ///if the max number of shuttle curses are used within this duration, the entire cult gets an achievement #define SHUTTLE_CURSE_OMFG_TIMESPAN 10 SECONDS +///how long is the evacuation delayed by? +#define EVAC_DELAY 3 MINUTES /obj/item/shuttle_curse name = "cursed orb" - desc = "You peer within this smokey orb and glimpse terrible fates befalling the emergency escape shuttle. " + desc = "You peer within this smokey orb and glimpse terrible fates befalling people during the evacuation. " icon = 'icons/obj/cult/items_and_weapons.dmi' icon_state = "shuttlecurse" ///how many times has the shuttle been cursed so far? @@ -535,58 +537,47 @@ Striking a noncultist, however, will tear their flesh."} user.Paralyze(100) to_chat(user, span_warning("A powerful force shoves you away from [src]!")) return - if(totalcurses >= MAX_SHUTTLE_CURSES) + if(totalcurses >= MAX_EVAC_CURSES) to_chat(user, span_warning("You try to shatter the orb, but it remains as solid as a rock!")) - to_chat(user, span_danger(span_big("It seems that the blood cult has exhausted its ability to curse the emergency escape shuttle. It would be unwise to create more cursed orbs or to continue to try to shatter this one."))) + to_chat(user, span_danger(span_big("It seems that the blood cult has exhausted its ability to curse the evacuation. It would be unwise to create more cursed orbs or to continue to try to shatter this one."))) return if(locate(/obj/narsie) in SSpoints_of_interest.narsies) to_chat(user, span_warning("Nar'Sie is already on this plane, there is no delaying the end of all things.")) return - if(SSshuttle.emergency.mode == SHUTTLE_CALL) - var/cursetime = 3 MINUTES - var/timer = SSshuttle.emergency.timeLeft(1) + cursetime - var/security_num = seclevel2num(get_security_level()) - var/set_coefficient = 1 + var/identifier = SSevacuation.get_initiated_controller() + if(!identifier) + return - if(totalcurses == 0) - first_curse_time = world.time + SSevacuation.delay_evacuation(identifier, 3 MINUTES) - switch(security_num) - if(SEC_LEVEL_GREEN) - set_coefficient = 1 - else - set_coefficient = 0.5 - - var/surplus = timer - (SSshuttle.emergency_call_time * set_coefficient) - SSshuttle.emergency.setTimer(timer) - if(surplus > 0) - SSshuttle.block_recall(surplus) - totalcurses++ - to_chat(user, span_danger("You shatter the orb! A dark essence spirals into the air, then disappears.")) - playsound(user.loc, 'sound/effects/glassbr1.ogg', 50, TRUE) - - if(!remaining_curses) - remaining_curses = strings(CULT_SHUTTLE_CURSE, "curse_announce") - - var/curse_message = pick_n_take(remaining_curses) || "Something has gone horrendously wrong..." - - curse_message += " The shuttle will be delayed by three minutes." - priority_announce("[curse_message]", "LSRV Icarus Announcement", "System Failure", 'sound/misc/notice1.ogg') - if(MAX_SHUTTLE_CURSES-totalcurses <= 0) - to_chat(user, span_danger(span_big("You sense that the emergency escape shuttle can no longer be cursed. It would be unwise to create more cursed orbs."))) - else if(MAX_SHUTTLE_CURSES-totalcurses == 1) - to_chat(user, span_danger(span_big("You sense that the emergency escape shuttle can only be cursed one more time."))) - else - to_chat(user, span_danger(span_big("You sense that the emergency escape shuttle can only be cursed [MAX_SHUTTLE_CURSES-totalcurses] more times."))) + totalcurses++ + to_chat(user, span_danger("You shatter the orb! A dark essence spirals into the air, then disappears.")) + playsound(user.loc, 'sound/effects/glassbr1.ogg', 50, TRUE) - if(totalcurses >= MAX_SHUTTLE_CURSES && (world.time < first_curse_time + SHUTTLE_CURSE_OMFG_TIMESPAN)) - var/omfg_message = pick_list(CULT_SHUTTLE_CURSE, "omfg_announce") || "LEAVE US ALONE!" - addtimer(CALLBACK(GLOBAL_PROC,PROC_REF(priority_announce),omfg_message,"Daedalus Industries Shuttle Dispatch","FUCK OFF",'sound/misc/notice1.ogg'), rand(2 SECONDS, 6 SECONDS)) + if(!remaining_curses) + remaining_curses = strings(CULT_SHUTTLE_CURSE, "curse_announce") - qdel(src) + var/curse_message = pick_n_take(remaining_curses) || "Something has gone horrendously wrong..." + + curse_message += " The shuttle will be delayed by three minutes." + priority_announce("[curse_message]", "LSRV Icarus Announcement", "System Failure", 'sound/misc/notice1.ogg') + if(MAX_EVAC_CURSES-totalcurses <= 0) + to_chat(user, span_danger(span_big("You sense that the emergency escape shuttle can no longer be cursed. It would be unwise to create more cursed orbs."))) + else if(MAX_EVAC_CURSES-totalcurses == 1) + to_chat(user, span_danger(span_big("You sense that the emergency escape shuttle can only be cursed one more time."))) + else + to_chat(user, span_danger(span_big("You sense that the emergency escape shuttle can only be cursed [MAX_EVAC_CURSES-totalcurses] more times."))) + + if(totalcurses >= MAX_EVAC_CURSES && (world.time < first_curse_time + SHUTTLE_CURSE_OMFG_TIMESPAN)) + var/omfg_message = pick_list(CULT_SHUTTLE_CURSE, "omfg_announce") || "LEAVE US ALONE!" + addtimer(CALLBACK(GLOBAL_PROC,PROC_REF(priority_announce),omfg_message,"Daedalus Industries Shuttle Dispatch","FUCK OFF",'sound/misc/notice1.ogg'), rand(2 SECONDS, 6 SECONDS)) + + qdel(src) -#undef MAX_SHUTTLE_CURSES +#undef SHUTTLE_CURSE_OMFG_TIMESPAN +#undef EVAC_DELAY +#undef MAX_EVAC_CURSES /obj/item/cult_shift name = "veil shifter" diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm index bd62e44e694e..5db631686047 100644 --- a/code/modules/antagonists/ert/ert.dm +++ b/code/modules/antagonists/ert/ert.dm @@ -5,7 +5,6 @@ /datum/antagonist/ert name = "Emergency Response Officer" - can_elimination_hijack = ELIMINATION_PREVENT show_in_antagpanel = FALSE show_to_ghosts = TRUE suicide_cry = "FOR NANOTRASEN!!" diff --git a/code/modules/antagonists/heretic/heretic_antag.dm b/code/modules/antagonists/heretic/heretic_antag.dm index 19846ddb2e44..1f920167bf6b 100644 --- a/code/modules/antagonists/heretic/heretic_antag.dm +++ b/code/modules/antagonists/heretic/heretic_antag.dm @@ -19,7 +19,6 @@ ui_name = "AntagInfoHeretic" job_rank = ROLE_HERETIC antag_hud_name = "heretic" - hijack_speed = 0.5 suicide_cry = "THE MANSUS SMILES UPON ME!!" preview_outfit = /datum/outfit/heretic /// Whether we give this antagonist objectives on gain. diff --git a/code/modules/antagonists/highlander/highlander.dm b/code/modules/antagonists/highlander/highlander.dm index a8af18b1b752..6949755ba474 100644 --- a/code/modules/antagonists/highlander/highlander.dm +++ b/code/modules/antagonists/highlander/highlander.dm @@ -3,7 +3,6 @@ var/obj/item/claymore/highlander/sword show_in_antagpanel = FALSE show_name_in_check_antagonists = TRUE - can_elimination_hijack = ELIMINATION_ENABLED suicide_cry = "FOR SCOTLAND!!" // If they manage to lose their no-drop stuff somehow /datum/antagonist/highlander/apply_innate_effects(mob/living/mob_override) @@ -27,9 +26,6 @@ steal_objective.owner = owner steal_objective.set_target(new /datum/objective_item/steal/nukedisc) objectives += steal_objective - var/datum/objective/elimination/highlander/elimination_objective = new - elimination_objective.owner = owner - objectives += elimination_objective /datum/antagonist/highlander/on_gain() forge_objectives() diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index cfbad105c32b..65dc9cd8b449 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -511,7 +511,7 @@ GLOBAL_VAR(station_nuke_source) off_station = NUKE_MISS_STATION if(off_station < NUKE_MISS_STATION) - SSshuttle.registerHostileEnvironment(src) + SSevacuation.add_evacuation_blocker(src) SSshuttle.lockdown = TRUE //Cinematic GLOB.station_nuke_source = off_station diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm index 788924a11a25..7205e12f427a 100644 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ b/code/modules/antagonists/nukeop/nukeop.dm @@ -5,7 +5,6 @@ job_rank = ROLE_OPERATIVE antag_hud_name = "synd" show_to_ghosts = TRUE - hijack_speed = 2 //If you can't take out the station, take the shuttle instead. suicide_cry = "FOR THE SYNDICATE!!" var/datum/team/nuclear/nuke_team var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team. @@ -338,12 +337,9 @@ /datum/team/nuclear/proc/disk_rescued() for(var/obj/item/disk/nuclear/D in SSpoints_of_interest.real_nuclear_disks) //If emergency shuttle is in transit disk is only safe on it - if(SSshuttle.emergency.mode == SHUTTLE_ESCAPE) - if(!SSshuttle.emergency.is_in_shuttle_bounds(D)) - return FALSE - //If shuttle escaped check if it's on centcom side - else if(SSshuttle.emergency.mode == SHUTTLE_ENDGAME) - if(!D.onCentCom()) + if(SSevacuation.evacuation_finished()) + var/list/area/evac_areas = SSevacuation.get_endgame_areas() + if(!D.onCentCom() && !evac_areas[get_area(D)]) return FALSE else //Otherwise disk is safe when on station var/turf/T = get_turf(D) @@ -359,7 +355,6 @@ return TRUE /datum/team/nuclear/proc/get_result() - var/evacuation = EMERGENCY_ESCAPED_OR_ENDGAMED var/disk_rescued = disk_rescued() var/syndies_didnt_escape = !syndies_escaped() var/station_was_nuked = GLOB.station_was_nuked @@ -375,13 +370,13 @@ return NUKE_RESULT_WRONG_STATION else if (!disk_rescued && !station_was_nuked && station_nuke_source && syndies_didnt_escape) return NUKE_RESULT_WRONG_STATION_DEAD - else if ((disk_rescued && evacuation) && operatives_dead()) + else if (disk_rescued && operatives_dead()) return NUKE_RESULT_CREW_WIN_SYNDIES_DEAD else if (disk_rescued) return NUKE_RESULT_CREW_WIN else if (!disk_rescued && operatives_dead()) return NUKE_RESULT_DISK_LOST - else if (!disk_rescued && evacuation) + else if (!disk_rescued) return NUKE_RESULT_DISK_STOLEN else return //Undefined result diff --git a/code/modules/antagonists/pirate/pirate.dm b/code/modules/antagonists/pirate/pirate.dm index 6d37eb507272..5262b495c913 100644 --- a/code/modules/antagonists/pirate/pirate.dm +++ b/code/modules/antagonists/pirate/pirate.dm @@ -5,7 +5,6 @@ show_in_antagpanel = FALSE show_to_ghosts = TRUE suicide_cry = "FOR ME MATEYS!!" - hijack_speed = 2 // That is without doubt the worst pirate I have ever seen. var/datum/team/pirate/crew /datum/antagonist/pirate/greet() diff --git a/code/modules/antagonists/revolution/enemy_of_the_state.dm b/code/modules/antagonists/revolution/enemy_of_the_state.dm index e42e5d75b558..b9ff1364b6db 100644 --- a/code/modules/antagonists/revolution/enemy_of_the_state.dm +++ b/code/modules/antagonists/revolution/enemy_of_the_state.dm @@ -7,7 +7,6 @@ name = "\improper Enemy of the State" show_in_antagpanel = FALSE show_name_in_check_antagonists = TRUE - hijack_speed = 2 //not like they have much to do suicide_cry = "FOR THE ETERNAL REVOLUTION!!" /datum/antagonist/enemy_of_the_state/proc/forge_objectives() @@ -17,11 +16,6 @@ exile_choice.objective_name = "Choice" objectives += exile_choice - var/datum/objective/hijack/hijack_choice = new - hijack_choice.owner = owner - hijack_choice.objective_name = "Choice" - objectives += hijack_choice - /datum/antagonist/enemy_of_the_state/on_gain() owner.special_role = "exiled headrev" forge_objectives() @@ -45,23 +39,16 @@ //needs to complete only one objective, not all var/option_chosen = FALSE - var/badass = FALSE if(objectives.len) report += printobjectives(objectives) for(var/datum/objective/objective in objectives) if(objective.check_completion()) option_chosen = TRUE - if(istype(objective, /datum/objective/hijack)) - badass = TRUE break if(objectives.len == 0 || option_chosen) - if(badass) - report += "Major [name] Victory" - report += "[name] chose the badass option, and hijacked the shuttle!" - else - report += "Minor [name] Victory" - report += "[name] has survived as an exile!" + report += "[name] Victory" + report += "[name] has survived as an exile!" else report += "The [name] has failed!" diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm index f8c224a73570..0ffe9d7a2226 100644 --- a/code/modules/antagonists/revolution/revolution.dm +++ b/code/modules/antagonists/revolution/revolution.dm @@ -414,7 +414,7 @@ else return - SSshuttle.clearHostileEnvironment(src) + SSevacuation.remove_evacuation_blocker(src) save_members() var/charter_given = FALSE diff --git a/code/modules/antagonists/space_ninja/space_ninja.dm b/code/modules/antagonists/space_ninja/space_ninja.dm index 959fada29615..9c136d3f499e 100644 --- a/code/modules/antagonists/space_ninja/space_ninja.dm +++ b/code/modules/antagonists/space_ninja/space_ninja.dm @@ -3,7 +3,6 @@ antagpanel_category = "Space Ninja" job_rank = ROLE_NINJA antag_hud_name = "space_ninja" - hijack_speed = 1 show_name_in_check_antagonists = TRUE show_to_ghosts = TRUE suicide_cry = "FOR THE SPIDER CLAN!!" diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index d9e9c24f65b6..88e7255f9b52 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -4,7 +4,6 @@ antagpanel_category = "Traitor" job_rank = ROLE_TRAITOR antag_hud_name = "traitor" - hijack_speed = 0.5 //10 seconds per hijack stage by default ui_name = "AntagInfoTraitor" suicide_cry = "FOR THE SYNDICATE!!" preview_outfit = /datum/outfit/traitor @@ -12,8 +11,6 @@ var/should_give_codewords = FALSE ///give this traitor an uplink? var/give_uplink = TRUE - ///if TRUE, this traitor will always get hijacking as their final objective - var/is_hijacker = FALSE ///the name of the antag flavor this traitor has. var/employer diff --git a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm index 262ea29b922c..23817f281001 100644 --- a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm +++ b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm @@ -273,7 +273,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) timing = FALSE QDEL_NULL(countdown) STOP_PROCESSING(SSfastprocess, src) - SSshuttle.clearHostileEnvironment(src) + SSevacuation.remove_evacuation_blocker(src) SSmapping.remove_nuke_threat(src) set_security_level("red") for(var/mob/living/silicon/robot/borg in owner?.connected_robots) @@ -293,7 +293,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) timing = TRUE countdown.start() START_PROCESSING(SSfastprocess, src) - SSshuttle.registerHostileEnvironment(src) + SSevacuation.add_evacuation_blocker(src) SSmapping.add_nuke_threat(src) //This causes all blue "circuit" tiles on the map to change to animated red icon state. for(var/mob/living/silicon/robot/borg in owner.connected_robots) borg.lamp_doom = TRUE diff --git a/code/modules/antagonists/wishgranter/wishgranter.dm b/code/modules/antagonists/wishgranter/wishgranter.dm index 82caf79143d5..bf6f8d819a95 100644 --- a/code/modules/antagonists/wishgranter/wishgranter.dm +++ b/code/modules/antagonists/wishgranter/wishgranter.dm @@ -2,13 +2,10 @@ name = "\improper Wishgranter Avatar" show_in_antagpanel = FALSE show_name_in_check_antagonists = TRUE - hijack_speed = 2 //You literally are here to do nothing else. Might as well be fast about it. suicide_cry = "HAHAHAHAHA!!" /datum/antagonist/wishgranter/proc/forge_objectives() - var/datum/objective/hijack/hijack = new - hijack.owner = owner - objectives += hijack + CRASH("Tried to forge wishgranter objective.") /datum/antagonist/wishgranter/on_gain() owner.special_role = "Avatar of the Wish Granter" diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm index 354986b7a3ee..d85e6a53aa2a 100644 --- a/code/modules/antagonists/wizard/wizard.dm +++ b/code/modules/antagonists/wizard/wizard.dm @@ -7,7 +7,6 @@ GLOBAL_LIST_EMPTY(wizard_spellbook_purchases_by_key) antagpanel_category = "Wizard" job_rank = ROLE_WIZARD antag_hud_name = "wizard" - hijack_speed = 0.5 ui_name = "AntagInfoWizard" suicide_cry = "FOR THE FEDERATION!!" preview_outfit = /datum/outfit/wizard diff --git a/code/modules/credits_roll/episode_name.dm b/code/modules/credits_roll/episode_name.dm index 42a85dae13e0..184353cc7bba 100644 --- a/code/modules/credits_roll/episode_name.dm +++ b/code/modules/credits_roll/episode_name.dm @@ -155,12 +155,12 @@ episode_names += new /datum/episode_name/rare("[pick("WHERE NO DOG HAS GONE BEFORE", "IAN SAYS", "IAN'S DAY OUT", "EVERY DOG HAS ITS DAY", "THE ONE WITH THE MAGIC PUPPY")]", "You know what you did.", 1000) break - if(!EMERGENCY_ESCAPED_OR_ENDGAMED) + if(!SSevacuation.station_evacuated()) return var/dead = GLOB.joined_player_list.len - SSticker.popcount[POPCOUNT_ESCAPEES] var/escaped = SSticker.popcount[POPCOUNT_ESCAPEES] - var/escaped_on_shuttle = SSticker.popcount[POPCOUNT_SHUTTLE_ESCAPEES] + var/escaped_on_shuttle = SSticker.popcount[POPCOUNT_EVAC_ESCAPEES] var/human_escapees = SSticker.popcount[POPCOUNT_ESCAPEES_HUMANONLY] if((REALTIMEOFDAY - SSticker.round_start_timeofday) < 20 MINUTES) //shuttle docked in less than 16 minutes!! episode_names += new /datum/episode_name/rare("[pick("THE CAPTAIN STUBS THEIR TOE", "QUICK GETAWAY", "A MOST EFFICIENT APOCALYPSE", "THE CREW'S [round((REALTIMEOFDAY - SSticker.round_start_timeofday)/60)] MINUTES OF FAME", "ON SECOND THOUGHT, LET'S NOT GO TO [uppr_name]. 'TIS A SILLY PLACE.")]", "This round was about as short as they come.", 750) @@ -168,7 +168,7 @@ episode_names += new /datum/episode_name/rare("DRY RUN", "This round was as short as they come, and there were no escapees.", 2500) if(dead == 0) episode_names += new /datum/episode_name/rare("[pick("EMPLOYEE TRANSFER", "LIVE LONG AND PROSPER", "PEACE AND QUIET IN [uppr_name]", "THE ONE WITHOUT ALL THE FIGHTING", "THE CREW TRIES TO KILL A FLY FOR [round((REALTIMEOFDAY - SSticker.round_start_timeofday)/60)] MINUTES")]", "No-one died this round.", 2500) //in practice, this one is very very very rare, so if it happens let's pick it more often - if(escaped == 0 || SSshuttle.emergency.is_hijacked()) + if(escaped == 0) episode_names += new /datum/episode_name("[pick("DEAD SPACE", "THE CREW GOES MISSING", "LOST IN TRANSLATION", "[uppr_name]: DELETED SCENES", "WHAT HAPPENS IN [uppr_name], STAYS IN [uppr_name]", "MISSING IN ACTION", "SCOOBY-DOO, WHERE'S THE CREW?")]", "There were no escapees on the shuttle.", 300) if(escaped < 6 && escaped > 0 && dead > escaped*2) episode_names += new /datum/episode_name("[pick("AND THEN THERE WERE FEWER", "THE 'FUN' IN 'FUNERAL'", "FREEDOM RIDE OR DIE", "THINGS WE LOST IN [uppr_name]", "GONE WITH [uppr_name]", "LAST TANGO IN [uppr_name]", "GET BUSY LIVING OR GET BUSY DYING", "THE CREW FUCKING DIES", "WISH YOU WERE HERE")]", "[dead] people died this round.", 400) @@ -224,8 +224,6 @@ if(voxcount / human_escapees > 0.6 && human_escapees > 2) episode_names += new /datum/episode_name/rare("BIRDS OF A FEATHER...", "Most of the survivors were Vox.", min(1500, voxcount*250)) - if(voxcount / human_escapees > 0.6 && SSshuttle.emergency.launch_status == EARLY_LAUNCHED) - episode_names += new /datum/episode_name/rare("EARLY BIRD GETS THE WORM", "Most or all of the survivors were Vox, and the shuttle timer was shortened.", 1500) //if(voxcount / human_escapees.len > 0.6 && score.shuttlebombed > 3) // episode_names += new /datum/episode_name/rare("SITTING DUCKS", "Most or all of the survivors were Vox, and the shuttle was bombed.", min(1500,score.shuttlebombed*3)) if(baldycount / human_escapees> 0.6 && human_escapees > 3) diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index 79cef6d02464..090b8bc7309a 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -49,7 +49,7 @@ return FALSE if(holidayID && (!SSevents.holidays || !SSevents.holidays[holidayID])) return FALSE - if(EMERGENCY_ESCAPED_OR_ENDGAMED) + if(SSticker.current_state >= GAME_STATE_FINISHED) return FALSE if(ispath(typepath, /datum/round_event/ghost_role) && !(GLOB.ghost_role_flags & GHOSTROLE_MIDROUND_EVENT)) return FALSE diff --git a/code/modules/events/blob.dm b/code/modules/events/blob.dm index 0407353399cb..b9f88d0d7c85 100644 --- a/code/modules/events/blob.dm +++ b/code/modules/events/blob.dm @@ -9,7 +9,7 @@ dynamic_should_hijack = TRUE /datum/round_event_control/blob/canSpawnEvent(players) - if(EMERGENCY_PAST_POINT_OF_NO_RETURN) // no blobs if the shuttle is past the point of no return + if(SSevacuation.station_evacuated()) // no blobs if the shuttle is past the point of no return return FALSE return ..() diff --git a/code/modules/events/shuttle_catastrophe.dm b/code/modules/events/shuttle_catastrophe.dm deleted file mode 100644 index cc14d6c25054..000000000000 --- a/code/modules/events/shuttle_catastrophe.dm +++ /dev/null @@ -1,53 +0,0 @@ -/datum/round_event_control/shuttle_catastrophe - name = "Shuttle Catastrophe" - typepath = /datum/round_event/shuttle_catastrophe - weight = 10 - max_occurrences = 1 - -/datum/round_event_control/shuttle_catastrophe/canSpawnEvent(players) - if(SSshuttle.shuttle_purchased == SHUTTLEPURCHASE_FORCED) - return FALSE //don't do it if its already been done - if(istype(SSshuttle.emergency, /obj/docking_port/mobile/emergency/shuttle_build)) - return FALSE //don't undo manual player engineering, it also would unload people and ghost them, there's just a lot of problems - if(EMERGENCY_AT_LEAST_DOCKED) - return FALSE //don't remove all players when its already on station or going to centcom - return ..() - - -/datum/round_event/shuttle_catastrophe - var/datum/map_template/shuttle/new_shuttle - -/datum/round_event/shuttle_catastrophe/announce(fake) - var/cause = pick("was attacked by [syndicate_name()] Operatives", "mysteriously teleported away", "had its refuelling crew mutiny", - "was found with its engines stolen", "\[REDACTED\]", "flew into the sunset, and melted", "learned something from a very wise cow, and left on its own", - "had cloning devices on it", "had its shuttle inspector put the shuttle in reverse instead of park, causing the shuttle to crash into the hangar") - var/message = "Your emergency shuttle [cause]. " - - if(SSshuttle.shuttle_insurance) - message += "Luckily, your shuttle insurance has covered the costs of repair!" - if(SSeconomy.department_accounts_by_id[ACCOUNT_CAR]) - message += " You have been awarded a bonus from [command_name()] for smart spending." - else - message += "Your replacement shuttle will be the [new_shuttle.name] until further notice." - priority_announce(message, "[command_name()] Spacecraft Engineering") - -/datum/round_event/shuttle_catastrophe/setup() - if(SSshuttle.shuttle_insurance) - return - var/list/valid_shuttle_templates = list() - for(var/shuttle_id in SSmapping.shuttle_templates) - var/datum/map_template/shuttle/template = SSmapping.shuttle_templates[shuttle_id] - if(!isnull(template.who_can_purchase) && template.credit_cost < INFINITY) //if we could get it from the communications console, it's cool for us to get it here - valid_shuttle_templates += template - new_shuttle = pick(valid_shuttle_templates) - -/datum/round_event/shuttle_catastrophe/start() - if(SSshuttle.shuttle_insurance) - var/datum/bank_account/station_balance = SSeconomy.department_accounts_by_id[ACCOUNT_CAR] - station_balance?.adjust_money(8000) - return - SSshuttle.shuttle_purchased = SHUTTLEPURCHASE_FORCED - SSshuttle.unload_preview() - SSshuttle.existing_shuttle = SSshuttle.emergency - SSshuttle.action_load(new_shuttle, replace = TRUE) - log_shuttle("Shuttle Catastrophe set a new shuttle, [new_shuttle.name].") diff --git a/code/modules/events/shuttle_insurance.dm b/code/modules/events/shuttle_insurance.dm deleted file mode 100644 index d16638d69a57..000000000000 --- a/code/modules/events/shuttle_insurance.dm +++ /dev/null @@ -1,50 +0,0 @@ - - -/datum/round_event_control/shuttle_insurance - name = "Shuttle Insurance" - typepath = /datum/round_event/shuttle_insurance - max_occurrences = 1 - -/datum/round_event_control/shuttle_insurance/canSpawnEvent(players) - if(!SSeconomy.department_accounts_by_id[ACCOUNT_CAR]) - return FALSE //They can't pay? - if(SSshuttle.shuttle_purchased == SHUTTLEPURCHASE_FORCED) - return FALSE //don't do it if there's nothing to insure - if(EMERGENCY_AT_LEAST_DOCKED) - return FALSE //catastrophes won't trigger so no point - return ..() - -/datum/round_event/shuttle_insurance - var/ship_name = "\"In the Unlikely Event\"" - var/datum/comm_message/insurance_message - var/insurance_evaluation = 0 - -/datum/round_event/shuttle_insurance/announce(fake) - priority_announce("Incoming long range communication. Secure channel opened at all communication consoles.", sound_type = ANNOUNCER_CENTCOM) - -/datum/round_event/shuttle_insurance/setup() - ship_name = pick(strings(PIRATE_NAMES_FILE, "rogue_names")) - for(var/shuttle_id in SSmapping.shuttle_templates) - var/datum/map_template/shuttle/template = SSmapping.shuttle_templates[shuttle_id] - if(template.name == SSshuttle.emergency.name) //found you slackin - insurance_evaluation = template.credit_cost/2 - break - if(!insurance_evaluation) - insurance_evaluation = 5000 //gee i dunno - -/datum/round_event/shuttle_insurance/start() - insurance_message = new("Shuttle Insurance", "Hey, pal, this is the [ship_name]. Can't help but notice you're rocking a wild and crazy shuttle there with NO INSURANCE! Crazy. What if something happened to it, huh?! We've done a quick evaluation on your rates in this sector and we're offering [insurance_evaluation] to cover for your shuttle in case of any disaster.", list("Purchase Insurance.","Reject Offer.")) - insurance_message.answer_callback = CALLBACK(src,PROC_REF(answered)) - SScommunications.send_message(insurance_message, unique = TRUE) - -/datum/round_event/shuttle_insurance/proc/answered() - if(EMERGENCY_AT_LEAST_DOCKED) - priority_announce("You are definitely too late to purchase insurance, my friends. Our agents don't work on site.", ship_name) - return - if(insurance_message && insurance_message.answered == 1) - var/datum/bank_account/station_balance = SSeconomy.department_accounts_by_id[ACCOUNT_CAR] - if(!station_balance?.adjust_money(-insurance_evaluation)) - priority_announce("You didn't send us enough money for shuttle insurance. This, in the space layman's terms, is considered scamming. We're keeping your money, scammers!", ship_name) - return - priority_announce("Thank you for purchasing shuttle insurance!", ship_name) - SSshuttle.shuttle_insurance = TRUE diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 545938c2280d..c0c1554d031f 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -375,13 +375,8 @@ GLOB.joined_player_list += character.ckey if(CONFIG_GET(flag/allow_latejoin_antagonists) && humanc) //Borgs aren't allowed to be antags. Will need to be tweaked if we get true latejoin ais. - if(SSshuttle.emergency) - switch(SSshuttle.emergency.mode) - if(SHUTTLE_RECALL, SHUTTLE_IDLE) - SSticker.mode.make_antag_chance(humanc) - if(SHUTTLE_CALL) - if(SSshuttle.emergency.timeLeft(1) > initial(SSshuttle.emergency_call_time)*0.5) - SSticker.mode.make_antag_chance(humanc) + if(SSevacuation.evacuation_can_be_cancelled()) + SSticker.mode.make_antag_chance(humanc) if((job.job_flags & JOB_ASSIGN_QUIRKS) && humanc && CONFIG_GET(flag/roundstart_traits)) SSquirks.AssignQuirks(humanc, humanc.client) @@ -404,13 +399,10 @@ if(SSlag_switch.measures[DISABLE_NON_OBSJOBS]) dat += "
Only Observers may join at this time.

" dat += "
Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]
" - if(SSshuttle.emergency) - switch(SSshuttle.emergency.mode) - if(SHUTTLE_ESCAPE) - dat += "
The station has been evacuated.

" - if(SHUTTLE_CALL) - if(!SSshuttle.canRecall()) - dat += "
The station is currently undergoing evacuation procedures.

" + if(SSevacuation.evacuation_in_progress()) + dat += "
The station is currently undergoing evacuation procedures.

" + else if(SSevacuation.station_evacuated()) + dat += "
The station has been evacuated.

" for(var/datum/job/prioritized_job in SSjob.prioritized_jobs) if(prioritized_job.current_positions >= prioritized_job.total_positions) SSjob.prioritized_jobs -= prioritized_job diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 0fb6bcc5f84a..127df11d2a16 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -217,7 +217,7 @@ /mob/living/silicon/ai/Destroy() GLOB.ai_list -= src UNSET_TRACKING(TRACKING_KEY_SHUTTLE_CALLER) - SSshuttle.autoEvac() + SSevacuation.trigger_auto_evac(EVACUATION_REASON_AI_DESTROYED) QDEL_NULL(eyeobj) // No AI, no Eye QDEL_NULL(spark_system) QDEL_NULL(malf_picker) @@ -306,29 +306,29 @@ Model: [connected_robot.designation] | Loc: [get_area_name(connected_robot, TRUE)] | Status: [robot_status]" . += "AI shell beacons detected: [LAZYLEN(GLOB.available_ai_shells)]" //Count of total AI shells -/mob/living/silicon/ai/proc/ai_call_shuttle() +/mob/living/silicon/ai/proc/ai_start_evacuation() if(control_disabled) to_chat(usr, span_warning("Wireless control is disabled!")) return - var/can_evac_or_fail_reason = SSshuttle.canEvac(src) + var/list/evacuation_means = SSevacuation.get_controllers_list_ai() + var/identifier = tgui_input_list(src, "Choose means of evacuation", "Evacuation", evacuation_means) + + var/can_evac_or_fail_reason = SSevacuation.can_evac(src, identifier) if(can_evac_or_fail_reason != TRUE) to_chat(usr, span_alert("[can_evac_or_fail_reason]")) return - var/reason = tgui_input_text(src, "What is the nature of your emergency? ([CALL_SHUTTLE_REASON_LENGTH] characters required.)", "Confirm Shuttle Call") + var/reason = tgui_input_text(src, "What is the nature of your emergency? ([EVAC_REASON_LENGTH] characters required.)", "Confirm Shuttle Call") if(incapacitated()) return - if(trim(reason)) - SSshuttle.requestEvac(src, reason) - - // hack to display shuttle timer - if(!EMERGENCY_IDLE_OR_RECALLED) - var/obj/machinery/computer/communications/C = locate() in INSTANCES_OF(/obj/machinery/computer/communications) - if(C) - C.post_status("shuttle") + if(length(trim(reason)) >= EVAC_REASON_LENGTH) + if(SSevacuation.request_evacuation(src, reason, identifier)) + var/obj/machinery/computer/communications/C = locate() in INSTANCES_OF(/obj/machinery/computer/communications) + if(C) + C.post_status("shuttle") /mob/living/silicon/ai/can_interact_with(atom/A) . = ..() diff --git a/code/modules/mob/living/silicon/ai/ai_defense.dm b/code/modules/mob/living/silicon/ai/ai_defense.dm index 54c63bba2e40..aa3fc218af1c 100644 --- a/code/modules/mob/living/silicon/ai/ai_defense.dm +++ b/code/modules/mob/living/silicon/ai/ai_defense.dm @@ -37,7 +37,12 @@ if(1) view_core() if(2) - SSshuttle.requestEvac(src,"ALERT: Energy surge detected in AI core! Station integrity may be compromised! Initiati--%m091#ar-BZZT") + SSevacuation.request_evacuation(src, + "ALERT: Energy surge detected in AI core! \ + Station integrity may be compromised! Initiati--%m091#ar-BZZT", + // I don't like it calls a single controlelr, but spam isn't cool either + pick(SSevacuation.controllers) + ) /mob/living/silicon/ai/ex_act(severity, target) switch(severity) diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index f6b2368a37a8..a578843dbeac 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -29,9 +29,8 @@ eyeobj.setLoc(get_turf(src)) set_eyeobj_visible(FALSE) - UNSET_TRACKING(TRACKING_KEY_SHUTTLE_CALLER) - SSshuttle.autoEvac() + SSevacuation.trigger_auto_evac(EVACUATION_REASON_AI_DESTROYED) ShutOffDoomsdayDevice() diff --git a/code/modules/mob/living/simple_animal/hostile/space_dragon.dm b/code/modules/mob/living/simple_animal/hostile/space_dragon.dm index 04bb989f94a7..1dd9bbe2fd32 100644 --- a/code/modules/mob/living/simple_animal/hostile/space_dragon.dm +++ b/code/modules/mob/living/simple_animal/hostile/space_dragon.dm @@ -126,7 +126,7 @@ consumed_mob.Paralyze(50) if(!mind.has_antag_datum(/datum/antagonist/space_dragon)) return - if((rifts_charged == 3 || (SSshuttle.emergency.mode == SHUTTLE_DOCKED && rifts_charged > 0)) && !objective_complete) + if(rifts_charged == 3 && !objective_complete) victory() if(riftTimer == -1) return diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm index aedb9eddac50..e606432c41e6 100644 --- a/code/modules/power/singularity/narsie.dm +++ b/code/modules/power/singularity/narsie.dm @@ -239,7 +239,7 @@ ///security level and shuttle lockdowns for [/proc/begin_the_end()] /proc/narsie_start_destroy_station() set_security_level("delta") - SSshuttle.registerHostileEnvironment(GLOB.cult_narsie) + SSevacuation.add_evacuation_blocker(GLOB.cult_narsie) SSshuttle.lockdown = TRUE addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(narsie_apocalypse)), 1 MINUTES) @@ -247,7 +247,7 @@ /proc/narsie_apocalypse() if(QDELETED(GLOB.cult_narsie)) // tres priority_announce("Normalization detected! Abort the solution package!","Ananke Research Higher Dimensional Affairs", sound_type = 'sound/misc/notice1.ogg') - SSshuttle.clearHostileEnvironment(GLOB.cult_narsie) + SSevacuation.remove_evacuation_blocker(GLOB.cult_narsie) GLOB.cult_narsie = null addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(narsie_last_second_win)), 2 SECONDS) return diff --git a/code/modules/security_levels/security_levels.dm b/code/modules/security_levels/security_levels.dm index 2d2cff94b751..7db5b8e67ae1 100644 --- a/code/modules/security_levels/security_levels.dm +++ b/code/modules/security_levels/security_levels.dm @@ -15,45 +15,21 @@ if(SEC_LEVEL_GREEN) priority_announce(CONFIG_GET(string/alert_green), sub_title = "Security level lowered to green.", do_not_modify = TRUE) - if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) - if(SSsecurity_level.current_level >= SEC_LEVEL_RED) - SSshuttle.emergency.modTimer(4) - else - SSshuttle.emergency.modTimer(2) - if(SEC_LEVEL_BLUE) if(SSsecurity_level.current_level < SEC_LEVEL_BLUE) priority_announce(CONFIG_GET(string/alert_blue_upto), sub_title = "Security level elevated to blue.", do_not_modify = TRUE, sound_type = ANNOUNCER_ALERT) - - if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) - SSshuttle.emergency.modTimer(0.5) - else priority_announce(CONFIG_GET(string/alert_blue_downto), sub_title = "Security level lowered to blue.", do_not_modify = TRUE, sound_type = ANNOUNCER_ALERT) - if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) - SSshuttle.emergency.modTimer(2) if(SEC_LEVEL_RED) if(SSsecurity_level.current_level < SEC_LEVEL_RED) priority_announce(CONFIG_GET(string/alert_red_upto), sub_title = "Security level elevated to red.", do_not_modify = TRUE, sound_type = ANNOUNCER_ALERT) - - if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) - if(SSsecurity_level.current_level == SEC_LEVEL_GREEN) - SSshuttle.emergency.modTimer(0.25) - else - SSshuttle.emergency.modTimer(0.5) else priority_announce(CONFIG_GET(string/alert_red_upto), sub_title = "Security level lowered to red.", do_not_modify = TRUE, sound_type = ANNOUNCER_ALERT) if(SEC_LEVEL_DELTA) priority_announce(CONFIG_GET(string/alert_delta), sub_title = "Security level elevated to delta.", do_not_modify = TRUE, sound_type = ANNOUNCER_ALERT) - if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) - if(SSsecurity_level.current_level == SEC_LEVEL_GREEN) - SSshuttle.emergency.modTimer(0.25) - else if(SSsecurity_level.current_level == SEC_LEVEL_BLUE) - SSshuttle.emergency.modTimer(0.5) - SSsecurity_level.set_level(level) /proc/get_security_level() diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index 55f492e98967..35ee78f97200 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -4,39 +4,23 @@ #define IS_DOCKED (SSshuttle.emergency.mode == SHUTTLE_DOCKED || (ENGINES_STARTED)) #define SHUTTLE_CONSOLE_ACTION_DELAY (5 SECONDS) -#define NOT_BEGUN 0 -#define STAGE_1 1 -#define STAGE_2 2 -#define STAGE_3 3 -#define STAGE_4 4 -#define HIJACKED 5 - /obj/machinery/computer/emergency_shuttle name = "emergency shuttle console" desc = "For shuttle control." icon_screen = "shuttle" icon_keyboard = "tech_key" resistance_flags = INDESTRUCTIBLE + var/shuttle_id var/auth_need = 3 var/list/authorized = list() var/list/acted_recently = list() - var/hijack_last_stage_increase = 0 SECONDS - var/hijack_stage_time = 5 SECONDS - var/hijack_stage_cooldown = 5 SECONDS - var/hijack_flight_time_increase = 30 SECONDS - var/hijack_completion_flight_time_set = 10 SECONDS //How long in deciseconds to set shuttle's timer after hijack is done. - var/hijack_hacking = FALSE - var/hijack_announce = TRUE - -/obj/machinery/computer/emergency_shuttle/examine(mob/user) - . = ..() - if(hijack_announce) - . += span_danger("Security systems present on console. Any unauthorized tampering will result in an emergency announcement.") - if(user?.mind?.get_hijack_speed()) - . += span_danger("Alt click on this to attempt to hijack the shuttle. This will take multiple tries (current: stage [SSshuttle.emergency.hijack_status]/[HIJACKED]).") - . += span_notice("It will take you [(hijack_stage_time * user.mind.get_hijack_speed()) / 10] seconds to reprogram a stage of the shuttle's navigational firmware, and the console will undergo automated timed lockout for [hijack_stage_cooldown/10] seconds after each stage.") - if(hijack_announce) - . += span_warning("It is probably best to fortify your position as to be uninterrupted during the attempt, given the automatic announcements..") + +/obj/machinery/computer/emergency_shuttle/Initialize(mapload, obj/item/circuitboard/C) + .=..() + var/obj/docking_port/mobile/port = SSshuttle.get_containing_shuttle(src) + if(!port) + return INITIALIZE_HINT_QDEL + shuttle_id = port.id /obj/machinery/computer/emergency_shuttle/attackby(obj/item/I, mob/user,params) if(istype(I, /obj/item/card/id)) @@ -54,10 +38,11 @@ ui.open() /obj/machinery/computer/emergency_shuttle/ui_data(user) + var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttle_id) var/list/data = list() - data["timer_str"] = SSshuttle.emergency.getTimerStr() - data["engines_started"] = ENGINES_STARTED + data["timer_str"] = M.getTimerStr() + data["engines_started"] = M.mode == SHUTTLE_IGNITING data["authorizations_remaining"] = max((auth_need - authorized.len), 0) var/list/A = list() for(var/i in authorized) @@ -71,7 +56,7 @@ A += list(list("name" = name, "job" = job)) data["authorizations"] = A - data["enabled"] = (IS_DOCKED && !ENGINES_STARTED) && !(user in acted_recently) + data["enabled"] = (M.mode == SHUTTLE_DOCKED) && !(user in acted_recently) data["emagged"] = obj_flags & EMAGGED ? 1 : 0 return data @@ -79,11 +64,10 @@ . = ..() if(.) return - if(ENGINES_STARTED) // past the point of no return + if(!shuttle_id) return - if(!IS_DOCKED) // shuttle computer only has uses when onstation - return - if(SSshuttle.emergency.mode == SHUTTLE_DISABLED) // admins have disabled the shuttle. + var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttle_id) + if(M.mode != SHUTTLE_DOCKED) // shuttle computer only has uses when onstation return if(!isliving(usr)) return @@ -121,7 +105,7 @@ authorized.Cut() . = TRUE - if((old_len != authorized.len) && !ENGINES_STARTED) + if((old_len != authorized.len) && M.mode != SHUTTLE_IGNITING) var/alert = (authorized.len > old_len) var/repeal = (authorized.len < old_len) var/remaining = max(0, auth_need - authorized.len) @@ -146,7 +130,7 @@ authorized += ID message_admins("[ADMIN_LOOKUPFLW(user)] has authorized early shuttle launch") - log_shuttle("[key_name(user)] has authorized early shuttle launch in [COORD(src)]") + log_evacuation("[key_name(user)] has authorized early shuttle launch in [COORD(src)]") // Now check if we're on our way . = TRUE process(SSMACHINES_DT) @@ -160,110 +144,39 @@ // Launch check is in process in case auth_need changes for some reason // probably external. . = FALSE - if(!SSshuttle.emergency) - return - - if(SSshuttle.emergency.mode == SHUTTLE_STRANDED) + var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttle_id) + if(M.mode == SHUTTLE_STRANDED) authorized.Cut() obj_flags &= ~(EMAGGED) - if(ENGINES_STARTED || (!IS_DOCKED)) + if(M.mode != SHUTTLE_DOCKED) return . // Check to see if we've reached criteria for early launch if((authorized.len >= auth_need) || (obj_flags & EMAGGED)) // shuttle timers use 1/10th seconds internally - SSshuttle.emergency.setTimer(ENGINES_START_TIME) + M.setTimer(ENGINES_START_TIME) var/system_error = obj_flags & EMAGGED ? "SYSTEM ERROR:" : null minor_announce("The emergency shuttle will launch in \ - [TIME_LEFT] seconds", system_error, alert=TRUE) + [M.timeLeft()] seconds", system_error, alert=TRUE) . = TRUE -/obj/machinery/computer/emergency_shuttle/proc/increase_hijack_stage() - var/obj/docking_port/mobile/emergency/shuttle = SSshuttle.emergency - shuttle.hijack_status++ - if(hijack_announce) - announce_hijack_stage() - hijack_last_stage_increase = world.time - say("Navigational protocol error! Rebooting systems.") - if(shuttle.mode == SHUTTLE_ESCAPE) - if(shuttle.hijack_status == HIJACKED) - shuttle.setTimer(hijack_completion_flight_time_set) - else - shuttle.setTimer(shuttle.timeLeft(1) + hijack_flight_time_increase) //give the guy more time to hijack if it's already in flight. - return shuttle.hijack_status - -/obj/machinery/computer/emergency_shuttle/AltClick(user) - if(isliving(user)) - attempt_hijack_stage(user) - -/obj/machinery/computer/emergency_shuttle/proc/attempt_hijack_stage(mob/living/user) - if(!user.CanReach(src)) - return - if(!user?.mind?.get_hijack_speed()) - to_chat(user, span_warning("You manage to open a user-mode shell on [src], and hundreds of lines of debugging output fly through your vision. It is probably best to leave this alone.")) - return - if(!EMERGENCY_AT_LEAST_DOCKED) // prevent advancing hijack stages on BYOS shuttles until the shuttle has "docked" - to_chat(user, span_warning("The flight plans for the shuttle haven't been loaded yet, you can't hack this right now.")) - return - if(hijack_hacking == TRUE) - return - if(SSshuttle.emergency.hijack_status >= HIJACKED) - to_chat(user, span_warning("The emergency shuttle is already loaded with a corrupt navigational payload. What more do you want from it?")) - return - if(hijack_last_stage_increase >= world.time + hijack_stage_cooldown) - say("Error - Catastrophic software error detected. Input is currently on timeout.") - return - hijack_hacking = TRUE - to_chat(user, span_boldwarning("You [SSshuttle.emergency.hijack_status == NOT_BEGUN? "begin" : "continue"] to override [src]'s navigational protocols.")) - say("Software override initiated.") - var/turf/console_hijack_turf = get_turf(src) - message_admins("[src] is being overriden for hijack by [ADMIN_LOOKUPFLW(user)] in [ADMIN_VERBOSEJMP(console_hijack_turf)]") - log_game("[src] is being overriden for hijack by [key_name(user)] at [AREACOORD(src)]") - . = FALSE - if(do_after(user, hijack_stage_time * (1 / user.mind.get_hijack_speed()), target = src)) - increase_hijack_stage() - console_hijack_turf = get_turf(src) - message_admins("[src] has had its hijack stage increased to stage [SSshuttle.emergency.hijack_status] out of [HIJACKED] by [ADMIN_LOOKUPFLW(user)] in [ADMIN_VERBOSEJMP(console_hijack_turf)]") - log_game("[src] has had its hijack stage increased to stage [SSshuttle.emergency.hijack_status] out of [HIJACKED] by [key_name(user)] at [AREACOORD(src)]") - . = TRUE - to_chat(user, span_notice("You reprogram some of [src]'s programming, putting it on timeout for [hijack_stage_cooldown/10] seconds.")) - hijack_hacking = FALSE - -/obj/machinery/computer/emergency_shuttle/proc/announce_hijack_stage() - var/msg - switch(SSshuttle.emergency.hijack_status) - if(NOT_BEGUN) - return - if(STAGE_1) - msg = "AUTHENTICATING - FAIL. AUTHENTICATING - FAIL. AUTHENTICATING - FAI###### Welcome, technician JOHN DOE." - if(STAGE_2) - msg = "Warning: Navigational route fails \"IS_AUTHORIZED\". Please try againNN[scramble_message_replace_chars("againagainagainagainagain", 70)]." - if(STAGE_3) - msg = "CRC mismatch at ~h~ in calculated route buffer. Full reset initiated of FTL_NAVIGATION_SERVICES. Memory decrypted for automatic repair." - if(STAGE_4) - msg = "~ACS_directive module_load(cyberdyne.exploit.nanotrasen.shuttlenav)... NT key mismatch. Confirm load? Y...###Reboot complete. $SET transponder_state = 0; System link initiated with connected engines..." - if(HIJACKED) - msg = "SYSTEM OVERRIDE - Resetting course to \[[scramble_message_replace_chars("###########", 100)]\] \ - ([scramble_message_replace_chars("#######", 100)]/[scramble_message_replace_chars("#######", 100)]/[scramble_message_replace_chars("#######", 100)]) \ - {AUTH - ROOT (uid: 0)}.[SSshuttle.emergency.mode == SHUTTLE_ESCAPE ? "Diverting from existing route - Bluespace exit in [hijack_completion_flight_time_set/10] seconds." : ""]" - minor_announce(scramble_message_replace_chars(msg, replaceprob = 10), "Emergency Shuttle", TRUE) - /obj/machinery/computer/emergency_shuttle/emag_act(mob/user) // How did you even get on the shuttle before it go to the station? - if(!IS_DOCKED) + var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttle_id) + if(M.mode != SHUTTLE_DOCKED) return - if((obj_flags & EMAGGED) || ENGINES_STARTED) //SYSTEM ERROR: THE SHUTTLE WILL LA-SYSTEM ERROR: THE SHUTTLE WILL LA-SYSTEM ERROR: THE SHUTTLE WILL LAUNCH IN 10 SECONDS + if((obj_flags & EMAGGED) || M.mode == SHUTTLE_IGNITING) //SYSTEM ERROR: THE SHUTTLE WILL LA-SYSTEM ERROR: THE SHUTTLE WILL LA-SYSTEM ERROR: THE SHUTTLE WILL LAUNCH IN 10 SECONDS to_chat(user, span_warning("The shuttle is already about to launch!")) return - var/time = TIME_LEFT + var/time = M.timeLeft() message_admins("[ADMIN_LOOKUPFLW(user)] has emagged the emergency shuttle [time] seconds before launch.") log_shuttle("[key_name(user)] has emagged the emergency shuttle in [COORD(src)] [time] seconds before launch.") obj_flags |= EMAGGED - SSshuttle.emergency.movement_force = list("KNOCKDOWN" = 60, "THROW" = 20)//YOUR PUNY SEATBELTS can SAVE YOU NOW, MORTAL + M.movement_force = list("KNOCKDOWN" = 60, "THROW" = 20)//YOUR PUNY SEATBELTS can SAVE YOU NOW, MORTAL var/datum/species/S = new for(var/i in 1 to 10) // the shuttle system doesn't know who these people are, but they @@ -299,117 +212,33 @@ dir = EAST port_direction = WEST var/sound_played = 0 //If the launch sound has been sent to all players on the shuttle itself - var/hijack_status = NOT_BEGUN + //Set by the evacuation controller + var/call_time + var/escape_time + var/dock_time /obj/docking_port/mobile/emergency/canDock(obj/docking_port/stationary/S) return SHUTTLE_CAN_DOCK //If the emergency shuttle can't move, the whole game breaks, so it will force itself to land even if it has to crush a few departments in the process /obj/docking_port/mobile/emergency/register() . = ..() - SSshuttle.emergency = src - -/obj/docking_port/mobile/emergency/Destroy(force) - if(force) - // This'll make the shuttle subsystem use the backup shuttle. - if(src == SSshuttle.emergency) - // If we're the selected emergency shuttle - SSshuttle.emergencyDeregister() - - . = ..() + GLOB.emergency_shuttle = src -///obj/docking_port/mobile/emergency/request(obj/docking_port/stationary/S, area/signalOrigin, reason, redAlert, set_coefficient=null) //ORIGINAL -/obj/docking_port/mobile/emergency/request(obj/docking_port/stationary/S, area/signalOrigin, reason, redAlert, set_coefficient=null, silent=FALSE) //PARIAH EDIT CHANGE - AUTOTRANSFER - if(!isnum(set_coefficient)) - var/security_num = seclevel2num(get_security_level()) - switch(security_num) - if(SEC_LEVEL_GREEN) - set_coefficient = 1 - else - set_coefficient = 0.5 - - var/call_time = SSshuttle.emergency_call_time * set_coefficient * engine_coeff +/obj/docking_port/mobile/emergency/request(obj/docking_port/stationary/S) switch(mode) // The shuttle can not normally be called while "recalling", so // if this proc is called, it's via admin fiat if(SHUTTLE_RECALL, SHUTTLE_IDLE, SHUTTLE_CALL) mode = SHUTTLE_CALL - setTimer(call_time) - else - return - - SSshuttle.emergencyCallAmount++ - - if(prob(70)) - SSshuttle.emergency_last_call_loc = signalOrigin - else - SSshuttle.emergency_last_call_loc = null - - if(!silent) - priority_announce("The emergency shuttle has been called. [redAlert ? "Red Alert state confirmed: Dispatching priority shuttle. " : "" ]It will arrive in [timeLeft(600)] minutes.[reason][SSshuttle.emergency_last_call_loc ? "\n\nCall signal traced. Results can be viewed on any communications console." : "" ][SSshuttle.admin_emergency_no_recall ? "\n\nWarning: Shuttle recall subroutines disabled; Recall not possible." : ""]", FLAVOR_CENTCOM_NAME, sound_type = ANNOUNCER_SHUTTLECALLED) + setTimer(call_time * engine_coeff) -/obj/docking_port/mobile/emergency/cancel(area/signalOrigin) +/obj/docking_port/mobile/emergency/cancel() if(mode != SHUTTLE_CALL) return - if(SSshuttle.emergency_no_recall) - return invertTimer() mode = SHUTTLE_RECALL - if(prob(70)) - SSshuttle.emergency_last_call_loc = signalOrigin - else - SSshuttle.emergency_last_call_loc = null - priority_announce("The emergency shuttle has been recalled.[SSshuttle.emergency_last_call_loc ? " Recall signal traced. Results can be viewed on any communications console." : "" ]", FLAVOR_CENTCOM_NAME, sound_type = ANNOUNCER_SHUTTLERECALLED) - - SSticker.emergency_reason = null - -/** - * Proc that handles checking if the emergency shuttle was successfully hijacked via being the only people present on the shuttle for the elimination hijack or highlander objective - * - * Checks for all mobs on the shuttle, checks their status, and checks if they're - * borgs or simple animals. Depending on the args, certain mobs may be ignored, - * and the presence of other antags may or may not invalidate a hijack. - * Args: - * filter_by_human, default TRUE, tells the proc that only humans should block a hijack. Borgs and animals are ignored and will not block if this is TRUE. - * solo_hijack, default FALSE, tells the proc to fail with multiple hijackers, such as for Highlander mode. - */ -/obj/docking_port/mobile/emergency/proc/elimination_hijack(filter_by_human = TRUE, solo_hijack = FALSE) - var/has_people = FALSE - var/hijacker_count = 0 - for(var/mob/living/player in GLOB.player_list) - if(player.mind) - if(player.stat != DEAD) - if(issilicon(player) && filter_by_human) //Borgs are technically dead anyways - continue - if(isanimal(player) && filter_by_human) //animals don't count - continue - if(isbrain(player)) //also technically dead - continue - if(shuttle_areas[get_area(player)]) - has_people = TRUE - var/location = get_turf(player.mind.current) - //Non-antag present. Can't hijack. - if(!(player.mind.has_antag_datum(/datum/antagonist)) && !istype(location, /turf/open/floor/mineral/plastitanium/red/brig)) - return FALSE - //Antag present, doesn't stop but let's see if we actually want to hijack - var/prevent = FALSE - for(var/datum/antagonist/A in player.mind.antag_datums) - if(A.can_elimination_hijack == ELIMINATION_ENABLED) - hijacker_count += 1 - prevent = FALSE - break //If we have both prevent and hijacker antags assume we want to hijack. - else if(A.can_elimination_hijack == ELIMINATION_PREVENT) - prevent = TRUE - if(prevent) - return FALSE - - //has people AND either there's only one hijacker or there's any but solo_hijack is disabled - return has_people && ((hijacker_count == 1) || (hijacker_count && !solo_hijack)) - -/obj/docking_port/mobile/emergency/proc/is_hijacked() - return hijack_status == HIJACKED - /obj/docking_port/mobile/emergency/proc/ShuttleDBStuff() set waitfor = FALSE if(!SSdbcore.Connect()) @@ -447,17 +276,13 @@ setTimer(20) return mode = SHUTTLE_DOCKED - setTimer(SSshuttle.emergency_dock_time) - send2adminchat("Server", "The Emergency Shuttle has docked with the station.") - priority_announce("The Icarus has docked with the station. You have [timeLeft(600)] minutes to board before departure.", "LRSV Icarus Announcement", sound_type = ANNOUNCER_SHUTTLEDOCK) + setTimer(dock_time) + SEND_SIGNAL(src, COMSIG_EMERGENCYSHUTTLE_ARRIVAL) ShuttleDBStuff() if(SHUTTLE_DOCKED) if(time_left <= ENGINES_START_TIME) mode = SHUTTLE_IGNITING - SSshuttle.checkHostileEnvironment() - if(mode == SHUTTLE_STRANDED) - return for(var/A in SSshuttle.mobile_docking_ports) var/obj/docking_port/mobile/M = A if(M.launch_status == UNLAUNCHED) //Pods will not launch from the mine/planet, and other ships won't launch unless we tell them to. @@ -465,9 +290,6 @@ if(SHUTTLE_IGNITING) var/success = TRUE - SSshuttle.checkHostileEnvironment() - if(mode == SHUTTLE_STRANDED) - return success &= (check_transit_zone() == TRANSIT_READY) for(var/A in SSshuttle.mobile_docking_ports) @@ -479,13 +301,13 @@ if(time_left <= 50 && !sound_played) //4 seconds left:REV UP THOSE ENGINES BOYS. - should sync up with the launch sound_played = 1 //Only rev them up once. + SEND_SIGNAL(src, COMSIG_EMERGENCYSHUTTLE_ANNOUNCE) var/list/areas = list() for(var/area/shuttle/escape/E in GLOB.areas) areas += E - priority_announce("Engines spooling up. Prepare for resonance jump.", "LRSV Icarus Announcement", do_not_modify = TRUE) hyperspace_sound(HYPERSPACE_WARMUP, areas) - if(time_left <= 0 && !SSshuttle.emergency_no_escape) + if(time_left <= 0) //move each escape pod (or applicable spaceship) to its corresponding transit dock for(var/A in SSshuttle.mobile_docking_ports) var/obj/docking_port/mobile/M = A @@ -503,14 +325,8 @@ M.post_emergency_launch() if(prob(10)) SSuniverse.SetUniversalState(/datum/universal_state/resonance_jump, list(ZTRAIT_TRANSIT)) - setTimer(SSshuttle.emergency_escape_time * engine_coeff) - priority_announce("The Icarus has entered the resonance gate and is enroute to it's destination. Estimate [timeLeft(600)] minutes until the shuttle docks at Sector Control.", "LRSV Icarus Announcement") - INVOKE_ASYNC(SSticker, TYPE_PROC_REF(/datum/controller/subsystem/ticker, poll_hearts)) - SSmapping.mapvote() //If no map vote has been run yet, start one. - - if(SHUTTLE_STRANDED, SHUTTLE_DISABLED) - SSshuttle.checkHostileEnvironment() - + setTimer(escape_time * engine_coeff) + SEND_SIGNAL(src, COMSIG_EMERGENCYSHUTTLE_DEPARTING) if(SHUTTLE_ESCAPE) if(sound_played && time_left <= HYPERSPACE_END_TIME) @@ -535,20 +351,12 @@ if(time_left <= 0) //move each escape pod to its corresponding escape dock + SEND_SIGNAL(src, COMSIG_EMERGENCYSHUTTLE_RETURNED) for(var/A in SSshuttle.mobile_docking_ports) var/obj/docking_port/mobile/M = A M.on_emergency_dock() - // now move the actual emergency shuttle to centcom - // unless the shuttle is "hijacked" - var/destination_dock = "emergency_away" - if(is_hijacked() || elimination_hijack()) - destination_dock = "emergency_syndicate" - minor_announce("Corruption detected in \ - shuttle navigation protocols. Please contact your \ - supervisor.", "SYSTEM ERROR:", alert=TRUE) - - dock_id(destination_dock) + dock_id("emergency_away") mode = SHUTTLE_ENDGAME timer = 0 @@ -558,10 +366,9 @@ mode = SHUTTLE_ESCAPE launch_status = ENDGAME_LAUNCHED - setTimer(SSshuttle.emergency_escape_time) + setTimer(escape_time) priority_announce("The Emergency Shuttle is preparing for direct jump. Estimate [timeLeft(600)] minutes until the shuttle docks at [FLAVOR_CENTCOM_SHORT].", "LSRV Icarus Announcement") - /obj/docking_port/mobile/pod name = "escape pod" id = "pod" @@ -619,7 +426,7 @@ * * source The datum source of the signal * * new_level The new security level that is in effect */ -/obj/machinery/computer/shuttle/pod/proc/check_lock(datum/source, new_level) +/obj/machinery/computer/shuttle/pod/proc/check_lock(datum/source, old_level, new_level) SIGNAL_HANDLER if(obj_flags & EMAGGED) @@ -743,21 +550,16 @@ width = 8 height = 8 dir = EAST + important = TRUE /obj/docking_port/mobile/emergency/backup/Initialize(mapload) - // We want to be a valid emergency shuttle - // but not be the main one, keep whatever's set + // We want to be a valid emergency shuttle but not be the main one, keep whatever's set // valid. // backup shuttle ignores `timid` because THERE SHOULD BE NO TOUCHING IT - var/current_emergency = SSshuttle.emergency + var/current_emergency = GLOB.emergency_shuttle . = ..() - SSshuttle.emergency = current_emergency - SSshuttle.backup_shuttle = src - -/obj/docking_port/mobile/emergency/backup/Destroy(force) - if(SSshuttle.backup_shuttle == src) - SSshuttle.backup_shuttle = null - return ..() + GLOB.emergency_shuttle = current_emergency + GLOB.backup_shuttle = src /obj/docking_port/mobile/emergency/shuttle_build/register() . = ..() @@ -768,10 +570,3 @@ #undef ENGINES_STARTED #undef IS_DOCKED #undef SHUTTLE_CONSOLE_ACTION_DELAY - -#undef NOT_BEGUN -#undef STAGE_1 -#undef STAGE_2 -#undef STAGE_3 -#undef STAGE_4 -#undef HIJACKED diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 48ba0afa1aa6..7d5b6b06b7ad 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -412,6 +412,9 @@ ///Bolt doors on take off, unbolt on arrival? var/bolt_doors = FALSE + ///Prevents admins from replacing it with a new shuttle + var/important = FALSE + /obj/docking_port/mobile/register(replace = FALSE) . = ..() if(!id) diff --git a/config/config.txt b/config/config.txt index 48f391552911..569e41c8b86f 100644 --- a/config/config.txt +++ b/config/config.txt @@ -173,6 +173,9 @@ LOG_CLONING ## log shuttle actions LOG_SHUTTLE +## log evacuation actions +LOG_EVACUATION + ## log tool interactions [/atom/proc/tool_act] LOG_TOOLS diff --git a/config/game_options.txt b/config/game_options.txt index 9ecac2b25a8a..d14b7bf9839c 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -420,8 +420,8 @@ ARRIVALS_SHUTTLE_REQUIRE_UNDOCKED MICE_ROUNDSTART 10 -## If the percentage of players alive (doesn't count conversions) drops below this threshold the emergency shuttle will be forcefully called (provided it can be) -#EMERGENCY_SHUTTLE_AUTOCALL_THRESHOLD 0.2 +## If the percentage of players alive (doesn't count conversions) drops below this threshold the evacuation will be forcefully started (provided it can be) +#EVACUATION_AUTOCALL_THRESHOLD 0.2 ## Uncomment to allow roundstart quirk selection in the character setup menu. ## This used to be named traits, hence the config name, but it handles quirks, not the other kind of trait! diff --git a/daedalus.dme b/daedalus.dme index e69b51299d19..4ef9638e163f 100644 --- a/daedalus.dme +++ b/daedalus.dme @@ -82,6 +82,7 @@ #include "code\__DEFINES\dynamic.dm" #include "code\__DEFINES\economy.dm" #include "code\__DEFINES\electrified_buckle.dm" +#include "code\__DEFINES\evacuation.dm" #include "code\__DEFINES\events.dm" #include "code\__DEFINES\exosuit_fab.dm" #include "code\__DEFINES\explosions.dm" @@ -260,6 +261,7 @@ #include "code\__DEFINES\dcs\signals\signals_container.dm" #include "code\__DEFINES\dcs\signals\signals_customizable.dm" #include "code\__DEFINES\dcs\signals\signals_datum.dm" +#include "code\__DEFINES\dcs\signals\signals_evacuation.dm" #include "code\__DEFINES\dcs\signals\signals_fish.dm" #include "code\__DEFINES\dcs\signals\signals_food.dm" #include "code\__DEFINES\dcs\signals\signals_gib.dm" @@ -509,6 +511,7 @@ #include "code\controllers\subsystem\assets.dm" #include "code\controllers\subsystem\atoms.dm" #include "code\controllers\subsystem\augury.dm" +#include "code\controllers\subsystem\autotransfer.dm" #include "code\controllers\subsystem\ban_cache.dm" #include "code\controllers\subsystem\blackbox.dm" #include "code\controllers\subsystem\blackmarket.dm" @@ -523,6 +526,7 @@ #include "code\controllers\subsystem\early_assets.dm" #include "code\controllers\subsystem\economy.dm" #include "code\controllers\subsystem\eigenstate.dm" +#include "code\controllers\subsystem\evacuation.dm" #include "code\controllers\subsystem\events.dm" #include "code\controllers\subsystem\explosions.dm" #include "code\controllers\subsystem\fail2topic.dm" @@ -1060,6 +1064,8 @@ #include "code\datums\elements\screentips\contextual_screentip_bare_hands.dm" #include "code\datums\elements\screentips\contextual_screentip_item_typechecks.dm" #include "code\datums\elements\screentips\contextual_screentip_tools.dm" +#include "code\datums\evacuation_controllers\emergency_shuttle.dm" +#include "code\datums\evacuation_controllers\evacuation_controller.dm" #include "code\datums\greyscale\_greyscale_config.dm" #include "code\datums\greyscale\json_reader.dm" #include "code\datums\greyscale\layer.dm" @@ -2891,8 +2897,6 @@ #include "code\modules\events\radiation_storm.dm" #include "code\modules\events\rpgtitles.dm" #include "code\modules\events\sentience.dm" -#include "code\modules\events\shuttle_catastrophe.dm" -#include "code\modules\events\shuttle_insurance.dm" #include "code\modules\events\shuttle_loan.dm" #include "code\modules\events\solar_flare.dm" #include "code\modules\events\space_ninja.dm" @@ -4682,8 +4686,6 @@ #include "modular_pariah\modules\alternative_job_titles\code\alt_job_titles.dm" #include "modular_pariah\modules\alternative_job_titles\code\job.dm" #include "modular_pariah\modules\announcer\code\baystation_announcer.dm" -#include "modular_pariah\modules\autotransfer\code\autotransfer.dm" -#include "modular_pariah\modules\autotransfer\code\shuttle.dm" #include "modular_pariah\modules\cryosleep\code\ai.dm" #include "modular_pariah\modules\cryosleep\code\cryopod.dm" #include "modular_pariah\modules\cryosleep\code\job.dm" diff --git a/modular_pariah/modules/autotransfer/code/shuttle.dm b/modular_pariah/modules/autotransfer/code/shuttle.dm deleted file mode 100644 index 076d556987e5..000000000000 --- a/modular_pariah/modules/autotransfer/code/shuttle.dm +++ /dev/null @@ -1,11 +0,0 @@ -/datum/controller/subsystem/shuttle - var/endvote_passed = FALSE - -/datum/controller/subsystem/shuttle/proc/autoEnd() - if(EMERGENCY_IDLE_OR_RECALLED) - SSshuttle.emergency.request(silent = TRUE) - priority_announce("The shift has come to an end and the shuttle called. [SSsecurity_level.current_level == SEC_LEVEL_RED ? "Red Alert state confirmed: Dispatching priority shuttle. " : "" ]It will arrive in [emergency.timeLeft(600)] minutes.", FLAVOR_CENTCOM_NAME, sound_type = ANNOUNCER_SHUTTLECALLED) - log_game("Round end vote passed. Shuttle has been auto-called.") - message_admins("Round end vote passed. Shuttle has been auto-called.") - emergency_no_recall = TRUE - endvote_passed = TRUE diff --git a/modular_pariah/modules/autotransfer/readme.md b/modular_pariah/modules/autotransfer/readme.md deleted file mode 100644 index 977da89009f0..000000000000 --- a/modular_pariah/modules/autotransfer/readme.md +++ /dev/null @@ -1,29 +0,0 @@ -## Title: Autotransfer - -MODULE ID: AUTOTRANSFER - -### Description: - -Adds an automatically called vote for the shuttle to come, timed with real time, so no TD. - -### TG Proc Changes: - -- code/controllers/subsystems/vote.dm -- code/modules/shuttle/emergency.dm - -### Defines: - -- N/A - -### Master file additions - -- N/A - -### Included files that are not contained in this module: - -- N/A - -### Credits: - -LYNXEMX - Pariah port -Azarak - porting to SR diff --git a/tgui/packages/tgui/interfaces/CommunicationsConsole.js b/tgui/packages/tgui/interfaces/CommunicationsConsole.js index 2a3bc90151ba..5c8929927975 100644 --- a/tgui/packages/tgui/interfaces/CommunicationsConsole.js +++ b/tgui/packages/tgui/interfaces/CommunicationsConsole.js @@ -1,7 +1,7 @@ import { sortBy } from "common/collections"; import { capitalize } from "common/string"; import { useBackend, useLocalState } from "../backend"; -import { Blink, Box, Button, Dimmer, Flex, Icon, Input, Modal, Section, TextArea } from "../components"; +import { Blink, Box, Button, Dimmer, Divider, Flex, Icon, Input, Modal, Section, Stack, TextArea } from "../components"; import { Window } from "../layouts"; import { sanitizeText } from "../sanitize"; @@ -311,7 +311,6 @@ const PageMain = (props, context) => { canBuyShuttles, canMakeAnnouncement, canMessageAssociates, - canRecallShuttles, canRequestNuke, canSendToSectors, canSetAlertLevel, @@ -321,15 +320,11 @@ const PageMain = (props, context) => { emergencyAccess, importantActionReady, sectors, - shuttleCalled, - shuttleCalledPreviously, - shuttleCanEvacOrFailReason, - shuttleLastCalled, - shuttleRecallable, + evacOptions, } = data; - const [callingShuttle, setCallingShuttle] = useLocalState( - context, "calling_shuttle", false); + const [callingEvac, setCallingEvac] = useLocalState( + context, "calling_shuttle", null); const [messagingAssociates, setMessagingAssociates] = useLocalState( context, "messaging_associates", false); const [messagingSector, setMessagingSector] = useLocalState( @@ -345,47 +340,36 @@ const PageMain = (props, context) => { return ( {!syndicate && ( -
- {!!shuttleCalled && ( - act("recallShuttle")} - /> - ) || ( - + + {option.status && ( + + {option.status} + + )} + {option.traceString &&( + + {option.traceString} + + )} + {index < evacOptions.length - 1 && } + + )) + } +
)} @@ -458,7 +442,6 @@ const PageMain = (props, context) => { // canBuyShuttles is a string detailing the fail reason // if one can be given tooltip={canBuyShuttles !== 1 ? canBuyShuttles : undefined} - tooltipPosition="right" onClick={() => act("setState", { state: STATE_BUYING_SHUTTLE })} />} @@ -512,17 +495,15 @@ const PageMain = (props, context) => { }} />} - {!!callingShuttle && setCallingShuttle(false)} - onSubmit={reason => { - setCallingShuttle(false); - act("callShuttle", { - reason, - }); + onBack={() => setCallingEvac(null)} + onSubmit={sumbitted => { + setCallingEvac(null); + act("startEvac", { reason: sumbitted, evacController: callingEvac.id }); }} />}