Skip to content

Commit

Permalink
more stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkSuckerberg committed Jan 25, 2024
1 parent ae7222a commit 12be50f
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 39 deletions.
4 changes: 4 additions & 0 deletions code/__DEFINES/maths.dm
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@

#define ROUND_UP(x) (-round(-(x)))

/// Returns the number of digits in a number. Only works on whole numbers.
/// This is marginally faster than string interpolation -> length
#define DIGITS(x) (ROUND_UP(log(10, x)))

// round() acts like floor(x, 1) by default but can't handle other values
#define FLOOR(x, y) (round((x) / (y)) * (y))

Expand Down
7 changes: 7 additions & 0 deletions code/__DEFINES/subsystems.dm
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,10 @@
#define VOTE_COUNT_METHOD_SINGLE 1
/// Approval voting. Any number of selections per person, and the selection with the most votes wins.
#define VOTE_COUNT_METHOD_MULTI 2

/// The choice with the most votes wins. Ties are broken by the first choice to reach that number of votes.
#define VOTE_WINNER_METHOD_SIMPLE "Simple"
/// The winning choice is selected randomly based on the number of votes each choice has.
#define VOTE_WINNER_METHOD_WEIGHTED_RANDOM "Weighted Random"
/// There is no winner for this vote.
#define VOTE_WINNER_METHOD_NONE "None"
4 changes: 2 additions & 2 deletions code/controllers/configuration/entries/general.dm
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@

/datum/config_entry/flag/allow_admin_asaycolor //Allows admins with relevant permissions to have a personalized asay color

/datum/config_entry/flag/allow_vote_restart // allow votes to restart
/datum/config_entry/flag/allow_vote_restart // allow player votes to restart

/datum/config_entry/flag/allow_vote_mode // allow votes to change mode
/datum/config_entry/flag/allow_vote_transfer // allow player votes to initiate a transfer

/datum/config_entry/flag/auth_only // server can only be used for authentication

Expand Down
3 changes: 3 additions & 0 deletions code/controllers/subsystem/autotransfer.dm
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ SUBSYSTEM_DEF(autotransfer)

/datum/controller/subsystem/autotransfer/fire()
if(COOLDOWN_FINISHED(src, next_vote))
//Delay the vote if there's already a vote in progress
if(SSvote.current_vote)
COOLDOWN_START(src, next_vote, SSvote.current_vote.time_remaining + 10 SECONDS)
SSvote.initiate_vote(/datum/vote/transfer_vote, "The Server", forced = TRUE)
COOLDOWN_START(src, next_vote, CONFIG_GET(number/vote_autotransfer_interval))

Expand Down
6 changes: 4 additions & 2 deletions code/controllers/subsystem/vote.dm
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,13 @@ SUBSYSTEM_DEF(vote)
// Announce the results of the vote to the world.
var/to_display = current_vote.get_result_text(winners, final_winner, non_voters)

log_vote(to_display)
var/log_string = replacetext(to_display, "\n", "\\n") // 'keep' the newlines, but dont actually print them as newlines
log_vote(log_string)
to_chat(world, span_infoplain(vote_font("\n[to_display]")))

// Finally, doing any effects on vote completion
current_vote.finalize_vote(final_winner)
if (final_winner) // if no one voted, or the vote cannot be won, final_winner will be null
current_vote.finalize_vote(final_winner)

/**
* One selection per person, and the selection with the most votes wins.
Expand Down
79 changes: 59 additions & 20 deletions code/datums/votes/_vote_datum.dm
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
var/time_remaining
/// The counting method we use for votes.
var/count_method = VOTE_COUNT_METHOD_SINGLE
/// The method for selecting a winner.
var/winner_method = VOTE_WINNER_METHOD_SIMPLE

/**
* Used to determine if this vote is a possible
Expand Down Expand Up @@ -121,33 +123,41 @@
*/
/datum/vote/proc/get_vote_result(list/non_voters)
RETURN_TYPE(/list)
SHOULD_CALL_PARENT(TRUE)

switch(winner_method)
if(VOTE_WINNER_METHOD_NONE)
return list()
if(VOTE_WINNER_METHOD_SIMPLE)
return get_simple_winner()
if(VOTE_WINNER_METHOD_WEIGHTED_RANDOM)
return get_random_winner()

stack_trace("invalid select winner method: [winner_method]. Defaulting to simple.")
return get_simple_winner()

var/list/winners = list()
/// Gets the winner of the vote, selecting the choice with the most votes.
/datum/vote/proc/get_simple_winner()
var/highest_vote = 0
var/list/current_winners = list()

for(var/option in choices)

var/vote_count = choices[option]
// If we currently have no winners...
if(!length(winners))
// And the current option has any votes, it's the new highest.
if(vote_count > 0)
winners += option
highest_vote = vote_count
if(vote_count < highest_vote)
continue

// If we're greater than, and NOT equal to, the highest vote,
// we are the new supreme winner - clear all others
if(vote_count > highest_vote)
winners.Cut()
winners += option
highest_vote = vote_count
current_winners = list(option)
continue
current_winners += option

