mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-22 03:27:05 +01:00
Delays handing out of Traitor objectives (#24857)
* Idk man * IT WORKS * SO CLOSE TO GREATNESS * IT ALL WORKS AAAAAA * Actually add a random timer * Oopsie * Removes empty proc * Update code/game/gamemodes/traitor/traitor.dm Co-authored-by: SteelSlayer <42044220+SteelSlayer@users.noreply.github.com> * Contra requested changes * Adds randomness to random_time * Whoops * Contra + AA Review * Removes TODO * Reverts standard mode * Makes CI not fail * Removes unused proc * FUCK * Fixes a kit bug (Thanks Erik) * Tourte Review * Matt review * Changes text, adds admin logs * Clarifies the log * New and improved version! * Fixes * Revert "Fixes" This reverts commitea29aa92b2. * Revert "New and improved version!" This reverts commitea053f3b94. * Properly rerolls objectives at handout * Adds trifecta support * Contra and Sirryan review * Forgor this * Fix CI * Final fixes * Update code/game/gamemodes/traitor/traitor.dm Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com> Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com> * Update code/game/gamemodes/trifecta/trifecta.dm Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com> Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com> * Steel review * Wow I was silly * Less whitespace * Dumbest bug in a while * No more lavaland player getting autobalanced * Streamlines a proc + another fix * AAAAA FUCK * Update code/game/gamemodes/objective.dm Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com> Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com> * Update code/game/gamemodes/objective.dm Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com> * Contra review * Faire review * Forgor to push this * Farie + Contra review * Hal + Contra review * Uses `replaceobjective` now + Fix * Farie review * Farie review * Farie review 2: electric bogaloo * Fix * Update code/game/gamemodes/objective_holder.dm Co-authored-by: Farie82 <farie82@users.noreply.github.com> Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com> * Contra review * Update code/game/gamemodes/objective_holder.dm Co-authored-by: Farie82 <farie82@users.noreply.github.com> Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com> --------- Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com> Co-authored-by: SteelSlayer <42044220+SteelSlayer@users.noreply.github.com> Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com> Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com> Co-authored-by: Farie82 <farie82@users.noreply.github.com>
This commit is contained in:
co-authored by
SteelSlayer
Ryan
Contrabang
Farie82
parent
98f0931c14
commit
3f8aff4374
@@ -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))
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
+16
-15
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, "<span class='userdanger'>Unfortunately, you weren't able to get a stealing kit. This is very bad and you should adminhelp immediately (press F1).</span>")
|
||||
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)
|
||||
|
||||
@@ -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...
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
to_chat(world, "<B>The current game mode is - Traitor!</B>")
|
||||
to_chat(world, "<B>There is a syndicate traitor on the station. Do not let the traitor succeed!</B>")
|
||||
|
||||
|
||||
/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()
|
||||
..()
|
||||
|
||||
@@ -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, "<b>The current game mode is - Trifecta</b>")
|
||||
to_chat(world, "<b>Vampires, traitors, and changelings, oh my! Stay safe as these forces work to bring down the station.</b>")
|
||||
|
||||
|
||||
/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
|
||||
|
||||
@@ -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
|
||||
/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()
|
||||
|
||||
return objective_holder.add_objective(O, explanation_text, target_override)
|
||||
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.
|
||||
|
||||
@@ -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("<br>")))
|
||||
delayed_objectives = FALSE
|
||||
|
||||
Reference in New Issue
Block a user