From 4569cbbb2ab3109b761635475fa75eff941c0e4b Mon Sep 17 00:00:00 2001 From: LT3 <83487515+lessthnthree@users.noreply.github.com> Date: Mon, 5 Jan 2026 13:37:09 -0800 Subject: [PATCH] Admin create antagonist/re-roll antagonist (#4971) ## About The Pull Request - Adds a prompt when an admin is removing someone's antagonist datum if they would like to re-roll for a new antagonist to replace them - Brings back the Create Antagonist verb - When creating an antagonist, it tells the admin who was selected ## Why It's Good For The Game Admin quality of life ## Changelog :cl: LT3 admin: Admin button in the traitor panel to automatically re-roll antagonists admin: Admin create-antagonist verb admin: Game logs now include what player gets turned into an antagonist /:cl: --- .../~~bubber_defines/storyteller_defines.dm | 2 + code/datums/mind/_mind.dm | 11 +++++ code/modules/admin/antag_panel.dm | 3 +- .../crewset/_antagonist_event.dm | 4 ++ .../event_defines/crewset/bloodsucker.dm | 7 ++++ .../event_defines/crewset/changeling.dm | 7 ++++ .../event_defines/crewset/heretic.dm | 7 ++++ .../event_defines/crewset/spies.dm | 7 ++++ .../event_defines/crewset/traitor.dm | 7 ++++ .../code/modules/storyteller/gamemode.dm | 41 ++++++++++++++++++- .../modules/zantag_tickets/candidate_setup.dm | 6 +++ 11 files changed, 99 insertions(+), 3 deletions(-) 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]).")