From aa441a96332829090664577d9b8a3cb5ddc1bcce Mon Sep 17 00:00:00 2001
From: Zonespace <41448081+Zonespace27@users.noreply.github.com>
Date: Wed, 11 Jan 2023 22:18:18 -0800
Subject: [PATCH] Mirror 72339 & 71284 (#18645)
* Renews a bunch of old roundend new reports that got lost. Plus, some roundend report QoL for cult and revs. (#71284)
A few roundend reports got lost from moving to dynamic and other prs.
This PRs re-allows them to occur. Namely: "Wizard Killed" (lost in
dynamic), "Blob nuked" (lost in dynamic), "Cult escaped" (lost in cult
rework), and "Nuke Ops Victory" (station destroyed via nuke) (lost from,
what I can see, an oversight / accidental swap of report values).
Additionally, small roundend report QOL for cult: Removes antag datums
from spirit realm ghosts after being dusted, so they do not show up on
the report. And in reverse, heads of staff who were dusted / destroyed
in revolution rounds are now also shown in roundend reports.
Some of these reports are dead, which is is a shame because I think
they're cool and fun.
:cl: Melbert
qol: Successfully fending off a blob now has a cross station news report
again. More pressing reports will take priority over it, though.
qol: Successfully killing a wizard (and all of their apprentices) now
has a cross station news report again.
qol: If more than half of a cultist team manages to escape on the
shuttle (rather than summoning Nar'sie), they will send a unique cross
station news report. This is still a loss, by the way. Summon Nar'sie!
qol: Nuclear Operatives successfully nuking the station now has its
unique cross station news report again, and no longer uses the generic
"The station was nuked" report.
qol: Nuking the station to stop a blob infection now has a unique cross
station news report again. Good luck convincing admins to allow this.
qol: Cult ghosts from "Spirit Realm" no longer persist on the cult's
team after being desummoned, meaning they will not show up on roundend
report.
qol: Heads of staff will now always show up on revolution roundend
report - even if their body was fully destroyed.
/:cl:
* Adds support for Rulesets having intrinsic template requirements (#72339)
Title
Ensures that we load templates for a ruleset before we attempt to place
or cache characters for that ruleset
Also makes wizard and abductor async load their template to improve
(apparent) loading times for them
This is the only thing left that I can think of that would cause antags
like nukies and abductors to spawn in wrong
This should not be player facing
Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
---
code/__DEFINES/roundend.dm | 2 -
code/controllers/subsystem/job.dm | 47 +++++-----
code/controllers/subsystem/mapping.dm | 12 ++-
code/controllers/subsystem/ticker.dm | 90 ++++++++++++++-----
code/datums/mind/_mind.dm | 3 +-
code/game/gamemodes/dynamic/dynamic.dm | 11 ++-
.../dynamic/dynamic_midround_rolling.dm | 1 +
.../gamemodes/dynamic/dynamic_rulesets.dm | 8 ++
.../dynamic/dynamic_rulesets_midround.dm | 6 +-
.../dynamic/dynamic_rulesets_roundstart.dm | 47 +++++++---
.../dynamic/dynamic_unfavorable_situation.dm | 1 +
code/game/gamemodes/game_mode.dm | 10 +--
code/game/gamemodes/objective.dm | 19 ++--
.../modules/antagonists/_common/antag_team.dm | 1 -
code/modules/antagonists/abductor/abductor.dm | 8 +-
code/modules/antagonists/blob/overmind.dm | 2 +
code/modules/antagonists/cult/cult.dm | 9 ++
code/modules/antagonists/cult/runes.dm | 5 +-
code/modules/antagonists/nukeop/nukeop.dm | 9 +-
code/modules/antagonists/nukeop/outfits.dm | 4 +-
.../antagonists/revolution/revolution.dm | 2 +-
code/modules/antagonists/wizard/wizard.dm | 7 ++
.../antagonists/nuclear_operative.dm | 3 -
.../job_types/antagonists/space_wizard.dm | 2 -
code/modules/shuttle/emergency.dm | 6 +-
25 files changed, 228 insertions(+), 87 deletions(-)
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 \