From dec0629faef89df1b59d6a15931233ffce833e26 Mon Sep 17 00:00:00 2001 From: HarpyEagle Date: Sun, 11 Oct 2015 11:26:01 -0400 Subject: [PATCH 1/8] Renames latespawn() to be less confusing --- code/game/gamemodes/game_mode_latespawn.dm | 3 ++- code/modules/mob/new_player/new_player.dm | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/code/game/gamemodes/game_mode_latespawn.dm b/code/game/gamemodes/game_mode_latespawn.dm index 038cf351ab8..f2bce2d8718 100644 --- a/code/game/gamemodes/game_mode_latespawn.dm +++ b/code/game/gamemodes/game_mode_latespawn.dm @@ -20,7 +20,8 @@ process_count = 0 try_latespawn() -/datum/game_mode/proc/latespawn(var/mob/living/carbon/human/character) +//This can be overriden in case a game mode needs to do stuff when a player latejoins +/datum/game_mode/proc/handle_latejoin(var/mob/living/carbon/human/character) if(!character.mind) return try_latespawn(character.mind) diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index fb3b6f4fca3..6afacc4af97 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -323,7 +323,7 @@ character.loc = C.loc AnnounceCyborg(character, rank, "has been downloaded to the empty core in \the [character.loc.loc]") - ticker.mode.latespawn(character) + ticker.mode.handle_latejoin(character) qdel(C) qdel(src) @@ -354,7 +354,7 @@ character.buckled.loc = character.loc character.buckled.set_dir(character.dir) - ticker.mode.latespawn(character) + ticker.mode.handle_latejoin(character) if(character.mind.assigned_role != "Cyborg") data_core.manifest_inject(character) From 43d5f2e3bd493ff6fb6b9673be190af953684659 Mon Sep 17 00:00:00 2001 From: HarpyEagle Date: Sun, 11 Oct 2015 11:39:26 -0400 Subject: [PATCH 2/8] Ensures leftover candidates and pending antags are cleared after finalizing --- code/game/antagonist/antagonist.dm | 9 +++++++-- code/game/gamemodes/game_mode.dm | 2 +- code/modules/mob/new_player/new_player.dm | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm index faf7526a9cb..d9bc5c56901 100644 --- a/code/game/antagonist/antagonist.dm +++ b/code/game/antagonist/antagonist.dm @@ -186,11 +186,16 @@ for(var/datum/mind/player in pending_antagonists) pending_antagonists -= player add_antagonist(player,0,0,1) + + reset_antag_selection() -//Resets all pending_antagonists, clearing their special_role (and assigned_role if ANTAG_OVERRIDE_JOB is set) -/datum/antagonist/proc/reset() +//Resets the antag selection, clearing all pending_antagonists and their special_role +//(and assigned_role if ANTAG_OVERRIDE_JOB is set) as well as clearing the candidate list. +//Existing antagonists are left untouched. +/datum/antagonist/proc/reset_antag_selection() for(var/datum/mind/player in pending_antagonists) if(flags & ANTAG_OVERRIDE_JOB) player.assigned_role = null player.special_role = null pending_antagonists.Cut() + candidates.Cut() diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 705c044e01b..57a936f581f 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -305,7 +305,7 @@ var/global/list/additional_antag_types = list() /datum/game_mode/proc/fail_setup() for(var/datum/antagonist/antag in antag_templates) - antag.reset() + antag.reset_antag_selection() /datum/game_mode/proc/announce_ert_disabled() if(!ert_disabled) diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 6afacc4af97..9eb43e48d98 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -289,7 +289,7 @@ proc/AttemptLateSpawn(rank,var/spawning_at) - if (src != usr) + if(src != usr) return 0 if(!ticker || ticker.current_state != GAME_STATE_PLAYING) usr << "\red The round is either not ready, or has already finished..." From d715e0645fada6bfe067fc93b2d4cb863053b00b Mon Sep 17 00:00:00 2001 From: HarpyEagle Date: Sun, 11 Oct 2015 11:48:04 -0400 Subject: [PATCH 3/8] Removes unused latejoin template list --- code/game/gamemodes/game_mode.dm | 3 --- code/game/gamemodes/game_mode_latespawn.dm | 6 ++---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 57a936f581f..b8a99badf11 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -22,7 +22,6 @@ var/global/list/additional_antag_types = list() var/list/antag_tags = list() // Core antag templates to spawn. var/list/antag_templates // Extra antagonist types to include. - var/list/latejoin_templates = list() var/round_autoantag = 0 // Will this round attempt to periodically spawn more antagonists? var/antag_scaling_coeff = 5 // Coefficient for scaling max antagonists to player count. var/require_all_templates = 0 // Will only start if all templates are checked and can spawn. @@ -291,8 +290,6 @@ var/global/list/additional_antag_types = list() if(!(antag.flags & ANTAG_OVERRIDE_JOB)) antag.attempt_spawn() //select antags to be spawned antag.finalize_spawn() //actually spawn antags - if(antag.is_latejoin_template()) - latejoin_templates |= antag if(emergency_shuttle && auto_recall_shuttle) emergency_shuttle.auto_recall = 1 diff --git a/code/game/gamemodes/game_mode_latespawn.dm b/code/game/gamemodes/game_mode_latespawn.dm index f2bce2d8718..28db276b493 100644 --- a/code/game/gamemodes/game_mode_latespawn.dm +++ b/code/game/gamemodes/game_mode_latespawn.dm @@ -27,7 +27,7 @@ try_latespawn(character.mind) return 0 -/datum/game_mode/proc/try_latespawn(var/datum/mind/player, var/latejoin_only) +/datum/game_mode/proc/try_latespawn(var/datum/mind/player) if(emergency_shuttle.departed || !round_autoantag) return @@ -38,9 +38,7 @@ message_admins("AUTO[uppertext(name)]: Attempting spawn.") var/list/usable_templates - if(latejoin_only && latejoin_templates.len) - usable_templates = get_usable_templates(latejoin_templates) - else if (antag_templates && antag_templates.len) + if (antag_templates && antag_templates.len) usable_templates = get_usable_templates(antag_templates) else message_admins("AUTO[uppertext(name)]: Failed to find configured mode spawn templates, please disable auto-antagonists until one is added.") From c7afded12d7aeac970d46f863021ebae08516d4a Mon Sep 17 00:00:00 2001 From: HarpyEagle Date: Sun, 11 Oct 2015 12:00:21 -0400 Subject: [PATCH 4/8] Cleans up calamity shuffle, makes sure antag types are selected in a random order for other game modes. --- code/game/gamemodes/calamity/calamity.dm | 13 +++++++------ code/game/gamemodes/game_mode.dm | 1 + 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/code/game/gamemodes/calamity/calamity.dm b/code/game/gamemodes/calamity/calamity.dm index 4f7b9ab49de..3104e624e34 100644 --- a/code/game/gamemodes/calamity/calamity.dm +++ b/code/game/gamemodes/calamity/calamity.dm @@ -12,14 +12,15 @@ /datum/game_mode/calamity/create_antagonists() - shuffle(all_antag_types) // This is probably the only instance in the game where the order will be important. - var/i = 1 + //Let's not modify global lists for trivial reasons, even if it seems harmless right now. + var/list/antag_candidates = all_antag_types.Copy() + var/grab_antags = round(num_players()/ANTAG_TYPE_RATIO)+1 - for(var/antag_id in all_antag_types) - if(i > grab_antags) - break + while(antag_candidates.len && antag_tags.len < grab_antags) + var/antag_id = pick(antag_candidates) + antag_candidates -= antag_id antag_tags |= antag_id - i++ + ..() /datum/game_mode/calamity/check_victory() diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index b8a99badf11..08a82890602 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -572,6 +572,7 @@ var/global/list/additional_antag_types = list() if(antag) antag_templates |= antag + shuffle(antag_templates) //In the case of multiple antag types newscaster_announcements = pick(newscaster_standard_feeds) /datum/game_mode/proc/check_victory() From e381e2faf2afa6b89ef7bbecf5e1854f0effd776 Mon Sep 17 00:00:00 2001 From: HarpyEagle Date: Sun, 11 Oct 2015 12:16:08 -0400 Subject: [PATCH 5/8] Fixes do_not_announce parameters not actually doing anything --- code/game/antagonist/antagonist_create.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/game/antagonist/antagonist_create.dm b/code/game/antagonist/antagonist_create.dm index 416a774541a..1b8b82210a7 100644 --- a/code/game/antagonist/antagonist_create.dm +++ b/code/game/antagonist/antagonist_create.dm @@ -16,7 +16,8 @@ create_objectives(target) update_icons_added(target) greet(target) - announce_antagonist_spawn() + if(!gag_announcement) + announce_antagonist_spawn() /datum/antagonist/proc/create_default(var/mob/source) var/mob/living/M From 241520f0bb4cc5e0d639df8942b86e7ec8c5f4d6 Mon Sep 17 00:00:00 2001 From: HarpyEagle Date: Mon, 12 Oct 2015 12:47:41 -0400 Subject: [PATCH 6/8] Cleans up autospawn, now uses existing code for selecting and choosing candidates. Adds more debug messages, and removes unused code. --- code/game/antagonist/antagonist.dm | 54 +++++++++++++--------- code/game/antagonist/antagonist_helpers.dm | 6 +-- code/game/antagonist/station/rogue_ai.dm | 4 +- code/game/gamemodes/game_mode.dm | 1 + code/game/gamemodes/game_mode_latespawn.dm | 53 ++++++++------------- code/modules/admin/admin.dm | 7 ++- 6 files changed, 60 insertions(+), 65 deletions(-) diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm index d9bc5c56901..011ae5ebe6c 100644 --- a/code/game/antagonist/antagonist.dm +++ b/code/game/antagonist/antagonist.dm @@ -86,7 +86,8 @@ /datum/antagonist/proc/tick() return 1 -/datum/antagonist/proc/get_candidates(var/ghosts_only) +// Get the raw list of potential players. +/datum/antagonist/proc/build_candidate_list(var/ghosts_only) candidates = list() // Clear. // Prune restricted status. Broke it up for readability. @@ -108,46 +109,57 @@ return candidates /datum/antagonist/proc/attempt_random_spawn() + update_current_antag_max() build_candidate_list(flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB)) attempt_spawn() finalize_spawn() -/datum/antagonist/proc/attempt_late_spawn(var/datum/mind/player) +/datum/antagonist/proc/attempt_auto_spawn() if(!can_late_spawn()) return 0 - if(!istype(player)) - var/list/players = get_candidates(is_latejoin_template()) - if(players && players.len) - player = pick(players) - if(!istype(player)) - message_admins("AUTO[uppertext(ticker.mode.name)]: Failed to find a candidate for [role_text].") - return 0 - player.current << "You have been selected this round as an antagonist!" - message_admins("AUTO[uppertext(ticker.mode.name)]: Selected [player] as a [role_text].") - if(istype(player.current, /mob/dead)) - create_default(player.current) - else - add_antagonist(player,0,0,0,1,1) - return 1 -/datum/antagonist/proc/build_candidate_list(var/ghosts_only) - // Get the raw list of potential players. update_current_antag_max() - candidates = get_candidates(ghosts_only) + var/active_antags = get_active_antag_count() + log_debug("[uppertext(id)]: Found [active_antags]/[cur_max] active [role_text_plural].") + + if(active_antags >= cur_max) + log_debug("Could not auto-spawn a [role_text], active antag limit reached.") + return 0 + + build_candidate_list(flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB)) + if(!candidates.len) + log_debug("Could not auto-spawn a [role_text], no candidates found.") + return 0 + + attempt_spawn(1) //auto-spawn antags one at a time + if(!pending_antagonists.len) + log_debug("Could not auto-spawn a [role_text], none of the available candidates could be selected.") + return 0 + + var/datum/mind/player = pending_antagonists[1] + if(!add_antagonist(player,0,0,0,1,1)) + log_debug("Could not auto-spawn a [role_text], failed to add antagonist.") + return 0 + + reset_antag_selection() + + return 1 //Selects players that will be spawned in the antagonist role from the potential candidates //Selected players are added to the pending_antagonists lists. //Attempting to spawn an antag role with ANTAG_OVERRIDE_JOB should be done before jobs are assigned, //so that they do not occupy regular job slots. All other antag roles should be spawned after jobs are //assigned, so that job restrictions can be respected. -/datum/antagonist/proc/attempt_spawn(var/rebuild_candidates = 1) +/datum/antagonist/proc/attempt_spawn(var/spawn_target = null) + if(spawn_target == null) + spawn_target = initial_spawn_target // Update our boundaries. if(!candidates.len) return 0 //Grab candidates randomly until we have enough. - while(candidates.len && pending_antagonists.len < initial_spawn_target) + while(candidates.len && pending_antagonists.len < spawn_target) var/datum/mind/player = pick(candidates) candidates -= player draft_antagonist(player) diff --git a/code/game/antagonist/antagonist_helpers.dm b/code/game/antagonist/antagonist_helpers.dm index 056fbd18651..37e332d8efb 100644 --- a/code/game/antagonist/antagonist_helpers.dm +++ b/code/game/antagonist/antagonist_helpers.dm @@ -20,6 +20,9 @@ /datum/antagonist/proc/get_antag_count() return current_antagonists ? current_antagonists.len : 0 +/datum/antagonist/proc/get_active_antag_count() + return get_antag_count() //TODO + /datum/antagonist/proc/is_antagonist(var/datum/mind/player) if(player in current_antagonists) return 1 @@ -33,9 +36,6 @@ return (flags & ANTAG_VOTABLE) /datum/antagonist/proc/can_late_spawn() - update_current_antag_max() - if(get_antag_count() >= cur_max) - return 0 return 1 /datum/antagonist/proc/is_latejoin_template() diff --git a/code/game/antagonist/station/rogue_ai.dm b/code/game/antagonist/station/rogue_ai.dm index 52fa7e3f38e..a277df922b2 100644 --- a/code/game/antagonist/station/rogue_ai.dm +++ b/code/game/antagonist/station/rogue_ai.dm @@ -22,13 +22,11 @@ var/datum/antagonist/rogue_ai/malf malf = src -/datum/antagonist/rogue_ai/get_candidates() +/datum/antagonist/rogue_ai/build_candidate_list() ..() for(var/datum/mind/player in candidates) if(player.assigned_role && player.assigned_role != "AI") candidates -= player - if(!candidates.len) - return list() return candidates diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 08a82890602..28f420547fd 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -266,6 +266,7 @@ var/global/list/additional_antag_types = list() /datum/game_mode/proc/pre_setup() for(var/datum/antagonist/antag in antag_templates) + antag.update_current_antag_max() antag.build_candidate_list() //compile a list of all eligible candidates //antag roles that replace jobs need to be assigned before the job controller hands out jobs. diff --git a/code/game/gamemodes/game_mode_latespawn.dm b/code/game/gamemodes/game_mode_latespawn.dm index 28db276b493..9a10f0ce358 100644 --- a/code/game/gamemodes/game_mode_latespawn.dm +++ b/code/game/gamemodes/game_mode_latespawn.dm @@ -3,54 +3,39 @@ /datum/game_mode/var/max_autotraitor_delay = 12000 // Approx 20 minutes. /datum/game_mode/var/process_count = 0 -/datum/game_mode/proc/get_usable_templates(var/list/supplied_templates) - var/list/usable_templates = list() - for(var/datum/antagonist/A in supplied_templates) - if(A.can_late_spawn()) - message_admins("AUTO[uppertext(name)]: [A.id] selected for spawn attempt.") - usable_templates |= A - return usable_templates - ///process() ///Called by the gameticker /datum/game_mode/proc/process() - // Slow this down a bit so latejoiners have a chance of being antags. - process_count++ - if(process_count >= 10) - process_count = 0 - try_latespawn() + if(round_autoantag && world.time < next_spawn && !emergency_shuttle.departed) + process_autoantag() //This can be overriden in case a game mode needs to do stuff when a player latejoins /datum/game_mode/proc/handle_latejoin(var/mob/living/carbon/human/character) - if(!character.mind) - return - try_latespawn(character.mind) return 0 -/datum/game_mode/proc/try_latespawn(var/datum/mind/player) +/datum/game_mode/proc/process_autoantag() + message_admins("[uppertext(name)]: Attempting autospawn.") - if(emergency_shuttle.departed || !round_autoantag) - return - - if(world.time < next_spawn) - return - - message_admins("AUTO[uppertext(name)]: Attempting spawn.") - - var/list/usable_templates - if (antag_templates && antag_templates.len) - usable_templates = get_usable_templates(antag_templates) - else - message_admins("AUTO[uppertext(name)]: Failed to find configured mode spawn templates, please disable auto-antagonists until one is added.") + var/list/usable_templates = list() + for(var/datum/antagonist/A in antag_templates) + if(A.can_late_spawn()) + message_admins("[uppertext(name)]: [A.id] selected for spawn attempt.") + usable_templates |= A + + if(!usable_templates.len) + message_admins("[uppertext(name)]: Failed to find configured mode spawn templates, please re-enable auto-antagonists after one is added.") round_autoantag = 0 return - + while(usable_templates.len) var/datum/antagonist/spawn_antag = pick(usable_templates) usable_templates -= spawn_antag - if(spawn_antag.attempt_late_spawn(player)) - message_admins("AUTO[uppertext(name)]: Attempting to latespawn [spawn_antag.id]. ([spawn_antag.get_antag_count()]/[spawn_antag.cur_max])") + + if(spawn_antag.attempt_auto_spawn()) + message_admins("[uppertext(name)]: Auto-added a new [spawn_antag.role_text].") + message_admins("There are now [spawn_antag.get_active_antag_count()]/[spawn_antag.cur_max] active [spawn_antag.role_text_plural].") next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay) return - message_admins("AUTO[uppertext(name)]: Failed to proc a viable spawn template.") + + message_admins("[uppertext(name)]: Failed to proc a viable spawn template.") next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index f02292d81f1..241f394cca4 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -1386,7 +1386,7 @@ proc/admin_notice(var/message, var/rights) var/datum/antagonist/antag = all_antag_types[antag_type] message_admins("[key_name(usr)] attempting to force latespawn with template [antag.id].") - antag.attempt_late_spawn() + antag.attempt_auto_spawn() /datum/admins/proc/force_mode_latespawn() set category = "Admin" @@ -1403,6 +1403,5 @@ proc/admin_notice(var/message, var/rights) usr << "Mode has not started." return - message_admins("[key_name(usr)] attempting to force mode latespawn.") - ticker.mode.next_spawn = 0 - ticker.mode.try_latespawn() + message_admins("[key_name(usr)] attempting to force mode autospawn.") + ticker.mode.process_autoantag() From c0dc32d60cbe5a2adde646fc84de4072ed471317 Mon Sep 17 00:00:00 2001 From: HarpyEagle Date: Mon, 12 Oct 2015 12:50:48 -0400 Subject: [PATCH 7/8] If an antag could not be auto-spawned, the game rechecks in the minimum time. --- code/game/gamemodes/game_mode_latespawn.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/game_mode_latespawn.dm b/code/game/gamemodes/game_mode_latespawn.dm index 9a10f0ce358..9c79a689251 100644 --- a/code/game/gamemodes/game_mode_latespawn.dm +++ b/code/game/gamemodes/game_mode_latespawn.dm @@ -38,4 +38,4 @@ return message_admins("[uppertext(name)]: Failed to proc a viable spawn template.") - next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay) + next_spawn = world.time + min_autotraitor_delay //recheck again in the miniumum time From ffb26a6f87f01d3418523fa7a965614b49eb28bb Mon Sep 17 00:00:00 2001 From: HarpyEagle Date: Mon, 12 Oct 2015 13:25:42 -0400 Subject: [PATCH 8/8] Adds checks for antags being dead or SSD --- code/game/antagonist/antagonist_helpers.dm | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/code/game/antagonist/antagonist_helpers.dm b/code/game/antagonist/antagonist_helpers.dm index 37e332d8efb..adc706734fd 100644 --- a/code/game/antagonist/antagonist_helpers.dm +++ b/code/game/antagonist/antagonist_helpers.dm @@ -21,7 +21,15 @@ return current_antagonists ? current_antagonists.len : 0 /datum/antagonist/proc/get_active_antag_count() - return get_antag_count() //TODO + var/active_antags = 0 + for(var/datum/mind/player in current_antagonists) + var/mob/living/L = player.current + if(!L || L.stat == DEAD) + continue //no mob or dead + if(!L.client && !L.teleop) + continue //SSD + active_antags++ + return active_antags /datum/antagonist/proc/is_antagonist(var/datum/mind/player) if(player in current_antagonists)