Split and convert matchmaker
This commit is contained in:
parent
84d25330b2
commit
35bcda40dc
@ -790,7 +790,7 @@
|
|||||||
"assassin_role_info": "You are an \u0002assassin\u0002{0}.",
|
"assassin_role_info": "You are an \u0002assassin\u0002{0}.",
|
||||||
"assassin_targeting": " and targeting {0}",
|
"assassin_targeting": " and targeting {0}",
|
||||||
"bitten_info": "You were bitten by an alpha wolf and have \u0002{0} night{1}\u0002 until your transformation.",
|
"bitten_info": "You were bitten by an alpha wolf and have \u0002{0} night{1}\u0002 until your transformation.",
|
||||||
"matched_info": "You are \u0002in love\u0002 with ",
|
"matched_info": "You are \u0002in love\u0002 with",
|
||||||
"no_command_in_channel": "You cannot use this command in channel right now",
|
"no_command_in_channel": "You cannot use this command in channel right now",
|
||||||
"no_such_role": "No such role: {0}",
|
"no_such_role": "No such role: {0}",
|
||||||
"ambiguous_role": "Ambiguous role. Possible matches are: {0}.",
|
"ambiguous_role": "Ambiguous role. Possible matches are: {0}.",
|
||||||
|
@ -24,39 +24,6 @@ def game_mode(name, minp, maxp, likelihood = 0):
|
|||||||
|
|
||||||
reset_roles = lambda i: OrderedDict([(role, (0,) * len(i)) for role in var.ROLE_GUIDE])
|
reset_roles = lambda i: OrderedDict([(role, (0,) * len(i)) for role in var.ROLE_GUIDE])
|
||||||
|
|
||||||
def get_lovers():
|
|
||||||
lovers = []
|
|
||||||
pl = 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:
|
class GameMode:
|
||||||
def __init__(self, arg=""):
|
def __init__(self, arg=""):
|
||||||
if not arg:
|
if not arg:
|
||||||
@ -111,6 +78,7 @@ class GameMode:
|
|||||||
winner = evt.data["winner"]
|
winner = evt.data["winner"]
|
||||||
if winner is not None and winner.startswith("@"):
|
if winner is not None and winner.startswith("@"):
|
||||||
return # fool won, lovers can't win even if they would
|
return # fool won, lovers can't win even if they would
|
||||||
|
from src.roles.matchmaker import get_lovers
|
||||||
all_lovers = get_lovers()
|
all_lovers = get_lovers()
|
||||||
if len(all_lovers) != 1:
|
if len(all_lovers) != 1:
|
||||||
return # we need exactly one cluster alive for this to trigger
|
return # we need exactly one cluster alive for this to trigger
|
||||||
|
@ -16,7 +16,7 @@ def setup_variables(rolename, *, send_role, types):
|
|||||||
|
|
||||||
@event_listener("transition_night_end")
|
@event_listener("transition_night_end")
|
||||||
def on_transition_night_end(evt, var):
|
def on_transition_night_end(evt, var):
|
||||||
villagers = set(get_players(("priest", "prophet", "matchmaker", "doctor")))
|
villagers = set(get_players(("priest", "prophet", "doctor")))
|
||||||
win_stealers = set(get_players(("fool", "monster", "demoniac")))
|
win_stealers = set(get_players(("fool", "monster", "demoniac")))
|
||||||
neutrals = set(get_players(("turncoat", "clone", "jester")))
|
neutrals = set(get_players(("turncoat", "clone", "jester")))
|
||||||
|
|
||||||
|
@ -77,12 +77,10 @@ def investigate(var, wrapper, message):
|
|||||||
else:
|
else:
|
||||||
t2role = "blue"
|
t2role = "blue"
|
||||||
|
|
||||||
same = t1role == t2role
|
evt = Event("get_team_affiliation", {"same": (t1role == t2role)})
|
||||||
# FIXME: split into matchmaker once that is split and make this an event
|
evt.dispatch(evt, target1, target2)
|
||||||
if target2.nick in var.LOVERS.get(target1.nick, set()):
|
|
||||||
same = True
|
|
||||||
|
|
||||||
if same:
|
if evt.data["same"]:
|
||||||
wrapper.pm(messages["investigator_results_same"].format(target1, target2))
|
wrapper.pm(messages["investigator_results_same"].format(target1, target2))
|
||||||
else:
|
else:
|
||||||
wrapper.pm(messages["investigator_results_different"].format(target1, target2))
|
wrapper.pm(messages["investigator_results_different"].format(target1, target2))
|
||||||
@ -90,7 +88,7 @@ def investigate(var, wrapper, message):
|
|||||||
INVESTIGATED.add(wrapper.source)
|
INVESTIGATED.add(wrapper.source)
|
||||||
debuglog("{0} (investigator) ID: {1} ({2}) and {3} ({4}) as {5}".format(
|
debuglog("{0} (investigator) ID: {1} ({2}) and {3} ({4}) as {5}".format(
|
||||||
wrapper.source, target1, get_main_role(target1), target2, get_main_role(target2),
|
wrapper.source, target1, get_main_role(target1), target2, get_main_role(target2),
|
||||||
"same" if same else "different"))
|
"same" if evt.data["same"] else "different"))
|
||||||
|
|
||||||
@event_listener("del_player")
|
@event_listener("del_player")
|
||||||
def on_del_player(evt, var, user, mainrole, allroles, death_triggers):
|
def on_del_player(evt, var, user, mainrole, allroles, death_triggers):
|
||||||
|
257
src/roles/matchmaker.py
Normal file
257
src/roles/matchmaker.py
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
import re
|
||||||
|
import random
|
||||||
|
import itertools
|
||||||
|
import math
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
import botconfig
|
||||||
|
from src.utilities import *
|
||||||
|
from src import channels, users, debuglog, errlog, plog
|
||||||
|
from src.functions import get_players, get_all_players, get_main_role, get_reveal_role, get_target
|
||||||
|
from src.decorators import command, event_listener
|
||||||
|
from src.containers import UserList, UserSet, UserDict, DefaultUserDict
|
||||||
|
from src.messages import messages
|
||||||
|
from src.events import Event
|
||||||
|
|
||||||
|
MATCHMAKERS = UserSet() # type: Set[users.User]
|
||||||
|
LOVERS = UserDict() # type: Dict[users.User, Set[users.User]]
|
||||||
|
|
||||||
|
def _set_lovers(target1, target2):
|
||||||
|
if target1 in LOVERS:
|
||||||
|
LOVERS[target1].add(target2)
|
||||||
|
else:
|
||||||
|
LOVERS[target1] = UserSet({target2})
|
||||||
|
|
||||||
|
if target2 in LOVERS:
|
||||||
|
LOVERS[target2].add(target1)
|
||||||
|
else:
|
||||||
|
LOVERS[target2] = UserSet({target1})
|
||||||
|
|
||||||
|
t1_msg = "matchmaker_target_notify"
|
||||||
|
if target1.prefers_simple():
|
||||||
|
t1_msg += "_simple"
|
||||||
|
|
||||||
|
t2_msg = "matchmaker_target_notify"
|
||||||
|
if target2.prefers_simple():
|
||||||
|
t2_msg += "_simple"
|
||||||
|
|
||||||
|
target1.send(messages[t1_msg].format(target2))
|
||||||
|
target2.send(messages[t2_msg].format(target1))
|
||||||
|
|
||||||
|
def get_lovers():
|
||||||
|
lovers = []
|
||||||
|
pl = get_players()
|
||||||
|
for lover in 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 LOVERS[lover]:
|
||||||
|
if lvr in pl:
|
||||||
|
done.add(lvr)
|
||||||
|
|
||||||
|
lset.clear()
|
||||||
|
continue
|
||||||
|
|
||||||
|
for lvr in 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 LOVERS[lover]:
|
||||||
|
if lvr in pl:
|
||||||
|
lovers[-1].add(lvr)
|
||||||
|
|
||||||
|
while set() in lovers:
|
||||||
|
lovers.remove(set())
|
||||||
|
|
||||||
|
return lovers
|
||||||
|
|
||||||
|
@command("match", "choose", chan=False, pm=True, playing=True, phases=("night",), roles=("matchmaker",))
|
||||||
|
def choose(var, wrapper, message):
|
||||||
|
"""Select two players to fall in love. You may select yourself as one of the lovers."""
|
||||||
|
if not var.FIRST_NIGHT:
|
||||||
|
return
|
||||||
|
if wrapper.source in MATCHMAKERS:
|
||||||
|
wrapper.send(messages["already_matched"])
|
||||||
|
return
|
||||||
|
|
||||||
|
pieces = re.split(" +", message)
|
||||||
|
victim1 = pieces[0]
|
||||||
|
if len(pieces) > 1:
|
||||||
|
if len(pieces) > 2 and pieces[1].lower() == "and":
|
||||||
|
victim2 = pieces[2]
|
||||||
|
else:
|
||||||
|
victim2 = pieces[1]
|
||||||
|
else:
|
||||||
|
victim2 = None
|
||||||
|
|
||||||
|
target1 = get_target(var, wrapper, victim1, allow_self=True)
|
||||||
|
target2 = get_target(var, wrapper, victim2, allow_self=True)
|
||||||
|
if not target1 or not target2:
|
||||||
|
return
|
||||||
|
|
||||||
|
if target1 is target2:
|
||||||
|
wrapper.send(messages["match_different_people"])
|
||||||
|
return
|
||||||
|
|
||||||
|
MATCHMAKERS.add(wrapper.source)
|
||||||
|
|
||||||
|
_set_lovers(target1, target2)
|
||||||
|
|
||||||
|
wrapper.send(messages["matchmaker_success"].format(target1, target2))
|
||||||
|
|
||||||
|
debuglog("{0} (matchmaker) MATCH: {1} ({2}) WITH {3} ({4})".format(wrapper.source, target1, get_main_role(target1), target2, get_main_role(target2)))
|
||||||
|
|
||||||
|
@event_listener("transition_day_begin")
|
||||||
|
def on_transition_day_begin(evt, var):
|
||||||
|
pl = get_players()
|
||||||
|
for mm in get_all_players(("matchmaker",)):
|
||||||
|
if mm not in MATCHMAKERS:
|
||||||
|
lovers = random.sample(pl, 2)
|
||||||
|
MATCHMAKERS.add(mm)
|
||||||
|
_set_lovers(*lovers)
|
||||||
|
mm.send(messages["random_matchmaker"])
|
||||||
|
|
||||||
|
@event_listener("transition_night_end")
|
||||||
|
def on_transition_night_end(evt, var):
|
||||||
|
if var.FIRST_NIGHT or var.ALWAYS_PM_ROLE:
|
||||||
|
ps = get_players()
|
||||||
|
for mm in get_all_players(("matchmaker",)):
|
||||||
|
pl = ps[:]
|
||||||
|
random.shuffle(pl)
|
||||||
|
if mm.prefers_simple():
|
||||||
|
mm.send(messages["matchmaker_simple"])
|
||||||
|
else:
|
||||||
|
mm.send(messages["matchmaker_notify"])
|
||||||
|
mm.send("Players: " + ", ".join(p.nick for p in pl))
|
||||||
|
|
||||||
|
@event_listener("del_player")
|
||||||
|
def on_del_player(evt, var, player, mainrole, allroles, death_triggers):
|
||||||
|
if death_triggers and player in LOVERS:
|
||||||
|
lovers = set(LOVERS[player])
|
||||||
|
for lover in lovers:
|
||||||
|
if lover not in evt.data["pl"]:
|
||||||
|
continue # already died somehow
|
||||||
|
if var.ROLE_REVEAL in ("on", "team"):
|
||||||
|
role = get_reveal_role(lover)
|
||||||
|
an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
|
||||||
|
message = messages["lover_suicide"].format(lover, an, role)
|
||||||
|
else:
|
||||||
|
message = messages["lover_suicide_no_reveal"].format(lover)
|
||||||
|
channels.Main.send(message)
|
||||||
|
debuglog("{0} ({1}) LOVE SUICIDE: {2} ({3})".format(lover, get_main_role(lover), player, mainrole))
|
||||||
|
evt.params.del_player(lover, end_game=False, killer_role=evt.params.killer_role, deadlist=evt.params.deadlist, original=evt.params.original, ismain=False)
|
||||||
|
evt.data["pl"] = evt.params.refresh_pl(evt.data["pl"])
|
||||||
|
|
||||||
|
@event_listener("game_end_messages")
|
||||||
|
def on_game_end_messages(evt, var):
|
||||||
|
done = {}
|
||||||
|
lovers = []
|
||||||
|
for lover1, lset in LOVERS.items():
|
||||||
|
for lover2 in lset:
|
||||||
|
# check if already said the pairing
|
||||||
|
if (lover1 in done and lover2 in done[lover1]) or (lover2 in done and lover1 in done[lover2]):
|
||||||
|
continue
|
||||||
|
lovers.append("\u0002{0}\u0002/\u0002{1}\u0002".format(lover1, lover2))
|
||||||
|
if lover1 in done:
|
||||||
|
done[lover1].append(lover2)
|
||||||
|
else:
|
||||||
|
done[lover1] = [lover2]
|
||||||
|
|
||||||
|
if len(lovers) == 1 or len(lovers) == 2:
|
||||||
|
evt.data["messages"].append("The lovers were {0}.".format(" and ".join(lovers)))
|
||||||
|
elif len(lovers) > 2:
|
||||||
|
evt.data["messages"].append("The lovers were {0}, and {1}".format(", ".join(lovers[0:-1]), lovers[-1]))
|
||||||
|
|
||||||
|
@event_listener("player_win")
|
||||||
|
def on_player_win(evt, var, player, role, winner, survived):
|
||||||
|
if player in LOVERS:
|
||||||
|
evt.data["special"].append("lover")
|
||||||
|
if winner == "lovers" and player in LOVERS:
|
||||||
|
evt.data["iwon"] = True
|
||||||
|
|
||||||
|
elif player in LOVERS and survived and LOVERS[player].intersection(get_players()):
|
||||||
|
for lvr in LOVERS[player]:
|
||||||
|
if lvr not in get_players():
|
||||||
|
# cannot win with dead lover (lover idled out)
|
||||||
|
continue
|
||||||
|
|
||||||
|
lover_role = get_main_role(lvr)
|
||||||
|
|
||||||
|
if not winner.startswith("@") and singular(winner) not in var.WIN_STEALER_ROLES:
|
||||||
|
evt.data["iwon"] = True
|
||||||
|
break
|
||||||
|
elif winner.startswith("@") and winner == "@" + lvr.nick and var.LOVER_WINS_WITH_FOOL:
|
||||||
|
evt.data["iwon"] = True
|
||||||
|
break
|
||||||
|
elif singular(winner) in var.WIN_STEALER_ROLES and lover_role == singular(winner):
|
||||||
|
evt.data["iwon"] = True
|
||||||
|
break
|
||||||
|
|
||||||
|
@event_listener("chk_nightdone")
|
||||||
|
def on_chk_nightdone(evt, var):
|
||||||
|
evt.data["actedcount"] += len(MATCHMAKERS)
|
||||||
|
evt.data["nightroles"].extend(get_all_players(("matchmaker",)))
|
||||||
|
|
||||||
|
@event_listener("get_special")
|
||||||
|
def on_get_special(evt, var):
|
||||||
|
evt.data["villagers"].update(get_all_players(("matchmaker",)))
|
||||||
|
|
||||||
|
@event_listener("get_team_affiliation")
|
||||||
|
def on_get_team_affiliation(evt, var, target1, target2):
|
||||||
|
if target1 in LOVERS and target2 in LOVERS:
|
||||||
|
for lset in get_lovers():
|
||||||
|
if target1 in lset and target2 in lset:
|
||||||
|
evt.data["same"] = True
|
||||||
|
break
|
||||||
|
|
||||||
|
@event_listener("myrole")
|
||||||
|
def on_myrole(evt, var, user):
|
||||||
|
# Remind lovers of each other
|
||||||
|
if user in get_players() and user in LOVERS:
|
||||||
|
msg = [messages["matched_info"]]
|
||||||
|
lovers = sorted(LOVERS[user])
|
||||||
|
if len(lovers) == 1:
|
||||||
|
message.append(lovers[0])
|
||||||
|
elif len(lovers) == 2:
|
||||||
|
message.extend((lovers[0], "and", lovers[1]))
|
||||||
|
else:
|
||||||
|
message.extend((", ".join(lovers[:-1]) + ",", "and", lovers[-1]))
|
||||||
|
evt.data["messages"].append(" ".join(msg) + ".")
|
||||||
|
|
||||||
|
@event_listener("revealroles")
|
||||||
|
def on_revealroles(evt, var, wrapper):
|
||||||
|
# print out lovers
|
||||||
|
pl = get_players()
|
||||||
|
done = {}
|
||||||
|
lovers = []
|
||||||
|
for lover1, lset in LOVERS.items():
|
||||||
|
if lover1 not in pl:
|
||||||
|
continue
|
||||||
|
for lover2 in lset:
|
||||||
|
# check if already said the pairing
|
||||||
|
if (lover1 in done and lover2 in done[lover1]) or (lover2 in done and lover1 in done[lover2]):
|
||||||
|
continue
|
||||||
|
if lover2 not in pl:
|
||||||
|
continue
|
||||||
|
lovers.append("{0}/{1}".format(lover1, lover2))
|
||||||
|
if lover1 in done:
|
||||||
|
done[lover1].append(lover2)
|
||||||
|
else:
|
||||||
|
done[lover1] = [lover2]
|
||||||
|
if len(lovers) == 1 or len(lovers) == 2:
|
||||||
|
evt.data["output"].append("\u0002lovers\u0002: {0}".format(" and ".join(lovers)))
|
||||||
|
elif len(lovers) > 2:
|
||||||
|
evt.data["output"].append("\u0002lovers\u0002: {0}, and {1}".format(", ".join(lovers[0:-1]), lovers[-1]))
|
||||||
|
|
||||||
|
@event_listener("reset")
|
||||||
|
def on_reset(evt, var):
|
||||||
|
MATCHMAKERS.clear()
|
||||||
|
LOVERS.clear()
|
||||||
|
|
||||||
|
# vim: set sw=4 expandtab:
|
@ -128,8 +128,6 @@ def on_player_win(evt, var, player, mainrole, winner, survived):
|
|||||||
|
|
||||||
if mainrole == "piper":
|
if mainrole == "piper":
|
||||||
evt.data["won"] = True
|
evt.data["won"] = True
|
||||||
# TODO: add code here (or maybe a sep event?) to let lovers win alongside piper
|
|
||||||
# Right now that's still in wolfgame.py, but should be moved here once mm is split
|
|
||||||
|
|
||||||
@event_listener("del_player")
|
@event_listener("del_player")
|
||||||
def on_del_player(evt, var, player, mainrole, allroles, death_triggers):
|
def on_del_player(evt, var, player, mainrole, allroles, death_triggers):
|
||||||
|
202
src/wolfgame.py
202
src/wolfgame.py
@ -322,7 +322,6 @@ def reset():
|
|||||||
var.FGAMED = False
|
var.FGAMED = False
|
||||||
var.GAMEMODE_VOTES = {} #list of players who have used !game
|
var.GAMEMODE_VOTES = {} #list of players who have used !game
|
||||||
var.START_VOTES.clear() # list of players who have voted to !start
|
var.START_VOTES.clear() # list of players who have voted to !start
|
||||||
var.LOVERS = {} # need to be here for purposes of random
|
|
||||||
var.ROLE_STATS = frozenset() # type: FrozenSet[FrozenSet[Tuple[str, int]]]
|
var.ROLE_STATS = frozenset() # type: FrozenSet[FrozenSet[Tuple[str, int]]]
|
||||||
var.ROLE_SETS = [] # type: List[Tuple[Counter[str], int]]
|
var.ROLE_SETS = [] # type: List[Tuple[Counter[str], int]]
|
||||||
var.VOTES.clear()
|
var.VOTES.clear()
|
||||||
@ -2041,22 +2040,8 @@ def stop_game(var, winner="", abort=False, additional_winners=None, log=True):
|
|||||||
message = ""
|
message = ""
|
||||||
count = 0
|
count = 0
|
||||||
if not abort:
|
if not abort:
|
||||||
done = {}
|
evt = Event("game_end_messages", {"messages": roles_msg})
|
||||||
lovers = []
|
evt.dispatch(var)
|
||||||
for lover1, llist in var.ORIGINAL_LOVERS.items():
|
|
||||||
for lover2 in llist:
|
|
||||||
# check if already said the pairing
|
|
||||||
if (lover1 in done and lover2 in done[lover1]) or (lover2 in done and lover1 in done[lover2]):
|
|
||||||
continue
|
|
||||||
lovers.append("\u0002{0}\u0002/\u0002{1}\u0002".format(lover1, lover2))
|
|
||||||
if lover1 in done:
|
|
||||||
done[lover1].append(lover2)
|
|
||||||
else:
|
|
||||||
done[lover1] = [lover2]
|
|
||||||
if len(lovers) == 1 or len(lovers) == 2:
|
|
||||||
roles_msg.append("The lovers were {0}.".format(" and ".join(lovers)))
|
|
||||||
elif len(lovers) > 2:
|
|
||||||
roles_msg.append("The lovers were {0}, and {1}".format(", ".join(lovers[0:-1]), lovers[-1]))
|
|
||||||
|
|
||||||
channels.Main.send(*roles_msg)
|
channels.Main.send(*roles_msg)
|
||||||
|
|
||||||
@ -2091,8 +2076,6 @@ def stop_game(var, winner="", abort=False, additional_winners=None, log=True):
|
|||||||
|
|
||||||
pentry["mainrole"] = rol
|
pentry["mainrole"] = rol
|
||||||
pentry["allroles"] = allroles[plr]
|
pentry["allroles"] = allroles[plr]
|
||||||
if splr in var.LOVERS:
|
|
||||||
pentry["special"].append("lover")
|
|
||||||
|
|
||||||
won = False
|
won = False
|
||||||
iwon = False
|
iwon = False
|
||||||
@ -2136,31 +2119,6 @@ def stop_game(var, winner="", abort=False, additional_winners=None, log=True):
|
|||||||
iwon = False
|
iwon = False
|
||||||
elif rol == "fool" and "@" + splr == winner:
|
elif rol == "fool" and "@" + splr == winner:
|
||||||
iwon = True
|
iwon = True
|
||||||
elif winner != "lovers" and splr in var.LOVERS and plr in survived and len([x for x in var.LOVERS[splr] if users._get(x) in survived]) > 0: # FIXME
|
|
||||||
for lvr in var.LOVERS[splr]:
|
|
||||||
lvuser = users._get(lvr) # FIXME
|
|
||||||
if lvuser not in survived:
|
|
||||||
# cannot win with dead lover (if splr in survived and lvr is not, that means lvr idled out)
|
|
||||||
continue
|
|
||||||
|
|
||||||
lvrrol = mainroles[lvuser]
|
|
||||||
|
|
||||||
if not winner.startswith("@") and singular(winner) not in var.WIN_STEALER_ROLES:
|
|
||||||
iwon = True
|
|
||||||
break
|
|
||||||
elif winner.startswith("@") and winner == "@" + lvr and var.LOVER_WINS_WITH_FOOL:
|
|
||||||
iwon = True
|
|
||||||
break
|
|
||||||
elif winner == "monsters" and lvrrol == "monster":
|
|
||||||
iwon = True
|
|
||||||
break
|
|
||||||
elif winner == "demoniacs" and lvrrol == "demoniac":
|
|
||||||
iwon = True
|
|
||||||
break
|
|
||||||
# TODO: split this into piper.py once matchmaker is split
|
|
||||||
elif winner == "pipers" and lvrrol == "piper":
|
|
||||||
iwon = True
|
|
||||||
break
|
|
||||||
elif rol == "monster" and plr in survived and winner == "monsters":
|
elif rol == "monster" and plr in survived and winner == "monsters":
|
||||||
iwon = True
|
iwon = True
|
||||||
elif rol == "demoniac" and plr in survived and winner == "demoniacs":
|
elif rol == "demoniac" and plr in survived and winner == "demoniacs":
|
||||||
@ -2451,28 +2409,6 @@ def del_player(player, *, devoice=True, end_game=True, death_triggers=True, kill
|
|||||||
if mainrole == "clone" and player.nick in var.CLONED:
|
if mainrole == "clone" and player.nick in var.CLONED:
|
||||||
del var.CLONED[player.nick]
|
del var.CLONED[player.nick]
|
||||||
|
|
||||||
if death_triggers and var.PHASE in var.GAME_PHASES:
|
|
||||||
if player.nick in var.LOVERS:
|
|
||||||
lovers = var.LOVERS[player.nick].copy()
|
|
||||||
var.LOVERS[player.nick].clear()
|
|
||||||
for lovernick in lovers:
|
|
||||||
lover = users._get(lovernick) # FIXME
|
|
||||||
if lover not in pl:
|
|
||||||
continue # already died somehow
|
|
||||||
if player.nick not in var.LOVERS[lover.nick]:
|
|
||||||
continue
|
|
||||||
var.LOVERS[lover.nick].remove(player.nick)
|
|
||||||
if var.ROLE_REVEAL in ("on", "team"):
|
|
||||||
role = get_reveal_role(lover)
|
|
||||||
an = "n" if role.startswith(("a", "e", "i", "o", "u")) else ""
|
|
||||||
message = messages["lover_suicide"].format(lover, an, role)
|
|
||||||
else:
|
|
||||||
message = messages["lover_suicide_no_reveal"].format(lover)
|
|
||||||
channels.Main.send(message)
|
|
||||||
debuglog("{0} ({1}) LOVE SUICIDE: {2} ({3})".format(lover, get_main_role(lover), player, mainrole))
|
|
||||||
del_player(lover, end_game=False, killer_role=killer_role, deadlist=deadlist, original=original, ismain=False)
|
|
||||||
pl = refresh_pl(pl)
|
|
||||||
|
|
||||||
pl = refresh_pl(pl)
|
pl = refresh_pl(pl)
|
||||||
# i herd u liek parameters
|
# i herd u liek parameters
|
||||||
evt_death_triggers = death_triggers and var.PHASE in var.GAME_PHASES
|
evt_death_triggers = death_triggers and var.PHASE in var.GAME_PHASES
|
||||||
@ -2566,7 +2502,7 @@ def del_player(player, *, devoice=True, end_game=True, death_triggers=True, kill
|
|||||||
# remove players from night variables
|
# remove players from night variables
|
||||||
# the dicts are handled above, these are the lists of who has acted which is used to determine whether night should end
|
# the dicts are handled above, these are the lists of who has acted which is used to determine whether night should end
|
||||||
# if these aren't cleared properly night may end prematurely
|
# if these aren't cleared properly night may end prematurely
|
||||||
for x in (var.PASSED, var.HEXED, var.MATCHMAKERS, var.CURSED):
|
for x in (var.PASSED, var.HEXED, var.CURSED):
|
||||||
x.discard(player.nick)
|
x.discard(player.nick)
|
||||||
if var.PHASE == "day" and ret:
|
if var.PHASE == "day" and ret:
|
||||||
if player in var.VOTES:
|
if player in var.VOTES:
|
||||||
@ -2893,21 +2829,6 @@ def rename_player(var, user, prefix):
|
|||||||
# defaultdict(list), where keys are nicks and items in list do not matter
|
# defaultdict(list), where keys are nicks and items in list do not matter
|
||||||
if prefix in var.ACTIVE_PROTECTIONS.keys():
|
if prefix in var.ACTIVE_PROTECTIONS.keys():
|
||||||
var.ACTIVE_PROTECTIONS[nick] = var.ACTIVE_PROTECTIONS.pop(prefix)
|
var.ACTIVE_PROTECTIONS[nick] = var.ACTIVE_PROTECTIONS.pop(prefix)
|
||||||
# Looks like {'6': {'jacob3'}, 'jacob3': {'6'}}
|
|
||||||
for dictvar in (var.LOVERS, var.ORIGINAL_LOVERS):
|
|
||||||
kvp = []
|
|
||||||
for a,b in dictvar.items():
|
|
||||||
nl = set()
|
|
||||||
for n in b:
|
|
||||||
if n == prefix:
|
|
||||||
n = nick
|
|
||||||
nl.add(n)
|
|
||||||
if a == prefix:
|
|
||||||
a = nick
|
|
||||||
kvp.append((a,nl))
|
|
||||||
dictvar.update(kvp)
|
|
||||||
if prefix in dictvar.keys():
|
|
||||||
del dictvar[prefix]
|
|
||||||
for idx, tup in enumerate(var.EXCHANGED_ROLES):
|
for idx, tup in enumerate(var.EXCHANGED_ROLES):
|
||||||
a, b = tup
|
a, b = tup
|
||||||
if a == prefix:
|
if a == prefix:
|
||||||
@ -2915,7 +2836,7 @@ def rename_player(var, user, prefix):
|
|||||||
if b == prefix:
|
if b == prefix:
|
||||||
b = nick
|
b = nick
|
||||||
var.EXCHANGED_ROLES[idx] = (a, b)
|
var.EXCHANGED_ROLES[idx] = (a, b)
|
||||||
for setvar in (var.HEXED, var.SILENCED, var.MATCHMAKERS, var.PASSED,
|
for setvar in (var.HEXED, var.SILENCED, var.PASSED,
|
||||||
var.JESTERS, var.LYCANTHROPES, var.LUCKY, var.DISEASED,
|
var.JESTERS, var.LYCANTHROPES, var.LUCKY, var.DISEASED,
|
||||||
var.MISDIRECTED, var.EXCHANGED, var.IMMUNIZED, var.CURED_LYCANS,
|
var.MISDIRECTED, var.EXCHANGED, var.IMMUNIZED, var.CURED_LYCANS,
|
||||||
var.ALPHA_WOLVES, var.CURSED, var.PRIESTS):
|
var.ALPHA_WOLVES, var.CURSED, var.PRIESTS):
|
||||||
@ -3215,12 +3136,6 @@ def transition_day(gameid=0):
|
|||||||
var.CLONED[clone.nick] = target.nick
|
var.CLONED[clone.nick] = target.nick
|
||||||
clone.send(messages["random_clone"].format(target))
|
clone.send(messages["random_clone"].format(target))
|
||||||
|
|
||||||
for mm in get_all_players(("matchmaker",)):
|
|
||||||
if mm.nick not in var.MATCHMAKERS:
|
|
||||||
lovers = random.sample(pl, 2)
|
|
||||||
choose.func(mm.client, mm.nick, mm.nick, "{0[0]} {0[1]}".format(lovers), sendmsg=False) # XXX: Old API
|
|
||||||
mm.send(messages["random_matchmaker"])
|
|
||||||
|
|
||||||
# Reset daytime variables
|
# Reset daytime variables
|
||||||
var.WOUNDED.clear()
|
var.WOUNDED.clear()
|
||||||
var.NO_LYNCH.clear()
|
var.NO_LYNCH.clear()
|
||||||
@ -3624,8 +3539,8 @@ def chk_nightdone():
|
|||||||
actedcount += 1
|
actedcount += 1
|
||||||
|
|
||||||
if var.FIRST_NIGHT:
|
if var.FIRST_NIGHT:
|
||||||
actedcount += len(var.MATCHMAKERS | var.CLONED.keys())
|
actedcount += len(var.CLONED.keys())
|
||||||
nightroles.extend(get_all_players(("matchmaker", "clone")))
|
nightroles.extend(get_all_players(("clone",)))
|
||||||
|
|
||||||
if var.ALPHA_ENABLED:
|
if var.ALPHA_ENABLED:
|
||||||
# alphas both kill and bite if they're activated at night, so add them into the counts
|
# alphas both kill and bite if they're activated at night, so add them into the counts
|
||||||
@ -4419,69 +4334,6 @@ def change_sides(cli, nick, chan, rest, sendmsg=True):
|
|||||||
var.TURNCOATS[nick] = (team, var.NIGHT_COUNT)
|
var.TURNCOATS[nick] = (team, var.NIGHT_COUNT)
|
||||||
debuglog("{0} ({1}) SIDE {2}".format(nick, get_role(nick), team))
|
debuglog("{0} ({1}) SIDE {2}".format(nick, get_role(nick), team))
|
||||||
|
|
||||||
@cmd("choose", chan=False, pm=True, playing=True, phases=("night",), roles=("matchmaker",))
|
|
||||||
@cmd("match", chan=False, pm=True, playing=True, phases=("night",), roles=("matchmaker",))
|
|
||||||
def choose(cli, nick, chan, rest, sendmsg=True): # XXX: transition_day also needs updating alongside this one
|
|
||||||
"""Select two players to fall in love. You may select yourself as one of the lovers."""
|
|
||||||
if not var.FIRST_NIGHT:
|
|
||||||
return
|
|
||||||
if nick in var.MATCHMAKERS:
|
|
||||||
pm(cli, nick, messages["already_matched"])
|
|
||||||
return
|
|
||||||
# no var.SILENCED check for night 1 only roles; silence should only apply for the night after
|
|
||||||
# but just in case, it also sucks if the one night you're allowed to act is when you are
|
|
||||||
# silenced, so we ignore it here anyway.
|
|
||||||
pieces = re.split(" +",rest)
|
|
||||||
victim = pieces[0]
|
|
||||||
if len(pieces) > 1:
|
|
||||||
if len(pieces) > 2 and pieces[1].lower() == "and":
|
|
||||||
victim2 = pieces[2]
|
|
||||||
else:
|
|
||||||
victim2 = pieces[1]
|
|
||||||
else:
|
|
||||||
victim2 = None
|
|
||||||
|
|
||||||
victim = get_victim(cli, nick, victim, False, True)
|
|
||||||
if not victim:
|
|
||||||
return
|
|
||||||
victim2 = get_victim(cli, nick, victim2, False, True)
|
|
||||||
if not victim2:
|
|
||||||
return
|
|
||||||
|
|
||||||
if victim == victim2:
|
|
||||||
pm(cli, nick, messages["match_different_people"])
|
|
||||||
return
|
|
||||||
|
|
||||||
var.MATCHMAKERS.add(nick)
|
|
||||||
if victim in var.LOVERS:
|
|
||||||
var.LOVERS[victim].add(victim2)
|
|
||||||
var.ORIGINAL_LOVERS[victim].add(victim2)
|
|
||||||
else:
|
|
||||||
var.LOVERS[victim] = {victim2}
|
|
||||||
var.ORIGINAL_LOVERS[victim] = {victim2}
|
|
||||||
|
|
||||||
if victim2 in var.LOVERS:
|
|
||||||
var.LOVERS[victim2].add(victim)
|
|
||||||
var.ORIGINAL_LOVERS[victim2].add(victim)
|
|
||||||
else:
|
|
||||||
var.LOVERS[victim2] = {victim}
|
|
||||||
var.ORIGINAL_LOVERS[victim2] = {victim}
|
|
||||||
|
|
||||||
if sendmsg:
|
|
||||||
pm(cli, nick, messages["matchmaker_success"].format(victim, victim2))
|
|
||||||
|
|
||||||
if victim in var.PLAYERS and not is_user_simple(victim):
|
|
||||||
pm(cli, victim, messages["matchmaker_target_notify"].format(victim2))
|
|
||||||
else:
|
|
||||||
pm(cli, victim, messages["matchmaker_target_notify_simple"].format(victim2))
|
|
||||||
|
|
||||||
if victim2 in var.PLAYERS and not is_user_simple(victim2):
|
|
||||||
pm(cli, victim2, messages["matchmaker_target_notify"].format(victim))
|
|
||||||
else:
|
|
||||||
pm(cli, victim2, messages["matchmaker_target_notify_simple"].format(victim))
|
|
||||||
|
|
||||||
debuglog("{0} ({1}) MATCH: {2} ({3}) + {4} ({5})".format(nick, get_role(nick), victim, get_role(victim), victim2, get_role(victim2)))
|
|
||||||
|
|
||||||
@cmd("hex", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("hag",))
|
@cmd("hex", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("hag",))
|
||||||
def hex_target(cli, nick, chan, rest):
|
def hex_target(cli, nick, chan, rest):
|
||||||
"""Hex someone, preventing them from acting the next day and night."""
|
"""Hex someone, preventing them from acting the next day and night."""
|
||||||
@ -4917,15 +4769,6 @@ def transition_night():
|
|||||||
priest.send(messages["priest_notify"])
|
priest.send(messages["priest_notify"])
|
||||||
|
|
||||||
if var.FIRST_NIGHT or var.ALWAYS_PM_ROLE:
|
if var.FIRST_NIGHT or var.ALWAYS_PM_ROLE:
|
||||||
for mm in get_all_players(("matchmaker",)):
|
|
||||||
pl = ps[:]
|
|
||||||
random.shuffle(pl)
|
|
||||||
if mm.prefers_simple():
|
|
||||||
mm.send(messages["matchmaker_simple"])
|
|
||||||
else:
|
|
||||||
mm.send(messages["matchmaker_notify"])
|
|
||||||
mm.send("Players: " + ", ".join(p.nick for p in pl))
|
|
||||||
|
|
||||||
for clone in get_all_players(("clone",)):
|
for clone in get_all_players(("clone",)):
|
||||||
pl = ps[:]
|
pl = ps[:]
|
||||||
random.shuffle(pl)
|
random.shuffle(pl)
|
||||||
@ -5189,7 +5032,6 @@ def start(cli, nick, chan, forced = False, restart = ""):
|
|||||||
var.OBSERVED = {}
|
var.OBSERVED = {}
|
||||||
var.CLONED = {}
|
var.CLONED = {}
|
||||||
var.LASTHEXED = {}
|
var.LASTHEXED = {}
|
||||||
var.MATCHMAKERS = set()
|
|
||||||
var.SILENCED = set()
|
var.SILENCED = set()
|
||||||
var.TOBESILENCED = set()
|
var.TOBESILENCED = set()
|
||||||
var.JESTERS = set()
|
var.JESTERS = set()
|
||||||
@ -5198,7 +5040,6 @@ def start(cli, nick, chan, forced = False, restart = ""):
|
|||||||
var.DISEASED_WOLVES = False
|
var.DISEASED_WOLVES = False
|
||||||
var.TRAITOR_TURNED = False
|
var.TRAITOR_TURNED = False
|
||||||
var.FINAL_ROLES = {}
|
var.FINAL_ROLES = {}
|
||||||
var.ORIGINAL_LOVERS = {}
|
|
||||||
var.LYCANTHROPES = set()
|
var.LYCANTHROPES = set()
|
||||||
var.LUCKY = set()
|
var.LUCKY = set()
|
||||||
var.DISEASED = set()
|
var.DISEASED = set()
|
||||||
@ -6072,19 +5913,6 @@ def myrole(var, wrapper, message): # FIXME: Need to fix !swap once this gets con
|
|||||||
if "prophet" in var.TEMPLATE_RESTRICTIONS and wrapper.source in var.ROLES["prophet"]:
|
if "prophet" in var.TEMPLATE_RESTRICTIONS and wrapper.source in var.ROLES["prophet"]:
|
||||||
wrapper.pm(messages["prophet_simple"])
|
wrapper.pm(messages["prophet_simple"])
|
||||||
|
|
||||||
# Remind lovers of each other
|
|
||||||
if wrapper.source in ps and wrapper.source.nick in var.LOVERS:
|
|
||||||
message = messages["matched_info"]
|
|
||||||
lovers = sorted(list(set(var.LOVERS[wrapper.source.nick])))
|
|
||||||
if len(lovers) == 1:
|
|
||||||
message += lovers[0]
|
|
||||||
elif len(lovers) == 2:
|
|
||||||
message += lovers[0] + " and " + lovers[1]
|
|
||||||
else:
|
|
||||||
message += ", ".join(lovers[:-1]) + ", and " + lovers[-1]
|
|
||||||
message += "."
|
|
||||||
wrapper.pm(message)
|
|
||||||
|
|
||||||
@command("aftergame", "faftergame", flag="D", pm=True)
|
@command("aftergame", "faftergame", flag="D", pm=True)
|
||||||
def aftergame(var, wrapper, message):
|
def aftergame(var, wrapper, message):
|
||||||
"""Schedule a command to be run after the current game."""
|
"""Schedule a command to be run after the current game."""
|
||||||
@ -6570,24 +6398,6 @@ def revealroles(var, wrapper, message):
|
|||||||
|
|
||||||
output.append("\u0002{0}\u0002: {1}".format(role, ", ".join(out)))
|
output.append("\u0002{0}\u0002: {1}".format(role, ", ".join(out)))
|
||||||
|
|
||||||
# print out lovers too
|
|
||||||
done = {}
|
|
||||||
lovers = []
|
|
||||||
for lover1, llist in var.LOVERS.items():
|
|
||||||
for lover2 in llist:
|
|
||||||
# check if already said the pairing
|
|
||||||
if (lover1 in done and lover2 in done[lover1]) or (lover2 in done and lover1 in done[lover2]):
|
|
||||||
continue
|
|
||||||
lovers.append("{0}/{1}".format(lover1, lover2))
|
|
||||||
if lover1 in done:
|
|
||||||
done[lover1].append(lover2)
|
|
||||||
else:
|
|
||||||
done[lover1] = [lover2]
|
|
||||||
if len(lovers) == 1 or len(lovers) == 2:
|
|
||||||
output.append("\u0002lovers\u0002: {0}".format(" and ".join(lovers)))
|
|
||||||
elif len(lovers) > 2:
|
|
||||||
output.append("\u0002lovers\u0002: {0}, and {1}".format(", ".join(lovers[0:-1]), lovers[-1]))
|
|
||||||
|
|
||||||
#show who got immunized
|
#show who got immunized
|
||||||
if var.IMMUNIZED:
|
if var.IMMUNIZED:
|
||||||
output.append("\u0002immunized\u0002: {0}".format(", ".join(var.IMMUNIZED)))
|
output.append("\u0002immunized\u0002: {0}".format(", ".join(var.IMMUNIZED)))
|
||||||
|
Loading…
Reference in New Issue
Block a user