Experimental stats: intelligently determine if traitor could have died
If it is impossible for other (non-wolf) roles to have killed at night, we do not deduct from the traitor count. This logic isn't perfect yet, but should cover the majority of cases.
This commit is contained in:
parent
bde640c9ae
commit
740d14ef72
@ -239,4 +239,13 @@ def on_reset(evt, var):
|
||||
KILLS.clear()
|
||||
TARGETS.clear()
|
||||
|
||||
@event_listener("get_role_metadata")
|
||||
def on_get_role_metadata(evt, cli, var, kind):
|
||||
if kind == "night_kills":
|
||||
num = 0
|
||||
for dull in var.ROLES["dullahan"]:
|
||||
if TARGETS[dull] - var.DEAD:
|
||||
num += 1
|
||||
evt.data["dullahan"] = num
|
||||
|
||||
# vim: set sw=4 expandtab:
|
||||
|
@ -160,4 +160,12 @@ def on_reset(evt, var):
|
||||
PASSED.clear()
|
||||
HUNTERS.clear()
|
||||
|
||||
@event_listener("get_role_metadata")
|
||||
def on_get_role_metadata(evt, cli, var, kind):
|
||||
if kind == "night_kills":
|
||||
# hunters is the set of all hunters that have not killed in a *previous* night
|
||||
# (if they're in both HUNTERS and KILLS, then they killed tonight and should be counted)
|
||||
hunters = (set(var.ROLES["hunter"]) - HUNTERS) | set(KILLS.keys())
|
||||
evt.data["hunter"] = len(hunters)
|
||||
|
||||
# vim: set sw=4 expandtab:
|
||||
|
@ -645,4 +645,12 @@ def on_frole_role(evt, cli, var, who, role, oldrole, args):
|
||||
TOTEMS[shaman] = t
|
||||
break
|
||||
|
||||
@event_listener("get_role_metadata")
|
||||
def on_get_role_metadata(evt, cli, var, kind):
|
||||
if kind == "night_kills":
|
||||
# only add shamans here if they were given a death totem
|
||||
# even though retribution kills, it is given a special kill message
|
||||
# note that all shaman types (shaman/CS/wolf shaman) are lumped under the "shaman" key
|
||||
evt.data["shaman"] = list(TOTEMS.values()).count("death")
|
||||
|
||||
# vim: set sw=4 expandtab:
|
||||
|
@ -28,13 +28,36 @@ def on_get_final_role(evt, cli, var, nick, role):
|
||||
if role == "traitor" and evt.data["role"] == "wolf":
|
||||
evt.data["role"] = "traitor"
|
||||
|
||||
@event_listener("update_stats")
|
||||
def on_update_stats(evt, cli, var, nick, nickrole, nickreveal, nicktpls):
|
||||
@event_listener("update_stats", priority=1)
|
||||
def on_update_stats1(evt, cli, var, nick, nickrole, nickreveal, nicktpls):
|
||||
if nickrole == var.DEFAULT_ROLE and var.HIDDEN_TRAITOR:
|
||||
evt.data["possible"].add("traitor")
|
||||
|
||||
@event_listener("update_stats", priority=3)
|
||||
def on_update_stats3(evt, cli, var, nick, nickrole, nickreveal, nicktpls):
|
||||
# if this is a night death and we know for sure that wolves (and only wolves)
|
||||
# killed, then that kill cannot be traitor as long as they're in wolfchat.
|
||||
# TODO: need to figure out how to actually piece this together, but will
|
||||
# likely require splitting off every other role first.
|
||||
# ismain True = night death, False = chain death; chain deaths can be traitors
|
||||
# even if only wolves killed, so we short-circuit there as well
|
||||
# TODO: an observant user will be able to determine if traitor dies due to luck/misdirection totem
|
||||
# redirecting a wolf kill onto traitor
|
||||
if "traitor" not in evt.data["possible"] or not evt.params.ismain or nickrole == "traitor":
|
||||
return
|
||||
if var.PHASE == "day" and var.GAMEPHASE == "night":
|
||||
mevt = Event("get_role_metadata", {})
|
||||
mevt.dispatch(cli, var, "night_kills")
|
||||
nonwolf = 0
|
||||
total = 0
|
||||
for role, num in mevt.data.items():
|
||||
if role != "wolf":
|
||||
nonwolf += num
|
||||
total += num
|
||||
if nonwolf == 0:
|
||||
evt.data["possible"].discard("traitor")
|
||||
return
|
||||
# TODO: this doesn't account for everything, for example if there was a hunter kill
|
||||
# and a wolf kill, and a wolf + villager died, we know the villager was the wolf kill
|
||||
# and therefore cannot be traitor. However, we currently do not have the logic to deduce this
|
||||
|
||||
|
||||
# vim: set sw=4 expandtab:
|
||||
|
@ -248,4 +248,9 @@ def on_reset(evt, var):
|
||||
KILLS.clear()
|
||||
GHOSTS.clear()
|
||||
|
||||
@event_listener("get_role_metadata")
|
||||
def on_get_role_metadata(evt, cli, var, kind):
|
||||
if kind == "night_kills":
|
||||
evt.data["vengeful ghost"] = sum(1 for against in GHOSTS.values() if against[0] != "!")
|
||||
|
||||
# vim: set sw=4 expandtab:
|
||||
|
@ -145,4 +145,9 @@ def on_reset(evt, var):
|
||||
KILLS.clear()
|
||||
PASSED.clear()
|
||||
|
||||
@event_listener("get_role_metadata")
|
||||
def on_get_role_metadata(evt, cli, var, kind):
|
||||
if kind == "night_kills":
|
||||
evt.data["vigilante"] = len(var.ROLES["vigilante"])
|
||||
|
||||
# vim: set sw=4 expandtab:
|
||||
|
@ -402,4 +402,22 @@ def on_begin_day(evt, cli, var):
|
||||
def on_reset(evt, var):
|
||||
KILLS.clear()
|
||||
|
||||
@event_listener("get_role_metadata")
|
||||
def on_get_role_metadata(evt, cli, var, kind):
|
||||
if kind == "night_kills":
|
||||
if var.DISEASED_WOLVES:
|
||||
evt.data["wolf"] = 0
|
||||
elif var.ANGRY_WOLVES:
|
||||
evt.data["wolf"] = 2
|
||||
else:
|
||||
evt.data["wolf"] = 1
|
||||
# TODO: split into alpha
|
||||
if var.ALPHA_ENABLED:
|
||||
# alpha wolf gives an extra kill; note that we consider someone being
|
||||
# bitten a "kill" for this metadata kind as well
|
||||
# rolled into wolf instead of as a separate alpha wolf key for ease of implementing
|
||||
# special logic for wolf kills vs non-wolf kills (as when alpha kills it is treated
|
||||
# as any other wolf kill).
|
||||
evt.data["wolf"] += 1
|
||||
|
||||
# vim: set sw=4 expandtab:
|
||||
|
@ -2747,7 +2747,13 @@ def del_player(cli, nick, forced_death=False, devoice=True, end_game=True, death
|
||||
event.dispatch(cli, var, nick, nickrole, nicktpls, evt_death_triggers)
|
||||
|
||||
# update var.ROLE_STATS
|
||||
event = Event("update_stats", {"possible": {nickrole, nickreveal}, "known_role": False})
|
||||
# Event priorities:
|
||||
# 1 = Expanding the possible set (e.g. traitor would add themselves if nickrole is villager)
|
||||
# 3 = Removing from the possible set (e.g. can't be traitor if was a night kill and only wolves could kill at night),
|
||||
# 5 = Setting known_role to True if the role is actually known for sure publically (e.g. revealing totem)
|
||||
# 2 and 4 are not used by included roles, but may be useful expansion points for custom roles to modify stats
|
||||
event = Event("update_stats", {"possible": {nickrole, nickreveal}, "known_role": False},
|
||||
killer_role=killer_role, ismain=ismain)
|
||||
event.dispatch(cli, var, nick, nickrole, nickreveal, nicktpls)
|
||||
# Given the set of possible roles this nick could be (or its actual role if known_role is True),
|
||||
# figure out the set of roles that need deducting from their counts in var.ROLE_STATS
|
||||
|
Loading…
Reference in New Issue
Block a user