diff --git a/messages/en.json b/messages/en.json index 1e11519..f2ea3dc 100644 --- a/messages/en.json +++ b/messages/en.json @@ -463,7 +463,6 @@ "seer_ability": "the role of a player", "oracle_ability": "whether or not a player is a wolf", "augur_ability": "which team a player is on", - "seer_role_bug": "??? (this is a bug, please report to admins)", "seer_role_info": "You are {0} \u0002{1}\u0002. It is your job to detect the wolves, you may have a vision once per night. Use \"see \" to see {2}.", "seer_simple": "You are {0} \u0002{1}\u0002.", "harlot_info": "You are a \u0002harlot\u0002. You may spend the night with one person per round. If you visit a victim of a wolf, or visit a wolf, you will die. Use \"visit \" to visit a player or \"pass\" to stay home tonight.", diff --git a/src/roles/_seer_helper.py b/src/roles/_seer_helper.py new file mode 100644 index 0000000..19729ba --- /dev/null +++ b/src/roles/_seer_helper.py @@ -0,0 +1,69 @@ +import re +import random + +import src.settings as var +from src.utilities import * +from src import users, channels, debuglog, errlog, plog +from src.decorators import cmd, event_listener +from src.containers import UserList, UserSet, UserDict, DefaultUserDict +from src.functions import get_players, get_all_players, get_main_role +from src.messages import messages +from src.events import Event + +def setup_variables(rolename): + SEEN = UserSet() + + @event_listener("del_player") + def on_del_player(evt, var, user, mainrole, allroles, death_triggers): + SEEN.discard(user) + + @event_listener("night_acted") + def on_acted(evt, var, user, actor): + if user in SEEN: + evt.data["acted"] = True + + @event_listener("get_special") + def on_get_special(evt, var): + evt.data["special"].update(get_players((rolename,))) + + @event_listener("exchange_roles") + def on_exchange(evt, var, actor, target, actor_role, target_role): + if actor_role == rolename and target_role != rolename: + SEEN.discard(actor) + elif target_role == rolename and actor_role != rolename: + SEEN.discard(target) + + @event_listener("chk_nightdone") + def on_chk_nightdone(evt, var): + evt.data["actedcount"] += len(SEEN) + evt.data["nightroles"].extend(get_all_players((rolename,))) + + @event_listener("transition_night_end", priority=2) + def on_transition_night_end(evt, var): + for seer in get_all_players((rolename,)): + pl = get_players() + random.shuffle(pl) + pl.remove(seer) # remove self from list + + a = "a" + if rolename.startswith(("a", "e", "i", "o", "u")): + a = "an" + + what = messages[rolename + "_ability"] + + to_send = "seer_role_info" + if seer.prefers_simple(): + to_send = "seer_simple" + seer.send(messages[to_send].format(a, rolename, what), "Players: " + ", ".join(p.nick for p in pl), sep="\n") + + @event_listener("begin_day") + def on_begin_day(evt, var): + SEEN.clear() + + @event_listener("reset") + def on_reset(evt, var): + SEEN.clear() + + return SEEN + +# vim: set sw=4 expandtab: diff --git a/src/roles/_shaman_helper.py b/src/roles/_shaman_helper.py index 79b96c5..3157756 100644 --- a/src/roles/_shaman_helper.py +++ b/src/roles/_shaman_helper.py @@ -225,8 +225,8 @@ def give_totem(var, wrapper, target, prefix, tags, role, msg): return UserList((target, orig_target)) @event_listener("see", priority=10) -def on_see(evt, var, nick, victim): - if (users._get(victim) in DECEIT) ^ (users._get(nick) in DECEIT): # FIXME +def on_see(evt, var, seer, target): + if (seer in DECEIT) ^ (target in DECEIT): if evt.data["role"] in var.SEEN_WOLF and evt.data["role"] not in var.SEEN_DEFAULT: evt.data["role"] = "villager" else: diff --git a/src/roles/augur.py b/src/roles/augur.py new file mode 100644 index 0000000..be6298e --- /dev/null +++ b/src/roles/augur.py @@ -0,0 +1,53 @@ +import re +import random + +import src.settings as var +from src.utilities import * +from src import users, channels, debuglog, errlog, plog +from src.decorators import command, event_listener +from src.containers import UserList, UserSet, UserDict, DefaultUserDict +from src.functions import get_players, get_all_players, get_main_role, get_target +from src.messages import messages +from src.events import Event + +from src.roles._seer_helper import setup_variables + +SEEN = setup_variables("augur") + +@command("see", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("augur",)) +def see(var, wrapper, message): + """Use your paranormal powers to determine the role or alignment of a player.""" + if wrapper.source in SEEN: + wrapper.send(messages["seer_fail"]) + return + + target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_see_self") + if target is None: + return + + evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True}) + if not evt.dispatch(var, "identify", wrapper.source, target, frozenset({"info", "immediate"})): + return + + target = evt.data["target"] + targrole = get_main_role(target) + trole = targrole # keep a copy for logging + + if targrole == "amnesiac": + targrole = var.AMNESIAC_ROLES[target.nick] + + evt = Event("investigate", {"role": targrole}) + evt.dispatch(var, wrapper.source, target) + targrole = evt.data["role"] + + aura = "blue" + if targrole in var.WOLFTEAM_ROLES: + aura = "red" + elif targrole in var.TRUE_NEUTRAL_ROLES: + aura = "grey" + wrapper.send(messages["augur_success"].format(target, aura)) + debuglog("{0} (augur) SEE: {1} ({2}) as {3} ({4} aura)".format(wrapper.source, target, trole, targrole, aura)) + + SEEN.add(wrapper.source) + +# vim: set sw=4 expandtab: diff --git a/src/roles/cursed.py b/src/roles/cursed.py index 544668e..208b779 100644 --- a/src/roles/cursed.py +++ b/src/roles/cursed.py @@ -13,8 +13,8 @@ from src.messages import messages from src.events import Event @event_listener("see") -def on_see(evt, var, nick, victim): - if users._get(victim) in var.ROLES["cursed villager"]: # FIXME +def on_see(evt, var, seer, target): + if target in var.ROLES["cursed villager"]: evt.data["role"] = "wolf" @event_listener("wolflist") diff --git a/src/roles/detective.py b/src/roles/detective.py index 6daed9e..015b07b 100644 --- a/src/roles/detective.py +++ b/src/roles/detective.py @@ -5,47 +5,42 @@ import random import src.settings as var from src.utilities import * 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.functions import get_players, get_all_players, get_main_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 -INVESTIGATED = set() +INVESTIGATED = UserSet() -@cmd("id", chan=False, pm=True, playing=True, silenced=True, phases=("day",), roles=("detective",)) -def investigate(cli, nick, chan, rest): +@command("id", chan=False, pm=True, playing=True, silenced=True, phases=("day",), roles=("detective",)) +def investigate(var, wrapper, message): """Investigate a player to determine their exact role.""" - if nick in INVESTIGATED: - pm(cli, nick, messages["already_investigated"]) - return - victim = get_victim(cli, nick, re.split(" +",rest)[0], False) - if not victim: + if wrapper.source in INVESTIGATED: + wrapper.send(messages["already_investigated"]) return - if victim == nick: - pm(cli, nick, messages["no_investigate_self"]) + target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_investigate_self") + if target is None: return - det = users._get(nick) # FIXME - target = users._get(victim) # FIXME - evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True}) - evt.dispatch(var, "identify", det, target, frozenset({"info", "immediate"})) - if evt.prevent_default: + if not evt.dispatch(var, "identify", wrapper.source, target, frozenset({"info", "immediate"})): return - victim = evt.data["target"].nick - vrole = get_role(victim) - if vrole == "amnesiac": - vrole = var.AMNESIAC_ROLES[victim] - evt = Event("investigate", {"role": vrole}) - evt.dispatch(cli, var, nick, victim) - vrole = evt.data["role"] + target = evt.data["target"] + targrole = get_main_role(target) - INVESTIGATED.add(nick) - pm(cli, nick, (messages["investigate_success"]).format(victim, vrole)) - debuglog("{0} ({1}) ID: {2} ({3})".format(nick, get_role(nick), victim, vrole)) + if targrole == "amnesiac": + targrole = var.AMNESIAC_ROLES[target.nick] + + evt = Event("investigate", {"role": targrole}) + evt.dispatch(var, wrapper.source, target) + targrole = evt.data["role"] + + INVESTIGATED.add(wrapper.source) + wrapper.send(messages["investigate_success"].format(target, targrole)) + debuglog("{0} (detective) ID: {1} ({2})".format(wrapper.source, target, targrole)) if random.random() < var.DETECTIVE_REVEALED_CHANCE: # a 2/5 chance (should be changeable in settings) # The detective's identity is compromised! @@ -56,18 +51,17 @@ def investigate(cli, nick, chan, rest): else: wcroles = var.WOLF_ROLES | {"traitor"} - mass_privmsg(cli, list_players(wcroles), messages["detective_reveal"].format(nick)) - debuglog("{0} ({1}) PAPER DROP".format(nick, get_role(nick))) + wolves = get_all_players(wcroles) + if wolves: + for wolf in wolves: + wolf.queue_message(messages["detective_reveal"].format(wrapper.source)) + wolf.send_messages() -@event_listener("rename_player") -def on_rename(evt, var, prefix, nick): - if prefix in INVESTIGATED: - INVESTIGATED.remove(prefix) - INVESTIGATED.add(nick) + debuglog("{0} (detective) PAPER DROP".format(wrapper.source)) @event_listener("del_player") def on_del_player(evt, var, user, mainrole, allroles, death_triggers): - INVESTIGATED.discard(user.nick) + INVESTIGATED.discard(user) @event_listener("get_special") def on_get_special(evt, var): @@ -76,9 +70,9 @@ def on_get_special(evt, var): @event_listener("exchange_roles") def on_exchange(evt, var, actor, target, actor_role, target_role): if actor_role == "detective" and target_role != "detective": - INVESTIGATED.discard(actor.nick) + INVESTIGATED.discard(actor) elif target_role == "detective" and actor_role != "detective": - INVESTIGATED.discard(target.nick) + INVESTIGATED.discard(target) @event_listener("transition_night_end", priority=2) def on_transition_night_end(evt, var): diff --git a/src/roles/investigator.py b/src/roles/investigator.py index 8610620..23e6911 100644 --- a/src/roles/investigator.py +++ b/src/roles/investigator.py @@ -58,11 +58,11 @@ def investigate(var, wrapper, message): t2role = var.AMNESIAC_ROLES[target2.nick] evt = Event("investigate", {"role": t1role}) - evt.dispatch(wrapper.client, var, wrapper.source.nick, target1.nick) # FIXME + evt.dispatch(var, wrapper.source, target1) t1role = evt.data["role"] evt = Event("investigate", {"role": t2role}) - evt.dispatch(wrapper.client, var, wrapper.source.nick, target2.nick) # FIXME + evt.dispatch(var, wrapper.source, target2) t2role = evt.data["role"] # FIXME: make a standardized way of getting team affiliation, and make diff --git a/src/roles/oracle.py b/src/roles/oracle.py new file mode 100644 index 0000000..5bef959 --- /dev/null +++ b/src/roles/oracle.py @@ -0,0 +1,55 @@ +import re +import random + +import src.settings as var +from src.utilities import * +from src import users, channels, debuglog, errlog, plog +from src.decorators import command, event_listener +from src.containers import UserList, UserSet, UserDict, DefaultUserDict +from src.functions import get_players, get_all_players, get_main_role, get_target +from src.messages import messages +from src.events import Event + +from src.roles._seer_helper import setup_variables + +SEEN = setup_variables("oracle") + +@command("see", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("oracle",)) +def see(var, wrapper, message): + """Use your paranormal powers to determine the role or alignment of a player.""" + if wrapper.source in SEEN: + wrapper.send(messages["seer_fail"]) + return + + target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_see_self") + if target is None: + return + + evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True}) + if not evt.dispatch(var, "see", wrapper.source, target, frozenset({"info", "immediate"})): + return + + target = evt.data["target"] + targrole = get_main_role(target) + trole = targrole # keep a copy for logging + + if targrole in var.SEEN_WOLF and targrole not in var.SEEN_DEFAULT: + targrole = "wolf" + elif targrole in var.SEEN_DEFAULT: + targrole = var.DEFAULT_ROLE + if var.DEFAULT_SEEN_AS_VILL: + targrole = "villager" + + evt = Event("see", {"role": targrole}) + evt.dispatch(var, wrapper.source, target) + targrole = evt.data["role"] + + iswolf = False + if targrole in var.SEEN_WOLF and targrole not in var.SEEN_DEFAULT: + iswolf = True + wrapper.send(messages["oracle_success"].format(target, "" if iswolf else "\u0002not\u0002 ", "\u0002" if iswolf else "")) + debuglog("{0} (oracle) SEE: {1} ({2}) (Wolf: {3})".format(wrapper.source, target, trole, str(iswolf))) + + SEEN.add(wrapper.source) + +# vim: set sw=4 expandtab: diff --git a/src/roles/seer.py b/src/roles/seer.py index 4b10914..c8eb7ec 100644 --- a/src/roles/seer.py +++ b/src/roles/seer.py @@ -4,141 +4,49 @@ import random import src.settings as var from src.utilities import * from src import users, channels, debuglog, errlog, plog -from src.decorators import cmd, event_listener +from src.decorators import command, event_listener from src.containers import UserList, UserSet, UserDict, DefaultUserDict -from src.functions import get_players, get_all_players, get_main_role +from src.functions import get_players, get_all_players, get_main_role, get_target from src.messages import messages from src.events import Event -SEEN = set() +from src.roles._seer_helper import setup_variables -# FIXME: this needs to be split into seer.py, oracle.py, and augur.py -@cmd("see", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("seer", "oracle", "augur")) -def see(cli, nick, chan, rest): +SEEN = setup_variables("seer") + +@command("see", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("seer",)) +def see(var, wrapper, message): """Use your paranormal powers to determine the role or alignment of a player.""" - role = get_role(nick) - if nick in SEEN: - pm(cli, nick, messages["seer_fail"]) - return - victim = get_victim(cli, nick, re.split(" +",rest)[0], False) - if not victim: + if wrapper.source in SEEN: + wrapper.send(messages["seer_fail"]) return - if victim == nick: - pm(cli, nick, messages["no_see_self"]) + target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_see_self") + if target is None: return - seer = users._get(nick) # FIXME - target = users._get(victim) # FIXME - evt = Event("targeted_command", {"target": target, "misdirection": True, "exchange": True}) - evt.dispatch(var, "see", seer, target, frozenset({"info", "immediate"})) - if evt.prevent_default: + if not evt.dispatch(var, "see", wrapper.source, target, frozenset({"info", "immediate"})): return - victim = evt.data["target"].nick - victimrole = get_role(victim) - vrole = victimrole # keep a copy for logging - if role != "augur": - if (victimrole in var.SEEN_WOLF and victimrole not in var.SEEN_DEFAULT): - victimrole = "wolf" - elif victimrole in var.SEEN_DEFAULT: - victimrole = var.DEFAULT_ROLE - if var.DEFAULT_SEEN_AS_VILL: - victimrole = "villager" + target = evt.data["target"] + targrole = get_main_role(target) + trole = targrole # keep a copy for logging - evt = Event("see", {"role": victimrole}) - evt.dispatch(var, nick, victim) - victimrole = evt.data["role"] - else: - if victimrole == "amnesiac": - victimrole = var.AMNESIAC_ROLES[victim] + if targrole in var.SEEN_WOLF and targrole not in var.SEEN_DEFAULT: + targrole = "wolf" + elif targrole in var.SEEN_DEFAULT: + targrole = var.DEFAULT_ROLE + if var.DEFAULT_SEEN_AS_VILL: + targrole = "villager" - evt = Event("investigate", {"role": victimrole}) - evt.dispatch(cli, var, nick, victim) - victimrole = evt.data["role"] + evt = Event("see", {"role": targrole}) + evt.dispatch(var, wrapper.source, target) + targrole = evt.data["role"] - if role == "seer": - pm(cli, nick, (messages["seer_success"]).format(victim, victimrole)) - debuglog("{0} ({1}) SEE: {2} ({3}) as {4}".format(nick, role, victim, vrole, victimrole)) - elif role == "oracle": - iswolf = False - if (victimrole in var.SEEN_WOLF and victimrole not in var.SEEN_DEFAULT): - iswolf = True - pm(cli, nick, (messages["oracle_success"]).format(victim, "" if iswolf else "\u0002not\u0002 ", "\u0002" if iswolf else "")) - debuglog("{0} ({1}) SEE: {2} ({3}) (Wolf: {4})".format(nick, role, victim, vrole, str(iswolf))) - elif role == "augur": - aura = "blue" - if victimrole in var.WOLFTEAM_ROLES: - aura = "red" - elif victimrole in var.TRUE_NEUTRAL_ROLES: - aura = "grey" - pm(cli, nick, (messages["augur_success"]).format(victim, aura)) - debuglog("{0} ({1}) SEE: {2} ({3}) as {4} ({5} aura)".format(nick, role, victim, vrole, victimrole, aura)) + wrapper.send(messages["seer_success"].format(target, targrole)) + debuglog("{0} (seer) SEE: {1} ({2}) as {3}".format(wrapper.source, target, trole, targrole)) - SEEN.add(nick) - -@event_listener("rename_player") -def on_rename(evt, var, prefix, nick): - if prefix in SEEN: - SEEN.remove(prefix) - SEEN.add(nick) - -@event_listener("del_player") -def on_del_player(evt, var, user, mainrole, allroles, death_triggers): - SEEN.discard(user.nick) - -@event_listener("night_acted") -def on_acted(evt, var, user, actor): - if user.nick in SEEN: - evt.data["acted"] = True - -@event_listener("get_special") -def on_get_special(evt, var): - evt.data["special"].update(get_players(("seer", "oracle", "augur"))) - -@event_listener("exchange_roles") -def on_exchange(evt, var, actor, target, actor_role, target_role): - if actor_role in ("seer", "oracle", "augur"): - SEEN.discard(actor.nick) - -@event_listener("chk_nightdone") -def on_chk_nightdone(evt, var): - evt.data["actedcount"] += len(SEEN) - evt.data["nightroles"].extend(get_all_players(("seer", "oracle", "augur"))) - -@event_listener("transition_night_end", priority=2) -def on_transition_night_end(evt, var): - for seer in get_players(("seer", "oracle", "augur")): - pl = get_players() - random.shuffle(pl) - role = get_main_role(seer) - pl.remove(seer) # remove self from list - - a = "a" - if role in ("oracle", "augur"): - a = "an" - - if role == "seer": - what = messages["seer_ability"] - elif role == "oracle": - what = messages["oracle_ability"] - elif role == "augur": - what = messages["augur_ability"] - else: - what = messages["seer_role_bug"] - - to_send = "seer_role_info" - if seer.prefers_simple(): - to_send = "seer_simple" - seer.send(messages[to_send].format(a, role, what), "Players: " + ", ".join(p.nick for p in pl), sep="\n") - -@event_listener("begin_day") -def on_begin_day(evt, var): - SEEN.clear() - -@event_listener("reset") -def on_reset(evt, var): - SEEN.clear() + SEEN.add(wrapper.source) # vim: set sw=4 expandtab: diff --git a/src/roles/traitor.py b/src/roles/traitor.py index 2e504ee..f517c0e 100644 --- a/src/roles/traitor.py +++ b/src/roles/traitor.py @@ -29,7 +29,7 @@ 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, var, player, mainrole, revealroles, allroles): +def on_update_stats1(evt, var, player, mainrole, revealrole, allroles): if mainrole == var.DEFAULT_ROLE and var.HIDDEN_TRAITOR: evt.data["possible"].add("traitor") diff --git a/src/roles/wildchild.py b/src/roles/wildchild.py index 0cfa16d..8388bae 100644 --- a/src/roles/wildchild.py +++ b/src/roles/wildchild.py @@ -36,8 +36,8 @@ def choose_idol(cli, nick, chan, rest): debuglog("{0} (wild child) IDOLIZE: {1} ({2})".format(nick, victim, get_role(victim))) @event_listener("see") -def on_see(evt, var, seer, victim): - if victim in WILD_CHILDREN: +def on_see(evt, var, seer, target): + if target.nick in WILD_CHILDREN: evt.data["role"] = "wild child" @event_listener("rename_player")