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 += "
| [M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""] | " 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 \