diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index ca009f76ad..473e2ae4a5 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -118,7 +118,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) /datum/game_mode/dynamic/admin_panel() var/list/dat = list("Game Mode Panel

Game Mode Panel

") - dat += "Dynamic Mode \[VV\]
" + dat += "Dynamic Mode \[VV\]\[Refresh\]
" dat += "Threat Level: [threat_level]
" dat += "Threat to Spend: [threat] \[Adjust\] \[View Log\]
" @@ -273,15 +273,6 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) threat = threat_level /datum/game_mode/dynamic/can_start() - /* Disabled for now, had some changes that need to be tested and this might interfere with that. - if(GLOB.dynamic_curve_centre == 0) - // 10 is when the centre starts to decrease - // 6 is just 1 + 5 (from the maximum value and the one decreased) - // 1 just makes the curve look better, I don't know. - // Limited between 1 and 5 then inverted and rounded - // With this you get a centre curve that stays at -5 until 10 then first rapidly decreases but slows down at the end - GLOB.dynamic_curve_centre = round(-CLAMP((10*6/GLOB.player_list.len)-1, 0, 5), 0.5) - */ message_admins("Dynamic mode parameters for the round:") message_admins("Centre is [GLOB.dynamic_curve_centre], Width is [GLOB.dynamic_curve_width], Forced extended is [GLOB.dynamic_forced_extended ? "Enabled" : "Disabled"], No stacking is [GLOB.dynamic_no_stacking ? "Enabled" : "Disabled"].") message_admins("Stacking limit is [GLOB.dynamic_stacking_limit], Classic secret is [GLOB.dynamic_classic_secret ? "Enabled" : "Disabled"], High population limit is [GLOB.dynamic_high_pop_limit].") @@ -342,8 +333,11 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) for(var/datum/dynamic_ruleset/roundstart/rule in executed_rules) rule.candidates.Cut() // The rule should not use candidates at this point as they all are null. - if(!rule.execute()) - stack_trace("The starting rule \"[rule.name]\" failed to execute.") + if(rule.delay > 0) + addtimer(CALLBACK(rule, /datum/dynamic_ruleset/roundstart.proc/execute), rule.delay) + else + if(!rule.execute()) + stack_trace("The starting rule \"[rule.name]\" failed to execute.") ..() /// A simple roundstart proc used when dynamic_forced_roundstart_ruleset has rules in it. @@ -427,16 +421,18 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) if(drafted_rules.len <= 0) return FALSE starting_rule = pickweight(drafted_rules) + // With low pop and high threat there might be rulesets that get executed with no valid candidates. + else if(starting_rule.ready()) + drafted_rules -= starting_rule + if(drafted_rules.len <= 0) + return FALSE + starting_rule = pickweight(drafted_rules) - log_game("DYNAMIC: Picking a [istype(starting_rule, /datum/dynamic_ruleset/roundstart/delayed/) ? " delayed " : ""] ruleset [starting_rule.name]") + log_game("DYNAMIC: Picking a ruleset [starting_rule.name]") roundstart_rules -= starting_rule drafted_rules -= starting_rule - if (istype(starting_rule, /datum/dynamic_ruleset/roundstart/delayed/)) - var/datum/dynamic_ruleset/roundstart/delayed/rule = starting_rule - addtimer(CALLBACK(src, .proc/execute_delayed, rule), rule.delay) - starting_rule.trim_candidates() if (starting_rule.pre_execute()) spend_threat(starting_rule.cost) @@ -448,29 +444,14 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) executed_rules += starting_rule if (starting_rule.persistent) current_rules += starting_rule - for(var/mob/M in starting_rule.assigned) - for (var/datum/dynamic_ruleset/roundstart/rule in roundstart_rules) - if (!rule.ready()) - drafted_rules -= rule // And removing rules that are no longer elligible + for (var/datum/dynamic_ruleset/roundstart/rule in drafted_rules) + if (!rule.ready()) + drafted_rules -= rule // And removing rules that are no longer elligible return TRUE else stack_trace("The starting rule \"[starting_rule.name]\" failed to pre_execute.") return FALSE -/// Executes delayed roundstart rules and has a hack in it. -/datum/game_mode/dynamic/proc/execute_delayed(datum/dynamic_ruleset/roundstart/delayed/rule) - update_playercounts() - rule.candidates = current_players[CURRENT_LIVING_PLAYERS].Copy() - rule.trim_candidates() - if(rule.execute()) - executed_rules += rule - if (rule.persistent) - current_rules += rule - return TRUE - else - stack_trace("The delayed roundstart rule \"[rule.name]\" failed to execute.") - return FALSE - /// Picks a random midround OR latejoin rule from the list given as an argument and executes it. /// Also this could be named better. /datum/game_mode/dynamic/proc/picking_midround_latejoin_rule(list/drafted_rules = list(), forced = FALSE) @@ -550,7 +531,6 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) update_playercounts() if ((forced || (new_rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && new_rule.cost <= threat))) - new_rule.candidates = current_players.Copy() new_rule.trim_candidates() if (new_rule.ready(forced)) spend_threat(new_rule.cost) @@ -582,7 +562,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) if (GLOB.dynamic_forced_extended) return - // Somehow it manages to trigger midround multiple times so this was moved here. + // Somehow it managed to trigger midround multiple times so this was moved here. // There is no way this should be able to trigger an injection twice now. var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min) midround_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max)) + world.time) @@ -591,21 +571,19 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) if(EMERGENCY_ESCAPED_OR_ENDGAMED) // Unless the shuttle is gone return - log_game("DYNAMIC: Checking state of the round.") + message_admins("DYNAMIC: Checking for midround injection.") + log_game("DYNAMIC: Checking for midround injection.") update_playercounts() - - if (prob(get_injection_chance())) + if (get_injection_chance()) var/list/drafted_rules = list() for (var/datum/dynamic_ruleset/midround/rule in midround_rules) if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost) // Classic secret : only autotraitor/minor roles if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))) continue - rule.candidates = list() - rule.candidates = current_players.Copy() rule.trim_candidates() - if (rule.ready() && rule.candidates.len > 0) + if (rule.ready()) drafted_rules[rule] = rule.get_weight() if (drafted_rules.len > 0) picking_midround_latejoin_rule(drafted_rules) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets.dm b/code/game/gamemodes/dynamic/dynamic_rulesets.dm index 011b6ec251..b77bfcc4a0 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets.dm @@ -86,10 +86,9 @@ /datum/dynamic_ruleset/roundstart // One or more of those drafted at roundstart ruletype = "Roundstart" - -/datum/dynamic_ruleset/roundstart/delayed/ // Executed with a 30 seconds delay - var/delay = 30 SECONDS - var/required_type = /mob/living/carbon/human // No ghosts, new players or silicons allowed. + /// Delay for when execute will get called from the time of post_setup. + /// Make sure your ruleset works with execute being called during the game when using this. + var/delay = 0 // Can be drafted when a player joins the server /datum/dynamic_ruleset/latejoin @@ -113,7 +112,7 @@ /datum/dynamic_ruleset/proc/rule_process() return -/// Called on game mode pre_setup, used for non-delayed roundstart rulesets only. +/// Called on game mode pre_setup for roundstart rulesets. /// Do everything you need to do before job is assigned here. /// IMPORTANT: ASSIGN special_role HERE /datum/dynamic_ruleset/proc/pre_execute() @@ -126,12 +125,6 @@ M.add_antag_datum(antag_datum) return TRUE -/// Called after delay set in ruleset. -/// Give your candidates or assignees equipment and antag datum here. -/datum/dynamic_ruleset/roundstart/delayed/execute() - if (SSticker && SSticker.current_state < GAME_STATE_PLAYING) - CRASH("The delayed ruleset [name] executed before the round started.") - /// Here you can perform any additional checks you want. (such as checking the map etc) /// Remember that on roundstart no one knows what their job is at this point. /// IMPORTANT: If ready() returns TRUE, that means pre_execute() or execute() should never fail! @@ -156,14 +149,6 @@ /datum/dynamic_ruleset/proc/trim_candidates() return -/// Counts how many players are ready at roundstart. -/// Used only by non-delayed roundstart rulesets. -/datum/dynamic_ruleset/proc/num_players() - . = 0 - for(var/mob/dead/new_player/P in GLOB.player_list) - if(P.client && P.ready == PLAYER_READY_TO_PLAY) - . ++ - /// Set mode result and news report here. /// Only called if ruleset is flagged as HIGHLANDER_RULESET /datum/dynamic_ruleset/proc/round_result() @@ -191,32 +176,14 @@ if(P.mind.special_role) // We really don't want to give antag to an antag. candidates.Remove(P) continue - if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))))//are they willing and not antag-banned? - candidates.Remove(P) - continue - -/// Checks if candidates are required mob type, connected, banned and if the job is exclusive to the role. -/datum/dynamic_ruleset/roundstart/delayed/trim_candidates() - . = ..() - for (var/mob/P in candidates) - if (!istype(P, required_type)) - candidates.Remove(P) // Can be a new_player, etc. - continue - if(!mode.check_age(P.client, minimum_required_age)) - candidates.Remove(P) - continue - if (!P.client || !P.mind || !P.mind.assigned_role) // Are they connected? - candidates.Remove(P) - continue - if(P.mind.special_role || P.mind.antag_datums?.len > 0) // Are they an antag already? - candidates.Remove(P) - continue - if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))))//are they willing and not antag-banned? - candidates.Remove(P) - continue - if ((exclusive_roles.len > 0) && !(P.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job? - candidates.Remove(P) - continue + if(antag_flag_override) + if(!(antag_flag_override in P.client.prefs.be_special) || is_banned_from(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))) + candidates.Remove(P) + continue + else + if(!(antag_flag in P.client.prefs.be_special) || is_banned_from(P.ckey, list(antag_flag, ROLE_SYNDICATE))) + candidates.Remove(P) + continue /// 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 fde020a3ae..a560e03f6e 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -12,9 +12,14 @@ if(!mode.check_age(P.client, minimum_required_age)) candidates.Remove(P) continue - if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override))))//are they willing and not antag-banned? - candidates.Remove(P) - continue + if(antag_flag_override) + if(!(antag_flag_override in P.client.prefs.be_special) || is_banned_from(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))) + candidates.Remove(P) + continue + else + if(!antag_flag in P.client.prefs.be_special || is_banned_from(P.ckey, list(antag_flag, ROLE_SYNDICATE))) + candidates.Remove(P) + continue if (P.mind.assigned_role in restricted_roles) // Does their job allow for it? candidates.Remove(P) continue diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index f24301d716..006a80cca6 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -8,7 +8,7 @@ ruletype = "Midround" /// If the ruleset should be restricted from ghost roles. var/restrict_ghost_roles = TRUE - /// What type the ruleset is restricted to. + /// What mob type the ruleset is restricted to. var/required_type = /mob/living/carbon/human var/list/living_players = list() var/list/living_antags = list() @@ -17,26 +17,18 @@ /datum/dynamic_ruleset/midround/from_ghosts weight = 0 + required_type = /mob/dead/observer /// Whether the ruleset should call generate_ruleset_body or not. var/makeBody = TRUE /datum/dynamic_ruleset/midround/trim_candidates() - // Unlike the previous two types, these rulesets are not meant for /mob/dead/new_player - // And since I want those rulesets to be as flexible as possible, I'm not gonna put much here, - // - // All you need to know is that here, the candidates list contains 4 lists itself, indexed with the following defines: - // Candidates = list(CURRENT_LIVING_PLAYERS, CURRENT_LIVING_ANTAGS, CURRENT_DEAD_PLAYERS, CURRENT_OBSERVERS) - // So for example you can get the list of all current dead players with var/list/dead_players = candidates[CURRENT_DEAD_PLAYERS] - // Make sure to properly typecheck the mobs in those lists, as the dead_players list could contain ghosts, or dead players still in their bodies. - // We're still gonna trim the obvious (mobs without clients, jobbanned players, etc) - living_players = trim_list(mode.current_players[CURRENT_LIVING_PLAYERS]) - living_antags = trim_list(mode.current_players[CURRENT_LIVING_ANTAGS]) - dead_players = trim_list(mode.current_players[CURRENT_DEAD_PLAYERS]) - list_observers = trim_list(mode.current_players[CURRENT_OBSERVERS]) + living_players = trim_list(mode.current_players[CURRENT_LIVING_PLAYERS]) + living_antags = trim_list(mode.current_players[CURRENT_LIVING_ANTAGS]) + dead_players = trim_list(mode.current_players[CURRENT_DEAD_PLAYERS]) + list_observers = trim_list(mode.current_players[CURRENT_OBSERVERS]) /datum/dynamic_ruleset/midround/proc/trim_list(list/L = list()) var/list/trimmed_list = L.Copy() - var/antag_name = initial(antag_flag) for(var/mob/M in trimmed_list) if (!istype(M, required_type)) trimmed_list.Remove(M) @@ -47,9 +39,14 @@ if(!mode.check_age(M.client, minimum_required_age)) trimmed_list.Remove(M) continue - if (!(antag_name in M.client.prefs.be_special) || jobban_isbanned(M.ckey, list(antag_name, ROLE_SYNDICATE)))//are they willing and not antag-banned? - trimmed_list.Remove(M) - continue + if(antag_flag_override) + if(!(antag_flag_override in M.client.prefs.be_special) || is_banned_from(M.ckey, list(antag_flag_override, ROLE_SYNDICATE))) + candidates.Remove(M) + continue + else + if(!antag_flag in M.client.prefs.be_special || is_banned_from(M.ckey, list(antag_flag, ROLE_SYNDICATE))) + candidates.Remove(M) + continue if (M.mind) if (restrict_ghost_roles && M.mind.assigned_role in GLOB.exp_specialmap[EXP_TYPE_SPECIAL]) // Are they playing a ghost role? trimmed_list.Remove(M) @@ -256,8 +253,7 @@ /datum/dynamic_ruleset/midround/malf/execute() if(!candidates || !candidates.len) return FALSE - var/mob/living/silicon/ai/M = pick(candidates) - candidates -= M + 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 diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index 6a9aefa996..f515ccc443 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -25,8 +25,7 @@ var/traitor_scaling_coeff = 10 - max(0,round(mode.threat_level/10)-5) // Above 50 threat level, coeff goes down by 1 for every 10 levels var/num_traitors = min(round(mode.candidates.len / traitor_scaling_coeff) + 1, candidates.len) for (var/i = 1 to num_traitors) - var/mob/M = pick(candidates) - candidates -= M + var/mob/M = pick_n_take(candidates) assigned += M.mind M.mind.special_role = ROLE_TRAITOR M.mind.restricted_roles = restricted_roles @@ -67,7 +66,7 @@ var/num_teams = team_amount var/bsc = CONFIG_GET(number/brother_scaling_coeff) if(bsc) - num_teams = max(1, round(num_players() / bsc)) + num_teams = max(1, round(mode.roundstart_pop_ready / bsc)) for(var/j = 1 to num_teams) if(candidates.len < min_team_size || candidates.len < required_candidates) @@ -75,8 +74,7 @@ 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(candidates) - candidates -= bro + var/mob/bro = pick_n_take(candidates) assigned += bro.mind team.add_member(bro.mind) bro.mind.special_role = "brother" @@ -117,8 +115,7 @@ /datum/dynamic_ruleset/roundstart/changeling/pre_execute() var/num_changelings = min(round(mode.candidates.len / 10) + 1, candidates.len) for (var/i = 1 to num_changelings) - var/mob/M = pick(candidates) - candidates -= M + var/mob/M = pick_n_take(candidates) assigned += M.mind M.mind.restricted_roles = restricted_roles M.mind.special_role = ROLE_CHANGELING @@ -175,9 +172,8 @@ if(GLOB.wizardstart.len == 0) return FALSE - var/mob/M = pick(candidates) + var/mob/M = pick_n_take(candidates) if (M) - candidates -= M assigned += M.mind M.mind.assigned_role = ROLE_WIZARD M.mind.special_role = ROLE_WIZARD @@ -225,8 +221,7 @@ for(var/cultists_number = 1 to cultists) if(candidates.len <= 0) break - var/mob/M = pick(candidates) - candidates -= M + var/mob/M = pick_n_take(candidates) assigned += M.mind M.mind.special_role = ROLE_CULTIST M.mind.restricted_roles = restricted_roles @@ -288,8 +283,7 @@ for(var/operatives_number = 1 to operatives) if(candidates.len <= 0) break - var/mob/M = pick(candidates) - candidates -= M + var/mob/M = pick_n_take(candidates) assigned += M.mind M.mind.assigned_role = "Nuclear Operative" M.mind.special_role = "Nuclear Operative" @@ -347,7 +341,7 @@ // // ////////////////////////////////////////////// -/datum/dynamic_ruleset/roundstart/delayed/revs +/datum/dynamic_ruleset/roundstart/revs name = "Revolution" config_tag = "revolution" persistent = TRUE @@ -358,47 +352,48 @@ restricted_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") required_candidates = 3 weight = 2 + delay = 7 MINUTES cost = 35 requirements = list(101,101,70,40,30,20,10,10,10,10) high_population_requirement = 10 - delay = 5 MINUTES flags = HIGHLANDER_RULESET // I give up, just there should be enough heads with 35 players... minimum_players = 35 var/datum/team/revolution/revolution var/finished = 0 -/datum/dynamic_ruleset/roundstart/delayed/revs/execute() - var/max_canditates = 4 - revolution = new() +/datum/dynamic_ruleset/roundstart/revs/pre_execute() + var/max_canditates = 3 for(var/i = 1 to max_canditates) if(candidates.len <= 0) break - var/mob/M = pick(candidates) - candidates -= M + 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() + revolution = new() + for(var/datum/mind/M in assigned) var/datum/antagonist/rev/head/new_head = new antag_datum() new_head.give_flash = TRUE new_head.give_hud = TRUE new_head.remove_clumsy = TRUE - M.mind.add_antag_datum(new_head,revolution) - + M.add_antag_datum(new_head,revolution) revolution.update_objectives() revolution.update_heads() SSshuttle.registerHostileEnvironment(src) - return TRUE -/datum/dynamic_ruleset/roundstart/delayed/revs/rule_process() +/datum/dynamic_ruleset/roundstart/revs/rule_process() if(check_rev_victory()) finished = 1 else if(check_heads_victory()) finished = 2 return -/datum/dynamic_ruleset/roundstart/delayed/revs/check_finished() +/datum/dynamic_ruleset/roundstart/revs/check_finished() if(CONFIG_GET(keyed_list/continuous)["revolution"]) if(finished) SSshuttle.clearHostileEnvironment(src) @@ -408,13 +403,13 @@ else return ..() -/datum/dynamic_ruleset/roundstart/delayed/revs/proc/check_rev_victory() +/datum/dynamic_ruleset/roundstart/revs/proc/check_rev_victory() for(var/datum/objective/mutiny/objective in revolution.objectives) if(!(objective.check_completion())) return FALSE return TRUE -/datum/dynamic_ruleset/roundstart/delayed/revs/proc/check_heads_victory() +/datum/dynamic_ruleset/roundstart/revs/proc/check_heads_victory() for(var/datum/mind/rev_mind in revolution.head_revolutionaries()) var/turf/T = get_turf(rev_mind.current) if(!considered_afk(rev_mind) && considered_alive(rev_mind) && is_station_level(T.z)) @@ -422,7 +417,7 @@ return FALSE return TRUE -/datum/dynamic_ruleset/roundstart/delayed/revs/round_result() +/datum/dynamic_ruleset/roundstart/revs/round_result() if(finished == 1) SSticker.mode_result = "win - heads killed" SSticker.news_report = REVS_WIN @@ -487,14 +482,13 @@ PM.initTemplateBounds() var/starter_servants = 4 - var/number_players = num_players() + var/number_players = mode.roundstart_pop_ready if(number_players > 30) number_players -= 30 starter_servants += round(number_players / 10) starter_servants = min(starter_servants, 8) for (var/i in 1 to starter_servants) - var/mob/servant = pick(candidates) - candidates -= servant + var/mob/servant = pick_n_take(candidates) assigned += servant.mind servant.mind.assigned_role = ROLE_SERVANT_OF_RATVAR servant.mind.special_role = ROLE_SERVANT_OF_RATVAR @@ -610,16 +604,15 @@ var/num_devils = 1 if(tsc) - num_devils = max(required_candidates, min(round(num_players() / (tsc * 3)) + 2, round(num_players() / (tsc * 1.5)))) + num_devils = max(required_candidates, min(round(mode.roundstart_pop_ready / (tsc * 3)) + 2, round(mode.roundstart_pop_ready / (tsc * 1.5)))) else - num_devils = max(required_candidates, min(num_players(), devil_limit)) + num_devils = max(required_candidates, min(mode.roundstart_pop_ready, devil_limit)) for(var/j = 0, j < num_devils, j++) if (!candidates.len) break - var/mob/devil = pick(candidates) - assigned += devil - candidates -= devil + var/mob/devil = pick_n_take(candidates) + assigned += devil.mind devil.mind.special_role = ROLE_DEVIL devil.mind.restricted_roles = restricted_roles @@ -668,13 +661,12 @@ var/datum/team/monkey/monkey_team /datum/dynamic_ruleset/roundstart/monkey/pre_execute() - var/carriers_to_make = max(round(num_players()/players_per_carrier, 1), 1) + var/carriers_to_make = max(round(mode.roundstart_pop_ready / players_per_carrier, 1), 1) for(var/j = 0, j < carriers_to_make, j++) if (!candidates.len) break - var/mob/carrier = pick(candidates) - candidates -= carrier + var/mob/carrier = pick_n_take(candidates) assigned += carrier.mind carrier.mind.special_role = "Monkey Leader" carrier.mind.restricted_roles = restricted_roles