// If we're equal to the highest vote, we tie for winner
else if(vote_count == highest_vote)
winners += option
return length(current_winners) ? current_winners : list()

return winners
/// Gets the winner of the vote, selecting a random choice from all choices based on their vote count.
/datum/vote/proc/get_random_winner()
var/winner = pickweight(choices)
return winner ? list(winner) : list()

/**
* Gets the resulting text displayed when the vote is completed.
Expand All @@ -159,17 +169,46 @@
* Return a formatted string of text to be displayed to everyone.
*/
/datum/vote/proc/get_result_text(list/all_winners, real_winner, list/non_voters)
if(length(all_winners) <= 0 || !real_winner)
return span_bold("Vote Result: Inconclusive - No Votes!")

var/returned_text = ""
if(override_question)
returned_text += span_bold(override_question)
else
returned_text += span_bold("[capitalize(name)] Vote")

returned_text += "\nWinner Selection: "
switch(winner_method)
if(VOTE_WINNER_METHOD_NONE)
returned_text += "None"
if(VOTE_WINNER_METHOD_WEIGHTED_RANDOM)
returned_text += "Weighted Random"
else
returned_text += "Simple"

var/total_votes = 0 // for determining percentage of votes
for(var/option in choices)
total_votes += choices[option]

if(total_votes <= 0)
return span_bold("Vote Result: Inconclusive - No Votes!")

returned_text += "\nResults:"
for(var/option in choices)
returned_text += "\n[span_bold(option)]: [choices[option]]"
returned_text += "\n"
var/votes = choices[option]
var/percentage_text = ""
if(votes > 0)
var/actual_percentage = round((votes / total_votes) * 100, 0.1)
var/text = "[actual_percentage]"
var/spaces_needed = 5 - length(text)
for(var/_ in 1 to spaces_needed)
returned_text += " "
percentage_text += "[text]%"
else
percentage_text = " 0%"
returned_text += "[percentage_text] | [span_bold(option)]: [choices[option]]"

if(!real_winner) // vote has no winner or cannot be won, but still had votes
return returned_text

returned_text += "\n"
returned_text += get_winner_text(all_winners, real_winner, non_voters)
Expand Down
23 changes: 19 additions & 4 deletions code/datums/votes/custom_vote.dm
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,25 @@
return forced

/datum/vote/custom_vote/create_vote(mob/vote_creator)
var/custom_win_method = tgui_input_list(
vote_creator,
"How should the vote winner be determined?",
"Winner Method",
list("Simple", "Weighted Random", "No Winner"),
)
if(!custom_win_method)
custom_win_method = "Simple"
switch(custom_win_method)
if("Simple")
winner_method = VOTE_WINNER_METHOD_SIMPLE
if("Weighted Random")
winner_method = VOTE_WINNER_METHOD_WEIGHTED_RANDOM
if("No Winner")
winner_method = VOTE_WINNER_METHOD_NONE
else
to_chat(vote_creator, span_boldwarning("Unknown winner method. Contact a coder."))
return FALSE

override_question = input(vote_creator, "What is the vote for?", "Custom Vote") as text|null
if(!override_question)
return FALSE
Expand All @@ -53,8 +72,4 @@
. = ..()
. += "\n[override_question]"

// There are no winners or losers for custom votes
/datum/vote/custom_vote/get_winner_text(list/all_winners, real_winner, list/non_voters)
return "[span_bold("Did not vote:")] [length(non_voters)]"

#undef MAX_CUSTOM_VOTE_OPTIONS
4 changes: 2 additions & 2 deletions code/datums/votes/transfer_vote.dm
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@
if(2 to 3)
factor = 1
if(3 to 4)
factor = 1.2
factor = 1.5
else
factor = 1.4
factor = 2
choices[CHOICE_TRANSFER] += round(length(non_voters) * factor)

return ..()
Expand Down
4 changes: 0 additions & 4 deletions code/game/world.dm
Original file line number Diff line number Diff line change
Expand Up @@ -304,10 +304,6 @@ GLOBAL_VAR(restart_counter)
if (server_name)
s += "<b>[server_name]</b> &#8212; "
features += "[CONFIG_GET(flag/norespawn) ? "no " : ""]respawn"
if(CONFIG_GET(flag/allow_vote_mode))
features += "vote"
if(CONFIG_GET(flag/allow_ai))
features += "AI allowed"
hostedby = CONFIG_GET(string/hostedby)

var/discord_url
Expand Down
7 changes: 2 additions & 5 deletions config/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,8 @@ ID_CONSOLE_JOBSLOT_DELAY 30
## allow players to initiate a restart vote
#ALLOW_VOTE_RESTART

## allow players to initiate a mode-change vote
#ALLOW_VOTE_MODE

## allow players to initiate a map-change vote
#ALLOW_VOTE_MAP
## allow players to initiate a transfer vote
#ALLOW_VOTE_TRANSFER

## min delay (deciseconds) between voting sessions (default 10 minutes)
VOTE_DELAY 6000
Expand Down

0 comments on commit 12be50f

Please sign in to comment.