diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index e7508654900..b7e1b028029 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -6,42 +6,37 @@ SUBSYSTEM_DEF(vote) runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT - var/initiator = null - var/started_time = null - var/time_remaining = 0 - var/mode = null - var/question = null var/list/choices = list() + var/list/choice_by_ckey = list() + var/list/generated_actions = list() + var/initiator + var/mode + var/question + var/started_time + var/time_remaining var/list/voted = list() var/list/voting = list() - var/list/generated_actions = list() - -/datum/controller/subsystem/vote/fire() //called by master_controller - if(mode) - time_remaining = round((started_time + CONFIG_GET(number/vote_period) - world.time)/10) - - if(time_remaining < 0) - result() - for(var/client/C in voting) - C << browse(null, "window=vote;can_close=0") - reset() - else - var/datum/browser/client_popup - for(var/client/C in voting) - client_popup = new(C, "vote", "Voting Panel") - client_popup.set_window_options("can_close=0") - client_popup.set_content(interface(C)) - client_popup.open(FALSE) +// Called by master_controller +/datum/controller/subsystem/vote/fire() + if(!mode) + return + time_remaining = round((started_time + CONFIG_GET(number/vote_period) - world.time)/10) + if(time_remaining < 0) + result() + SStgui.close_uis(src) + reset() /datum/controller/subsystem/vote/proc/reset() + choices.Cut() + choice_by_ckey.Cut() initiator = null - time_remaining = 0 mode = null question = null - choices.Cut() + time_remaining = 0 voted.Cut() voting.Cut() + remove_action_buttons() /datum/controller/subsystem/vote/proc/get_result() @@ -74,17 +69,13 @@ SUBSYSTEM_DEF(vote) else if(mode == "map") for (var/non_voter_ckey in non_voters) var/client/C = non_voters[non_voter_ckey] - if(C.prefs.preferred_map) - if(choices[C.prefs.preferred_map]) //No votes if the map isn't in the vote. - var/preferred_map = C.prefs.preferred_map - choices[preferred_map] += 1 - greatest_votes = max(greatest_votes, choices[preferred_map]) - else if(config.defaultmap) - if(choices[config.defaultmap]) //No votes if the map isn't in the vote. - var/default_map = config.defaultmap.map_name - choices[default_map] += 1 - greatest_votes = max(greatest_votes, choices[default_map]) - //get all options with that many votes and return them in a list + var/preferred_map = C.prefs.preferred_map + if(isnull(global.config.defaultmap)) + continue + if(!preferred_map) + preferred_map = global.config.defaultmap.map_name + choices[preferred_map] += 1 + greatest_votes = max(greatest_votes, choices[preferred_map]) . = list() if(greatest_votes) for(var/option in choices) @@ -141,12 +132,13 @@ SUBSYSTEM_DEF(vote) SSmapping.map_voted = TRUE if(restart) var/active_admins = FALSE - for(var/client/C in GLOB.admins) + for(var/client/C in GLOB.admins + GLOB.deadmins) if(!C.is_afk() && check_rights_for(C, R_SERVER)) active_admins = TRUE break if(!active_admins) - SSticker.Reboot("Restart vote successful.", "restart vote", 1) //no delay in case the restart is due to lag + // No delay in case the restart is due to lag + SSticker.Reboot("Restart vote successful.", "restart vote", 1) else to_chat(world, "Notice:Restart vote will not restart the server automatically because there are active admins on.") message_admins("A restart vote has passed, but there are active admins on with +server, so it has been canceled. If you wish, you may restart the server.") @@ -154,24 +146,30 @@ SUBSYSTEM_DEF(vote) return . /datum/controller/subsystem/vote/proc/submit_vote(vote) - if(mode) - if(CONFIG_GET(flag/no_dead_vote) && usr.stat == DEAD && !usr.client.holder) - return FALSE - if(!(usr.ckey in voted)) - if(vote && 1<=vote && vote<=choices.len) - voted += usr.ckey - choices[choices[vote]]++ //check this - return vote - return FALSE + if(!mode) + return FALSE + if(CONFIG_GET(flag/no_dead_vote) && usr.stat == DEAD && !usr.client.holder) + return FALSE + if(!vote || vote < 1 || vote > choices.len) + return FALSE + // If user has already voted, remove their specific vote + if(usr.ckey in voted) + choices[choices[choice_by_ckey[usr.ckey]]]-- + else + voted += usr.ckey + choice_by_ckey[usr.ckey] = vote + choices[choices[vote]]++ + return vote /datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key) - if(!Master.current_runlevel) //Server is still intializing. + //Server is still intializing. + if(!Master.current_runlevel) to_chat(usr, "Cannot start vote, server is not done initializing.") return FALSE - var/admin = FALSE + var/lower_admin = FALSE var/ckey = ckey(initiator_key) if(GLOB.admin_datums[ckey]) - admin = TRUE + lower_admin = TRUE if(!mode) if(started_time) @@ -179,9 +177,7 @@ SUBSYSTEM_DEF(vote) if(mode) to_chat(usr, "There is already a vote in progress! please wait for it to finish.") return FALSE - - - if(next_allowed_time > world.time && !admin) + if(next_allowed_time > world.time && !lower_admin) to_chat(usr, "A vote was initiated recently, you must wait [DisplayTimeText(next_allowed_time-world.time)] before a new vote can be started!") return FALSE @@ -192,14 +188,19 @@ SUBSYSTEM_DEF(vote) if("gamemode") choices.Add(config.votable_modes) if("map") - if(!admin && SSmapping.map_voted) + if(!lower_admin && SSmapping.map_voted) to_chat(usr, "The next map has already been selected.") return FALSE - for(var/map in config.maplist) + // Randomizes the list so it isn't always METASTATION + var/list/maps = list() + for(var/map in global.config.maplist) var/datum/map_config/VM = config.maplist[map] if(!VM.votable || (VM.map_name in SSpersistence.blocked_maps)) continue - choices.Add(VM.map_name) + maps += VM.map_name + shuffle_inplace(maps) + for(var/valid_map in maps) + choices.Add(valid_map) if("custom") question = stripped_input(usr,"What is the vote for?") if(!question) @@ -214,12 +215,12 @@ SUBSYSTEM_DEF(vote) mode = vote_type initiator = initiator_key started_time = world.time - var/text = "[capitalize(mode)] vote started by [initiator]." + var/text = "[capitalize(mode)] vote started by [initiator || "CentCom"]." if(mode == "custom") text += "\n[question]" log_vote(text) var/vp = CONFIG_GET(number/vote_period) - to_chat(world, "\n[text]\nType vote or click here to place your votes.\nYou have [DisplayTimeText(vp)] to vote.") + to_chat(world, "\n[text]\nType vote or click here to place your votes.\nYou have [DisplayTimeText(vp)] to vote.") time_remaining = round(vp/10) for(var/c in GLOB.clients) var/client/C = c @@ -234,97 +235,73 @@ SUBSYSTEM_DEF(vote) return TRUE return FALSE -/datum/controller/subsystem/vote/proc/interface(client/C) - if(!C) +/mob/verb/vote() + set category = "OOC" + set name = "Vote" + SSvote.ui_interact(usr) + +/datum/controller/subsystem/vote/ui_state() + return GLOB.always_state + +/datum/controller/subsystem/vote/ui_interact(mob/user, datum/tgui/ui) + // Tracks who is voting + if(!(user.client?.ckey in voting)) + voting += user.client?.ckey + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Vote") + ui.open() + +/datum/controller/subsystem/vote/ui_data(mob/user) + var/list/data = list( + "allow_vote_map" = CONFIG_GET(flag/allow_vote_map), + "allow_vote_mode" = CONFIG_GET(flag/allow_vote_mode), + "allow_vote_restart" = CONFIG_GET(flag/allow_vote_restart), + "choices" = list(), + "lower_admin" = !!user.client?.holder, + "mode" = mode, + "question" = question, + "selected_choice" = choice_by_ckey[user.client?.ckey], + "time_remaining" = time_remaining, + "upper_admin" = check_rights_for(user.client, R_ADMIN), + "voting" = list(), + ) + + if(!!user.client?.holder) + data["voting"] += list(voting) + + for(var/key in choices) + data["choices"] += list(list( + "name" = key, + "votes" = choices[key] || 0 + )) + + return data + +/datum/controller/subsystem/vote/ui_act(action, params) + . = ..() + if(.) return - var/admin = FALSE - var/trialmin = FALSE - if(C.holder) - admin = TRUE - if(check_rights_for(C, R_ADMIN)) - trialmin = TRUE - voting |= C - if(mode) - if(question) - . += "