Split GA and bodyguard
This commit is contained in:
parent
87e8b57745
commit
446d77b452
258
src/roles/angel.py
Normal file
258
src/roles/angel.py
Normal file
@ -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:
|
187
src/wolfgame.py
187
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]
|
target = var.TARGETED[nick]
|
||||||
del var.TARGETED[nick]
|
del var.TARGETED[nick]
|
||||||
if target != None and target in pl:
|
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":
|
if "totem" in var.ACTIVE_PROTECTIONS[target] and nickrole != "fallen angel":
|
||||||
var.ACTIVE_PROTECTIONS[target].remove("totem")
|
var.ACTIVE_PROTECTIONS[target].remove("totem")
|
||||||
message = messages["assassin_fail_totem"].format(nick, target)
|
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)
|
cli.msg(botconfig.CHANNEL, message)
|
||||||
elif "bodyguard" in var.ACTIVE_PROTECTIONS[target] and nickrole != "fallen angel":
|
elif "bodyguard" in var.ACTIVE_PROTECTIONS[target] and nickrole != "fallen angel":
|
||||||
var.ACTIVE_PROTECTIONS[target].remove("bodyguard")
|
var.ACTIVE_PROTECTIONS[target].remove("bodyguard")
|
||||||
|
from src.roles import angel
|
||||||
for ga in var.ROLES["bodyguard"]:
|
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)
|
message = messages["assassin_fail_bodyguard"].format(nick, target, ga)
|
||||||
cli.msg(botconfig.CHANNEL, message)
|
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)
|
pl = refresh_pl(pl)
|
||||||
break
|
break
|
||||||
elif "blessing" in var.ACTIVE_PROTECTIONS[target] or (var.GAMEPHASE == "day" and target in var.ROLES["blessed villager"]):
|
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:
|
if var.PHASE in var.GAME_PHASES:
|
||||||
# remove the player from variables if they're in there
|
# remove the player from variables if they're in there
|
||||||
if ret:
|
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):
|
for k in list(x):
|
||||||
if nick in (k, x[k]):
|
if nick in (k, x[k]):
|
||||||
del x[k]
|
del x[k]
|
||||||
@ -3416,9 +3418,8 @@ def rename_player(cli, prefix, nick):
|
|||||||
if prefix in var.PRAYED.keys():
|
if prefix in var.PRAYED.keys():
|
||||||
del var.PRAYED[prefix]
|
del var.PRAYED[prefix]
|
||||||
|
|
||||||
for dictvar in (var.HVISITED, var.OBSERVED, var.GUARDED, var.TARGETED,
|
for dictvar in (var.HVISITED, var.OBSERVED, var.TARGETED,
|
||||||
var.CLONED, var.LASTGUARDED, var.LASTHEXED,
|
var.CLONED, var.LASTHEXED, var.BITE_PREFERENCES):
|
||||||
var.BITE_PREFERENCES):
|
|
||||||
kvp = []
|
kvp = []
|
||||||
for a,b in dictvar.items():
|
for a,b in dictvar.items():
|
||||||
if a == prefix:
|
if a == prefix:
|
||||||
@ -3679,7 +3680,6 @@ def begin_day(cli):
|
|||||||
var.HEXED = set() # set of hags that have silenced others
|
var.HEXED = set() # set of hags that have silenced others
|
||||||
var.OBSERVED = {} # those whom werecrows/sorcerers have observed
|
var.OBSERVED = {} # those whom werecrows/sorcerers have observed
|
||||||
var.HVISITED = {} # those whom harlots have visited
|
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.PASSED = set() # set of certain roles that have opted not to act
|
||||||
var.STARTED_DAY_PLAYERS = len(list_players())
|
var.STARTED_DAY_PLAYERS = len(list_players())
|
||||||
var.SILENCED = copy.copy(var.TOBESILENCED)
|
var.SILENCED = copy.copy(var.TOBESILENCED)
|
||||||
@ -3764,12 +3764,6 @@ def transition_day(cli, gameid=0):
|
|||||||
pl = list_players()
|
pl = list_players()
|
||||||
|
|
||||||
if not var.START_WITH_DAY or not var.FIRST_DAY:
|
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"]):
|
if len(var.HEXED) < len(var.ROLES["hag"]):
|
||||||
for hag in var.ROLES["hag"]:
|
for hag in var.ROLES["hag"]:
|
||||||
if hag not in var.HEXED:
|
if hag not in var.HEXED:
|
||||||
@ -3840,7 +3834,6 @@ def transition_day(cli, gameid=0):
|
|||||||
evt = Event("night_acted", {"acted": False})
|
evt = Event("night_acted", {"acted": False})
|
||||||
evt.dispatch(cli, var, target, crow)
|
evt.dispatch(cli, var, target, crow)
|
||||||
if ((target in var.HVISITED and var.HVISITED[target]) or
|
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.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"]):
|
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))
|
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 victims_set:
|
||||||
if v in var.DYING:
|
if v in var.DYING:
|
||||||
continue # bypass protections
|
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"]:
|
if v in var.ROLES["blessed villager"]:
|
||||||
numkills[v] -= 1
|
numkills[v] -= 1
|
||||||
if numkills[v] >= 0:
|
if numkills[v] >= 0:
|
||||||
@ -3937,23 +3912,18 @@ def transition_day(cli, gameid=0):
|
|||||||
onlybywolves.add(v)
|
onlybywolves.add(v)
|
||||||
else:
|
else:
|
||||||
# player wasn't targeted, but apply protections on them
|
# 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"]:
|
if v in var.ROLES["blessed villager"]:
|
||||||
var.ACTIVE_PROTECTIONS[v].append("blessing")
|
var.ACTIVE_PROTECTIONS[v].append("blessing")
|
||||||
|
|
||||||
fallenkills = set()
|
fallenkills = set()
|
||||||
brokentotem = set()
|
brokentotem = set()
|
||||||
from src.roles.shaman import havetotem
|
from src.roles.shaman import havetotem
|
||||||
|
from src.roles import angel
|
||||||
if len(var.ROLES["fallen angel"]) > 0:
|
if len(var.ROLES["fallen angel"]) > 0:
|
||||||
for p, t in list(protected.items()):
|
for p, t in list(protected.items()):
|
||||||
if p in bywolves:
|
if p in bywolves:
|
||||||
for g in var.ROLES["guardian angel"]:
|
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:
|
if g in protected:
|
||||||
del protected[g]
|
del protected[g]
|
||||||
bywolves.add(g)
|
bywolves.add(g)
|
||||||
@ -3963,7 +3933,7 @@ def transition_day(cli, gameid=0):
|
|||||||
victims_set.add(g)
|
victims_set.add(g)
|
||||||
onlybywolves.add(g)
|
onlybywolves.add(g)
|
||||||
for g in var.ROLES["bodyguard"]:
|
for g in var.ROLES["bodyguard"]:
|
||||||
if var.GUARDED.get(g) == p:
|
if angel.GUARDED.get(g) == p:
|
||||||
if g in protected:
|
if g in protected:
|
||||||
del protected[g]
|
del protected[g]
|
||||||
bywolves.add(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
|
# 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
|
# 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.)
|
# 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:
|
for v in victims_set:
|
||||||
if v in var.DYING:
|
if v in var.DYING:
|
||||||
victims.append(v)
|
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)
|
vappend.append(v)
|
||||||
elif v in var.ROLES["harlot"] and var.HVISITED.get(v) in victims_set:
|
elif v in var.ROLES["harlot"] and var.HVISITED.get(v) in victims_set:
|
||||||
vappend.append(v)
|
vappend.append(v)
|
||||||
@ -4074,7 +4046,7 @@ def transition_day(cli, gameid=0):
|
|||||||
|
|
||||||
prevlen = len(vappend)
|
prevlen = len(vappend)
|
||||||
for v in copy.copy(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)
|
vappend.remove(v)
|
||||||
victims.append(v)
|
victims.append(v)
|
||||||
elif v in var.ROLES["harlot"] and var.HVISITED.get(v) not in vappend:
|
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()
|
fallenmsg = set()
|
||||||
if len(var.ROLES["fallen angel"]) > 0:
|
if len(var.ROLES["fallen angel"]) > 0:
|
||||||
for v in fallenkills:
|
for v in fallenkills:
|
||||||
t = var.GUARDED.get(v)
|
t = angel.GUARDED.get(v)
|
||||||
if v not in fallenmsg:
|
if v not in fallenmsg:
|
||||||
fallenmsg.add(v)
|
fallenmsg.add(v)
|
||||||
if v != t:
|
if v != t:
|
||||||
@ -4098,7 +4070,7 @@ def transition_day(cli, gameid=0):
|
|||||||
pm(cli, t, messages["fallen_angel_deprotect"])
|
pm(cli, t, messages["fallen_angel_deprotect"])
|
||||||
# Also message GAs that don't die and their victims
|
# Also message GAs that don't die and their victims
|
||||||
for g in var.ROLES["guardian angel"]:
|
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 v in bywolves and g not in fallenkills:
|
||||||
if g not in fallenmsg:
|
if g not in fallenmsg:
|
||||||
fallenmsg.add(g)
|
fallenmsg.add(g)
|
||||||
@ -4170,16 +4142,6 @@ def transition_day(cli, gameid=0):
|
|||||||
if victim not in revt.data["bitten"]:
|
if victim not in revt.data["bitten"]:
|
||||||
revt.data["message"].append(messages["target_not_home"])
|
revt.data["message"].append(messages["target_not_home"])
|
||||||
revt.data["novictmsg"] = False
|
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":
|
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
|
# 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
|
# 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)
|
bywolves.add(harlot)
|
||||||
onlybywolves.add(harlot)
|
onlybywolves.add(harlot)
|
||||||
dead.append(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):
|
for victim in list(dead):
|
||||||
if victim in var.GUNNERS.keys() and var.GUNNERS[victim] > 0 and victim in bywolves:
|
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()
|
pl = list_players()
|
||||||
spl = set(pl)
|
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)))
|
var.HEXED, var.CURSED, var.CHARMERS)))
|
||||||
|
|
||||||
nightroles = get_roles("harlot", "succubus", "bodyguard", "guardian angel",
|
nightroles = get_roles("harlot", "succubus", "sorcerer", "hag", "warlock", "piper", "prophet")
|
||||||
"sorcerer", "hag", "warlock", "piper", "prophet")
|
|
||||||
|
|
||||||
for nick, info in var.PRAYED.items():
|
for nick, info in var.PRAYED.items():
|
||||||
if info[0] > 0:
|
if info[0] > 0:
|
||||||
@ -4642,11 +4581,6 @@ def check_exchange(cli, actor, nick):
|
|||||||
elif actor_role == "clone":
|
elif actor_role == "clone":
|
||||||
if actor in var.CLONED:
|
if actor in var.CLONED:
|
||||||
actor_target = var.CLONED.pop(actor)
|
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"):
|
elif actor_role in ("werecrow", "sorcerer"):
|
||||||
if actor in var.OBSERVED:
|
if actor in var.OBSERVED:
|
||||||
del var.OBSERVED[actor]
|
del var.OBSERVED[actor]
|
||||||
@ -4687,11 +4621,6 @@ def check_exchange(cli, actor, nick):
|
|||||||
elif nick_role == "clone":
|
elif nick_role == "clone":
|
||||||
if nick in var.CLONED:
|
if nick in var.CLONED:
|
||||||
nick_target = var.CLONED.pop(nick)
|
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"):
|
elif nick_role in ("werecrow", "sorcerer"):
|
||||||
if nick in var.OBSERVED:
|
if nick in var.OBSERVED:
|
||||||
del var.OBSERVED[nick]
|
del var.OBSERVED[nick]
|
||||||
@ -4946,39 +4875,6 @@ def shoot(cli, nick, chan, rest):
|
|||||||
def is_safe(nick, victim): # helper function
|
def is_safe(nick, victim): # helper function
|
||||||
return nick in var.ENTRANCED and victim in var.ROLES["succubus"]
|
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",))
|
@cmd("bless", chan=False, pm=True, playing=True, silenced=True, phases=("day",), roles=("priest",))
|
||||||
def bless(cli, nick, chan, rest):
|
def bless(cli, nick, chan, rest):
|
||||||
"""Bless a player, preventing them from being killed for the remainder of the game."""
|
"""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)
|
chk_nightdone(cli)
|
||||||
|
|
||||||
@cmd("pass", chan=False, pm=True, playing=True, phases=("night",),
|
@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):
|
def pass_cmd(cli, nick, chan, rest):
|
||||||
"""Decline to use your special power for that night."""
|
"""Decline to use your special power for that night."""
|
||||||
nickrole = get_role(nick)
|
nickrole = get_role(nick)
|
||||||
@ -5370,12 +5266,6 @@ def pass_cmd(cli, nick, chan, rest):
|
|||||||
return
|
return
|
||||||
var.HVISITED[nick] = None
|
var.HVISITED[nick] = None
|
||||||
pm(cli, nick, messages["succubus_pass"])
|
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":
|
elif nickrole == "turncoat":
|
||||||
if var.TURNCOATS[nick][1] == var.NIGHT_COUNT:
|
if var.TURNCOATS[nick][1] == var.NIGHT_COUNT:
|
||||||
# theoretically passing would revert them to how they were before, but
|
# theoretically passing would revert them to how they were before, but
|
||||||
@ -5880,7 +5770,6 @@ def transition_night(cli):
|
|||||||
var.TIMERS = {}
|
var.TIMERS = {}
|
||||||
|
|
||||||
# Reset nighttime variables
|
# Reset nighttime variables
|
||||||
var.GUARDED = {} # key = by whom, value = the person that is visited
|
|
||||||
var.KILLER = "" # nickname of who chose the victim
|
var.KILLER = "" # nickname of who chose the victim
|
||||||
var.HEXED = set() # set of hags that have hexed
|
var.HEXED = set() # set of hags that have hexed
|
||||||
var.CURSED = set() # set of warlocks that have cursed
|
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, messages["harlot_simple"]) # !simple
|
||||||
pm(cli, harlot, "Players: " + ", ".join(pl))
|
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"]:
|
for pht in var.ROLES["prophet"]:
|
||||||
chance1 = math.floor(var.PROPHET_REVEALED_CHANCE[0] * 100)
|
chance1 = math.floor(var.PROPHET_REVEALED_CHANCE[0] * 100)
|
||||||
chance2 = math.floor(var.PROPHET_REVEALED_CHANCE[1] * 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.ROLES = {}
|
||||||
var.GUNNERS = {}
|
var.GUNNERS = {}
|
||||||
var.OBSERVED = {}
|
var.OBSERVED = {}
|
||||||
var.GUARDED = {}
|
|
||||||
var.HVISITED = {}
|
var.HVISITED = {}
|
||||||
var.CLONED = {}
|
var.CLONED = {}
|
||||||
var.TARGETED = {}
|
var.TARGETED = {}
|
||||||
var.LASTGUARDED = {}
|
|
||||||
var.LASTHEXED = {}
|
var.LASTHEXED = {}
|
||||||
var.MATCHMAKERS = set()
|
var.MATCHMAKERS = set()
|
||||||
var.REVEALED_MAYORS = set()
|
var.REVEALED_MAYORS = set()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user