diff --git a/src/gamemodes.py b/src/gamemodes.py index 0f08d18..9ae0cb0 100644 --- a/src/gamemodes.py +++ b/src/gamemodes.py @@ -1143,9 +1143,9 @@ class SleepyMode(GameMode): if mainrole == "priest": pl = evt.data["pl"] turn_chance = 3/4 - seers = [p for p in get_all_players(("seer",)) if p.nick in pl and random.random() < turn_chance] - harlots = [p for p in get_all_players(("harlot",)) if p.nick in pl and random.random() < turn_chance] - cultists = [p for p in get_all_players(("cultist",)) if p.nick in pl and random.random() < turn_chance] + seers = [p for p in get_players(("seer",)) if p in pl and random.random() < turn_chance] + harlots = [p for p in get_players(("harlot",)) if p in pl and random.random() < turn_chance] + cultists = [p for p in get_players(("cultist",)) if p in pl and random.random() < turn_chance] channels.Main.send(messages["sleepy_priest_death"]) for seer in seers: change_role(seer, "seer", "doomsayer") diff --git a/src/handler.py b/src/handler.py index 26bc904..04a780a 100644 --- a/src/handler.py +++ b/src/handler.py @@ -13,7 +13,7 @@ import src.settings as var from src import decorators, wolfgame, events, channels, hooks, users, errlog as log, stream_handler as alog from src.messages import messages from src.utilities import reply, get_role, get_templates -from src.functions import get_participants +from src.functions import get_participants, get_all_roles from src.dispatcher import MessageDispatcher from src.decorators import handle_error @@ -69,7 +69,7 @@ def on_privmsg(cli, rawnick, chan, msg, *, notice=False, force_role=None): cmds = [] phase = var.PHASE if user in get_participants(): - roles = {get_role(user.nick)} | set(get_templates(user.nick)) + roles = get_all_roles(user) if force_role is not None: roles &= {force_role} # only fire off role commands for the forced role diff --git a/src/roles/angel.py b/src/roles/angel.py index fdbc62c..d659d94 100644 --- a/src/roles/angel.py +++ b/src/roles/angel.py @@ -7,7 +7,7 @@ from collections import defaultdict import botconfig import src.settings as var from src.utilities import * -from src import users, debuglog, errlog, plog +from src import users, channels, debuglog, errlog, plog from src.functions import get_players, get_all_players from src.decorators import cmd, event_listener from src.messages import messages @@ -266,19 +266,19 @@ def on_transition_night_end(evt, var): gangel.send(messages[to_send].format(warning, gself), "Players: " + ", ".join(p.nick for p in pl), sep="\n") @event_listener("assassinate") -def on_assassinate(evt, cli, var, nick, target, prot): +def on_assassinate(evt, var, killer, target, prot): if prot == "angel" and var.GAMEPHASE == "night": - var.ACTIVE_PROTECTIONS[target].remove("angel") + var.ACTIVE_PROTECTIONS[target.nick].remove("angel") evt.prevent_default = True evt.stop_processing = True - cli.msg(botconfig.CHANNEL, messages[evt.params.message_prefix + "angel"].format(nick, target)) + channels.Main.send(messages[evt.params.message_prefix + "angel"].format(killer, target)) elif prot == "bodyguard": - var.ACTIVE_PROTECTIONS[target].remove("bodyguard") + var.ACTIVE_PROTECTIONS[target.nick].remove("bodyguard") evt.prevent_default = True evt.stop_processing = True for bg in var.ROLES["bodyguard"]: - if GUARDED.get(bg) == target: - cli.msg(botconfig.CHANNEL, messages[evt.params.message_prefix + "bodyguard"].format(nick, target, bg)) + if GUARDED.get(bg) == target.nick: + channels.Main.send(messages[evt.params.message_prefix + "bodyguard"].format(killer, target, bg)) # redirect the assassination to the bodyguard evt.data["target"] = users._get(bg) # FIXME break diff --git a/src/roles/blessed.py b/src/roles/blessed.py index ce8eb5e..669bd83 100644 --- a/src/roles/blessed.py +++ b/src/roles/blessed.py @@ -7,7 +7,7 @@ from collections import defaultdict import botconfig import src.settings as var from src.utilities import * -from src import users, debuglog, errlog, plog +from src import users, channels, debuglog, errlog, plog from src.functions import get_players, get_all_players from src.decorators import cmd, event_listener from src.messages import messages @@ -65,13 +65,13 @@ def on_retribution(evt, var, victim, target, prot): evt.stop_processing = True @event_listener("assassinate") -def on_assassinate(evt, cli, var, nick, target, prot): +def on_assassinate(evt, var, killer, target, prot): if prot == "blessing": - var.ACTIVE_PROTECTIONS[target].remove("blessing") + var.ACTIVE_PROTECTIONS[target.nick].remove("blessing") evt.prevent_default = True evt.stop_processing = True # don't message the channel whenever a blessing blocks a kill, but *do* let the killer know so they don't try to report it as a bug - pm(cli, nick, messages["assassin_fail_blessed"].format(target)) + killer.send(messages["assassin_fail_blessed"].format(target)) @event_listener("myrole") def on_myrole(evt, var, user): diff --git a/src/roles/cursed.py b/src/roles/cursed.py index 4940eac..0e6fcd4 100644 --- a/src/roles/cursed.py +++ b/src/roles/cursed.py @@ -7,7 +7,7 @@ from collections import defaultdict import botconfig import src.settings as var from src.utilities import * -from src import debuglog, errlog, plog +from src import users, channels, debuglog, errlog, plog from src.decorators import cmd, event_listener from src.messages import messages from src.events import Event @@ -18,8 +18,8 @@ def on_see(evt, cli, var, nick, victim): evt.data["role"] = "wolf" @event_listener("wolflist") -def on_wolflist(evt, cli, var, nick, wolf): - if nick in var.ROLES["cursed villager"]: +def on_wolflist(evt, var, player, wolf): + if player.nick in var.ROLES["cursed villager"]: evt.data["tags"].add("cursed") # vim: set sw=4 expandtab: diff --git a/src/roles/detective.py b/src/roles/detective.py index 9c16cbc..d8111a9 100644 --- a/src/roles/detective.py +++ b/src/roles/detective.py @@ -4,7 +4,7 @@ import random import src.settings as var from src.utilities import * -from src import debuglog, errlog, plog +from src import users, channels, debuglog, errlog, plog from src.functions import get_players, get_all_players from src.decorators import cmd, event_listener from src.messages import messages diff --git a/src/roles/doomsayer.py b/src/roles/doomsayer.py index fde5e67..1f027e0 100644 --- a/src/roles/doomsayer.py +++ b/src/roles/doomsayer.py @@ -3,7 +3,7 @@ import random import src.settings as var from src.utilities import * -from src import users, debuglog, errlog, plog +from src import users, channels, debuglog, errlog, plog from src.functions import get_players, get_all_players from src.decorators import cmd, event_listener from src.messages import messages diff --git a/src/roles/dullahan.py b/src/roles/dullahan.py index 76633b6..bec9d47 100644 --- a/src/roles/dullahan.py +++ b/src/roles/dullahan.py @@ -4,8 +4,8 @@ import random from collections import defaultdict, deque from src.utilities import * -from src.functions import get_players, get_all_players, get_target -from src import users, debuglog, errlog, plog +from src.functions import get_players, get_all_players, get_target, get_main_role +from src import users, channels, debuglog, errlog, plog from src.decorators import command, event_listener from src.messages import messages from src.events import Event @@ -40,7 +40,7 @@ def dullahan_kill(var, wrapper, message): wrapper.pm(messages["player_kill"].format(orig)) - debuglog("{0} (dullahan) KILL: {1} ({2})".format(wrapper.source, target, get_role(target.nick))) + debuglog("{0} (dullahan) KILL: {1} ({2})".format(wrapper.source, target, get_main_role(target))) chk_nightdone(wrapper.client) @@ -68,7 +68,7 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): del KILLS[h] if death_triggers and "dullahan" in allroles: pl = evt.data["pl"] - targets = TARGETS[user].intersection(users._get(x) for x in pl) # FIXME + targets = TARGETS[user].intersection(pl) if targets: target = random.choice(list(targets)) prots = deque(var.ACTIVE_PROTECTIONS[target.nick]) @@ -79,7 +79,7 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): refresh_pl=evt.params.refresh_pl, message_prefix="dullahan_die_", source="dullahan", - killer=user.nick, + killer=user, killer_mainrole=mainrole, killer_allroles=allroles, prots=prots) @@ -87,7 +87,7 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): # an event can read the current active protection and cancel or redirect the assassination # if it cancels, it is responsible for removing the protection from var.ACTIVE_PROTECTIONS # so that it cannot be used again (if the protection is meant to be usable once-only) - if not aevt.dispatch(user.client, var, user.nick, target.nick, prots[0]): + if not aevt.dispatch(var, user, target, prots[0]): evt.data["pl"] = aevt.data["pl"] if target is not aevt.data["target"]: target = aevt.data["target"] @@ -97,15 +97,14 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): return prots.popleft() - target = target.nick # FIXME if var.ROLE_REVEAL in ("on", "team"): - role = get_reveal_role(target) + role = get_reveal_role(target.nick) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" channels.Main.send(messages["dullahan_die_success"].format(user, target, an, role)) else: channels.Main.send(messages["dullahan_die_success_noreveal"].format(user, target)) - debuglog("{0} (dullahan) DULLAHAN ASSASSINATE: {1} ({2})".format(user, target, get_role(target))) - evt.params.del_player(user.client, target, True, end_game=False, killer_role="dullahan", deadlist=evt.params.deadlist, original=evt.params.original, ismain=False) + debuglog("{0} (dullahan) DULLAHAN ASSASSINATE: {1} ({2})".format(user, target, get_main_role(target))) + evt.params.del_player(target, end_game=False, killer_role="dullahan", deadlist=evt.params.deadlist, original=evt.params.original, ismain=False) evt.data["pl"] = evt.params.refresh_pl(pl) @event_listener("night_acted") diff --git a/src/roles/fallenangel.py b/src/roles/fallenangel.py index 6fc1b48..420d897 100644 --- a/src/roles/fallenangel.py +++ b/src/roles/fallenangel.py @@ -7,7 +7,7 @@ from collections import defaultdict import botconfig import src.settings as var from src.utilities import * -from src import users, debuglog, errlog, plog +from src import users, channels, debuglog, errlog, plog from src.decorators import cmd, event_listener from src.functions import get_players, get_all_players from src.messages import messages @@ -42,7 +42,7 @@ def on_transition_day(evt, var): evt.data["killers"][p].append(killer) @event_listener("assassinate", priority=1) -def on_assassinate(evt, cli, var, nick, target, prot): +def on_assassinate(evt, var, killer, target, prot): # bypass all protection if FA is doing the killing # we do this by stopping propagation, meaning future events won't fire if "fallen angel" in evt.params.killer_allroles: diff --git a/src/roles/hunter.py b/src/roles/hunter.py index 3ec138b..48044ed 100644 --- a/src/roles/hunter.py +++ b/src/roles/hunter.py @@ -4,8 +4,8 @@ from collections import defaultdict import src.settings as var from src.utilities import * -from src import users, debuglog, errlog, plog -from src.functions import get_players, get_all_players, get_target +from src import users, channels, debuglog, errlog, plog +from src.functions import get_players, get_all_players, get_target, get_main_role from src.decorators import command, event_listener from src.messages import messages from src.events import Event @@ -42,7 +42,7 @@ def hunter_kill(var, wrapper, message): wrapper.pm(messages["player_kill"].format(orig)) - debuglog("{0} (hunter) KILL: {1} ({2})".format(wrapper.source, target, get_role(target.nick))) + debuglog("{0} (hunter) KILL: {1} ({2})".format(wrapper.source, target, get_main_role(target))) chk_nightdone(wrapper.client) @command("retract", "r", chan=False, pm=True, playing=True, phases=("night",), roles=("hunter",)) diff --git a/src/roles/madscientist.py b/src/roles/madscientist.py index 5e0fb7c..b6a6880 100644 --- a/src/roles/madscientist.py +++ b/src/roles/madscientist.py @@ -8,12 +8,12 @@ import botconfig import src.settings as var from src.utilities import * from src import channels, users, debuglog, errlog, plog -from src.functions import get_players, get_all_players +from src.functions import get_players, get_all_players, get_main_role from src.decorators import command, event_listener from src.messages import messages from src.events import Event -def _get_targets(var, pl, nick): +def _get_targets(var, pl, user): """Gets the mad scientist's targets. var - settings module @@ -21,8 +21,8 @@ def _get_targets(var, pl, nick): nick - nick of the mad scientist """ - for index, user in enumerate(var.ALL_PLAYERS): - if user.nick == nick: # FIXME + for index, player in enumerate(var.ALL_PLAYERS): + if player is user: break num_players = len(var.ALL_PLAYERS) @@ -33,14 +33,14 @@ def _get_targets(var, pl, nick): i = index while True: i = (i - 1) % num_players - if var.ALL_PLAYERS[i].nick in pl or var.ALL_PLAYERS[i].nick == nick: + if var.ALL_PLAYERS[i] in pl or var.ALL_PLAYERS[i] is user: target1 = var.ALL_PLAYERS[i] break # determine right player i = index while True: i = (i + 1) % num_players - if var.ALL_PLAYERS[i].nick in pl or var.ALL_PLAYERS[i].nick == nick: + if var.ALL_PLAYERS[i] in pl or var.ALL_PLAYERS[i] is user: target2 = var.ALL_PLAYERS[i] break @@ -53,7 +53,7 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): return pl = evt.data["pl"] - target1, target2 = _get_targets(var, pl, user.nick) + target1, target2 = _get_targets(var, pl, user) # apply protections (if applicable) prots1 = deque(var.ACTIVE_PROTECTIONS[target1.nick]) @@ -68,13 +68,13 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): refresh_pl=evt.params.refresh_pl, message_prefix="mad_scientist_fail_", source="mad scientist", - killer=user.nick, + killer=user, killer_mainrole=mainrole, killer_allroles=allroles, prots=prots1) while len(prots1) > 0: # events may be able to cancel this kill - if not aevt.dispatch(user.client, var, user.nick, target1.nick, prots1[0]): + if not aevt.dispatch(var, user, target1, prots1[0]): pl = aevt.data["pl"] if target1 is not aevt.data["target"]: target1 = aevt.data["target"] @@ -87,7 +87,7 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): aevt.params.prots = prots2 while len(prots2) > 0: # events may be able to cancel this kill - if not aevt.dispatch(user.client, var, user.nick, target2.nick, prots2[0]): + if not aevt.dispatch(var, user, target2, prots2[0]): pl = aevt.data["pl"] if target2 is not aevt.data["target"]: target2 = aevt.data["target"] @@ -97,8 +97,8 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): break prots2.popleft() - kill1 = target1.nick in pl and len(prots1) == 0 - kill2 = target2.nick in pl and len(prots2) == 0 and target1 is not target2 + kill1 = target1 in pl and len(prots1) == 0 + kill2 = target2 in pl and len(prots2) == 0 and target1 is not target2 if kill1: if kill2: @@ -111,14 +111,14 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): else: tmsg = messages["mad_scientist_kill_no_reveal"].format(user, target1, target2) channels.Main.send(tmsg) - debuglog(user.nick, "(mad scientist) KILL: {0} ({1}) - {2} ({3})".format(target1, get_role(target1.nick), target2, get_role(target2.nick))) + debuglog(user.nick, "(mad scientist) KILL: {0} ({1}) - {2} ({3})".format(target1, get_main_role(target1), target2, get_main_role(target2))) # here we DO want to tell that the other one is dying already so chained deaths don't mess things up deadlist1 = evt.params.deadlist[:] - deadlist1.append(target2.nick) + deadlist1.append(target2) deadlist2 = evt.params.deadlist[:] - deadlist2.append(target1.nick) - evt.params.del_player(user.client, target1.nick, True, end_game=False, killer_role="mad scientist", deadlist=deadlist1, original=evt.params.original, ismain=False) - evt.params.del_player(user.client, target2.nick, True, end_game=False, killer_role="mad scientist", deadlist=deadlist2, original=evt.params.original, ismain=False) + deadlist2.append(target1) + evt.params.del_player(target1, end_game=False, killer_role="mad scientist", deadlist=deadlist1, original=evt.params.original, ismain=False) + evt.params.del_player(target2, end_game=False, killer_role="mad scientist", deadlist=deadlist2, original=evt.params.original, ismain=False) pl = evt.params.refresh_pl(pl) else: if var.ROLE_REVEAL in ("on", "team"): @@ -128,8 +128,8 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): else: tmsg = messages["mad_scientist_kill_single_no_reveal"].format(user, target1) channels.Main.send(tmsg) - debuglog(user.nick, "(mad scientist) KILL: {0} ({1})".format(target1, get_role(target1.nick))) - evt.params.del_player(user.client, target1.nick, True, end_game=False, killer_role="mad scientist", deadlist=evt.params.deadlist, original=evt.params.original, ismain=False) + debuglog(user.nick, "(mad scientist) KILL: {0} ({1})".format(target1, get_main_role(target1))) + evt.params.del_player(target1, end_game=False, killer_role="mad scientist", deadlist=evt.params.deadlist, original=evt.params.original, ismain=False) pl = evt.params.refresh_pl(pl) else: if kill2: @@ -140,8 +140,8 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): else: tmsg = messages["mad_scientist_kill_single_no_reveal"].format(user, target2) channels.Main.send(tmsg) - debuglog(user.nick, "(mad scientist) KILL: {0} ({1})".format(target2, get_role(target2.nick))) - evt.params.del_player(user.client, target2.nick, True, end_game=False, killer_role="mad scientist", deadlist=evt.params.deadlist, original=evt.params.original, ismain=False) + debuglog(user.nick, "(mad scientist) KILL: {0} ({1})".format(target2, get_main_role(target2))) + evt.params.del_player(target2, end_game=False, killer_role="mad scientist", deadlist=evt.params.deadlist, original=evt.params.original, ismain=False) pl = evt.params.refresh_pl(pl) else: tmsg = messages["mad_scientist_fail"].format(user) @@ -153,8 +153,8 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): @event_listener("transition_night_end", priority=2) def on_transition_night_end(evt, var): for ms in get_all_players(("mad scientist",)): - pl = list_players() - target1, target2 = _get_targets(var, pl, ms.nick) # FIXME: Need to update _get_targets to accept users + pl = get_players() + target1, target2 = _get_targets(var, pl, ms) to_send = "mad_scientist_notify" if ms.prefers_simple(): @@ -164,15 +164,15 @@ def on_transition_night_end(evt, var): @event_listener("myrole") def on_myrole(evt, var, user): if user.nick in var.ROLES["mad scientist"]: - pl = list_players() - target1, target2 = _get_targets(var, pl, user.nick) + pl = get_players() + target1, target2 = _get_targets(var, pl, user) evt.data["messages"].append(messages["mad_scientist_myrole_targets"].format(target1, target2)) @event_listener("revealroles_role") def on_revealroles(evt, var, wrapper, nickname, role): if role == "mad scientist": - pl = list_players() - target1, target2 = _get_targets(var, pl, nickname) + pl = get_players() + target1, target2 = _get_targets(var, pl, users._get(nickname)) # FIXME evt.data["special_case"].append(messages["mad_scientist_revealroles_targets"].format(target1, target2)) diff --git a/src/roles/mayor.py b/src/roles/mayor.py index 783991c..18584ae 100644 --- a/src/roles/mayor.py +++ b/src/roles/mayor.py @@ -7,7 +7,7 @@ from collections import defaultdict import botconfig import src.settings as var from src.utilities import * -from src import debuglog, errlog, plog +from src import users, channels, debuglog, errlog, plog from src.decorators import cmd, event_listener from src.messages import messages from src.events import Event diff --git a/src/roles/mystic.py b/src/roles/mystic.py index f9723bd..92a1cde 100644 --- a/src/roles/mystic.py +++ b/src/roles/mystic.py @@ -3,7 +3,7 @@ import random import src.settings as var from src.utilities import * -from src import debuglog, errlog, plog +from src import users, channels, debuglog, errlog, plog from src.functions import get_players, get_all_players from src.decorators import cmd, event_listener from src.messages import messages diff --git a/src/roles/seer.py b/src/roles/seer.py index c2afff8..c028a05 100644 --- a/src/roles/seer.py +++ b/src/roles/seer.py @@ -3,7 +3,7 @@ import random import src.settings as var from src.utilities import * -from src import debuglog, errlog, plog +from src import users, channels, debuglog, errlog, plog from src.decorators import cmd, event_listener from src.functions import get_players, get_all_players, get_main_role from src.messages import messages diff --git a/src/roles/shaman.py b/src/roles/shaman.py index 8eed488..954c336 100644 --- a/src/roles/shaman.py +++ b/src/roles/shaman.py @@ -297,7 +297,9 @@ def on_chk_decision_lynch5(evt, cli, var, voters): cli.msg(botconfig.CHANNEL, tmsg) # we lie to this function so it doesn't devoice the player yet. instead, we'll let the call further down do it evt.data["deadlist"].append(target) - evt.params.del_player(cli, target, True, end_game=False, killer_role="shaman", deadlist=evt.data["deadlist"], original=target, ismain=False) + better_deadlist = [users._get(p) for p in evt.data["deadlist"]] # FIXME + target_user = users._get(target) # FIXME + evt.params.del_player(target_user, end_game=False, killer_role="shaman", deadlist=better_deadlist, ismain=False) @event_listener("player_win") def on_player_win(evt, var, user, rol, winner, survived): @@ -576,12 +578,12 @@ def on_lynch(evt, cli, var, nick): evt.prevent_default = True @event_listener("assassinate") -def on_assassinate(evt, cli, var, nick, target, prot): +def on_assassinate(evt, var, killer, target, prot): if prot == "totem": - var.ACTIVE_PROTECTIONS[target].remove("totem") + var.ACTIVE_PROTECTIONS[target.nick].remove("totem") evt.prevent_default = True evt.stop_processing = True - cli.msg(botconfig.CHANNEL, messages[evt.params.message_prefix + "totem"].format(nick, target)) + channels.Main.send(messages[evt.params.message_prefix + "totem"].format(killer, target)) @event_listener("succubus_visit") def on_succubus_visit(evt, cli, var, nick, victim): diff --git a/src/roles/succubus.py b/src/roles/succubus.py index 1e6553b..eb4cdb1 100644 --- a/src/roles/succubus.py +++ b/src/roles/succubus.py @@ -8,7 +8,7 @@ import botconfig import src.settings as var from src.utilities import * from src import channels, users, debuglog, errlog, plog -from src.functions import get_players, get_all_players +from src.functions import get_players, get_all_players, get_main_role from src.decorators import cmd, event_listener from src.messages import messages from src.events import Event @@ -184,7 +184,7 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): if death_triggers: ALL_SUCC_IDLE = False if len(var.ROLES["succubus"]) == 0: - entranced_alive = ENTRANCED - set(evt.params.deadlist) + entranced_alive = {users._get(x) for x in ENTRANCED}.difference(evt.params.deadlist) # FIXME if ALL_SUCC_IDLE: while ENTRANCED: e = ENTRANCED.pop() @@ -198,7 +198,7 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): comma = "," for e in entranced_alive: if var.ROLE_REVEAL in ("on", "team"): - role = get_reveal_role(e) + role = get_reveal_role(e.nick) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" msg.append("\u0002{0}\u0002, a{1} \u0002{2}\u0002".format(e, an, role)) else: @@ -214,8 +214,8 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): # killing off everyone else that is entranced so they don't need to bother dlc = list(evt.params.deadlist) dlc.extend(entranced_alive - {e}) - debuglog("{0} (succubus) SUCCUBUS DEATH KILL: {1} ({2})".format(user, e, get_role(e))) - evt.params.del_player(user.client, e, end_game=False, killer_role="succubus", + debuglog("{0} (succubus) SUCCUBUS DEATH KILL: {1} ({2})".format(user, e, get_main_role(e))) + evt.params.del_player(e, end_game=False, killer_role="succubus", deadlist=dlc, original=evt.params.original, ismain=False) evt.data["pl"] = evt.params.refresh_pl(evt.data["pl"]) ENTRANCED_DYING.clear() diff --git a/src/roles/traitor.py b/src/roles/traitor.py index 1770d7b..fc3bfbb 100644 --- a/src/roles/traitor.py +++ b/src/roles/traitor.py @@ -7,7 +7,7 @@ from collections import defaultdict import botconfig import src.settings as var from src.utilities import * -from src import debuglog, errlog, plog, users +from src import debuglog, errlog, plog, users, channels from src.decorators import cmd, event_listener from src.messages import messages from src.events import Event @@ -29,19 +29,19 @@ def on_get_final_role(evt, cli, var, nick, role): evt.data["role"] = "traitor" @event_listener("update_stats", priority=1) -def on_update_stats1(evt, cli, var, nick, nickrole, nickreveal, nicktpls): - if nickrole == var.DEFAULT_ROLE and var.HIDDEN_TRAITOR: +def on_update_stats1(evt, var, player, mainrole, revealroles, allroles): + if mainrole == var.DEFAULT_ROLE and var.HIDDEN_TRAITOR: evt.data["possible"].add("traitor") @event_listener("update_stats", priority=3) -def on_update_stats3(evt, cli, var, nick, nickrole, nickreveal, nicktpls): +def on_update_stats3(evt, var, player, mainrole, revealroles, allroles): # if this is a night death and we know for sure that wolves (and only wolves) # killed, then that kill cannot be traitor as long as they're in wolfchat. # ismain True = night death, False = chain death; chain deaths can be traitors # even if only wolves killed, so we short-circuit there as well # TODO: an observant user will be able to determine if traitor dies due to luck/misdirection totem # redirecting a wolf kill onto traitor - if "traitor" not in evt.data["possible"] or not evt.params.ismain or nickrole == "traitor": + if "traitor" not in evt.data["possible"] or not evt.params.ismain or mainrole == "traitor": return if var.PHASE == "day" and var.GAMEPHASE == "night": mevt = Event("get_role_metadata", {}) diff --git a/src/roles/vengefulghost.py b/src/roles/vengefulghost.py index f9838a0..50e01c4 100644 --- a/src/roles/vengefulghost.py +++ b/src/roles/vengefulghost.py @@ -89,7 +89,7 @@ def on_player_win(evt, var, user, role, winner, survived): evt.data["iwon"] = False @event_listener("del_player", priority=6) -def on_del_player(evt, var, user, nickrole, nicktpls, death_triggers): +def on_del_player(evt, var, user, mainrole, allroles, death_triggers): for h, v in list(KILLS.items()): if user is v: h.send(messages["hunter_discard"]) @@ -97,7 +97,7 @@ def on_del_player(evt, var, user, nickrole, nicktpls, death_triggers): # extending VG to work with new teams can be done by registering a listener # at priority < 6, importing src.roles.vengefulghost, and setting # GHOSTS[user] to something; if that is done then this logic is not run. - if death_triggers and nickrole == "vengeful ghost" and user not in GHOSTS: + if death_triggers and mainrole == "vengeful ghost" and user not in GHOSTS: if evt.params.killer_role in var.WOLFTEAM_ROLES: GHOSTS[user] = "wolves" else: diff --git a/src/roles/vigilante.py b/src/roles/vigilante.py index d1ce7f8..f693c9f 100644 --- a/src/roles/vigilante.py +++ b/src/roles/vigilante.py @@ -4,7 +4,7 @@ from collections import defaultdict import src.settings as var from src.utilities import * -from src import users, debuglog, errlog, plog +from src import users, channels, debuglog, errlog, plog from src.functions import get_players, get_all_players, get_main_role from src.decorators import cmd, event_listener from src.messages import messages diff --git a/src/roles/villager.py b/src/roles/villager.py index e426065..9b39c40 100644 --- a/src/roles/villager.py +++ b/src/roles/villager.py @@ -1,6 +1,6 @@ import src.settings as var from src.utilities import * -from src import debuglog, errlog, plog +from src import users, channels, debuglog, errlog, plog from src.functions import get_players from src.decorators import cmd, event_listener from src.messages import messages diff --git a/src/roles/wildchild.py b/src/roles/wildchild.py index 5539e49..31db765 100644 --- a/src/roles/wildchild.py +++ b/src/roles/wildchild.py @@ -3,7 +3,7 @@ import re import src.settings as var from src.utilities import * -from src import users, debuglog, errlog, plog +from src import users, channels, debuglog, errlog, plog from src.functions import get_players, get_all_players, get_main_role from src.decorators import cmd, event_listener from src.messages import messages @@ -85,7 +85,7 @@ def on_del_player(evt, var, user, mainrole, allroles, death_triggers): return for child in get_all_players(("wild child",)): - if child.nick not in IDOLS or child.nick in evt.params.deadlist or IDOLS[child.nick] not in evt.params.deadlist: + if child.nick not in IDOLS or child in evt.params.deadlist or users._get(IDOLS[child.nick]) not in evt.params.deadlist: # FIXME continue # change their main role to wolf, even if wild child was a template diff --git a/src/roles/wolf.py b/src/roles/wolf.py index 62b5035..1c53021 100644 --- a/src/roles/wolf.py +++ b/src/roles/wolf.py @@ -5,7 +5,7 @@ from collections import defaultdict import src.settings as var from src.utilities import * from src.functions import get_players, get_all_players, get_main_role, get_all_roles -from src import debuglog, errlog, plog, users +from src import debuglog, errlog, plog, users, channels from src.decorators import cmd, event_listener from src.messages import messages from src.events import Event @@ -241,7 +241,7 @@ def on_exchange(evt, var, actor, target, actor_role, target_role): if player is target: prole = actor_role wevt = Event("wolflist", {"tags": set()}) - wevt.dispatch(actor.client, var, player.nick, actor.nick) + wevt.dispatch(var, player, actor) tags = " ".join(wevt.data["tags"]) if prole in wcroles: if tags: @@ -274,7 +274,7 @@ def on_exchange(evt, var, actor, target, actor_role, target_role): if player is actor: prole = target_role wevt = Event("wolflist", {"tags": set()}) - wevt.dispatch(actor.client, var, player.nick, target.nick) + wevt.dispatch(var, player, target) tags = " ".join(wevt.data["tags"]) if prole in wcroles: if tags: @@ -363,7 +363,7 @@ def on_transition_night_end(evt, var): wevt = Event("wolflist", {"tags": set()}) tags = "" if role in wcroles: - wevt.dispatch(wolf.client, var, wolf.nick, wolf.nick) # FIXME: Need to update the wolflist event + wevt.dispatch(var, wolf, wolf) tags = " ".join(wevt.data["tags"]) if tags: tags += " " @@ -401,7 +401,7 @@ def on_transition_night_end(evt, var): for player in pl: prole = get_main_role(player) wevt.data["tags"] = set() - wevt.dispatch(wolf.client, var, player.nick, wolf.nick) # FIXME: Need to update the wolflist event + wevt.dispatch(var, player, wolf) tags = " ".join(wevt.data["tags"]) if prole in wcroles: if tags: diff --git a/src/roles/wolfcub.py b/src/roles/wolfcub.py index c0a7a5c..78dc4c5 100644 --- a/src/roles/wolfcub.py +++ b/src/roles/wolfcub.py @@ -5,7 +5,7 @@ from collections import defaultdict import src.settings as var from src.utilities import * from src.functions import get_players -from src import debuglog, errlog, plog, users +from src import debuglog, errlog, plog, users, channels from src.decorators import cmd, event_listener from src.messages import messages from src.events import Event @@ -78,7 +78,7 @@ def on_chk_win(evt, cli, var, rolemap, mainroles, lpl, lwolves, lrealwolves): evt.stop_processing = True @event_listener("reconfigure_stats") -def on_reconfigure_stats(evt, cli, var, stats): +def on_reconfigure_stats(evt, var, stats): if "wolf cub" not in stats or stats["wolf cub"] == 0: return for role in var.WOLF_ROLES - {"wolf cub"}: diff --git a/src/wolfgame.py b/src/wolfgame.py index 32830b4..cdc8c6a 100644 --- a/src/wolfgame.py +++ b/src/wolfgame.py @@ -49,7 +49,7 @@ import src.settings as var from src.utilities import * from src import db, events, dispatcher, channels, users, hooks, logger, proxy, debuglog, errlog, plog from src.decorators import command, cmd, hook, handle_error, event_listener, COMMANDS -from src.functions import get_players, get_all_players, get_participants, get_main_role +from src.functions import get_players, get_all_players, get_participants, get_main_role, get_all_roles from src.messages import messages from src.warnings import * from src.context import IRCContext @@ -1084,7 +1084,7 @@ def fleave(var, wrapper, message): return msg = [messages["fquit_success"].format(wrapper.source, target)] - if get_role(target.nick) != "person" and var.ROLE_REVEAL in ("on", "team"): + if get_main_role(target) != "person" and var.ROLE_REVEAL in ("on", "team"): msg.append(messages["fquit_goodbye"].format(get_reveal_role(target.nick))) if var.PHASE == "join": player_count = len(list_players()) - 1 @@ -1103,7 +1103,7 @@ def fleave(var, wrapper, message): if target.nick in var.PLAYERS: var.DCED_PLAYERS[target.nick] = var.PLAYERS.pop(target.nick) - del_player(wrapper.client, target.nick, death_triggers=False) # FIXME: Need to fix once del_player is updated + del_player(target, death_triggers=False) elif dead_target is not None: leave_deadchat(var, dead_target, force=wrapper.source) @@ -1167,7 +1167,7 @@ def stats(cli, nick, chan, rest): for i, player in enumerate(ps): prole = get_role(player) wevt = Event("wolflist", {"tags": set()}) - wevt.dispatch(cli, var, player, nick) + wevt.dispatch(var, users._get(player), users._get(nick)) # FIXME tags = " ".join(wevt.data["tags"]) if prole in badguys: if tags: @@ -1885,7 +1885,8 @@ def chk_decision(cli, force=""): else: lmsg = random.choice(messages["lynch_no_reveal"]).format(votee) cli.msg(botconfig.CHANNEL, lmsg) - if not del_player(cli, votee, True, killer_role="villager", deadlist=deadlist, original=votee): + better_deadlist = [users._get(p) for p in deadlist] # FIXME -- convert chk_decision_lynch to be user-aware + if not del_player(users._get(votee), killer_role="villager", deadlist=better_deadlist): # FIXME return do_night_transision = True break @@ -2371,166 +2372,171 @@ def chk_win_conditions(cli, rolemap, mainroles, end_game=True, winner=None): return True @handle_error -def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death_triggers=True, killer_role="", deadlist=[], original="", cmode=[], deadchat=[], ismain=True): +def del_player(player, *, devoice=True, end_game=True, death_triggers=True, killer_role="", deadlist=[], original=None, cmode=[], deadchat=[], ismain=True): """ Returns: False if one side won. - arg: forced_death = True when lynched """ def refresh_pl(old_pl): - return [p for p in list_players() if p in old_pl] + return set(p for p in get_players() if p in old_pl) t = time.time() # time var.LAST_STATS = None # reset var.LAST_VOTES = None + if original is None: + original = player + with var.GRAVEYARD_LOCK: if not var.GAME_ID or var.GAME_ID > t: # either game ended, or a new game has started. return False ret = True - pl = list_players() - for dead in deadlist: - if dead in pl: - pl.remove(dead) - if nick != None and (nick == original or nick in pl): - nickrole = get_role(nick) - nickreveal = get_reveal_role(nick) - nicktpls = get_templates(nick) - allroles = {nickrole} | set(nicktpls) - del var.MAIN_ROLES[users._get(nick)] # FIXME - var.ROLES[nickrole].remove(nick) - for t in nicktpls: - var.ROLES[t].remove(nick) - if nick in var.BITTEN_ROLES: - del var.BITTEN_ROLES[nick] - if nick in var.CHARMED: - var.CHARMED.remove(nick) - if nick in pl: - pl.remove(nick) + pl = set(get_players()).difference(deadlist) + if player is not None and (player is original or player in pl): + mainrole = get_main_role(player) + revealrole = get_reveal_role(player.nick) # FIXME + allroles = get_all_roles(player) + del var.MAIN_ROLES[player] + for r in allroles: + var.ROLES[r].remove(player.nick) # FIXME + if player.nick in var.BITTEN_ROLES: + del var.BITTEN_ROLES[player.nick] # FIXME + if player.nick in var.CHARMED: + var.CHARMED.remove(player.nick) # FIXME + pl.discard(player) # handle roles that trigger on death # clone happens regardless of death_triggers being true or not if var.PHASE in var.GAME_PHASES: - clones = copy.copy(var.ROLES["clone"]) + clones = get_all_players(("clone",)) for clone in clones: - if clone in var.CLONED and clone not in deadlist: - target = var.CLONED[clone] - if nick == target and clone in var.CLONED: + # clone is a User, var.CLONED is a Dict[str,str] + # dealist is a List[User]; ensure we add .nick appropriately + # FIXME: someone should convert var.CLONED + if clone.nick in var.CLONED and clone not in deadlist: + target = var.CLONED[clone.nick] + if player.nick == target and clone.nick in var.CLONED: # clone is cloning nick, so clone becomes nick's role # clone does NOT get any of nick's templates (gunner/assassin/etc.) - del var.CLONED[clone] - if nickrole == "amnesiac": + del var.CLONED[clone.nick] + if mainrole == "amnesiac": # clone gets the amnesiac's real role - sayrole = var.AMNESIAC_ROLES[nick] + sayrole = var.AMNESIAC_ROLES[player.nick] else: - sayrole = nickrole - change_role(users._get(clone), "clone", sayrole) # FIXME + sayrole = mainrole + change_role(clone, "clone", sayrole) debuglog("{0} (clone) CLONE DEAD PLAYER: {1} ({2})".format(clone, target, sayrole)) if sayrole in var.HIDDEN_VILLAGERS: sayrole = "villager" elif sayrole in var.HIDDEN_ROLES: sayrole = var.DEFAULT_ROLE an = "n" if sayrole.startswith(("a", "e", "i", "o", "u")) else "" - pm(cli, clone, messages["clone_turn"].format(an, sayrole)) + clone.send(messages["clone_turn"].format(an, sayrole)) # if a clone is cloning a clone, clone who the old clone cloned - if nickrole == "clone" and nick in var.CLONED: - if var.CLONED[nick] == clone: - pm(cli, clone, messages["forever_aclone"].format(nick)) + if mainrole == "clone" and player.nick in var.CLONED: + if var.CLONED[player.nick] == clone.nick: + clone.send(messages["forever_aclone"].format(player)) else: - var.CLONED[clone] = var.CLONED[nick] - pm(cli, clone, messages["clone_success"].format(var.CLONED[clone])) - debuglog("{0} (clone) CLONE: {1} ({2})".format(clone, var.CLONED[clone], get_role(var.CLONED[clone]))) - elif nickrole in var.WOLFCHAT_ROLES: - wolves = list_players(var.WOLFCHAT_ROLES) + var.CLONED[clone.nick] = var.CLONED[player.nick] + clone.send(messages["clone_success"].format(var.CLONED[clone.nick])) + # FIXME: change below to get_main_role(var.CLONED[clone]) once var.CLONED is converted + debuglog("{0} (clone) CLONE: {1} ({2})".format(clone, var.CLONED[clone.nick], get_role(var.CLONED[clone.nick]))) + elif mainrole in var.WOLFCHAT_ROLES: + wolves = get_players(var.WOLFCHAT_ROLES) wolves.remove(clone) # remove self from list for wolf in wolves: - pm(cli, wolf, messages["clone_wolf"].format(clone, nick)) + wolf.queue_message(messages["clone_wolf"].format(clone, player)) + if wolves: + wolf.send_messages() if var.PHASE == "day": random.shuffle(wolves) for i, wolf in enumerate(wolves): - wolfrole = get_role(wolf) + wolfrole = get_main_role(wolf) wevt = Event("wolflist", {"tags": set()}) - wevt.dispatch(cli, var, wolf, clone) + wevt.dispatch(var, wolf, clone) tags = " ".join(wevt.data["tags"]) if tags: tags += " " wolves[i] = "\u0002{0}\u0002 ({1}{2})".format(wolf, tags, wolfrole) - if len(wolves): - pm(cli, clone, "Wolves: " + ", ".join(wolves)) + if wolves: + clone.send("Wolves: " + ", ".join(wolves)) else: - pm(cli, clone, messages["no_other_wolves"]) - elif nickrole == "turncoat": - var.TURNCOATS[clone] = ("none", -1) + clone.send(messages["no_other_wolves"]) + elif mainrole == "turncoat": + var.TURNCOATS[clone.nick] = ("none", -1) # FIXME - if nickrole == "clone" and nick in var.CLONED: - del var.CLONED[nick] + if mainrole == "clone" and player.nick in var.CLONED: + del var.CLONED[player.nick] if death_triggers and var.PHASE in var.GAME_PHASES: - if nick in var.LOVERS: - others = var.LOVERS[nick].copy() - var.LOVERS[nick].clear() - for other in others: - if other not in pl: + 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 nick not in var.LOVERS[other]: + if player.nick not in var.LOVERS[lover.nick]: continue - var.LOVERS[other].remove(nick) + var.LOVERS[lover.nick].remove(player.nick) if var.ROLE_REVEAL in ("on", "team"): - role = get_reveal_role(other) + role = get_reveal_role(lover.nick) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" - message = messages["lover_suicide"].format(other, an, role) + message = messages["lover_suicide"].format(lover, an, role) else: - message = messages["lover_suicide_no_reveal"].format(other) - cli.msg(botconfig.CHANNEL, message) - debuglog("{0} ({1}) LOVE SUICIDE: {2} ({3})".format(other, get_role(other), nick, nickrole)) - del_player(cli, other, True, end_game = False, killer_role = killer_role, deadlist = deadlist, original = original, ismain = False) + 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) - if "assassin" in nicktpls: - if nick in var.TARGETED: - target = var.TARGETED[nick] - del var.TARGETED[nick] + if "assassin" in allroles: + if player.nick in var.TARGETED: + targetnick = var.TARGETED[player.nick] + del var.TARGETED[player.nick] + if targetnick is None: + target = None + else: + target = users._get(targetnick) # FIXME if target is not None and target in pl: - targuser = users._get(target) # FIXME - prots = deque(var.ACTIVE_PROTECTIONS[target]) - aevt = Event("assassinate", {"pl": pl, "target": targuser}, + prots = deque(var.ACTIVE_PROTECTIONS[target.nick]) + aevt = Event("assassinate", {"pl": pl, "target": target}, del_player=del_player, deadlist=deadlist, original=original, refresh_pl=refresh_pl, message_prefix="assassin_fail_", source="assassin", - killer=nick, - killer_mainrole=nickrole, + killer=player, + killer_mainrole=mainrole, killer_allroles=allroles, prots=prots) while len(prots) > 0: # an event can read the current active protection and cancel the assassination # if it cancels, it is responsible for removing the protection from var.ACTIVE_PROTECTIONS # so that it cannot be used again (if the protection is meant to be usable once-only) - if not aevt.dispatch(cli, var, nick, target, prots[0]): + if not aevt.dispatch(var, player, target, prots[0]): pl = aevt.data["pl"] - if targuser is not aevt.data["target"]: - targuser = aevt.data["target"] - target = targuser.nick - prots = deque(var.ACTIVE_PROTECTIONS[target]) + if target is not aevt.data["target"]: + target = aevt.data["target"] + prots = deque(var.ACTIVE_PROTECTIONS[target.nick]) aevt.params.prots = prots continue break prots.popleft() if len(prots) == 0: if var.ROLE_REVEAL in ("on", "team"): - role = get_reveal_role(target) + role = get_reveal_role(target.nick) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" - message = messages["assassin_success"].format(nick, target, an, role) + message = messages["assassin_success"].format(player, target, an, role) else: - message = messages["assassin_success_no_reveal"].format(nick, target) - cli.msg(botconfig.CHANNEL, message) - debuglog("{0} (assassin) ASSASSINATE: {1} ({2})".format(nick, target, get_role(target))) - del_player(cli, target, True, end_game=False, killer_role=nickrole, deadlist=deadlist, original=original, ismain=False) + message = messages["assassin_success_no_reveal"].format(player, target) + channels.Main.send(message) + debuglog("{0} (assassin) ASSASSINATE: {1} ({2})".format(player, target, get_main_role(target))) + del_player(target, end_game=False, killer_role=mainrole, deadlist=deadlist, original=original, ismain=False) pl = refresh_pl(pl) - if nickrole == "time lord": + if mainrole == "time lord": if "DAY_TIME_LIMIT" not in var.ORIGINAL_SETTINGS: var.ORIGINAL_SETTINGS["DAY_TIME_LIMIT"] = var.DAY_TIME_LIMIT if "DAY_TIME_WARN" not in var.ORIGINAL_SETTINGS: @@ -2549,7 +2555,7 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death var.SHORT_DAY_WARN = var.TIME_LORD_DAY_WARN var.NIGHT_TIME_LIMIT = var.TIME_LORD_NIGHT_LIMIT var.NIGHT_TIME_WARN = var.TIME_LORD_NIGHT_WARN - cli.msg(botconfig.CHANNEL, messages["time_lord_dead"].format(var.TIME_LORD_DAY_LIMIT, var.TIME_LORD_NIGHT_LIMIT)) + channels.Main.send(messages["time_lord_dead"].format(var.TIME_LORD_DAY_LIMIT, var.TIME_LORD_NIGHT_LIMIT)) if var.GAMEPHASE == "day" and timeleft_internal("day") > var.DAY_TIME_LIMIT and var.DAY_TIME_LIMIT > 0: if "day" in var.TIMERS: var.TIMERS["day"][0].cancel() @@ -2557,7 +2563,7 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death var.TIMERS["day"] = (t, time.time(), var.DAY_TIME_LIMIT) t.daemon = True t.start() - # Don't duplicate warnings, e.g. only set the warn timer if a warning was not already given + # Don't duplicate warnings, i.e. only set the warn timer if a warning was not already given if "day_warn" in var.TIMERS and var.TIMERS["day_warn"][0].isAlive(): var.TIMERS["day_warn"][0].cancel() t = threading.Timer(var.DAY_TIME_WARN, hurry_up, [cli, var.DAY_ID, False]) @@ -2579,17 +2585,16 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death t.daemon = True t.start() - debuglog(nick, "(time lord) TRIGGER") + debuglog(player.nick, "(time lord) TRIGGER") pl = refresh_pl(pl) # i herd u liek parameters evt_death_triggers = death_triggers and var.PHASE in var.GAME_PHASES - user = users._get(nick) # FIXME event = Event("del_player", {"pl": pl}, - forced_death=forced_death, end_game=end_game, + end_game=end_game, deadlist=deadlist, original=original, killer_role=killer_role, ismain=ismain, refresh_pl=refresh_pl, del_player=del_player) - event.dispatch(var, user, nickrole, allroles, evt_death_triggers) + event.dispatch(var, player, mainrole, allroles, evt_death_triggers) # update var.ROLE_STATS # Event priorities: @@ -2597,15 +2602,15 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death # 3 = Removing from the possible set (e.g. can't be traitor if was a night kill and only wolves could kill at night), # 5 = Setting known_role to True if the role is actually known for sure publically (e.g. revealing totem) # 2 and 4 are not used by included roles, but may be useful expansion points for custom roles to modify stats - event = Event("update_stats", {"possible": {nickrole, nickreveal}, "known_role": False}, + event = Event("update_stats", {"possible": {mainrole, revealrole}, "known_role": False}, killer_role=killer_role, ismain=ismain) - event.dispatch(cli, var, nick, nickrole, nickreveal, nicktpls) + event.dispatch(var, player, mainrole, revealrole, allroles) # Given the set of possible roles this nick could be (or its actual role if known_role is True), # figure out the set of roles that need deducting from their counts in var.ROLE_STATS if event.data["known_role"]: # we somehow know the exact role that died (for example, we know traitor died even though they revealed as villager) # as a result, deduct only them - possible = {nickrole} + possible = {mainrole} else: possible = set(event.data["possible"]) newstats = set() @@ -2619,28 +2624,27 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death d = dict(rs) if p in d and d[p] >= 1: d[p] -= 1 - event.dispatch(cli, var, d) + event.dispatch(var, d) if min(d.values()) >= 0: newstats.add(frozenset(d.items())) var.ROLE_STATS = frozenset(newstats) if devoice and (var.PHASE != "night" or not var.DEVOICE_DURING_NIGHT): - cmode.append(("-v", nick)) - if users.exists(nick): - host = users.get(nick).host.lower() - acc = irc_lower(users.get(nick).account) - if acc not in var.DEADCHAT_PREFS_ACCS and host not in var.DEADCHAT_PREFS: - deadchat.append(users._get(nick)) # FIXME + cmode.append(("-v", player.nick)) + if not player.is_fake: + lplayer = player.lower() + if lplayer.account not in var.DEADCHAT_PREFS_ACCS and lplayer.host not in var.DEADCHAT_PREFS: + deadchat.append(player) # devoice all players that died as a result, if we are in the original del_player if ismain: - mass_mode(cli, cmode, []) + channels.Main.mode(*cmode) del cmode[:] if var.PHASE == "join": - if nick in var.GAMEMODE_VOTES: - del var.GAMEMODE_VOTES[nick] + if player.nick in var.GAMEMODE_VOTES: + del var.GAMEMODE_VOTES[player.nick] with var.WARNING_LOCK: - var.START_VOTES.discard(nick) + var.START_VOTES.discard(player.nick) # Cancel the start vote timer if there are no votes left if not var.START_VOTES and "start_votes" in var.TIMERS: @@ -2648,17 +2652,17 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death del var.TIMERS["start_votes"] # Died during the joining process as a person - for mode in var.OLD_MODES[users._get(nick)]: # FIXME - cmode.append(("+" + mode, nick)) - del var.OLD_MODES[users._get(nick)] - var.ALL_PLAYERS.remove(users._get(nick)) # FIXME - ret = not chk_win(cli) + for mode in var.OLD_MODES[player]: + cmode.append(("+" + mode, player.nick)) + del var.OLD_MODES[player] + var.ALL_PLAYERS.remove(player) + ret = not chk_win(channels.Main.client) # FIXME else: # Died during the game, so quiet! - if var.QUIET_DEAD_PLAYERS and not is_fake_nick(nick): - cmode.append(("+{0}".format(var.QUIET_MODE), var.QUIET_PREFIX+nick+"!*@*")) - var.DEAD.add(nick) - ret = not chk_win(cli, end_game) + if var.QUIET_DEAD_PLAYERS and not player.is_fake: + cmode.append(("+{0}".format(var.QUIET_MODE), var.QUIET_PREFIX+player.nick+"!*@*")) + var.DEAD.add(player.nick) + ret = not chk_win(channels.Main.client, end_game) # FIXME # only join to deadchat if the game isn't about to end if ismain: if ret: @@ -2667,36 +2671,36 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death if var.PHASE in var.GAME_PHASES: # remove the player from variables if they're in there if ret: - for x in (var.OBSERVED, var.HVISITED, var.TARGETED, var.LASTHEXED): + for x in (var.OBSERVED, var.TARGETED, var.LASTHEXED): for k in list(x): - if nick in (k, x[k]): + if player.nick in (k, x[k]): del x[k] - if nick in var.DISCONNECTED: - del var.DISCONNECTED[nick] + if player.nick in var.DISCONNECTED: + del var.DISCONNECTED[player.nick] if var.PHASE == "night": # 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 # if these aren't cleared properly night may end prematurely for x in (var.PASSED, var.HEXED, var.MATCHMAKERS, var.CURSED, var.CHARMERS): - x.discard(nick) - if var.PHASE == "day" and not forced_death and ret: # didn't die from lynching - var.VOTES.pop(nick, None) # Delete other people's votes on the player + x.discard(player.nick) + if var.PHASE == "day" and ret: + var.VOTES.pop(player.nick, None) # Delete other people's votes on the player for k in list(var.VOTES.keys()): - if nick in var.VOTES[k]: - var.VOTES[k].remove(nick) + if player.nick in var.VOTES[k]: + var.VOTES[k].remove(player.nick) if not var.VOTES[k]: # no more votes on that person del var.VOTES[k] break # can only vote once - var.NO_LYNCH.discard(nick) - var.WOUNDED.discard(nick) - var.CONSECRATING.discard(nick) + var.NO_LYNCH.discard(player.nick) + var.WOUNDED.discard(player.nick) + var.CONSECRATING.discard(player.nick) # note: PHASE = "day" and GAMEPHASE = "night" during transition_day; - # we only want to induce a lynch if it's actually day - if var.GAMEPHASE == "day": - chk_decision(cli) - elif var.PHASE == "night" and ret: - chk_nightdone(cli) + # we only want to induce a lynch if it's actually day and we aren't in a chained death + if var.GAMEPHASE == "day" and ismain: + chk_decision(channels.Main.client) + elif var.PHASE == "night" and ret and ismain: + chk_nightdone(channels.Main.client) return ret @@ -2772,7 +2776,7 @@ def reaper(cli, gameid): var.ORIGINAL_ROLES[r].add("(dced)"+nck) if var.IDLE_PENALTY: add_warning(cli, nck, var.IDLE_PENALTY, botconfig.NICK, messages["idle_warning"], expires=var.IDLE_EXPIRY) - del_player(cli, nck, end_game = False, death_triggers = False) + del_player(users._get(nck), end_game=False, death_triggers=False) # FIXME chk_win(cli) pl = list_players() x = [a for a in to_warn if a in pl] @@ -2789,7 +2793,7 @@ def reaper(cli, gameid): cli.msg(chan, messages["quit_death_no_reveal"].format(dcedplayer)) if var.PHASE != "join" and var.PART_PENALTY: add_warning(cli, dcedplayer, var.PART_PENALTY, botconfig.NICK, messages["quit_warning"], expires=var.PART_EXPIRY) - if not del_player(cli, dcedplayer, devoice = False, death_triggers = False): + if not del_player(users._get(dcedplayer), devoice=False, death_triggers=False): # FIXME return elif what == "part" and (datetime.now() - timeofdc) > timedelta(seconds=var.PART_GRACE_TIME): if get_role(dcedplayer) != "person" and var.ROLE_REVEAL in ("on", "team"): @@ -2798,7 +2802,7 @@ def reaper(cli, gameid): cli.msg(chan, messages["part_death_no_reveal"].format(dcedplayer)) if var.PHASE != "join" and var.PART_PENALTY: add_warning(cli, dcedplayer, var.PART_PENALTY, botconfig.NICK, messages["part_warning"], expires=var.PART_EXPIRY) - if not del_player(cli, dcedplayer, devoice = False, death_triggers = False): + if not del_player(users._get(dcedplayer), devoice=False, death_triggers=False): # FIXME return elif what == "account" and (datetime.now() - timeofdc) > timedelta(seconds=var.ACC_GRACE_TIME): if get_role(dcedplayer) != "person" and var.ROLE_REVEAL in ("on", "team"): @@ -2807,7 +2811,7 @@ def reaper(cli, gameid): cli.msg(chan, messages["account_death_no_reveal"].format(dcedplayer)) if var.PHASE != "join" and var.ACC_PENALTY: add_warning(cli, dcedplayer, var.ACC_PENALTY, botconfig.NICK, messages["acc_warning"], expires=var.ACC_EXPIRY) - if not del_player(cli, dcedplayer, devoice = False, death_triggers = False): + if not del_player(users._get(dcedplayer), devoice=False, death_triggers=False): # FIXME return time.sleep(10) @@ -2999,8 +3003,7 @@ def rename_player(var, user, prefix): if prefix in var.PRAYED.keys(): del var.PRAYED[prefix] - for dictvar in (var.HVISITED, var.OBSERVED, var.TARGETED, - var.CLONED, var.LASTHEXED, var.BITE_PREFERENCES): + for dictvar in (var.OBSERVED, var.TARGETED, var.CLONED, var.LASTHEXED, var.BITE_PREFERENCES): kvp = [] for a,b in dictvar.items(): if a == prefix: @@ -3197,7 +3200,7 @@ def leave(var, what, user, why=None): population = " " + messages["new_player_count"].format(lpl) reveal = "" - if get_role(user.nick) == "person" or var.ROLE_REVEAL not in ("on", "team"): + if get_main_role(user) == "person" or var.ROLE_REVEAL not in ("on", "team"): reveal = "_no_reveal" grace_times = {"part": var.PART_GRACE_TIME, "quit": var.QUIT_GRACE_TIME, "account": var.ACC_GRACE_TIME, "leave": 0} @@ -3226,7 +3229,7 @@ def leave(var, what, user, why=None): var.USERS[user.nick]["moded"] = set() if killplayer: - del_player(user.client, user.nick, death_triggers=False) + del_player(user, death_triggers=False) else: temp = user.lower() var.DISCONNECTED[user.nick] = (temp.account, temp.userhost, datetime.now(), what) # FIXME: Need to make var.DISCONNECTED hold User instances @@ -3280,7 +3283,7 @@ def leave_game(cli, nick, chan, rest): if nick in var.PLAYERS: var.DCED_PLAYERS[nick] = var.PLAYERS.pop(nick) - del_player(cli, nick, death_triggers = False) + del_player(users._get(nick), death_triggers=False) # FIXME def begin_day(cli): chan = botconfig.CHANNEL @@ -3442,8 +3445,7 @@ def transition_day(cli, gameid=0): user = users._get(target) # FIXME evt = Event("night_acted", {"acted": False}) evt.dispatch(var, user, actor) - if ((target in var.HVISITED and var.HVISITED[target]) or - (target in var.PRAYED and var.PRAYED[target][0] > 0) or target in var.CHARMERS or + if ((target in var.PRAYED and var.PRAYED[target][0] > 0) or target in var.CHARMERS or target in var.OBSERVED or target in var.HEXED or target in var.CURSED or evt.data["acted"]): actor.send(messages["werecrow_success"].format(user)) else: @@ -3667,7 +3669,7 @@ def transition_day(cli, gameid=0): wolf.queue_message(messages["lycan_wc_notification"].format(victim)) role = get_main_role(wolf) wevt = Event("wolflist", {"tags": set()}) - wevt.dispatch(cli, var, wolf.nick, victim.nick) + wevt.dispatch(var, wolf, victim) tags = " ".join(wevt.data["tags"]) if tags: tags += " " @@ -3818,12 +3820,11 @@ def transition_day(cli, gameid=0): # no killers, so assume suicide killer_role[deadperson] = get_main_role(deadperson) - dead_nicks = [p.nick for p in dead] # FIXME: Update once del_player has been updated - for deadperson in dead: + for deadperson in dead[:]: # check if they have already been killed since del_player could do chain reactions and we want # to avoid sending duplicate messages. if deadperson in get_players(): - del_player(cli, deadperson.nick, end_game=False, killer_role=killer_role[deadperson], deadlist=dead_nicks, original=deadperson.nick) + del_player(deadperson, end_game=False, killer_role=killer_role[deadperson], deadlist=dead) event_end = Event("transition_day_end", {"begin_day": begin_day}) event_end.dispatch(var) @@ -4314,7 +4315,7 @@ def shoot(var, wrapper, message): wrapper.send(messages["gunner_victim_wolf_death"].format(victim,an, victimrole)) else: # off and team wrapper.send(messages["gunner_victim_wolf_death_no_reveal"].format(victim)) - if not del_player(wrapper.source.client, victim, killer_role=get_role(wrapper.source.nick)): + if not del_player(users._get(victim), killer_role=get_main_role(wrapper.source)): # FIXME return elif random.random() <= chances[3]: accident = "accidentally " @@ -4323,7 +4324,7 @@ def shoot(var, wrapper, message): wrapper.send(messages["gunner_victim_villager_death"].format(victim, accident)) if var.ROLE_REVEAL in ("on", "team"): wrapper.send(messages["gunner_victim_role"].format(an, victimrole)) - if not del_player(wrapper.source.client, victim, killer_role=get_role(wrapper.source.nick)): + if not del_player(users._get(victim), killer_role=get_main_role(wrapper.source)): # FIXME return else: wrapper.send(messages["gunner_victim_injured"].format(victim)) @@ -4344,7 +4345,7 @@ def shoot(var, wrapper, message): wrapper.send(messages["gunner_suicide"].format(wrapper.source.nick, get_reveal_role(wrapper.source.nick))) else: wrapper.send(messages["gunner_suicide_no_reveal"].format(wrapper.source.nick)) - if not del_player(wrapper.source.client, wrapper.source.nick, killer_role="villager"): # blame explosion on villager's shoddy gun construction or something + if not del_player(wrapper.source, killer_role="villager"): # blame explosion on villager's shoddy gun construction or something return # Someone won. def is_safe(nick, victim): # replace calls to this with targeted_command event when splitting roles @@ -5163,7 +5164,6 @@ def transition_night(cli): var.PASSED = set() var.OBSERVED = {} # those whom werecrows have observed var.CHARMERS = set() # pipers who have charmed - var.HVISITED = {} var.TOBESILENCED = set() var.CONSECRATING = set() for nick in var.PRAYED: @@ -5623,7 +5623,6 @@ def start(cli, nick, chan, forced = False, restart = ""): var.ROLES = {var.DEFAULT_ROLE: set()} var.GUNNERS = {} var.OBSERVED = {} - var.HVISITED = {} var.CLONED = {} var.TARGETED = {} var.LASTHEXED = {}