Split and convert clone (#340)
This commit is contained in:
parent
aaeb51b203
commit
213f7b2c3b
@ -83,12 +83,7 @@ def get_all_roles(user):
|
|||||||
return {role for role, users in var.ROLES.items() if user in users}
|
return {role for role, users in var.ROLES.items() if user in users}
|
||||||
|
|
||||||
def get_reveal_role(user):
|
def get_reveal_role(user):
|
||||||
# FIXME: when clone is split, move this into an event
|
evt = Event("get_reveal_role", {"role": get_main_role(user)})
|
||||||
role = get_main_role(user)
|
|
||||||
if var.HIDDEN_CLONE and user in var.ORIGINAL_ROLES["clone"]:
|
|
||||||
role = "clone"
|
|
||||||
|
|
||||||
evt = Event("get_reveal_role", {"role": role})
|
|
||||||
evt.dispatch(var, user)
|
evt.dispatch(var, user)
|
||||||
role = evt.data["role"]
|
role = evt.data["role"]
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ def setup_variables(rolename, *, send_role, types):
|
|||||||
def on_transition_night_end(evt, var):
|
def on_transition_night_end(evt, var):
|
||||||
villagers = set(get_players(("priest", "doctor")))
|
villagers = set(get_players(("priest", "doctor")))
|
||||||
win_stealers = set(get_players(("fool", "monster", "demoniac")))
|
win_stealers = set(get_players(("fool", "monster", "demoniac")))
|
||||||
neutrals = set(get_players(("turncoat", "clone", "jester")))
|
neutrals = set(get_players(("turncoat", "jester")))
|
||||||
|
|
||||||
special_evt = Event("get_special", {"villagers": villagers, "wolves": set(), "win_stealers": win_stealers, "neutrals": neutrals})
|
special_evt = Event("get_special", {"villagers": villagers, "wolves": set(), "win_stealers": win_stealers, "neutrals": neutrals})
|
||||||
special_evt.dispatch(var)
|
special_evt.dispatch(var)
|
||||||
|
214
src/roles/clone.py
Normal file
214
src/roles/clone.py
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
import re
|
||||||
|
import random
|
||||||
|
import itertools
|
||||||
|
import math
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
from src.utilities import *
|
||||||
|
from src import channels, users, debuglog, errlog, plog
|
||||||
|
from src.functions import get_players, get_all_players, get_main_role, get_reveal_role, get_target
|
||||||
|
from src.decorators import command, event_listener
|
||||||
|
from src.containers import UserList, UserSet, UserDict, DefaultUserDict
|
||||||
|
from src.messages import messages
|
||||||
|
from src.events import Event
|
||||||
|
|
||||||
|
CLONED = UserDict() # type: Dict[users.User, users.User]
|
||||||
|
CLONE_ENABLED = False # becomes True if at least one person died and there are clones
|
||||||
|
|
||||||
|
@command("clone", chan=False, pm=True, playing=True, phases=("night",), roles=("clone",))
|
||||||
|
def clone(var, wrapper, message):
|
||||||
|
"""Clone another player. You will turn into their role if they die."""
|
||||||
|
if not var.FIRST_NIGHT:
|
||||||
|
return
|
||||||
|
if wrapper.source in CLONED:
|
||||||
|
wrapper.pm(messages["already_cloned"])
|
||||||
|
return
|
||||||
|
|
||||||
|
params = re.split(" +", message)
|
||||||
|
# allow for role-prefixed command such as !clone clone target
|
||||||
|
# if we get !clone clone (with no 3rd arg), we give preference to prefixed version;
|
||||||
|
# meaning if the person wants to clone someone named clone, they must type !clone clone clone
|
||||||
|
# (or just !clone clon, !clone clo, etc. assuming those would be unambiguous matches)
|
||||||
|
if params[0] == "clone":
|
||||||
|
if len(params) > 1:
|
||||||
|
del params[0]
|
||||||
|
else:
|
||||||
|
wrapper.pm(messages["clone_clone_clone"])
|
||||||
|
return
|
||||||
|
|
||||||
|
target = get_target(var, wrapper, params[0])
|
||||||
|
if target is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
CLONED[wrapper.source] = target
|
||||||
|
wrapper.pm(messages["clone_target_success"].format(target))
|
||||||
|
|
||||||
|
debuglog("{0} (clone) CLONE: {1} ({2})".format(wrapper.source, target, get_main_role(target)))
|
||||||
|
|
||||||
|
@event_listener("init")
|
||||||
|
def on_init(evt):
|
||||||
|
# We need to add "clone" to the role command exceptions so there's no error
|
||||||
|
# This is done here so that var isn't imported at the global scope
|
||||||
|
# (when we implement proper game state this will be in a different event)
|
||||||
|
from src import settings as var
|
||||||
|
var.ROLE_COMMAND_EXCEPTIONS.add("clone")
|
||||||
|
|
||||||
|
@event_listener("get_reveal_role")
|
||||||
|
def on_get_reveal_role(evt, var, user):
|
||||||
|
if var.HIDDEN_CLONE and user in var.ORIGINAL_ROLES["clone"]:
|
||||||
|
evt.data["role"] = "clone"
|
||||||
|
|
||||||
|
@event_listener("del_player")
|
||||||
|
def on_del_player(evt, var, player, mainrole, allroles, death_triggers):
|
||||||
|
# clone happens regardless of death_triggers being true or not
|
||||||
|
if var.PHASE not in var.GAME_PHASES:
|
||||||
|
return
|
||||||
|
|
||||||
|
clones = get_all_players(("clone",))
|
||||||
|
for clone in clones:
|
||||||
|
if clone in CLONED and clone not in evt.params.deadlist:
|
||||||
|
target = CLONED[clone]
|
||||||
|
if player is target:
|
||||||
|
# clone is cloning target, so clone becomes target's role
|
||||||
|
# clone does NOT get any of target's templates (gunner/assassin/etc.)
|
||||||
|
del CLONED[clone]
|
||||||
|
if mainrole == "amnesiac":
|
||||||
|
from src.roles.amnesiac import ROLES as amn_roles
|
||||||
|
# clone gets the amnesiac's real role
|
||||||
|
mainrole = amn_roles[player]
|
||||||
|
change_role(clone, "clone", mainrole)
|
||||||
|
debuglog("{0} (clone) CLONE DEAD PLAYER: {1} ({2})".format(clone, target, mainrole))
|
||||||
|
sayrole = mainrole
|
||||||
|
if sayrole in var.HIDDEN_VILLAGERS:
|
||||||
|
sayrole = "villager"
|
||||||
|
elif sayrole in var.HIDDEN_ROLES:
|
||||||
|
sayrole = var.DEFAULT_ROLE
|
||||||
|
an = "n" if sayrole.startswith(("a", "e", "i", "o", "u")) else ""
|
||||||
|
clone.send(messages["clone_turn"].format(an, sayrole))
|
||||||
|
# if a clone is cloning a clone, clone who the old clone cloned
|
||||||
|
if mainrole == "clone" and player in CLONED:
|
||||||
|
if CLONED[player] is clone:
|
||||||
|
clone.send(messages["forever_aclone"].format(player))
|
||||||
|
else:
|
||||||
|
CLONED[clone] = CLONED[player]
|
||||||
|
clone.send(messages["clone_success"].format(CLONED[clone]))
|
||||||
|
debuglog("{0} (clone) CLONE: {1} ({2})".format(clone, CLONED[clone], get_main_role(CLONED[clone])))
|
||||||
|
elif mainrole in var.WOLFCHAT_ROLES:
|
||||||
|
wolves = get_players(var.WOLFCHAT_ROLES)
|
||||||
|
wolves.remove(clone) # remove self from list
|
||||||
|
for wolf in wolves:
|
||||||
|
wolf.queue_message(messages["clone_wolf"].format(clone, player))
|
||||||
|
if wolves:
|
||||||
|
wolf.send_messages()
|
||||||
|
if var.PHASE == "day":
|
||||||
|
random.shuffle(wolves)
|
||||||
|
for i, wolf in enumerate(wolves):
|
||||||
|
wolfrole = get_main_role(wolf)
|
||||||
|
wevt = Event("wolflist", {"tags": set()})
|
||||||
|
wevt.dispatch(var, wolf, clone)
|
||||||
|
tags = " ".join(wevt.data["tags"])
|
||||||
|
if tags:
|
||||||
|
tags += " "
|
||||||
|
wolves[i] = "\u0002{0}\u0002 ({1}{2})".format(wolf, tags, wolfrole)
|
||||||
|
|
||||||
|
if wolves:
|
||||||
|
clone.send(messages["wolves_list"].format(wolves))
|
||||||
|
else:
|
||||||
|
clone.send(messages["no_other_wolves"])
|
||||||
|
elif mainrole == "turncoat":
|
||||||
|
var.TURNCOATS[clone.nick] = ("none", -1) # FIXME
|
||||||
|
|
||||||
|
if mainrole == "clone" and player in CLONED:
|
||||||
|
del CLONED[player]
|
||||||
|
|
||||||
|
@event_listener("transition_night_end")
|
||||||
|
def on_transition_night_end(evt, var):
|
||||||
|
if var.FIRST_NIGHT or var.ALWAYS_PM_ROLE:
|
||||||
|
ps = get_players()
|
||||||
|
for clone in get_all_players(("clone",)):
|
||||||
|
pl = ps[:]
|
||||||
|
random.shuffle(pl)
|
||||||
|
pl.remove(clone)
|
||||||
|
if clone.prefers_simple():
|
||||||
|
clone.send(messages["clone_simple"])
|
||||||
|
else:
|
||||||
|
clone.send(messages["clone_notify"])
|
||||||
|
clone.send(messages["players_list"].format(", ".join(p.nick for p in pl)))
|
||||||
|
|
||||||
|
@event_listener("chk_nightdone")
|
||||||
|
def on_chk_nightdone(evt, var):
|
||||||
|
if var.FIRST_NIGHT:
|
||||||
|
evt.data["actedcount"] += len(CLONED)
|
||||||
|
evt.data["nightroles"].extend(get_all_players(("clone",)))
|
||||||
|
|
||||||
|
@event_listener("transition_day_begin")
|
||||||
|
def on_transition_day_begin(evt, var):
|
||||||
|
if var.FIRST_NIGHT:
|
||||||
|
# Select a random target for clone if they didn't choose someone
|
||||||
|
pl = get_players()
|
||||||
|
for clone in get_all_players(("clone",)):
|
||||||
|
if clone not in CLONED:
|
||||||
|
ps = pl[:]
|
||||||
|
ps.remove(clone)
|
||||||
|
if len(ps) > 0:
|
||||||
|
target = random.choice(ps)
|
||||||
|
CLONED[clone] = target
|
||||||
|
clone.send(messages["random_clone"].format(target))
|
||||||
|
|
||||||
|
@event_listener("exchange_roles")
|
||||||
|
def on_exchange_roles(evt, var, actor, target, actor_role, target_role):
|
||||||
|
actor_target = None
|
||||||
|
target_target = None
|
||||||
|
if actor_role == "clone":
|
||||||
|
if actor in CLONED:
|
||||||
|
actor_target = CLONED.pop(actor)
|
||||||
|
evt.data["target_messages"].append(messages["clone_target"].format(actor_target))
|
||||||
|
if target_role == "clone":
|
||||||
|
if target in CLONED:
|
||||||
|
target_target = CLONED.pop(target)
|
||||||
|
evt.data["actor_messages"].append(messages["clone_target"].format(target_target))
|
||||||
|
|
||||||
|
if actor_target is not None:
|
||||||
|
CLONED[target] = actor_target
|
||||||
|
if target_target is not None:
|
||||||
|
CLONED[actor] = target_target
|
||||||
|
|
||||||
|
@event_listener("player_win")
|
||||||
|
def on_player_win(evt, var, player, role, winner, survived):
|
||||||
|
# this means they ended game while being clone and not some other role
|
||||||
|
if survived and not winner.startswith("@") and singular(winner) not in var.WIN_STEALER_ROLES:
|
||||||
|
evt.data["iwon"] = True
|
||||||
|
|
||||||
|
@event_listener("del_player")
|
||||||
|
def first_death_occured(evt, var, player, mainrole, allroles, death_triggers):
|
||||||
|
global CLONE_ENABLED
|
||||||
|
if CLONE_ENABLED:
|
||||||
|
return
|
||||||
|
if (CLONED or get_all_players(("clone",))) and var.PHASE in var.GAME_PHASES and not var.FIRST_NIGHT:
|
||||||
|
CLONE_ENABLED = True
|
||||||
|
|
||||||
|
@event_listener("update_stats")
|
||||||
|
def on_update_stats(evt, var, player, mainrole, revealrole, allroles):
|
||||||
|
if CLONE_ENABLED:
|
||||||
|
evt.data["possible"].add("clone")
|
||||||
|
|
||||||
|
@event_listener("myrole")
|
||||||
|
def on_myrole(evt, var, user):
|
||||||
|
# Remind clone who they have cloned
|
||||||
|
if evt.data["role"] == "clone" and user in CLONED:
|
||||||
|
evt.data["messages"].append(messages["clone_target"].format(CLONED[user]))
|
||||||
|
|
||||||
|
@event_listener("revealroles_role")
|
||||||
|
def on_revealroles_role(evt, var, user, role):
|
||||||
|
if role == "clone" and user in CLONED:
|
||||||
|
evt.data["special_case"].append("cloning {0}".format(CLONED[user]))
|
||||||
|
|
||||||
|
@event_listener("get_special")
|
||||||
|
def on_get_special(evt, var):
|
||||||
|
evt.data["neutrals"].update(get_players(("clone",)))
|
||||||
|
|
||||||
|
@event_listener("reset")
|
||||||
|
def on_reset(evt, var):
|
||||||
|
global CLONE_ENABLED
|
||||||
|
CLONE_ENABLED = False
|
||||||
|
CLONED.clear()
|
171
src/wolfgame.py
171
src/wolfgame.py
@ -2123,10 +2123,6 @@ def stop_game(var, winner="", abort=False, additional_winners=None, log=True):
|
|||||||
iwon = True
|
iwon = True
|
||||||
elif rol == "demoniac" and plr in survived and winner == "demoniacs":
|
elif rol == "demoniac" and plr in survived and winner == "demoniacs":
|
||||||
iwon = True
|
iwon = True
|
||||||
elif rol == "clone":
|
|
||||||
# this means they ended game while being clone and not some other role
|
|
||||||
if plr in survived and not winner.startswith("@") and singular(winner) not in var.WIN_STEALER_ROLES:
|
|
||||||
iwon = True
|
|
||||||
elif rol == "jester" and splr in var.JESTERS:
|
elif rol == "jester" and splr in var.JESTERS:
|
||||||
iwon = True
|
iwon = True
|
||||||
elif not iwon:
|
elif not iwon:
|
||||||
@ -2344,72 +2340,6 @@ def del_player(player, *, devoice=True, end_game=True, death_triggers=True, kill
|
|||||||
if player.nick in var.BITTEN_ROLES:
|
if player.nick in var.BITTEN_ROLES:
|
||||||
del var.BITTEN_ROLES[player.nick] # FIXME
|
del var.BITTEN_ROLES[player.nick] # FIXME
|
||||||
pl.discard(player)
|
pl.discard(player)
|
||||||
# handle roles that trigger on death
|
|
||||||
# clone happens regardless of death_triggers being true or not
|
|
||||||
if var.PHASE in var.GAME_PHASES:
|
|
||||||
clones = get_all_players(("clone",))
|
|
||||||
for clone in clones:
|
|
||||||
# clone is a User, var.CLONED is a Dict[str,str]
|
|
||||||
# dealist is a List[User]; ensure we add .nick appropriately
|
|
||||||
# FIXME: someone should convert var.CLONED
|
|
||||||
if clone.nick in var.CLONED and clone not in deadlist:
|
|
||||||
target = var.CLONED[clone.nick]
|
|
||||||
if player.nick == target and clone.nick in var.CLONED:
|
|
||||||
# clone is cloning nick, so clone becomes nick's role
|
|
||||||
# clone does NOT get any of nick's templates (gunner/assassin/etc.)
|
|
||||||
del var.CLONED[clone.nick]
|
|
||||||
if mainrole == "amnesiac":
|
|
||||||
from src.roles.amnesiac import ROLES
|
|
||||||
# clone gets the amnesiac's real role
|
|
||||||
sayrole = ROLES[player]
|
|
||||||
else:
|
|
||||||
sayrole = mainrole
|
|
||||||
change_role(clone, "clone", sayrole)
|
|
||||||
debuglog("{0} (clone) CLONE DEAD PLAYER: {1} ({2})".format(clone, target, sayrole))
|
|
||||||
if sayrole in var.HIDDEN_VILLAGERS:
|
|
||||||
sayrole = "villager"
|
|
||||||
elif sayrole in var.HIDDEN_ROLES:
|
|
||||||
sayrole = var.DEFAULT_ROLE
|
|
||||||
an = "n" if sayrole.startswith(("a", "e", "i", "o", "u")) else ""
|
|
||||||
clone.send(messages["clone_turn"].format(an, sayrole))
|
|
||||||
# if a clone is cloning a clone, clone who the old clone cloned
|
|
||||||
if mainrole == "clone" and player.nick in var.CLONED:
|
|
||||||
if var.CLONED[player.nick] == clone.nick:
|
|
||||||
clone.send(messages["forever_aclone"].format(player))
|
|
||||||
else:
|
|
||||||
var.CLONED[clone.nick] = var.CLONED[player.nick]
|
|
||||||
clone.send(messages["clone_success"].format(var.CLONED[clone.nick]))
|
|
||||||
# FIXME: change below to get_main_role(var.CLONED[clone]) once var.CLONED is converted
|
|
||||||
debuglog("{0} (clone) CLONE: {1} ({2})".format(clone, var.CLONED[clone.nick], get_role(var.CLONED[clone.nick])))
|
|
||||||
elif mainrole in var.WOLFCHAT_ROLES:
|
|
||||||
wolves = get_players(var.WOLFCHAT_ROLES)
|
|
||||||
wolves.remove(clone) # remove self from list
|
|
||||||
for wolf in wolves:
|
|
||||||
wolf.queue_message(messages["clone_wolf"].format(clone, player))
|
|
||||||
if wolves:
|
|
||||||
wolf.send_messages()
|
|
||||||
if var.PHASE == "day":
|
|
||||||
random.shuffle(wolves)
|
|
||||||
for i, wolf in enumerate(wolves):
|
|
||||||
wolfrole = get_main_role(wolf)
|
|
||||||
wevt = Event("wolflist", {"tags": set()})
|
|
||||||
wevt.dispatch(var, wolf, clone)
|
|
||||||
tags = " ".join(wevt.data["tags"])
|
|
||||||
if tags:
|
|
||||||
tags += " "
|
|
||||||
wolves[i] = "\u0002{0}\u0002 ({1}{2})".format(wolf, tags, wolfrole)
|
|
||||||
|
|
||||||
if wolves:
|
|
||||||
clone.send(messages["wolves_list"].format(wolves))
|
|
||||||
else:
|
|
||||||
clone.send(messages["no_other_wolves"])
|
|
||||||
elif mainrole == "turncoat":
|
|
||||||
var.TURNCOATS[clone.nick] = ("none", -1) # FIXME
|
|
||||||
|
|
||||||
if mainrole == "clone" and player.nick in var.CLONED:
|
|
||||||
del var.CLONED[player.nick]
|
|
||||||
|
|
||||||
pl = refresh_pl(pl)
|
|
||||||
# i herd u liek parameters
|
# i herd u liek parameters
|
||||||
evt_death_triggers = death_triggers and var.PHASE in var.GAME_PHASES
|
evt_death_triggers = death_triggers and var.PHASE in var.GAME_PHASES
|
||||||
event = Event("del_player", {"pl": pl},
|
event = Event("del_player", {"pl": pl},
|
||||||
@ -2793,7 +2723,7 @@ def rename_player(var, user, prefix):
|
|||||||
if prefix == k:
|
if prefix == k:
|
||||||
var.PLAYERS[nick] = var.PLAYERS.pop(k)
|
var.PLAYERS[nick] = var.PLAYERS.pop(k)
|
||||||
|
|
||||||
for dictvar in (var.OBSERVED, var.CLONED, var.LASTHEXED, var.BITE_PREFERENCES):
|
for dictvar in (var.OBSERVED, var.LASTHEXED, var.BITE_PREFERENCES):
|
||||||
kvp = []
|
kvp = []
|
||||||
for a,b in dictvar.items():
|
for a,b in dictvar.items():
|
||||||
if a == prefix:
|
if a == prefix:
|
||||||
@ -3096,27 +3026,14 @@ def transition_day(gameid=0):
|
|||||||
event_begin = Event("transition_day_begin", {})
|
event_begin = Event("transition_day_begin", {})
|
||||||
event_begin.dispatch(var)
|
event_begin.dispatch(var)
|
||||||
|
|
||||||
pl = get_players()
|
|
||||||
|
|
||||||
if not var.START_WITH_DAY or not var.FIRST_DAY:
|
if not var.START_WITH_DAY or not var.FIRST_DAY:
|
||||||
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.nick not in var.HEXED: # FIXME
|
if hag.nick not in var.HEXED: # FIXME
|
||||||
var.LASTHEXED[hag.nick] = None # FIXME
|
var.LASTHEXED[hag.nick] = None # FIXME
|
||||||
|
|
||||||
# NOTE: Random assassin selection is further down, since if we're choosing at random we pick someone
|
# NOTE: Random assassin selection is further down, since if we're choosing at random we pick someone
|
||||||
# that isn't going to be dying today, meaning we need to know who is dying first :)
|
# that isn't going to be dying today, meaning we need to know who is dying first :)
|
||||||
|
|
||||||
if var.FIRST_NIGHT:
|
|
||||||
# Select a random target for clone if they didn't choose someone
|
|
||||||
for clone in get_all_players(("clone",)):
|
|
||||||
if clone.nick not in var.CLONED:
|
|
||||||
ps = pl[:]
|
|
||||||
ps.remove(clone)
|
|
||||||
if len(ps) > 0:
|
|
||||||
target = random.choice(ps)
|
|
||||||
var.CLONED[clone.nick] = target.nick
|
|
||||||
clone.send(messages["random_clone"].format(target))
|
|
||||||
|
|
||||||
# Reset daytime variables
|
# Reset daytime variables
|
||||||
var.WOUNDED.clear()
|
var.WOUNDED.clear()
|
||||||
@ -3515,10 +3432,6 @@ def chk_nightdone():
|
|||||||
|
|
||||||
nightroles = list(get_all_players(("sorcerer", "hag", "warlock", "werecrow")))
|
nightroles = list(get_all_players(("sorcerer", "hag", "warlock", "werecrow")))
|
||||||
|
|
||||||
if var.FIRST_NIGHT:
|
|
||||||
actedcount += len(var.CLONED.keys())
|
|
||||||
nightroles.extend(get_all_players(("clone",)))
|
|
||||||
|
|
||||||
if var.ALPHA_ENABLED:
|
if var.ALPHA_ENABLED:
|
||||||
# alphas both kill and bite if they're activated at night, so add them into the counts
|
# alphas both kill and bite if they're activated at night, so add them into the counts
|
||||||
nightroles.extend(get_all_players(("alpha wolf",)))
|
nightroles.extend(get_all_players(("alpha wolf",)))
|
||||||
@ -3704,10 +3617,7 @@ def check_exchange(cli, actor, nick):
|
|||||||
# var.PASSED is used by many roles
|
# var.PASSED is used by many roles
|
||||||
var.PASSED.discard(actor)
|
var.PASSED.discard(actor)
|
||||||
|
|
||||||
if actor_role == "clone":
|
if actor_role in ("werecrow", "sorcerer"):
|
||||||
if actor in var.CLONED:
|
|
||||||
actor_target = var.CLONED.pop(actor)
|
|
||||||
elif actor_role in ("werecrow", "sorcerer"):
|
|
||||||
if actor in var.OBSERVED:
|
if actor in var.OBSERVED:
|
||||||
del var.OBSERVED[actor]
|
del var.OBSERVED[actor]
|
||||||
elif actor_role == "hag":
|
elif actor_role == "hag":
|
||||||
@ -3732,10 +3642,7 @@ def check_exchange(cli, actor, nick):
|
|||||||
# var.PASSED is used by many roles
|
# var.PASSED is used by many roles
|
||||||
var.PASSED.discard(nick)
|
var.PASSED.discard(nick)
|
||||||
|
|
||||||
if nick_role == "clone":
|
if nick_role in ("werecrow", "sorcerer"):
|
||||||
if nick in var.CLONED:
|
|
||||||
nick_target = var.CLONED.pop(nick)
|
|
||||||
elif nick_role in ("werecrow", "sorcerer"):
|
|
||||||
if nick in var.OBSERVED:
|
if nick in var.OBSERVED:
|
||||||
del var.OBSERVED[nick]
|
del var.OBSERVED[nick]
|
||||||
elif nick_role == "hag":
|
elif nick_role == "hag":
|
||||||
@ -3809,9 +3716,7 @@ def check_exchange(cli, actor, nick):
|
|||||||
else:
|
else:
|
||||||
wcroles = var.WOLF_ROLES | {"traitor"}
|
wcroles = var.WOLF_ROLES | {"traitor"}
|
||||||
|
|
||||||
if nick_role == "clone":
|
if nick_role not in wcroles and nick_role == "warlock":
|
||||||
pm(cli, actor, messages["clone_target"].format(nick_target))
|
|
||||||
elif nick_role not in wcroles and nick_role == "warlock":
|
|
||||||
# this means warlock isn't in wolfchat, so only give cursed list
|
# this means warlock isn't in wolfchat, so only give cursed list
|
||||||
pl = list_players()
|
pl = list_players()
|
||||||
random.shuffle(pl)
|
random.shuffle(pl)
|
||||||
@ -3823,9 +3728,7 @@ def check_exchange(cli, actor, nick):
|
|||||||
elif nick_role == "turncoat":
|
elif nick_role == "turncoat":
|
||||||
var.TURNCOATS[actor] = ("none", -1)
|
var.TURNCOATS[actor] = ("none", -1)
|
||||||
|
|
||||||
if actor_role == "clone":
|
if actor_role not in wcroles and actor_role == "warlock":
|
||||||
pm(cli, nick, messages["clone_target"].format(actor_target))
|
|
||||||
elif actor_role not in wcroles and actor_role == "warlock":
|
|
||||||
# this means warlock isn't in wolfchat, so only give cursed list
|
# this means warlock isn't in wolfchat, so only give cursed list
|
||||||
pl = list_players()
|
pl = list_players()
|
||||||
random.shuffle(pl)
|
random.shuffle(pl)
|
||||||
@ -4265,46 +4168,6 @@ def curse(cli, nick, chan, rest):
|
|||||||
|
|
||||||
debuglog("{0} ({1}) CURSE: {2} ({3})".format(nick, get_role(nick), victim, vrole))
|
debuglog("{0} ({1}) CURSE: {2} ({3})".format(nick, get_role(nick), victim, vrole))
|
||||||
|
|
||||||
@cmd("clone", chan=False, pm=True, playing=True, phases=("night",), roles=("clone",))
|
|
||||||
def clone(cli, nick, chan, rest):
|
|
||||||
"""Clone another player. You will turn into their role if they die."""
|
|
||||||
if not var.FIRST_NIGHT:
|
|
||||||
return
|
|
||||||
if nick in var.CLONED.keys():
|
|
||||||
pm(cli, nick, messages["already_cloned"])
|
|
||||||
return
|
|
||||||
|
|
||||||
params = re.split(" +", rest)
|
|
||||||
# allow for role-prefixed command such as !clone clone target
|
|
||||||
# if we get !clone clone (with no 3rd arg), we give preference to prefixed version;
|
|
||||||
# meaning if the person wants to clone someone named clone, they must type !clone clone clone
|
|
||||||
# (or just !clone clon, !clone clo, etc. assuming thos would be unambiguous matches)
|
|
||||||
if params[0] == "clone":
|
|
||||||
if len(params) > 1:
|
|
||||||
del params[0]
|
|
||||||
else:
|
|
||||||
pm(cli, nick, messages["clone_clone_clone"])
|
|
||||||
return
|
|
||||||
|
|
||||||
# no var.SILENCED check for night 1 only roles; silence should only apply for the night after
|
|
||||||
# but just in case, it also sucks if the one night you're allowed to act is when you are
|
|
||||||
# silenced, so we ignore it here anyway.
|
|
||||||
|
|
||||||
victim = get_victim(cli, nick, params[0], False)
|
|
||||||
if not victim:
|
|
||||||
return
|
|
||||||
|
|
||||||
if nick == victim:
|
|
||||||
pm(cli, nick, messages["no_target_self"])
|
|
||||||
return
|
|
||||||
|
|
||||||
var.CLONED[nick] = victim
|
|
||||||
pm(cli, nick, messages["clone_target_success"].format(victim))
|
|
||||||
|
|
||||||
debuglog("{0} ({1}) CLONE: {2} ({3})".format(nick, get_role(nick), victim, get_role(victim)))
|
|
||||||
|
|
||||||
var.ROLE_COMMAND_EXCEPTIONS.add("clone")
|
|
||||||
|
|
||||||
@event_listener("targeted_command", priority=9)
|
@event_listener("targeted_command", priority=9)
|
||||||
def on_targeted_command(evt, var, actor, orig_target):
|
def on_targeted_command(evt, var, actor, orig_target):
|
||||||
if evt.data["misdirection"]:
|
if evt.data["misdirection"]:
|
||||||
@ -4594,17 +4457,6 @@ def transition_night():
|
|||||||
else:
|
else:
|
||||||
priest.send(messages["priest_notify"])
|
priest.send(messages["priest_notify"])
|
||||||
|
|
||||||
if var.FIRST_NIGHT or var.ALWAYS_PM_ROLE:
|
|
||||||
for clone in get_all_players(("clone",)):
|
|
||||||
pl = ps[:]
|
|
||||||
random.shuffle(pl)
|
|
||||||
pl.remove(clone)
|
|
||||||
if clone.prefers_simple():
|
|
||||||
clone.send(messages["clone_simple"])
|
|
||||||
else:
|
|
||||||
clone.send(messages["clone_notify"])
|
|
||||||
clone.send(messages["players_list"].format(", ".join(p.nick for p in pl)))
|
|
||||||
|
|
||||||
for g in var.GUNNERS:
|
for g in var.GUNNERS:
|
||||||
if g not in ps:
|
if g not in ps:
|
||||||
continue
|
continue
|
||||||
@ -4847,7 +4699,6 @@ def start(cli, nick, chan, forced = False, restart = ""):
|
|||||||
var.MAIN_ROLES.clear()
|
var.MAIN_ROLES.clear()
|
||||||
var.GUNNERS.clear()
|
var.GUNNERS.clear()
|
||||||
var.OBSERVED = {}
|
var.OBSERVED = {}
|
||||||
var.CLONED = {}
|
|
||||||
var.LASTHEXED = {}
|
var.LASTHEXED = {}
|
||||||
var.SILENCED = set()
|
var.SILENCED = set()
|
||||||
var.TOBESILENCED = set()
|
var.TOBESILENCED = set()
|
||||||
@ -5702,10 +5553,6 @@ def myrole(var, wrapper, message):
|
|||||||
for msg in evt.data["messages"]:
|
for msg in evt.data["messages"]:
|
||||||
wrapper.pm(msg)
|
wrapper.pm(msg)
|
||||||
|
|
||||||
# Remind clone who they have cloned
|
|
||||||
if role == "clone" and wrapper.source.nick in var.CLONED:
|
|
||||||
wrapper.pm(messages["clone_target"].format(var.CLONED[wrapper.source.nick]))
|
|
||||||
|
|
||||||
# Remind turncoats of their side
|
# Remind turncoats of their side
|
||||||
if role == "turncoat":
|
if role == "turncoat":
|
||||||
wrapper.pm(messages["turncoat_side"].format(var.TURNCOATS.get(wrapper.source.nick, "none")[0]))
|
wrapper.pm(messages["turncoat_side"].format(var.TURNCOATS.get(wrapper.source.nick, "none")[0]))
|
||||||
@ -6177,10 +6024,8 @@ def revealroles(var, wrapper, message):
|
|||||||
# go through each nickname, adding extra info if necessary
|
# go through each nickname, adding extra info if necessary
|
||||||
for user in users:
|
for user in users:
|
||||||
special_case = []
|
special_case = []
|
||||||
if role == "clone" and user.nick in var.CLONED:
|
|
||||||
special_case.append("cloning {0}".format(var.CLONED[user.nick]))
|
|
||||||
# print how many bullets normal gunners have
|
# print how many bullets normal gunners have
|
||||||
elif (role == "gunner" or role == "sharpshooter") and user in var.GUNNERS:
|
if (role == "gunner" or role == "sharpshooter") and user in var.GUNNERS:
|
||||||
special_case.append("{0} bullet{1}".format(var.GUNNERS[user], "" if var.GUNNERS[user] == 1 else "s"))
|
special_case.append("{0} bullet{1}".format(var.GUNNERS[user], "" if var.GUNNERS[user] == 1 else "s"))
|
||||||
elif role == "turncoat" and user.nick in var.TURNCOATS:
|
elif role == "turncoat" and user.nick in var.TURNCOATS:
|
||||||
special_case.append("currently with \u0002{0}\u0002".format(var.TURNCOATS[user.nick][0])
|
special_case.append("currently with \u0002{0}\u0002".format(var.TURNCOATS[user.nick][0])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user