Skip to content

Commit

Permalink
Delays handing out of Traitor objectives (ParadiseSS13#24857)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>

* 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 commit ea29aa9.

* Revert "New and improved version!"

This reverts commit ea053f3.

* 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 <[email protected]>
Signed-off-by: DGamerL <[email protected]>

* Update code/game/gamemodes/trifecta/trifecta.dm

Co-authored-by: Ryan <[email protected]>
Signed-off-by: DGamerL <[email protected]>

* 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 <[email protected]>
Signed-off-by: DGamerL <[email protected]>

* Update code/game/gamemodes/objective.dm

Signed-off-by: DGamerL <[email protected]>

* 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 <[email protected]>
Signed-off-by: DGamerL <[email protected]>

* Contra review

* Update code/game/gamemodes/objective_holder.dm

Co-authored-by: Farie82 <[email protected]>
Signed-off-by: DGamerL <[email protected]>

---------

Signed-off-by: DGamerL <[email protected]>
Co-authored-by: SteelSlayer <[email protected]>
Co-authored-by: Ryan <[email protected]>
Co-authored-by: Contrabang <[email protected]>
Co-authored-by: Farie82 <[email protected]>
  • Loading branch information
5 people authored Jul 24, 2024
1 parent 98f0931 commit 3f8aff4
Show file tree
Hide file tree
Showing 11 changed files with 239 additions and 81 deletions.
10 changes: 10 additions & 0 deletions code/__DEFINES/antag_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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))

2 changes: 1 addition & 1 deletion code/controllers/subsystem/SSticker.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
31 changes: 16 additions & 15 deletions code/datums/mind.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
102 changes: 76 additions & 26 deletions code/game/gamemodes/game_mode.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()
Expand Down Expand Up @@ -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)

Expand All @@ -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)
Expand Down Expand Up @@ -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
41 changes: 34 additions & 7 deletions code/game/gamemodes/objective.dm
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,19 @@ 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
if(text)
explanation_text = text
if(team_to_join)
team = team_to_join
if(_owner)
owner = _owner

/datum/objective/Destroy()
GLOB.all_objectives -= src
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)
Expand All @@ -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()
Expand Down Expand Up @@ -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)
Expand All @@ -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)
. = ..()
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
8 changes: 5 additions & 3 deletions code/game/gamemodes/objective_holder.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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...
Expand Down
3 changes: 0 additions & 3 deletions code/game/gamemodes/steal_items.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 3f8aff4

Please sign in to comment.