Merge pull request #170 from lutoma/vote-start

Require a minimum number of votes to start a game
This commit is contained in:
Ryan Schmidt 2015-10-25 09:37:35 -07:00
commit f274f113c4
2 changed files with 75 additions and 3 deletions

View File

@ -80,6 +80,9 @@ STATS_TYPE = "default" # default/accurate/team/disabled - what role information
LOVER_WINS_WITH_FOOL = False # if fool is lynched, does their lover win with them?
DEFAULT_SEEN_AS_VILL = True # non-wolves are seen as villager regardless of the default role
START_VOTES_SCALE = 0.3
START_VOTES_MAX = 4
# Debug mode settings, whether or not timers and stasis should apply during debug mode
DISABLE_DEBUG_MODE_TIMERS = True
DISABLE_DEBUG_MODE_TIME_LORD = False

View File

@ -439,6 +439,7 @@ def reset():
var.NO_LYNCH = set()
var.FGAMED = False
var.GAMEMODE_VOTES = {} #list of players who have used !game
var.START_VOTES = set() # list of players who have voted to !start
var.LOVERS = {} # need to be here for purposes of random
reset_settings()
@ -1164,7 +1165,7 @@ def join_player(cli, player, chan, who = None, forced = False):
var.JOINED_THIS_GAME_ACCS.add(acc)
var.CAN_START_TIME = datetime.now() + timedelta(seconds=var.MINIMUM_WAIT)
cli.msg(chan, ('\u0002{0}\u0002 has started a game of Werewolf. '+
'Type "{1}join" to join. Type "{1}start" to start the game. '+
'Type "{1}join" to join. Type "{1}start" to vote to start the game. '+
'Type "{1}wait" to increase the start wait time.').format(player, botconfig.CMD_CHAR))
# Set join timer
@ -2185,6 +2186,11 @@ def show_votes(cli, nick, chan, rest):
the_message = ", ".join(votelist)
if len(pl) >= var.MIN_PLAYERS:
the_message += "{0}Votes needed for a majority: {1}".format("; " if votelist else "", int(math.ceil(len(pl)/2)))
with var.WARNING_LOCK:
if var.START_VOTES:
the_message += "; Votes to start the game: {} ({})".format(len(var.START_VOTES), ', '.join(var.START_VOTES))
elif var.PHASE == "night":
cli.notice(nick, "Voting is only during the day.")
return
@ -2976,6 +2982,10 @@ def del_player(cli, nick, forced_death = False, devoice = True, end_game = True,
if var.PHASE == "join":
if nick in var.GAMEMODE_VOTES:
del var.GAMEMODE_VOTES[nick]
with var.WARNING_LOCK:
var.START_VOTES.discard(nick)
# Died during the joining process as a person
if var.AUTO_TOGGLE_MODES and nick in var.USERS and var.USERS[nick]["moded"]:
for newmode in var.USERS[nick]["moded"]:
@ -3497,6 +3507,10 @@ def rename_player(cli, prefix, nick):
if var.PHASE == "join":
if prefix in var.GAMEMODE_VOTES:
var.GAMEMODE_VOTES[nick] = var.GAMEMODE_VOTES.pop(prefix)
with var.WARNING_LOCK:
if prefix in var.START_VOTES:
var.START_VOTES.discard(prefix)
var.START_VOTES.add(nick)
# Check if player was disconnected
if var.PHASE in ("night", "day"):
@ -3570,6 +3584,11 @@ def leave(cli, what, nick, why=""):
if var.PHASE == "join":
lpl = len(var.list_players()) - 1
if lpl < var.MIN_PLAYERS:
with var.WARNING_LOCK:
var.START_VOTES = set()
if lpl == 0:
population = (" No more players remaining.")
else:
@ -4962,7 +4981,7 @@ def check_exchange(cli, actor, nick):
return True
return False
@cmd("retract", "r", pm=True, phases=("day", "night"))
@cmd("retract", "r", pm=True, phases=("day", "night", "join"))
def retract(cli, nick, chan, rest):
"""Takes back your vote during the day (for whom to lynch)."""
@ -4972,6 +4991,19 @@ def retract(cli, nick, chan, rest):
cli.notice(nick, "You're not currently playing.")
return
with var.GRAVEYARD_LOCK, var.WARNING_LOCK:
if var.PHASE == "join":
if not nick in var.START_VOTES:
cli.notice(nick, "You haven't voted to start.")
else:
var.START_VOTES.discard(nick)
cli.msg(chan, "\u0002{0}\u0002's vote to start was retracted.".format(nick))
if len(var.START_VOTES) < 1:
var.TIMERS['start_votes'][0].cancel()
del var.TIMERS['start_votes']
return
if chan == nick: # PM, use different code
role = var.get_role(nick)
if role not in var.WOLF_ROLES - {"wolf cub"} and role != "hunter" and nick not in var.VENGEFUL_GHOSTS.keys():
@ -6837,6 +6869,15 @@ def cgamemode(cli, arg):
cli.msg(chan, "Mode \u0002{0}\u0002 not found.".format(modeargs[0]))
def expire_start_votes(cli, chan):
# Should never happen as the timer is removed on game start, but just to be safe
if var.PHASE != 'join':
return
with var.WARNING_LOCK:
var.START_VOTES = set()
cli.msg(chan, "Not enough votes to start were accumulated in 1 minute, removing start votes.")
@cmd("start", phases=("join",))
def start_cmd(cli, nick, chan, rest):
"""Starts a game of Werewolf."""
@ -6892,6 +6933,34 @@ def start(cli, nick, chan, forced = False, restart = ""):
cli.msg(chan, "{0}: At most \u0002{1}\u0002 players may play.".format(nick, var.MAX_PLAYERS))
return
with var.WARNING_LOCK:
if not forced and nick in var.START_VOTES:
cli.notice(nick, "You have already voted to start the game.")
return
start_votes_required = min(math.ceil(len(villagers) * var.START_VOTES_SCALE), var.START_VOTES_MAX)
if not forced and len(var.START_VOTES) < start_votes_required:
# If there's only one more vote required, start the game immediately.
# Checked here to make sure that a player that has already voted can't
# vote again for the final start.
if len(var.START_VOTES) < start_votes_required - 1:
var.START_VOTES.add(nick)
msg = "{0} has voted to \u0002start\u0002 the game. \u0002{1}\u0002 more {2} required."
remaining_votes = start_votes_required - len(var.START_VOTES)
if remaining_votes == 1:
cli.msg(chan, msg.format(nick, remaining_votes, 'vote'))
else:
cli.msg(chan, msg.format(nick, remaining_votes, 'votes'))
# If this was the first vote
if len(var.START_VOTES) == 1:
t = threading.Timer(60, expire_start_votes, (cli, chan))
var.TIMERS["start_votes"] = (t, time.time(), 60)
t.daemon = True
t.start()
return
if not var.FGAMED:
votes = {} #key = gamemode, not hostmask
for gamemode in var.GAMEMODE_VOTES.values():
@ -7077,7 +7146,7 @@ def start(cli, nick, chan, forced = False, restart = ""):
var.SPECIAL_ROLES["goat herder"] = [ nick ]
with var.WARNING_LOCK: # cancel timers
for name in ("join", "join_pinger"):
for name in ("join", "join_pinger", "start_votes"):
if name in var.TIMERS:
var.TIMERS[name][0].cancel()
del var.TIMERS[name]