diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets.dm b/code/game/gamemodes/dynamic/dynamic_rulesets.dm index b742f6f36c0b..6389dd5a9494 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets.dm @@ -196,27 +196,23 @@ /// Checks if candidates are connected and if they are banned or don't want to be the antagonist. /datum/dynamic_ruleset/roundstart/trim_candidates() + var/list/real_candidates = list() for(var/mob/dead/new_player/candidate_player in candidates) var/client/candidate_client = GET_CLIENT(candidate_player) if (!candidate_client || !candidate_player.mind) // Are they connected? - candidates.Remove(candidate_player) continue else if(!mode.check_age(candidate_client, minimum_required_age)) - candidates.Remove(candidate_player) continue if(candidate_player.mind.special_role) // We really don't want to give antag to an antag. - candidates.Remove(candidate_player) continue if(antag_flag_override) if(!(HAS_ANTAG_PREF(candidate_player.client, antag_flag_override))) - candidates.Remove(candidate_player) continue else if(!(HAS_ANTAG_PREF(candidate_player.client, antag_flag))) - candidates.Remove(candidate_player) continue // If this ruleset has exclusive_roles set, we want to only consider players who have those @@ -232,7 +228,9 @@ // If they didn't have any of the required job prefs enabled or were banned from all enabled prefs, // they're not eligible for this antag type. if(!exclusive_candidate) - candidates.Remove(candidate_player) + continue + real_candidates += candidate_player.mind + candidates = real_candidates /// Do your checks if the ruleset is ready to be executed here. /// Should ignore certain checks if forced is TRUE diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm index 4dbe7a4387cb..dd495fc1205f 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -85,7 +85,7 @@ cost = 20 requirements = list(101,101,101,101,50,20,20,20,20,20) flags = HIGH_IMPACT_RULESET - blocking_rules = list(/datum/dynamic_ruleset/roundstart/revs) + blocking_rules = list(/datum/dynamic_ruleset/roundstart/on_station/revs) var/required_heads_of_staff = 3 var/finished = FALSE /// How much threat should be injected when the revolution wins? diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index b6de6c300a4a..087ec565c4e3 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -216,13 +216,15 @@ /datum/dynamic_ruleset/midround/autotraitor/trim_candidates() ..() + candidates = list() for(var/mob/living/player in living_players) if(issilicon(player)) // Your assigned role doesn't change when you are turned into a silicon. - living_players -= player + continue else if(is_centcom_level(player.z)) - living_players -= player // We don't autotator people in CentCom + continue // We don't autotator people in CentCom else if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0)) - living_players -= player // We don't autotator people with roles already + continue // We don't autotator people with roles already + candidates += player.mind /datum/dynamic_ruleset/midround/autotraitor/ready(forced = FALSE) if (required_candidates > living_players.len) @@ -230,12 +232,12 @@ return ..() /datum/dynamic_ruleset/midround/autotraitor/execute() - var/mob/M = pick(living_players) + var/datum/mind/M = antag_pick(candidates) assigned += M - living_players -= M + living_players -= M.current var/datum/antagonist/traitor/newTraitor = new - M.mind.add_antag_datum(newTraitor) - message_admins("[ADMIN_LOOKUPFLW(M)] was selected by the [name] ruleset and has been made into a midround traitor.") + M.add_antag_datum(newTraitor) + message_admins("[ADMIN_LOOKUPFLW(M.current)] was selected by the [name] ruleset and has been made into a midround traitor.") log_game("DYNAMIC: [key_name(M)] was selected by the [name] ruleset and has been made into a midround traitor.") return TRUE @@ -323,33 +325,33 @@ /datum/dynamic_ruleset/midround/malf/trim_candidates() ..() - candidates = living_players + candidates = list() for(var/mob/living/player in candidates) if(!isAI(player)) - candidates -= player continue if(is_centcom_level(player.z)) - candidates -= player continue if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0)) - candidates -= player + continue + candidates += player.mind /datum/dynamic_ruleset/midround/malf/execute() if(!candidates || !candidates.len) return FALSE - var/mob/living/silicon/ai/M = pick_n_take(candidates) - assigned += M.mind - var/datum/antagonist/traitor/AI = new - M.mind.special_role = antag_flag - M.mind.add_antag_datum(AI) + var/datum/mind/M = antag_pick(candidates) + assigned += M + var/datum/antagonist/traitor/malf = new + M.special_role = antag_flag + M.add_antag_datum(malf) if(prob(MALF_ION_PROB)) + var/mob/living/silicon/ai = M.current priority_announce("Ion storm detected near the station. Please check all AI-controlled equipment for errors.", "Anomaly Alert", "ionstorm") if(prob(REPLACE_LAW_WITH_ION_PROB)) - M.replace_random_law(generate_ion_law(), list(LAW_INHERENT, LAW_SUPPLIED, LAW_ION)) + ai.replace_random_law(generate_ion_law(), list(LAW_INHERENT, LAW_SUPPLIED, LAW_ION)) else - M.add_ion_law(generate_ion_law()) + ai.add_ion_law(generate_ion_law()) return TRUE ////////////////////////////////////////////// @@ -467,7 +469,7 @@ flags = HIGH_IMPACT_RULESET /datum/dynamic_ruleset/midround/ratvar_awakening/acceptable(population=0, threat=0) - if (locate(/datum/dynamic_ruleset/roundstart/clockcult) in mode.executed_rules) + if (locate(/datum/dynamic_ruleset/roundstart/on_station/clockcult) in mode.executed_rules) return FALSE // Unavailable if clockies exist at round start indice_pop = min(clock_cap.len, round(living_players.len/5)+1) required_candidates = clock_cap[indice_pop] diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index a9d0ec7d3cda..467749ad1102 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -1,11 +1,27 @@ +/datum/dynamic_ruleset/roundstart/on_station + weight = 0 + requirements = list(101,101,101,101,101,101,101,101,101,101) + minimum_players = INFINITY // it's abstract + +/datum/dynamic_ruleset/roundstart/on_station/pre_execute(population) + . = ..() + var/max_candidates = get_antag_cap(population) + var/list/picked = antag_pick(candidates, max_candidates) + for(var/m in picked) + var/datum/mind/M = m + assigned += M + M.restricted_roles = restricted_roles + M.special_role = antag_flag + return TRUE + ////////////////////////////////////////////// // // // SYNDICATE TRAITORS // // // ////////////////////////////////////////////// -/datum/dynamic_ruleset/roundstart/traitor +/datum/dynamic_ruleset/roundstart/on_station/traitor name = "Traitors" persistent = TRUE antag_flag = ROLE_TRAITOR @@ -22,18 +38,11 @@ var/autotraitor_cooldown = (15 MINUTES) COOLDOWN_DECLARE(autotraitor_cooldown_check) -/datum/dynamic_ruleset/roundstart/traitor/pre_execute(population) +/datum/dynamic_ruleset/roundstart/on_station/traitor/pre_execute(population) . = ..() COOLDOWN_START(src, autotraitor_cooldown_check, autotraitor_cooldown) - var/num_traitors = get_antag_cap(population) * (scaled_times + 1) - for (var/i = 1 to num_traitors) - var/mob/M = pick_n_take(candidates) - assigned += M.mind - M.mind.special_role = ROLE_TRAITOR - M.mind.restricted_roles = restricted_roles - return TRUE -/datum/dynamic_ruleset/roundstart/traitor/rule_process() +/datum/dynamic_ruleset/roundstart/on_station/traitor/rule_process() if (COOLDOWN_FINISHED(src, autotraitor_cooldown_check)) COOLDOWN_START(src, autotraitor_cooldown_check, autotraitor_cooldown) log_game("DYNAMIC: Checking if we can turn someone into a traitor.") @@ -68,12 +77,14 @@ break var/datum/team/brother_team/team = new var/team_size = prob(10) ? min(3, candidates.len) : 2 - for(var/k = 1 to team_size) - var/mob/bro = pick_n_take(candidates) - assigned += bro.mind - team.add_member(bro.mind) - bro.mind.special_role = "brother" - bro.mind.restricted_roles = restricted_roles + var/list/picked = antag_pick(candidates, team_size) + candidates -= picked + for(var/m in picked) + var/datum/mind/M = picked + assigned += M + team.add_member(M) + M.special_role = "brother" + M.restricted_roles = restricted_roles pre_brother_teams += team return TRUE @@ -93,7 +104,7 @@ // // ////////////////////////////////////////////// -/datum/dynamic_ruleset/roundstart/changeling +/datum/dynamic_ruleset/roundstart/on_station/changeling name = "Changelings" antag_flag = ROLE_CHANGELING antag_datum = /datum/antagonist/changeling @@ -106,29 +117,13 @@ requirements = list(101,60,50,40,30,20,15,10,10,10) antag_cap = list("denominator" = 29) -/datum/dynamic_ruleset/roundstart/changeling/pre_execute(population) - . = ..() - var/num_changelings = get_antag_cap(population) * (scaled_times + 1) - for (var/i = 1 to num_changelings) - var/mob/M = pick_n_take(candidates) - assigned += M.mind - M.mind.restricted_roles = restricted_roles - M.mind.special_role = ROLE_CHANGELING - return TRUE - -/datum/dynamic_ruleset/roundstart/changeling/execute() - for(var/datum/mind/changeling in assigned) - var/datum/antagonist/changeling/new_antag = new antag_datum() - changeling.add_antag_datum(new_antag) - return TRUE - ////////////////////////////////////////////// // // // ELDRITCH CULT // // // ////////////////////////////////////////////// -/datum/dynamic_ruleset/roundstart/heretics +/datum/dynamic_ruleset/roundstart/on_station/heretics name = "Heretics" antag_flag = ROLE_HERETIC antag_datum = /datum/antagonist/heretic @@ -141,20 +136,7 @@ requirements = list(101,101,101,50,40,20,20,15,10,10)//higher because of 'round end' antag_cap = list("denominator" = 24) - -/datum/dynamic_ruleset/roundstart/heretics/pre_execute(population) - . = ..() - var/num_ecult = get_antag_cap(population) * (scaled_times + 1) - - for (var/i = 1 to num_ecult) - var/mob/picked_candidate = pick_n_take(candidates) - assigned += picked_candidate.mind - picked_candidate.mind.restricted_roles = restricted_roles - picked_candidate.mind.special_role = ROLE_HERETIC - return TRUE - -/datum/dynamic_ruleset/roundstart/heretics/execute() - +/datum/dynamic_ruleset/roundstart/on_station/heretics/execute() for(var/c in assigned) var/datum/mind/cultie = c var/datum/antagonist/heretic/new_antag = new antag_datum() @@ -193,11 +175,11 @@ . = ..() if(GLOB.wizardstart.len == 0) return FALSE - var/mob/M = pick_n_take(candidates) + var/datum/mind/M = antag_pick(candidates) if (M) - assigned += M.mind - M.mind.assigned_role = ROLE_WIZARD - M.mind.special_role = ROLE_WIZARD + assigned += M + M.assigned_role = ROLE_WIZARD + M.special_role = ROLE_WIZARD return TRUE @@ -213,7 +195,7 @@ // // ////////////////////////////////////////////// -/datum/dynamic_ruleset/roundstart/bloodcult +/datum/dynamic_ruleset/roundstart/on_station/bloodcult name = "Blood Cult" antag_flag = ROLE_CULTIST antag_datum = /datum/antagonist/cult @@ -228,23 +210,11 @@ antag_cap = list("denominator" = 20, "offset" = 1) var/datum/team/cult/main_cult -/datum/dynamic_ruleset/roundstart/bloodcult/ready(population, forced = FALSE) +/datum/dynamic_ruleset/roundstart/on_station/bloodcult/ready(population, forced = FALSE) required_candidates = get_antag_cap(population) . = ..() -/datum/dynamic_ruleset/roundstart/bloodcult/pre_execute(population) - . = ..() - var/cultists = get_antag_cap(population) - for(var/cultists_number = 1 to cultists) - if(candidates.len <= 0) - break - var/mob/M = pick_n_take(candidates) - assigned += M.mind - M.mind.special_role = ROLE_CULTIST - M.mind.restricted_roles = restricted_roles - return TRUE - -/datum/dynamic_ruleset/roundstart/bloodcult/execute() +/datum/dynamic_ruleset/roundstart/on_station/bloodcult/execute() main_cult = new for(var/datum/mind/M in assigned) var/datum/antagonist/cult/new_cultist = new antag_datum() @@ -254,7 +224,7 @@ main_cult.setup_objectives() return TRUE -/datum/dynamic_ruleset/roundstart/bloodcult/round_result() +/datum/dynamic_ruleset/roundstart/on_station/bloodcult/round_result() ..() if(main_cult.check_cult_victory()) SSticker.mode_result = "win - cult win" @@ -292,13 +262,12 @@ . = ..() // If ready() did its job, candidates should have 5 or more members in it var/operatives = get_antag_cap(population) - for(var/operatives_number = 1 to operatives) - if(candidates.len <= 0) - break - var/mob/M = pick_n_take(candidates) - assigned += M.mind - M.mind.assigned_role = "Nuclear Operative" - M.mind.special_role = "Nuclear Operative" + var/list/picked = antag_pick(candidates, operatives) + for(var/m in picked) + var/datum/mind/M = m + assigned += M + M.assigned_role = "Nuclear Operative" + M.special_role = "Nuclear Operative" return TRUE /datum/dynamic_ruleset/roundstart/nuclear/execute() @@ -353,7 +322,7 @@ // // ////////////////////////////////////////////// -/datum/dynamic_ruleset/roundstart/revs +/datum/dynamic_ruleset/roundstart/on_station/revs name = "Revolution" persistent = TRUE antag_flag = ROLE_REV_HEAD @@ -376,19 +345,7 @@ var/datum/team/revolution/revolution var/finished = FALSE -/datum/dynamic_ruleset/roundstart/revs/pre_execute(population) - . = ..() - var/max_candidates = get_antag_cap(population) - for(var/i = 1 to max_candidates) - if(candidates.len <= 0) - break - var/mob/M = pick_n_take(candidates) - assigned += M.mind - M.mind.restricted_roles = restricted_roles - M.mind.special_role = antag_flag - return TRUE - -/datum/dynamic_ruleset/roundstart/revs/execute() +/datum/dynamic_ruleset/roundstart/on_station/revs/execute() revolution = new() for(var/datum/mind/M in assigned) if(check_eligible(M)) @@ -408,11 +365,11 @@ log_game("DYNAMIC: [ruletype] [name] failed to get any eligible headrevs. Refunding [cost] threat.") return FALSE -/datum/dynamic_ruleset/roundstart/revs/clean_up() +/datum/dynamic_ruleset/roundstart/on_station/revs/clean_up() qdel(revolution) ..() -/datum/dynamic_ruleset/roundstart/revs/rule_process() +/datum/dynamic_ruleset/roundstart/on_station/revs/rule_process() var/winner = revolution.process_victory(revs_win_threat_injection) if (isnull(winner)) return @@ -421,13 +378,13 @@ return RULESET_STOP_PROCESSING /// Checks for revhead loss conditions and other antag datums. -/datum/dynamic_ruleset/roundstart/revs/proc/check_eligible(datum/mind/M) +/datum/dynamic_ruleset/roundstart/on_station/revs/proc/check_eligible(datum/mind/M) var/turf/T = get_turf(M.current) if(!considered_afk(M) && considered_alive(M) && is_station_level(T.z) && !M.antag_datums?.len && !HAS_TRAIT(M, TRAIT_MINDSHIELD)) return TRUE return FALSE -/datum/dynamic_ruleset/roundstart/revs/round_result() +/datum/dynamic_ruleset/roundstart/on_station/revs/round_result() revolution.round_result(finished) ////////////////////////////////////////////// @@ -436,7 +393,7 @@ // // ////////////////////////////////////////////// -/datum/dynamic_ruleset/roundstart/clockcult +/datum/dynamic_ruleset/roundstart/on_station/clockcult name = "Clock Cult" antag_flag = ROLE_SERVANT_OF_RATVAR antag_datum = /datum/antagonist/clockcult @@ -450,23 +407,11 @@ antag_cap = list("denominator" = 20, "offset" = 1) var/datum/team/clockcult/main_clockcult -/datum/dynamic_ruleset/roundstart/clockcult/ready(population, forced = FALSE) +/datum/dynamic_ruleset/roundstart/on_station/clockcult/ready(population, forced = FALSE) required_candidates = get_antag_cap(population) . = ..() -/datum/dynamic_ruleset/roundstart/clockcult/pre_execute(population) - . = ..() - var/cultists = get_antag_cap(population) - for(var/cultists_number = 1 to cultists) - if(candidates.len <= 0) - break - var/mob/M = pick_n_take(candidates) - assigned += M.mind - M.mind.special_role = ROLE_SERVANT_OF_RATVAR - M.mind.restricted_roles = restricted_roles - return TRUE - -/datum/dynamic_ruleset/roundstart/clockcult/execute() +/datum/dynamic_ruleset/roundstart/on_station/clockcult/execute() main_clockcult = new for(var/datum/mind/M in assigned) var/datum/antagonist/clockcult/new_cultist = new antag_datum() @@ -476,7 +421,7 @@ M.add_antag_datum(new_cultist) return TRUE -/datum/dynamic_ruleset/roundstart/clockcult/round_result() +/datum/dynamic_ruleset/roundstart/on_station/clockcult/round_result() ..() if(main_clockcult.check_clockwork_victory()) SSticker.mode_result = "win - servants completed their objective (summon ratvar)" diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 12dfc92cc4be..68a87d3e60ba 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -332,7 +332,7 @@ //More efficient if you use return list instead of calling this multiple times //fail_default_pick makes it use pick() instead of antag rep if it can't find anyone //allow_zero_if_insufficient allows it to pick people with zero rep if there isn't enough antags -/datum/game_mode/proc/antag_pick(list/datum/mind/candidates, return_list = FALSE, fail_default_pick = TRUE, allow_zero_if_insufficient = TRUE) +/proc/antag_pick(list/datum/mind/candidates, return_list = FALSE, fail_default_pick = TRUE, allow_zero_if_insufficient = TRUE) if(!CONFIG_GET(flag/use_antag_rep)) // || candidates.len <= 1) return pick(candidates) @@ -365,7 +365,7 @@ SSpersistence.antag_rep_change[ckey] = -(curr_tickets[ckey] - free_tickets) //deduct what they spent var/mind = ckey_to_mind[ckey] || (allow_zero_if_insufficient? pick(insufficient) : null) //we want their mind if(!mind) //no mind - var/warning = "WARNING: No antagonists were successfully picked by /datum/gamemode/proc/antag_pick()![fail_default_pick? " Defaulting to pick()!":""]" + var/warning = "WARNING: No antagonists were successfully picked by /proc/antag_pick()![fail_default_pick? " Defaulting to pick()!":""]" message_admins(warning) log_game(warning) if(fail_default_pick) @@ -390,7 +390,7 @@ var/datum/mind/M = pick_n_take(insufficient) add += M if(!length(rolled) && !length(add)) //if no one could normally roll AND no one can zero roll - var/warning = "WARNING: No antagonists were successfully picked by /datum/gamemode/proc/antag_pick()![fail_default_pick? " Defaulting to pick()!":""]" + var/warning = "WARNING: No antagonists were successfully picked by /proc/antag_pick()![fail_default_pick? " Defaulting to pick()!":""]" message_admins(warning) log_game(warning) var/list/failed = list() diff --git a/code/modules/unit_tests/dynamic_ruleset_sanity.dm b/code/modules/unit_tests/dynamic_ruleset_sanity.dm index 837e0b235cca..c473682964a9 100644 --- a/code/modules/unit_tests/dynamic_ruleset_sanity.dm +++ b/code/modules/unit_tests/dynamic_ruleset_sanity.dm @@ -5,6 +5,8 @@ for (var/_ruleset in subtypesof(/datum/dynamic_ruleset/roundstart)) var/datum/dynamic_ruleset/roundstart/ruleset = _ruleset + if(!initial(ruleset.weight)) + continue var/has_scaling_cost = initial(ruleset.scaling_cost) var/is_lone = initial(ruleset.flags) & (LONE_RULESET | HIGH_IMPACT_RULESET) diff --git a/config/entries/general.txt b/config/entries/general.txt index 3688b8197bda..4a7c5f4357c5 100644 --- a/config/entries/general.txt +++ b/config/entries/general.txt @@ -85,7 +85,7 @@ SHUTTLE_REFUEL_DELAY 12000 ## Comment this out to disable the antagonist reputation system. This system rewards players who participate in the game instead of greytiding by giving them slightly higher odds to ## roll antagonist in subsequent rounds until they get it. ## -## For details See the comments for /datum/game_mode/proc/antag_pick in code/game/gamemodes/game_mode.dm +## For details See the comments for /proc/antag_pick in code/game/gamemodes/game_mode.dm # USE_ANTAG_REP ## The maximum amount of antagonist reputation tickets a player can bank (not use at once)