diff --git a/code/__DEFINES/roundend.dm b/code/__DEFINES/roundend.dm index 29db1953ea7..a210d034015 100644 --- a/code/__DEFINES/roundend.dm +++ b/code/__DEFINES/roundend.dm @@ -11,8 +11,6 @@ #define STATION_EVACUATED 5 /// The blob has reached critical mass and overtaken the station #define BLOB_WIN 8 -/// The station's nuke was detonated destroying the blob -#define BLOB_NUKE 9 /// The blob was destroyed by the crew #define BLOB_DESTROYED 10 /// The cult managed to escape alive on the shuttle diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 6fbe0741564..f9476751cd0 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -958,42 +958,39 @@ SUBSYSTEM_DEF(job) living_mob.forceMove(toLaunch) new /obj/effect/pod_landingzone(spawn_turf, toLaunch) -/////////////////////////////////// -//Keeps track of all living heads// -/////////////////////////////////// +/// Returns a list of minds of all heads of staff who are alive /datum/controller/subsystem/job/proc/get_living_heads() . = list() - for(var/mob/living/carbon/human/player as anything in GLOB.human_list) - if(player.stat != DEAD && (player.mind?.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND)) - . += player.mind + for(var/datum/mind/head as anything in get_crewmember_minds()) + if(!(head.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND)) + continue + if(isnull(head.current) || head.current.stat == DEAD) + continue + . += head - -//////////////////////////// -//Keeps track of all heads// -//////////////////////////// +/// Returns a list of minds of all heads of staff /datum/controller/subsystem/job/proc/get_all_heads() . = list() - for(var/mob/living/carbon/human/player as anything in GLOB.human_list) - if(player.mind?.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND) - . += player.mind + for(var/datum/mind/head as anything in get_crewmember_minds()) + if(head.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND) + . += head -////////////////////////////////////////////// -//Keeps track of all living security members// -////////////////////////////////////////////// +/// Returns a list of minds of all security members who are alive /datum/controller/subsystem/job/proc/get_living_sec() . = list() - for(var/mob/living/carbon/human/player as anything in GLOB.human_list) - if(player.stat != DEAD && (player.mind?.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_SECURITY)) - . += player.mind + for(var/datum/mind/sec as anything in get_crewmember_minds()) + if(!(sec.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_SECURITY)) + continue + if(isnull(sec.current) || sec.current.stat == DEAD) + continue + . += sec -//////////////////////////////////////// -//Keeps track of all security members// -//////////////////////////////////////// +/// Returns a list of minds of all security members /datum/controller/subsystem/job/proc/get_all_sec() . = list() - for(var/mob/living/carbon/human/player as anything in GLOB.human_list) - if(player.mind?.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_SECURITY) - . += player.mind + for(var/datum/mind/sec as anything in get_crewmember_minds()) + if(sec.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_SECURITY) + . += sec /datum/controller/subsystem/job/proc/JobDebug(message) log_job_debug(message) diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index 45f48b6a366..ab9b27a1e4f 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -861,6 +861,17 @@ GLOBAL_LIST_EMPTY(the_station_areas) /datum/controller/subsystem/mapping/proc/lazy_load_template(template_key, force = FALSE) RETURN_TYPE(/datum/turf_reservation) + var/static/lazy_loading = FALSE + UNTIL(!lazy_loading) + + lazy_loading = TRUE + . = _lazy_load_template(template_key, force) + lazy_loading = FALSE + return . + +/datum/controller/subsystem/mapping/proc/_lazy_load_template(template_key, force = FALSE) + PRIVATE_PROC(TRUE) + if(LAZYACCESS(loaded_lazy_templates, template_key) && !force) var/datum/lazy_template/template = GLOB.lazy_templates[template_key] return template.reservations[1] @@ -869,7 +880,6 @@ GLOBAL_LIST_EMPTY(the_station_areas) var/datum/lazy_template/target = GLOB.lazy_templates[template_key] if(!target) CRASH("Attempted to lazy load a template key that does not exist: '[template_key]'") - return target.lazy_load() /proc/generate_lighting_appearance_by_z(z_level) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index e08018b02f0..ad90d86467b 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -48,6 +48,7 @@ SUBSYSTEM_DEF(ticker) var/queue_delay = 0 var/list/queued_players = list() //used for join queues when the server exceeds the hard population cap + /// What is going to be reported to other stations at end of round? var/news_report @@ -582,47 +583,96 @@ SUBSYSTEM_DEF(ticker) /datum/controller/subsystem/ticker/proc/send_news_report() var/news_message var/news_source = "Nanotrasen News Network" - var/decoded_station_name = html_decode("[CONFIG_GET(string/cross_comms_name)]([station_name()])") //decode station_name to avoid minor_announce double encode //SKYRAT EDIT CHANGE + var/decoded_station_name = html_decode(CONFIG_GET(string/cross_comms_name)) //decode station_name to avoid minor_announce double encode // SKYRAT EDIT: CROSS COMMS CONFIG + switch(news_report) + // The nuke was detonated on the syndicate recon outpost if(NUKE_SYNDICATE_BASE) - news_message = "In a daring raid, the heroic crew of [decoded_station_name] detonated a nuclear device in the heart of a terrorist base." + news_message = "In a daring raid, the heroic crew of [decoded_station_name] \ + detonated a nuclear device in the heart of a terrorist base." + // The station was destroyed by nuke ops if(STATION_DESTROYED_NUKE) - news_message = "We would like to reassure all employees that the reports of a Syndicate backed nuclear attack on [decoded_station_name] are, in fact, a hoax. Have a secure day!" + news_message = "We would like to reassure all employees that the reports of a Syndicate \ + backed nuclear attack on [decoded_station_name] are, in fact, a hoax. Have a secure day!" + // The station was evacuated (normal result) if(STATION_EVACUATED) + // Had an emergency reason supplied to pass along if(emergency_reason) - news_message = "[decoded_station_name] has been evacuated after transmitting the following distress beacon:\n\n[html_decode(emergency_reason)]" + news_message = "[decoded_station_name] has been evacuated after transmitting \ + the following distress beacon:\n\n[html_decode(emergency_reason)]" else - news_message = "The crew of [decoded_station_name] has been evacuated amid unconfirmed reports of enemy activity." + news_message = "The crew of [decoded_station_name] has been \ + evacuated amid unconfirmed reports of enemy activity." + // A blob won if(BLOB_WIN) - news_message = "[decoded_station_name] was overcome by an unknown biological outbreak, killing all crew on board. Don't let it happen to you! Remember, a clean work station is a safe work station." - if(BLOB_NUKE) - news_message = "[decoded_station_name] is currently undergoing decontanimation after a controlled burst of radiation was used to remove a biological ooze. All employees were safely evacuated prior, and are enjoying a relaxing vacation." + news_message = "[decoded_station_name] was overcome by an unknown biological outbreak, killing \ + all crew on board. Don't let it happen to you! Remember, a clean work station is a safe work station." + // A blob was destroyed if(BLOB_DESTROYED) - news_message = "[decoded_station_name] is currently undergoing decontamination procedures after the destruction of a biological hazard. As a reminder, any crew members experiencing cramps or bloating should report immediately to security for incineration." + news_message = "[decoded_station_name] is currently undergoing decontamination procedures \ + after the destruction of a biological hazard. As a reminder, any crew members experiencing \ + cramps or bloating should report immediately to security for incineration." + // A certain percentage of all cultists managed to escape at the end of round if(CULT_ESCAPE) news_message = "Security Alert: A group of religious fanatics have escaped from [decoded_station_name]." + // Cult was completely or almost completely wiped out if(CULT_FAILURE) - news_message = "Following the dismantling of a restricted cult aboard [decoded_station_name], we would like to remind all employees that worship outside of the Chapel is strictly prohibited, and cause for termination." + news_message = "Following the dismantling of a restricted cult aboard [decoded_station_name], \ + we would like to remind all employees that worship outside of the Chapel is strictly prohibited, \ + and cause for termination." + // Cult summoned Nar'sie if(CULT_SUMMON) - news_message = "Company officials would like to clarify that [decoded_station_name] was scheduled to be decommissioned following meteor damage earlier this year. Earlier reports of an unknowable eldritch horror were made in error." + news_message = "Company officials would like to clarify that [decoded_station_name] was scheduled \ + to be decommissioned following meteor damage earlier this year. Earlier reports of an \ + unknowable eldritch horror were made in error." + // Nuke detonated, but missed the station entirely if(NUKE_MISS) - news_message = "The Syndicate have bungled a terrorist attack [decoded_station_name], detonating a nuclear weapon in empty space nearby." + news_message = "The Syndicate have bungled a terrorist attack [decoded_station_name], \ + detonating a nuclear weapon in empty space nearby." + // All nuke ops got killed if(OPERATIVES_KILLED) - news_message = "Repairs to [decoded_station_name] are underway after an elite Syndicate death squad was wiped out by the crew." + news_message = "Repairs to [decoded_station_name] are underway after an elite \ + Syndicate death squad was wiped out by the crew." + // Nuke ops results inconclusive - Crew escaped without the disk, or nukies were left alive, or something if(OPERATIVE_SKIRMISH) - news_message = "A skirmish between security forces and Syndicate agents aboard [decoded_station_name] ended with both sides bloodied but intact." + news_message = "A skirmish between security forces and Syndicate agents aboard [decoded_station_name] \ + ended with both sides bloodied but intact." + // Revolution victory if(REVS_WIN) - news_message = "Company officials have reassured investors that despite a union led revolt aboard [decoded_station_name] there will be no wage increases for workers." + news_message = "Company officials have reassured investors that despite a union led revolt \ + aboard [decoded_station_name] there will be no wage increases for workers." + // Revolution defeat if(REVS_LOSE) - news_message = "[decoded_station_name] quickly put down a misguided attempt at mutiny. Remember, unionizing is illegal!" + news_message = "[decoded_station_name] quickly put down a misguided attempt at mutiny. \ + Remember, unionizing is illegal!" + // All wizards (plus apprentices) have been killed if(WIZARD_KILLED) - news_message = "Tensions have flared with the Space Wizard Federation following the death of one of their members aboard [decoded_station_name]." + news_message = "Tensions have flared with the Space Wizard Federation following the death \ + of one of their members aboard [decoded_station_name]." + // The station was nuked generically 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." + // There was a blob on board, guess it was nuked to stop it + if(length(GLOB.overminds)) + for(var/mob/camera/blob/overmind as anything in GLOB.overminds) + if(overmind.max_count < overmind.announcement_size) + continue + + news_message = "[decoded_station_name] is currently undergoing decontanimation after a controlled \ + burst of radiation was used to remove a biological ooze. All employees were safely evacuated prior, \ + and are enjoying a relaxing vacation." + break + // A self destruct or something else + else + news_message = "[decoded_station_name] activated its self-destruct device for unknown reasons. \ + Attempts to clone the Captain for arrest and execution are underway." + // The emergency escape shuttle was hijacked 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." + 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." + // A supermatter cascade triggered if(SUPERMATTER_CASCADE) - news_message = "Officials are advising nearby colonies about a newly declared exclusion zone in the sector surrounding [decoded_station_name]." + news_message = "Officials are advising nearby colonies about a newly declared exclusion zone in \ + the sector surrounding [decoded_station_name]." //SKYRAT EDIT - START if(SSblackbox.first_death) diff --git a/code/datums/mind/_mind.dm b/code/datums/mind/_mind.dm index 2a2c50e9596..4d1e2f8945d 100644 --- a/code/datums/mind/_mind.dm +++ b/code/datums/mind/_mind.dm @@ -73,7 +73,8 @@ var/has_ever_been_ai = FALSE var/last_death = 0 - /// Set by Into The Sunset command of the shuttle manipulator + /// Set by Into The Sunset command of the shuttle manipulator. + /// If TRUE, the mob will always be considered "escaped" if they are alive and not exiled. var/force_escaped = FALSE var/list/learned_recipes //List of learned recipe TYPES. diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index c632f8386d7..59f2826d4ec 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -290,7 +290,11 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) // If it got to this part, just pick one high impact ruleset if it exists for(var/datum/dynamic_ruleset/rule in executed_rules) if(rule.flags & HIGH_IMPACT_RULESET) - return rule.round_result() + rule.round_result() + // One was set, so we're done here + if(SSticker.news_report) + return + return ..() /datum/game_mode/dynamic/proc/send_intercept() @@ -503,6 +507,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) rule.acceptable(roundstart_pop_ready, threat_level) // Assigns some vars in the modes, running it here for consistency rule.candidates = candidates.Copy() rule.trim_candidates() + rule.load_templates() if (rule.ready(roundstart_pop_ready, TRUE)) var/cost = rule.cost var/scaled_times = 0 @@ -523,6 +528,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) if (rule.acceptable(roundstart_pop_ready, threat_level) && round_start_budget >= rule.cost) // If we got the population and threat required rule.candidates = candidates.Copy() rule.trim_candidates() + rule.load_templates() if (rule.ready(roundstart_pop_ready) && rule.candidates.len > 0) drafted_rules[rule] = rule.weight @@ -630,6 +636,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) var/population = GLOB.alive_player_list.len if((new_rule.acceptable(population, threat_level) && (ignore_cost || new_rule.cost <= mid_round_budget)) || forced) new_rule.trim_candidates() + new_rule.load_templates() if (new_rule.ready(forced)) if (!ignore_cost) spend_midround_budget(new_rule.cost, threat_log, "[worldtime2text()]: Forced rule [new_rule.name]") @@ -682,6 +689,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) if (forced_latejoin_rule) forced_latejoin_rule.candidates = list(newPlayer) forced_latejoin_rule.trim_candidates() + forced_latejoin_rule.load_templates() log_dynamic("Forcing ruleset [forced_latejoin_rule]") if (forced_latejoin_rule.ready(TRUE)) if (!forced_latejoin_rule.repeatable) @@ -704,6 +712,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) rule.candidates = list(newPlayer) rule.trim_candidates() + rule.load_templates() if (rule.ready()) drafted_rules[rule] = rule.get_weight() diff --git a/code/game/gamemodes/dynamic/dynamic_midround_rolling.dm b/code/game/gamemodes/dynamic/dynamic_midround_rolling.dm index 65f744838d5..59f133f2b30 100644 --- a/code/game/gamemodes/dynamic/dynamic_midround_rolling.dm +++ b/code/game/gamemodes/dynamic/dynamic_midround_rolling.dm @@ -62,6 +62,7 @@ continue ruleset.trim_candidates() + ruleset.load_templates() if (!ruleset.ready()) log_game("DYNAMIC: FAIL: [ruleset] is not ready()") continue diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets.dm b/code/game/gamemodes/dynamic/dynamic_rulesets.dm index 43292ab0a3e..3b946b3b2f4 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets.dm @@ -85,6 +85,9 @@ /// If written as a linear equation, will be in the form of `list("denominator" = denominator, "offset" = offset). var/antag_cap = 0 + /// A list, or null, of templates that the ruleset depends on to function correctly + var/list/ruleset_lazy_templates + /datum/dynamic_ruleset/New() // Rulesets can be instantiated more than once, such as when an admin clicks // "Execute Midround Ruleset". Thus, it would be wrong to perform any @@ -173,6 +176,11 @@ /datum/dynamic_ruleset/proc/ready(forced = 0) return check_candidates() +/// This should always be called before ready is, to ensure that the ruleset can locate map/template based landmarks as needed +/datum/dynamic_ruleset/proc/load_templates() + for(var/template in ruleset_lazy_templates) + SSmapping.lazy_load_template(template) + /// Runs from gamemode process() if ruleset fails to start, like delayed rulesets not getting valid candidates. /// This one only handles refunding the threat, override in ruleset to clean up the rest. /datum/dynamic_ruleset/proc/clean_up() diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 7fdd10757d7..891f58c1736 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -347,12 +347,12 @@ cost = 10 requirements = REQUIREMENTS_VERY_HIGH_THREAT_NEEDED flags = HIGH_IMPACT_RULESET + ruleset_lazy_templates = list(LAZY_TEMPLATE_KEY_WIZARDDEN) /datum/dynamic_ruleset/midround/from_ghosts/wizard/ready(forced = FALSE) - SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_WIZARDDEN) - if (!check_candidates()) + if(!check_candidates()) return FALSE - if(GLOB.wizardstart.len == 0) + if(!length(GLOB.wizardstart)) log_admin("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") message_admins("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") return FALSE diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index 12b6d007d74..92748f1d6a4 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -273,16 +273,30 @@ weight = 2 cost = 20 requirements = list(90,90,90,80,60,40,30,20,10,10) - var/list/roundstart_wizards = list() + ruleset_lazy_templates = list(LAZY_TEMPLATE_KEY_WIZARDDEN) -/datum/dynamic_ruleset/roundstart/wizard/acceptable(population=0, threat=0) - SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_WIZARDDEN) - if(GLOB.wizardstart.len == 0) +/datum/dynamic_ruleset/roundstart/wizard/ready(forced = FALSE) + if(!check_candidates()) + return FALSE + if(!length(GLOB.wizardstart)) log_admin("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") message_admins("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") return FALSE return ..() +/datum/dynamic_ruleset/roundstart/wizard/round_result() + for(var/datum/antagonist/wizard/wiz in GLOB.antagonists) + var/mob/living/real_wiz = wiz.owner?.current + if(isnull(real_wiz)) + continue + + var/turf/wiz_location = get_turf(real_wiz) + // If this wiz is alive AND not in an away level, then we know not all wizards are dead and can leave entirely + if(considered_alive(wiz.owner) && wiz_location && !is_away_level(wiz_location.z)) + return + + SSticker.news_report = WIZARD_KILLED + /datum/dynamic_ruleset/roundstart/wizard/pre_execute() . = ..() if(GLOB.wizardstart.len == 0) @@ -361,13 +375,25 @@ return TRUE /datum/dynamic_ruleset/roundstart/bloodcult/round_result() - ..() if(main_cult.check_cult_victory()) SSticker.mode_result = "win - cult win" SSticker.news_report = CULT_SUMMON - else - SSticker.mode_result = "loss - staff stopped the cult" - SSticker.news_report = CULT_FAILURE + return + + SSticker.mode_result = "loss - staff stopped the cult" + + if(main_cult.size_at_maximum == 0) + CRASH("Cult team existed with a size_at_maximum of 0 at round end!") + + // If more than a certain ratio of our cultists have escaped, give the "cult escape" resport. + // Otherwise, give the "cult failure" report. + var/ratio_to_be_considered_escaped = 0.5 + var/escaped_cultists = 0 + for(var/datum/mind/escapee as anything in main_cult.members) + if(considered_escaped(escapee)) + escaped_cultists++ + + SSticker.news_report = (escaped_cultists / main_cult.size_at_maximum) >= ratio_to_be_considered_escaped ? CULT_ESCAPE : CULT_FAILURE ////////////////////////////////////////////// // // @@ -391,6 +417,7 @@ requirements = list(90,90,90,80,60,40,30,20,10,10) flags = HIGH_IMPACT_RULESET antag_cap = list("denominator" = 18, "offset" = 1) + ruleset_lazy_templates = list(LAZY_TEMPLATE_KEY_NUKIEBASE) var/required_role = ROLE_NUCLEAR_OPERATIVE var/datum/team/nuclear/nuke_team @@ -432,10 +459,10 @@ SSticker.news_report = NUKE_SYNDICATE_BASE if(NUKE_RESULT_NUKE_WIN) SSticker.mode_result = "win - syndicate nuke" - SSticker.news_report = STATION_NUKED + SSticker.news_report = STATION_DESTROYED_NUKE if(NUKE_RESULT_NOSURVIVORS) SSticker.mode_result = "halfwin - syndicate nuke - did not evacuate in time" - SSticker.news_report = STATION_NUKED + SSticker.news_report = STATION_DESTROYED_NUKE if(NUKE_RESULT_WRONG_STATION) SSticker.mode_result = "halfwin - blew wrong station" SSticker.news_report = NUKE_MISS diff --git a/code/game/gamemodes/dynamic/dynamic_unfavorable_situation.dm b/code/game/gamemodes/dynamic/dynamic_unfavorable_situation.dm index 7625ab70901..55ed15e92bf 100644 --- a/code/game/gamemodes/dynamic/dynamic_unfavorable_situation.dm +++ b/code/game/gamemodes/dynamic/dynamic_unfavorable_situation.dm @@ -38,6 +38,7 @@ ruleset.trim_candidates() + ruleset.load_templates() if (!ruleset.ready()) continue diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index b868b4141cd..1a70faf482e 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -212,14 +212,14 @@ //Set result and news report here /datum/game_mode/proc/set_round_result() SSticker.mode_result = "undefined" + // Something nuked the station - it wasn't nuke ops (they set their own via their rulset) if(GLOB.station_was_nuked) - SSticker.news_report = STATION_DESTROYED_NUKE - if(EMERGENCY_ESCAPED_OR_ENDGAMED) - SSticker.news_report = STATION_EVACUATED - if(SSshuttle.emergency.is_hijacked()) - SSticker.news_report = SHUTTLE_HIJACK + SSticker.news_report = STATION_NUKED if(SSsupermatter_cascade.cascade_initiated) SSticker.news_report = SUPERMATTER_CASCADE + // Only show this one if we have nothing better to show + if(EMERGENCY_ESCAPED_OR_ENDGAMED && !SSticker.news_report) + SSticker.news_report = SSshuttle.emergency?.is_hijacked() ? SHUTTLE_HIJACK : STATION_EVACUATED /// Mode specific admin panel. /datum/game_mode/proc/admin_panel() diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 79c9d9e467f..94f660f6339 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -61,21 +61,28 @@ GLOBAL_LIST_EMPTY(objectives) //SKYRAT EDIT ADDITION update_explanation_text() -/datum/objective/proc/considered_escaped(datum/mind/M) - if(!considered_alive(M)) +/** + * Checks if the passed mind is considered "escaped". + * + * Escaped mobs are used to check certain antag objectives / results. + * + * Escaped includes minds with alive, non-exiled mobs generally. + */ +/proc/considered_escaped(datum/mind/escapee) + if(!considered_alive(escapee)) return FALSE - if(considered_exiled(M)) + if(considered_exiled(escapee)) return FALSE - if(M.force_escaped) + if(escapee.force_escaped) return TRUE if(SSticker.force_ending || GLOB.station_was_nuked) // Just let them win. return TRUE if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME) return FALSE - var/area/current_area = get_area(M.current) + var/area/current_area = get_area(escapee.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) + var/turf/current_turf = get_turf(escapee.current) return current_turf.onCentCom() || current_turf.onSyndieBase() /datum/objective/proc/check_completion() diff --git a/code/modules/antagonists/_common/antag_team.dm b/code/modules/antagonists/_common/antag_team.dm index 4f6ba5737e3..c568c58e310 100644 --- a/code/modules/antagonists/_common/antag_team.dm +++ b/code/modules/antagonists/_common/antag_team.dm @@ -115,4 +115,3 @@ GLOBAL_LIST_EMPTY(antagonist_teams) ///Custom names for individuals in a team /datum/team/proc/antag_listing_name() return name - diff --git a/code/modules/antagonists/abductor/abductor.dm b/code/modules/antagonists/abductor/abductor.dm index ea24a99e0e4..15544405919 100644 --- a/code/modules/antagonists/abductor/abductor.dm +++ b/code/modules/antagonists/abductor/abductor.dm @@ -17,6 +17,11 @@ /// Type path for the associated job datum. var/role_job = /datum/job/abductor_agent +/datum/antagonist/abductor/New() + // lets get the loading started now, but don't block waiting for it + INVOKE_ASYNC(SSmapping, TYPE_PROC_REF(/datum/controller/subsystem/mapping, lazy_load_template), LAZY_TEMPLATE_KEY_ABDUCTOR_SHIPS) + return ..() + /datum/antagonist/abductor/get_preview_icon() var/mob/living/carbon/human/dummy/consistent/scientist = new var/mob/living/carbon/human/dummy/consistent/agent = new @@ -99,6 +104,8 @@ H.real_name = "[team.name] [sub_role]" H.equipOutfit(outfit) + // We require that the template be loaded here, so call it in a blocking manner, if its already done loading, this won't block + SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_ABDUCTOR_SHIPS) //Teleport to ship for(var/obj/effect/landmark/abductor/LM in GLOB.landmarks_list) if(istype(LM, landmark_type) && LM.team_number == team.team_number) @@ -116,7 +123,6 @@ . = ..() /datum/antagonist/abductor/admin_add(datum/mind/new_owner,mob/admin) - SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_ABDUCTOR_SHIPS) var/list/current_teams = list() for(var/datum/team/abductor_team/T in GLOB.antagonist_teams) current_teams[T.name] = T diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm index 9b88131c00f..898089aa9e1 100644 --- a/code/modules/antagonists/blob/overmind.dm +++ b/code/modules/antagonists/blob/overmind.dm @@ -135,6 +135,8 @@ GLOBAL_LIST_EMPTY(blob_nodes) if(autoplace_max_time && world.time >= autoplace_max_time) place_blob_core(BLOB_RANDOM_PLACEMENT) else + // If we get here, it means yes: the blob is kill + SSticker.news_report = BLOB_DESTROYED qdel(src) else if(!victory_in_progress && (blobs_legit.len >= blobwincount)) victory_in_progress = TRUE diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm index 3aaa2f71763..6c4c6603c1d 100644 --- a/code/modules/antagonists/cult/cult.dm +++ b/code/modules/antagonists/cult/cult.dm @@ -271,6 +271,8 @@ ///Has narsie been summoned yet? var/narsie_summoned = FALSE + ///How large were we at max size. + var/size_at_maximum = 0 /datum/team/cult/proc/check_size() if(cult_ascendent) @@ -305,6 +307,13 @@ cult_ascendent = TRUE log_game("The blood cult has ascended with [cultplayers] players.") +/datum/team/cult/add_member(datum/mind/new_member) + . = ..() + // A little hacky, but this checks that cult ghosts don't contribute to the size at maximum value. + if(is_unassigned_job(new_member.assigned_role)) + return + size_at_maximum++ + /datum/team/cult/proc/make_image(datum/objective/sacrifice/sac_objective) var/datum/job/job_of_sacrifice = sac_objective.target.assigned_role var/datum/preferences/prefs_of_sacrifice = sac_objective.target.current.client.prefs diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index 2a082377bb4..ab8c354273e 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -869,7 +869,8 @@ structure_check() searches for nearby cultist structures required for the invoca to_chat(user, span_cultitalic("Your blood begins flowing into [src]. You must remain in place and conscious to maintain the forms of those summoned. This will hurt you slowly but surely...")) var/obj/structure/emergency_shield/cult/weak/N = new(T) new_human.key = ghost_to_spawn.key - new_human.mind?.add_antag_datum(/datum/antagonist/cult) + var/datum/antagonist/cult/created_cultist = new_human.mind?.add_antag_datum(/datum/antagonist/cult) + created_cultist?.silent = TRUE to_chat(new_human, span_cultitalic("You are a servant of the Geometer. You have been made semi-corporeal by the cult of Nar'Sie, and you are to serve them at all costs.")) while(!QDELETED(src) && !QDELETED(user) && !QDELETED(new_human) && (user in T)) @@ -885,7 +886,9 @@ structure_check() searches for nearby cultist structures required for the invoca span_cultlarge("Your link to the world fades. Your form breaks apart.")) for(var/obj/I in new_human) new_human.dropItemToGround(I, TRUE) + new_human.mind?.remove_antag_datum(/datum/antagonist/cult) new_human.dust() + else if(choice == "Ascend as a Dark Spirit") affecting = user affecting.add_atom_colour(RUNE_COLOR_DARKRED, ADMIN_COLOUR_PRIORITY) diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm index eb48839047f..69fc8bc67e2 100644 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ b/code/modules/antagonists/nukeop/nukeop.dm @@ -25,6 +25,11 @@ /// The amount of limited discounts that the team get var/discount_limited_amount = 10 +/datum/antagonist/nukeop/New() + if(send_to_spawnpoint) // lets get the loading started now, but don't block waiting for it + INVOKE_ASYNC(SSmapping, TYPE_PROC_REF(/datum/controller/subsystem/mapping, lazy_load_template), LAZY_TEMPLATE_KEY_NUKIEBASE) + return ..() + /datum/antagonist/nukeop/proc/equip_op() if(!ishuman(owner.current)) return @@ -118,6 +123,9 @@ objectives |= nuke_team.objectives /datum/antagonist/nukeop/proc/move_to_spawnpoint() + // Ensure that the nukiebase is loaded, and wait for it if required + SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_NUKIEBASE) + var/team_number = 1 if(nuke_team) team_number = nuke_team.members.Find(owner) @@ -127,7 +135,6 @@ owner.current.forceMove(pick(GLOB.nukeop_leader_start)) /datum/antagonist/nukeop/create_team(datum/team/nuclear/new_team) - SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_NUKIEBASE) if(!new_team) if(!always_new_team) for(var/datum/antagonist/nukeop/N in GLOB.antagonists) diff --git a/code/modules/antagonists/nukeop/outfits.dm b/code/modules/antagonists/nukeop/outfits.dm index 693624bc82b..cb08771860f 100644 --- a/code/modules/antagonists/nukeop/outfits.dm +++ b/code/modules/antagonists/nukeop/outfits.dm @@ -28,7 +28,9 @@ /datum/outfit/syndicate/post_equip(mob/living/carbon/human/nukie, visualsOnly = FALSE) if(visualsOnly) return - SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_NUKIEBASE) + + // We don't require the nukiebase be loaded to function, but lets go ahead and kick off loading just in case + INVOKE_ASYNC(SSmapping, TYPE_PROC_REF(/datum/controller/subsystem/mapping, lazy_load_template), LAZY_TEMPLATE_KEY_NUKIEBASE) var/obj/item/radio/radio = nukie.ears radio.set_frequency(FREQ_SYNDICATE) radio.freqlock = RADIO_FREQENCY_LOCKED diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm index f241e260ae9..c16e54ab021 100644 --- a/code/modules/antagonists/revolution/revolution.dm +++ b/code/modules/antagonists/revolution/revolution.dm @@ -626,7 +626,7 @@ var/heads_report = "Heads of Staff
" heads_report += "" - for(var/datum/mind/N in SSjob.get_living_heads()) + for(var/datum/mind/N as anything in SSjob.get_living_heads()) var/mob/M = N.current if(M) heads_report += "" diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm index ec7f3aba08c..66a1d77ae42 100644 --- a/code/modules/antagonists/wizard/wizard.dm +++ b/code/modules/antagonists/wizard/wizard.dm @@ -21,6 +21,11 @@ GLOBAL_LIST_EMPTY(wizard_spellbook_purchases_by_key) var/wiz_age = WIZARD_AGE_MIN /* Wizards by nature cannot be too young. */ show_to_ghosts = TRUE +/datum/antagonist/wizard/New() + if(move_to_lair) // kick off loading of your lair, if you want to be moved to it + INVOKE_ASYNC(SSmapping, TYPE_PROC_REF(/datum/controller/subsystem/mapping, lazy_load_template), LAZY_TEMPLATE_KEY_WIZARDDEN) + return ..() + /datum/antagonist/wizard_minion name = "Wizard Minion" antagpanel_category = "Wizard" @@ -92,7 +97,9 @@ GLOBAL_LIST_EMPTY(wizard_spellbook_purchases_by_key) wiz_team.master_wizard = src /datum/antagonist/wizard/proc/send_to_lair() + // And now we ensure that its loaded SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_WIZARDDEN) + if(!owner) CRASH("Antag datum with no owner.") if(!owner.current) diff --git a/code/modules/jobs/job_types/antagonists/nuclear_operative.dm b/code/modules/jobs/job_types/antagonists/nuclear_operative.dm index f727e37f6c7..6fbfdd50994 100644 --- a/code/modules/jobs/job_types/antagonists/nuclear_operative.dm +++ b/code/modules/jobs/job_types/antagonists/nuclear_operative.dm @@ -1,11 +1,8 @@ /datum/job/nuclear_operative title = ROLE_NUCLEAR_OPERATIVE - /datum/job/nuclear_operative/get_roundstart_spawn_point() - SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_NUKIEBASE) return pick(GLOB.nukeop_start) /datum/job/nuclear_operative/get_latejoin_spawn_point() - SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_NUKIEBASE) return pick(GLOB.nukeop_start) diff --git a/code/modules/jobs/job_types/antagonists/space_wizard.dm b/code/modules/jobs/job_types/antagonists/space_wizard.dm index e317cfb3276..fc0c2cdbf15 100644 --- a/code/modules/jobs/job_types/antagonists/space_wizard.dm +++ b/code/modules/jobs/job_types/antagonists/space_wizard.dm @@ -3,9 +3,7 @@ faction = ROLE_WIZARD /datum/job/space_wizard/get_roundstart_spawn_point() - SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_WIZARDDEN) return pick(GLOB.wizardstart) /datum/job/space_wizard/get_latejoin_spawn_point() - SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_WIZARDDEN) return pick(GLOB.wizardstart) diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index ae338a0bd1b..4b9f37d08c7 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -181,8 +181,9 @@ /obj/machinery/computer/emergency_shuttle/proc/increase_hijack_stage() var/obj/docking_port/mobile/emergency/shuttle = SSshuttle.emergency - // Begin loading this early, otherwise we get an awkward 30 second delay on the - SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_NUKIEBASE) + // Begin loading this early, prevents a delay when the shuttle goes to land + INVOKE_ASYNC(SSmapping, TYPE_PROC_REF(/datum/controller/subsystem/mapping, lazy_load_template), LAZY_TEMPLATE_KEY_NUKIEBASE) + shuttle.hijack_status++ if(hijack_announce) announce_hijack_stage() @@ -542,6 +543,7 @@ // unless the shuttle is "hijacked" var/destination_dock = "emergency_away" if(is_hijacked() || elimination_hijack()) + // just double check SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_NUKIEBASE) destination_dock = "emergency_syndicate" minor_announce("Corruption detected in \
[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]