diff --git a/baystation12.dme b/baystation12.dme
index 4f863fdac92..76be5e8764e 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -238,6 +238,7 @@
#include "code\game\antagonist\antagonist_add.dm"
#include "code\game\antagonist\antagonist_create.dm"
#include "code\game\antagonist\antagonist_equip.dm"
+#include "code\game\antagonist\antagonist_factions.dm"
#include "code\game\antagonist\antagonist_helpers.dm"
#include "code\game\antagonist\antagonist_objectives.dm"
#include "code\game\antagonist\antagonist_panel.dm"
@@ -256,6 +257,7 @@
#include "code\game\antagonist\station\changeling.dm"
#include "code\game\antagonist\station\cultist.dm"
#include "code\game\antagonist\station\highlander.dm"
+#include "code\game\antagonist\station\loyalist.dm"
#include "code\game\antagonist\station\renegade.dm"
#include "code\game\antagonist\station\revolutionary.dm"
#include "code\game\antagonist\station\rogue_ai.dm"
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 06adfe42f96..1482efb88ad 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -74,9 +74,6 @@ var/list/gamemode_cache = list()
var/automute_on = 0 //enables automuting/spam prevention
var/jobs_have_minimal_access = 0 //determines whether jobs use minimal access or expanded access.
- var/rp_rev = 0 // Changes between conversion methods in rev.
- var/announce_revheads = 0 // Determines if revheads are announced in revolution mode.
-
var/cult_ghostwriter = 1 //Allows ghosts to write in blood in cult rounds...
var/cult_ghostwriter_req_cultists = 10 //...so long as this many cultists are active.
@@ -636,12 +633,6 @@ var/list/gamemode_cache = list()
if("disable_welder_vision")
config.welder_vision = 0
- if("rp_rev")
- config.rp_rev = 1
-
- if("announce_revheads")
- config.announce_revheads = 1
-
if("allow_extra_antags")
config.allow_extra_antags = 1
@@ -841,21 +832,15 @@ var/list/gamemode_cache = list()
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
return gamemode_cache["extended"]
/datum/configuration/proc/get_runnable_modes()
- var/list/datum/game_mode/runnable_modes = new
- for (var/game_mode in gamemode_cache)
+ var/list/runnable_modes = list()
+ for(var/game_mode in gamemode_cache)
var/datum/game_mode/M = gamemode_cache[game_mode]
- if (!(M.config_tag in modes))
- continue
- if (probabilities[M.config_tag]<=0)
- continue
- if (M.can_start())
- runnable_modes[M] = probabilities[M.config_tag]
- //world << "DEBUG: runnable_mode\[[runnable_modes.len]\] = [M.config_tag]"
+ if(M && M.can_start() && !isnull(config.probabilities[M.config_tag]) && config.probabilities[M.config_tag] > 0)
+ runnable_modes |= M
return runnable_modes
/datum/configuration/proc/post_load()
diff --git a/code/game/antagonist/alien/borer.dm b/code/game/antagonist/alien/borer.dm
index bd436ceaf8e..aabb6bd7e39 100644
--- a/code/game/antagonist/alien/borer.dm
+++ b/code/game/antagonist/alien/borer.dm
@@ -7,7 +7,14 @@ var/datum/antagonist/xenos/borer/borers
mob_path = /mob/living/simple_animal/borer
bantype = "Borer"
welcome_text = "Use your Infest power to crawl into the ear of a host and fuse with their brain. You can only take control temporarily, and at risk of hurting your host, so be clever and careful; your host is encouraged to help you however they can. Talk to your fellow borers with :x."
- var/list/hosts = list()
+ antag_indicator = "brainworm"
+
+ faction_role_text = "Borer Thrall"
+ faction_descriptor = "Unity"
+ faction_welcome = "You are now a thrall to a cortical borer. Please listen to what they have to say; they're in your head."
+
+ initial_spawn_req = 3
+ initial_spawn_target = 5
/datum/antagonist/xenos/borer/New()
..(1)
@@ -23,32 +30,23 @@ var/datum/antagonist/xenos/borer/borers
player.objectives += new /datum/objective/borer_reproduce()
player.objectives += new /datum/objective/escape()
-/datum/antagonist/xenos/borer/proc/place_in_host(var/mob/living/simple_animal/borer/borer, var/mob/living/carbon/human/host)
- borer.host = host
- borer.host_brain.name = host.name
- borer.host_brain.real_name = host.real_name
- var/obj/item/organ/external/head = host.get_organ("head")
- if(head) head.implants += borer
-
-/datum/antagonist/xenos/borer/proc/get_hosts()
- var/list/possible_hosts = list()
- for(var/mob/living/carbon/human/H in mob_list)
- var/obj/item/organ/external/head/head = H.get_organ("head")
- if(head.status & ORGAN_ROBOT)
- continue
- if(H.stat != DEAD && !H.has_brain_worms())
- possible_hosts |= H
- return possible_hosts
-
-/datum/antagonist/xenos/borer/place_all_mobs()
- var/list/possible_hosts = get_hosts()
- for(var/datum/mind/player in current_antagonists)
- if(!possible_hosts.len)
- return
- var/mob/host = pick(possible_hosts)
- possible_hosts -= host
- place_in_host(player, host)
-
/datum/antagonist/xenos/borer/place_mob(var/mob/living/mob)
- var/list/possible_hosts = get_hosts()
- if(possible_hosts.len) place_in_host(mob, pick(possible_hosts))
+ var/mob/living/simple_animal/borer/borer = mob
+ if(istype(borer))
+ var/mob/living/carbon/human/host
+ for(var/mob/living/carbon/human/H in mob_list)
+ if(H.stat != 2 && !(H.species.flags & IS_SYNTHETIC) && !H.has_brain_worms())
+ host = H
+ break
+ if(istype(host))
+ var/obj/item/organ/external/head = host.get_organ("head")
+ if(head)
+ borer.host = host
+ head.implants += borer
+ borer.loc = head
+ if(!borer.host_brain)
+ borer.host_brain = new(borer)
+ borer.host_brain.name = host.name
+ borer.host_brain.real_name = host.real_name
+ return
+ ..() // Place them at a vent if they can't get a host.
diff --git a/code/game/antagonist/alien/xenomorph.dm b/code/game/antagonist/alien/xenomorph.dm
index f93409a8203..f6a8bc5cb1d 100644
--- a/code/game/antagonist/alien/xenomorph.dm
+++ b/code/game/antagonist/alien/xenomorph.dm
@@ -10,27 +10,21 @@ var/datum/antagonist/xenos/xenomorphs
flags = ANTAG_OVERRIDE_MOB | ANTAG_RANDSPAWN | ANTAG_OVERRIDE_JOB | ANTAG_VOTABLE
welcome_text = "Hiss! You are a larval alien. Hide and bide your time until you are ready to evolve."
- max_antags = 5
- max_antags_round = 8
+ hard_cap = 5
+ hard_cap_round = 8
+ initial_spawn_req = 4
+ initial_spawn_target = 6
spawn_announcement = "Unidentified lifesigns detected coming aboard the station. Secure any exterior access, including ducting and ventilation."
spawn_announcement_title = "Lifesign Alert"
spawn_announcement_sound = 'sound/AI/aliens.ogg'
- spawn_announcement_delay = 400
+ spawn_announcement_delay = 5000
/datum/antagonist/xenos/New(var/no_reference)
..()
if(!no_reference)
xenomorphs = src
-/datum/antagonist/xenos/Topic(href, href_list)
- if (..())
- return
- if(href_list["move_to_spawn"]) place_mob(locate(href_list["move_to_spawn"]))
-
-/datum/antagonist/xenos/get_extra_panel_options(var/datum/mind/player)
- return "\[move to vent\]"
-
/datum/antagonist/xenos/attempt_random_spawn()
if(config.aliens_allowed) ..()
@@ -48,12 +42,5 @@ var/datum/antagonist/xenos/xenomorphs
player.objectives += new /datum/objective/survive()
player.objectives += new /datum/objective/escape()
-/datum/antagonist/xenos/place_all_mobs()
- var/list/vents = get_vents()
- for(var/datum/mind/player in current_antagonists)
- var/obj/machinery/atmospherics/unary/vent_pump/temp_vent = pick(vents)
- vents -= temp_vent
- player.current.loc = get_turf(temp_vent)
-
/datum/antagonist/xenos/place_mob(var/mob/living/player)
player.loc = get_turf(pick(get_vents()))
diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm
index 220ba7e6d1d..3be89beba17 100644
--- a/code/game/antagonist/antagonist.dm
+++ b/code/game/antagonist/antagonist.dm
@@ -1,53 +1,76 @@
/datum/antagonist
- var/role_type = BE_TRAITOR
- var/role_text = "Traitor"
- var/role_text_plural = "Traitors"
+ // Text shown when becoming this antagonist.
+ var/list/restricted_jobs = list() // Jobs that cannot be this antagonist (depending on config)
+ var/list/protected_jobs = list() // As above.
+
+ // Strings.
var/welcome_text = "Cry havoc and let slip the dogs of war!"
- var/leader_welcome_text
- var/victory_text
- var/loss_text
- var/victory_feedback_tag
- var/loss_feedback_tag
- var/max_antags = 3
- var/max_antags_round = 5
+ var/leader_welcome_text // Text shown to the leader, if any.
+ var/victory_text // World output at roundend for victory.
+ var/loss_text // As above for loss.
+ var/victory_feedback_tag // Used by the database for end of round loss.
+ var/loss_feedback_tag // Used by the database for end of round loss.
- // Random spawn values.
- var/spawn_announcement
- var/spawn_announcement_title
- var/spawn_announcement_sound
- var/spawn_announcement_delay
+ // Role data.
+ var/id = "traitor" // Unique datum identifier.
+ var/role_type = BE_TRAITOR // Preferences option for this role.
+ var/role_text = "Traitor" // special_role text.
+ var/role_text_plural = "Traitors" // As above but plural.
- var/id = "traitor"
- var/landmark_id
- var/antag_indicator
- var/mob_path = /mob/living/carbon/human
- var/feedback_tag = "traitor_objective"
- var/bantype = "Syndicate"
- var/suspicion_chance = 50
- var/flags = 0
- var/cur_max = 0
+ // Visual references.
+ var/antag_indicator // icon_state for icons/mob/mob.dm visual indicator.
+ var/faction_indicator // See antag_indicator, but for factionalized people only.
+ var/faction_invisible // Can members of the faction identify other antagonists?
- var/datum/mind/leader
- var/spawned_nuke
- var/nuke_spawn_loc
+ // Faction data.
+ var/faction_role_text // Role for sub-antags. Mandatory for faction role.
+ var/faction_descriptor // Description of the cause. Mandatory for faction role.
+ var/faction_verb // Verb added when becoming a member of the faction, if any.
+ var/faction_welcome // Message shown to faction members.
- var/list/valid_species = list("Unathi","Tajara","Skrell","Human") // Used for setting appearance.
- 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()
- var/list/candidates = list()
+ // Spawn values (autotraitor and game mode)
+ var/hard_cap = 3 // Autotraitor var. Won't spawn more than this many antags.
+ var/hard_cap_round = 5 // As above but 'core' round antags ie. roundstart.
+ var/initial_spawn_req = 1 // Gamemode using this template won't start without this # candidates.
+ var/initial_spawn_target = 3 // Gamemode will attempt to spawn this many antags.
+ var/announced // Has an announcement been sent?
+ var/spawn_announcement // When the datum spawn proc is called, does it announce to the world? (ie. xenos)
+ var/spawn_announcement_title // Report title.
+ var/spawn_announcement_sound // Report sound clip.
+ var/spawn_announcement_delay // Time between initial spawn and round announcement.
+ // Misc.
+ var/landmark_id // Spawn point identifier.
+ var/mob_path = /mob/living/carbon/human // Mobtype this antag will use if none is provided.
+ var/feedback_tag = "traitor_objective" // End of round
+ var/bantype = "Syndicate" // Ban to check when spawning this antag.
+ var/suspicion_chance = 50 // Prob of being on the initial Command report
+ var/flags = 0 // Various runtime options.
+
+ // Used for setting appearance.
+ var/list/valid_species = list("Unathi","Tajara","Skrell","Human")
+
+ // Runtime vars.
+ var/datum/mind/leader // Current leader, if any.
+ var/cur_max = 0 // Autotraitor current effective maximum.
+ var/spawned_nuke // Has a bomb been spawned?
+ var/nuke_spawn_loc // If so, where should it be placed?
+ var/list/current_antagonists = list() // All marked antagonists for this type.
+ var/list/pending_antagonists = list() // Candidates that are awaiting finalized antag status.
+ var/list/starting_locations = list() // Spawn points.
+ var/list/global_objectives = list() // Universal objectives if any.
+ var/list/candidates = list() // Potential candidates.
+ var/list/faction_members = list() // Semi-antags (in-round revs, borer thralls)
+
+ // ID card stuff.
var/default_access = list()
var/id_type = /obj/item/weapon/card/id
- var/announced
+
/datum/antagonist/New()
..()
- cur_max = max_antags
+ cur_max = hard_cap
get_starting_locations()
if(!role_text_plural)
role_text_plural = role_text
@@ -59,7 +82,7 @@
/datum/antagonist/proc/get_candidates(var/ghosts_only)
candidates = list() // Clear.
-
+
// Prune restricted status. Broke it up for readability.
// Note that this is done before jobs are handed out.
for(var/datum/mind/player in ticker.mode.get_players_for_role(role_type, id))
@@ -85,14 +108,21 @@
/datum/antagonist/proc/attempt_late_spawn(var/datum/mind/player)
if(!can_late_spawn())
- return
- if(!istype(player)) player = get_candidates(is_latejoin_template())
+ 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,1,0,1,1)
- return
+ 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.
@@ -111,7 +141,7 @@
return 0
//Grab candidates randomly until we have enough.
- while(candidates.len && pending_antagonists.len < cur_max)
+ while(candidates.len && pending_antagonists.len < initial_spawn_target)
var/datum/mind/player = pick(candidates)
candidates -= player
draft_antagonist(player)
@@ -132,14 +162,14 @@
pending_antagonists |= player
log_debug("[player.key] has been selected for [role_text] by lottery.")
-
+
//Ensure that antags with ANTAG_OVERRIDE_JOB do not occupy job slots.
if(flags & ANTAG_OVERRIDE_JOB)
player.assigned_role = role_text
-
+
//Ensure that a player cannot be drafted for multiple antag roles, taking up slots for antag roles that they will not fill.
player.special_role = role_text
-
+
return 1
//Spawns all pending_antagonists. This is done separately from attempt_spawn in case the game mode setup fails.
diff --git a/code/game/antagonist/antagonist_add.dm b/code/game/antagonist/antagonist_add.dm
index 7815167d6fe..5ca66731c47 100644
--- a/code/game/antagonist/antagonist_add.dm
+++ b/code/game/antagonist/antagonist_add.dm
@@ -1,15 +1,8 @@
/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
-
+ if(!add_antagonist_mind(player, ignore_role))
+ return
+
//do this again, just in case
if(flags & ANTAG_OVERRIDE_JOB)
player.assigned_role = role_text
@@ -23,10 +16,37 @@
equip(player.current)
return 1
+/datum/antagonist/proc/add_antagonist_mind(var/datum/mind/player, var/ignore_role, var/nonstandard_role_type, var/nonstandard_role_msg)
+ 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
+
+ if(faction_verb && player.current)
+ player.current.verbs |= faction_verb
+
+ // Handle only adding a mind and not bothering with gear etc.
+ if(nonstandard_role_type)
+ faction_members |= player
+ player.current << "You are \a [nonstandard_role_type]!"
+ player.special_role = nonstandard_role_type
+ if(nonstandard_role_msg)
+ player.current << "[nonstandard_role_msg]"
+ update_icons_added(player)
+ return 1
+
/datum/antagonist/proc/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted)
+ if(player.current && faction_verb)
+ player.current.verbs -= faction_verb
if(player in current_antagonists)
player.current << "You are no longer a [role_text]!"
current_antagonists -= player
+ faction_members -= player
player.special_role = null
update_icons_removed(player)
BITSET(player.current.hud_updateflag, SPECIALROLE_HUD)
diff --git a/code/game/antagonist/antagonist_factions.dm b/code/game/antagonist/antagonist_factions.dm
new file mode 100644
index 00000000000..83c9957be20
--- /dev/null
+++ b/code/game/antagonist/antagonist_factions.dm
@@ -0,0 +1,50 @@
+/mob/living/proc/convert_to_rev(mob/M as mob in oview(src))
+ set name = "Convert Bourgeoise"
+ set category = "Abilities"
+ if(!M.mind)
+ return
+ convert_to_faction(M.mind, revs)
+
+/mob/living/proc/convert_to_faction(var/datum/mind/player, var/datum/antagonist/faction)
+
+ if(!player || !faction || !player.current)
+ return
+
+ if(!faction.faction_verb || !faction.faction_descriptor || !faction.faction_verb)
+ return
+
+ if(faction.is_antagonist(player))
+ src << "\The [player.current] already serves the [faction.faction_descriptor]."
+ return
+
+ if(player_is_antag(player))
+ src << "\The [player.current]'s loyalties seem to be elsewhere..."
+ return
+
+ if(!faction.can_become_antag(player))
+ src << "\The [player.current] cannot be \a [faction.faction_role_text]!"
+ return
+
+ if(world.time < player.rev_cooldown)
+ src << "You must wait five seconds between attempts."
+ return
+
+ src << "You are attempting to convert \the [player.current]..."
+ log_admin("[src]([src.ckey]) attempted to convert [player.current].")
+ message_admins("[src]([src.ckey]) attempted to convert [player.current].")
+
+ player.rev_cooldown = world.time+100
+ var/choice = alert(player.current,"Asked by [src]: Do you want to join the [faction.faction_descriptor]?","Join the [faction.faction_descriptor]?","No!","Yes!")
+ if(choice == "Yes!" && faction.add_antagonist_mind(player, 0, faction.faction_role_text, faction.faction_welcome))
+ src << "\The [player.current] joins the [faction.faction_descriptor]!"
+ return
+ if(choice == "No!")
+ player << "You reject this traitorous cause!"
+ src << "\The [player.current] does not support the [faction.faction_descriptor]!"
+
+/mob/living/proc/convert_to_loyalist(mob/M as mob in oview(src))
+ set name = "Convert Recidivist"
+ set category = "Abilities"
+ if(!M.mind)
+ return
+ convert_to_faction(M.mind, loyalists)
\ No newline at end of file
diff --git a/code/game/antagonist/antagonist_place.dm b/code/game/antagonist/antagonist_place.dm
index 1d69aaa96f8..db8c74a14f6 100644
--- a/code/game/antagonist/antagonist_place.dm
+++ b/code/game/antagonist/antagonist_place.dm
@@ -5,23 +5,20 @@
if(L.name == landmark_id)
starting_locations |= get_turf(L)
-/datum/antagonist/proc/place_all_mobs()
- if(!starting_locations || !starting_locations.len || !current_antagonists || !current_antagonists.len)
- return
- for(var/datum/mind/player in current_antagonists)
- player.current.loc = pick(starting_locations)
-
/datum/antagonist/proc/announce_antagonist_spawn()
+
if(spawn_announcement)
if(announced)
return
announced = 1
- 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"]")
+ spawn(0)
+ 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"]")
+ return
/datum/antagonist/proc/place_mob(var/mob/living/mob)
if(!starting_locations || !starting_locations.len)
diff --git a/code/game/antagonist/antagonist_update.dm b/code/game/antagonist/antagonist_update.dm
index 0fd5fb2a93f..59e3489587f 100644
--- a/code/game/antagonist/antagonist_update.dm
+++ b/code/game/antagonist/antagonist_update.dm
@@ -22,50 +22,63 @@
id.name = "[player.real_name]'s ID Card"
id.registered_name = player.real_name
+/datum/antagonist/proc/clear_indicators(var/datum/mind/recipient)
+ if(!recipient.current || !recipient.current.client)
+ return
+ for(var/image/I in recipient.current.client.images)
+ if(I.icon_state == antag_indicator || (faction_indicator && I.icon_state == faction_indicator))
+ qdel(I)
+
+/datum/antagonist/proc/get_indicator(var/datum/mind/recipient, var/datum/mind/other)
+ if(!antag_indicator || !other.current || !recipient.current)
+ return
+ var/indicator = (faction_indicator && (other in faction_members)) ? faction_indicator : antag_indicator
+ return image('icons/mob/mob.dmi', loc = other.current, icon_state = indicator)
+
/datum/antagonist/proc/update_all_icons()
if(!antag_indicator)
return
for(var/datum/mind/antag in current_antagonists)
- if(antag.current && antag.current.client)
- for(var/image/I in antag.current.client.images)
- if(I.icon_state == antag_indicator)
- qdel(I)
- for(var/datum/mind/other_antag in current_antagonists)
- if(other_antag.current)
- antag.current.client.images |= image('icons/mob/mob.dmi', loc = other_antag.current, icon_state = antag_indicator)
+ clear_indicators(antag)
+ if(faction_invisible && (antag in faction_members))
+ continue
+ for(var/datum/mind/other_antag in current_antagonists)
+ if(antag.current && antag.current.client)
+ antag.current.client.images |= get_indicator(antag, other_antag)
/datum/antagonist/proc/update_icons_added(var/datum/mind/player)
if(!antag_indicator || !player.current)
return
spawn(0)
+
+ var/give_to_player = (!faction_invisible || !(player in faction_members))
for(var/datum/mind/antag in current_antagonists)
if(!antag.current)
continue
if(antag.current.client)
- antag.current.client.images |= image('icons/mob/mob.dmi', loc = player.current, icon_state = antag_indicator)
+ antag.current.client.images |= get_indicator(antag, player)
+ if(!give_to_player)
+ continue
if(player.current.client)
- player.current.client.images |= image('icons/mob/mob.dmi', loc = antag.current, icon_state = antag_indicator)
+ player.current.client.images |= get_indicator(player, antag)
/datum/antagonist/proc/update_icons_removed(var/datum/mind/player)
if(!antag_indicator || !player.current)
return
spawn(0)
- for(var/datum/mind/antag in current_antagonists)
- if(antag.current)
- if(antag.current.client)
- for(var/image/I in antag.current.client.images)
- if(I.icon_state == antag_indicator && I.loc == player.current)
- qdel(I)
+ clear_indicators(player)
if(player.current && player.current.client)
- for(var/image/I in player.current.client.images)
- if(I.icon_state == antag_indicator)
- qdel(I)
+ for(var/datum/mind/antag in current_antagonists)
+ if(antag.current && antag.current.client)
+ for(var/image/I in antag.current.client.images)
+ if(I.loc == player.current)
+ qdel(I)
/datum/antagonist/proc/update_current_antag_max()
var/main_type
if(ticker && ticker.mode)
- if(ticker.mode.antag_tag && ticker.mode.antag_tag == id)
+ if(ticker.mode.antag_tags && (id in ticker.mode.antag_tags))
main_type = 1
- cur_max = (main_type ? max_antags_round : max_antags)
+ cur_max = (main_type ? hard_cap_round : hard_cap)
if(ticker.mode.antag_scaling_coeff)
cur_max = Clamp((ticker.mode.num_players()/ticker.mode.antag_scaling_coeff), 1, cur_max)
diff --git a/code/game/antagonist/outsider/commando.dm b/code/game/antagonist/outsider/commando.dm
index 50d8ac5361b..8cdee8639c1 100644
--- a/code/game/antagonist/outsider/commando.dm
+++ b/code/game/antagonist/outsider/commando.dm
@@ -7,6 +7,12 @@ var/datum/antagonist/deathsquad/mercenary/commandos
role_text_plural = "Commandos"
welcome_text = "You are in the employ of a criminal syndicate hostile to NanoTrasen."
+ hard_cap = 4
+ hard_cap_round = 8
+ initial_spawn_req = 4
+ initial_spawn_target = 6
+
+
/datum/antagonist/deathsquad/mercenary/New()
..(1)
commandos = src
diff --git a/code/game/antagonist/outsider/deathsquad.dm b/code/game/antagonist/outsider/deathsquad.dm
index 376f25c34ac..4b655be47ea 100644
--- a/code/game/antagonist/outsider/deathsquad.dm
+++ b/code/game/antagonist/outsider/deathsquad.dm
@@ -8,9 +8,13 @@ var/datum/antagonist/deathsquad/deathsquad
welcome_text = "You work in the service of Central Command Asset Protection, answering directly to the Board of Directors."
landmark_id = "Commando"
flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_HAS_NUKE | ANTAG_HAS_LEADER
- max_antags = 4
- max_antags_round = 6
default_access = list(access_cent_general, access_cent_specops, access_cent_living, access_cent_storage)
+
+ hard_cap = 4
+ hard_cap_round = 8
+ initial_spawn_req = 4
+ initial_spawn_target = 6
+
var/deployed = 0
/datum/antagonist/deathsquad/New(var/no_reference)
diff --git a/code/game/antagonist/outsider/ert.dm b/code/game/antagonist/outsider/ert.dm
index d847d4ef7a8..64338c5a939 100644
--- a/code/game/antagonist/outsider/ert.dm
+++ b/code/game/antagonist/outsider/ert.dm
@@ -8,12 +8,14 @@ var/datum/antagonist/ert/ert
role_text_plural = "Emergency Responders"
welcome_text = "As member of the Emergency Response Team, you answer only to your leader and CentComm officials."
leader_welcome_text = "As leader of the Emergency Response Team, you answer only to CentComm, and have authority to override the Captain where it is necessary to achieve your mission goals. It is recommended that you attempt to cooperate with the captain where possible, however."
- max_antags = 5
- max_antags_round = 5 // ERT mode?
landmark_id = "Response Team"
-
flags = ANTAG_OVERRIDE_JOB | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER | ANTAG_CHOOSE_NAME
+ hard_cap = 5
+ hard_cap_round = 7
+ initial_spawn_req = 5
+ initial_spawn_target = 7
+
/datum/antagonist/ert/create_default(var/mob/source)
var/mob/living/carbon/human/M = ..()
if(istype(M)) M.age = rand(25,45)
diff --git a/code/game/antagonist/outsider/mercenary.dm b/code/game/antagonist/outsider/mercenary.dm
index 1ddc6457d94..69d9f604202 100644
--- a/code/game/antagonist/outsider/mercenary.dm
+++ b/code/game/antagonist/outsider/mercenary.dm
@@ -5,15 +5,19 @@ var/datum/antagonist/mercenary/mercs
role_type = BE_OPERATIVE
role_text = "Mercenary"
bantype = "operative"
+ antag_indicator = "synd"
role_text_plural = "Mercenaries"
landmark_id = "Syndicate-Spawn"
leader_welcome_text = "You are the leader of the mercenary strikeforce; hail to the chief. Use :t to speak to your underlings."
welcome_text = "To speak on the strike team's private channel use :t."
flags = ANTAG_OVERRIDE_JOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_HAS_NUKE | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER
- max_antags = 4
- max_antags_round = 6
id_type = /obj/item/weapon/card/id/syndicate
+ hard_cap = 4
+ hard_cap_round = 8
+ initial_spawn_req = 4
+ initial_spawn_target = 6
+
/datum/antagonist/mercenary/New()
..()
mercs = src
@@ -44,14 +48,6 @@ var/datum/antagonist/mercenary/mercs
create_radio(SYND_FREQ, player)
return 1
-/datum/antagonist/mercenary/place_all_mobs()
- var/spawnpos = 1
- for(var/datum/mind/player in current_antagonists)
- player.current.loc = starting_locations[spawnpos]
- spawnpos++
- if(spawnpos > starting_locations.len)
- spawnpos = 1
-
/datum/antagonist/mercenary/create_nuke()
..()
// Create the radio.
diff --git a/code/game/antagonist/outsider/ninja.dm b/code/game/antagonist/outsider/ninja.dm
index a29cfc44fa4..2d04334737c 100644
--- a/code/game/antagonist/outsider/ninja.dm
+++ b/code/game/antagonist/outsider/ninja.dm
@@ -9,8 +9,12 @@ 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 = 1
- max_antags_round = 1
+
+ initial_spawn_req = 1
+ initial_spawn_target = 1
+ hard_cap = 1
+ hard_cap_round = 3
+
id_type = /obj/item/weapon/card/id/syndicate
/datum/antagonist/ninja/New()
diff --git a/code/game/antagonist/outsider/raider.dm b/code/game/antagonist/outsider/raider.dm
index 8ac7530e926..f377480a4da 100644
--- a/code/game/antagonist/outsider/raider.dm
+++ b/code/game/antagonist/outsider/raider.dm
@@ -6,11 +6,16 @@ var/datum/antagonist/raider/raiders
role_text = "Raider"
role_text_plural = "Raiders"
bantype = "raider"
+ antag_indicator = "mutineer"
landmark_id = "voxstart"
welcome_text = "Use :H to talk on your encrypted channel."
flags = ANTAG_OVERRIDE_JOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_VOTABLE | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER
- max_antags = 6
- max_antags_round = 10
+
+ hard_cap = 6
+ hard_cap_round = 10
+ initial_spawn_req = 4
+ initial_spawn_target = 6
+
id_type = /obj/item/weapon/card/id/syndicate
// Heist overrides check_victory() and doesn't need victory or loss strings/tags.
diff --git a/code/game/antagonist/outsider/wizard.dm b/code/game/antagonist/outsider/wizard.dm
index 57a00adfdde..af1fc09e8e6 100644
--- a/code/game/antagonist/outsider/wizard.dm
+++ b/code/game/antagonist/outsider/wizard.dm
@@ -9,8 +9,12 @@ var/datum/antagonist/wizard/wizards
landmark_id = "wizard"
welcome_text = "You will find a list of available spells in your spell book. Choose your magic arsenal carefully.
In your pockets you will find a teleport scroll. Use it as needed."
flags = ANTAG_OVERRIDE_JOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_VOTABLE | ANTAG_SET_APPEARANCE
- max_antags = 1
- max_antags_round = 1
+
+ hard_cap = 1
+ hard_cap_round = 3
+ initial_spawn_req = 1
+ initial_spawn_target = 1
+
/datum/antagonist/wizard/New()
..()
diff --git a/code/game/antagonist/station/cultist.dm b/code/game/antagonist/station/cultist.dm
index 78d07adcf27..20c2bd428d4 100644
--- a/code/game/antagonist/station/cultist.dm
+++ b/code/game/antagonist/station/cultist.dm
@@ -22,10 +22,12 @@ var/datum/antagonist/cultist/cult
victory_feedback_tag = "win - cult win"
loss_feedback_tag = "loss - staff stopped the cult"
flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE
- max_antags = 200 // No upper limit.
- max_antags_round = 200
- var/allow_narsie = 1
+ hard_cap = 5
+ hard_cap_round = 6
+ initial_spawn_req = 4
+ initial_spawn_target = 6
+ var/allow_narsie = 1
var/datum/mind/sacrifice_target
var/list/startwords = list("blood","join","self","hell")
var/list/allwords = list("travel","self","see","hell","blood","join","tech","destroy", "other", "hide")
diff --git a/code/game/antagonist/station/highlander.dm b/code/game/antagonist/station/highlander.dm
index 1fd573bf1a3..23d816bd975 100644
--- a/code/game/antagonist/station/highlander.dm
+++ b/code/game/antagonist/station/highlander.dm
@@ -6,8 +6,11 @@ var/datum/antagonist/highlander/highlanders
welcome_text = "There can be only one."
id = MODE_HIGHLANDER
flags = ANTAG_SUSPICIOUS | ANTAG_IMPLANT_IMMUNE //| ANTAG_RANDSPAWN | ANTAG_VOTABLE // Someday...
- max_antags = 5
- max_antags_round = 7
+
+ hard_cap = 5
+ hard_cap_round = 7
+ initial_spawn_req = 3
+ initial_spawn_target = 5
/datum/antagonist/highlander/New()
..()
diff --git a/code/game/antagonist/station/loyalist.dm b/code/game/antagonist/station/loyalist.dm
new file mode 100644
index 00000000000..4b95467691f
--- /dev/null
+++ b/code/game/antagonist/station/loyalist.dm
@@ -0,0 +1,46 @@
+var/datum/antagonist/loyalists/loyalists
+
+/datum/antagonist/loyalists
+ id = MODE_LOYALIST
+ role_type = BE_LOYALIST
+ role_text = "Head Loyalist"
+ role_text_plural = "Loyalists"
+ bantype = "loyalist"
+ feedback_tag = "loyalist_objective"
+ antag_indicator = "loyal_head"
+ welcome_text = "You belong to the Company, body and soul. Preserve its interests against the conspirators amongst the crew."
+ victory_text = "The heads of staff remained at their posts! The loyalists win!"
+ loss_text = "The heads of staff did not stop the revolution!"
+ victory_feedback_tag = "win - rev heads killed"
+ loss_feedback_tag = "loss - heads killed"
+ flags = 0
+
+ hard_cap = 2
+ hard_cap_round = 4
+ initial_spawn_req = 2
+ initial_spawn_target = 4
+
+ // Inround loyalists.
+ faction_role_text = "Loyalist"
+ faction_descriptor = "Company"
+ faction_verb = /mob/living/proc/convert_to_loyalist
+ faction_welcome = "Preserve NanoTrasen's interests against the traitorous recidivists amongst the crew. Protect the heads of staff with your life."
+ faction_indicator = "loyal"
+ faction_invisible = 1
+ restricted_jobs = list("AI", "Cyborg")
+
+/datum/antagonist/loyalists/New()
+ ..()
+ loyalists = src
+
+/datum/antagonist/loyalists/create_global_objectives()
+ if(!..())
+ return
+ global_objectives = list()
+ for(var/mob/living/carbon/human/player in mob_list)
+ if(!player.mind || player.stat==2 || !(player.mind.assigned_role in command_positions))
+ continue
+ var/datum/objective/protect/loyal_obj = new
+ loyal_obj.target = player.mind
+ loyal_obj.explanation_text = "Protect [player.real_name], the [player.mind.assigned_role]."
+ global_objectives += loyal_obj
diff --git a/code/game/antagonist/station/renegade.dm b/code/game/antagonist/station/renegade.dm
index 9b275776f88..cd9dd9b83bb 100644
--- a/code/game/antagonist/station/renegade.dm
+++ b/code/game/antagonist/station/renegade.dm
@@ -6,30 +6,28 @@ var/datum/antagonist/renegade/renegades
welcome_text = "Your own safety matters above all else, trust no one and kill anyone who gets in your way. However, armed as you are, now would be the perfect time to settle that score or grab that pair of yellow gloves you've been eyeing..."
id = MODE_RENEGADE
flags = ANTAG_SUSPICIOUS | ANTAG_IMPLANT_IMMUNE | ANTAG_RANDSPAWN | ANTAG_VOTABLE
- max_antags = 5
- max_antags_round = 7
+ hard_cap = 5
+ hard_cap_round = 7
+
+ hard_cap = 8
+ hard_cap_round = 12
+ initial_spawn_req = 3
+ initial_spawn_target = 6
var/list/spawn_guns = list(
- /obj/item/weapon/gun/energy/taser,
/obj/item/weapon/gun/energy/gun,
/obj/item/weapon/gun/energy/laser,
/obj/item/weapon/gun/projectile,
/obj/item/weapon/gun/projectile/revolver/detective,
/obj/item/weapon/gun/projectile/automatic/c20r,
- /obj/item/weapon/gun/energy/gun/nuclear,
/obj/item/weapon/gun/projectile/deagle/camo,
/obj/item/weapon/gun/projectile/pistol,
/obj/item/weapon/silencer,
- /obj/item/weapon/gun/energy/lasercannon,
/obj/item/weapon/gun/projectile/shotgun/pump,
/obj/item/weapon/gun/projectile/shotgun/pump/combat,
/obj/item/weapon/gun/projectile/automatic,
/obj/item/weapon/gun/projectile/automatic/mini_uzi,
/obj/item/weapon/gun/energy/crossbow
- //obj/item/weapon/gun/projectile/gyropistol,
- //obj/item/weapon/gun/energy/pulse_rifle,
- //obj/item/weapon/gun/projectile/revolver/mateba,
- //obj/item/weapon/gun/projectile/automatic/l6_saw,
)
/datum/antagonist/renegade/New()
diff --git a/code/game/antagonist/station/revolutionary.dm b/code/game/antagonist/station/revolutionary.dm
index 06819c96ce6..f3454cf7561 100644
--- a/code/game/antagonist/station/revolutionary.dm
+++ b/code/game/antagonist/station/revolutionary.dm
@@ -3,196 +3,46 @@ var/datum/antagonist/revolutionary/revs
/datum/antagonist/revolutionary
id = MODE_REVOLUTIONARY
role_type = BE_REV
- role_text = "Revolutionary"
+ role_text = "Head Revolutionary"
role_text_plural = "Revolutionaries"
bantype = "revolutionary"
feedback_tag = "rev_objective"
- restricted_jobs = list("Internal Affairs Agent", "AI", "Cyborg","Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer")
- protected_jobs = list("Security Officer", "Warden", "Detective")
- antag_indicator = "rev"
- welcome_text = "The flash in your possession will help you to persuade the crew to join your cause."
+ antag_indicator = "rev_head"
+ welcome_text = "Down with the capitalists! Down with the Bourgeoise!"
victory_text = "The heads of staff were relieved of their posts! The revolutionaries win!"
loss_text = "The heads of staff managed to stop the revolution!"
victory_feedback_tag = "win - heads killed"
loss_feedback_tag = "loss - rev heads killed"
flags = ANTAG_SUSPICIOUS | ANTAG_VOTABLE
- max_antags = 200 // No upper limit.
- max_antags_round = 200
- var/list/head_revolutionaries = list()
+ hard_cap = 2
+ hard_cap_round = 4
+ initial_spawn_req = 2
+ initial_spawn_target = 4
+
+ //Inround revs.
+ faction_role_text = "Revolutionary"
+ faction_descriptor = "Revolution"
+ faction_verb = /mob/living/proc/convert_to_rev
+ faction_welcome = "Help the cause overturn the ruling class. Do not harm your fellow freedom fighters."
+ faction_indicator = "rev"
+ faction_invisible = 1
+
+ restricted_jobs = list("Internal Affairs Agent", "AI", "Cyborg","Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer")
+ protected_jobs = list("Security Officer", "Warden", "Detective")
/datum/antagonist/revolutionary/New()
..()
revs = src
-/datum/antagonist/revolutionary/is_antagonist(var/datum/mind/player)
- if(..() || (player in head_revolutionaries))
- return 1
- return 0
-
-/datum/antagonist/revolutionary/equip(mob/living/carbon/human/mob)
-
- if(!..())
- return 0
-
- if(!config.rp_rev)
- mob.verbs |= /mob/living/carbon/human/proc/convert_to_rev
- return
-
- var/obj/item/device/flash/T = new(mob)
-
- var/list/slots = list (
- "backpack" = slot_in_backpack,
- "left pocket" = slot_l_store,
- "right pocket" = slot_r_store,
- "left hand" = slot_l_hand,
- "right hand" = slot_r_hand,
- )
- mob.equip_in_one_of_slots(T, slots)
-
-/*
-datum/antagonist/revolutionary/finalize(var/datum/mind/target)
- if(target)
- return ..(target)
- current_antagonists |= head_revolutionaries
- create_global_objectives()
- ..()
-
-/datum/antagonist/revolutionary/get_additional_check_antag_output(var/datum/admins/caller)
- return ..() //Todo
-
- Rev extras:
- dat += "
| Revolutionaries | |
"
- for(var/datum/mind/N in ticker.mode.head_revolutionaries)
- var/mob/M = N.current
- if(!M)
- dat += "| Head Revolutionary not found! |
"
- else
- dat += "| [M.real_name] (Leader)[M.client ? "" : " (logged out)"][M.stat == 2 ? " (DEAD)" : ""] | "
- dat += "PM |
"
- for(var/datum/mind/N in ticker.mode.revolutionaries)
- var/mob/M = N.current
- if(M)
- dat += "| [M.real_name][M.client ? "" : " (logged out)"][M.stat == 2 ? " (DEAD)" : ""] | "
- dat += "PM |
"
- dat += "
| Target(s) | | Location |
"
- for(var/datum/mind/N in ticker.mode.get_living_heads())
- var/mob/M = N.current
- if(M)
- dat += "| [M.real_name][M.client ? "" : " (logged out)"][M.stat == 2 ? " (DEAD)" : ""] | "
- dat += "PM | "
- var/turf/mob_loc = get_turf(M)
- dat += "[mob_loc.loc] |
"
- else
- dat += "| Head not found! |
"
-*/
-
/datum/antagonist/revolutionary/create_global_objectives()
if(!..())
return
-
global_objectives = list()
-
- for(var/datum/mind/head_mind in get_living_heads())
- var/datum/objective/mutiny/rev_obj = new
- rev_obj.target = head_mind
- rev_obj.explanation_text = "Assassinate [head_mind.name], the [head_mind.assigned_role]."
+ for(var/mob/living/carbon/human/player in mob_list)
+ if(!player.mind || player.stat==2 || !(player.mind.assigned_role in command_positions))
+ continue
+ var/datum/objective/rev/rev_obj = new
+ rev_obj.target = player.mind
+ rev_obj.explanation_text = "Assassinate, capture or convert [player.real_name], the [player.mind.assigned_role]."
global_objectives += rev_obj
-
-/datum/antagonist/revolutionary/print_player_summary()
-
- current_antagonists |= head_revolutionaries
- if(!current_antagonists.len)
- return
-
- var/text = "
The [head_revolutionaries.len == 1 ? "Head Revolutionary was" : "Head Revolutionaries were"]:"
- for(var/datum/mind/ply in head_revolutionaries)
- text += "
[ply.name]"
- world << text
-
- ..()
-
- var/list/heads = list()
- for(var/mob/player in mob_list)
- if(player.mind && (player.mind.assigned_role in command_positions))
- heads += player.mind
-
- text = "The heads of staff were:"
- for(var/datum/mind/head in heads)
- text += "
[head.key] was [head.name] ("
- if(head.current)
- if(head.current.stat == DEAD)
- text += "died"
- else if(isNotStationLevel(head.current.z))
- text += "fled the station"
- else
- text += "survived the revolution"
- if(head.current.real_name != head.name)
- text += " as [head.current.real_name]"
- else
- text += "body destroyed"
- text += ")"
- world << text
-
-// This is a total redefine because headrevs are greeted differently to subrevs.
-/datum/antagonist/revolutionary/add_antagonist(var/datum/mind/player, var/ignore_role)
- if((player in current_antagonists) || (player in head_revolutionaries))
- return 0
- if(!can_become_antag(player, ignore_role))
- return 0
- current_antagonists |= player
- player.current << "You are a Revolutionary!"
- player.current << "Help the cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them overturn the ruling class!"
- player.special_role = "Revolutionary"
- create_objectives(player)
- show_objectives(player)
- update_icons_added(player)
- return 1
-
-/datum/antagonist/revolutionary/remove_antagonist(datum/mind/player, var/show_message, var/implanted)
- if(!..())
- return
-
- if(player in head_revolutionaries)
- return
-
- if(istype(player.current, /mob/living/carbon/brain))
- player.current << "The frame's firmware detects and deletes your neural reprogramming! You remember nothing from the moment you were flashed until now."
- if(show_message)
- player.current.visible_message("The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it.")
- else
- if(implanted)
- player.current << "The nanobots in the loyalty implant remove all thoughts about being a revolutionary. Get back to work!"
- else
- player.current << "You have been brainwashed! You are no longer a revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you..."
- if(show_message)
- player.current.visible_message("[player.current] looks like they just remembered their real allegiance!")
-
-// Used by RP-rev.
-/mob/living/carbon/human/proc/convert_to_rev(mob/M as mob in oview(src))
- set name = "Convert Bourgeoise"
- set category = "Abilities"
-
- if(revs.is_antagonist(M.mind))
- src << "\The [M] already serves the revolution."
- return
- if(!revs.can_become_antag(M.mind))
- src << "\The [M] cannot be a revolutionary!"
-
- if(world.time < M.mind.rev_cooldown)
- src << "You must wait five seconds between attempts."
- return
-
- src << "You are attempting to convert \the [M]..."
- log_admin("[src]([src.ckey]) attempted to convert [M].")
- message_admins("[src]([src.ckey]) attempted to convert [M].")
-
- var/choice = alert(M,"Asked by [src]: Do you want to join the revolution?","Join the revolution?","No!","Yes!")
- if(choice == "Yes!")
- M << "You join the revolution!"
- src << "[M] joins the revolution!"
- revs.add_antagonist(M.mind, 0, 0, 1)
- else if(choice == "No!")
- M << "You reject this traitorous cause!"
- src << "\The [M] does not support the revolution!"
- M.mind.rev_cooldown = world.time+50
\ No newline at end of file
diff --git a/code/game/antagonist/station/rogue_ai.dm b/code/game/antagonist/station/rogue_ai.dm
index f19edb28077..a3e609e55df 100644
--- a/code/game/antagonist/station/rogue_ai.dm
+++ b/code/game/antagonist/station/rogue_ai.dm
@@ -11,8 +11,10 @@ var/datum/antagonist/rogue_ai/malf
victory_text = "The AI has taken control of all of the station's systems."
loss_text = "The AI has been shut down!"
flags = ANTAG_VOTABLE | ANTAG_OVERRIDE_MOB | ANTAG_OVERRIDE_JOB | ANTAG_CHOOSE_NAME
- max_antags = 1
- max_antags_round = 1
+ hard_cap = 1
+ hard_cap_round = 1
+ initial_spawn_req = 1
+ initial_spawn_target = 1
/datum/antagonist/rogue_ai/New()
diff --git a/code/game/antagonist/station/traitor.dm b/code/game/antagonist/station/traitor.dm
index a4f14dccf8e..4527f1412f0 100644
--- a/code/game/antagonist/station/traitor.dm
+++ b/code/game/antagonist/station/traitor.dm
@@ -1,12 +1,10 @@
var/datum/antagonist/traitor/traitors
+// Inherits most of its vars from the base datum.
/datum/antagonist/traitor
id = MODE_TRAITOR
- restricted_jobs = list("Cyborg")//They are part of the AI if he is traitor so are they, they use to get double chances
- protected_jobs = list("Security Officer", "Warden", "Detective", "Internal Affairs Agent", "Head of Security", "Captain")//AI", Currently out of the list as malf does not work for shit
+ protected_jobs = list("Security Officer", "Warden", "Detective", "Internal Affairs Agent", "Head of Security", "Captain")
flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE
- max_antags = 200 // No upper limit.
- max_antags_round = 200
/datum/antagonist/traitor/New()
..()
diff --git a/code/game/gamemodes/calamity/calamity.dm b/code/game/gamemodes/calamity/calamity.dm
index d8872bbbff4..4f7b9ab49de 100644
--- a/code/game/gamemodes/calamity/calamity.dm
+++ b/code/game/gamemodes/calamity/calamity.dm
@@ -18,7 +18,7 @@
for(var/antag_id in all_antag_types)
if(i > grab_antags)
break
- additional_antag_types |= antag_id
+ antag_tags |= antag_id
i++
..()
diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm
index 678d6d71839..a551bab83f9 100644
--- a/code/game/gamemodes/changeling/changeling.dm
+++ b/code/game/gamemodes/changeling/changeling.dm
@@ -1,5 +1,4 @@
/datum/game_mode/changeling
- antag_tag = MODE_CHANGELING
name = "changeling"
round_description = "There are alien changelings on the station. Do not let the changelings succeed!"
extended_round_description = "Life always finds a way. However, life can sometimes take a more disturbing route. Humanity's extensive knowledge of xeno-biological specimens has made them confident and arrogant. Yet something slipped past their eyes. Something dangerous. Something alive. Most frightening of all, however, is that this something is someone. An unknown alien specimen has incorporated itself into the crew of the NSS Exodus. Its unique biology allows it to manipulate its own or anyone else's DNA. With the ability to copy faces, voices, animals, but also change the chemical make up of your own body, its existence is a threat to not only your personal safety but the lives of everyone on board. No one knows where it came from. No one knows who it is or what it wants. One thing is for certain though... there is never just one of them. Good luck."
@@ -9,3 +8,4 @@
required_enemies = 1
end_on_antag_death = 1
antag_scaling_coeff = 10
+ antag_tags = list(MODE_CHANGELING)
diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm
index f6c7d46063d..6141ceacc9e 100644
--- a/code/game/gamemodes/cult/cult.dm
+++ b/code/game/gamemodes/cult/cult.dm
@@ -7,4 +7,4 @@
required_players_secret = 15
required_enemies = 3
end_on_antag_death = 1
- antag_tag = MODE_CULTIST
+ antag_tags = list(MODE_CULTIST)
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index e34f7c59d24..30bbc5df474 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -1,25 +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//
-///////////////////////////////////
-/proc/get_living_heads()
- var/list/heads = list()
- for(var/mob/living/carbon/human/player in mob_list)
- if(player.stat!=2 && player.mind && (player.mind.assigned_role in command_positions))
- heads += player.mind
- return heads
-
-/*
- * GAMEMODES (by Rastaf0)
- *
- * In the new mode system all special roles are fully supported.
- * You can have proper wizards/traitors/changelings/cultists during any mode.
- * Only two things really depends on gamemode:
- * 1. Starting roles, equipment and preparations
- * 2. Conditions of finishing the round.
- *
- */
/datum/game_mode
var/name = "invalid"
@@ -40,11 +20,12 @@ var/global/list/additional_antag_types = list()
var/shuttle_delay = 1 // Shuttle transit time is multiplied by this.
var/auto_recall_shuttle = 0 // Will the shuttle automatically be recalled?
- var/antag_tag // First (main) antag template to spawn.
+ 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.
var/station_was_nuked = 0 // See nuclearbomb.dm and malfunction.dm.
var/explosion_in_progress = 0 // Sit back and relax
@@ -54,6 +35,13 @@ var/global/list/additional_antag_types = list()
var/event_delay_mod_moderate // Modifies the timing of random events.
var/event_delay_mod_major // As above.
+/datum/game_mode/New()
+ ..()
+ // Enforce some formatting.
+ // This will probably break something.
+ name = capitalize(lowertext(name))
+ config_tag = lowertext(config_tag)
+
/datum/game_mode/Topic(href, href_list[])
if(..())
return
@@ -79,18 +67,18 @@ var/global/list/additional_antag_types = list()
shuttle_delay = choice
if("antag_scaling")
choice = input("Enter a new antagonist cap scaling coefficient.") as num
- if(!choice || choice < 0 || choice > 100)
+ if(isnull(choice) || choice < 0 || choice > 100)
return
antag_scaling_coeff = choice
if("event_modifier_moderate")
choice = input("Enter a new moderate event time modifier.") as num
- if(!choice || choice < 0 || choice > 100)
+ if(isnull(choice) || choice < 0 || choice > 100)
return
event_delay_mod_moderate = choice
refresh_event_modifiers()
if("event_modifier_severe")
choice = input("Enter a new moderate event time modifier.") as num
- if(!choice || choice < 0 || choice > 100)
+ if(isnull(choice) || choice < 0 || choice > 100)
return
event_delay_mod_major = choice
refresh_event_modifiers()
@@ -104,7 +92,7 @@ var/global/list/additional_antag_types = list()
usr.client.debug_variables(antag)
message_admins("Admin [key_name_admin(usr)] is debugging the [antag.role_text] template.")
else if(href_list["remove_antag_type"])
- if(antag_tag && href_list["remove_antag_type"] == antag_tag)
+ if(antag_tags && (href_list["remove_antag_type"] in antag_tags))
usr << "Cannot remove core mode antag type."
return
var/datum/antagonist/antag = all_antag_types[href_list["remove_antag_type"]]
@@ -118,14 +106,15 @@ var/global/list/additional_antag_types = list()
return
var/datum/antagonist/antag = all_antag_types[choice]
if(antag)
- additional_antag_types |= antag
+ ticker.mode.antag_templates |= antag
message_admins("Admin [key_name_admin(usr)] added [antag.role_text] template to game mode.")
// I am very sure there's a better way to do this, but I'm not sure what it might be. ~Z
- for(var/datum/admins/admin in world)
- if(usr.client == admin.owner)
- admin.show_game_mode(usr)
- return
+ spawn(1)
+ for(var/datum/admins/admin in world)
+ if(usr.client == admin.owner)
+ admin.show_game_mode(usr)
+ return
/datum/game_mode/proc/announce() //to be called when round starts
world << "The current game mode is [capitalize(name)]!"
@@ -166,15 +155,23 @@ var/global/list/additional_antag_types = list()
if(!(antag_templates && antag_templates.len))
return 1
- var/datum/antagonist/main_antags = antag_templates[1]
- var/list/potential
- if(main_antags.flags & ANTAG_OVERRIDE_JOB)
- potential = main_antags.pending_antagonists
- else
- potential = main_antags.candidates
-
- if(potential.len >= required_enemies)
- return 1
+ var/enemy_count = 0
+ if(antag_tags && antag_tags.len)
+ for(var/antag_tag in antag_tags)
+ var/datum/antagonist/antag = all_antag_types[antag_tag]
+ if(!antag)
+ continue
+ var/list/potential = list()
+ if(antag.flags & ANTAG_OVERRIDE_JOB)
+ potential = antag.pending_antagonists
+ else
+ potential = antag.candidates
+ if(islist(potential))
+ if(require_all_templates && potential.len < antag.initial_spawn_req)
+ return 0
+ enemy_count += potential.len
+ if(enemy_count >= required_enemies)
+ return 1
return 0
/datum/game_mode/proc/refresh_event_modifiers()
@@ -471,11 +468,13 @@ var/global/list/additional_antag_types = list()
if(!config.traitor_scaling)
antag_scaling_coeff = 0
- if(antag_tag)
+ if(antag_tags && antag_tags.len)
antag_templates = list()
- var/datum/antagonist/antag = all_antag_types[antag_tag]
- if(antag)
- antag_templates |= antag
+ for(var/antag_tag in antag_tags)
+ var/datum/antagonist/antag = all_antag_types[antag_tag]
+ if(antag)
+ antag_templates |= antag
+
if(additional_antag_types && additional_antag_types.len)
if(!antag_templates)
antag_templates = list()
@@ -484,15 +483,6 @@ var/global/list/additional_antag_types = list()
if(antag)
antag_templates |= antag
- /*
- if(antag_templates && antag_templates.len)
- for(var/datum/antagonist/antag in antag_templates)
- 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)
/datum/game_mode/proc/check_victory()
diff --git a/code/game/gamemodes/game_mode_latespawn.dm b/code/game/gamemodes/game_mode_latespawn.dm
index 9af35241441..f849f7133da 100644
--- a/code/game/gamemodes/game_mode_latespawn.dm
+++ b/code/game/gamemodes/game_mode_latespawn.dm
@@ -1,7 +1,12 @@
+/datum/game_mode/var/next_spawn = 0
+/datum/game_mode/var/min_autotraitor_delay = 4200 // Approx 7 minutes.
+/datum/game_mode/var/max_autotraitor_delay = 12000 // Approx 20 minutes.
+
/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
@@ -21,23 +26,27 @@
if(emergency_shuttle.departed || !round_autoantag)
return
- if(!prob(get_antag_prob()))
+ if(world.time < next_spawn)
return
+ 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.len)
+ else 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.")
+ round_autoantag = 0
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
+ 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])")
+ next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay)
+ return
+ message_admins("AUTO[uppertext(name)]: Failed to proc a viable spawn template.")
+ next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay)
diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm
index 614d181795d..1067d332c52 100644
--- a/code/game/gamemodes/gameticker.dm
+++ b/code/game/gamemodes/gameticker.dm
@@ -69,33 +69,34 @@ var/global/datum/controller/gameticker/ticker
//Create and announce mode
if(master_mode=="secret")
src.hide_mode = 1
- var/list/datum/game_mode/runnable_modes
- var/mode_started
+
+ var/list/runnable_modes = config.get_runnable_modes()
if((master_mode=="random") || (master_mode=="secret"))
- runnable_modes = config.get_runnable_modes()
- if (runnable_modes.len==0)
+ if(!runnable_modes.len)
current_state = GAME_STATE_PREGAME
world << "Unable to choose playable game mode. Reverting to pre-game lobby."
return 0
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()
+ src.mode = config.pick_mode(secret_force_mode)
if(!src.mode)
- src.mode = pickweight(runnable_modes)
- if(src.mode)
- var/mtype = src.mode.type
- src.mode = new mtype
+ var/list/weighted_modes = list()
+ for(var/datum/game_mode/GM in runnable_modes)
+ weighted_modes[GM.config_tag] = config.probabilities[GM.config_tag]
+ src.mode = gamemode_cache[pickweight(weighted_modes)]
else
src.mode = config.pick_mode(master_mode)
- src.mode.pre_setup()
+ if(!src.mode)
+ current_state = GAME_STATE_PREGAME
+ world << "Serious error in mode setup! Reverting to pre-game lobby."
+ return 0
+ job_master.ResetOccupations()
+ src.mode.create_antagonists()
+ src.mode.pre_setup()
job_master.DivideOccupations() // Apparently important for new antagonist system to register specific job antags properly.
- if(!mode_started && !src.mode.can_start())
+ if(!src.mode.can_start())
world << "Unable to start [mode.name]. Not enough players, [mode.required_players] players needed. Reverting to pre-game lobby."
current_state = GAME_STATE_PREGAME
mode.fail_setup()
@@ -104,12 +105,14 @@ var/global/datum/controller/gameticker/ticker
return 0
if(hide_mode)
- var/list/modes = new
- for (var/datum/game_mode/M in runnable_modes)
- modes+=M.name
- modes = sortList(modes)
world << "The current game mode is - Secret!"
- world << "Possibilities: [english_list(modes)]"
+ if(runnable_modes.len)
+ var/list/tmpmodes = new
+ for (var/datum/game_mode/M in runnable_modes)
+ tmpmodes+=M.name
+ tmpmodes = sortList(tmpmodes)
+ if(tmpmodes.len)
+ world << "Possibilities: [english_list(tmpmodes)]"
else
src.mode.announce()
diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm
index 03680c8ff34..0a1badfe0a9 100644
--- a/code/game/gamemodes/heist/heist.dm
+++ b/code/game/gamemodes/heist/heist.dm
@@ -5,7 +5,6 @@ VOX HEIST ROUNDTYPE
var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' objective. Clumsy, rewrite sometime.
/datum/game_mode/heist
- antag_tag = MODE_RAIDER
name = "heist"
config_tag = "heist"
required_players = 15
@@ -13,6 +12,7 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind'
required_enemies = 4
round_description = "An unidentified bluespace signature has slipped past the Icarus and is approaching the station!"
end_on_antag_death = 1
+ antag_tags = list(MODE_RAIDER)
/datum/game_mode/heist/check_finished()
if(!..())
diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm
index b5280168982..ea98f32558f 100644
--- a/code/game/gamemodes/malfunction/malfunction.dm
+++ b/code/game/gamemodes/malfunction/malfunction.dm
@@ -8,4 +8,4 @@
required_enemies = 1
end_on_antag_death = 0
auto_recall_shuttle = 0
- antag_tag = MODE_MALFUNCTION
+ antag_tags = list(MODE_MALFUNCTION)
diff --git a/code/game/gamemodes/ninja/ninja.dm b/code/game/gamemodes/ninja/ninja.dm
index d410dbeb7d3..06ded4e1356 100644
--- a/code/game/gamemodes/ninja/ninja.dm
+++ b/code/game/gamemodes/ninja/ninja.dm
@@ -2,9 +2,9 @@
name = "ninja"
round_description = "An agent of the Spider Clan is onboard the station!"
extended_round_description = "What was that?! Was that a person or did your eyes just play tricks on you? You have no idea. That slim-suited, cryptic individual is an enigma to you and all of your knowledge. Their purpose is unknown. Their mission is unknown. How they arrived to this secure and isolated section of the galaxy, you don't know. What you do know is that there is a silent shadow-stalker piercing through the defenses of Nanotrasen with technological capabilities eons ahead of your time. They can avoid the omniscience of the AI and rival the most hardened weapons your station is capable of. Tread lightly and only hope this unknown assassin isn't here for you."
- antag_tag = MODE_NINJA
config_tag = "ninja"
required_players = 1
required_players_secret = 10
required_enemies = 1
- end_on_antag_death = 1
\ No newline at end of file
+ end_on_antag_death = 1
+ antag_tags = list(MODE_NINJA)
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index 37ec7d9a2a7..2be6f558f72 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -12,10 +12,9 @@ var/list/nuke_disks = list()
required_players_secret = 25 // 25 players - 5 players to be the nuke ops = 20 players remaining
required_enemies = 1
end_on_antag_death = 1
- antag_tag = MODE_MERCENARY
-
var/nuke_off_station = 0 //Used for tracking if the syndies actually haul the nuke to the station
var/syndies_didnt_escape = 0 //Used for tracking if the syndies got the shuttle off of the z-level
+ antag_tags = list(MODE_MERCENARY)
//delete all nuke disks not on a station zlevel
/datum/game_mode/nuclear/proc/check_nuke_disks()
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 1fac875ab4e..5ccdd4c00bb 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -64,69 +64,6 @@ datum/objective/assassinate
return 1
-
-datum/objective/mutiny
- find_target()
- ..()
- if(target && target.current)
- explanation_text = "Assassinate [target.current.real_name], the [target.assigned_role]."
- else
- explanation_text = "Free Objective"
- return target
-
-
- find_target_by_role(role, role_type=0)
- ..(role, role_type)
- if(target && target.current)
- explanation_text = "Assassinate [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role]."
- else
- explanation_text = "Free Objective"
- return target
-
- check_completion()
- if(target && target.current)
- if(target.current.stat == DEAD || !ishuman(target.current) || !target.current.ckey)
- return 1
- var/turf/T = get_turf(target.current)
- if(T && isNotStationLevel(T.z)) //If they leave the station they count as dead for this
- return 2
- return 0
- return 1
-
-datum/objective/mutiny/rp
- find_target()
- ..()
- if(target && target.current)
- explanation_text = "Assassinate, capture or convert [target.current.real_name], the [target.assigned_role]."
- else
- explanation_text = "Free Objective"
- return target
-
-
- find_target_by_role(role, role_type=0)
- ..(role, role_type)
- if(target && target.current)
- explanation_text = "Assassinate, capture or convert [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role]."
- else
- explanation_text = "Free Objective"
- return target
-
- // less violent rev objectives
- check_completion()
- var/rval = 1
- if(target && target.current)
- //assume that only carbon mobs can become rev heads for now
- if(target.current.stat == DEAD || target.current:handcuffed || !ishuman(target.current))
- return 1
- // Check if they're converted
- if(target in revs.head_revolutionaries)
- return 1
- var/turf/T = get_turf(target.current)
- if(T && isNotStationLevel(T.z)) //If they leave the station they count as dead for this
- rval = 2
- return 0
- return rval
-
datum/objective/anti_revolution/execute
find_target()
..()
@@ -933,3 +870,38 @@ datum/objective/heist/salvage
/datum/objective/cult/sacrifice/check_completion()
return (target && cult && !cult.sacrificed.Find(target))
+
+/datum/objective/rev/find_target()
+ ..()
+ if(target && target.current)
+ explanation_text = "Assassinate, capture or convert [target.current.real_name], the [target.assigned_role]."
+ else
+ explanation_text = "Free Objective"
+ return target
+
+
+/datum/objective/rev/find_target_by_role(role, role_type=0)
+ ..(role, role_type)
+ if(target && target.current)
+ explanation_text = "Assassinate, capture or convert [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role]."
+ else
+ explanation_text = "Free Objective"
+ return target
+
+/datum/objective/rev/check_completion()
+ var/rval = 1
+ if(target && target.current)
+ var/mob/living/carbon/human/H = target.current
+ if(!istype(H))
+ return 1
+ if(H.stat == DEAD || H.restrained())
+ return 1
+ // Check if they're converted
+ if(target in revs.current_antagonists)
+ return 1
+ var/turf/T = get_turf(H)
+ if(T && isNotStationLevel(T.z)) //If they leave the station they count as dead for this
+ rval = 2
+ return 0
+ return rval
+
diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm
index 7d2cbf1ca7e..efd75927561 100644
--- a/code/game/gamemodes/revolution/revolution.dm
+++ b/code/game/gamemodes/revolution/revolution.dm
@@ -2,47 +2,12 @@
name = "Revolution"
config_tag = "revolution"
round_description = "Some crewmembers are attempting to start a revolution!"
- extended_round_description = "Revolutionaries - Kill the Captain, HoP, HoS, CE, RD and CMO. Convert other crewmembers (excluding the heads of staff, and security officers) to your cause by flashing them. Protect your leaders.
\nPersonnel - Protect the heads of staff. Kill the leaders of the revolution, and brainwash the other revolutionaries (by beating them in the head)."
+ extended_round_description = "Revolutionaries - Remove the heads of staff from power. Convert other crewmembers to your cause using the 'Convert Bourgeoise' verb. Protect your leaders."
required_players = 4
required_players_secret = 15
required_enemies = 3
auto_recall_shuttle = 1
end_on_antag_death = 1
shuttle_delay = 3
- antag_tag = MODE_REVOLUTIONARY
-
-/datum/game_mode/revolution/New()
- if(config && config.rp_rev)
- extended_round_description = "Revolutionaries - Remove the heads of staff from power. Convert other crewmembers to your cause using the 'Convert Bourgeoise' verb. Protect your leaders."
-
-/datum/game_mode/revolution/send_intercept()
-
- ..()
-
- if(config.announce_revheads)
- spawn(54000)
- var/intercepttext = ""
- command_announcement.Announce("Summary downloaded and printed out at all communications consoles.", "Local agitators have been determined.")
- intercepttext = "Cent. Com. Update Requested status information:
"
- intercepttext += "We have determined several members of your staff to be political activists. They are:"
- for(var/datum/mind/revmind in revs.head_revolutionaries)
- intercepttext += "
[revmind.current.real_name]"
- intercepttext += "
Please arrest them at once."
- for (var/obj/machinery/computer/communications/comm in world)
- if (!(comm.stat & (BROKEN | NOPOWER)) && comm.prints_intercept)
- var/obj/item/weapon/paper/intercept = new /obj/item/weapon/paper( comm.loc )
- intercept.name = "Cent. Com. Status Summary"
- intercept.info = intercepttext
- comm.messagetitle.Add("Cent. Com. Status Summary")
- comm.messagetext.Add(intercepttext)
- spawn(12000)
- command_announcement.Announce("Repeating the previous message over intercoms due to urgency. The station has political agitators onboard by the names of [reveal_rev_heads()], please arrest them at once.", "Local agitators have been determined.")
-
-/datum/game_mode/revolution/proc/reveal_rev_heads()
- . = ""
- for(var/i = 1, i <= revs.head_revolutionaries.len,i++)
- var/datum/mind/revmind = revs.head_revolutionaries[i]
- if(i < revs.head_revolutionaries.len)
- . += "[revmind.current.real_name],"
- else
- . += "and [revmind.current.real_name]"
+ antag_tags = list(MODE_REVOLUTIONARY, MODE_LOYALIST)
+ require_all_templates = 1
diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm
index 2b0e776ce1f..c83f14d4780 100644
--- a/code/game/gamemodes/traitor/traitor.dm
+++ b/code/game/gamemodes/traitor/traitor.dm
@@ -6,5 +6,11 @@
required_players = 0
required_enemies = 1
end_on_antag_death = 1
+ antag_tags = list(MODE_TRAITOR)
antag_scaling_coeff = 10
- antag_tag = MODE_TRAITOR
+
+/datum/game_mode/traitor/auto
+ name = "autotraitor"
+ config_tag = "autotraitor"
+ round_autoantag = 1
+ antag_scaling_coeff = 1
diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm
index 7209844d386..df149953fae 100644
--- a/code/game/gamemodes/wizard/wizard.dm
+++ b/code/game/gamemodes/wizard/wizard.dm
@@ -7,4 +7,4 @@
required_players_secret = 10
required_enemies = 1
end_on_antag_death = 1
- antag_tag = MODE_WIZARD
+ antag_tags = list(MODE_WIZARD)
diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm
index 1fcf6e8625c..009c12403dc 100644
--- a/code/game/machinery/computer/ai_core.dm
+++ b/code/game/machinery/computer/ai_core.dm
@@ -137,8 +137,7 @@
return
if(M.brainmob.mind)
- cult.remove_antagonist(M.brainmob.mind, 1)
- revs.remove_antagonist(M.brainmob.mind, 1)
+ clear_antag_roles(M.brainmob.mind, 1)
user.drop_item()
P.loc = src
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index 760e393aa13..10dd54ad197 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -341,20 +341,10 @@
for(var/datum/objective/O in all_objectives)
// We don't want revs to get objectives that aren't for heads of staff. Letting
// them win or lose based on cryo is silly so we remove the objective.
- if(istype(O,/datum/objective/mutiny) && O.target == occupant.mind)
+ if(O.target == occupant.mind)
+ if(O.owner && O.owner.current)
+ O.owner.current << "You get the feeling your target is no longer within your reach..."
qdel(O)
- else if(O.target && istype(O.target,/datum/mind))
- if(O.target == occupant.mind)
- if(O.owner && O.owner.current)
- O.owner.current << "You get the feeling your target is no longer within your reach. Time for Plan [pick(list("A","B","C","D","X","Y","Z"))]..."
- O.target = null
- spawn(1) //This should ideally fire after the occupant is deleted.
- if(!O) return
- O.find_target()
- if(!(O.target))
- all_objectives -= O
- O.owner.objectives -= O
- qdel(O)
//Handle job slot/tater cleanup.
var/job = occupant.mind.assigned_role
diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm
index 8f9fa270939..ed2fa769c0e 100644
--- a/code/game/objects/items/devices/flash.dm
+++ b/code/game/objects/items/devices/flash.dm
@@ -70,7 +70,7 @@
flick("e_flash", M.flash)
if(ishuman(M) && ishuman(user) && M.stat!=DEAD)
- if(user.mind && user.mind in revs.head_revolutionaries)
+ if(user.mind && user.mind in revs.current_antagonists)
var/revsafe = 0
for(var/obj/item/weapon/implant/loyalty/L in M)
if(L && L.implanted)
diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm
index 83c5ea20982..45323739222 100644
--- a/code/game/objects/items/robot/robot_parts.dm
+++ b/code/game/objects/items/robot/robot_parts.dm
@@ -213,10 +213,6 @@
user << "Sticking a dead [W] into the frame would sort of defeat the purpose."
return
- if(M.brainmob.mind in revs.head_revolutionaries)
- user << "The frame's firmware lets out a shrill sound, and flashes 'Abnormal Memory Engram'. It refuses to accept the [W]."
- return
-
if(jobban_isbanned(M.brainmob, "Cyborg"))
user << "This [W] does not seem to fit."
return
diff --git a/code/game/response_team.dm b/code/game/response_team.dm
index 7894aadde6a..25d381e0668 100644
--- a/code/game/response_team.dm
+++ b/code/game/response_team.dm
@@ -53,7 +53,7 @@ client/verb/JoinResponseTeam()
if(jobban_isbanned(usr, "Syndicate") || jobban_isbanned(usr, "Emergency Response Team") || jobban_isbanned(usr, "Security Officer"))
usr << "You are jobbanned from the emergency reponse team!"
return
- if(ert.current_antagonists.len >= ert.max_antags)
+ if(ert.current_antagonists.len >= ert.hard_cap)
usr << "The emergency response team is already full!"
return
ert.create_default(usr)
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 00bc01eda19..505dfa3f9c9 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -1160,30 +1160,27 @@ proc/admin_notice(var/message, var/rights)
out += "
"
- if(ticker.mode.antag_tag)
- out += "Core antag id: [ticker.mode.antag_tag]."
+ if(ticker.mode.antag_tags && ticker.mode.antag_tags.len)
+ out += "Core antag templates:"
+ for(var/antag_tag in ticker.mode.antag_tags)
+ out += "[antag_tag]."
if(ticker.mode.round_autoantag)
- out += "Autotraitor enabled ([ticker.mode.get_antag_prob()]% spawn chance)"
- if(ticker.mode.antag_scaling_coeff)
+ out += "Autotraitor enabled."
+ if(ticker.mode.antag_scaling_coeff > 0)
out += " (scaling with [ticker.mode.antag_scaling_coeff])"
+ else
+ out += " (not currently scaling, set a coefficient)"
out += "
"
else
out += "Autotraitor disabled.
"
out += "All antag ids:"
if(ticker.mode.antag_templates && ticker.mode.antag_templates.len).
- var/playercount = ticker.mode.num_players()
for(var/datum/antagonist/antag in ticker.mode.antag_templates)
- var/cur_max_antags
- if(ticker.mode.antag_tag && antag.id == ticker.mode.antag_tag)
- cur_max_antags = antag.max_antags_round
- else
- cur_max_antags = antag.max_antags
- if(ticker.mode.antag_scaling_coeff)
- cur_max_antags = Clamp((playercount/ticker.mode.antag_scaling_coeff), 1, cur_max_antags)
+ antag.update_current_antag_max()
out += " [antag.id]"
- out += " ([antag.get_antag_count()]/[cur_max_antags]) "
+ out += " ([antag.get_antag_count()]/[antag.cur_max]) "
out += " \[-\]
"
else
out += " None."
@@ -1365,3 +1362,46 @@ proc/admin_notice(var/message, var/rights)
tomob.ckey = frommob.ckey
qdel(frommob)
return 1
+
+/datum/admins/proc/force_antag_latespawn()
+ set category = "Admin"
+ set name = "Force Template Spawn"
+ set desc = "Force an antagonist template to spawn."
+
+ if (!istype(src,/datum/admins))
+ src = usr.client.holder
+ if (!istype(src,/datum/admins))
+ usr << "Error: you are not an admin!"
+ return
+
+ if(!ticker || !ticker.mode)
+ usr << "Mode has not started."
+ return
+
+ var/antag_type = input("Choose a template.","Force Latespawn") as null|anything in all_antag_types
+ if(!antag_type || !all_antag_types[antag_type])
+ usr << "Aborting."
+ return
+
+ 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()
+
+/datum/admins/proc/force_mode_latespawn()
+ set category = "Admin"
+ set name = "Force Mode Spawn"
+ set desc = "Force autotraitor to proc."
+
+ if (!istype(src,/datum/admins))
+ src = usr.client.holder
+ if (!istype(src,/datum/admins))
+ usr << "Error: you are not an admin!"
+ return
+
+ if(!ticker || !ticker.mode)
+ 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()
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index a3d0b31bd66..8f01fe91e26 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -16,6 +16,8 @@ var/list/admin_verbs_admin = list(
/client/proc/invisimin, /*allows our mob to go invisible/visible*/
// /datum/admins/proc/show_traitor_panel, /*interface which shows a mob's mind*/ -Removed due to rare practical use. Moved to debug verbs ~Errorage
/datum/admins/proc/show_game_mode, /*Configuration window for the current game mode.*/
+ /datum/admins/proc/force_mode_latespawn, /*Force the mode to try a latespawn proc*/
+ /datum/admins/proc/force_antag_latespawn, /*Force a specific template to try a latespawn proc*/
/datum/admins/proc/toggleenter, /*toggles whether people can join the current game*/
/datum/admins/proc/toggleguests, /*toggles whether guests can join the current game*/
/datum/admins/proc/announce, /*priority announce something to all clients.*/
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index e96afb3a56a..9627cd65b38 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -18,7 +18,7 @@ var/global/list/special_roles = list( //keep synced with the defines BE_* in set
"ninja" = "true", // 10
"raider" = IS_MODE_COMPILED("heist"), // 11
"diona" = 1, // 12
- "mutineer" = IS_MODE_COMPILED("mutiny"), // 13
+ "loyalist" = IS_MODE_COMPILED("revolution"), // 13
"pAI candidate" = 1, // -- TLE // 14
)
diff --git a/code/modules/mob/language/outsider.dm b/code/modules/mob/language/outsider.dm
index 1f89c16ff9c..7295a6ae205 100644
--- a/code/modules/mob/language/outsider.dm
+++ b/code/modules/mob/language/outsider.dm
@@ -90,7 +90,7 @@
ask_verb = "intones"
exclaim_verb = "chants"
colour = "cult"
- key = "n"
+ key = "f"
flags = RESTRICTED
space_chance = 100
syllables = list("ire","ego","nahlizet","certum","veri","jatkaa","mgar","balaq", "karazet", "geeri", \
@@ -108,5 +108,5 @@
ask_verb = "intones"
exclaim_verb = "chants"
colour = "cult"
- key = "m"
+ key = "y"
flags = RESTRICTED | HIVEMIND
diff --git a/code/modules/mob/living/simple_animal/borer/borer.dm b/code/modules/mob/living/simple_animal/borer/borer.dm
index 520bfdf596a..73410552fb9 100644
--- a/code/modules/mob/living/simple_animal/borer/borer.dm
+++ b/code/modules/mob/living/simple_animal/borer/borer.dm
@@ -34,6 +34,11 @@
/mob/living/simple_animal/borer/roundstart
roundstart = 1
+/mob/living/simple_animal/borer/Login()
+ ..()
+ if(mind)
+ borers.add_antagonist(mind)
+
/mob/living/simple_animal/borer/New()
..()
@@ -150,11 +155,7 @@
if(!host) return
if(host.mind)
- //If they're not a proper traitor, reset their antag status.
- if(host.mind.special_role == "Borer Thrall")
- host << "You are no longer an antagonist."
- borers.hosts -= host.mind
- host.mind.special_role = null
+ borers.remove_antagonist(host.mind)
src.loc = get_turf(host)
diff --git a/code/modules/mob/living/simple_animal/borer/borer_powers.dm b/code/modules/mob/living/simple_animal/borer/borer_powers.dm
index cc003938dec..88be25cc245 100644
--- a/code/modules/mob/living/simple_animal/borer/borer_powers.dm
+++ b/code/modules/mob/living/simple_animal/borer/borer_powers.dm
@@ -109,15 +109,9 @@
//Update their traitor status.
if(host.mind)
- if(!host.mind.special_role)
- borers.hosts |= host.mind
- host.mind.special_role = "Borer Thrall"
- host << "A creeping lassitude surrounds you. Your mind is being invaded by an alien intelligence and that's just fine."
- host << "You are now a thrall to a cortical borer. Please listen to what they have to say; they're in your head."
- show_generic_antag_text(host.mind)
+ borers.add_antagonist_mind(host.mind, 1, borers.faction_role_text, borers.faction_welcome)
if(istype(M,/mob/living/carbon/human))
-
var/mob/living/carbon/human/H = M
var/obj/item/organ/I = H.internal_organs_by_name["brain"]
if(!I) // No brain organ, so the borer moves in and replaces it permanently.
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm
index 30bcf0ba6f3..9644528e0c1 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm
@@ -141,7 +141,7 @@
metabolism = REM * 0.5
scannable = 1
-/datum/reagent/cryoxadone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
+/datum/reagent/clonexadone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
if(M.bodytemperature < 170)
M.adjustCloneLoss(-30 * removed)
M.adjustOxyLoss(-30 * removed)
diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi
index bfee242faae..c20a2cbc0ff 100644
Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