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