diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 4f5ad8f3d74..b21ce90ef41 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -164,6 +164,14 @@ /// allow votes to change map /datum/config_entry/flag/allow_vote_map +/// allow players to vote to re-do the map vote +/datum/config_entry/flag/allow_rock_the_vote + +/// the number of times we allow players to rock the vote +/datum/config_entry/number/max_rocking_votes + default = 1 + min_val = 1 + /// minimum time between voting sessions (deciseconds, 10 minute default) /datum/config_entry/number/vote_delay default = 6000 @@ -176,8 +184,8 @@ integer = FALSE min_val = 0 -/// If disabled, no-voters will automatically have their votes added to certain vote options -/// (For eample: restart votes will default to "no restart", map votes will default to their preferred map / default map) +/// If disabled, non-voters will automatically have their votes added to certain vote options +/// (For example: restart votes will default to "no restart", map votes will default to their preferred map / default map, rocking the vote will default to "no") /datum/config_entry/flag/default_no_vote /// Prevents dead people from voting. diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index db20431886a..c35a6244252 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -9,7 +9,12 @@ SUBSYSTEM_DEF(mapping) var/datum/map_config/config var/datum/map_config/next_map_config + /// Has the map for the next round been voted for already? var/map_voted = FALSE + /// Has the map for the next round been deliberately chosen by an admin? + var/map_force_chosen = FALSE + /// Has the map vote been rocked? + var/map_vote_rocked = FALSE var/list/map_templates = list() diff --git a/code/datums/votes/_vote_datum.dm b/code/datums/votes/_vote_datum.dm index 63bcd9cf22e..13cae111ef5 100644 --- a/code/datums/votes/_vote_datum.dm +++ b/code/datums/votes/_vote_datum.dm @@ -13,6 +13,8 @@ var/vote_sound = 'sound/misc/bloop.ogg' /// A list of default choices we have for this vote. var/list/default_choices + /// Does the name of this vote contain the word "vote"? + var/contains_vote_in_name = FALSE // Internal values used when tracking ongoing votes. // Don't mess with these, change the above values / override procs for subtypes. @@ -103,7 +105,7 @@ started_time = world.time time_remaining = round(duration / 10) - return "[capitalize(name)] vote started by [initiator || "Central Command"]." + return "[contains_vote_in_name ? "[capitalize(name)]" : "[capitalize(name)] vote"] started by [initiator || "Central Command"]." /** * Gets the result of the vote. diff --git a/code/datums/votes/map_vote.dm b/code/datums/votes/map_vote.dm index b55ee8419ee..849f7c20d12 100644 --- a/code/datums/votes/map_vote.dm +++ b/code/datums/votes/map_vote.dm @@ -48,6 +48,9 @@ if(forced) return TRUE + if(SSmapping.map_vote_rocked) + return TRUE + if(!CONFIG_GET(flag/allow_vote_map)) if(by_who) to_chat(by_who, span_warning("Map voting is disabled.")) @@ -85,3 +88,5 @@ SSmapping.changemap(winning_map) SSmapping.map_voted = TRUE + if(SSmapping.map_vote_rocked) + SSmapping.map_vote_rocked = FALSE diff --git a/code/datums/votes/rock_the_vote.dm b/code/datums/votes/rock_the_vote.dm new file mode 100644 index 00000000000..62181fef64f --- /dev/null +++ b/code/datums/votes/rock_the_vote.dm @@ -0,0 +1,80 @@ +#define CHOICE_TO_ROCK "Yes, re-do the map vote." +#define CHOICE_NOT_TO_ROCK "No, keep the currently selected map." + +/// If a map vote is called before the emergency shuttle leaves the station, the players can call another vote to re-run the vote on the shuttle leaving. +/datum/vote/rock_the_vote + name = "Rock the Vote" + override_question = "Rock the Vote?" + contains_vote_in_name = TRUE //lol + default_choices = list( + CHOICE_TO_ROCK, + CHOICE_NOT_TO_ROCK, + ) + /// The number of times we have rocked the vote thus far. + var/rocking_votes = 0 + +/datum/vote/rock_the_vote/toggle_votable(mob/toggler) + if(!toggler) + CRASH("[type] wasn't passed a \"toggler\" mob to toggle_votable.") + if(!check_rights_for(toggler.client, R_ADMIN)) + return FALSE + + CONFIG_SET(flag/allow_rock_the_vote, !CONFIG_GET(flag/allow_rock_the_vote)) + return TRUE + +/datum/vote/rock_the_vote/is_config_enabled() + return CONFIG_GET(flag/allow_rock_the_vote) + +/datum/vote/rock_the_vote/can_be_initiated(mob/by_who, forced) + . = ..() + + if(!.) + return FALSE + + if(!forced && !CONFIG_GET(flag/allow_rock_the_vote)) + if(by_who) + to_chat(by_who, span_warning("Rocking the vote is disabled by this server's configuration settings.")) + return FALSE + + if(SSticker.current_state == GAME_STATE_FINISHED) + if(by_who) + to_chat(by_who, span_warning("The game is finished, no map votes can be initiated.")) + return FALSE + + if(rocking_votes >= CONFIG_GET(number/max_rocking_votes)) + if(by_who) + to_chat(by_who, span_warning("You have rocked the vote the maximum number of times.")) + return FALSE + + if(SSmapping.map_vote_rocked) + if(by_who) + to_chat(by_who, span_warning("The vote has already been rocked! Initiate a map vote!")) + return FALSE + + if(!SSmapping.map_voted) + if(by_who) + to_chat(by_who, span_warning("Rocking the vote is disabled because no map has been voted on yet!")) + return FALSE + + if(SSmapping.map_force_chosen) + if(by_who) + to_chat(by_who, span_warning("Rocking the vote is disabled because an admin has forcibly set the map!")) + return FALSE + + return TRUE + +/datum/vote/rock_the_vote/finalize_vote(winning_option) + rocking_votes++ + if(winning_option == CHOICE_NOT_TO_ROCK) + return + + if(winning_option == CHOICE_TO_ROCK) + to_chat(world, span_boldannounce("The vote has been rocked! Players are now able to re-run the map vote once more.")) + message_admins("The players have successfully rocked the vote.") + SSmapping.map_vote_rocked = TRUE + return + + CRASH("[type] wasn't passed a valid winning choice. (Got: [winning_option || "null"])") + +#undef CHOICE_TO_ROCK +#undef CHOICE_NOT_TO_ROCK diff --git a/code/modules/admin/verbs/maprotation.dm b/code/modules/admin/verbs/maprotation.dm index cc7e72f1ea5..c985a835a11 100644 --- a/code/modules/admin/verbs/maprotation.dm +++ b/code/modules/admin/verbs/maprotation.dm @@ -98,9 +98,11 @@ if(SSmapping.changemap(VM)) message_admins("[key_name_admin(usr)] has changed the map to [VM.map_name]") + SSmapping.map_force_chosen = TRUE else var/datum/map_config/VM = maprotatechoices[chosenmap] message_admins("[key_name_admin(usr)] is changing the map to [VM.map_name]") log_admin("[key_name(usr)] is changing the map to [VM.map_name]") if (SSmapping.changemap(VM)) message_admins("[key_name_admin(usr)] has changed the map to [VM.map_name]") + SSmapping.map_force_chosen = TRUE diff --git a/config/config.txt b/config/config.txt index 569b62c7160..c80b60cae87 100644 --- a/config/config.txt +++ b/config/config.txt @@ -200,6 +200,12 @@ ID_CONSOLE_JOBSLOT_DELAY 30 ## allow players to initiate a map-change vote #ALLOW_VOTE_MAP +## allow players to rock the vote, or to vote on the map again if they didn't like the last results +#ALLOW_ROCK_THE_VOTE + +## the number of times you wish to allow players to rock the vote in a given shift +MAX_ROCKING_VOTES 1 + ## min delay (deciseconds) between voting sessions (default 10 minutes) VOTE_DELAY 6000 diff --git a/tgstation.dme b/tgstation.dme index 7cd419dbc20..4b606016959 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1226,6 +1226,7 @@ #include "code\datums\votes\custom_vote.dm" #include "code\datums\votes\map_vote.dm" #include "code\datums\votes\restart_vote.dm" +#include "code\datums\votes\rock_the_vote.dm" #include "code\datums\weather\weather.dm" #include "code\datums\weather\weather_types\ash_storm.dm" #include "code\datums\weather\weather_types\floor_is_lava.dm"