Add alternate win condition if only lovers are alive

The message could use a better phrasing, but anyway this works.
This commit is contained in:
Vgr E. Barry 2015-10-19 14:51:03 -04:00
parent 26e7acc8f8
commit 04180bc036
2 changed files with 65 additions and 6 deletions

View File

@ -16,6 +16,39 @@ def game_mode(name, minp, maxp, likelihood = 0):
reset_roles = lambda i: OrderedDict([(role, (0,) * len(i)) for role in var.ROLE_GUIDE])
def get_lovers():
lovers = []
pl = var.list_players()
for lover in var.LOVERS:
done = None
for i, lset in enumerate(lovers):
if lover in pl and lover in lset:
if done is not None: # plot twist! two clusters turn out to be linked!
done.update(lset)
for lvr in var.LOVERS[lover]:
if lvr in pl:
done.add(lvr)
lset.clear()
continue
for lvr in var.LOVERS[lover]:
if lvr in pl:
lset.add(lvr)
done = lset
if done is None and lover in pl:
lovers.append(set())
lovers[-1].add(lover)
for lvr in var.LOVERS[lover]:
if lvr in pl:
lovers[-1].add(lvr)
while set() in lovers:
lovers.remove(set())
return lovers
class GameMode:
def __init__(self, arg=""):
if not arg:
@ -64,6 +97,23 @@ class GameMode:
def teardown(self):
pass
# Here so any game mode can use it
def lovers_chk_win(self, evt, var, lpl, lwolves, lrealwolves):
winner = evt.data["winner"]
if winner is not None and winner.startswith("@"):
return # fool won, lovers can't win even if they would
all_lovers = get_lovers()
if len(all_lovers) != 1:
return # we need exactly one cluster alive for this to trigger
lovers = all_lovers[0]
if len(lovers) == lpl:
evt.data["winner"] = "lovers"
evt.data["message"] = "Game over! All of the remaining villagers are in love with each other! All of them win."
evt.data["players"] = ["{0} ({1})".format(x, var.get_role(x)) for x in lovers]
evt.data["winners"] = list(lovers)
@game_mode("roles", minp = 4, maxp = 35)
class ChangedRolesMode(GameMode):
"""Example: !fgame roles=wolf:1,seer:0,guardian angel:1"""
@ -398,6 +448,12 @@ class MatchmakerMode(GameMode):
"mad scientist" : [i >= 18 for i in self.ROLE_INDEX],
})
def startup(self):
events.add_listener("chk_win", self.lovers_chk_win, 1)
def teardown(self):
events.remove_listener("chk_win", self.lovers_chk_win, 1)
@game_mode("random", minp = 8, maxp = 24, likelihood = 0)
class RandomMode(GameMode):
"""Completely random and hidden roles."""
@ -430,9 +486,11 @@ class RandomMode(GameMode):
def startup(self):
events.add_listener("role_attribution", self.role_attribution, 1)
events.add_listener("chk_win", self.lovers_chk_win, 1)
def teardown(self):
events.remove_listener("role_attribution", self.role_attribution, 1)
events.remove_listener("chk_win", self.lovers_chk_win, 1)
def role_attribution(self, evt, cli, chk_win_conditions, var, villagers):
lpl = len(villagers) - 1

View File

@ -2275,7 +2275,7 @@ def chk_traitor(cli):
"frightened as they hear a loud howl. The wolves are "+
"not gone!\u0002")
def stop_game(cli, winner = "", abort = False):
def stop_game(cli, winner = "", abort = False, winners = None):
chan = botconfig.CHANNEL
if abort:
cli.msg(chan, "The role attribution failed 3 times. Game was canceled.")
@ -2369,7 +2369,8 @@ def stop_game(cli, winner = "", abort = False):
# Only update if someone actually won, "" indicates everyone died or abnormal game stop
if winner != "":
plrl = {}
winners = []
if winners is None:
winners = []
for role,ppl in var.ORIGINAL_ROLES.items():
if role in var.TEMPLATE_RESTRICTIONS.keys():
continue
@ -2426,7 +2427,7 @@ def stop_game(cli, winner = "", abort = False):
iwon = False
elif rol == "fool" and "@" + splr == winner:
iwon = True
elif splr in var.LOVERS and splr in survived and len([x for x in var.LOVERS[splr] if x in survived]) > 0:
elif winner != "lovers" and splr in var.LOVERS and splr in survived and len([x for x in var.LOVERS[splr] if x in survived]) > 0:
for lvr in var.LOVERS[splr]:
if lvr not in survived:
# cannot win with dead lover (if splr in survived and lvr is not, that means lvr idled out)
@ -2622,7 +2623,7 @@ def chk_win_conditions(lpl, lwolves, lcubs, lrealwolves, lmonsters, ltraitors, l
ltraitors = len(var.ROLES.get("traitor", ()))
return chk_win_conditions(lpl, lwolves, lcubs, lrealwolves, lmonsters, ltraitors, lpipers, cli, end_game)
event = Event("chk_win", {"winner": winner, "message": message})
event = Event("chk_win", {"winner": winner, "message": message, "players": [], "winners": None})
event.dispatch(var, lpl, lwolves, lrealwolves)
winner = event.data["winner"]
message = event.data["message"]
@ -2631,7 +2632,7 @@ def chk_win_conditions(lpl, lwolves, lcubs, lrealwolves, lmonsters, ltraitors, l
return False
if end_game:
players = []
players = event.data["players"]
if winner == "monsters":
for plr in var.ROLES["monster"]:
players.append("{0} ({1})".format(plr, var.get_role(plr)))
@ -2648,7 +2649,7 @@ def chk_win_conditions(lpl, lwolves, lcubs, lrealwolves, lmonsters, ltraitors, l
debuglog("WIN:", winner)
debuglog("PLAYERS:", ", ".join(players))
cli.msg(chan, message)
stop_game(cli, winner)
stop_game(cli, winner, winners=event.data["winners"])
return True
def del_player(cli, nick, forced_death = False, devoice = True, end_game = True, death_triggers = True, killer_role = "", deadlist = [], original = "", cmode = [], ismain = True):