diff --git a/baystation12.dme b/baystation12.dme
index 88966c957f..1497ff493b 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -252,6 +252,7 @@
#include "code\game\dna\genes\powers.dm"
#include "code\game\gamemodes\events.dm"
#include "code\game\gamemodes\game_mode.dm"
+#include "code\game\gamemodes\game_mode_latespawn.dm"
#include "code\game\gamemodes\gameticker.dm"
#include "code\game\gamemodes\intercept_report.dm"
#include "code\game\gamemodes\objective.dm"
diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm
index c7cbde15ab..11431682a1 100644
--- a/code/game/antagonist/antagonist.dm
+++ b/code/game/antagonist/antagonist.dm
@@ -33,8 +33,9 @@
var/nuke_spawn_loc
var/list/valid_species = list("Unathi","Tajara","Skrell","Human") // Used for setting appearance.
- var/list/starting_locations = list()
var/list/current_antagonists = list()
+ var/list/pending_antagonists = list()
+ var/list/starting_locations = list()
var/list/global_objectives = list()
var/list/restricted_jobs = list()
var/list/protected_jobs = list()
@@ -57,29 +58,32 @@
return 1
/datum/antagonist/proc/get_candidates(var/ghosts_only)
-
candidates = list() // Clear.
candidates = ticker.mode.get_players_for_role(role_type, id)
- // Prune restricted jobs and status.
+ // Prune restricted jobs and status. Broke it up for readability.
for(var/datum/mind/player in candidates)
- if((ghosts_only && !istype(player.current, /mob/dead)) || player.special_role || (player.assigned_role in restricted_jobs))
+ if(ghosts_only && !istype(player.current, /mob/dead))
+ candidates -= player
+ else if(player.special_role)
+ candidates -= player
+ else if (player in pending_antagonists)
+ candidates -= player
+ else if(!can_become_antag(player))
candidates -= player
return candidates
/datum/antagonist/proc/attempt_random_spawn()
attempt_spawn(flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB))
-/datum/antagonist/proc/attempt_late_spawn(var/datum/mind/player, var/move_to_spawn)
-
- update_current_antag_max()
- if(get_antag_count() >= cur_max)
- return 0
-
+/datum/antagonist/proc/attempt_late_spawn(var/datum/mind/player)
+ if(!can_late_spawn())
+ return
+ if(!istype(player)) player = get_candidates(is_latejoin_template())
player.current << "You have been selected this round as an antagonist!"
- if(move_to_spawn)
- place_mob(player.current)
- add_antagonist(player)
- equip(player.current)
+ if(istype(player.current, /mob/dead))
+ create_default(player.current)
+ else
+ add_antagonist(player,0,1,0,1,1)
return
/datum/antagonist/proc/attempt_spawn(var/ghosts_only)
@@ -95,11 +99,14 @@
//Grab candidates randomly until we have enough.
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"
+ pending_antagonists |= player
candidates -= player
return 1
+/datum/antagonist/proc/finalize_spawn()
+ if(!pending_antagonists || !pending_antagonists.len)
+ return
+ for(var/datum/mind/player in pending_antagonists)
+ if(can_become_antag(player) && !player.special_role)
+ add_antagonist(player,0,0,1)
+ pending_antagonists.Cut()
\ No newline at end of file
diff --git a/code/game/antagonist/antagonist_add.dm b/code/game/antagonist/antagonist_add.dm
index 9a0ef84e8d..e3c653a4e5 100644
--- a/code/game/antagonist/antagonist_add.dm
+++ b/code/game/antagonist/antagonist_add.dm
@@ -1,14 +1,23 @@
/datum/antagonist/proc/add_antagonist(var/datum/mind/player, var/ignore_role, var/do_not_equip, var/move_to_spawn, var/do_not_announce, var/preserve_appearance)
if(!istype(player))
return 0
+ if(!player.current)
+ return 0
if(player in current_antagonists)
return 0
if(!can_become_antag(player, ignore_role))
return 0
+
current_antagonists |= player
- create_antagonist(player, move_to_spawn, do_not_announce, preserve_appearance)
- if(!do_not_equip && player.current)
- equip(player.current)
+ if(flags & ANTAG_OVERRIDE_JOB)
+ player.assigned_role = "MODE"
+
+ if(istype(player.current, /mob/dead))
+ create_default(player.current)
+ else
+ create_antagonist(player, move_to_spawn, do_not_announce, preserve_appearance)
+ if(!do_not_equip)
+ equip(player.current)
return 1
/datum/antagonist/proc/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted)
diff --git a/code/game/antagonist/antagonist_create.dm b/code/game/antagonist/antagonist_create.dm
index c7387d92a8..0c1aab6898 100644
--- a/code/game/antagonist/antagonist_create.dm
+++ b/code/game/antagonist/antagonist_create.dm
@@ -21,9 +21,9 @@
/datum/antagonist/proc/create_default(var/mob/source)
var/mob/living/M
if(mob_path)
- M = new mob_path()
+ M = new mob_path(get_turf(source))
else
- M = new /mob/living/carbon/human
+ M = new /mob/living/carbon/human(get_turf(source))
M.real_name = source.real_name
M.name = M.real_name
M.ckey = source.ckey
diff --git a/code/game/antagonist/antagonist_helpers.dm b/code/game/antagonist/antagonist_helpers.dm
index bf010b6003..a578c1bf4f 100644
--- a/code/game/antagonist/antagonist_helpers.dm
+++ b/code/game/antagonist/antagonist_helpers.dm
@@ -30,4 +30,13 @@
return 0
/datum/antagonist/proc/is_votable()
- return (flags & ANTAG_VOTABLE)
\ No newline at end of file
+ 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()
+ return (flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB))
\ No newline at end of file
diff --git a/code/game/antagonist/antagonist_objectives.dm b/code/game/antagonist/antagonist_objectives.dm
index 010ba565cc..432c3f6bbe 100644
--- a/code/game/antagonist/antagonist_objectives.dm
+++ b/code/game/antagonist/antagonist_objectives.dm
@@ -23,8 +23,6 @@
for(var/datum/objective/O in global_objectives)
if(!O.completed && !O.check_completion())
result = 0
- else
- O.completed = 1 //Will this break anything?
if(result && victory_text)
world << "[victory_text]"
if(victory_feedback_tag) feedback_set_details("round_end_result","[victory_feedback_tag]")
diff --git a/code/game/antagonist/antagonist_print.dm b/code/game/antagonist/antagonist_print.dm
index ae35c22820..ab6271b35b 100644
--- a/code/game/antagonist/antagonist_print.dm
+++ b/code/game/antagonist/antagonist_print.dm
@@ -12,7 +12,7 @@
var/num = 1
for(var/datum/objective/O in P.objectives)
text += print_objective(O, num)
- if(O.completed) // This is set actively in check_victory()
+ if(O.check_completion())
text += "Success!"
feedback_add_details(feedback_tag,"[O.type]|SUCCESS")
else
@@ -21,11 +21,11 @@
failed = 1
num++
- if(!config.objectives_disabled)
- if(failed)
- text += "
The [role_text] has failed."
- else
- text += "
The [role_text] was successful!"
+ if(!config.objectives_disabled)
+ if(failed)
+ text += "
The [role_text] has failed."
+ else
+ text += "
The [role_text] was successful!"
if(global_objectives && global_objectives.len)
text += "
Their objectives were:"
diff --git a/code/game/antagonist/antagonist_update.dm b/code/game/antagonist/antagonist_update.dm
index a06b3e5993..0fd5fb2a93 100644
--- a/code/game/antagonist/antagonist_update.dm
+++ b/code/game/antagonist/antagonist_update.dm
@@ -62,15 +62,10 @@
qdel(I)
/datum/antagonist/proc/update_current_antag_max()
-
- candidates = list()
var/main_type
if(ticker && ticker.mode)
if(ticker.mode.antag_tag && ticker.mode.antag_tag == id)
main_type = 1
- else
- return list()
-
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)
\ No newline at end of file
+ cur_max = Clamp((ticker.mode.num_players()/ticker.mode.antag_scaling_coeff), 1, cur_max)
diff --git a/code/game/antagonist/outsider/ninja.dm b/code/game/antagonist/outsider/ninja.dm
index 17083eb89a..3149db81bc 100644
--- a/code/game/antagonist/outsider/ninja.dm
+++ b/code/game/antagonist/outsider/ninja.dm
@@ -9,8 +9,8 @@ var/datum/antagonist/ninja/ninjas
landmark_id = "ninjastart"
welcome_text = "You are an elite mercenary assassin of the Spider Clan. You have a variety of abilities at your disposal, thanks to your nano-enhanced cyber armor."
flags = ANTAG_OVERRIDE_JOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_RANDSPAWN | ANTAG_VOTABLE | ANTAG_SET_APPEARANCE
- max_antags = 3
- max_antags_round = 3
+ max_antags = 1//3
+ max_antags_round = 1//3
/datum/antagonist/ninja/New()
..()
@@ -164,7 +164,7 @@ var/datum/antagonist/ninja/ninjas
if(17)
directive += "The Spider Clan has recently begun recruiting outsiders. Consider suitable candidates and assess their behavior amongst the crew."
if(18)
- directive += "A cyborg liberation group has expressed interest in our serves. Prove the Spider Clan merciful towards law-bound synthetics."
+ directive += "A cyborg liberation group has expressed interest in our services. Prove the Spider Clan merciful towards law-bound synthetics."
else
directive += "There are no special supplemental instructions at this time."
return directive
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 76ab7b5106..eaa7e67e5f 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -42,17 +42,10 @@ var/global/list/additional_antag_types = list()
var/antag_tag // First (main) antag template 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_prob = 0 // Likelihood of a new antagonist spawning.
- var/antag_count = 0 // Current number of antagonists.
var/antag_scaling_coeff = 5 // Coefficient for scaling max antagonists to player count.
- var/list/living_antag_templates = list() // Currently selected antag types that do not require a ghosted player.
- var/list/ghost_antag_templates = list() // Inverse of above.
- var/list/antag_candidates = list() // Living antag candidates.
- var/list/ghost_candidates = list() // Observing antag candidates.
-
var/station_was_nuked = 0 // See nuclearbomb.dm and malfunction.dm.
var/explosion_in_progress = 0 // Sit back and relax
var/waittime_l = 600 // Lower bound on time before intercept arrives (in tenths of seconds)
@@ -272,7 +265,6 @@ var/global/list/additional_antag_types = list()
EMajor.delay_modifier = event_delay_mod_major
///post_setup()
-///Everyone should now be on the station and have their normal gear. This is the place to give the special roles extra things
/datum/game_mode/proc/post_setup()
refresh_event_modifiers()
@@ -285,9 +277,11 @@ var/global/list/additional_antag_types = list()
spawn(rand(100,150))
announce_ert_disabled()
- //if(antag_templates && antag_templates.len)
- // for(var/datum/antagonist/antag in antag_templates)
- // antag.finalize()
+ if(antag_templates && antag_templates.len)
+ for(var/datum/antagonist/antag in antag_templates)
+ antag.finalize_spawn()
+ if(antag.is_latejoin_template())
+ latejoin_templates |= antag
if(emergency_shuttle && auto_recall_shuttle)
emergency_shuttle.auto_recall = 1
@@ -336,67 +330,6 @@ var/global/list/additional_antag_types = list()
)
command_announcement.Announce("The presence of [pick(reasons)] in the region is tying up all available local emergency resources; emergency response teams cannot be called at this time, and post-evacuation recovery efforts will be substantially delayed.","Emergency Transmission")
-///process()
-///Called by the gameticker
-/datum/game_mode/proc/process()
-
- if(emergency_shuttle.departed)
- return
-
- if(!round_autoantag || !antag_templates || !antag_templates.len)
- return
-
- var/player_count = 0
- antag_count = 0
- antag_candidates = list()
-
- for(var/mob/living/player in mob_list)
- if(player.client)
- player_count += 1
- if(player.mind)
- if(player.stat == 2) // observing
- ghost_candidates |= player
- else
- if(player.mind.special_role)
- antag_count += 1
- else
- antag_candidates |= player
-
- antag_prob = min(100,max(0,(player_count - 5 * 10) * 5)) // This is arbitrary, probably needs adjusting.
-
- 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)
- else
- return // Failed :(
- else
- return
-
- if(spawn_antag.can_become_antag(candidate))
- spawn_antag.attempt_late_spawn(candidate, from_ghosts)
-
-/datum/game_mode/proc/latespawn(mob/living/carbon/human/character)
-
- if(emergency_shuttle.departed || !character.mind)
- return
-
- var/datum/antagonist/spawn_antag
- if(prob(antag_prob) && round_autoantag && living_antag_templates.len)
- spawn_antag = pick(living_antag_templates)
- if(spawn_antag && spawn_antag.can_become_antag(character.mind))
- spawn_antag.attempt_late_spawn(character.mind)
-
- return 0
-
/datum/game_mode/proc/check_finished()
if(emergency_shuttle.returned() || station_was_nuked)
return 1
@@ -623,13 +556,10 @@ var/global/list/additional_antag_types = list()
if(antag_templates && antag_templates.len)
for(var/datum/antagonist/antag in antag_templates)
- if(antag.flags & ANTAG_OVERRIDE_JOB)
- ghost_antag_templates |= antag
- else if(antag.flags & ANTAG_RANDSPAWN)
- living_antag_templates |= antag
- else
- antag_templates -= antag
- world << "[antag.role_text_plural] are invalid for additional roundtype antags!"
+ if(antag.flags & (ANTAG_OVERRIDE_JOB|ANTAG_RANDSPAWN))
+ continue
+ antag_templates -= antag
+ world << "[antag.role_text_plural] are invalid for additional roundtype antags!"
newscaster_announcements = pick(newscaster_standard_feeds)
diff --git a/code/game/gamemodes/game_mode_latespawn.dm b/code/game/gamemodes/game_mode_latespawn.dm
new file mode 100644
index 0000000000..9af3524144
--- /dev/null
+++ b/code/game/gamemodes/game_mode_latespawn.dm
@@ -0,0 +1,43 @@
+/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())
+ usable_templates |= A
+ return usable_templates
+
+///process()
+///Called by the gameticker
+/datum/game_mode/proc/process()
+ try_latespawn()
+
+/datum/game_mode/proc/latespawn(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, var/latejoin_only)
+
+ if(emergency_shuttle.departed || !round_autoantag)
+ return
+
+ if(!prob(get_antag_prob()))
+ return
+
+ var/list/usable_templates
+ if(latejoin_only && latejoin_templates.len)
+ usable_templates = get_usable_templates(latejoin_templates)
+ else if (antag_templates.len)
+ usable_templates = get_usable_templates(antag_templates)
+ else
+ return
+ if(usable_templates.len)
+ var/datum/antagonist/spawn_antag = pick(usable_templates)
+ spawn_antag.attempt_late_spawn(player)
+
+/datum/game_mode/proc/get_antag_prob()
+ var/player_count = 0
+ for(var/mob/living/M in mob_list)
+ if(M.client)
+ player_count += 1
+ return min(100,max(0,(player_count - 5 * 10) * 5))
\ No newline at end of file
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index c91d77dba2..452754d746 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -1164,7 +1164,7 @@ proc/admin_notice(var/message, var/rights)
out += "Core antag id: [ticker.mode.antag_tag]."
if(ticker.mode.round_autoantag)
- out += "Autotraitor enabled ([ticker.mode.antag_prob]% spawn chance)"
+ out += "Autotraitor enabled ([ticker.mode.get_antag_prob()]% spawn chance)"
if(ticker.mode.antag_scaling_coeff)
out += " (scaling with [ticker.mode.antag_scaling_coeff])"
out += "
"