diff --git a/src/roles/angel.py b/src/roles/angel.py new file mode 100644 index 0000000..fa7601b --- /dev/null +++ b/src/roles/angel.py @@ -0,0 +1,258 @@ +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 import debuglog, errlog, plog +from src.decorators import cmd, event_listener +from src.messages import messages +from src.events import Event + +GUARDED = {} # type: Dict[str, str] +LASTGUARDED = {} # type: Dict[str, str] +PASSED = set() # type: Set[str] + +@cmd("guard", "protect", "save", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("bodyguard", "guardian angel")) +def guard(cli, nick, chan, rest): + """Guard a player, preventing them from being killed that night.""" + if nick in GUARDED: + pm(cli, nick, messages["already_protecting"]) + return + role = get_role(nick) + self_in_list = role == "guardian angel" and var.GUARDIAN_ANGEL_CAN_GUARD_SELF + victim = get_victim(cli, nick, re.split(" +",rest)[0], False, self_in_list) + if not victim: + return + if role == "guardian angel" and LASTGUARDED.get(nick) == victim: + pm(cli, nick, messages["guardian_target_another"].format(victim)) + return + # self-guard ignores luck/misdirection/exchange totem + evt = Event("targeted_command", {"target": victim, "misdirection": victim != nick, "exchange": victim != nick}) + if not evt.dispatch(cli, var, "guard", nick, victim, frozenset({"beneficial"})): + return + victim = evt.data["target"] + GUARDED[nick] = victim + LASTGUARDED[nick] = victim + if victim == nick: + pm(cli, nick, messages["guardian_guard_self"]) + else: + pm(cli, nick, messages["protecting_target"].format(GUARDED[nick])) + pm(cli, victim, messages["target_protected"]) + debuglog("{0} ({1}) GUARD: {2} ({3})".format(nick, role, victim, get_role(victim))) + chk_nightdone(cli) + +@cmd("pass", chan=False, pm=True, playing=True, phases=("night",), roles=("bodyguard", "guardian angel")) +def pass_cmd(cli, nick, chan, rest): + """Decline to use your special power for that night.""" + if nick in GUARDED: + pm(cli, nick, messages["already_protecting"]) + return + PASSED.add(nick) + pm(cli, nick, messages["guardian_no_protect"]) + debuglog("{0} ({1}) PASS".format(nick, get_role(nick))) + chk_nightdone(cli) + +@event_listener("rename_player") +def on_rename(evt, cli, var, prefix, nick): + for dictvar in (GUARDED, LASTGUARDED): + kvp = {} + for a,b in dictvar.items(): + if a == prefix: + if b == prefix: + kvp[nick] = nick + else: + kvp[nick] = b + elif b == prefix: + kvp[a] = nick + dictvar.update(kvp) + if prefix in dictvar: + del dictvar[prefix] + if prefix in PASSED: + PASSED.discard(prefix) + PASSED.add(nick) + +@event_listener("del_player") +def on_del_player(evt, cli, var, nick, nickrole, nicktpls, death_triggers): + if var.PHASE == "night" and nick in GUARDED: + pm(cli, GUARDED[nick], messages["protector_disappeared"]) + for dictvar in (GUARDED, LASTGUARDED): + for k,v in list(dictvar.items()): + if nick in (k, v): + del dictvar[k] + if nick in PASSED: + PASSED.discard(nick) + +@event_listener("night_acted") +def on_acted(evt, cli, var, nick, sender): + if nick in GUARDED: + evt.data["acted"] = True + +@event_listener("get_special") +def on_get_special(evt, cli, var): + evt.data["special"].update(list_players(("guardian angel", "bodyguard"))) + +@event_listener("exchange_roles") +def on_exchange(evt, cli, var, actor, nick, actor_role, nick_role): + if actor_role in ("bodyguard", "guardian angel"): + if actor in GUARDED: + pm(cli, GUARDED.pop(actor), messages["protector disappeared"]) + if actor in LASTGUARDED: + del LASTGUARDED[actor] + if nick_role in ("bodyguard", "guardian angel"): + if nick in GUARDED: + pm(cli, GUARDED.pop(nick), messages["protector disappeared"]) + if nick in LASTGUARDED: + del LASTGUARDED[nick] + +@event_listener("chk_nightdone") +def on_chk_nightdone(evt, cli, var): + evt.data["actedcount"] += len(GUARDED) + len(PASSED) + evt.data["nightroles"].extend(list_players(("guardian angel", "bodyguard"))) + +@event_listener("transition_day", priority=4.2) +def on_transition_day(evt, cli, var): + pl = list_players() + vs = set(evt.data["victims"]) + for v in pl: + if v in vs: + if v in var.DYING: + continue + for g in var.ROLES["guardian angel"]: + if GUARDED.get(g) == v: + evt.data["numkills"][v] -= 1 + if evt.data["numkills"][v] >= 0: + evt.data["killers"][v].pop(0) + if evt.data["numkills"][v] <= 0 and v not in evt.data["protected"]: + evt.data["protected"][v] = "angel" + elif evt.data["numkills"][v] <= 0: + var.ACTIVE_PROTECTIONS[v].append("angel") + for g in var.ROLES["bodyguard"]: + if GUARDED.get(g) == v: + evt.data["numkills"][v] -= 1 + if evt.data["numkills"][v] >= 0: + evt.data["killers"][v].pop(0) + if evt.data["numkills"][v] <= 0 and v not in evt.data["protected"]: + evt.data["protected"][v] = "bodyguard" + elif evt.data["numkills"][v] <= 0: + var.ACTIVE_PROTECTIONS[v].append("bodyguard") + else: + for g in var.ROLES["guardian angel"]: + if GUARDED.get(g) == v: + var.ACTIVE_PROTECTIONS[v].append("angel") + for g in var.ROLES["bodyguard"]: + if GUARDED.get(g) == v: + var.ACTIVE_PROTECTIONS[v].append("bodyguard") + +@event_listener("transition_day_resolve", priority=2) +def on_transition_day_resolve(evt, cli, var, victim): + # TODO: remove these checks once everything is split + # right now they're needed because otherwise protection may fire off even if the person isn't home + # that will not be an issue once everything is using the event + if victim in var.ROLES["harlot"] | var.ROLES["succubus"] and var.HVISITED.get(victim) and victim not in evt.data["dead"] and victim in evt.data["onlybywolves"]: + return + # END checks to remove + + if evt.data["protected"].get(victim) == "angel": + evt.data["message"].append(messages["angel_protection"].format(victim)) + evt.data["novictmsg"] = False + evt.stop_propagation = True + evt.prevent_default = True + elif evt.data["protected"].get(victim) == "bodyguard": + for bodyguard in var.ROLES["bodyguard"]: + if GUARDED.get(bodyguard) == victim: + evt.data["dead"].append(bodyguard) + evt.data["message"].append(messages["bodyguard_protection"].format(bodyguard)) + evt.data["novictmsg"] = False + evt.stop_propagation = True + evt.prevent_default = True + break + +@event_listener("transition_day_resolve_end") +def on_transition_day_resolve_end(evt, cli, var, victims): + for bodyguard in var.ROLES["bodyguard"]: + if GUARDED.get(bodyguard) in list_players(var.WOLF_ROLES) and bodyguard not in evt.data["dead"] and bodyguard not in evt.data["bitten"]: + r = random.random() + if r < var.BODYGUARD_DIES_CHANCE: + evt.data["bywolves"].add(bodyguard) + evt.data["onlybywolves"].add(bodyguard) + if var.ROLE_REVEAL == "on": + evt.data["message"].append(messages["bodyguard_protected_wolf"].format(bodyguard)) + else: # off and team + evt.data["message"].append(messages["bodyguard_protection"].format(bodyguard)) + evt.data["dead"].append(bodyguard) + for gangel in var.ROLES["guardian angel"]: + if GUARDED.get(gangel) in list_players(var.WOLF_ROLES) and gangel not in evt.data["dead"] and gangel not in evt.data["bitten"]: + r = random.random() + if r < var.GUARDIAN_ANGEL_DIES_CHANCE: + evt.data["bywolves"].add(gangel) + evt.data["onlybywolves"].add(gangel) + if var.ROLE_REVEAL == "on": + evt.data["message"].append(messages["guardian_angel_protected_wolf"].format(gangel)) + else: # off and team + evt.data["message"].append(messages["guardian_angel_protected_wolf_no_reveal"].format(gangel)) + evt.data["dead"].append(gangel) + +@event_listener("transition_night_begin") +def on_transition_night_begin(evt, cli, var): + # needs to be here in order to allow bodyguard protections to work during the daytime + # (right now they don't due to other reasons, but that may change) + GUARDED.clear() + +@event_listener("transition_night_end", priority=2) +def on_transition_night_end(evt, cli, var): + # the messages for angel and guardian angel are different enough to merit individual loops + ps = list_players() + for bg in var.ROLES["bodyguard"]: + pl = ps[:] + random.shuffle(pl) + pl.remove(bg) + chance = math.floor(var.BODYGUARD_DIES_CHANCE * 100) + warning = "" + if chance > 0: + warning = messages["bodyguard_death_chance"].format(chance) + + if bg in var.PLAYERS and not is_user_simple(bg): + pm(cli, bg, messages["bodyguard_notify"].format(warning)) + else: + pm(cli, bg, messages["bodyguard_simple"]) # !simple + pm(cli, bg, "Players: " + ", ".join(pl)) + + for gangel in var.ROLES["guardian angel"]: + pl = ps[:] + random.shuffle(pl) + gself = messages["guardian_self_notification"] + if not var.GUARDIAN_ANGEL_CAN_GUARD_SELF: + pl.remove(gangel) + gself = "" + if LASTGUARDED.get(gangel) in pl: + pl.remove(LASTGUARDED[gangel]) + chance = math.floor(var.GUARDIAN_ANGEL_DIES_CHANCE * 100) + warning = "" + if chance > 0: + warning = messages["bodyguard_death_chance"].format(chance) + + if gangel in var.PLAYERS and not is_user_simple(gangel): + pm(cli, gangel, messages["guardian_notify"].format(warning, gself)) + else: + pm(cli, gangel, messages["guardian_simple"]) # !simple + pm(cli, gangel, "Players: " + ", ".join(pl)) + +@event_listener("begin_day") +def on_begin_day(evt, cli, var): + PASSED.clear() + # clear out LASTGUARDED for people that didn't guard last night + for g in list(LASTGUARDED.keys()): + if g not in GUARDED: + del LASTGUARDED[g] + +@event_listener("reset") +def on_reset(evt, var): + GUARDED.clear() + LASTGUARDED.clear() + PASSED.clear() + +# vim: set sw=4 expandtab: diff --git a/src/wolfgame.py b/src/wolfgame.py index 0eced2c..9ffd4ce 100644 --- a/src/wolfgame.py +++ b/src/wolfgame.py @@ -2860,6 +2860,7 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death target = var.TARGETED[nick] del var.TARGETED[nick] if target != None and target in pl: + # TODO: split this off into an event so that individual roles can handle it as needed if "totem" in var.ACTIVE_PROTECTIONS[target] and nickrole != "fallen angel": var.ACTIVE_PROTECTIONS[target].remove("totem") message = messages["assassin_fail_totem"].format(nick, target) @@ -2870,11 +2871,12 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death cli.msg(botconfig.CHANNEL, message) elif "bodyguard" in var.ACTIVE_PROTECTIONS[target] and nickrole != "fallen angel": var.ACTIVE_PROTECTIONS[target].remove("bodyguard") + from src.roles import angel for ga in var.ROLES["bodyguard"]: - if var.GUARDED.get(ga) == target: + if angel.GUARDED.get(ga) == target: message = messages["assassin_fail_bodyguard"].format(nick, target, ga) cli.msg(botconfig.CHANNEL, message) - del_player(cli, ga, True, end_game = False, killer_role = nickrole, deadlist = deadlist, original = original, ismain = False) + del_player(cli, ga, True, end_game=False, killer_role=nickrole, deadlist=deadlist, original=original, ismain=False) pl = refresh_pl(pl) break elif "blessing" in var.ACTIVE_PROTECTIONS[target] or (var.GAMEPHASE == "day" and target in var.ROLES["blessed villager"]): @@ -3077,7 +3079,7 @@ 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.GUARDED, var.TARGETED, var.LASTGUARDED, var.LASTHEXED): + for x in (var.OBSERVED, var.HVISITED, var.TARGETED, var.LASTHEXED): for k in list(x): if nick in (k, x[k]): del x[k] @@ -3416,9 +3418,8 @@ def rename_player(cli, prefix, nick): if prefix in var.PRAYED.keys(): del var.PRAYED[prefix] - for dictvar in (var.HVISITED, var.OBSERVED, var.GUARDED, var.TARGETED, - var.CLONED, var.LASTGUARDED, var.LASTHEXED, - var.BITE_PREFERENCES): + for dictvar in (var.HVISITED, var.OBSERVED, var.TARGETED, + var.CLONED, var.LASTHEXED, var.BITE_PREFERENCES): kvp = [] for a,b in dictvar.items(): if a == prefix: @@ -3679,7 +3680,6 @@ def begin_day(cli): var.HEXED = set() # set of hags that have silenced others var.OBSERVED = {} # those whom werecrows/sorcerers have observed var.HVISITED = {} # those whom harlots have visited - var.GUARDED = {} # this whom bodyguards/guardian angels have guarded var.PASSED = set() # set of certain roles that have opted not to act var.STARTED_DAY_PLAYERS = len(list_players()) var.SILENCED = copy.copy(var.TOBESILENCED) @@ -3764,12 +3764,6 @@ def transition_day(cli, gameid=0): pl = list_players() if not var.START_WITH_DAY or not var.FIRST_DAY: - # bodyguard doesn't have restrictions, but being checked anyway since both GA and bodyguard use var.GUARDED - if len(var.GUARDED.keys()) < len(var.ROLES["bodyguard"] | var.ROLES["guardian angel"]): - for gangel in var.ROLES["guardian angel"]: - if gangel not in var.GUARDED or var.GUARDED[gangel] is None: - var.LASTGUARDED[gangel] = None - if len(var.HEXED) < len(var.ROLES["hag"]): for hag in var.ROLES["hag"]: if hag not in var.HEXED: @@ -3840,7 +3834,6 @@ def transition_day(cli, gameid=0): evt = Event("night_acted", {"acted": False}) evt.dispatch(cli, var, target, crow) if ((target in var.HVISITED and var.HVISITED[target]) or - (target in var.GUARDED and var.GUARDED[target]) or (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"]): pm(cli, crow, messages["werecrow_success"].format(target)) @@ -3907,24 +3900,6 @@ def transition_day(cli, gameid=0): if v in victims_set: if v in var.DYING: continue # bypass protections - for g in var.ROLES["guardian angel"]: - if var.GUARDED.get(g) == v: - numkills[v] -= 1 - if numkills[v] >= 0: - killers[v].pop(0) - if numkills[v] <= 0 and v not in protected: - protected[v] = "angel" - elif numkills[v] <= 0: - var.ACTIVE_PROTECTIONS[v].append("angel") - for g in var.ROLES["bodyguard"]: - if var.GUARDED.get(g) == v: - numkills[v] -= 1 - if numkills[v] >= 0: - killers[v].pop(0) - if numkills[v] <= 0 and v not in protected: - protected[v] = "bodyguard" - elif numkills[v] <= 0: - var.ACTIVE_PROTECTIONS[v].append("bodyguard") if v in var.ROLES["blessed villager"]: numkills[v] -= 1 if numkills[v] >= 0: @@ -3937,23 +3912,18 @@ def transition_day(cli, gameid=0): onlybywolves.add(v) else: # player wasn't targeted, but apply protections on them - for g in var.ROLES["guardian angel"]: - if var.GUARDED.get(g) == v: - var.ACTIVE_PROTECTIONS[v].append("angel") - for g in var.ROLES["bodyguard"]: - if var.GUARDED.get(g) == v: - var.ACTIVE_PROTECTIONS[v].append("bodyguard") if v in var.ROLES["blessed villager"]: var.ACTIVE_PROTECTIONS[v].append("blessing") fallenkills = set() brokentotem = set() from src.roles.shaman import havetotem + from src.roles import angel if len(var.ROLES["fallen angel"]) > 0: for p, t in list(protected.items()): if p in bywolves: for g in var.ROLES["guardian angel"]: - if var.GUARDED.get(g) == p and random.random() < var.FALLEN_ANGEL_KILLS_GUARDIAN_ANGEL_CHANCE: + if angel.GUARDED.get(g) == p and random.random() < var.FALLEN_ANGEL_KILLS_GUARDIAN_ANGEL_CHANCE: if g in protected: del protected[g] bywolves.add(g) @@ -3963,7 +3933,7 @@ def transition_day(cli, gameid=0): victims_set.add(g) onlybywolves.add(g) for g in var.ROLES["bodyguard"]: - if var.GUARDED.get(g) == p: + if angel.GUARDED.get(g) == p: if g in protected: del protected[g] bywolves.add(g) @@ -4054,10 +4024,12 @@ def transition_day(cli, gameid=0): # be correctly attributed to wolves (for vengeful ghost lover), and that any gunner events # can play. Harlot visiting wolf doesn't play special events if they die via other means since # that assumes they die en route to the wolves (and thus don't shoot/give out gun/etc.) + # TODO: this needs to be split off into angel.py, but all the stuff above it needs to be split off first + # so even though angel.py exists we can't exactly do this now for v in victims_set: if v in var.DYING: victims.append(v) - elif v in var.ROLES["bodyguard"] and var.GUARDED.get(v) in victims_set: + elif v in var.ROLES["bodyguard"] and angel.GUARDED.get(v) in victims_set: vappend.append(v) elif v in var.ROLES["harlot"] and var.HVISITED.get(v) in victims_set: vappend.append(v) @@ -4074,7 +4046,7 @@ def transition_day(cli, gameid=0): prevlen = len(vappend) for v in copy.copy(vappend): - if v in var.ROLES["bodyguard"] and var.GUARDED.get(v) not in vappend: + if v in var.ROLES["bodyguard"] and angel.GUARDED.get(v) not in vappend: vappend.remove(v) victims.append(v) elif v in var.ROLES["harlot"] and var.HVISITED.get(v) not in vappend: @@ -4086,7 +4058,7 @@ def transition_day(cli, gameid=0): fallenmsg = set() if len(var.ROLES["fallen angel"]) > 0: for v in fallenkills: - t = var.GUARDED.get(v) + t = angel.GUARDED.get(v) if v not in fallenmsg: fallenmsg.add(v) if v != t: @@ -4098,7 +4070,7 @@ def transition_day(cli, gameid=0): pm(cli, t, messages["fallen_angel_deprotect"]) # Also message GAs that don't die and their victims for g in var.ROLES["guardian angel"]: - v = var.GUARDED.get(g) + v = angel.GUARDED.get(g) if v in bywolves and g not in fallenkills: if g not in fallenmsg: fallenmsg.add(g) @@ -4170,16 +4142,6 @@ def transition_day(cli, gameid=0): if victim not in revt.data["bitten"]: revt.data["message"].append(messages["target_not_home"]) revt.data["novictmsg"] = False - elif revt.data["protected"].get(victim) == "angel": - revt.data["message"].append(messages["angel_protection"].format(victim)) - revt.data["novictmsg"] = False - elif revt.data["protected"].get(victim) == "bodyguard": - for bodyguard in var.ROLES["bodyguard"]: - if var.GUARDED.get(bodyguard) == victim: - revt.data["dead"].append(bodyguard) - revt.data["message"].append(messages["bodyguard_protection"].format(bodyguard)) - revt.data["novictmsg"] = False - break elif revt.data["protected"].get(victim) == "blessing": # don't play any special message for a blessed target, this means in a game with priest and monster it's not really possible # for wolves to tell which is which. May want to change that in the future to be more obvious to wolves since there's not really @@ -4281,28 +4243,6 @@ def transition_day(cli, gameid=0): bywolves.add(harlot) onlybywolves.add(harlot) dead.append(harlot) - for bodyguard in var.ROLES["bodyguard"]: - if var.GUARDED.get(bodyguard) in list_players(var.WOLF_ROLES) and bodyguard not in dead and bodyguard not in bitten: - r = random.random() - if r < var.BODYGUARD_DIES_CHANCE: - bywolves.add(bodyguard) - onlybywolves.add(bodyguard) - if var.ROLE_REVEAL == "on": - message.append(messages["bodyguard_protected_wolf"].format(bodyguard)) - else: # off and team - message.append(messages["bodyguard_protection"].format(bodyguard)) - dead.append(bodyguard) - for gangel in var.ROLES["guardian angel"]: - if var.GUARDED.get(gangel) in list_players(var.WOLF_ROLES) and gangel not in dead and gangel not in bitten: - r = random.random() - if r < var.GUARDIAN_ANGEL_DIES_CHANCE: - bywolves.add(gangel) - onlybywolves.add(gangel) - if var.ROLE_REVEAL == "on": - message.append(messages["guardian_angel_protected_wolf"].format(gangel)) - else: # off and team - message.append(messages["guardian_angel_protected_wolf_no_reveal"].format(gangel)) - dead.append(gangel) for victim in list(dead): if victim in var.GUNNERS.keys() and var.GUNNERS[victim] > 0 and victim in bywolves: @@ -4419,11 +4359,10 @@ def chk_nightdone(cli): pl = list_players() spl = set(pl) - actedcount = sum(map(len, (var.HVISITED, var.GUARDED, var.PASSED, var.OBSERVED, + actedcount = sum(map(len, (var.HVISITED, var.PASSED, var.OBSERVED, var.HEXED, var.CURSED, var.CHARMERS))) - nightroles = get_roles("harlot", "succubus", "bodyguard", "guardian angel", - "sorcerer", "hag", "warlock", "piper", "prophet") + nightroles = get_roles("harlot", "succubus", "sorcerer", "hag", "warlock", "piper", "prophet") for nick, info in var.PRAYED.items(): if info[0] > 0: @@ -4642,11 +4581,6 @@ def check_exchange(cli, actor, nick): elif actor_role == "clone": if actor in var.CLONED: actor_target = var.CLONED.pop(actor) - elif actor_role in ("bodyguard", "guardian angel"): - if actor in var.GUARDED: - pm(cli, var.GUARDED.pop(actor), messages["protector_disappeared"]) - if actor in var.LASTGUARDED: - del var.LASTGUARDED[actor] elif actor_role in ("werecrow", "sorcerer"): if actor in var.OBSERVED: del var.OBSERVED[actor] @@ -4687,11 +4621,6 @@ def check_exchange(cli, actor, nick): elif nick_role == "clone": if nick in var.CLONED: nick_target = var.CLONED.pop(nick) - elif nick_role in ("bodyguard", "guardian angel"): - if nick in var.GUARDED: - pm(cli, var.GUARDED.pop(nick), messages["protector_disappeared"]) - if nick in var.LASTGUARDED: - del var.LASTGUARDED[nick] elif nick_role in ("werecrow", "sorcerer"): if nick in var.OBSERVED: del var.OBSERVED[nick] @@ -4946,39 +4875,6 @@ def shoot(cli, nick, chan, rest): def is_safe(nick, victim): # helper function return nick in var.ENTRANCED and victim in var.ROLES["succubus"] -@cmd("guard", "protect", "save", chan=False, pm=True, playing=True, silenced=True, phases=("night",), roles=("bodyguard", "guardian angel")) -def guard(cli, nick, chan, rest): - """Guard a player, preventing them from being killed that night.""" - if var.GUARDED.get(nick): - pm(cli, nick, messages["already_protecting"]) - return - role = get_role(nick) - victim = get_victim(cli, nick, re.split(" +",rest)[0], False, role == "bodyguard" or var.GUARDIAN_ANGEL_CAN_GUARD_SELF) - if not victim: - return - - if role == "guardian angel" and var.LASTGUARDED.get(nick) == victim: - pm(cli, nick, messages["guardian_target_another"].format(victim)) - return - if victim == nick: - if role == "bodyguard" or not var.GUARDIAN_ANGEL_CAN_GUARD_SELF: - pm(cli, nick, messages["cannot_guard_self"]) - return - elif role == "guardian angel": # choosing to guard self bypasses lucky/misdirection - var.GUARDED[nick] = nick - var.LASTGUARDED[nick] = nick - pm(cli, nick, messages["guardian_guard_self"]) - else: - victim = choose_target(nick, victim) - if check_exchange(cli, nick, victim): - return - var.GUARDED[nick] = victim - var.LASTGUARDED[nick] = victim - pm(cli, nick, messages["protecting_target"].format(var.GUARDED[nick])) - pm(cli, var.GUARDED[nick], messages["target_protected"]) - debuglog("{0} ({1}) GUARD: {2} ({3})".format(nick, role, victim, get_role(victim))) - chk_nightdone(cli) - @cmd("bless", chan=False, pm=True, playing=True, silenced=True, phases=("day",), roles=("priest",)) def bless(cli, nick, chan, rest): """Bless a player, preventing them from being killed for the remainder of the game.""" @@ -5345,7 +5241,7 @@ def bite_cmd(cli, nick, chan, rest): chk_nightdone(cli) @cmd("pass", chan=False, pm=True, playing=True, phases=("night",), - roles=("harlot", "bodyguard", "guardian angel", "turncoat", "warlock", "piper", "succubus")) + roles=("harlot", "turncoat", "warlock", "piper", "succubus")) def pass_cmd(cli, nick, chan, rest): """Decline to use your special power for that night.""" nickrole = get_role(nick) @@ -5370,12 +5266,6 @@ def pass_cmd(cli, nick, chan, rest): return var.HVISITED[nick] = None pm(cli, nick, messages["succubus_pass"]) - elif nickrole == "bodyguard" or nickrole == "guardian angel": - if var.GUARDED.get(nick): - pm(cli, nick, messages["already_protecting"]) - return - var.GUARDED[nick] = None - pm(cli, nick, messages["guardian_no_protect"]) elif nickrole == "turncoat": if var.TURNCOATS[nick][1] == var.NIGHT_COUNT: # theoretically passing would revert them to how they were before, but @@ -5880,7 +5770,6 @@ def transition_night(cli): var.TIMERS = {} # Reset nighttime variables - var.GUARDED = {} # key = by whom, value = the person that is visited var.KILLER = "" # nickname of who chose the victim var.HEXED = set() # set of hags that have hexed var.CURSED = set() # set of warlocks that have cursed @@ -5975,42 +5864,6 @@ def transition_night(cli): pm(cli, harlot, messages["harlot_simple"]) # !simple pm(cli, harlot, "Players: " + ", ".join(pl)) - # the messages for angel and guardian angel are different enough to merit individual loops - for g_angel in var.ROLES["bodyguard"]: - pl = ps[:] - random.shuffle(pl) - pl.remove(g_angel) - chance = math.floor(var.BODYGUARD_DIES_CHANCE * 100) - warning = "" - if chance > 0: - warning = messages["bodyguard_death_chance"].format(chance) - - if g_angel in var.PLAYERS and not is_user_simple(g_angel): - pm(cli, g_angel, messages["bodyguard_notify"].format(warning)) - else: - pm(cli, g_angel, messages["bodyguard_simple"]) # !simple - pm(cli, g_angel, "Players: " + ", ".join(pl)) - - for gangel in var.ROLES["guardian angel"]: - pl = ps[:] - random.shuffle(pl) - gself = messages["guardian_self_notification"] - if not var.GUARDIAN_ANGEL_CAN_GUARD_SELF: - pl.remove(gangel) - gself = "" - if var.LASTGUARDED.get(gangel) in pl: - pl.remove(var.LASTGUARDED[gangel]) - chance = math.floor(var.GUARDIAN_ANGEL_DIES_CHANCE * 100) - warning = "" - if chance > 0: - warning = messages["bodyguard_death_chance"].format(chance) - - if gangel in var.PLAYERS and not is_user_simple(gangel): - pm(cli, gangel, messages["guardian_notify"].format(warning, gself)) - else: - pm(cli, gangel, messages["guardian_simple"]) # !simple - pm(cli, gangel, "Players: " + ", ".join(pl)) - for pht in var.ROLES["prophet"]: chance1 = math.floor(var.PROPHET_REVEALED_CHANCE[0] * 100) chance2 = math.floor(var.PROPHET_REVEALED_CHANCE[1] * 100) @@ -6417,11 +6270,9 @@ def start(cli, nick, chan, forced = False, restart = ""): var.ROLES = {} var.GUNNERS = {} var.OBSERVED = {} - var.GUARDED = {} var.HVISITED = {} var.CLONED = {} var.TARGETED = {} - var.LASTGUARDED = {} var.LASTHEXED = {} var.MATCHMAKERS = set() var.REVEALED_MAYORS = set()