diff --git a/code/__DEFINES/antag_defines.dm b/code/__DEFINES/antag_defines.dm
index 24cfb19d97e45..01a9b291e6a2d 100644
--- a/code/__DEFINES/antag_defines.dm
+++ b/code/__DEFINES/antag_defines.dm
@@ -62,6 +62,16 @@ GLOBAL_LIST(contractors)
*/
#define PULSEDEMON_SOURCE_DRAIN_INVALID (-1)
+/**
+ * Objectives
+ */
+#define THEFT_FLAG_SPECIAL 1 // Unused, maybe someone will use it some day, I'll leave it here for the children
+#define THEFT_FLAG_UNIQUE 2
+
+/**
+ * IS_ANTAG defines
+ */
#define IS_CHANGELING(mob) (isliving(mob) && mob?:mind?:has_antag_datum(/datum/antagonist/changeling))
#define IS_MINDSLAVE(mob) (ishuman(mob) && mob?:mind?:has_antag_datum(/datum/antagonist/mindslave, FALSE))
+
diff --git a/code/controllers/subsystem/SSticker.dm b/code/controllers/subsystem/SSticker.dm
index 4a197abfffa79..bc19b6c93fd33 100644
--- a/code/controllers/subsystem/SSticker.dm
+++ b/code/controllers/subsystem/SSticker.dm
@@ -225,7 +225,7 @@ SUBSYSTEM_DEF(ticker)
P.ready = FALSE
//Configure mode and assign player to special mode stuff
- mode.pre_pre_setup()
+
var/can_continue = FALSE
can_continue = mode.pre_setup() //Setup special modes. This also does the antag fishing checks.
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 6b4aab83cb3f0..5fbe68087c42a 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -1540,29 +1540,30 @@
* Create and/or add the `datum_type_or_instance` antag datum to the src mind.
*
* Arguments:
- * * datum_type - an antag datum typepath or instance
+ * * antag_datum - an antag datum typepath or instance. If it's a typepath, it will create a new antag datum
* * datum/team/team - the antag team that the src mind should join, if any
*/
-/datum/mind/proc/add_antag_datum(datum_type_or_instance, datum/team/team = null)
- var/datum/antagonist/A
+/datum/mind/proc/add_antag_datum(datum_type_or_instance, datum/team/team)
+ var/datum/antagonist/antag_datum
if(!ispath(datum_type_or_instance))
- A = datum_type_or_instance
- if(!istype(A))
+ antag_datum = datum_type_or_instance
+ if(!istype(antag_datum))
return
else
- A = new datum_type_or_instance()
- if(!A.can_be_owned(src))
- qdel(A)
+ antag_datum = new datum_type_or_instance()
+
+ if(!antag_datum.can_be_owned(src))
+ qdel(antag_datum)
return
- A.owner = src
- LAZYADD(antag_datums, A)
- A.create_team(team)
- var/datum/team/antag_team = A.get_team()
+ antag_datum.owner = src
+ LAZYADD(antag_datums, antag_datum)
+ antag_datum.create_team(team)
+ var/datum/team/antag_team = antag_datum.get_team()
if(antag_team)
antag_team.add_member(src)
- ASSERT(A.owner && A.owner.current)
- A.on_gain()
- return A
+ ASSERT(antag_datum.owner && antag_datum.owner.current)
+ antag_datum.on_gain()
+ return antag_datum
/**
* Remove the specified `datum_type` antag datum from the src mind.
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 416f7f9272d80..866d264108f0e 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -104,23 +104,17 @@
/datum/game_mode/proc/can_start()
var/playerC = 0
for(var/mob/new_player/player in GLOB.player_list)
- if((player.client)&&(player.ready))
+ if((player.client) && (player.ready))
playerC++
if(!GLOB.configuration.gamemode.enable_gamemode_player_limit || (playerC >= required_players))
- return 1
- return 0
-
-//pre_pre_setup() For when you really don't want certain jobs ingame.
-/datum/game_mode/proc/pre_pre_setup()
-
- return 1
+ return TRUE
+ return FALSE
///pre_setup()
///Attempts to select players for special roles the mode might have.
/datum/game_mode/proc/pre_setup()
-
- return 1
+ return TRUE
///post_setup()
@@ -137,12 +131,12 @@
GLOB.start_state = new /datum/station_state()
GLOB.start_state.count()
- return 1
+ return TRUE
///process()
///Called by the gameticker
/datum/game_mode/process()
- return 0
+ return FALSE
// I wonder what this could do guessing by the name
/datum/game_mode/proc/set_mode_in_db()
@@ -264,11 +258,9 @@
if(rev_team)
rev_team.check_all_victory()
-/datum/game_mode/proc/get_players_for_role(role, override_jobbans=0)
+/datum/game_mode/proc/get_players_for_role(role, override_jobbans = FALSE)
var/list/players = list()
var/list/candidates = list()
- //var/list/drafted = list()
- //var/datum/mind/applicant = null
var/roletext = get_roletext(role)
@@ -293,29 +285,56 @@
// Remove candidates who want to be antagonist but have a job that precludes it
if(restricted_jobs)
for(var/datum/mind/player in candidates)
- for(var/job in restricted_jobs)
- if(player.assigned_role == job)
- candidates -= player
+ if(player.assigned_role in restricted_jobs)
+ candidates -= player
return candidates // Returns: The number of people who had the antagonist role set to yes, regardless of recomended_enemies, if that number is greater than recommended_enemies
// recommended_enemies if the number of people with that role set to yes is less than recomended_enemies,
// Less if there are not enough valid players in the game entirely to make recommended_enemies.
+// Just the above proc but for alive players
+/// Gets all alive players for a specific role. Disables offstation roles by default
+/datum/game_mode/proc/get_alive_players_for_role(role, override_jobbans = FALSE, allow_offstation_roles = FALSE)
+ var/list/players = list()
+ var/list/candidates = list()
+
+ var/roletext = get_roletext(role)
+
+ // Assemble a list of active players without jobbans.
+ for(var/mob/living/carbon/human/player in GLOB.player_list)
+ if(!player.client || (locate(player) in SSafk.afk_players))
+ continue
+ if(!jobban_isbanned(player, ROLE_SYNDICATE) && !jobban_isbanned(player, roletext))
+ players += player
+
+ // Shuffle the players list so that it becomes ping-independent.
+ players = shuffle(players)
+
+ // Get a list of all the people who want to be the antagonist for this round, except those with incompatible species
+ for(var/mob/living/carbon/human/player in players)
+ if(player.client.skip_antag || !(allow_offstation_roles || !player.mind?.offstation_role))
+ continue
+
+ if(!(role in player.client.prefs.be_special) || (player.client.prefs.active_character.species in protected_species))
+ continue
+
+ player_draft_log += "[player.key] had [roletext] enabled, so we are drafting them."
+ candidates += player.mind
+ players -= player
+
+ // Remove candidates who want to be antagonist but have a job that precludes it
+ if(restricted_jobs)
+ for(var/datum/mind/player in candidates)
+ if(player.assigned_role in restricted_jobs)
+ candidates -= player
+ return candidates
/datum/game_mode/proc/latespawn(mob)
if(rev_team)
rev_team.update_team_objectives()
rev_team.process_promotion(REVOLUTION_PROMOTION_OPTIONAL)
-
-/*
-/datum/game_mode/proc/check_player_role_pref(role, mob/player)
- if(player.preferences.be_special & role)
- return 1
- return 0
-*/
-
/datum/game_mode/proc/num_players()
. = 0
for(var/mob/new_player/P in GLOB.player_list)
@@ -606,3 +625,34 @@
. += auto_declare_completion_revolution()
. += auto_declare_completion_abduction()
listclearnulls(.)
+
+/// Returns how many traitors should be added to the round
+/datum/game_mode/proc/traitors_to_add()
+ return 0
+
+/datum/game_mode/proc/fill_antag_slots()
+ var/traitors_to_add = 0
+
+ traitors_to_add += traitors_to_add()
+
+ if(length(traitors) < traitors_to_add())
+ traitors_to_add += (traitors_to_add() - length(traitors))
+
+ if(!traitors_to_add)
+ return
+
+ var/list/potential_recruits = get_alive_players_for_role(ROLE_TRAITOR)
+ for(var/datum/mind/candidate as anything in potential_recruits)
+ if(candidate.special_role) // no traitor vampires or changelings or traitors or wizards or ... yeah you get the deal
+ potential_recruits.Remove(candidate)
+
+ if(!length(potential_recruits))
+ return
+
+ log_admin("Attempting to add [traitors_to_add] traitors to the round. There are [length(potential_recruits)] potential recruits.")
+
+ for(var/i in 1 to traitors_to_add)
+ var/datum/mind/traitor = pick_n_take(potential_recruits)
+ traitor.special_role = SPECIAL_ROLE_TRAITOR
+ traitor.restricted_roles = restricted_jobs
+ traitor.add_antag_datum(/datum/antagonist/traitor) // They immediately get a new objective
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 235845fc80962..931e04b8f30fa 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -35,7 +35,10 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
var/datum/objective_holder/holder
-/datum/objective/New(text, datum/team/team_to_join)
+ /// What is the text we show when our objective is delayed?
+ var/delayed_objective_text = "This is a bug! Report it on the github and ask an admin what type of objective"
+
+/datum/objective/New(text, datum/team/team_to_join, datum/mind/_owner)
. = ..()
SHOULD_CALL_PARENT(TRUE)
GLOB.all_objectives += src
@@ -43,6 +46,8 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
explanation_text = text
if(team_to_join)
team = team_to_join
+ if(_owner)
+ owner = _owner
/datum/objective/Destroy()
GLOB.all_objectives -= src
@@ -120,7 +125,6 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
possible_targets += possible_target
-
if(length(possible_targets) > 0)
target = pick(possible_targets)
@@ -160,6 +164,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
/datum/objective/assassinate
name = "Assassinate"
martyr_compatible = TRUE
+ delayed_objective_text = "Your objective is to assassinate another crewmember. You will receive further information in a few minutes."
/datum/objective/assassinate/update_explanation_text()
if(target?.current)
@@ -181,6 +186,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
/datum/objective/assassinateonce
name = "Assassinate once"
martyr_compatible = TRUE
+ delayed_objective_text = "Your objective is to teach another crewmember a lesson. You will receive further information in a few minutes."
var/won = FALSE
/datum/objective/assassinateonce/update_explanation_text()
@@ -244,6 +250,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
/datum/objective/maroon
name = "Maroon"
martyr_compatible = FALSE
+ delayed_objective_text = "Your objective is to make sure another crewmember doesn't leave on the Escape Shuttle. You will receive further information in a few minutes."
/datum/objective/maroon/update_explanation_text()
if(target?.current)
@@ -265,11 +272,11 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
return TRUE
return TRUE
-
/// I want braaaainssss
/datum/objective/debrain
name = "Debrain"
martyr_compatible = FALSE
+ delayed_objective_text = "Your objective is to steal another crewmember's brain. You will receive further information in a few minutes."
/datum/objective/debrain/is_invalid_target(datum/mind/possible_target)
. = ..()
@@ -433,7 +440,6 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
return TRUE
-
/datum/objective/escape/escape_with_identity
name = null
/// Stored because the target's `[mob/var/real_name]` can change over the course of the round.
@@ -526,9 +532,10 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
/datum/objective/steal
name = "Steal Item"
- var/datum/theft_objective/steal_target
martyr_compatible = FALSE
+ delayed_objective_text = "Your objective is to steal a high-value item. You will receive further information in a few minutes."
var/theft_area
+ var/datum/theft_objective/steal_target
/datum/objective/steal/found_target()
return steal_target
@@ -552,7 +559,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
continue
if(!O.check_objective_conditions())
continue
- if(O.flags & 2) // THEFT_FLAG_UNIQUE
+ if(O.flags & THEFT_FLAG_UNIQUE)
continue
steal_target = O
@@ -649,7 +656,6 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
to_chat(failed_receiver, "Unfortunately, you weren't able to get a stealing kit. This is very bad and you should adminhelp immediately (press F1).")
message_admins("[ADMIN_LOOKUPFLW(failed_receiver)] Failed to spawn with their [item_path] theft kit.")
-
/datum/objective/absorb
name = "Absorb DNA"
needs_target = FALSE
@@ -691,6 +697,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
/datum/objective/destroy
name = "Destroy AI"
martyr_compatible = TRUE
+ delayed_objective_text = "Your objective is to destroy an Artificial Intelligence. You will receive further information in a few minutes."
/datum/objective/destroy/find_target(list/target_blacklist)
var/list/possible_targets = active_ais(1)
@@ -823,3 +830,23 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
explanation_text = "Hunger grows within us, we need to feast on the brains of the uninfected. Scratch, bite, and spread the plague."
needs_target = FALSE
completed = TRUE
+
+// Placeholder objectives that will replace themselves
+
+/datum/objective/delayed
+ needs_target = FALSE
+ var/datum/objective/objective_to_replace_with
+
+/datum/objective/delayed/New(datum/objective/delayed_objective)
+ ..()
+ if(!ispath(delayed_objective))
+ stack_trace("A delayed objective has been given a non-path. Given was instead [delayed_objective]")
+ return
+ objective_to_replace_with = delayed_objective
+ explanation_text = initial(delayed_objective.delayed_objective_text)
+
+/datum/objective/delayed/update_explanation_text()
+ return
+
+/datum/objective/delayed/proc/reveal_objective()
+ return holder.replace_objective(src, objective_to_replace_with)
diff --git a/code/game/gamemodes/objective_holder.dm b/code/game/gamemodes/objective_holder.dm
index 2b65e1eb7b47a..057d07d6def4f 100644
--- a/code/game/gamemodes/objective_holder.dm
+++ b/code/game/gamemodes/objective_holder.dm
@@ -59,9 +59,11 @@
* Replace old_objective with new_objective
*/
/datum/objective_holder/proc/replace_objective(datum/objective/old_objective, datum/objective/new_objective)
+ if(ispath(new_objective))
+ new_objective = new(null, old_objective.team, old_objective.owner)
+
new_objective = add_objective(new_objective, add_to_list = FALSE)
- new_objective.owner = old_objective.owner
- new_objective.team = old_objective.team
+
// Replace where the old objective was, with the new one
objectives.Insert(objectives.Find(old_objective), new_objective)
remove_objective(old_objective)
@@ -106,7 +108,7 @@
/datum/objective_holder/proc/handle_objective(datum/objective/Objective)
for(var/loop in 1 to 5)
Objective.find_target(assigned_targets)
- if(Objective.found_target()) // handles normal objectives, and steal objectives
+ if(Objective.found_target()) // Handles normal objectives, and steal objectives
return
// We failed to find any target. Oh well...
diff --git a/code/game/gamemodes/steal_items.dm b/code/game/gamemodes/steal_items.dm
index c74a0200a685e..1122ec65ef190 100644
--- a/code/game/gamemodes/steal_items.dm
+++ b/code/game/gamemodes/steal_items.dm
@@ -2,9 +2,6 @@
//
// Separated into datums so we can prevent roles from getting certain objectives.
-#define THEFT_FLAG_SPECIAL 1//unused, maybe someone will use it some day, I'll leave it here for the children
-#define THEFT_FLAG_UNIQUE 2
-
/datum/theft_objective
var/name = "this objective is impossible, yell at a coder"
var/typepath=/obj/effect/debugging
diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm
index e8c2249efdd83..9dda5bec3f58b 100644
--- a/code/game/gamemodes/traitor/traitor.dm
+++ b/code/game/gamemodes/traitor/traitor.dm
@@ -17,7 +17,6 @@
to_chat(world, "The current game mode is - Traitor!")
to_chat(world, "There is a syndicate traitor on the station. Do not let the traitor succeed!")
-
/datum/game_mode/traitor/pre_setup()
if(GLOB.configuration.gamemode.prevent_mindshield_antags)
@@ -35,10 +34,7 @@
var/num_traitors = 1
- if(GLOB.configuration.gamemode.traitor_scaling)
- num_traitors = max(1, round((num_players())/(traitor_scaling_coeff)))
- else
- num_traitors = max(1, min(num_players(), traitors_possible))
+ num_traitors = traitors_to_add()
for(var/i in 1 to num_traitors)
if(!length(possible_traitors))
@@ -52,13 +48,35 @@
return FALSE
return TRUE
-
/datum/game_mode/traitor/post_setup()
- for(var/t in pre_traitors)
- var/datum/mind/traitor = t
- traitor.add_antag_datum(/datum/antagonist/traitor)
- ..()
+ . = ..()
+
+ var/random_time = rand(5 MINUTES, 15 MINUTES)
+ if(length(pre_traitors))
+ addtimer(CALLBACK(src, PROC_REF(fill_antag_slots)), random_time)
+
+ for(var/datum/mind/traitor in pre_traitors)
+ var/datum/antagonist/traitor/traitor_datum = new(src)
+ if(ishuman(traitor.current))
+ traitor_datum.delayed_objectives = TRUE
+ traitor_datum.addtimer(CALLBACK(traitor_datum, TYPE_PROC_REF(/datum/antagonist/traitor, reveal_delayed_objectives)), random_time, TIMER_DELETE_ME)
+
+ traitor.add_antag_datum(traitor_datum)
+
+/datum/game_mode/traitor/traitors_to_add()
+ if(GLOB.configuration.gamemode.traitor_scaling)
+ . = max(1, round(num_players() / traitor_scaling_coeff))
+ else
+ . = max(1, min(num_players(), traitors_possible))
+
+ if(!length(traitors))
+ return
+ for(var/datum/mind/traitor_mind as anything in traitors)
+ if(!QDELETED(traitor_mind) && traitor_mind.current) // Explicitly no client check in case you happen to fall SSD when this gets ran
+ continue
+ .++
+ traitors -= traitor_mind
/datum/game_mode/traitor/declare_completion()
..()
diff --git a/code/game/gamemodes/trifecta/trifecta.dm b/code/game/gamemodes/trifecta/trifecta.dm
index 61bd9188ffac9..13ed99be84a5b 100644
--- a/code/game/gamemodes/trifecta/trifecta.dm
+++ b/code/game/gamemodes/trifecta/trifecta.dm
@@ -20,14 +20,16 @@
var/amount_vamp = 1
var/amount_cling = 1
var/amount_tot = 1
+ /// How many points did we get at roundstart
+ var/cost_at_roundstart
/datum/game_mode/trifecta/announce()
to_chat(world, "The current game mode is - Trifecta")
to_chat(world, "Vampires, traitors, and changelings, oh my! Stay safe as these forces work to bring down the station.")
-
/datum/game_mode/trifecta/pre_setup()
calculate_quantities()
+ cost_at_roundstart = num_players()
if(GLOB.configuration.gamemode.prevent_mindshield_antags)
restricted_jobs += protected_jobs
var/list/datum/mind/possible_vampires = get_players_for_role(ROLE_VAMPIRE)
@@ -101,12 +103,38 @@
/datum/game_mode/trifecta/post_setup()
for(var/datum/mind/vampire as anything in pre_vampires)
vampire.add_antag_datum(/datum/antagonist/vampire)
+
for(var/datum/mind/changeling as anything in pre_changelings)
changeling.add_antag_datum(/datum/antagonist/changeling)
+
for(var/datum/mind/traitor as anything in pre_traitors)
- traitor.add_antag_datum(/datum/antagonist/traitor)
+ var/datum/antagonist/traitor/tot_datum = new()
+ tot_datum.delayed_objectives = TRUE
+ traitor.add_antag_datum(tot_datum)
+
+ if(length(pre_traitors))
+ var/random_time = rand(5 MINUTES, 15 MINUTES)
+ addtimer(CALLBACK(src, PROC_REF(fill_antag_slots)), random_time)
+
..()
+/datum/game_mode/trifecta/traitors_to_add()
+ . = 0
+ for(var/datum/mind/traitor_mind as anything in traitors)
+ if(!QDELETED(traitor_mind) && traitor_mind.current) // Explicitly no client check in case you happen to fall SSD when this gets ran
+ continue
+ .++
+ traitors -= traitor_mind
+
+ var/extra_points = num_players_started() - cost_at_roundstart
+ if(extra_points - TOT_COST < 0)
+ return 0 // Not enough new players to add extra tots
+
+ while(extra_points)
+ .++
+ if(extra_points < TOT_COST) // The leftover change is enough for us to buy another traitor with, what a deal!
+ return
+ extra_points -= TOT_COST
#undef TOT_COST
#undef VAMP_COST
diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm
index 28c6d0ce9ec72..fa4f1eb694d68 100644
--- a/code/modules/antagonists/_common/antag_datum.dm
+++ b/code/modules/antagonists/_common/antag_datum.dm
@@ -55,6 +55,9 @@ GLOBAL_LIST_EMPTY(antagonists)
var/blurb_b = 0
var/blurb_a = 0
+ /// Do we have delayed objective giving?
+ var/delayed_objectives = FALSE
+
/datum/antagonist/New()
GLOB.antagonists += src
objective_holder = new(src)
@@ -236,14 +239,15 @@ GLOBAL_LIST_EMPTY(antagonists)
* * explanation_text - the explanation text that will be passed into the objective's `New()` proc
* * mob/target_override - a target for the objective
*/
-/datum/antagonist/proc/add_antag_objective(datum/objective/O, explanation_text, mob/target_override)
- if(ispath(O))
- O = new O()
- if(O.owner)
- stack_trace("[O], [O.type] was assigned as an objective to [owner] (mind), but already had an owner: [O.owner] (mind). Overriding.")
- O.owner = owner
-
- return objective_holder.add_objective(O, explanation_text, target_override)
+/datum/antagonist/proc/add_antag_objective(datum/objective/objective_to_add, explanation_text, mob/target_override)
+ if(ispath(objective_to_add))
+ objective_to_add = new objective_to_add()
+
+ if(objective_to_add.owner)
+ stack_trace("[objective_to_add], [objective_to_add.type] was assigned as an objective to [owner] (mind), but already had an owner: [objective_to_add.owner] (mind). Overriding.")
+ objective_to_add.owner = owner
+
+ return objective_holder.add_objective(objective_to_add, explanation_text, target_override)
/**
* Complement to add_antag_objective that removes the objective.
diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm
index 3657a61b69785..f4ad986352783 100644
--- a/code/modules/antagonists/traitor/datum_traitor.dm
+++ b/code/modules/antagonists/traitor/datum_traitor.dm
@@ -136,19 +136,29 @@ RESTRICT_TYPE(/datum/antagonist/traitor)
* Create and assign a single randomized human traitor objective.
*/
/datum/antagonist/traitor/proc/forge_single_human_objective()
+ var/datum/objective/objective_to_add
+
if(prob(50))
if(length(active_ais()) && prob(100 / length(GLOB.player_list)))
- add_antag_objective(/datum/objective/destroy)
+ objective_to_add = /datum/objective/destroy
+
else if(prob(5))
- add_antag_objective(/datum/objective/debrain)
+ objective_to_add = /datum/objective/debrain
+
else if(prob(30))
- add_antag_objective(/datum/objective/maroon)
+ objective_to_add = /datum/objective/maroon
+
else if(prob(30))
- add_antag_objective(/datum/objective/assassinateonce)
+ objective_to_add = /datum/objective/assassinateonce
+
else
- add_antag_objective(/datum/objective/assassinate)
+ objective_to_add = /datum/objective/assassinate
else
- add_antag_objective(/datum/objective/steal)
+ objective_to_add = /datum/objective/steal
+
+ if(delayed_objectives)
+ objective_to_add = new /datum/objective/delayed(objective_to_add)
+ add_antag_objective(objective_to_add)
/**
* Give human traitors their uplink, and AI traitors their law 0. Play the traitor an alert sound.
@@ -267,3 +277,14 @@ RESTRICT_TYPE(/datum/antagonist/traitor)
/datum/antagonist/traitor/custom_blurb()
return "[GLOB.current_date_string], [station_time_timestamp()]\n[station_name()], [get_area_name(owner.current, TRUE)]\nBEGIN_MISSION"
+
+/datum/antagonist/traitor/proc/reveal_delayed_objectives()
+ for(var/datum/objective/delayed/delayed_obj in objective_holder.objectives)
+ delayed_obj.reveal_objective()
+
+ if(!owner?.current)
+ return
+ SEND_SOUND(owner.current, sound('sound/ambience/alarm4.ogg'))
+ var/list/messages = owner.prepare_announce_objectives()
+ to_chat(owner.current, chat_box_red(messages.Join("
")))
+ delayed_objectives = FALSE