diff --git a/code/__DEFINES/~~bubber_defines/storyteller_defines.dm b/code/__DEFINES/~~bubber_defines/storyteller_defines.dm
index 6ea31c3bace..b51009c278f 100644
--- a/code/__DEFINES/~~bubber_defines/storyteller_defines.dm
+++ b/code/__DEFINES/~~bubber_defines/storyteller_defines.dm
@@ -25,6 +25,8 @@
#define TAG_SPACE "space"
/// When the event requires the station to be on planetary.
#define TAG_PLANETARY "planetary"
+/// When the event is used for re-rolling antagonists
+#define TAG_ANTAG_REROLL "antag_reroll"
#define EVENT_TRACK_MUNDANE "Mundane"
diff --git a/code/datums/mind/_mind.dm b/code/datums/mind/_mind.dm
index 44eac8ae6c7..328c9aeae32 100644
--- a/code/datums/mind/_mind.dm
+++ b/code/datums/mind/_mind.dm
@@ -461,6 +461,17 @@
else if (href_list["obj_announce"])
announce_objectives()
+ // BUBBER EDIT ADDITION BEGIN - ANTAG RE-ROLLING
+ else if (href_list["reroll_antag"])
+ var/datum/antagonist/antag = locate(href_list["reroll_antag"]) in antag_datums
+ if(!istype(antag))
+ to_chat(usr, span_warning("Invalid antagonist ref to be removed."))
+ return
+
+ SSgamemode.reroll_antagonist(antag_name = name)
+ antag.admin_remove(usr)
+ // BUBBER EDIT ADDITION END - ANTAG RE-ROLLING
+
//Something in here might have changed your mob
if(self_antagging && (!usr || !usr.client) && current.client)
usr = current
diff --git a/code/modules/admin/antag_panel.dm b/code/modules/admin/antag_panel.dm
index d06a583c515..b3ba22fcaa0 100644
--- a/code/modules/admin/antag_panel.dm
+++ b/code/modules/admin/antag_panel.dm
@@ -167,6 +167,7 @@ GLOBAL_VAR(antag_prototypes)
else //Show removal and current one
priority_sections |= antag_category
antag_header_parts += span_bad("[current_antag.name]")
+ antag_header_parts += "Remove and reassign to new player" // BUBBER EDIT ADDITION - ANTAG RE-ROLLING
antag_header_parts += "Remove"
antag_header_parts += "Open VV"
@@ -180,7 +181,7 @@ GLOBAL_VAR(antag_prototypes)
pref_source = prototype
break
if(pref_source.pref_flag)
- antag_header_parts += pref_source.enabled_in_preferences(src) ? "Enabled in Prefs" : "Disabled in Prefs"
+ antag_header_parts += pref_source.enabled_in_preferences(src) ? "
Enabled in Prefs" : "
Disabled in Prefs" // BUBBER EDIT CHANGE - ORIGINAL: "Enabled in Prefs" : "Disabled in Prefs"
//Traitor : None | Traitor | IAA
// Command1 | Command2 | Command3
diff --git a/modular_zubbers/code/modules/storyteller/event_defines/crewset/_antagonist_event.dm b/modular_zubbers/code/modules/storyteller/event_defines/crewset/_antagonist_event.dm
index 887fc1c6195..3c3e8b4f491 100644
--- a/modular_zubbers/code/modules/storyteller/event_defines/crewset/_antagonist_event.dm
+++ b/modular_zubbers/code/modules/storyteller/event_defines/crewset/_antagonist_event.dm
@@ -160,6 +160,8 @@
/datum/round_event/antagonist/solo/start()
for(var/datum/mind/antag_mind as anything in setup_minds)
add_datum_to_mind(antag_mind)
+ log_game("[antag_mind.current] was selected for antagonist role [antag_flag].")
+ message_admins(span_yellowteamradio("[ADMIN_LOOKUPFLW(antag_mind.current)] was selected for antagonist role [antag_flag]."))
/datum/round_event/antagonist/proc/add_datum_to_mind(datum/mind/antag_mind)
antag_mind.add_antag_datum(antag_datum)
@@ -181,6 +183,8 @@
/datum/round_event/antagonist/team/start()
for(var/datum/mind/antag_mind as anything in setup_minds)
add_datum_to_mind(antag_mind)
+ log_game("[antag_mind.current] was selected for antagonist role [antag_flag].")
+ message_admins(span_yellowteamradio("[ADMIN_LOOKUPFLW(antag_mind.current)] was selected for antagonist role [antag_flag]."))
/datum/round_event/antagonist/team/load_vars(datum/round_event_control/antagonist/team/cast_control)
. = ..()
diff --git a/modular_zubbers/code/modules/storyteller/event_defines/crewset/bloodsucker.dm b/modular_zubbers/code/modules/storyteller/event_defines/crewset/bloodsucker.dm
index 636a2079def..ca937066086 100644
--- a/modular_zubbers/code/modules/storyteller/event_defines/crewset/bloodsucker.dm
+++ b/modular_zubbers/code/modules/storyteller/event_defines/crewset/bloodsucker.dm
@@ -14,3 +14,10 @@
/datum/round_event_control/antagonist/solo/bloodsucker/midround
name = "Vampiric Accident"
roundstart = FALSE
+
+/datum/round_event_control/antagonist/solo/bloodsucker/event
+ name = "Event Generated Bloodsucker"
+ roundstart = FALSE
+ tags = list(TAG_ANTAG_REROLL)
+ max_occurrences = 0
+ maximum_antags = 1
diff --git a/modular_zubbers/code/modules/storyteller/event_defines/crewset/changeling.dm b/modular_zubbers/code/modules/storyteller/event_defines/crewset/changeling.dm
index 120fed3b6cd..eccd2425ef7 100644
--- a/modular_zubbers/code/modules/storyteller/event_defines/crewset/changeling.dm
+++ b/modular_zubbers/code/modules/storyteller/event_defines/crewset/changeling.dm
@@ -14,3 +14,10 @@
/datum/round_event_control/antagonist/solo/changeling/midround
name = "Genome Awakening (Changelings)"
roundstart = FALSE
+
+/datum/round_event_control/antagonist/solo/changeling/event
+ name = "Event Generated Changeling"
+ roundstart = FALSE
+ tags = list(TAG_ANTAG_REROLL)
+ max_occurrences = 0
+ maximum_antags = 1
diff --git a/modular_zubbers/code/modules/storyteller/event_defines/crewset/heretic.dm b/modular_zubbers/code/modules/storyteller/event_defines/crewset/heretic.dm
index 21f9855a35e..58ac18aea56 100644
--- a/modular_zubbers/code/modules/storyteller/event_defines/crewset/heretic.dm
+++ b/modular_zubbers/code/modules/storyteller/event_defines/crewset/heretic.dm
@@ -18,3 +18,10 @@
/datum/round_event_control/antagonist/solo/heretic/midround
name = "Midround Heretics"
roundstart = FALSE
+
+/datum/round_event_control/antagonist/solo/heretic/event
+ name = "Event Generated Heretic"
+ roundstart = FALSE
+ tags = list(TAG_ANTAG_REROLL)
+ max_occurrences = 0
+ maximum_antags = 1
diff --git a/modular_zubbers/code/modules/storyteller/event_defines/crewset/spies.dm b/modular_zubbers/code/modules/storyteller/event_defines/crewset/spies.dm
index f4a94625fb3..fd95508bab3 100644
--- a/modular_zubbers/code/modules/storyteller/event_defines/crewset/spies.dm
+++ b/modular_zubbers/code/modules/storyteller/event_defines/crewset/spies.dm
@@ -12,3 +12,10 @@
/datum/round_event_control/antagonist/solo/spy/midround
name = "Spies (Midround)"
roundstart = FALSE
+
+/datum/round_event_control/antagonist/solo/spy/event
+ name = "Event Generated Spy"
+ roundstart = FALSE
+ tags = list(TAG_ANTAG_REROLL)
+ max_occurrences = 0
+ maximum_antags = 1
diff --git a/modular_zubbers/code/modules/storyteller/event_defines/crewset/traitor.dm b/modular_zubbers/code/modules/storyteller/event_defines/crewset/traitor.dm
index 8c2ea190743..506b8a5522f 100644
--- a/modular_zubbers/code/modules/storyteller/event_defines/crewset/traitor.dm
+++ b/modular_zubbers/code/modules/storyteller/event_defines/crewset/traitor.dm
@@ -12,3 +12,10 @@
/datum/round_event_control/antagonist/solo/traitor/midround
name = "Sleeper Agents (Traitors)"
roundstart = FALSE
+
+/datum/round_event_control/antagonist/solo/traitor/event
+ name = "Event Generated Traitor"
+ roundstart = FALSE
+ tags = list(TAG_ANTAG_REROLL)
+ max_occurrences = 0
+ maximum_antags = 1
diff --git a/modular_zubbers/code/modules/storyteller/gamemode.dm b/modular_zubbers/code/modules/storyteller/gamemode.dm
index d20b3d745ea..8438805ddda 100644
--- a/modular_zubbers/code/modules/storyteller/gamemode.dm
+++ b/modular_zubbers/code/modules/storyteller/gamemode.dm
@@ -132,6 +132,8 @@ SUBSYSTEM_DEF(gamemode)
//Security Based Antag Cap
var/sec_antag_cap = 0
+ /// A list of event controls to re-roll antagonists
+ var/list/antag_rerolls
/// Whether we looked up pop info in this process tick
var/pop_data_cached = FALSE
@@ -179,8 +181,14 @@ SUBSYSTEM_DEF(gamemode)
if(!holiday_categorized)
uncategorized += event
continue
- else
- event_pools[event.track] += event //Add it to the categorized event pools
+
+ var/list/event_tags = event.tags
+ if(LAZYLEN(event_tags))
+ if(LAZYFIND(event_tags, TAG_ANTAG_REROLL))
+ LAZYADDASSOC(antag_rerolls, event.type, event.weight)
+ continue
+
+ event_pools[event.track] += event //Add it to the categorized event pools
return SS_INIT_SUCCESS
@@ -847,4 +855,33 @@ SUBSYSTEM_DEF(gamemode)
if(event.type == text2path(type))
return event
+/datum/controller/subsystem/gamemode/proc/inject_event(datum/round_event_control/event_control)
+ if(!istype(event_control, /datum/round_event_control))
+ return
+
+ var/datum/round_event_control/event = locate(event_control) in SSevents.control
+ if(!event)
+ return
+
+ event.run_event(admin_forced = TRUE)
+
+/datum/controller/subsystem/gamemode/proc/reroll_antagonist(datum/round_event_control/event_control, antag_name)
+ message_admins(span_yellowteamradio("[key_name_admin(usr)] requested a new antagonist to replace [antag_name]."))
+ log_admin("[key_name_admin(usr)] requested a new antagonist to replace [antag_name].")
+ if(isnull(event_control))
+ event_control = pick_weight(SSgamemode.antag_rerolls)
+ SSgamemode.inject_event(event_control = event_control)
+
+ADMIN_VERB(create_antagonist, R_FUN, "Create Antagonist", "Inject a little more action into the round.", ADMIN_CATEGORY_EVENTS)
+ var/list/available_antags = list()
+ for(var/datum/round_event_control/event_control as anything in SSgamemode.antag_rerolls)
+ var/datum/round_event_control/event = locate(event_control) in SSevents.control
+ LAZYADD(available_antags, event)
+
+ var/datum/round_event_control/selected_event = tgui_input_list(user, "Choose a crew antagonist type to spawn.", "Create Antagonist", available_antags)
+ if(isnull(selected_event))
+ return
+
+ SSgamemode.reroll_antagonist(event_control = selected_event, antag_name = "nobody")
+
#undef INIT_ORDER_GAMEMODE
diff --git a/modular_zubbers/code/modules/zantag_tickets/candidate_setup.dm b/modular_zubbers/code/modules/zantag_tickets/candidate_setup.dm
index 65c9268e015..8d626efc81a 100644
--- a/modular_zubbers/code/modules/zantag_tickets/candidate_setup.dm
+++ b/modular_zubbers/code/modules/zantag_tickets/candidate_setup.dm
@@ -1,6 +1,10 @@
/datum/round_event/antagonist/candidate_setup(datum/round_event_control/antagonist/cast_control)
var/list/candidates_tickets = candidates_to_tickets(cast_control.get_candidates())
+ if(!length(candidates_tickets))
+ message_admins(span_yellowteamradio("Antag tickets system failed to find any candidates!"))
+ log_game("Antag tickets system failed to find any candidates!")
+ return
//Logging purposes.
var/total_tickets = 0
@@ -17,5 +21,7 @@
setup_minds += candidate.mind
candidate_roles_setup(candidate)
var/our_weight = candidates_tickets[candidate]
+ if(!total_tickets)
+ total_tickets = our_weight
var/percent_chance = round( (our_weight/total_tickets)*100, 1)
log_antag_tickets("[key_name(candidate)] was made an antagonist with a [percent_chance]% chance to roll (self tickets: [our_weight], total tickets: [total_tickets], average tickets: [average_tickets]).")