From 70bced24a6b9f32df668f1331b0c903fdc1c1842 Mon Sep 17 00:00:00 2001 From: skizzerz Date: Thu, 4 Jun 2015 01:30:50 -0500 Subject: [PATCH 1/4] New roles, protection semantics, and alpha fixes This commit adds 3 new roles and changes the semantics of kills/protections to work more like the impatience and pacifism totems. - Add mystic and wolf mystic roles which can divine the number of players still alive on the opposing team each night. These roles are meant for games where role reveal is off as !stats gives the same info otherwise. - Add fallen angel which is a corrupted version of the guardian angel, created when a guardian angel is bitten by alpha wolf. This role is incredibly potent as they bypass all forms of protection on their target. GAs corrupted this way also automatically gain the assassin template. - Protections/kills now stack and cancel each other out. As such, 2 kills but only 1 protection will result in the kill still happening. - Fix help text for active alpha wolf to show the reworked bite command. - If alpha bites someone who is going to die via other means that night, refund the bite. - If the bite was unsuccessful due to whatever reason and was refunded, give a different message to alpha wolf to let them know that. - Make adding more wolf roles in the future easier to do by replacing some hardcoded lists with var.WOLF_ROLES. --- src/settings.py | 8 +- src/wolfgame.py | 451 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 332 insertions(+), 127 deletions(-) diff --git a/src/settings.py b/src/settings.py index e233f01..664b6f7 100644 --- a/src/settings.py +++ b/src/settings.py @@ -103,6 +103,7 @@ GUARDIAN_ANGEL_DIES_CHANCE = 0 BODYGUARD_DIES_CHANCE = 0 DETECTIVE_REVEALED_CHANCE = 2/5 SHARPSHOOTER_CHANCE = 1/5 # if sharpshooter is enabled, chance that a gunner will become a sharpshooter instead +FALLEN_ANGEL_KILLS_GUARDIAN_ANGEL_CHANCE = 1/2 AMNESIAC_NIGHTS = 3 # amnesiac gets to know their actual role on this night ALPHA_WOLF_NIGHTS = 3 # alpha wolf turns the target into a wolf after this many nights (note the night they are bitten is considered night 1) @@ -160,6 +161,7 @@ ROLE_GUIDE = {# village roles "hunter" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ), "shaman" : ( 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ), "doctor" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), + "mystic" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), # wolf roles "wolf" : ( 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 2 , 2 , 2 , 2 , 3 , 3 , 3 ), "traitor" : ( 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ), @@ -172,6 +174,8 @@ ROLE_GUIDE = {# village roles "alpha wolf" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "werekitten" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "warlock" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), + "wolf mystic" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), + "fallen angel" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), # neutral roles "lycan" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), "vengeful ghost" : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), @@ -194,7 +198,7 @@ ROLE_GUIDE = {# village roles # Harlot dies when visiting, seer sees as wolf, gunner kills when shooting, GA and bodyguard have a chance at dying when guarding # If every wolf role dies, and there are no remaining traitors, the game ends and villagers win (monster may steal win) -WOLF_ROLES = ["wolf", "alpha wolf", "werecrow", "wolf cub", "werekitten"] +WOLF_ROLES = ["wolf", "alpha wolf", "werecrow", "wolf cub", "werekitten", "wolf mystic", "fallen angel"] # Access to wolfchat, and counted towards the # of wolves vs villagers when determining if a side has won WOLFCHAT_ROLES = WOLF_ROLES + ["traitor", "hag", "sorcerer", "warlock"] # Wins with the wolves, even if the roles are not necessarily wolves themselves @@ -218,6 +222,8 @@ TEMPLATE_RESTRICTIONS = {"cursed villager" : WOLF_ROLES + ["seer", "oracle", "fo "assassin" : WOLF_ROLES + ["traitor", "seer", "augur", "oracle", "harlot", "detective", "bodyguard", "guardian angel", "lycan"], "bureaucrat" : [], } +# fallen angel can be assassin even though they are a wolf role +TEMPLATE_RESTRICTIONS["assassin"].remove("fallen angel") # Roles listed here cannot be used in !fgame roles=blah. If they are defined in ROLE_GUIDE they may still be used. DISABLED_ROLES = [] diff --git a/src/wolfgame.py b/src/wolfgame.py index 531291d..f8dc2d3 100644 --- a/src/wolfgame.py +++ b/src/wolfgame.py @@ -1305,6 +1305,10 @@ def stats(cli, nick, chan, rest): count += bitten_roles["time lord"] elif role == "wolf": count -= sum(bitten_roles.values()) + # GAs turn into FAs, not wolves + count += bitten_roles["guardian angel"] + elif role == "fallen angel": + count -= bitten_roles["guardian angel"] else: count += bitten_roles[role] @@ -2126,26 +2130,26 @@ def del_player(cli, nick, forced_death = False, devoice = True, end_game = True, target = var.TARGETED[nick] del var.TARGETED[nick] if target != None and target in pl: - if target in var.PROTECTED: + if "totem" in var.ACTIVE_PROTECTIONS[target] and nickrole != "fallen angel": + var.ACTIVE_PROTECTIONS[target].remove("totem") message = ("Before dying, \u0002{0}\u0002 quickly attempts to slit \u0002{1}\u0002's throat; " + "however, {1}'s totem emits a brilliant flash of light, causing the attempt to miss.").format(nick, target) cli.msg(botconfig.CHANNEL, message) - elif target in var.GUARDED.values() and var.GAMEPHASE == "night": - for bg in var.ROLES["guardian angel"]: - if bg in var.GUARDED and var.GUARDED[bg] == target: + elif "angel" in var.ACTIVE_PROTECTIONS[target] and nickrole != "fallen angel": + var.ACTIVE_PROTECTIONS[target].remove("angel") + message = ("Before dying, \u0002{0}\u0002 quickly attempts to slit \u0002{1}\u0002's throat; " + + "however, a guardian angel was on duty and able to foil the attempt.").format(nick, target) + cli.msg(botconfig.CHANNEL, message) + elif "bodyguard" in var.ACTIVE_PROTECTIONS[target] and nickrole != "fallen angel": + var.ACTIVE_PROTECTIONS[target].remove("bodyguard") + for ga in var.ROLES["bodyguard"]: + if var.GUARDED.get(ga) == target: message = ("Before dying, \u0002{0}\u0002 quickly attempts to slit \u0002{1}\u0002's throat; " + - "however, a guardian angel was on duty and able to foil the attempt.").format(nick, target) + "however, \u0002{2}\u0002, a bodyguard, sacrificed their life to protect them.").format(nick, target, ga) cli.msg(botconfig.CHANNEL, message) + del_player(cli, ga, True, end_game = False, killer_role = nickrole, deadlist = deadlist, original = original) + pl.remove(ga) break - else: - for ga in var.ROLES["bodyguard"]: - if ga in var.GUARDED and var.GUARDED[ga] == target: - message = ("Before dying, \u0002{0}\u0002 quickly attempts to slit \u0002{1}\u0002's throat; " + - "however, \u0002{2}\u0002, a bodyguard, sacrificed their life to protect them.").format(nick, target, ga) - cli.msg(botconfig.CHANNEL, message) - del_player(cli, ga, True, end_game = False, killer_role = nickrole, deadlist = deadlist, original = original) - pl.remove(ga) - break else: if var.ROLE_REVEAL: role = var.get_reveal_role(target) @@ -2672,7 +2676,13 @@ def on_nick(cli, oldnick, nick): if prefix in var.DESPERATE: var.DESPERATE.remove(prefix) var.DESPERATE.append(nick) - if prefix in var.PROTECTED: + for k, d in list(var.DEATH_TOTEM): + if k == prefix or d == prefix: + var.DEATH_TOTEM.remove((k, d)) + nk = nick if k == prefix else k + nd = nick if d == prefix else d + var.DEATH_TOTEM.append((nk, nd)) + while prefix in var.PROTECTED: var.PROTECTED.remove(prefix) var.PROTECTED.append(nick) if prefix in var.REVEALED: @@ -2976,6 +2986,7 @@ def begin_day(cli): var.DISEASED = copy.copy(var.TOBEDISEASED) var.MISDIRECTED = copy.copy(var.TOBEMISDIRECTED) var.EXCHANGED = copy.copy(var.TOBEEXCHANGED) + var.ACTIVE_PROTECTIONS = defaultdict(list) msg = ('The villagers must now vote for whom to lynch. '+ 'Use "{0}lynch " to cast your vote. {1} votes '+ @@ -3073,7 +3084,7 @@ def transition_day(cli, gameid=0): var.NO_LYNCH = [] var.DAY_COUNT += 1 var.FIRST_DAY = (var.DAY_COUNT == 1) - havetotem = copy.copy(var.LASTGIVEN) + havetotem = list(var.LASTGIVEN.values()) if var.START_WITH_DAY and var.FIRST_DAY: # TODO: need to message everyone their roles and give a short thing saying "it's daytime" @@ -3138,6 +3149,112 @@ def transition_day(cli, gameid=0): onlybywolves.add(victim) killers[victim].append("@wolves") # special key to let us know to randomly select a wolf + if len(var.ROLES["fallen angel"]) == 0: + for monster in var.ROLES["monster"]: + if monster in victims: + victims.remove(monster) + bywolves.discard(monster) + onlybywolves.discard(monster) + + wolfghostvictims = [] + for ghost, target in var.VENGEFUL_GHOSTS.items(): + if target == "villagers": + victim = var.OTHER_KILLS[ghost] + killers[victim].append(ghost) + if victim not in var.DYING: # wolf ghost killing ghost will take precedence over everything except elder + wolfghostvictims.append(victim) + + for k, d in var.OTHER_KILLS.items(): + victims.append(d) + onlybywolves.discard(d) + killers[d].append(k) + + for k, d in var.DEATH_TOTEM: + victims.append(d) + onlybywolves.discard(d) + killers[d].append(k) + + # handle elder and other auto-deaths + for d in var.DYING: + victims.append(d) + onlybywolves.discard(d) + + victims_set = set(victims) # remove duplicates + victims_set.discard(None) # in the event that ever happens + vappend = [] + # this keeps track of the protections active on each nick, stored in var since del_player needs to access it for sake of assassin + protected = {} + var.ACTIVE_PROTECTIONS = defaultdict(list) + + # Logic out stacked kills and protections. If we get down to 1 kill remaining that is valid and the victim is in bywolves, + # we re-add them to onlybywolves to indicate that the other kill attempts were guarded against (and the wolf kill is what went through) + # If protections >= kills, we keep track of which protection message to show (prot totem > GA > bodyguard) + for v in victims_set: + if v in var.DYING: + # this person is dying no matter what + continue + numkills = sum(1 for n in victims if n == v) + numtotems = sum(1 for n in var.PROTECTED if n == v) + if numtotems >= numkills: + protected[v] = "totem" + if numtotems > numkills: + for i in range(0, numtotems - numkills): + var.ACTIVE_PROTECTIONS[v].append("totem") + numkills -= numtotems + for g in var.ROLES["guardian angel"]: + if var.GUARDED.get(g) == v: + numkills -= 1 + if numkills <= 0 and v not in protected: + protected[v] = "angel" + elif numkills <= 0: + var.ACTIVE_PROTECTIONS[v].append("angel") + for g in var.ROLES["bodyguard"]: + if var.GUARDED.get(g) == v: + numkills -= 1 + if numkills <= 0 and v not in protected: + protected[v] = "bodyguard" + elif numkills <= 0: + var.ACTIVE_PROTECTIONS[v].append("bodyguard") + numkills -= 1 + if numkills == 1 and v in bywolves: + onlybywolves.add(v) + + fallenkills = set() + brokentotem = set() + if len(var.ROLES["fallen angel"]) > 0: + for p, t in list(protected.items()): + if p in bywolves: + if t == "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 g in protected: + del protected[g] + bywolves.add(g) + victims.append(g) + fallenkills.add(g) + if g not in victims_set: + victims_set.add(g) + onlybywolves.add(g) + elif t == "bodyguard": + for g in var.ROLES["bodyguard"]: + if var.GUARDED.get(g) == p: + if g in protected: + del protected[g] + bywolves.add(g) + victims.append(g) + fallenkills.add(g) + if g not in victims_set: + victims_set.add(g) + onlybywolves.add(g) + elif t == "totem": + # we'll never end up killing a shaman who gave out protection, but delete the totem since + # story-wise it gets demolished at night by the FA + while p in havetotem: + havetotem.remove(p) + brokentotem.add(p) + if p in protected: + del protected[p] + if var.ALPHA_ENABLED: # check for bites for (alpha, desired) in var.BITE_PREFERENCES.items(): if len(bywolves) == 0: @@ -3150,57 +3267,38 @@ def transition_day(cli, gameid=0): target = desired else: target = random.choice(tuple(bywolves)) - pm(cli, alpha, "You have bitten \u0002{0}\u0002.".format(target)) targetrole = var.get_role(target) # do the usual checks; we can only bite those that would otherwise die # (e.g. block it on visiting harlot, GA/bodyguard, and protection totem) # also if a lycan is bitten, just turn them into a wolf immediately - if (target not in var.PROTECTED - and target not in var.GUARDED.values() + if (target not in protected and (target not in var.ROLES["harlot"] or not var.HVISITED.get(target)) and target not in var.ROLES["lycan"] and target not in var.LYCANTHROPES and target not in var.IMMUNIZED): - var.BITTEN[target] = var.ALPHA_WOLF_NIGHTS - bitten.append(target) victims.remove(target) bywolves.remove(target) onlybywolves.remove(target) killers[target].remove("@wolves") + if target not in victims: + victims_set.discard(target) + var.BITTEN[target] = var.ALPHA_WOLF_NIGHTS + bitten.append(target) + else: + # someone else also killed them, mark bite unsuccessful + var.ALPHA_WOLVES.remove(alpha) else: # bite was unsuccessful, let them try again var.ALPHA_WOLVES.remove(alpha) + + if alpha in var.ALPHA_WOLVES: + pm(cli, alpha, "You have bitten \u0002{0}\u0002.".format(target)) + else: + pm(cli, alpha, "You tried to bite \u0002{0}\u0002, but it didn't work. Better luck next time!".format(target)) + var.BITE_PREFERENCES = {} - - for monster in var.ROLES["monster"]: - if monster in victims: - victims.remove(monster) - bywolves.discard(monster) - onlybywolves.discard(monster) - - wolfghostvictims = [] - for ghost, target in var.VENGEFUL_GHOSTS.items(): - if target == "villagers": - victim = var.OTHER_KILLS[ghost] - killers[victim].append(ghost) - if victim not in var.DYING: # wolf ghost killing ghost will take precedence over everything except death totem and elder - wolfghostvictims.append(victim) - - for k, d in var.OTHER_KILLS.items(): - victims.append(d) - onlybywolves.discard(d) - killers[d].append(k) - for d in var.DYING: - victims.append(d) - onlybywolves.discard(d) - for s, v in var.LASTGIVEN.items(): - if v == d and var.TOTEMS[s] == "death": - killers[d].append(s) - victims_set = set(victims) # remove duplicates - victims_set.discard(None) # in the event that ever happens victims = [] - vappend = [] # Ensures that special events play for bodyguard and harlot-visiting-victim so that kill can # 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 @@ -3230,6 +3328,37 @@ def transition_day(cli, gameid=0): vappend.remove(v) victims.append(v) + # If FA is killing through a guard, let them as well as the victim know so they don't + # try to report the extra kills as a bug + fallenmsg = set() + if len(var.ROLES["fallen angel"]) > 0: + for v in fallenkills: + t = var.GUARDED.get(v) + if v not in fallenmsg: + fallenmsg.add(v) + if v != t: + pm(cli, v, ("A fell wind starts blowing through the village and you catch the flurry of blackened wings out of the corner of your eye. " + + "No longer caring for \u0002{0}\u0002's safety, you attempt to get away before your own life is taken...").format(t)) + else: + pm(cli, v, "A fell wind blows through you and chills you to the bone. You no longer feel safe or protected...") + if v != t and t not in fallenmsg: + fallenmsg.add(t) + pm(cli, t, "A fell wind blows through you and chills you to the bone. You no longer feel safe or protected...") + # Also message GAs that don't die and their victims + for g in var.ROLES["guardian angel"]: + v = var.GUARDED.get(g) + if v in bywolves and g not in fallenkills: + if g not in fallenmsg: + fallenmsg.add(g) + if g != v: + pm(cli, g, ("A fell wind starts blowing through the village and you catch the flurry of blackened wings out of the corner of your eye. " + + "No longer caring for \u0002{0}\u0002's safety, you attempt to get away before your own life is taken...").format(v)) + else: + pm(cli, g, "A fell wind blows through you and chills you to the bone. You no longer feel safe or protected...") + if g != v and v not in fallenmsg: + fallenmsg.add(g) + pm(cli, v, "A fell wind blows through you and chills you to the bone. You no longer feel safe or protected...") + # Select a random target for assassin that isn't already going to die if they didn't target pl = var.list_players() for ass in var.ROLES["assassin"]: @@ -3288,24 +3417,21 @@ def transition_day(cli, gameid=0): if victim in var.ROLES["harlot"] and var.HVISITED.get(victim) and victim not in var.DYING and victim not in dead and victim in onlybywolves: message.append("The wolves' selected victim was a harlot, who was not at home last night.") novictmsg = False - elif victim in var.PROTECTED and victim not in var.DYING: + elif protected.get(victim) == "totem": message.append(("\u0002{0}\u0002 was attacked last night, but their totem " + "emitted a brilliant flash of light, blinding the attacker and " + "allowing them to escape.").format(victim)) novictmsg = False - elif victim in var.GUARDED.values() and victim not in var.DYING: - for gangel in var.ROLES["guardian angel"]: - if var.GUARDED.get(gangel) == victim: - message.append(("\u0002{0}\u0002 was attacked last night, but luckily, the guardian angel was on duty.").format(victim)) + elif protected.get(victim) == "angel": + message.append(("\u0002{0}\u0002 was attacked last night, but luckily, the guardian angel was on duty.").format(victim)) + novictmsg = False + elif protected.get(victim) == "bodyguard": + for bodyguard in var.ROLES["bodyguard"]: + if var.GUARDED.get(bodyguard) == victim: + dead.append(bodyguard) + message.append(("\u0002{0}\u0002 sacrificed their life to guard that of another.").format(bodyguard)) novictmsg = False break - else: - for bodyguard in var.ROLES["bodyguard"]: - if var.GUARDED.get(bodyguard) == victim: - dead.append(bodyguard) - message.append(("\u0002{0}\u0002 sacrificed their life to guard that of another.").format(bodyguard)) - novictmsg = False - break elif (victim in var.ROLES["lycan"] or victim in var.LYCANTHROPES) and victim in onlybywolves and victim not in var.IMMUNIZED: vrole = var.get_role(victim) if vrole not in var.WOLFCHAT_ROLES: @@ -3459,21 +3585,25 @@ def transition_day(cli, gameid=0): if var.WOLF_STEALS_GUN and victim in bywolves and victim in var.GUNNERS.keys() and var.GUNNERS[victim] > 0: # victim has bullets try: - while True: - guntaker = random.choice(var.list_players(var.WOLFCHAT_ROLES)) # random looter + looters = var.list_players(var.WOLFCHAT_ROLES) + while len(looters) > 0: + guntaker = random.choice(looters) # random looter if guntaker not in dead: break - numbullets = var.GUNNERS[victim] - if guntaker not in var.WOLF_GUNNERS: - var.WOLF_GUNNERS[guntaker] = 0 - var.WOLF_GUNNERS[guntaker] += 1 # transfer bullets a wolf - mmsg = ("While searching {0}'s belongings, you found " + - "a gun loaded with 1 silver bullet! " + - "You may only use it during the day. " + - "If you shoot at a wolf, you will intentionally miss. " + - "If you shoot a villager, it is likely that they will be injured.") - mmsg = mmsg.format(victim) - pm(cli, guntaker, mmsg) + else: + looters.remove(guntaker) + if guntaker not in dead: + numbullets = var.GUNNERS[victim] + if guntaker not in var.WOLF_GUNNERS: + var.WOLF_GUNNERS[guntaker] = 0 + var.WOLF_GUNNERS[guntaker] += 1 # transfer bullets a wolf + mmsg = ("While searching {0}'s belongings, you found " + + "a gun loaded with 1 silver bullet! " + + "You may only use it during the day. " + + "If you shoot at a wolf, you will intentionally miss. " + + "If you shoot a villager, it is likely that they will be injured.") + mmsg = mmsg.format(victim) + pm(cli, guntaker, mmsg) except IndexError: pass # no wolves to give gun to (they were all killed during night or something) var.GUNNERS[victim] = 0 # just in case @@ -3497,9 +3627,11 @@ def transition_day(cli, gameid=0): del_player(cli, deadperson, end_game = False, killer_role = "wolf" if deadperson in onlybywolves or deadperson in wolfghostvictims else "villager", deadlist = dead, original = deadperson) message = [] - for havetotem in havetotem.values(): + for havetotem in havetotem: if havetotem: message.append("\u0002{0}\u0002 seem{1} to be in possession of a mysterious totem...".format(havetotem, "ed" if havetotem in dead else "s")) + for brokentotem in brokentotem: + message.append("Broken totem pieces were found next to \u0002{0}\u0002's body...".format(brokentotem)) cli.msg(chan, "\n".join(message)) if chk_win(cli): # if after the last person is killed, one side wins, then actually end the game here @@ -3518,13 +3650,13 @@ def chk_nightdone(cli): var.ROLES["werecrow"] + var.ROLES["alpha wolf"] + var.ROLES["sorcerer"] + var.ROLES["hunter"] + list(var.VENGEFUL_GHOSTS.keys()) + var.ROLES["hag"] + var.ROLES["shaman"] + var.ROLES["crazed shaman"] + var.ROLES["augur"] + var.ROLES["werekitten"] + - var.ROLES["warlock"] + var.ROLES["piper"]) + var.ROLES["warlock"] + var.ROLES["piper"] + var.ROLES["wolf mystic"] + var.ROLES["fallen angel"]) if var.FIRST_NIGHT: actedcount += len(var.MATCHMAKERS + list(var.CLONED.keys())) nightroles += var.ROLES["matchmaker"] + var.ROLES["clone"] if var.DISEASED_WOLVES: - nightroles = [p for p in nightroles if p not in (var.ROLES["wolf"] + var.ROLES["alpha wolf"] + var.ROLES["werekitten"])] + nightroles = [p for p in nightroles if p not in var.list_players(("wolf", "alpha wolf", "werekitten", "wolf mystic", "fallen angel"))] for p in var.HUNTERS: # only remove one instance of their name if they have used hunter ability, in case they have templates @@ -3729,7 +3861,7 @@ def check_exchange(cli, actor, nick): var.SHAMANS.remove(actor) if actor in var.LASTGIVEN: del var.LASTGIVEN[actor] - elif actor_role == "wolf" or actor_role == "werekitten": + elif actor_role in ("wolf", "werekitten", "wolf mystic", "fallen angel"): if actor in var.KILLS: del var.KILLS[actor] elif actor_role == "hunter": @@ -3795,7 +3927,7 @@ def check_exchange(cli, actor, nick): var.SHAMANS.remove(nick) if nick in var.LASTGIVEN: del var.LASTGIVEN[nick] - elif nick_role == "wolf" or nick_role == "werekitten": + elif nick_role in ("wolf", "werekitten", "wolf mystic", "fallen angel"): if nick in var.KILLS: del var.KILLS[nick] elif nick_role == "hunter": @@ -3879,6 +4011,9 @@ def check_exchange(cli, actor, nick): if nick_role == "shaman": pm(cli, actor, "You have a \u0002{0}\u0002 totem.".format(nick_totem)) var.TOTEMS[actor] = nick_totem + elif nick_role == "mystic": + numevil = len(var.list_players(var.WOLFTEAM_ROLES)) + pm(cli, actor, "There are \u0002{0}\u0002 evil villager{1} still alive.".format(numevil, "s" if numevil != 1 else "")) elif nick_role in var.WOLFCHAT_ROLES and actor_role not in var.WOLFCHAT_ROLES: pl = var.list_players() random.shuffle(pl) @@ -3895,15 +4030,17 @@ def check_exchange(cli, actor, nick): pl[i] = player + " (cursed)" pm(cli, actor, "Players: " + ", ".join(pl)) - angry_alpha = '' + if actor_role == "wolf mystic": + # # of special villagers = # of players - # of villagers - # of wolves - # of neutrals + numvills = len(ps) - len(var.list_players(var.WOLFTEAM_ROLES)) - len(var.list_players(("villager",))) - len(var.list_players(var.TRUE_NEUTRAL_ROLES)) + pm(cli, actor, "There are \u0002{0}\u0002 special villager{1} still alive.".format(numvills, "s" if numvills != 1 else "")) if var.DISEASED_WOLVES: pm(cli, actor, 'You are feeling ill tonight, and are unable to kill anyone.') - elif var.ANGRY_WOLVES and actor_role in ("wolf", "werecrow", "alpha wolf", "werekitten"): + elif var.ANGRY_WOLVES and actor_role in var.WOLF_ROLES and actor_role != "wolf cub": pm(cli, actor, 'You are \u0002angry\u0002 tonight, and may kill two targets by using "kill and ".') - angry_alpha = ' ' if var.ALPHA_ENABLED and actor_role == "alpha wolf" and actor not in var.ALPHA_WOLVES: - pm(cli, actor, ('You may use "bite{0}" tonight in order to turn the wolves\' target into a wolf instead of killing them. ' + - 'They will turn into a wolf in {1} night{2}.').format(angry_alpha, var.ALPHA_WOLF_NIGHTS, 's' if var.ALPHA_WOLF_NIGHTS > 1 else '')) + pm(cli, actor, ('You may use "bite " tonight in order to turn the wolves\' target into a wolf instead of killing them. ' + + 'They will turn into a wolf in {0} night{1}.').format(var.ALPHA_WOLF_NIGHTS, 's' if var.ALPHA_WOLF_NIGHTS > 1 else '')) elif nick_role == "minion": wolves = var.list_players(var.WOLF_ROLES) random.shuffle(wolves) @@ -3915,6 +4052,9 @@ def check_exchange(cli, actor, nick): if actor_role == "shaman": pm(cli, nick, "You have a \u0002{0}\u0002 totem.".format(actor_totem)) var.TOTEMS[nick] = actor_totem + elif actor_role == "mystic": + numevil = len(var.list_players(var.WOLFTEAM_ROLES)) + pm(cli, nick, "There are \u0002{0}\u0002 evil villager{1} still alive.".format(numevil, "s" if numevil != 1 else "")) elif actor_role in var.WOLFCHAT_ROLES and nick_role not in var.WOLFCHAT_ROLES: pl = var.list_players() random.shuffle(pl) @@ -3931,15 +4071,17 @@ def check_exchange(cli, actor, nick): pl[i] = player + " (cursed)" pm(cli, nick, "Players: " + ", ".join(pl)) - angry_alpha = '' + if nick_role == "wolf mystic": + # # of special villagers = # of players - # of villagers - # of wolves - # of neutrals + numvills = len(ps) - len(var.list_players(var.WOLFTEAM_ROLES)) - len(var.list_players(("villager",))) - len(var.list_players(var.TRUE_NEUTRAL_ROLES)) + pm(cli, nick, "There are \u0002{0}\u0002 special villager{1} still alive.".format(numvills, "s" if numvills != 1 else "")) if var.DISEASED_WOLVES: pm(cli, nick, 'You are feeling ill tonight, and are unable to kill anyone.') elif var.ANGRY_WOLVES and nick_role in ("wolf", "werecrow", "alpha wolf", "werekitten"): pm(cli, nick, 'You are \u0002angry\u0002 tonight, and may kill two targets by using "kill and ".') - angry_alpha = ' ' if var.ALPHA_ENABLED and nick_role == "alpha wolf" and nick not in var.ALPHA_WOLVES: - pm(cli, nick, ('You may use "bite{0}" tonight in order to turn the wolves\' target into a wolf instead of killing them. ' + - 'They will turn into a wolf in {1} night{2}.').format(angry_alpha, var.ALPHA_WOLF_NIGHTS, 's' if var.ALPHA_WOLF_NIGHTS > 1 else '')) + pm(cli, nick, ('You may use "bite " tonight in order to turn the wolves\' target into a wolf instead of killing them. ' + + 'They will turn into a wolf in {0} night{1}.').format(var.ALPHA_WOLF_NIGHTS, 's' if var.ALPHA_WOLF_NIGHTS > 1 else '')) elif actor_role == "minion": wolves = var.list_players(var.WOLF_ROLES) random.shuffle(wolves) @@ -3957,7 +4099,9 @@ def retract(cli, nick, chan, rest): if chan == nick: # PM, use different code role = var.get_role(nick) - if role not in ("wolf", "werecrow", "alpha wolf", "werekitten", "hunter") and nick not in var.VENGEFUL_GHOSTS.keys(): + if role not in var.WOLF_ROLES + ("hunter",) and nick not in var.VENGEFUL_GHOSTS.keys(): + return + if role == "wolf cub": return if var.PHASE != "night": pm(cli, nick, "You may only retract at night.") @@ -4507,12 +4651,10 @@ def totem(cli, nick, chan, rest): return pm(cli, nick, ("You have given a totem{0} to \u0002{1}\u0002.").format(type, victim)) totem = var.TOTEMS[nick] - if totem == "death": - if victim not in var.DYING: - var.DYING.append(victim) - elif totem == "protection": - if victim not in var.PROTECTED: - var.PROTECTED.append(victim) + if totem == "death": # this totem stacks + var.DEATH_TOTEM.append((nick, victim)) + elif totem == "protection": # this totem stacks + var.PROTECTED.append(victim) elif totem == "revealing": if victim not in var.REVEALED: var.REVEALED.append(victim) @@ -4575,11 +4717,12 @@ def immunize(cli, nick, chan, rest): if not victim: return victim = choose_target(nick, victim) + vrole = var.get_role(victim) if check_exchange(cli, nick, victim): return pm(cli, nick, "You have given an immunization to \u0002{0}\u0002.".format(victim)) lycan = False - if var.get_role(victim) == "lycan": + if vrole == "lycan": lycan = True lycan_message = ("You feel as if a curse has been lifted from you... It seems that your lycanthropy is cured " + "and you will no longer become a werewolf if targeted by the wolves!") @@ -4595,8 +4738,9 @@ def immunize(cli, nick, chan, rest): # naturally, we would want to mimic that behavior here, and what better way of indicating that things got worse than # by making the turning happen a night earlier? :) var.BITTEN[victim] -= 1 - lycan_message = ("You have a brief flashback to your dream last night. " + - "The event quickly subsides, but a lingering thought remains in your mind...") + lycan_message = ("You have a brief flashback to {0} last night. " + + "The event quickly subsides, but a lingering thought remains in your mind...").format( + "the events of" if vrole == "guardian angel" else "your dream") else: lycan_message = "You don't feel any different..." var.IMMUNIZED.add(victim) @@ -4607,23 +4751,41 @@ def immunize(cli, nick, chan, rest): def get_bitten_message(nick): time_left = var.BITTEN[nick] + role = var.get_role(nick) message = "" - if time_left <= 1: - message = ("You had the same dream again, but this time YOU were the pursuer. You smell fear from your quarry " + - "as you give an exhilerating chase, going only half your speed in order to draw out the fun. " + - "Suddenly your prey trips over a rock and falls down, allowing you to close in the remaining distance. " + - "You savor the fear in their eyes briefly before you raise your claw to deal a killing blow. " + - "Right before it connects, you wake up.") - elif time_left == 2: - message = ("You dreamt of running through the woods outside the village at night, wind blowing across your " + - "face as you weave between the pines. Suddenly you hear a rustling sound as a monstrous creature " + - "jumps out at you - a werewolf! You start running as fast as you can, you soon feel yourself falling " + - "down as you trip over a rock. You look up helplessly as the werewolf catches up to you, " + - "then wake up screaming.") + if role == "guardian angel": + if time_left <= 1: + message = ("After returning from last night's activities, you felt another wave of pain, this time on your back. " + + "Your wings grew larger and you can now fly faster and farther than ever before. Along with " + + "the size change, their color shifted from pure white to a midnight black. You didn't spend much " + + "time thinking on what happened, as you were tired and went to sleep shortly thereafter.") + elif time_left == 2: + message = ("Despite the gloves, it seems that the villagers have been keeping their distance from you as of late. " + + "None of them seem to know about your changes, so the change of behavior greatly angers you. You're " + + "doing just as good a job as ever, and if anything the changes make you MORE effective and powerful. " + + "These thoughts lingered for the rest of last night until you finally drifted off to an uneasy sleep.") + else: + message = ("As you were out last night, you felt a painful sensation as your hands grew very sharp claws. " + + "You figure they are now sharp enough to cut through most anything, but to avoid alarming the village " + + "you decide to fashion some gloves and wear them around from now on in an attempt to show nothing is " + + "happening.") else: - message = ("You had a strange dream last night; a person was running away from something through a forest. " + - "They tripped and fell over a rock as a shadow descended upon them. Before you could actually see " + - "who or what the pursuer was, you woke with a start.") + if time_left <= 1: + message = ("You had the same dream again, but this time YOU were the pursuer. You smell fear from your quarry " + + "as you give an exhilerating chase, going only half your speed in order to draw out the fun. " + + "Suddenly your prey trips over a rock and falls down, allowing you to close in the remaining distance. " + + "You savor the fear in their eyes briefly before you raise your claw to deal a killing blow. " + + "Right before it connects, you wake up.") + elif time_left == 2: + message = ("You dreamt of running through the woods outside the village at night, wind blowing across your " + + "face as you weave between the pines. Suddenly you hear a rustling sound as a monstrous creature " + + "jumps out at you - a werewolf! You start running as fast as you can, you soon feel yourself falling " + + "down as you trip over a rock. You look up helplessly as the werewolf catches up to you, " + + "then wake up screaming.") + else: + message = ("You had a strange dream last night; a person was running away from something through a forest. " + + "They tripped and fell over a rock as a shadow descended upon them. Before you could actually see " + + "who or what the pursuer was, you woke with a start.") return message @cmd("bite", chan=False, pm=True, game=True, playing=True, roles=("alpha wolf",)) @@ -5136,6 +5298,7 @@ def transition_night(cli): var.REVEALED = [] var.TOBESILENCED = [] var.IMPATIENT = [] + var.DEATH_TOTEM = [] var.PACIFISTS = [] var.INFLUENTIAL = [] var.TOBELYCANTHROPES = [] @@ -5189,18 +5352,33 @@ def transition_night(cli): if var.BITTEN[chump] <= 0: # now a wolf - pm(cli, chump, ("As you prepare for bed, you watch in horror as your body starts growing a coat of fur! " + - "Sudden realization hits you as you grin with your now muzzled face; that mysterious bite " + - "earlier slowly changed you into a werewolf! You feel bigger, stronger, faster, and ready to " + - "seize the night as you stealthily exit your home and search for the rest of your pack...")) + newrole = "wolf" + if chumprole == "guardian angel": + pm(cli, chump, ("As the moonlight filters through your window, you think back on the past few days. " + + "Your power has been growing, but the villagers you protect subconsciously detected " + + "your shift and have been keeping more distant from you. Grinning with wicked resolve, " + + "you vow to show them what fools they have been as you take to the skies once more " + + "with an unholy vengeance. Soon they will know true fear.")) + # fallen angels also automatically gain the assassin template if they don't already have it + # by default GA can never be assassin, but this guards against non-default cases + newrole = "fallen angel" + if chump not in var.ROLES["assassin"]: + var.ROLES["assassin"].append(chump) + debuglog("{0} ({1}) TURNED FALLEN ANGEL".format(chump, chumprole)) + else: + pm(cli, chump, ("As you prepare for bed, you watch in horror as your body starts growing a coat of fur! " + + "Sudden realization hits you as you grin with your now muzzled face; that mysterious bite " + + "earlier slowly changed you into a werewolf! You feel bigger, stronger, faster, and ready to " + + "seize the night as you stealthily exit your home and search for the rest of your pack...")) + debuglog("{0} ({1}) TURNED WOLF".format(chump, chumprole)) var.BITTEN_ROLES[chump] = chumprole var.ROLES[chumprole].remove(chump) - var.ROLES["wolf"].append(chump) - var.FINAL_ROLES[chump] = "wolf" + var.ROLES[newrole].append(chump) + var.FINAL_ROLES[chump] = newrole for wolf in var.list_players(var.WOLFCHAT_ROLES): if wolf != chump: - pm(cli, wolf, "\u0002{0}\u0002 is now a \u0002wolf\u0002!".format(chump)) - debuglog("{0} ({1}) TURNED WOLF".format(chump, chumprole)) + # no need for a/an since newrole is either wolf or fallen angel + pm(cli, wolf, "\u0002{0}\u0002 is now a \u0002{1}\u0002!".format(chump, newrole)) # convert amnesiac and kill village elder if necessary if var.NIGHT_COUNT == var.AMNESIAC_NIGHTS: @@ -5291,6 +5469,12 @@ def transition_night(cli): 'to turn them into a cursed villager, so the seer sees them as wolf. Act quickly, as ' + 'your curse applies as soon as you cast it! Only detectives can reveal your true identity, ' + 'seers will see you as a regular villager.').format(cursed)) + elif role == "wolf mystic": + pm(cli, wolf, ('You are a \u0002wolf mystic\u0002. Each night you divine the number of alive good villagers ' + + 'who have a special role. You may also use "kill " to kill a villager.')) + elif role == "fallen angel": + pm(cli, wolf, ('You are a \u0002fallen angel\u0002. Your sharp claws will rend any protection the villagers ' + + 'may have, and will likely kill living guardians as well. Use "kill " to kill a villager.')) else: # catchall in case we forgot something above an = 'n' if role.startswith(("a", "e", "i", "o", "u")) else "" @@ -5318,17 +5502,20 @@ def transition_night(cli): pl[i] = player + " (cursed)" pm(cli, wolf, "Players: " + ", ".join(pl)) + if role == "wolf mystic": + # if adding this info to !myrole, you will need to save off this count so that they can't get updated info until the next night + # # of special villagers = # of players - # of villagers - # of wolves - # of neutrals + numvills = len(ps) - len(var.list_players(var.WOLFTEAM_ROLES)) - len(var.list_players(("villager",))) - len(var.list_players(var.TRUE_NEUTRAL_ROLES)) + pm(cli, wolf, "There are \u0002{0}\u0002 special villager{1} still alive.".format(numvills, "s" if numvills != 1 else "")) if wolf in var.WOLF_GUNNERS.keys() and var.WOLF_GUNNERS[wolf] > 0: pm(cli, wolf, "You have a \u0002gun\u0002 with {0} bullet{1}.".format(var.WOLF_GUNNERS[wolf], "s" if var.WOLF_GUNNERS[wolf] > 1 else "")) - angry_alpha = '' if var.DISEASED_WOLVES: pm(cli, wolf, 'You are feeling ill tonight, and are unable to kill anyone.') - elif var.ANGRY_WOLVES and role in ("wolf", "werecrow", "alpha wolf", "werekitten"): + elif var.ANGRY_WOLVES and role in var.WOLF_ROLES and role != "wolf cub": pm(cli, wolf, 'You are \u0002angry\u0002 tonight, and may kill two targets by using "kill and ".') - angry_alpha = ' ' if var.ALPHA_ENABLED and role == "alpha wolf" and wolf not in var.ALPHA_WOLVES: - pm(cli, wolf, ('You may use "bite{0}" tonight in order to turn the wolves\' target into a wolf instead of killing them. ' + - 'They will turn into a wolf in {1} night{2}.').format(angry_alpha, var.ALPHA_WOLF_NIGHTS, 's' if var.ALPHA_WOLF_NIGHTS > 1 else '')) + pm(cli, wolf, ('You may use "bite " tonight in order to turn the wolves\' target into a wolf instead of killing them. ' + + 'They will turn into a wolf in {0} night{1}.').format(var.ALPHA_WOLF_NIGHTS, 's' if var.ALPHA_WOLF_NIGHTS > 1 else '')) for seer in var.list_players(("seer", "oracle", "augur")): pl = ps[:] @@ -5441,6 +5628,16 @@ def transition_night(cli): else: pm(cli, drunk, "You are the \u0002village drunk\u0002.") + for mystic in var.ROLES["mystic"]: + if mystic in var.PLAYERS and not is_user_simple(mystic): + pm(cli, mystic, ("You are the \u0002mystic\u0002. Each night you divine the number of evil " + + "villagers (including wolves) that are still alive.")) + else: + pm(cli, mystic, "You are the \u0002mystic\u0002.") + # if adding this info to !myrole, you will need to save off this count so that they can't get updated info until the next night + numevil = len(var.list_players(var.WOLFTEAM_ROLES)) + pm(cli, mystic, "There are \u0002{0}\u0002 evil villager{1} still alive.".format(numevil, "s" if numevil != 1 else "")) + max_totems = {} for sham in var.TOTEM_ORDER: max_totems[sham] = 0 @@ -5931,6 +6128,7 @@ def start(cli, nick, chan, forced = False, restart = ""): var.FINAL_ROLES = {} var.ORIGINAL_LOVERS = {} var.IMPATIENT = [] + var.DEATH_TOTEM = [] var.PACIFISTS = [] var.INFLUENTIAL = [] var.LYCANTHROPES = [] @@ -5959,6 +6157,7 @@ def start(cli, nick, chan, forced = False, restart = ""): var.BITTEN_ROLES = {} var.CHARMERS = set() var.CHARMED = set() + var.ACTIVE_PROTECTIONS = defaultdict(list) for role, count in addroles.items(): if role in var.TEMPLATE_RESTRICTIONS.keys(): From c47fa284d26bf39548263521db61b49a58ae18a2 Mon Sep 17 00:00:00 2001 From: skizzerz Date: Thu, 4 Jun 2015 17:53:22 -0500 Subject: [PATCH 2/4] noreveal tweaks - Add in new mystic roles, replacing minion and village elder. - Also add elder to amnesiac blacklist. --- src/settings.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/settings.py b/src/settings.py index 664b6f7..2c44d33 100644 --- a/src/settings.py +++ b/src/settings.py @@ -206,7 +206,7 @@ WOLFTEAM_ROLES = WOLFCHAT_ROLES + ["minion", "cultist"] # These roles never win as a team, only ever individually (either instead of or in addition to the regular winners) TRUE_NEUTRAL_ROLES = ["crazed shaman", "fool", "jester", "monster", "clone", "piper"] # These are the roles that will NOT be used for when amnesiac turns, everything else is fair game! (var.DEFAULT_ROLE is also appended if not in this list) -AMNESIAC_BLACKLIST = ["monster", "minion", "matchmaker", "clone", "doctor", "villager", "cultist", "piper"] +AMNESIAC_BLACKLIST = ["monster", "minion", "matchmaker", "clone", "doctor", "villager", "cultist", "piper", "village elder"] # These roles are seen as wolf by the seer/oracle SEEN_WOLF = WOLF_ROLES + ["monster", "mad scientist"] # These are seen as the default role (or villager) when seen by seer (this overrides SEEN_WOLF) @@ -696,15 +696,15 @@ class NoRevealMode(GameMode): self.ROLE_GUIDE = reset_roles(self.ROLE_INDEX) self.ROLE_GUIDE.update({# village roles "seer" : ( 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ), - "guardian angel" : ( 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 ), + "guardian angel" : ( 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 ), "shaman" : ( 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 ), - "village elder" : ( 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 ), + "mystic" : ( 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 ), "detective" : ( 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 ), "hunter" : ( 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 ), # wolf roles - "wolf" : ( 1 , 1 , 2 , 2 , 2 , 2 , 2 , 3 ), + "wolf" : ( 1 , 1 , 1 , 1 , 2 , 2 , 2 , 3 ), + "wolf mystic" : ( 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 ), "traitor" : ( 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 ), - "minion" : ( 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 ), "werecrow" : ( 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 ), # neutral roles "clone" : ( 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 ), From 6604de63e335bdd8238a6699539d6013a2453d7d Mon Sep 17 00:00:00 2001 From: skizzerz Date: Fri, 5 Jun 2015 19:27:09 -0500 Subject: [PATCH 3/4] Also hide villager-like roles from wolf mystic --- src/wolfgame.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wolfgame.py b/src/wolfgame.py index f8dc2d3..f049690 100644 --- a/src/wolfgame.py +++ b/src/wolfgame.py @@ -4032,7 +4032,7 @@ def check_exchange(cli, actor, nick): pm(cli, actor, "Players: " + ", ".join(pl)) if actor_role == "wolf mystic": # # of special villagers = # of players - # of villagers - # of wolves - # of neutrals - numvills = len(ps) - len(var.list_players(var.WOLFTEAM_ROLES)) - len(var.list_players(("villager",))) - len(var.list_players(var.TRUE_NEUTRAL_ROLES)) + numvills = len(ps) - len(var.list_players(var.WOLFTEAM_ROLES)) - len(var.list_players(("villager", "vengeful ghost", "time lord", "amnesiac", "village elder", "lycan"))) - len(var.list_players(var.TRUE_NEUTRAL_ROLES)) pm(cli, actor, "There are \u0002{0}\u0002 special villager{1} still alive.".format(numvills, "s" if numvills != 1 else "")) if var.DISEASED_WOLVES: pm(cli, actor, 'You are feeling ill tonight, and are unable to kill anyone.') @@ -4073,7 +4073,7 @@ def check_exchange(cli, actor, nick): pm(cli, nick, "Players: " + ", ".join(pl)) if nick_role == "wolf mystic": # # of special villagers = # of players - # of villagers - # of wolves - # of neutrals - numvills = len(ps) - len(var.list_players(var.WOLFTEAM_ROLES)) - len(var.list_players(("villager",))) - len(var.list_players(var.TRUE_NEUTRAL_ROLES)) + numvills = len(ps) - len(var.list_players(var.WOLFTEAM_ROLES)) - len(var.list_players(("villager", "vengeful ghost", "time lord", "amnesiac", "village elder", "lycan"))) - len(var.list_players(var.TRUE_NEUTRAL_ROLES)) pm(cli, nick, "There are \u0002{0}\u0002 special villager{1} still alive.".format(numvills, "s" if numvills != 1 else "")) if var.DISEASED_WOLVES: pm(cli, nick, 'You are feeling ill tonight, and are unable to kill anyone.') @@ -5505,7 +5505,7 @@ def transition_night(cli): if role == "wolf mystic": # if adding this info to !myrole, you will need to save off this count so that they can't get updated info until the next night # # of special villagers = # of players - # of villagers - # of wolves - # of neutrals - numvills = len(ps) - len(var.list_players(var.WOLFTEAM_ROLES)) - len(var.list_players(("villager",))) - len(var.list_players(var.TRUE_NEUTRAL_ROLES)) + numvills = len(ps) - len(var.list_players(var.WOLFTEAM_ROLES)) - len(var.list_players(("villager", "vengeful ghost", "time lord", "amnesiac", "village elder", "lycan"))) - len(var.list_players(var.TRUE_NEUTRAL_ROLES)) pm(cli, wolf, "There are \u0002{0}\u0002 special villager{1} still alive.".format(numvills, "s" if numvills != 1 else "")) if wolf in var.WOLF_GUNNERS.keys() and var.WOLF_GUNNERS[wolf] > 0: pm(cli, wolf, "You have a \u0002gun\u0002 with {0} bullet{1}.".format(var.WOLF_GUNNERS[wolf], "s" if var.WOLF_GUNNERS[wolf] > 1 else "")) From 02a35b8d20cab12307e900f70b3a369229dd2887 Mon Sep 17 00:00:00 2001 From: skizzerz Date: Mon, 8 Jun 2015 19:22:09 -0500 Subject: [PATCH 4/4] Fix TypeError from list+tuple and s/sum/count/ where able --- src/wolfgame.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/wolfgame.py b/src/wolfgame.py index f049690..be835a4 100644 --- a/src/wolfgame.py +++ b/src/wolfgame.py @@ -1374,8 +1374,8 @@ def hurry_up(cli, gameid, change): voters.append(v) for v in voters: weight = 1 - imp_count = sum(1 if p == v else 0 for p in var.IMPATIENT) - pac_count = sum(1 if p == v else 0 for p in var.PACIFISTS) + imp_count = var.IMPATIENT.count(v) + pac_count = var.PACIFISTS.count(v) if pac_count > imp_count: weight = 0 # more pacifists than impatience totems elif imp_count == pac_count and v not in var.VOTES[votee]: @@ -1455,8 +1455,8 @@ def chk_decision(cli, force = ""): if v in pl and v not in voters and v != votee and v not in var.WOUNDED and v not in var.ASLEEP: # don't add them in if they have the same number or more of pacifism totems # this matters for desperation totem on the votee - imp_count = sum(1 if p == v else 0 for p in var.IMPATIENT) - pac_count = sum(1 if p == v else 0 for p in var.PACIFISTS) + imp_count = var.IMPATIENT.count(v) + pac_count = var.PACIFISTS.count(v) if pac_count >= imp_count: continue @@ -1466,8 +1466,8 @@ def chk_decision(cli, force = ""): impatient_voters.append(v) for v in voters[:]: weight = 1 - imp_count = sum(1 if p == v else 0 for p in var.IMPATIENT) - pac_count = sum(1 if p == v else 0 for p in var.PACIFISTS) + imp_count = var.IMPATIENT.count(v) + pac_count = var.PACIFISTS.count(v) if pac_count > imp_count: weight = 0 # more pacifists than impatience totems elif imp_count == pac_count and v not in var.VOTES[votee]: @@ -3193,8 +3193,8 @@ def transition_day(cli, gameid=0): if v in var.DYING: # this person is dying no matter what continue - numkills = sum(1 for n in victims if n == v) - numtotems = sum(1 for n in var.PROTECTED if n == v) + numkills = victims.count(v) + numtotems = var.PROTECTED.count(v) if numtotems >= numkills: protected[v] = "totem" if numtotems > numkills: @@ -4099,7 +4099,7 @@ def retract(cli, nick, chan, rest): if chan == nick: # PM, use different code role = var.get_role(nick) - if role not in var.WOLF_ROLES + ("hunter",) and nick not in var.VENGEFUL_GHOSTS.keys(): + if role not in var.WOLF_ROLES + ["hunter"] and nick not in var.VENGEFUL_GHOSTS.keys(): return if role == "wolf cub": return