Fix race condition for day timing out immediately when a vote succeeds
This commit is contained in:
parent
bb5cb78c68
commit
3dc3e4d172
245
src/wolfgame.py
245
src/wolfgame.py
@ -1952,136 +1952,139 @@ def fday(cli, nick, chan, rest):
|
|||||||
|
|
||||||
# Specify force = "nick" to force nick to be lynched
|
# Specify force = "nick" to force nick to be lynched
|
||||||
def chk_decision(cli, force = ""):
|
def chk_decision(cli, force = ""):
|
||||||
chan = botconfig.CHANNEL
|
with var.GRAVEYARD_LOCK:
|
||||||
pl = var.list_players()
|
if var.PHASE != "day":
|
||||||
avail = len(pl) - len(var.WOUNDED) - len(var.ASLEEP)
|
return
|
||||||
votesneeded = avail // 2 + 1
|
chan = botconfig.CHANNEL
|
||||||
not_lynching = var.NO_LYNCH[:]
|
pl = var.list_players()
|
||||||
for p in var.PACIFISTS:
|
avail = len(pl) - len(var.WOUNDED) - len(var.ASLEEP)
|
||||||
if p in pl and p not in var.WOUNDED and p not in var.ASLEEP:
|
votesneeded = avail // 2 + 1
|
||||||
not_lynching.append(p)
|
not_lynching = var.NO_LYNCH[:]
|
||||||
|
for p in var.PACIFISTS:
|
||||||
|
if p in pl and p not in var.WOUNDED and p not in var.ASLEEP:
|
||||||
|
not_lynching.append(p)
|
||||||
|
|
||||||
# .remove() will only remove the first instance, which means this plays nicely with pacifism countering this
|
# .remove() will only remove the first instance, which means this plays nicely with pacifism countering this
|
||||||
for p in var.IMPATIENT:
|
for p in var.IMPATIENT:
|
||||||
if p in not_lynching:
|
if p in not_lynching:
|
||||||
not_lynching.remove(p)
|
not_lynching.remove(p)
|
||||||
|
|
||||||
# remove duplicates
|
# remove duplicates
|
||||||
not_lynching = set(not_lynching)
|
not_lynching = set(not_lynching)
|
||||||
|
|
||||||
# we only need 50%+ to not lynch, instead of an actual majority, because a tie would time out day anyway
|
# we only need 50%+ to not lynch, instead of an actual majority, because a tie would time out day anyway
|
||||||
# don't check for ABSTAIN_ENABLED here since we may have a case where the majority of people have pacifism totems or something
|
# don't check for ABSTAIN_ENABLED here since we may have a case where the majority of people have pacifism totems or something
|
||||||
if len(not_lynching) >= math.ceil(avail / 2):
|
if len(not_lynching) >= math.ceil(avail / 2):
|
||||||
for p in not_lynching:
|
for p in not_lynching:
|
||||||
if p not in var.NO_LYNCH:
|
if p not in var.NO_LYNCH:
|
||||||
cli.msg(botconfig.CHANNEL, "\u0002{0}\u0002 meekly votes not to lynch anyone today.".format(p))
|
cli.msg(botconfig.CHANNEL, "\u0002{0}\u0002 meekly votes not to lynch anyone today.".format(p))
|
||||||
cli.msg(botconfig.CHANNEL, "The villagers have agreed not to lynch anybody today.")
|
cli.msg(botconfig.CHANNEL, "The villagers have agreed not to lynch anybody today.")
|
||||||
var.ABSTAINED = True
|
var.ABSTAINED = True
|
||||||
transition_night(cli)
|
transition_night(cli)
|
||||||
return
|
return
|
||||||
aftermessage = None
|
aftermessage = None
|
||||||
votelist = copy.deepcopy(var.VOTES)
|
votelist = copy.deepcopy(var.VOTES)
|
||||||
for votee, voters in votelist.items():
|
for votee, voters in votelist.items():
|
||||||
impatient_voters = []
|
impatient_voters = []
|
||||||
numvotes = 0
|
numvotes = 0
|
||||||
random.shuffle(var.IMPATIENT)
|
random.shuffle(var.IMPATIENT)
|
||||||
for v in var.IMPATIENT:
|
for v in var.IMPATIENT:
|
||||||
if v in pl and v not in voters and v != votee and v not in var.WOUNDED and v not in var.ASLEEP:
|
if v in pl and v not in voters and v != votee and v not in var.WOUNDED and v not in var.ASLEEP:
|
||||||
# don't add them in if they have the same number or more of pacifism totems
|
# don't add them in if they have the same number or more of pacifism totems
|
||||||
# this matters for desperation totem on the votee
|
# this matters for desperation totem on the votee
|
||||||
|
imp_count = var.IMPATIENT.count(v)
|
||||||
|
pac_count = var.PACIFISTS.count(v)
|
||||||
|
if pac_count >= imp_count:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# yes, this means that one of the impatient people will get desperation totem'ed if they didn't
|
||||||
|
# already !vote earlier. sucks to suck. >:)
|
||||||
|
voters.append(v)
|
||||||
|
impatient_voters.append(v)
|
||||||
|
for v in voters[:]:
|
||||||
|
weight = 1
|
||||||
imp_count = var.IMPATIENT.count(v)
|
imp_count = var.IMPATIENT.count(v)
|
||||||
pac_count = var.PACIFISTS.count(v)
|
pac_count = var.PACIFISTS.count(v)
|
||||||
if pac_count >= imp_count:
|
if pac_count > imp_count:
|
||||||
continue
|
weight = 0 # more pacifists than impatience totems
|
||||||
|
elif imp_count == pac_count and v not in var.VOTES[votee]:
|
||||||
|
weight = 0 # impatience and pacifist cancel each other out, so don't count impatience
|
||||||
|
if v in var.ROLES["bureaucrat"] or v in var.INFLUENTIAL: # the two do not stack
|
||||||
|
weight *= 2
|
||||||
|
numvotes += weight
|
||||||
|
|
||||||
# yes, this means that one of the impatient people will get desperation totem'ed if they didn't
|
if numvotes >= votesneeded or votee == force:
|
||||||
# already !vote earlier. sucks to suck. >:)
|
for p in impatient_voters:
|
||||||
voters.append(v)
|
cli.msg(botconfig.CHANNEL, "\u0002{0}\u0002 impatiently votes for \u0002{1}\u0002.".format(p, votee))
|
||||||
impatient_voters.append(v)
|
|
||||||
for v in voters[:]:
|
|
||||||
weight = 1
|
|
||||||
imp_count = var.IMPATIENT.count(v)
|
|
||||||
pac_count = var.PACIFISTS.count(v)
|
|
||||||
if pac_count > imp_count:
|
|
||||||
weight = 0 # more pacifists than impatience totems
|
|
||||||
elif imp_count == pac_count and v not in var.VOTES[votee]:
|
|
||||||
weight = 0 # impatience and pacifist cancel each other out, so don't count impatience
|
|
||||||
if v in var.ROLES["bureaucrat"] or v in var.INFLUENTIAL: # the two do not stack
|
|
||||||
weight *= 2
|
|
||||||
numvotes += weight
|
|
||||||
|
|
||||||
if numvotes >= votesneeded or votee == force:
|
# roles that prevent any lynch from happening
|
||||||
for p in impatient_voters:
|
if votee in var.ROLES["mayor"] and votee not in var.REVEALED_MAYORS:
|
||||||
cli.msg(botconfig.CHANNEL, "\u0002{0}\u0002 impatiently votes for \u0002{1}\u0002.".format(p, votee))
|
lmsg = ("While being dragged to the gallows, \u0002{0}\u0002 reveals that they " +
|
||||||
|
"are the \u0002mayor\u0002. The village agrees to let them live for now.").format(votee)
|
||||||
|
var.REVEALED_MAYORS.append(votee)
|
||||||
|
votee = None
|
||||||
|
elif votee in var.REVEALED:
|
||||||
|
role = var.get_role(votee)
|
||||||
|
if role == "amnesiac":
|
||||||
|
var.ROLES["amnesiac"].remove(votee)
|
||||||
|
role = var.AMNESIAC_ROLES[votee]
|
||||||
|
var.ROLES[role].append(votee)
|
||||||
|
var.AMNESIACS.append(votee)
|
||||||
|
var.FINAL_ROLES[votee] = role
|
||||||
|
pm(cli, votee, "Your totem clears your amnesia and you now fully remember who you are!")
|
||||||
|
# If wolfteam, don't bother giving list of wolves since night is about to start anyway
|
||||||
|
# Existing wolves also know that someone just joined their team because revealing totem says what they are
|
||||||
|
# If turncoat, set their initial starting side to "none" just in case game ends before they can set it themselves
|
||||||
|
if role == "turncoat":
|
||||||
|
var.TURNCOATS[votee] = ("none", -1)
|
||||||
|
|
||||||
# roles that prevent any lynch from happening
|
an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
|
||||||
if votee in var.ROLES["mayor"] and votee not in var.REVEALED_MAYORS:
|
lmsg = ("Before the rope is pulled, \u0002{0}\u0002's totem emits a brilliant flash of light. " +
|
||||||
lmsg = ("While being dragged to the gallows, \u0002{0}\u0002 reveals that they " +
|
"When the villagers are able to see again, they discover that {0} has escaped! " +
|
||||||
"are the \u0002mayor\u0002. The village agrees to let them live for now.").format(votee)
|
"The left-behind totem seems to have taken on the shape of a{1} \u0002{2}\u0002.").format(votee, an, role)
|
||||||
var.REVEALED_MAYORS.append(votee)
|
votee = None
|
||||||
votee = None
|
|
||||||
elif votee in var.REVEALED:
|
|
||||||
role = var.get_role(votee)
|
|
||||||
if role == "amnesiac":
|
|
||||||
var.ROLES["amnesiac"].remove(votee)
|
|
||||||
role = var.AMNESIAC_ROLES[votee]
|
|
||||||
var.ROLES[role].append(votee)
|
|
||||||
var.AMNESIACS.append(votee)
|
|
||||||
var.FINAL_ROLES[votee] = role
|
|
||||||
pm(cli, votee, "Your totem clears your amnesia and you now fully remember who you are!")
|
|
||||||
# If wolfteam, don't bother giving list of wolves since night is about to start anyway
|
|
||||||
# Existing wolves also know that someone just joined their team because revealing totem says what they are
|
|
||||||
# If turncoat, set their initial starting side to "none" just in case game ends before they can set it themselves
|
|
||||||
if role == "turncoat":
|
|
||||||
var.TURNCOATS[votee] = ("none", -1)
|
|
||||||
|
|
||||||
an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
|
|
||||||
lmsg = ("Before the rope is pulled, \u0002{0}\u0002's totem emits a brilliant flash of light. " +
|
|
||||||
"When the villagers are able to see again, they discover that {0} has escaped! " +
|
|
||||||
"The left-behind totem seems to have taken on the shape of a{1} \u0002{2}\u0002.").format(votee, an, role)
|
|
||||||
votee = None
|
|
||||||
else:
|
|
||||||
# roles that end the game upon being lynched
|
|
||||||
if votee in var.ROLES["fool"]:
|
|
||||||
# ends game immediately, with fool as only winner
|
|
||||||
lmsg = random.choice(var.LYNCH_MESSAGES).format(votee, "", var.get_reveal_role(votee))
|
|
||||||
cli.msg(botconfig.CHANNEL, lmsg)
|
|
||||||
if chk_win(cli, winner="@" + votee):
|
|
||||||
return
|
|
||||||
# roles that eliminate other players upon being lynched
|
|
||||||
# note that lovers, assassin, clone, and vengeful ghost are handled in del_player() since they trigger on more than just lynch
|
|
||||||
if votee in var.DESPERATE:
|
|
||||||
# Also kill the very last person to vote them, unless they voted themselves last in which case nobody else dies
|
|
||||||
target = voters[-1]
|
|
||||||
if target != votee:
|
|
||||||
if var.ROLE_REVEAL in ("on", "team"):
|
|
||||||
r1 = var.get_reveal_role(target)
|
|
||||||
an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else ""
|
|
||||||
tmsg = ("As the noose is being fitted, \u0002{0}\u0002's totem emits a brilliant flash of light. " +
|
|
||||||
"When the villagers are able to see again, they discover that \u0002{1}\u0002, " +
|
|
||||||
"a{2} \u0002{3}\u0002, has fallen over dead.").format(votee, target, an1, r1)
|
|
||||||
else:
|
|
||||||
tmsg = ("As the noose is being fitted, \u0002{0}\u0002's totem emits a brilliant flash of light. " +
|
|
||||||
"When the villagers are able to see again, they discover that \u0002{1}\u0002 " +
|
|
||||||
"has fallen over dead.").format(votee, target)
|
|
||||||
cli.msg(botconfig.CHANNEL, tmsg)
|
|
||||||
del_player(cli, target, True, end_game = False, killer_role = "shaman") # do not end game just yet, we have more killin's to do!
|
|
||||||
# Other
|
|
||||||
if votee in var.ROLES["jester"]:
|
|
||||||
var.JESTERS.append(votee)
|
|
||||||
|
|
||||||
if var.ROLE_REVEAL in ("on", "team"):
|
|
||||||
rrole = var.get_reveal_role(votee)
|
|
||||||
an = "n" if rrole.startswith(("a", "e", "i", "o", "u")) else ""
|
|
||||||
lmsg = random.choice(var.LYNCH_MESSAGES).format(votee, an, rrole)
|
|
||||||
else:
|
else:
|
||||||
lmsg = random.choice(var.LYNCH_MESSAGES_NO_REVEAL).format(votee)
|
# roles that end the game upon being lynched
|
||||||
cli.msg(botconfig.CHANNEL, lmsg)
|
if votee in var.ROLES["fool"]:
|
||||||
if aftermessage != None:
|
# ends game immediately, with fool as only winner
|
||||||
cli.msg(botconfig.CHANNEL, aftermessage)
|
lmsg = random.choice(var.LYNCH_MESSAGES).format(votee, "", var.get_reveal_role(votee))
|
||||||
if del_player(cli, votee, True, killer_role = "villager"):
|
cli.msg(botconfig.CHANNEL, lmsg)
|
||||||
transition_night(cli)
|
if chk_win(cli, winner="@" + votee):
|
||||||
break
|
return
|
||||||
|
# roles that eliminate other players upon being lynched
|
||||||
|
# note that lovers, assassin, clone, and vengeful ghost are handled in del_player() since they trigger on more than just lynch
|
||||||
|
if votee in var.DESPERATE:
|
||||||
|
# Also kill the very last person to vote them, unless they voted themselves last in which case nobody else dies
|
||||||
|
target = voters[-1]
|
||||||
|
if target != votee:
|
||||||
|
if var.ROLE_REVEAL in ("on", "team"):
|
||||||
|
r1 = var.get_reveal_role(target)
|
||||||
|
an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else ""
|
||||||
|
tmsg = ("As the noose is being fitted, \u0002{0}\u0002's totem emits a brilliant flash of light. " +
|
||||||
|
"When the villagers are able to see again, they discover that \u0002{1}\u0002, " +
|
||||||
|
"a{2} \u0002{3}\u0002, has fallen over dead.").format(votee, target, an1, r1)
|
||||||
|
else:
|
||||||
|
tmsg = ("As the noose is being fitted, \u0002{0}\u0002's totem emits a brilliant flash of light. " +
|
||||||
|
"When the villagers are able to see again, they discover that \u0002{1}\u0002 " +
|
||||||
|
"has fallen over dead.").format(votee, target)
|
||||||
|
cli.msg(botconfig.CHANNEL, tmsg)
|
||||||
|
del_player(cli, target, True, end_game = False, killer_role = "shaman") # do not end game just yet, we have more killin's to do!
|
||||||
|
# Other
|
||||||
|
if votee in var.ROLES["jester"]:
|
||||||
|
var.JESTERS.append(votee)
|
||||||
|
|
||||||
|
if var.ROLE_REVEAL in ("on", "team"):
|
||||||
|
rrole = var.get_reveal_role(votee)
|
||||||
|
an = "n" if rrole.startswith(("a", "e", "i", "o", "u")) else ""
|
||||||
|
lmsg = random.choice(var.LYNCH_MESSAGES).format(votee, an, rrole)
|
||||||
|
else:
|
||||||
|
lmsg = random.choice(var.LYNCH_MESSAGES_NO_REVEAL).format(votee)
|
||||||
|
cli.msg(botconfig.CHANNEL, lmsg)
|
||||||
|
if aftermessage != None:
|
||||||
|
cli.msg(botconfig.CHANNEL, aftermessage)
|
||||||
|
if del_player(cli, votee, True, killer_role = "villager"):
|
||||||
|
transition_night(cli)
|
||||||
|
break
|
||||||
|
|
||||||
@cmd("votes", pm=True, phases=("join", "day", "night"))
|
@cmd("votes", pm=True, phases=("join", "day", "night"))
|
||||||
def show_votes(cli, nick, chan, rest):
|
def show_votes(cli, nick, chan, rest):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user