Merge pull request #304 from lykoss/split_piper
Split piper and convert it to new APIs
This commit is contained in:
commit
1ce4360f3e
@ -396,7 +396,6 @@
|
|||||||
"already_cursed": "You have already cursed someone tonight.",
|
"already_cursed": "You have already cursed someone tonight.",
|
||||||
"warlock_pass": "You have chosen not to curse anyone tonight.",
|
"warlock_pass": "You have chosen not to curse anyone tonight.",
|
||||||
"warlock_pass_wolfchat": "\u0002{0}\u0002 has chosen not to curse anyone tonight.",
|
"warlock_pass_wolfchat": "\u0002{0}\u0002 has chosen not to curse anyone tonight.",
|
||||||
"already_charmed": "You have already charmed players tonight.",
|
|
||||||
"piper_pass": "You have chosen not to charm anyone tonight.",
|
"piper_pass": "You have chosen not to charm anyone tonight.",
|
||||||
"turncoat_already_turned": "You have changed sides yesterday night, and may not do so again tonight.",
|
"turncoat_already_turned": "You have changed sides yesterday night, and may not do so again tonight.",
|
||||||
"turncoat_error": "Please specify which team you wish to side with, villagers or wolves.",
|
"turncoat_error": "Please specify which team you wish to side with, villagers or wolves.",
|
||||||
@ -422,7 +421,6 @@
|
|||||||
"clone_target_success": "You have chosen to clone \u0002{0}\u0002.",
|
"clone_target_success": "You have chosen to clone \u0002{0}\u0002.",
|
||||||
"clone_clone_clone": "Ambiguous command; if you would like to clone someone whose name is or starts with \"clone\", please use \"clone clone clone\".",
|
"clone_clone_clone": "Ambiguous command; if you would like to clone someone whose name is or starts with \"clone\", please use \"clone clone clone\".",
|
||||||
"must_charm_multiple": "You must choose two different people.",
|
"must_charm_multiple": "You must choose two different people.",
|
||||||
"no_charm_self": "You may not charm yourself.",
|
|
||||||
"targets_already_charmed": "\u0002{0}\u0002 and \u0002{1}\u0002 are already charmed!",
|
"targets_already_charmed": "\u0002{0}\u0002 and \u0002{1}\u0002 are already charmed!",
|
||||||
"target_already_charmed": "\u0002{0}\u0002 is already charmed!",
|
"target_already_charmed": "\u0002{0}\u0002 is already charmed!",
|
||||||
"charm_success": "You have charmed \u0002{0}\u0002.",
|
"charm_success": "You have charmed \u0002{0}\u0002.",
|
||||||
|
@ -37,7 +37,7 @@ def get_participants():
|
|||||||
evt.dispatch(var)
|
evt.dispatch(var)
|
||||||
return evt.data["players"]
|
return evt.data["players"]
|
||||||
|
|
||||||
def get_target(var, wrapper, message, *, allow_self=False, allow_bot=False):
|
def get_target(var, wrapper, message, *, allow_self=False, allow_bot=False, not_self_message=None):
|
||||||
if not message:
|
if not message:
|
||||||
wrapper.pm(messages["not_enough_parameters"])
|
wrapper.pm(messages["not_enough_parameters"])
|
||||||
return
|
return
|
||||||
@ -52,7 +52,8 @@ def get_target(var, wrapper, message, *, allow_self=False, allow_bot=False):
|
|||||||
match, count = users.complete_match(message, players)
|
match, count = users.complete_match(message, players)
|
||||||
if match is None:
|
if match is None:
|
||||||
if not count and users.lower(wrapper.source.nick).startswith(users.lower(message)):
|
if not count and users.lower(wrapper.source.nick).startswith(users.lower(message)):
|
||||||
return wrapper.source
|
wrapper.pm(messages[not_self_message or "no_target_self"])
|
||||||
|
return
|
||||||
wrapper.pm(messages["not_playing"].format(message))
|
wrapper.pm(messages["not_playing"].format(message))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -21,14 +21,10 @@ def dullahan_kill(var, wrapper, message):
|
|||||||
wrapper.pm(messages["dullahan_targets_dead"])
|
wrapper.pm(messages["dullahan_targets_dead"])
|
||||||
return
|
return
|
||||||
|
|
||||||
target = get_target(var, wrapper, re.split(" +", message)[0])
|
target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_suicide")
|
||||||
if not target:
|
if not target:
|
||||||
return
|
return
|
||||||
|
|
||||||
if target is wrapper.source:
|
|
||||||
wrapper.pm(messages["no_suicide"])
|
|
||||||
return
|
|
||||||
|
|
||||||
orig = target
|
orig = target
|
||||||
evt = Event("targeted_command", {"target": target.nick, "misdirection": True, "exchange": True})
|
evt = Event("targeted_command", {"target": target.nick, "misdirection": True, "exchange": True})
|
||||||
evt.dispatch(wrapper.client, var, "kill", wrapper.source.nick, target.nick, frozenset({"detrimental"}))
|
evt.dispatch(wrapper.client, var, "kill", wrapper.source.nick, target.nick, frozenset({"detrimental"}))
|
||||||
|
@ -20,14 +20,10 @@ def hunter_kill(var, wrapper, message):
|
|||||||
if wrapper.source in HUNTERS and wrapper.source not in KILLS:
|
if wrapper.source in HUNTERS and wrapper.source not in KILLS:
|
||||||
wrapper.pm(messages["hunter_already_killed"])
|
wrapper.pm(messages["hunter_already_killed"])
|
||||||
return
|
return
|
||||||
target = get_target(var, wrapper, re.split(" +", message)[0])
|
target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="no_suicide")
|
||||||
if not target:
|
if not target:
|
||||||
return
|
return
|
||||||
|
|
||||||
if wrapper.source is target:
|
|
||||||
wrapper.pm(messages["no_suicide"])
|
|
||||||
return
|
|
||||||
|
|
||||||
orig = target
|
orig = target
|
||||||
evt = Event("targeted_command", {"target": target.nick, "misdirection": True, "exchange": True})
|
evt = Event("targeted_command", {"target": target.nick, "misdirection": True, "exchange": True})
|
||||||
evt.dispatch(wrapper.client, var, "kill", wrapper.source.nick, target.nick, frozenset({"detrimental"}))
|
evt.dispatch(wrapper.client, var, "kill", wrapper.source.nick, target.nick, frozenset({"detrimental"}))
|
||||||
|
@ -15,7 +15,7 @@ def on_exchange(evt, var, actor, target, actor_role, target_role):
|
|||||||
return
|
return
|
||||||
|
|
||||||
special = set(get_players(("harlot", "priest", "prophet", "matchmaker",
|
special = set(get_players(("harlot", "priest", "prophet", "matchmaker",
|
||||||
"doctor", "hag", "sorcerer", "turncoat", "clone", "piper")))
|
"doctor", "hag", "sorcerer", "turncoat", "clone")))
|
||||||
evt2 = Event("get_special", {"special": special})
|
evt2 = Event("get_special", {"special": special})
|
||||||
evt2.dispatch(var)
|
evt2.dispatch(var)
|
||||||
pl = set(get_players())
|
pl = set(get_players())
|
||||||
@ -43,7 +43,7 @@ def on_exchange(evt, var, actor, target, actor_role, target_role):
|
|||||||
def on_transition_night_end(evt, var):
|
def on_transition_night_end(evt, var):
|
||||||
# init with all roles that haven't been split yet
|
# init with all roles that haven't been split yet
|
||||||
special = set(get_players(("harlot", "priest", "prophet", "matchmaker",
|
special = set(get_players(("harlot", "priest", "prophet", "matchmaker",
|
||||||
"doctor", "hag", "sorcerer", "turncoat", "clone", "piper")))
|
"doctor", "hag", "sorcerer", "turncoat", "clone")))
|
||||||
evt2 = Event("get_special", {"special": special})
|
evt2 = Event("get_special", {"special": special})
|
||||||
evt2.dispatch(var)
|
evt2.dispatch(var)
|
||||||
pl = set(get_players())
|
pl = set(get_players())
|
||||||
|
201
src/roles/piper.py
Normal file
201
src/roles/piper.py
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
import re
|
||||||
|
import random
|
||||||
|
import itertools
|
||||||
|
import math
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
import botconfig
|
||||||
|
import src.settings as var
|
||||||
|
from src.utilities import *
|
||||||
|
from src.functions import get_players, get_all_players, get_target, get_main_role
|
||||||
|
from src import channels, users, debuglog, errlog, plog
|
||||||
|
from src.decorators import command, event_listener
|
||||||
|
from src.messages import messages
|
||||||
|
from src.events import Event
|
||||||
|
|
||||||
|
TOBECHARMED = {} # type: Dict[users.User, Set[users.User]]
|
||||||
|
CHARMED = set() # type: Set[users.User]
|
||||||
|
|
||||||
|
@command("charm", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("piper",))
|
||||||
|
def charm(var, wrapper, message):
|
||||||
|
"""Charm a player, slowly leading to your win!"""
|
||||||
|
pieces = re.split(" +", message)
|
||||||
|
target1 = pieces[0]
|
||||||
|
if len(pieces) > 1:
|
||||||
|
if len(pieces) > 2 and pieces[1].lower() == "and":
|
||||||
|
target2 = pieces[2]
|
||||||
|
else:
|
||||||
|
target2 = pieces[1]
|
||||||
|
else:
|
||||||
|
target2 = None
|
||||||
|
|
||||||
|
target1 = get_target(var, wrapper, target1)
|
||||||
|
if not target1:
|
||||||
|
return
|
||||||
|
|
||||||
|
if target2 is not None:
|
||||||
|
target2 = get_target(var, wrapper, target2)
|
||||||
|
if not target2:
|
||||||
|
return
|
||||||
|
|
||||||
|
orig1 = target1
|
||||||
|
orig2 = target2
|
||||||
|
|
||||||
|
evt1 = Event("targeted_command", {"target": target1.nick, "misdirection": True, "exchange": True})
|
||||||
|
evt1.dispatch(wrapper.client, var, "charm", wrapper.source.nick, target1.nick, frozenset({"detrimental"}))
|
||||||
|
if evt1.prevent_default:
|
||||||
|
return
|
||||||
|
target1 = users._get(evt1.data["target"]) # FIXME: need to make targeted_command use users
|
||||||
|
|
||||||
|
if target2 is not None:
|
||||||
|
evt2 = Event("targeted_command", {"target": target2.nick, "misdirection": True, "exchange": True})
|
||||||
|
evt2.dispatch(wrapper.client, var, "charm", wrapper.source.nick, target2.nick, frozenset({"detrimental"}))
|
||||||
|
if evt2.prevent_default:
|
||||||
|
return
|
||||||
|
target2 = users._get(evt2.data["target"]) # FIXME
|
||||||
|
|
||||||
|
# Do these checks based on original targets, so piper doesn't know to change due to misdirection/luck totem
|
||||||
|
if orig1 is orig2:
|
||||||
|
wrapper.send(messages["must_charm_multiple"])
|
||||||
|
return
|
||||||
|
|
||||||
|
if orig1 in CHARMED and orig2 in CHARMED:
|
||||||
|
wrapper.send(messages["targets_already_charmed"].format(orig1, orig2))
|
||||||
|
return
|
||||||
|
elif orig1 in CHARMED:
|
||||||
|
wrapper.send(messages["target_already_charmed"].format(orig1))
|
||||||
|
return
|
||||||
|
elif orig2 in CHARMED:
|
||||||
|
wrapper.send(messages["target_already_charmed"].format(orig2))
|
||||||
|
return
|
||||||
|
|
||||||
|
TOBECHARMED[wrapper.source] = {target1, target2}
|
||||||
|
TOBECHARMED[wrapper.source].discard(None)
|
||||||
|
|
||||||
|
if orig2:
|
||||||
|
debuglog("{0} (piper) CHARM {1} ({2}) && {3} ({4})".format(wrapper.source,
|
||||||
|
target1, get_main_role(target1),
|
||||||
|
target2, get_main_role(target2)))
|
||||||
|
wrapper.send(messages["charm_multiple_success"].format(orig1, orig2))
|
||||||
|
else:
|
||||||
|
debuglog("{0} (piper) CHARM {1} ({2})".format(wrapper.source, target1, get_main_role(target1)))
|
||||||
|
wrapper.send(messages["charm_success"].format(orig1))
|
||||||
|
|
||||||
|
chk_nightdone(wrapper.client)
|
||||||
|
|
||||||
|
@event_listener("chk_win", priority=2)
|
||||||
|
def on_chk_win(evt, cli, var, rolemap, mainroles, lpl, lwolves, lrealwolves):
|
||||||
|
# lpl doesn't included wounded/sick people or consecrating priests
|
||||||
|
# whereas we want to ensure EVERYONE (even wounded people) are charmed for piper win
|
||||||
|
pipers = set(users._get(p) for p in rolemap.get("piper", ())) # FIXME
|
||||||
|
lp = len(pipers)
|
||||||
|
if lp == 0: # no alive pipers, short-circuit this check
|
||||||
|
return
|
||||||
|
|
||||||
|
uncharmed = set(get_players(mainroles=mainroles)) - CHARMED - pipers
|
||||||
|
|
||||||
|
if var.PHASE == "day" and len(uncharmed) == 0:
|
||||||
|
evt.data["winner"] = "pipers"
|
||||||
|
evt.data["message"] = messages["piper_win"].format("s" if lp > 1 else "", "s" if lp == 1 else "")
|
||||||
|
|
||||||
|
@event_listener("player_win")
|
||||||
|
def on_player_win(evt, var, player, mainrole, winner, survived):
|
||||||
|
if winner != "pipers":
|
||||||
|
return
|
||||||
|
|
||||||
|
if mainrole == "piper":
|
||||||
|
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")
|
||||||
|
def on_del_player(evt, var, player, mainrole, allroles, death_triggers):
|
||||||
|
CHARMED.discard(player)
|
||||||
|
TOBECHARMED.pop(player, None)
|
||||||
|
|
||||||
|
@event_listener("transition_day_begin")
|
||||||
|
def on_transition_day_begin(evt, var):
|
||||||
|
tocharm = set(itertools.chain.from_iterable(TOBECHARMED.values()))
|
||||||
|
# remove pipers from set; they can never be charmed
|
||||||
|
# but might end up in there due to misdirection/luck totems
|
||||||
|
tocharm.difference_update(get_all_players(("piper",)))
|
||||||
|
|
||||||
|
# Send out PMs to players who have been charmed
|
||||||
|
for target in tocharm:
|
||||||
|
charmedlist = list(CHARMED | tocharm - {target})
|
||||||
|
message = messages["charmed"]
|
||||||
|
|
||||||
|
if len(charmedlist) <= 0:
|
||||||
|
target.send(message + messages["no_charmed_players"])
|
||||||
|
elif len(charmedlist) == 1:
|
||||||
|
target.send(message + messages["one_charmed_player"].format(charmedlist[0]))
|
||||||
|
elif len(charmedlist) == 2:
|
||||||
|
target.send(message + messages["two_charmed_players"].format(charmedlist[0], charmedlist[1]))
|
||||||
|
else:
|
||||||
|
target.send(message + messages["many_charmed_players"].format("\u0002, \u0002".join(p.nick for p in charmedlist[:-1]), charmedlist[-1]))
|
||||||
|
|
||||||
|
if len(tocharm) > 0:
|
||||||
|
for target in CHARMED:
|
||||||
|
tobecharmedlist = list(tocharm)
|
||||||
|
|
||||||
|
if len(tobecharmedlist) == 1:
|
||||||
|
message = messages["players_charmed_one"].format(tobecharmedlist[0])
|
||||||
|
elif len(tobecharmedlist) == 2:
|
||||||
|
message = messages["players_charmed_two"].format(tobecharmedlist[0], tobecharmedlist[1])
|
||||||
|
else:
|
||||||
|
message = messages["players_charmed_many"].format("\u0002, \u0002".join(p.nick for p in tobecharmedlist[:-1]), tobecharmedlist[-1])
|
||||||
|
|
||||||
|
previouscharmed = CHARMED - {target}
|
||||||
|
if len(previouscharmed):
|
||||||
|
target.send(message + messages["previously_charmed"].format("\u0002, \u0002".join(p.nick for p in previouscharmed)))
|
||||||
|
else:
|
||||||
|
target.send(message)
|
||||||
|
|
||||||
|
CHARMED.update(tocharm)
|
||||||
|
TOBECHARMED.clear()
|
||||||
|
|
||||||
|
@event_listener("night_acted")
|
||||||
|
def on_night_acted(evt, var, target, actor):
|
||||||
|
if target in TOBECHARMED:
|
||||||
|
evt.data["acted"] = True
|
||||||
|
|
||||||
|
@event_listener("chk_nightdone")
|
||||||
|
def on_chk_nightdone(evt, var):
|
||||||
|
evt.data["actedcount"] += len(TOBECHARMED.keys())
|
||||||
|
evt.data["nightroles"].extend(get_all_players(("piper",)))
|
||||||
|
|
||||||
|
@event_listener("transition_night_end", priority=2)
|
||||||
|
def on_transition_night_end(evt, var):
|
||||||
|
ps = set(get_players()) - CHARMED
|
||||||
|
for piper in get_all_players(("piper",)):
|
||||||
|
pl = list(ps)
|
||||||
|
random.shuffle(pl)
|
||||||
|
pl.remove(piper)
|
||||||
|
to_send = "piper_notify"
|
||||||
|
if piper.prefers_simple():
|
||||||
|
to_send = "piper_simple"
|
||||||
|
piper.send(messages[to_send], "Players: " + ", ".join(p.nick for p in pl), sep="\n")
|
||||||
|
|
||||||
|
@event_listener("exchange_roles")
|
||||||
|
def on_exchange(evt, var, actor, target, actor_role, target_role):
|
||||||
|
# if we're shifting piper around, ensure that the new piper isn't charmed
|
||||||
|
if actor_role == "piper":
|
||||||
|
CHARMED.discard(target)
|
||||||
|
if target_role == "piper":
|
||||||
|
CHARMED.discard(actor)
|
||||||
|
|
||||||
|
@event_listener("get_special")
|
||||||
|
def on_get_special(evt, var):
|
||||||
|
evt.data["special"].update(get_players(("piper",)))
|
||||||
|
|
||||||
|
@event_listener("reset")
|
||||||
|
def on_reset(evt, var):
|
||||||
|
CHARMED.clear()
|
||||||
|
TOBECHARMED.clear()
|
||||||
|
|
||||||
|
@event_listener("revealroles")
|
||||||
|
def on_revealroles(evt, var, wrapper):
|
||||||
|
if CHARMED:
|
||||||
|
evt.data["output"].append("\u0002charmed players\u0002: {0}".format(", ".join(p.nick for p in CHARMED)))
|
||||||
|
|
||||||
|
# vim: set sw=4 expandtab:
|
155
src/wolfgame.py
155
src/wolfgame.py
@ -96,7 +96,6 @@ var.RESTARTING = False
|
|||||||
|
|
||||||
var.BITTEN_ROLES = {}
|
var.BITTEN_ROLES = {}
|
||||||
var.LYCAN_ROLES = {}
|
var.LYCAN_ROLES = {}
|
||||||
var.CHARMED = set()
|
|
||||||
var.START_VOTES = set()
|
var.START_VOTES = set()
|
||||||
|
|
||||||
if botconfig.DEBUG_MODE and var.DISABLE_DEBUG_MODE_TIMERS:
|
if botconfig.DEBUG_MODE and var.DISABLE_DEBUG_MODE_TIMERS:
|
||||||
@ -2130,7 +2129,7 @@ def stop_game(winner="", abort=False, additional_winners=None, log=True):
|
|||||||
# determine if this player's team won
|
# determine if this player's team won
|
||||||
if rol in var.TRUE_NEUTRAL_ROLES:
|
if rol in var.TRUE_NEUTRAL_ROLES:
|
||||||
# most true neutral roles never have a team win, only individual wins. Exceptions to that are here
|
# most true neutral roles never have a team win, only individual wins. Exceptions to that are here
|
||||||
teams = {"monster":"monsters", "piper":"pipers", "demoniac":"demoniacs"}
|
teams = {"monster":"monsters", "demoniac":"demoniacs"}
|
||||||
if rol in teams and winner == teams[rol]:
|
if rol in teams and winner == teams[rol]:
|
||||||
won = True
|
won = True
|
||||||
elif rol == "turncoat" and splr in var.TURNCOATS and var.TURNCOATS[splr][0] != "none":
|
elif rol == "turncoat" and splr in var.TURNCOATS and var.TURNCOATS[splr][0] != "none":
|
||||||
@ -2166,6 +2165,7 @@ def stop_game(winner="", abort=False, additional_winners=None, log=True):
|
|||||||
elif winner == "demoniacs" and lvrrol == "demoniac":
|
elif winner == "demoniacs" and lvrrol == "demoniac":
|
||||||
iwon = True
|
iwon = True
|
||||||
break
|
break
|
||||||
|
# TODO: split this into piper.py once matchmaker is split
|
||||||
elif winner == "pipers" and lvrrol == "piper":
|
elif winner == "pipers" and lvrrol == "piper":
|
||||||
iwon = True
|
iwon = True
|
||||||
break
|
break
|
||||||
@ -2173,8 +2173,6 @@ def stop_game(winner="", abort=False, additional_winners=None, log=True):
|
|||||||
iwon = True
|
iwon = True
|
||||||
elif rol == "demoniac" and splr in survived and winner == "demoniacs":
|
elif rol == "demoniac" and splr in survived and winner == "demoniacs":
|
||||||
iwon = True
|
iwon = True
|
||||||
elif rol == "piper" and splr in survived and winner == "pipers":
|
|
||||||
iwon = True
|
|
||||||
elif rol == "clone":
|
elif rol == "clone":
|
||||||
# this means they ended game while being clone and not some other role
|
# this means they ended game while being clone and not some other role
|
||||||
if splr in survived and not winner.startswith("@") and singular(winner) not in var.WIN_STEALER_ROLES:
|
if splr in survived and not winner.startswith("@") and singular(winner) not in var.WIN_STEALER_ROLES:
|
||||||
@ -2309,7 +2307,6 @@ def chk_win_conditions(cli, rolemap, mainroles, end_game=True, winner=None):
|
|||||||
lmonsters = len(rolemap.get("monster", ()))
|
lmonsters = len(rolemap.get("monster", ()))
|
||||||
ldemoniacs = len(rolemap.get("demoniac", ()))
|
ldemoniacs = len(rolemap.get("demoniac", ()))
|
||||||
ltraitors = len(rolemap.get("traitor", ()))
|
ltraitors = len(rolemap.get("traitor", ()))
|
||||||
lpipers = len(rolemap.get("piper", ()))
|
|
||||||
|
|
||||||
message = ""
|
message = ""
|
||||||
# fool won, chk_win was called from !lynch
|
# fool won, chk_win was called from !lynch
|
||||||
@ -2319,9 +2316,6 @@ def chk_win_conditions(cli, rolemap, mainroles, end_game=True, winner=None):
|
|||||||
message = messages["no_win"]
|
message = messages["no_win"]
|
||||||
# still want people like jesters, dullahans, etc. to get wins if they fulfilled their win conds
|
# still want people like jesters, dullahans, etc. to get wins if they fulfilled their win conds
|
||||||
winner = "no_team_wins"
|
winner = "no_team_wins"
|
||||||
elif var.PHASE == "day" and lpipers and len(list_players()) - lpipers == len(var.CHARMED - var.ROLES["piper"]):
|
|
||||||
winner = "pipers"
|
|
||||||
message = messages["piper_win"].format("s" if lpipers > 1 else "", "s" if lpipers == 1 else "")
|
|
||||||
elif lrealwolves == 0 and ltraitors == 0 and lcubs == 0:
|
elif lrealwolves == 0 and ltraitors == 0 and lcubs == 0:
|
||||||
if ldemoniacs > 0:
|
if ldemoniacs > 0:
|
||||||
s = "s" if ldemoniacs > 1 else ""
|
s = "s" if ldemoniacs > 1 else ""
|
||||||
@ -2342,6 +2336,7 @@ def chk_win_conditions(cli, rolemap, mainroles, end_game=True, winner=None):
|
|||||||
message = messages["monster_wolf_win"].format(s)
|
message = messages["monster_wolf_win"].format(s)
|
||||||
winner = "monsters"
|
winner = "monsters"
|
||||||
|
|
||||||
|
# TODO: convert to using users, flip priority order (so that things like fool run last, and therefore override previous win conds)
|
||||||
# Priorities:
|
# Priorities:
|
||||||
# 0 = fool, other roles that end game immediately
|
# 0 = fool, other roles that end game immediately
|
||||||
# 1 = things that could short-circuit game ending, such as cub growing up or traitor turning
|
# 1 = things that could short-circuit game ending, such as cub growing up or traitor turning
|
||||||
@ -2401,8 +2396,6 @@ def del_player(player, *, devoice=True, end_game=True, death_triggers=True, kill
|
|||||||
var.ROLES[r].remove(player.nick) # FIXME
|
var.ROLES[r].remove(player.nick) # FIXME
|
||||||
if player.nick in var.BITTEN_ROLES:
|
if player.nick in var.BITTEN_ROLES:
|
||||||
del var.BITTEN_ROLES[player.nick] # FIXME
|
del var.BITTEN_ROLES[player.nick] # FIXME
|
||||||
if player.nick in var.CHARMED:
|
|
||||||
var.CHARMED.remove(player.nick) # FIXME
|
|
||||||
pl.discard(player)
|
pl.discard(player)
|
||||||
# handle roles that trigger on death
|
# handle roles that trigger on death
|
||||||
# clone happens regardless of death_triggers being true or not
|
# clone happens regardless of death_triggers being true or not
|
||||||
@ -2678,7 +2671,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, var.CHARMERS):
|
for x in (var.PASSED, var.HEXED, var.MATCHMAKERS, var.CURSED):
|
||||||
x.discard(player.nick)
|
x.discard(player.nick)
|
||||||
if var.PHASE == "day" and ret:
|
if var.PHASE == "day" and ret:
|
||||||
var.VOTES.pop(player.nick, None) # Delete other people's votes on the player
|
var.VOTES.pop(player.nick, None) # Delete other people's votes on the player
|
||||||
@ -3023,8 +3016,7 @@ def rename_player(var, user, prefix):
|
|||||||
for setvar in (var.HEXED, var.SILENCED, var.MATCHMAKERS, var.PASSED,
|
for setvar in (var.HEXED, var.SILENCED, var.MATCHMAKERS, var.PASSED,
|
||||||
var.JESTERS, var.AMNESIACS, var.LYCANTHROPES, var.LUCKY, var.DISEASED,
|
var.JESTERS, var.AMNESIACS, 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.CHARMERS, var.CHARMED, var.TOBECHARMED,
|
var.ALPHA_WOLVES, var.CURSED, var.PRIESTS, var.CONSECRATING):
|
||||||
var.PRIESTS, var.CONSECRATING):
|
|
||||||
if prefix in setvar:
|
if prefix in setvar:
|
||||||
setvar.remove(prefix)
|
setvar.remove(prefix)
|
||||||
setvar.add(nick)
|
setvar.add(nick)
|
||||||
@ -3368,40 +3360,6 @@ def transition_day(cli, gameid=0):
|
|||||||
var.WOUNDED = set()
|
var.WOUNDED = set()
|
||||||
var.NO_LYNCH = set()
|
var.NO_LYNCH = set()
|
||||||
|
|
||||||
# Send out PMs to players who have been charmed
|
|
||||||
for victim in var.TOBECHARMED:
|
|
||||||
charmedlist = list(var.CHARMED | var.TOBECHARMED - {victim})
|
|
||||||
message = messages["charmed"]
|
|
||||||
|
|
||||||
if len(charmedlist) <= 0:
|
|
||||||
pm(cli, victim, message + messages["no_charmed_players"])
|
|
||||||
elif len(charmedlist) == 1:
|
|
||||||
pm(cli, victim, message + messages["one_charmed_player"].format(charmedlist[0]))
|
|
||||||
elif len(charmedlist) == 2:
|
|
||||||
pm(cli, victim, message + messages["two_charmed_players"].format(charmedlist[0], charmedlist[1]))
|
|
||||||
else:
|
|
||||||
pm(cli, victim, message + messages["many_charmed_players"].format("\u0002, \u0002".join(charmedlist[:-1]), charmedlist[-1]))
|
|
||||||
|
|
||||||
if var.TOBECHARMED:
|
|
||||||
tobecharmedlist = list(var.TOBECHARMED)
|
|
||||||
for victim in var.CHARMED:
|
|
||||||
if len(tobecharmedlist) == 1:
|
|
||||||
message = messages["players_charmed_one"].format(tobecharmedlist[0])
|
|
||||||
elif len(tobecharmedlist) == 2:
|
|
||||||
message = messages["players_charmed_two"].format(tobecharmedlist[0], tobecharmedlist[1])
|
|
||||||
else:
|
|
||||||
message = messages["players_charmed_many"].format(
|
|
||||||
"\u0002, \u0002".join(tobecharmedlist[:-1]), tobecharmedlist[-1])
|
|
||||||
|
|
||||||
previouscharmed = var.CHARMED - {victim}
|
|
||||||
if len(previouscharmed):
|
|
||||||
pm(cli, victim, message + (messages["previously_charmed"]).format("\u0002, \u0002".join(previouscharmed)))
|
|
||||||
else:
|
|
||||||
pm(cli, victim, message)
|
|
||||||
|
|
||||||
var.CHARMED.update(var.TOBECHARMED)
|
|
||||||
var.TOBECHARMED.clear()
|
|
||||||
|
|
||||||
for crow, target in iter(var.OBSERVED.items()):
|
for crow, target in iter(var.OBSERVED.items()):
|
||||||
if crow not in var.ROLES["werecrow"]:
|
if crow not in var.ROLES["werecrow"]:
|
||||||
continue
|
continue
|
||||||
@ -3409,7 +3367,7 @@ def transition_day(cli, gameid=0):
|
|||||||
user = users._get(target) # FIXME
|
user = users._get(target) # FIXME
|
||||||
evt = Event("night_acted", {"acted": False})
|
evt = Event("night_acted", {"acted": False})
|
||||||
evt.dispatch(var, user, actor)
|
evt.dispatch(var, user, actor)
|
||||||
if ((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.OBSERVED or target in var.HEXED or target in var.CURSED or evt.data["acted"]):
|
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))
|
actor.send(messages["werecrow_success"].format(user))
|
||||||
else:
|
else:
|
||||||
@ -3810,10 +3768,9 @@ def chk_nightdone(cli):
|
|||||||
|
|
||||||
pl = get_players()
|
pl = get_players()
|
||||||
spl = set(pl)
|
spl = set(pl)
|
||||||
actedcount = sum(map(len, (var.PASSED, var.OBSERVED,
|
actedcount = sum(map(len, (var.PASSED, var.OBSERVED, var.HEXED, var.CURSED)))
|
||||||
var.HEXED, var.CURSED, var.CHARMERS)))
|
|
||||||
|
|
||||||
nightroles = list(get_all_players(("sorcerer", "hag", "warlock", "werecrow", "piper", "prophet")))
|
nightroles = list(get_all_players(("sorcerer", "hag", "warlock", "werecrow", "prophet")))
|
||||||
|
|
||||||
for nick, info in var.PRAYED.items():
|
for nick, info in var.PRAYED.items():
|
||||||
if info[0] > 0:
|
if info[0] > 0:
|
||||||
@ -4876,81 +4833,6 @@ def clone(cli, nick, chan, rest):
|
|||||||
|
|
||||||
var.ROLE_COMMAND_EXCEPTIONS.add("clone")
|
var.ROLE_COMMAND_EXCEPTIONS.add("clone")
|
||||||
|
|
||||||
@cmd("charm", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("piper",))
|
|
||||||
def charm(cli, nick, chan, rest):
|
|
||||||
"""Charm a player, slowly leading to your win!"""
|
|
||||||
if nick in var.CHARMERS:
|
|
||||||
pm(cli, nick, messages["already_charmed"])
|
|
||||||
return
|
|
||||||
|
|
||||||
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
|
|
||||||
if is_safe(nick, victim):
|
|
||||||
pm(cli, nick, messages["no_acting_on_succubus"].format("charm"))
|
|
||||||
return
|
|
||||||
if victim2 is not None:
|
|
||||||
victim2 = get_victim(cli, nick, victim2, False, True)
|
|
||||||
if not victim2:
|
|
||||||
return
|
|
||||||
if is_safe(nick, victim2):
|
|
||||||
pm(cli, nick, messages["no_acting_on_succubus"].format("charm"))
|
|
||||||
return
|
|
||||||
|
|
||||||
if victim == victim2:
|
|
||||||
pm(cli, nick, messages["must_charm_multiple"])
|
|
||||||
return
|
|
||||||
if nick in (victim, victim2):
|
|
||||||
pm(cli, nick, messages["no_charm_self"])
|
|
||||||
return
|
|
||||||
charmedlist = var.CHARMED|var.TOBECHARMED
|
|
||||||
if victim in charmedlist or victim2 and victim2 in charmedlist:
|
|
||||||
if victim in charmedlist and victim2 and victim2 in charmedlist:
|
|
||||||
pm(cli, nick, messages["targets_already_charmed"].format(victim, victim2))
|
|
||||||
return
|
|
||||||
if (len(list_players()) - len(var.ROLES["piper"]) - len(charmedlist) - 2 >= 0 or
|
|
||||||
victim in charmedlist and not victim2):
|
|
||||||
pm(cli, nick, messages["target_already_charmed"].format(victim in charmedlist and victim or victim2))
|
|
||||||
return
|
|
||||||
|
|
||||||
var.CHARMERS.add(nick)
|
|
||||||
var.PASSED.discard(nick)
|
|
||||||
|
|
||||||
var.TOBECHARMED.add(victim)
|
|
||||||
if victim2:
|
|
||||||
var.TOBECHARMED.add(victim2)
|
|
||||||
pm(cli, nick, messages["charm_multiple_success"].format(victim, victim2))
|
|
||||||
else:
|
|
||||||
pm(cli, nick, messages["charm_success"].format(victim))
|
|
||||||
|
|
||||||
# if there are other pipers, tell them who gets charmed (so they don't have to keep guessing who they are still allowed to charm)
|
|
||||||
for piper in var.ROLES["piper"]:
|
|
||||||
if piper != nick:
|
|
||||||
if victim2:
|
|
||||||
pm(cli, piper, messages["another_piper_charmed_multiple"].format(victim, victim2))
|
|
||||||
else:
|
|
||||||
pm(cli, piper, messages["another_piper_charmed"].format(victim))
|
|
||||||
|
|
||||||
if victim2:
|
|
||||||
debuglog("{0} ({1}) CHARM {2} ({3}) && {4} ({5})".format(nick, get_role(nick),
|
|
||||||
victim, get_role(victim),
|
|
||||||
victim2, get_role(victim2)))
|
|
||||||
else:
|
|
||||||
debuglog("{0} ({1}) CHARM {2} ({3})".format(nick, get_role(nick),
|
|
||||||
victim, get_role(victim)))
|
|
||||||
|
|
||||||
chk_nightdone(cli)
|
|
||||||
|
|
||||||
@event_listener("targeted_command", priority=9)
|
@event_listener("targeted_command", priority=9)
|
||||||
def on_targeted_command(evt, cli, var, cmd, actor, orig_target, tags):
|
def on_targeted_command(evt, cli, var, cmd, actor, orig_target, tags):
|
||||||
if evt.data["misdirection"]:
|
if evt.data["misdirection"]:
|
||||||
@ -5134,7 +5016,6 @@ def transition_night(cli):
|
|||||||
var.CURSED = set() # set of warlocks that have cursed
|
var.CURSED = set() # set of warlocks that have cursed
|
||||||
var.PASSED = set()
|
var.PASSED = set()
|
||||||
var.OBSERVED = {} # those whom werecrows have observed
|
var.OBSERVED = {} # those whom werecrows have observed
|
||||||
var.CHARMERS = set() # pipers who have charmed
|
|
||||||
var.TOBESILENCED = set()
|
var.TOBESILENCED = set()
|
||||||
var.CONSECRATING = set()
|
var.CONSECRATING = set()
|
||||||
for nick in var.PRAYED:
|
for nick in var.PRAYED:
|
||||||
@ -5294,19 +5175,6 @@ def transition_night(cli):
|
|||||||
pm(cli, ass, messages["assassin_simple"])
|
pm(cli, ass, messages["assassin_simple"])
|
||||||
pm(cli, ass, "Players: " + ", ".join(pl))
|
pm(cli, ass, "Players: " + ", ".join(pl))
|
||||||
|
|
||||||
for piper in var.ROLES["piper"]:
|
|
||||||
pl = ps[:]
|
|
||||||
random.shuffle(pl)
|
|
||||||
pl.remove(piper)
|
|
||||||
for charmed in var.CHARMED:
|
|
||||||
if charmed in pl: # corner case: if there are multiple pipers and a piper is charmed, the piper will be in var.CHARMED but not in pl
|
|
||||||
pl.remove(charmed)
|
|
||||||
if piper in var.PLAYERS and not is_user_simple(piper):
|
|
||||||
pm(cli, piper, (messages["piper_notify"]))
|
|
||||||
else:
|
|
||||||
pm(cli, piper, messages["piper_simple"])
|
|
||||||
pm(cli, piper, "Players: " + ", ".join(pl))
|
|
||||||
|
|
||||||
for turncoat in var.ROLES["turncoat"]:
|
for turncoat in var.ROLES["turncoat"]:
|
||||||
# they start out as unsided, but can change n1
|
# they start out as unsided, but can change n1
|
||||||
if turncoat not in var.TURNCOATS:
|
if turncoat not in var.TURNCOATS:
|
||||||
@ -5625,9 +5493,6 @@ def start(cli, nick, chan, forced = False, restart = ""):
|
|||||||
var.BITTEN_ROLES = {}
|
var.BITTEN_ROLES = {}
|
||||||
var.LYCAN_ROLES = {}
|
var.LYCAN_ROLES = {}
|
||||||
var.AMNESIAC_ROLES = {}
|
var.AMNESIAC_ROLES = {}
|
||||||
var.CHARMERS = set()
|
|
||||||
var.CHARMED = set()
|
|
||||||
var.TOBECHARMED = set()
|
|
||||||
var.ACTIVE_PROTECTIONS = defaultdict(list)
|
var.ACTIVE_PROTECTIONS = defaultdict(list)
|
||||||
var.TURNCOATS = {}
|
var.TURNCOATS = {}
|
||||||
var.EXCHANGED_ROLES = []
|
var.EXCHANGED_ROLES = []
|
||||||
@ -7002,10 +6867,6 @@ def revealroles(var, wrapper, message):
|
|||||||
if var.IMMUNIZED:
|
if var.IMMUNIZED:
|
||||||
output.append("\u0002immunized\u0002: {0}".format(", ".join(var.IMMUNIZED)))
|
output.append("\u0002immunized\u0002: {0}".format(", ".join(var.IMMUNIZED)))
|
||||||
|
|
||||||
# get charmed players
|
|
||||||
if var.CHARMED | var.TOBECHARMED:
|
|
||||||
output.append("\u0002charmed players\u0002: {0}".format(", ".join(var.CHARMED | var.TOBECHARMED)))
|
|
||||||
|
|
||||||
evt = Event("revealroles", {"output": output})
|
evt = Event("revealroles", {"output": output})
|
||||||
evt.dispatch(var, wrapper)
|
evt.dispatch(var, wrapper)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user