From 4b60813831e0a8f5471fc400bdab067fae05496e Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Tue, 6 Feb 2024 10:46:45 +0300 Subject: [PATCH] [MIRROR] Fixes Cult voting for a leader (#713) (#1780) * Fixes Cult voting for a leader (#81169) ## About The Pull Request With the recent changes to polling, it seems like it didn't properly poll cultists, I fixed that and fixed other issues with it (such as it telling players that they are signing up to BE a cult leader, when they arent). Also fixed the button to put yourself forward as cult leader, it properly removes and gives itself when necessary. ## Why It's Good For The Game Cult button works again how cool is that Closes https://github.com/tgstation/tgstation/issues/80620 ## Changelog :cl: fix: Cultists can now vote for a Cult leader again. /:cl: * Fixes Cult voting for a leader --------- Co-authored-by: NovaBot <154629622+NovaBot13@users.noreply.github.com> Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> --- code/__DEFINES/polls.dm | 11 ++ code/controllers/subsystem/polling.dm | 12 +- code/datums/candidate_poll.dm | 31 +++++- code/modules/antagonists/cult/cult.dm | 6 +- code/modules/antagonists/cult/cult_comms.dm | 116 +++++++++++++------- 5 files changed, 124 insertions(+), 52 deletions(-) diff --git a/code/__DEFINES/polls.dm b/code/__DEFINES/polls.dm index a5a0616d8d4..435e9f60141 100644 --- a/code/__DEFINES/polls.dm +++ b/code/__DEFINES/polls.dm @@ -5,3 +5,14 @@ #define POLLTYPE_RATING "NUMVAL" #define POLLTYPE_MULTI "MULTICHOICE" #define POLLTYPE_IRV "IRV" + +///The message sent when you sign up to a poll. +#define POLL_RESPONSE_SIGNUP "signup" +///The message sent when you've already signed up for a poll and are trying to sign up again. +#define POLL_RESPONSE_ALREADY_SIGNED "already_signed" +///The message sent when you are not signed up for a poll. +#define POLL_RESPONSE_NOT_SIGNED "not_signed" +///The message sent when you are too late to unregister from a poll. +#define POLL_RESPONSE_TOO_LATE_TO_UNREGISTER "failed_unregister" +///The message sent when you successfully unregister from a poll. +#define POLL_RESPONSE_UNREGISTERED "unregistered" diff --git a/code/controllers/subsystem/polling.dm b/code/controllers/subsystem/polling.dm index 1eab3fb8f0d..8bbb37661c0 100644 --- a/code/controllers/subsystem/polling.dm +++ b/code/controllers/subsystem/polling.dm @@ -16,7 +16,7 @@ SUBSYSTEM_DEF(polling) if(running_poll.time_left() <= 0) polling_finished(running_poll) -/datum/controller/subsystem/polling/proc/poll_candidates(question, role, check_jobban, poll_time = 30 SECONDS, ignore_category = null, flash_window = TRUE, list/group = null, pic_source, role_name_text) +/datum/controller/subsystem/polling/proc/poll_candidates(question, role, check_jobban, poll_time = 30 SECONDS, ignore_category = null, flash_window = TRUE, list/group = null, pic_source, role_name_text, list/custom_response_messages) if(group.len == 0) return list() if(role && !role_name_text) @@ -32,7 +32,7 @@ SUBSYSTEM_DEF(polling) var/jumpable = isatom(pic_source) ? pic_source : null - var/datum/candidate_poll/new_poll = new(role_name_text, question, poll_time, ignore_category, jumpable) + var/datum/candidate_poll/new_poll = new(role_name_text, question, poll_time, ignore_category, jumpable, custom_response_messages) LAZYADD(currently_polling, new_poll) var/category = "[new_poll.poll_key]_poll_alert" @@ -40,13 +40,13 @@ SUBSYSTEM_DEF(polling) for(var/mob/candidate_mob as anything in group) if(!candidate_mob.client) continue - // Universal opt-out for all players. - if((!candidate_mob.client.prefs.read_preference(/datum/preference/toggle/ghost_roles))) + // Universal opt-out for all players if it's for a role. + if(role && (!candidate_mob.client.prefs.read_preference(/datum/preference/toggle/ghost_roles))) continue // Opt-out for admins whom are currently adminned. - if((!candidate_mob.client.prefs.read_preference(/datum/preference/toggle/ghost_roles_as_admin)) && candidate_mob.client.holder) + if(role && (!candidate_mob.client.prefs.read_preference(/datum/preference/toggle/ghost_roles_as_admin)) && candidate_mob.client.holder) continue - if(!is_eligible(candidate_mob, role, check_jobban, ignore_category)) + if(role && !is_eligible(candidate_mob, role, check_jobban, ignore_category)) continue SEND_SOUND(candidate_mob, 'sound/misc/notice2.ogg') diff --git a/code/datums/candidate_poll.dm b/code/datums/candidate_poll.dm index 1856858accd..6ccd43c01fd 100644 --- a/code/datums/candidate_poll.dm +++ b/code/datums/candidate_poll.dm @@ -20,8 +20,23 @@ var/finished = FALSE /// Used to categorize in the alerts system and identify polls of same question+role so we can stack the alert buttons var/poll_key + ///Response messages sent in specific key areas for full customization of polling. + var/list/response_messages = list( + POLL_RESPONSE_SIGNUP = "You have signed up for %ROLE%! A candidate will be picked randomly soon.", + POLL_RESPONSE_ALREADY_SIGNED = "You have already signed up for this!", + POLL_RESPONSE_NOT_SIGNED = "You aren't signed up for this!", + POLL_RESPONSE_TOO_LATE_TO_UNREGISTER = "It's too late to unregister yourself, selection has already begun!", + POLL_RESPONSE_UNREGISTERED = "You have been unregistered as a candidate for %ROLE%. You can sign up again before the poll ends.", + ) -/datum/candidate_poll/New(polled_role, polled_question, poll_duration, poll_ignoring_category, poll_jumpable) +/datum/candidate_poll/New( + polled_role, + polled_question, + poll_duration, + poll_ignoring_category, + poll_jumpable, + list/custom_response_messages = list(), +) role = polled_role question = polled_question duration = poll_duration @@ -30,6 +45,10 @@ signed_up = list() time_started = world.time poll_key = "[question]_[role ? role : "0"]" + if(custom_response_messages.len) + response_messages = custom_response_messages + for(var/individual_message in response_messages) + response_messages[individual_message] = replacetext(response_messages[individual_message], "%ROLE%", role) return ..() /datum/candidate_poll/Destroy() @@ -49,7 +68,7 @@ return FALSE if(candidate in signed_up) if(!silent) - to_chat(candidate, span_warning("You have already signed up for this!")) + to_chat(candidate, span_warning(response_messages[POLL_RESPONSE_ALREADY_SIGNED])) return FALSE if(time_left() <= 0) if(!silent) @@ -59,7 +78,7 @@ signed_up += candidate if(!silent) - to_chat(candidate, span_notice("You have signed up for [role]! A candidate will be picked randomly soon.")) + to_chat(candidate, span_notice(response_messages[POLL_RESPONSE_SIGNUP])) // Sign them up for any other polls with the same mob type for(var/datum/candidate_poll/existing_poll as anything in SSpolling.currently_polling) if(src != existing_poll && poll_key == existing_poll.poll_key && !(candidate in existing_poll.signed_up)) @@ -73,17 +92,17 @@ return FALSE if(!(candidate in signed_up)) if(!silent) - to_chat(candidate, span_warning("You aren't signed up for this!")) + to_chat(candidate, span_warning(response_messages[POLL_RESPONSE_NOT_SIGNED])) return FALSE if(time_left() <= 0) if(!silent) - to_chat(candidate, span_danger("It's too late to unregister yourself, selection has already begun!")) + to_chat(candidate, span_danger(response_messages[POLL_RESPONSE_TOO_LATE_TO_UNREGISTER])) return FALSE signed_up -= candidate if(!silent) - to_chat(candidate, span_danger("You have been unregistered as a candidate for [role]. You can sign up again before the poll ends.")) + to_chat(candidate, span_danger(response_messages[POLL_RESPONSE_UNREGISTERED])) for(var/datum/candidate_poll/existing_poll as anything in SSpolling.currently_polling) if(src != existing_poll && poll_key == existing_poll.poll_key && (candidate in existing_poll.signed_up)) diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm index 9cd24f8e707..e38c762d700 100644 --- a/code/modules/antagonists/cult/cult.dm +++ b/code/modules/antagonists/cult/cult.dm @@ -200,7 +200,8 @@ owner.current.update_mob_action_buttons() for(var/datum/mind/cult_mind as anything in cult_team.members) - vote_ability.Remove(cult_mind.current) + var/datum/antagonist/cult/cult_datum = cult_mind.has_antag_datum(/datum/antagonist/cult) + cult_datum.vote_ability.Remove(cult_mind.current) to_chat(cult_mind.current, span_cultlarge("[owner.current] has won the cult's support and is now their master. \ Follow [owner.current.p_their()] orders to the best of your ability!")) @@ -234,7 +235,8 @@ throwing.Remove(owner.current) owner.current.update_mob_action_buttons() for(var/datum/mind/cult_mind as anything in cult_team.members) - vote_ability.Grant(cult_mind.current) + var/datum/antagonist/cult/cult_datum = cult_mind.has_antag_datum(/datum/antagonist/cult) + cult_datum.vote_ability.Grant(cult_mind.current) to_chat(owner.current, span_cultlarge("You have been demoted from being the cult's Master, you are now an acolyte once more!")) diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm index 00bdc960644..bee8eec306f 100644 --- a/code/modules/antagonists/cult/cult_comms.dm +++ b/code/modules/antagonists/cult/cult_comms.dm @@ -99,60 +99,100 @@ /datum/action/innate/cult/mastervote/IsAvailable(feedback = FALSE) if(!owner || !owner.mind) return FALSE - var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE) - if(!C || C.cult_team.cult_vote_called || !ishuman(owner)) + var/datum/antagonist/cult/mind_cult_datum = owner.mind.has_antag_datum(/datum/antagonist/cult) + if(!mind_cult_datum || mind_cult_datum.cult_team.cult_leader_datum || mind_cult_datum.cult_team.cult_vote_called || !ishuman(owner)) return FALSE return ..() /datum/action/innate/cult/mastervote/Activate() var/choice = tgui_alert(owner, "The mantle of leadership is heavy. Success in this role requires an expert level of communication and experience. Are you sure?",, list("Yes", "No")) if(choice == "Yes" && IsAvailable()) - var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE) - pollCultists(owner,C.cult_team) + var/datum/antagonist/cult/mind_cult_datum = owner.mind.has_antag_datum(/datum/antagonist/cult) + start_poll_cultists_for_leader(owner, mind_cult_datum.cult_team) -/proc/pollCultists(mob/living/Nominee, datum/team/cult/team) //Cult Master Poll +///Start the poll for Cult Leaeder. +/proc/start_poll_cultists_for_leader(mob/living/nominee, datum/team/cult/team) if(world.time < CULT_POLL_WAIT) - to_chat(Nominee, "It would be premature to select a leader while everyone is still settling in, try again in [DisplayTimeText(CULT_POLL_WAIT-world.time)].") + to_chat(nominee, "It would be premature to select a leader while everyone is still settling in, try again in [DisplayTimeText(CULT_POLL_WAIT-world.time)].") return - team.cult_vote_called = TRUE //somebody's trying to be a master, make sure we don't let anyone else try - for(var/datum/mind/B in team.members) - if(B.current) - B.current.update_mob_action_buttons() - if(!B.current.incapacitated()) - SEND_SOUND(B.current, 'sound/hallucinations/im_here1.ogg') - to_chat(B.current, span_cultlarge("Acolyte [Nominee] has asserted that [Nominee.p_theyre()] worthy of leading the cult. A vote will be called shortly.")) - sleep(10 SECONDS) - var/list/asked_cultists = list() - for(var/datum/mind/B in team.members) - if(B.current && B.current != Nominee && !B.current.incapacitated()) - SEND_SOUND(B.current, 'sound/magic/exit_blood.ogg') - asked_cultists += B.current - var/list/yes_voters = SSpolling.poll_candidates("[Nominee] seeks to lead your cult, do you support [Nominee.p_them()]?", poll_time = 30 SECONDS, group = asked_cultists, pic_source = Nominee, role_name_text = "cult master") - if(QDELETED(Nominee) || Nominee.incapacitated()) + team.cult_vote_called = TRUE + for(var/datum/mind/team_member as anything in team.members) + if(!team_member.current) + continue + team_member.current.update_mob_action_buttons() + if(team_member.current.incapacitated()) + continue + SEND_SOUND(team_member.current, 'sound/hallucinations/im_here1.ogg') + to_chat(team_member.current, span_cultlarge("Acolyte [nominee] has asserted that [nominee.p_theyre()] worthy of leading the cult. A vote will be called shortly.")) + + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(poll_cultists_for_leader), nominee, team), 10 SECONDS) + +///Polls all Cultists on whether the person putting themselves forward should be made the Cult Leader, if they can actually be such. +/proc/poll_cultists_for_leader(mob/living/nominee, datum/team/cult/team) + if(QDELETED(nominee) || nominee.incapacitated()) team.cult_vote_called = FALSE - for(var/datum/mind/B in team.members) - if(B.current) - B.current.update_mob_action_buttons() - if(!B.current.incapacitated()) - to_chat(B.current,span_cultlarge("[Nominee] has died in the process of attempting to win the cult's support!")) + for(var/datum/mind/team_member as anything in team.members) + if(!team_member.current) + continue + team_member.current.update_mob_action_buttons() + if(team_member.current.incapacitated()) + continue + to_chat(team_member.current,span_cultlarge("[nominee] has died in the process of attempting to start a vote!")) return FALSE - if(!Nominee.mind) + var/list/mob/living/asked_cultists = list() + for(var/datum/mind/team_member as anything in team.members) + if(!team_member.current || team_member.current == nominee || team_member.current.incapacitated()) + continue + SEND_SOUND(team_member.current, 'sound/magic/exit_blood.ogg') + asked_cultists += team_member.current + + var/list/yes_voters = SSpolling.poll_candidates( + question = "[nominee] seeks to lead your cult, do you support [nominee.p_them()]?", + poll_time = 30 SECONDS, + group = asked_cultists, + pic_source = nominee, + role_name_text = "cult master", + custom_response_messages = list( + POLL_RESPONSE_SIGNUP = "You have pledged your allegience to [nominee].", + POLL_RESPONSE_ALREADY_SIGNED = "You have already pledged your allegience!", + POLL_RESPONSE_NOT_SIGNED = "You aren't nominated for this.", + POLL_RESPONSE_TOO_LATE_TO_UNREGISTER = "It's too late to unregister yourself, voting has already begun!", + POLL_RESPONSE_UNREGISTERED = "You have been removed your pledge to [nominee].", + ) + ) + if(QDELETED(nominee) || nominee.incapacitated()) + team.cult_vote_called = FALSE + for(var/datum/mind/team_member as anything in team.members) + if(!team_member.current) + continue + team_member.current.update_mob_action_buttons() + if(team_member.current.incapacitated()) + continue + to_chat(team_member.current,span_cultlarge("[nominee] has died in the process of attempting to win the cult's support!")) + return FALSE + if(!nominee.mind) team.cult_vote_called = FALSE - for(var/datum/mind/B in team.members) - if(B.current) - B.current.update_mob_action_buttons() - if(!B.current.incapacitated()) - to_chat(B.current,span_cultlarge("[Nominee] has gone catatonic in the process of attempting to win the cult's support!")) + for(var/datum/mind/team_member as anything in team.members) + if(!team_member.current) + continue + team_member.current.update_mob_action_buttons() + if(team_member.current.incapacitated()) + continue + to_chat(team_member.current,span_cultlarge("[nominee] has gone catatonic in the process of attempting to win the cult's support!")) return FALSE if(LAZYLEN(yes_voters) <= LAZYLEN(asked_cultists) * 0.5) team.cult_vote_called = FALSE - for(var/datum/mind/B in team.members) - if(B.current) - B.current.update_mob_action_buttons() - if(!B.current.incapacitated()) - to_chat(B.current, span_cultlarge("[Nominee] could not win the cult's support and shall continue to serve as an acolyte.")) + for(var/datum/mind/team_member as anything in team.members) + if(!team_member.current) + continue + team_member.current.update_mob_action_buttons() + if(team_member.current.incapacitated()) + continue + to_chat(team_member.current, span_cultlarge("[nominee] could not win the cult's support and shall continue to serve as an acolyte.")) return FALSE - var/datum/antagonist/cult/cult_datum = Nominee.mind.has_antag_datum(/datum/antagonist/cult) + + team.cult_vote_called = FALSE + var/datum/antagonist/cult/cult_datum = nominee.mind.has_antag_datum(/datum/antagonist/cult) if(!cult_datum.make_cult_leader()) CRASH("[cult_datum.owner.current] was supposed to turn into the leader, but they didn't for some reason. This isn't supposed to happen unless an Admin messed with it.") return TRUE