def on_transition_day_begin(self, evt, var): ps = get_players() for p in ps: if get_main_role(p) in Wolfteam: continue # wolf shamans can't starve if self.totem_tracking[p] > 0: # if sustenance totem made it through, fully feed player self.hunger_levels[p] = 0 elif self.totem_tracking[p] < 0: # if hunger totem made it through, fast-track player to starvation if self.hunger_levels[p] < 3: self.hunger_levels[p] = 3 # apply natural hunger self.hunger_levels[p] += 1 if self.hunger_levels[p] >= 5: # if they hit 5, they die of starvation # if there are less VGs than alive wolf shamans, they become a wendigo as well self.maybe_make_wendigo(var, p) add_dying(var, p, killer_role="villager", reason="boreal_starvation") elif self.hunger_levels[p] >= 3: # if they are at 3 or 4, alert them that they are hungry p.send(messages["boreal_hungry"]) self.totem_tracking.clear()
def on_del_player(evt, var, player, all_roles, death_triggers): for h, v in list(KILLS.items()): if v is player: h.send(messages["hunter_discard"]) del KILLS[h] elif h is player: del KILLS[h] if death_triggers and "dullahan" in all_roles: pl = get_players() with TARGETS[player].intersection(pl) as targets: if targets: target = random.choice(list(targets)) protected = try_protection(var, target, player, "dullahan", "dullahan_die") if protected is not None: channels.Main.send(*protected) return if var.ROLE_REVEAL in ("on", "team"): role = get_reveal_role(target) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" channels.Main.send(messages["dullahan_die_success"].format(player, target, an, role)) else: channels.Main.send(messages["dullahan_die_success_noreveal"].format(player, target)) debuglog("{0} (dullahan) DULLAHAN ASSASSINATE: {1} ({2})".format(player, target, get_main_role(target))) add_dying(var, target, "dullahan", "dullahan_die")
def on_del_player(evt, var, player, all_roles, death_triggers): if player in TARGETED.values(): for x, y in list(TARGETED.items()): if y is player: del TARGETED[x] PREV_ACTED.discard(x) if death_triggers and "assassin" in all_roles and player in TARGETED: target = TARGETED[player] del TARGETED[player] PREV_ACTED.discard(player) if target in get_players(): protected = try_protection(var, target, player, "assassin", "assassin_fail") if protected is not None: channels.Main.send(*protected) return if var.ROLE_REVEAL in ("on", "team"): role = get_reveal_role(target) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" message = messages["assassin_success"].format(player, target, an, role) else: message = messages["assassin_success_no_reveal"].format(player, target) channels.Main.send(message) debuglog("{0} (assassin) ASSASSINATE: {1} ({2})".format(player, target, get_main_role(target))) add_dying(var, target, killer_role=evt.params.main_role, reason="assassin")
def on_chk_decision_lynch5(evt, var, voters): votee = evt.data["votee"] if votee in DESPERATION: # Also kill the very last person to vote them, unless they voted themselves last in which case nobody else dies target = voters[-1] if target is not votee: protected = try_protection(var, target, attacker=votee, attacker_role="shaman", reason="totem_desperation") if protected is not None: channels.Main.send(*protected) return if var.ROLE_REVEAL in ("on", "team"): r1 = get_reveal_role(target) an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else "" tmsg = messages["totem_desperation"].format( votee, target, an1, r1) else: tmsg = messages["totem_desperation_no_reveal"].format( votee, target) channels.Main.send(tmsg) add_dying(var, target, killer_role="shaman", reason="totem_desperation")
def on_remove_protection(evt, var, target, attacker, attacker_role, protector, protector_role, reason): if attacker_role == "fallen angel" and protector_role == "guardian angel": evt.data["remove"] = True protector.send(messages[reason + "_success"].format(target)) target.send(messages[reason + "_deprotect"]) if random.random() < var.FALLEN_ANGEL_KILLS_GUARDIAN_ANGEL_CHANCE: add_dying(var, protector, killer_role="fallen angel", reason=reason)
def on_del_player(evt, var, player, all_roles, death_triggers): for h, v in list(KILLS.items()): if v is player: h.send(messages["hunter_discard"]) del KILLS[h] elif h is player: del KILLS[h] if death_triggers and "dullahan" in all_roles: pl = get_players() with TARGETS[player].intersection(pl) as targets: if targets: target = random.choice(list(targets)) protected = try_protection(var, target, player, "dullahan", "dullahan_die") if protected is not None: channels.Main.send(*protected) return if var.ROLE_REVEAL in ("on", "team"): role = get_reveal_role(target) channels.Main.send(messages["dullahan_die_success"].format( player, target, role)) else: channels.Main.send( messages["dullahan_die_success_noreveal"].format( player, target)) debuglog( "{0} (dullahan) DULLAHAN ASSASSINATE: {1} ({2})".format( player, target, get_main_role(target))) add_dying(var, target, "dullahan", "dullahan_die")
def on_transition_day(evt, var): for vigilante, target in list(KILLS.items()): evt.data["victims"].append(target) evt.data["killers"][target].append(vigilante) # important, otherwise our del_player listener lets hunter kill again del KILLS[vigilante] if get_main_role(target) not in Wolf | Win_Stealer: add_dying(var, vigilante, "vigilante", "night_kill")
def on_remove_protection(evt, var, target, attacker, attacker_role, protector, protector_role, reason): if attacker_role == "fallen angel" and protector_role == "guardian angel": evt.data["remove"] = True protector.send(messages[reason + "_success"].format(target)) target.send(messages[reason + "_deprotect"]) if random.random() < var.FALLEN_ANGEL_KILLS_GUARDIAN_ANGEL_CHANCE: status.add_dying(var, protector, killer_role="fallen angel", reason=reason)
def on_del_player(evt, var, player, all_roles, death_triggers): if not death_triggers or "mad scientist" not in all_roles: return target1, target2 = _get_targets(var, get_players(), player) prots1 = try_protection(var, target1, player, "mad scientist", "mad_scientist_fail") prots2 = try_protection(var, target2, player, "mad scientist", "mad_scientist_fail") if prots1: channels.Main.send(*prots1) if prots2: channels.Main.send(*prots2) kill1 = prots1 is None and add_dying( var, target1, killer_role="mad scientist", reason="mad_scientist") kill2 = prots2 is None and target1 is not target2 and add_dying( var, target2, killer_role="mad scientist", reason="mad_scientist") role1 = kill1 and get_reveal_role(target1) role2 = kill2 and get_reveal_role(target2) if kill1 and kill2: to_send = "mad_scientist_kill" debuglog( player.nick, "(mad scientist) KILL: {0} ({1}) - {2} ({3})".format( target1, get_main_role(target1), target2, get_main_role(target2))) elif kill1: to_send = "mad_scientist_kill_single" debuglog( player.nick, "(mad scientist) KILL: {0} ({1})".format(target1, get_main_role(target1))) elif kill2: to_send = "mad_scientist_kill_single" debuglog( player.nick, "(mad scientist) KILL: {0} ({1})".format(target2, get_main_role(target2))) # swap the targets around to show the proper target target1, target2 = target2, target1 role1, role2 = role2, role1 else: to_send = "mad_scientist_fail" debuglog(player.nick, "(mad scientist) KILL FAIL") if to_send != "mad_scientist_fail" and var.ROLE_REVEAL not in ("on", "team"): to_send += "_no_reveal" channels.Main.send(messages[to_send].format(player, target1, role1, target2, role2))
def on_del_player(evt, var, player, all_roles, death_triggers): if not death_triggers or "mad scientist" not in all_roles: return target1, target2 = _get_targets(var, get_players(), player) prots1 = try_protection(var, target1, player, "mad scientist", "mad_scientist_fail") prots2 = try_protection(var, target2, player, "mad scientist", "mad_scientist_fail") if prots1: channels.Main.send(*prots1) if prots2: channels.Main.send(*prots2) kill1 = prots1 is None and add_dying(var, target1, killer_role="mad scientist", reason="mad_scientist") kill2 = prots2 is None and target1 is not target2 and add_dying(var, target2, killer_role="mad scientist", reason="mad_scientist") if kill1: if kill2: if var.ROLE_REVEAL in ("on", "team"): r1 = get_reveal_role(target1) an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else "" r2 = get_reveal_role(target2) an2 = "n" if r2.startswith(("a", "e", "i", "o", "u")) else "" tmsg = messages["mad_scientist_kill"].format(player, target1, an1, r1, target2, an2, r2) else: tmsg = messages["mad_scientist_kill_no_reveal"].format(player, target1, target2) channels.Main.send(tmsg) debuglog(player.nick, "(mad scientist) KILL: {0} ({1}) - {2} ({3})".format(target1, get_main_role(target1), target2, get_main_role(target2))) else: if var.ROLE_REVEAL in ("on", "team"): r1 = get_reveal_role(target1) an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else "" tmsg = messages["mad_scientist_kill_single"].format(player, target1, an1, r1) else: tmsg = messages["mad_scientist_kill_single_no_reveal"].format(player, target1) channels.Main.send(tmsg) debuglog(player.nick, "(mad scientist) KILL: {0} ({1})".format(target1, get_main_role(target1))) else: if kill2: if var.ROLE_REVEAL in ("on", "team"): r2 = get_reveal_role(target2) an2 = "n" if r2.startswith(("a", "e", "i", "o", "u")) else "" tmsg = messages["mad_scientist_kill_single"].format(player, target2, an2, r2) else: tmsg = messages["mad_scientist_kill_single_no_reveal"].format(player, target2) channels.Main.send(tmsg) debuglog(player.nick, "(mad scientist) KILL: {0} ({1})".format(target2, get_main_role(target2))) else: tmsg = messages["mad_scientist_fail"].format(player) channels.Main.send(tmsg) debuglog(player.nick, "(mad scientist) KILL FAIL")
def on_lynch(evt, var, votee, voters): if votee in DESPERATION: # Also kill the very last person to vote them, unless they voted themselves last in which case nobody else dies target = voters[-1] if target is not votee: protected = try_protection(var, target, attacker=votee, attacker_role="shaman", reason="totem_desperation") if protected is not None: channels.Main.send(*protected) return to_send = "totem_desperation_no_reveal" if var.ROLE_REVEAL in ("on", "team"): to_send = "totem_desperation" channels.Main.send(messages[to_send].format(votee, target, get_reveal_role(target))) status.add_dying(var, target, killer_role="shaman", reason="totem_desperation")
def on_del_player(evt, var, player, all_roles, death_triggers): MATCHMAKERS.discard(player) if death_triggers and player in LOVERS: lovers = set(LOVERS[player]) for lover in lovers: if lover not in get_players(): continue # already died somehow if var.ROLE_REVEAL in ("on", "team"): role = get_reveal_role(lover) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" message = messages["lover_suicide"].format(lover, an, role) else: message = messages["lover_suicide_no_reveal"].format(lover) channels.Main.send(message) debuglog("{0} ({1}) LOVE SUICIDE: {2} ({3})".format(lover, get_main_role(lover), player, evt.params.main_role)) add_dying(var, lover, killer_role=evt.params.killer_role, reason="lover_suicide")
def on_del_player(evt, var, player, all_roles, death_triggers): MATCHMAKERS.discard(player) ACTED.discard(player) if death_triggers and player in LOVERS: lovers = set(LOVERS[player]) for lover in lovers: if lover not in get_players(): continue # already died somehow to_send = "lover_suicide_no_reveal" if var.ROLE_REVEAL in ("on", "team"): to_send = "lover_suicide" channels.Main.send(messages[to_send].format( lover, get_reveal_role(lover))) debuglog("{0} ({1}) LOVE SUICIDE: {2} ({3})".format( lover, get_main_role(lover), player, evt.params.main_role)) add_dying(var, lover, killer_role=evt.params.killer_role, reason="lover_suicide")
def on_del_player(evt, var, player, all_roles, death_triggers): MATCHMAKERS.discard(player) if death_triggers and player in LOVERS: lovers = set(LOVERS[player]) for lover in lovers: if lover not in get_players(): continue # already died somehow if var.ROLE_REVEAL in ("on", "team"): role = get_reveal_role(lover) an = "n" if role.startswith(("a", "e", "i", "o", "u")) else "" message = messages["lover_suicide"].format(lover, an, role) else: message = messages["lover_suicide_no_reveal"].format(lover) channels.Main.send(message) debuglog("{0} ({1}) LOVE SUICIDE: {2} ({3})".format( lover, get_main_role(lover), player, evt.params.main_role)) add_dying(var, lover, killer_role=evt.params.killer_role, reason="lover_suicide")
def on_transition_day_begin(self, evt, var): from src.roles import vengefulghost num_wendigos = len(vengefulghost.GHOSTS) num_wolf_shamans = len(get_players(("wolf shaman", ))) ps = get_players() for p in ps: if get_main_role(p) in Wolfteam: continue # wolf shamans can't starve if self.totem_tracking[p] > 0: # if sustenance totem made it through, fully feed player self.hunger_levels[p] = 0 elif self.totem_tracking[p] < 0: # if hunger totem made it through, fast-track player to starvation if self.hunger_levels[p] < 3: self.hunger_levels[p] = 3 # apply natural hunger self.hunger_levels[p] += 1 if self.hunger_levels[p] >= 5: # if they hit 5, they die of starvation # if there are less VGs than alive wolf shamans, they become a wendigo as well if num_wendigos < num_wolf_shamans: num_wendigos += 1 change_role(var, p, get_main_role(p), "vengeful ghost", message=None) add_dying(var, p, killer_role="villager", reason="boreal_starvation") elif self.hunger_levels[p] >= 3: # if they are at 3 or 4, alert them that they are hungry p.send(messages["boreal_hungry"]) self.totem_tracking.clear()
def on_player_protected(evt, var, target, attacker, attacker_role, protector, protector_role, reason): if protector_role == "bodyguard": evt.data["messages"].append(messages[reason + "_bodyguard"].format(attacker, target, protector)) add_dying(var, protector, killer_role=attacker_role, reason="bodyguard") if var.PHASE == "night" and var.GAMEPHASE == "day": # currently transitioning DYING.add(protector)
def shoot(var, wrapper, message): """Use this to fire off a bullet at someone in the day if you have bullets.""" if not GUNNERS[wrapper.source]: wrapper.pm(messages["no_bullets"]) return target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="gunner_target_self") if not target: return target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return GUNNERS[wrapper.source] -= 1 gun_evt = Event("gun_chances", {"hit": 0, "miss": 0, "headshot": 0}) gun_evt.dispatch(var, wrapper.source, rolename) rand = random.random() # need to save it shoot_evt = Event("gun_shoot", {"hit": rand <= gun_evt.data["hit"], "kill": random.random() <= gun_evt.data["headshot"]}) shoot_evt.dispatch(var, wrapper.source, target) realrole = get_main_role(target) targrole = get_reveal_role(target) if shoot_evt.data["hit"]: wrapper.send(messages["shoot_success"].format(wrapper.source, target)) an = "n" if targrole.startswith(("a", "e", "i", "o", "u")) else "" if realrole in Wolf: if var.ROLE_REVEAL == "on": wrapper.send(messages["gunner_victim_wolf_death"].format(target, an, targrole)) else: # off and team wrapper.send(messages["gunner_victim_wolf_death_no_reveal"].format(target)) add_dying(var, target, killer_role=get_main_role(wrapper.source), reason="gunner_victim") if kill_players(var): return elif shoot_evt.data["kill"]: accident = "accidentally " if gun_evt.data["headshot"] == 1: # would always headshot accident = "" wrapper.send(messages["gunner_victim_villager_death"].format(target, accident)) if var.ROLE_REVEAL in ("on", "team"): wrapper.send(messages["gunner_victim_role"].format(an, targrole)) add_dying(var, target, killer_role=get_main_role(wrapper.source), reason="gunner_victim") if kill_players(var): return else: wrapper.send(messages["gunner_victim_injured"].format(target)) add_absent(var, target, "wounded") from src.wolfgame import chk_decision, chk_win chk_decision() chk_win() elif rand <= gun_evt.data["hit"] + gun_evt.data["miss"]: wrapper.send(messages["gunner_miss"].format(wrapper.source)) else: # BOOM! your gun explodes, you're dead if var.ROLE_REVEAL in ("on", "team"): wrapper.send(messages["gunner_suicide"].format(wrapper.source, get_reveal_role(wrapper.source))) else: wrapper.send(messages["gunner_suicide_no_reveal"].format(wrapper.source)) add_dying(var, wrapper.source, killer_role="villager", reason="gunner_suicide") # blame explosion on villager's shoddy gun construction or something kill_players(var)
def chk_decision(var, *, timeout=False): with var.GRAVEYARD_LOCK: players = set(get_players()) - get_absent(var) avail = len(players) needed = avail // 2 + 1 to_vote = [] for votee, voters in VOTES.items(): votes = (set(voters) | get_forced_votes(var, votee)) - get_forced_abstains(var) if sum(get_vote_weight(var, x) for x in votes) >= needed: to_vote.append(votee) break behaviour_evt = Event("lynch_behaviour", { "num_lynches": 1, "kill_ties": False, "force": timeout }, votes=VOTES, players=avail) behaviour_evt.dispatch(var) num_lynches = behaviour_evt.data["num_lynches"] kill_ties = behaviour_evt.data["kill_ties"] force = behaviour_evt.data["force"] abstaining = False if not to_vote: if len(ABSTAINS | get_forced_abstains(var)) >= avail / 2: abstaining = True elif force: voting = [] if VOTES: plurality = [(x, len(y)) for x, y in VOTES.items()] plurality.sort(key=lambda x: x[1]) votee, value = plurality.pop() max_value = value # Fetch all of the highest ties, exit out if we find someone lower # If everyone is tied, then at some point plurality will be empty, # but the values will still be at the max. Everything's fine, just break while value == max_value: voting.append(votee) if not plurality: break votee, value = plurality.pop() if len(voting) == 1: to_vote.append(voting[0]) elif voting and kill_ties: if set(voting) == set( get_players() ): # killing everyone off? have you considered not doing that abstaining = True else: to_vote.extend(voting) else: abstaining = True if abstaining: for forced_abstainer in get_forced_abstains(var): if forced_abstainer not in ABSTAINS: # did not explicitly abstain channels.Main.send(messages["player_meek_abstain"].format( forced_abstainer)) abstain_evt = Event("abstain", {}) abstain_evt.dispatch(var, ABSTAINS | get_forced_abstains(var)) global ABSTAINED ABSTAINED = True channels.Main.send(messages["village_abstain"]) from src.wolfgame import transition_night transition_night() if to_vote: global LYNCHED LYNCHED += len( to_vote) # track how many people we've lynched today if timeout: channels.Main.send(messages["sunset_lynch"]) for votee in to_vote: voters = list(VOTES[votee]) for forced_voter in get_forced_votes(var, votee): if forced_voter not in voters: # did not explicitly vote channels.Main.send(messages["impatient_vote"].format( forced_voter, votee)) voters.append( forced_voter ) # they need to be counted as voting for them still if not try_lynch_immunity(var, votee): lynch_evt = Event("lynch", {}, players=avail) if lynch_evt.dispatch(var, votee, voters): if var.ROLE_REVEAL in ("on", "team"): rrole = get_reveal_role(votee) an = "n" if rrole.startswith( ("a", "e", "i", "o", "u")) else "" lmsg = random.choice( messages["lynch_reveal"]).format( votee, an, rrole) else: lmsg = random.choice( messages["lynch_no_reveal"]).format(votee) channels.Main.send(lmsg) add_dying(var, votee, "villager", "lynch") kill_players(var, end_game=False) # FIXME elif timeout: channels.Main.send(messages["sunset"]) from src.wolfgame import chk_win if chk_win(): return # game ended, just exit out if timeout or LYNCHED >= num_lynches: from src.wolfgame import transition_night transition_night()
def on_player_protected(evt, var, target, attacker, attacker_role, protector, protector_role, reason): if protector_role == "bodyguard": evt.data["messages"].append(messages[reason + "_bodyguard"].format(attacker, target, protector)) status.add_dying(var, protector, killer_role=attacker_role, reason="bodyguard") DYING.add(protector)
def on_del_player(evt, var, player, all_roles, death_triggers): if not death_triggers or "mad scientist" not in all_roles: return target1, target2 = _get_targets(var, get_players(), player) prots1 = try_protection(var, target1, player, "mad scientist", "mad_scientist_fail") prots2 = try_protection(var, target2, player, "mad scientist", "mad_scientist_fail") if prots1: channels.Main.send(*prots1) if prots2: channels.Main.send(*prots2) kill1 = prots1 is None and add_dying( var, target1, killer_role="mad scientist", reason="mad_scientist") kill2 = prots2 is None and target1 is not target2 and add_dying( var, target2, killer_role="mad scientist", reason="mad_scientist") if kill1: if kill2: if var.ROLE_REVEAL in ("on", "team"): r1 = get_reveal_role(target1) an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else "" r2 = get_reveal_role(target2) an2 = "n" if r2.startswith(("a", "e", "i", "o", "u")) else "" tmsg = messages["mad_scientist_kill"].format( player, target1, an1, r1, target2, an2, r2) else: tmsg = messages["mad_scientist_kill_no_reveal"].format( player, target1, target2) channels.Main.send(tmsg) debuglog( player.nick, "(mad scientist) KILL: {0} ({1}) - {2} ({3})".format( target1, get_main_role(target1), target2, get_main_role(target2))) else: if var.ROLE_REVEAL in ("on", "team"): r1 = get_reveal_role(target1) an1 = "n" if r1.startswith(("a", "e", "i", "o", "u")) else "" tmsg = messages["mad_scientist_kill_single"].format( player, target1, an1, r1) else: tmsg = messages["mad_scientist_kill_single_no_reveal"].format( player, target1) channels.Main.send(tmsg) debuglog( player.nick, "(mad scientist) KILL: {0} ({1})".format( target1, get_main_role(target1))) else: if kill2: if var.ROLE_REVEAL in ("on", "team"): r2 = get_reveal_role(target2) an2 = "n" if r2.startswith(("a", "e", "i", "o", "u")) else "" tmsg = messages["mad_scientist_kill_single"].format( player, target2, an2, r2) else: tmsg = messages["mad_scientist_kill_single_no_reveal"].format( player, target2) channels.Main.send(tmsg) debuglog( player.nick, "(mad scientist) KILL: {0} ({1})".format( target2, get_main_role(target2))) else: tmsg = messages["mad_scientist_fail"].format(player) channels.Main.send(tmsg) debuglog(player.nick, "(mad scientist) KILL FAIL")
def nightmare_kill(self, evt, var): if self.having_nightmare and self.having_nightmare[0] in get_players(): add_dying(var, self.having_nightmare[0], "bot", "night_kill") self.having_nightmare[0].send(messages["sleepy_nightmare_death"]) del self.having_nightmare[0]
def on_remove_protection(evt, var, target, attacker, attacker_role, protector, protector_role, reason): if attacker_role == "fallen angel" and protector_role == "bodyguard": evt.data["remove"] = True add_dying(var, protector, killer_role="fallen angel", reason=reason) protector.send(messages[reason + "_success"].format(target)) target.send(messages[reason + "_deprotect"])
def shoot(var, wrapper, message): """Use this to fire off a bullet at someone in the day if you have bullets.""" if not GUNNERS[wrapper.source]: wrapper.pm(messages["no_bullets"]) return target = get_target(var, wrapper, re.split(" +", message)[0], not_self_message="gunner_target_self") if not target: return target = try_misdirection(var, wrapper.source, target) if try_exchange(var, wrapper.source, target): return GUNNERS[wrapper.source] -= 1 gun_evt = Event("gun_chances", {"hit": 0, "miss": 0, "headshot": 0}) gun_evt.dispatch(var, wrapper.source, rolename) rand = random.random() # need to save it shoot_evt = Event("gun_shoot", {"hit": rand <= gun_evt.data["hit"], "kill": random.random() <= gun_evt.data["headshot"]}) shoot_evt.dispatch(var, wrapper.source, target) realrole = get_main_role(target) targrole = get_reveal_role(target) if shoot_evt.data["hit"]: wrapper.send(messages["shoot_success"].format(wrapper.source, target)) an = "n" if targrole.startswith(("a", "e", "i", "o", "u")) else "" if realrole in Wolf: if var.ROLE_REVEAL == "on": wrapper.send(messages["gunner_victim_wolf_death"].format(target, an, targrole)) else: # off and team wrapper.send(messages["gunner_victim_wolf_death_no_reveal"].format(target)) add_dying(var, target, killer_role=get_main_role(wrapper.source), reason="gunner_victim") if kill_players(var): return elif shoot_evt.data["kill"]: accident = "accidentally " if gun_evt.data["headshot"] == 1: # would always headshot accident = "" wrapper.send(messages["gunner_victim_villager_death"].format(target, accident)) if var.ROLE_REVEAL in ("on", "team"): wrapper.send(messages["gunner_victim_role"].format(an, targrole)) add_dying(var, target, killer_role=get_main_role(wrapper.source), reason="gunner_victim") if kill_players(var): return else: wrapper.send(messages["gunner_victim_injured"].format(target)) add_absent(var, target, "wounded") from src.votes import chk_decision from src.wolfgame import chk_win if not chk_win(): # game didn't immediately end due to injury, see if we should force through a vote chk_decision(var) elif rand <= gun_evt.data["hit"] + gun_evt.data["miss"]: wrapper.send(messages["gunner_miss"].format(wrapper.source)) else: # BOOM! your gun explodes, you're dead if var.ROLE_REVEAL in ("on", "team"): wrapper.send(messages["gunner_suicide"].format(wrapper.source, get_reveal_role(wrapper.source))) else: wrapper.send(messages["gunner_suicide_no_reveal"].format(wrapper.source)) add_dying(var, wrapper.source, killer_role="villager", reason="gunner_suicide") # blame explosion on villager's shoddy gun construction or something kill_players(var)
def chk_decision(var, *, timeout=False): with var.GRAVEYARD_LOCK: players = set(get_players()) - get_absent(var) avail = len(players) needed = avail // 2 + 1 to_vote = [] for votee, voters in VOTES.items(): votes = (set(voters) | get_forced_votes(var, votee)) - get_forced_abstains(var) if sum(get_vote_weight(var, x) for x in votes) >= needed: to_vote.append(votee) break behaviour_evt = Event("lynch_behaviour", {"num_lynches": 1, "kill_ties": False, "force": timeout}, votes=VOTES, players=avail) behaviour_evt.dispatch(var) num_lynches = behaviour_evt.data["num_lynches"] kill_ties = behaviour_evt.data["kill_ties"] force = behaviour_evt.data["force"] abstaining = False if not to_vote: if len(ABSTAINS | get_forced_abstains(var)) >= avail / 2: abstaining = True elif force: voting = [] if VOTES: plurality = [(x, len(y)) for x, y in VOTES.items()] plurality.sort(key=lambda x: x[1]) votee, value = plurality.pop() max_value = value # Fetch all of the highest ties, exit out if we find someone lower # If everyone is tied, then at some point plurality will be empty, # but the values will still be at the max. Everything's fine, just break while value == max_value: voting.append(votee) if not plurality: break votee, value = plurality.pop() if len(voting) == 1: to_vote.append(voting[0]) elif voting and kill_ties: if set(voting) == set(get_players()): # killing everyone off? have you considered not doing that abstaining = True else: to_vote.extend(voting) else: abstaining = True if abstaining: for forced_abstainer in get_forced_abstains(var): if forced_abstainer not in ABSTAINS: # did not explicitly abstain channels.Main.send(messages["player_meek_abstain"].format(forced_abstainer)) abstain_evt = Event("abstain", {}) abstain_evt.dispatch(var, ABSTAINS | get_forced_abstains(var)) global ABSTAINED ABSTAINED = True channels.Main.send(messages["village_abstain"]) from src.wolfgame import transition_night transition_night() if to_vote: global LYNCHED LYNCHED += len(to_vote) # track how many people we've lynched today if timeout: channels.Main.send(messages["sunset_lynch"]) for votee in to_vote: voters = list(VOTES[votee]) for forced_voter in get_forced_votes(var, votee): if forced_voter not in voters: # did not explicitly vote channels.Main.send(messages["impatient_vote"].format(forced_voter, votee)) voters.append(forced_voter) # they need to be counted as voting for them still if not try_lynch_immunity(var, votee): lynch_evt = Event("lynch", {}, players=avail) if lynch_evt.dispatch(var, votee, voters): if var.ROLE_REVEAL in ("on", "team"): rrole = get_reveal_role(votee) an = "n" if rrole.startswith(("a", "e", "i", "o", "u")) else "" lmsg = random.choice(messages["lynch_reveal"]).format(votee, an, rrole) else: lmsg = random.choice(messages["lynch_no_reveal"]).format(votee) channels.Main.send(lmsg) add_dying(var, votee, "villager", "lynch") kill_players(var, end_game=False) # FIXME elif timeout: channels.Main.send(messages["sunset"]) from src.wolfgame import chk_win if chk_win(): return # game ended, just exit out if timeout or LYNCHED >= num_lynches: from src.wolfgame import transition_night transition_night()