diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index e452d7cfcd..afa91dc79a 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -1,3 +1,5 @@ +var/list/gamemode_cache = list() + /datum/configuration var/server_name = null // server name (for world name / status) var/server_suffix = 0 // generate numeric suffix based on server port @@ -197,8 +199,8 @@ // I wish I didn't have to instance the game modes in order to look up // their information, but it is the only way (at least that I know of). var/datum/game_mode/M = new T() - if (M.config_tag) + gamemode_cache[M.config_tag] = M // So we don't instantiate them repeatedly. if(!(M.config_tag in modes)) // ensure each mode is added only once log_misc("Adding game mode [M.name] ([M.config_tag]) to configuration.") src.modes += M.config_tag @@ -206,7 +208,6 @@ src.probabilities[M.config_tag] = M.probability if (M.votable) src.votable_modes += M.config_tag - del(M) src.votable_modes += "secret" /datum/configuration/proc/load(filename, type = "config") //the type can also be game_options, in which case it uses a different switch. not making it separate to not copypaste code - Urist @@ -779,24 +780,20 @@ /datum/configuration/proc/pick_mode(mode_name) // I wish I didn't have to instance the game modes in order to look up // their information, but it is the only way (at least that I know of). - for (var/T in (typesof(/datum/game_mode) - /datum/game_mode)) - var/datum/game_mode/M = new T() + for (var/game_mode in gamemode_cache) + var/datum/game_mode/M = gamemode_cache[game_mode] if (M.config_tag && M.config_tag == mode_name) M.create_antagonists() return M - del(M) - return new /datum/game_mode/extended() + return gamemode_cache["extended"] /datum/configuration/proc/get_runnable_modes() var/list/datum/game_mode/runnable_modes = new - for (var/T in (typesof(/datum/game_mode) - /datum/game_mode)) - var/datum/game_mode/M = new T() - //world << "DEBUG: [T], tag=[M.config_tag], prob=[probabilities[M.config_tag]]" + for (var/game_mode in gamemode_cache) + var/datum/game_mode/M = gamemode_cache[game_mode] if (!(M.config_tag in modes)) - del(M) continue if (probabilities[M.config_tag]<=0) - del(M) continue if (M.can_start()) runnable_modes[M] = probabilities[M.config_tag] diff --git a/code/controllers/voting.dm b/code/controllers/voting.dm index d42332c8bb..34658944bc 100644 --- a/code/controllers/voting.dm +++ b/code/controllers/voting.dm @@ -212,14 +212,12 @@ datum/controller/vote if(ticker.current_state >= 2) return 0 choices.Add(config.votable_modes) - var/list/L = typesof(/datum/game_mode) - /datum/game_mode for (var/F in choices) - for (var/T in L) - var/datum/game_mode/M = new T(1) - if (M.config_tag == F) - gamemode_names[M.config_tag] = capitalize(M.name) //It's ugly to put this here but it works - additional_text.Add("[M.required_players]") - break + var/datum/game_mode/M = gamemode_cache[F] + if(!M) + continue + gamemode_names[M.config_tag] = capitalize(M.name) //It's ugly to put this here but it works + additional_text.Add("[M.required_players]") gamemode_names["secret"] = "Secret" if("crew_transfer") if(check_rights(R_ADMIN|R_MOD, 0)) diff --git a/code/game/gamemodes/antagonist/alien/borer.dm b/code/game/gamemodes/antagonist/alien/borer.dm index 588802be25..2b45d1f778 100644 --- a/code/game/gamemodes/antagonist/alien/borer.dm +++ b/code/game/gamemodes/antagonist/alien/borer.dm @@ -14,7 +14,7 @@ var/datum/antagonist/xenos/borer/borers borers = src /datum/antagonist/xenos/borer/get_extra_panel_options(var/datum/mind/player) - return "\[put in host\]" + return "\[put in host\]" /datum/antagonist/xenos/borer/create_objectives(var/datum/mind/player) if(!..()) diff --git a/code/game/gamemodes/antagonist/alien/xenomorph.dm b/code/game/gamemodes/antagonist/alien/xenomorph.dm index b219b52365..8d9c883ba3 100644 --- a/code/game/gamemodes/antagonist/alien/xenomorph.dm +++ b/code/game/gamemodes/antagonist/alien/xenomorph.dm @@ -31,7 +31,7 @@ var/datum/antagonist/xenos/xenomorphs if(href_list["move_to_spawn"]) place_mob(href_list["move_to_spawn"]) /datum/antagonist/xenos/get_extra_panel_options(var/datum/mind/player) - return "\[move to vent\]" + return "\[move to vent\]" /datum/antagonist/xenos/random_spawn() if(config.aliens_allowed) ..() diff --git a/code/game/gamemodes/antagonist/antagonist.dm b/code/game/gamemodes/antagonist/antagonist.dm index dd7196d93d..62afcd5ef2 100644 --- a/code/game/gamemodes/antagonist/antagonist.dm +++ b/code/game/gamemodes/antagonist/antagonist.dm @@ -51,7 +51,6 @@ var/global/list/antag_names_to_ids = list() var/loss_text var/victory_feedback_tag var/loss_feedback_tag - var/spawn_upper = 5 var/spawn_lower = 3 var/max_antags = 3 @@ -71,7 +70,7 @@ var/global/list/antag_names_to_ids = list() var/bantype = "Syndicate" var/suspicion_chance = 50 var/flags = 0 - + var/cur_max = 0 var/datum/mind/leader @@ -82,6 +81,7 @@ var/global/list/antag_names_to_ids = list() var/list/global_objectives = list() var/list/restricted_jobs = list() var/list/protected_jobs = list() + var/list/candidates = list() /datum/antagonist/New() ..() @@ -89,7 +89,7 @@ var/global/list/antag_names_to_ids = list() if(config.protect_roles_from_antagonist) restricted_jobs |= protected_jobs -/datum/antagonist/proc/attempt_late_spawn(var/datum/mind/player) +/datum/antagonist/proc/attempt_late_spawn(var/datum/mind/player, var/move_to_spawn) var/main_type if(ticker && ticker.mode) @@ -106,6 +106,11 @@ var/global/list/antag_names_to_ids = list() return 0 player.current << "You have been selected this round as an antagonist!" + add_antagonist(player) + equip(player.current) + finalize(player) + if(move_to_spawn) + place_mob(player.current) return /datum/antagonist/proc/tick() @@ -122,18 +127,17 @@ var/global/list/antag_names_to_ids = list() /datum/antagonist/proc/get_panel_entry(var/datum/mind/player) - var/dat = "" - dat += "[role_text]:" - if(is_antagonist(player)) - dat += "\[-\]" - dat += "\[equip\]" - if(starting_locations && starting_locations.len) - dat += "\[move to spawn\]" - else - dat += "\[+\]" + var/dat = "[role_text]:" var/extra = get_extra_panel_options(player) - if(extra) dat += "[extra]" - dat += "" + if(is_antagonist(player)) + dat += "\[-\]" + dat += "\[equip\]" + if(starting_locations && starting_locations.len) + dat += "\[move to spawn\]" + if(extra) dat += "[extra]" + else + dat += "\[+\]" + dat += "" return dat @@ -152,25 +156,23 @@ var/global/list/antag_names_to_ids = list() /datum/antagonist/proc/get_antag_count() return current_antagonists ? current_antagonists.len : 0 -/datum/antagonist/proc/attempt_spawn(var/lower_count, var/upper_count, var/ghosts_only) - world << "Attempting to spawn [id]." +/datum/antagonist/proc/get_candidates(var/lower_count, var/upper_count, var/ghosts_only) + candidates = list() var/main_type if(ticker && ticker.mode) if(ticker.mode.antag_tag && ticker.mode.antag_tag == id) main_type = 1 else - world << "Ticker uninitialized, failed." - return 0 + return list() var/cur_max = (main_type ? max_antags_round : max_antags) if(ticker.mode.antag_scaling_coeff) cur_max = Clamp((ticker.mode.num_players()/ticker.mode.antag_scaling_coeff), 1, cur_max) if(get_antag_count() >= cur_max) - world << "Antag count: [get_antag_count()] greater than [cur_max], failed." - return 0 + return list() // Sanity. if(lower_count) @@ -189,67 +191,44 @@ var/global/list/antag_names_to_ids = list() if(upper_count < lower_count) upper_count = lower_count - - // Get the raw list of potential players. - var/req_num = 0 - var/list/candidates = ticker.mode.get_players_for_role(role_type, id) - if(!candidates) candidates = list() - - world << "Candidate count is [candidates.len]." + candidates = list() // Clear. + candidates = ticker.mode.get_players_for_role(role_type, id) // Prune restricted jobs and status. for(var/datum/mind/player in candidates) if((ghosts_only && !istype(player.current, /mob/dead)) || (player.assigned_role in restricted_jobs)) - world << "Removing [player.name]." candidates -= player - world << "Candidate count is now [candidates.len]." + if((!candidates.len) || candidates.len < lower_count) + return list() + + return candidates + +/datum/antagonist/proc/attempt_spawn(var/lower_count, var/upper_count, var/ghosts_only) + + world << "Attempting to spawn." + // Get the raw list of potential players. + candidates = get_candidates(lower_count, upper_count, ghosts_only) // Update our boundaries. - if((!candidates.len) || candidates.len < lower_count) - world << "[candidates.len] not set or below [lower_count], failed." + if(!candidates.len) + world << "No candidates." return 0 - else if(candidates.len < upper_count) - req_num = candidates.len - else - req_num = upper_count //Grab candidates randomly until we have enough. - while(req_num > 0) + while(candidates.len) var/datum/mind/player = pick(candidates) current_antagonists |= player + // Update job and role. + player.special_role = role_text + if(flags & ANTAG_OVERRIDE_JOB) + player.assigned_role = "MODE" candidates -= player - req_num-- - - // This will be used in equip() and greet(). Random due to random order of candidates being grabbed. - if(flags & ANTAG_HAS_LEADER) - leader = current_antagonists[1] - - // Generate first stage antagonists. - for(var/datum/mind/player in current_antagonists) - apply(player) - equip(player.current) - finalize(player) - - spawn(1) - if(spawn_announcement) - if(spawn_announcement_delay) - sleep(spawn_announcement_delay) - if(spawn_announcement_sound) - command_announcement.Announce("[spawn_announcement]", "[spawn_announcement_title ? spawn_announcement_title : "Priority Alert"]", new_sound = spawn_announcement_sound) - else - command_announcement.Announce("[spawn_announcement]", "[spawn_announcement_title ? spawn_announcement_title : "Priority Alert"]") - - world << "Success." + world << "Done." return 1 /datum/antagonist/proc/apply(var/datum/mind/player) - // Update job and role. - player.special_role = role_text - if(flags & ANTAG_OVERRIDE_JOB) - player.assigned_role = "MODE" - // Get the mob. if((flags & ANTAG_OVERRIDE_MOB) && (!player.current || (mob_path && !istype(player.current, mob_path)))) var/mob/holder = player.current @@ -334,13 +313,20 @@ var/global/list/antag_names_to_ids = list() // This will fail if objectives have already been generated. create_global_objectives() + if(flags & ANTAG_HAS_LEADER) + leader = current_antagonists[1] + if(target) + apply(target) + equip(target.current) create_objectives(target) update_icons_added(target) greet(target) return for(var/datum/mind/player in current_antagonists) + apply(player) + equip(player.current) create_objectives(player) update_icons_added(player) greet(player) @@ -348,17 +334,29 @@ var/global/list/antag_names_to_ids = list() if(flags & ANTAG_HAS_NUKE) make_nuke(leader) + place_all_mobs() + + spawn(1) + if(spawn_announcement) + if(spawn_announcement_delay) + sleep(spawn_announcement_delay) + if(spawn_announcement_sound) + command_announcement.Announce("[spawn_announcement]", "[spawn_announcement_title ? spawn_announcement_title : "Priority Alert"]", new_sound = spawn_announcement_sound) + else + command_announcement.Announce("[spawn_announcement]", "[spawn_announcement_title ? spawn_announcement_title : "Priority Alert"]") + + /datum/antagonist/proc/print_player_summary() if(!current_antagonists.len) return 0 - var/text = "
The [current_antagonists.len == 1 ? "[role_text] was" : "[role_text_plural] were"]:" + var/text = "
The [current_antagonists.len == 1 ? "[role_text] was" : "[role_text_plural] were"]:" for(var/datum/mind/P in current_antagonists) text += print_player_full(P) text += get_special_objective_text(P) var/failed - if(!global_objectives && P.objectives) + if(!global_objectives && P.objectives && P.objectives.len) var/num = 1 for(var/datum/objective/O in P.objectives) text += print_objective(O, num) @@ -376,7 +374,7 @@ var/global/list/antag_names_to_ids = list() else text += "
The [role_text] was successful!" - if(global_objectives) + if(global_objectives && global_objectives.len) text += "
Their objectives were:" var/num = 1 for(var/datum/objective/O in global_objectives) diff --git a/code/game/gamemodes/antagonist/station/rogue_ai.dm b/code/game/gamemodes/antagonist/station/rogue_ai.dm index f4a44b88fe..f9f7ee3fb0 100644 --- a/code/game/gamemodes/antagonist/station/rogue_ai.dm +++ b/code/game/gamemodes/antagonist/station/rogue_ai.dm @@ -33,19 +33,18 @@ var/datum/antagonist/rogue_ai/malf if(hack_time <=0) capture_station() -/datum/antagonist/rogue_ai/attempt_spawn() - - var/list/candidates = ticker.mode.get_players_for_role(role_type, id) +/datum/antagonist/rogue_ai/get_candidates() + candidates = ticker.mode.get_players_for_role(role_type, id) for(var/datum/mind/player in candidates) if(player.assigned_role != "AI") candidates -= player - if(!candidates.len) - return 0 + return list() + +/datum/antagonist/rogue_ai/attempt_spawn() var/datum/mind/player = pick(candidates) current_antagonists |= player - apply(player) return 1 /datum/antagonist/rogue_ai/equip(var/mob/living/silicon/ai/player) @@ -126,9 +125,6 @@ var/datum/antagonist/rogue_ai/malf set category = "Abilities" set name = "System Override" set desc = "Begin taking over the station." - if (!istype(ticker.mode,/datum/game_mode/malfunction)) - usr << "You cannot begin a takeover in this round type!" - return if (malf.revealed) usr << "You've already begun your takeover." return diff --git a/code/game/gamemodes/antagonist/station/traitor.dm b/code/game/gamemodes/antagonist/station/traitor.dm index 7d206dd57e..c8b8b95b2a 100644 --- a/code/game/gamemodes/antagonist/station/traitor.dm +++ b/code/game/gamemodes/antagonist/station/traitor.dm @@ -13,7 +13,7 @@ var/datum/antagonist/traitor/traitors traitors = src /datum/antagonist/traitor/get_extra_panel_options(var/datum/mind/player) - return "\[set crystals\]\[spawn uplink\]" + return "\[set crystals\]\[spawn uplink\]" /datum/antagonist/traitor/Topic(href, href_list) if (..()) diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 06f6f979f1..2883864594 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -1,6 +1,5 @@ var/global/antag_add_failed // Used in antag type voting. var/global/list/additional_antag_types = list() - /////////////////////////////////// //Keeps track of all living heads// /////////////////////////////////// @@ -218,7 +217,7 @@ var/global/list/additional_antag_types = list() world << "The current game mode is [capitalize(name)]!" if(round_description) world << "[round_description]" if(round_autoantag) world << "Antagonists will be added to the round automagically as needed." - if(antag_templates && antag_templates.len > 1 && master_mode != "secret") + if(antag_templates && antag_templates.len) var/antag_summary = "Possible antagonist types: " var/i = 1 for(var/datum/antagonist/antag in antag_templates) @@ -230,11 +229,14 @@ var/global/list/additional_antag_types = list() antag_summary += "[antag.role_text_plural]" i++ antag_summary += "." - world << "[antag_summary]" + if(antag_templates.len > 1 && master_mode != "secret") + world << "[antag_summary]" + else + message_admins("[antag_summary]") ///can_start() ///Checks to see if the game can be setup and ran with the current number of players or whatnot. -/datum/game_mode/proc/can_start() +/datum/game_mode/proc/can_start(var/do_not_spawn) var/playerC = 0 for(var/mob/new_player/player in player_list) if((player.client)&&(player.ready)) @@ -247,25 +249,17 @@ var/global/list/additional_antag_types = list() if(playerC < required_players) return 0 - // Ensure we can spawn at least the voted roundtype main antagonist type after scaling the max antag counts. // If we can, -try- to spawn the other voted antagonist types. It doesn't really matter if we can't. - if(antag_templates && antag_templates.len) - var/datum/antagonist/main_antags = antag_templates[1] - if(main_antags.attempt_spawn(required_enemies)) - for(var/datum/antagonist/antag in (antag_templates-main_antags)) - antag.attempt_spawn() - return 1 - + if(!do_not_spawn) + if(antag_templates && antag_templates.len) + var/datum/antagonist/main_antags = antag_templates[1] + var/list/candidates = main_antags.get_candidates(required_enemies) + if(candidates.len > required_enemies) + return 1 + else + return 1 return 0 -///pre_setup() -///Attempts to select players for special roles the mode might have. -/datum/game_mode/proc/pre_setup() - if(antag_templates && antag_templates.len) - for(var/datum/antagonist/antag in antag_templates) - antag.place_all_mobs() - return 1 - /datum/game_mode/proc/refresh_event_modifiers() if(event_delay_mod_moderate || event_delay_mod_major) event_manager.report_at_round_end = 1 @@ -292,7 +286,7 @@ var/global/list/additional_antag_types = list() if(antag_templates && antag_templates.len) for(var/datum/antagonist/antag in antag_templates) - antag.create_global_objectives() + antag.attempt_spawn(required_enemies) antag.finalize() if(emergency_shuttle && auto_recall_shuttle) @@ -373,10 +367,12 @@ var/global/list/additional_antag_types = list() var/datum/antagonist/spawn_antag var/datum/mind/candidate + var/from_ghosts if(prob(antag_prob)) if(ghost_candidates.len && ghost_antag_templates.len && prob(50)) spawn_antag = pick(ghost_antag_templates) candidate = pick(ghost_candidates) + from_ghosts = 1 else if(antag_candidates.len && living_antag_templates.len) spawn_antag = pick(living_antag_templates) candidate = pick(antag_candidates) @@ -386,7 +382,7 @@ var/global/list/additional_antag_types = list() return if(spawn_antag.can_become_antag(candidate)) - spawn_antag.attempt_late_spawn(candidate) + spawn_antag.attempt_late_spawn(candidate, from_ghosts) /datum/game_mode/proc/latespawn(mob/living/carbon/human/character) diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm index cbd2aff270..544776d144 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -76,6 +76,7 @@ var/global/datum/controller/gameticker/ticker if(master_mode=="secret") src.hide_mode = 1 var/list/datum/game_mode/runnable_modes + var/mode_started if((master_mode=="random") || (master_mode=="secret")) runnable_modes = config.get_runnable_modes() if (runnable_modes.len==0) @@ -85,6 +86,7 @@ var/global/datum/controller/gameticker/ticker if(secret_force_mode != "secret") var/datum/game_mode/M = config.pick_mode(secret_force_mode) if(M.can_start()) + mode_started = 1 src.mode = config.pick_mode(secret_force_mode) job_master.ResetOccupations() if(!src.mode) @@ -94,7 +96,7 @@ var/global/datum/controller/gameticker/ticker src.mode = new mtype else src.mode = config.pick_mode(master_mode) - if (!src.mode.can_start()) + if(!mode_started && !src.mode.can_start()) world << "Unable to start [mode.name]. Not enough players, [mode.required_players] players needed. Reverting to pre-game lobby." del(mode) current_state = GAME_STATE_PREGAME @@ -103,13 +105,6 @@ var/global/datum/controller/gameticker/ticker //Configure mode and assign player to special mode stuff job_master.DivideOccupations() //Distribute jobs - var/can_continue = src.mode.pre_setup()//Setup special modes - if(!can_continue) - del(mode) - current_state = GAME_STATE_PREGAME - world << "Error setting up [master_mode]. Reverting to pre-game lobby." - job_master.ResetOccupations() - return 0 if(hide_mode) var/list/modes = new