Part 2 of 2

And as thus we sat in darkness,
Each one busy in his prayers,
“We are lost!” the captain shouted,
As he staggered down the stairs.

But his little daughter whispered,
As she took his icy hand,
“Isn’t God upon the ocean,
Just the same as on the land?”

Then we kissed the little maiden,
And we spoke in better cheer;
And we anchored safe in harbor
When the morn was shining clear.
This commit is contained in:
skizzerz 2016-02-03 22:04:29 -06:00
parent 69f72499ef
commit dbad8d1f09
4 changed files with 98 additions and 28 deletions

View File

@ -432,7 +432,7 @@
"day_lasted": "Day lasted \u0002{0:0>2}:{1:0>2}\u0002. ",
"fallen_angel_turn": "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.",
"bitten_turn": "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...",
"bitten_turn_wolfchat": "\u0002{0}\u0002 is now a \u0002{1}\u0002!",
"wolfchat_new_member": "\u0002{0}\u0002 is now a \u0002{1}\u0002!",
"amnesia_clear": "Your amnesia clears and you now remember that you are a{0} \u0002{1}\u0002!",
"amnesia_wolfchat": "\u0002{0}\u0002 is now a \u0002{1}\u0002!",
"wolf_notify": "You are a \u0002wolf\u0002. It is your job to kill all the villagers. Use \"kill <nick>\" to kill a villager.",

View File

@ -24,12 +24,12 @@ class Event:
self.name = name
self.data = data
def dispatch(self, *args):
def dispatch(self, *args, **kwargs):
if self.name not in EVENT_CALLBACKS:
return True
for item in list(EVENT_CALLBACKS[self.name]):
item[1](self, *args)
item[1](self, *args, **kwargs)
if self.stop_processing:
break

View File

@ -1055,14 +1055,63 @@ class MaelstromMode(GameMode):
self.LOVER_WINS_WITH_FOOL = True
self.MAD_SCIENTIST_SKIPS_DEAD_PLAYERS = 0 # always make it happen
self.ALWAYS_PM_ROLE = True
# clone is pointless in this mode
# dullahan doesn't really work in this mode either, if enabling anyway special logic to determine kill list
# needs to be added above for when dulls are added during the game
# matchmaker is conditionally enabled during night 1 only
self.roles = list(var.ROLE_GUIDE.keys() - var.TEMPLATE_RESTRICTIONS.keys() - {"amnesiac", "clone", "dullahan", "matchmaker"})
def startup(self):
events.add_listener("role_attribution", self.role_attribution)
events.add_listener("transition_night_begin", self.transition_night_begin)
events.add_listener("join", self.on_join)
def teardown(self):
events.remove_listener("role_attribution", self.role_attribution)
events.remove_listener("transition_night_begin", self.transition_night_begin)
events.remove_listener("join", self.on_join)
def on_join(self, evt, cli, var, nick, chan, rest, forced=False):
if var.PHASE != "day" or (nick != chan and chan != botconfig.CHANNEL):
return
if not forced and evt.data["join_player"](cli, nick, botconfig.CHANNEL, sanity=False):
self._on_join(cli, var, nick, chan)
evt.prevent_default = True
elif forced:
# in fjoin, handle this differently
jp = evt.data["join_player"]
evt.data["join_player"] = lambda cli, nick, chan, who=None, forced=False: jp(cli, nick, chan, who=who, forced=forced, sanity=False) and self._on_join(cli, var, nick, chan)
def _on_join(self, cli, var, nick, chan):
role = random.choice(self.roles)
var.ROLES[role].add(nick)
var.ORIGINAL_ROLES[role].add(nick)
var.FINAL_ROLES[nick] = role
if role == "doctor":
lpl = len(var.list_players())
var.DOCTORS[nick] = math.ceil(var.DOCTOR_IMMUNIZATION_MULTIPLIER * lpl)
# let them know their role
# FIXME: this is fugly
from src.decorators import COMMANDS
COMMANDS["myrole"][0].caller(cli, nick, chan, "")
# if they're a wolfchat role, alert the other wolves
if role in var.WOLFCHAT_ROLES:
relay_wolfchat_command(cli, nick, messages["wolfchat_new_member"].format(nick, role), var.WOLFCHAT_ROLES, is_wolf_command=True, is_kill_command=True)
# TODO: make this part of !myrole instead, no reason we can't give out wofllist in that
wolves = var.list_players(var.WOLFCHAT_ROLES)
pl = var.list_players()
random.shuffle(pl)
pl.remove(nick)
for i, player in enumerate(pl):
prole = var.get_role(player)
if prole in var.WOLFCHAT_ROLES:
cursed = ""
if player in var.ROLES["cursed villager"]:
cursed = "cursed "
pl[i] = "\u0002{0}\u0002 ({1}{2})".format(player, cursed, prole)
elif player in var.ROLES["cursed villager"]:
pl[i] = player + " (cursed)"
pm(cli, nick, "Players: " + ", ".join(pl))
def role_attribution(self, evt, cli, chk_win_conditions, var, villagers):
self.chk_win_conditions = chk_win_conditions
@ -1112,13 +1161,10 @@ class MaelstromMode(GameMode):
wolves = var.WOLF_ROLES - {"wolf cub"}
addroles[random.choice(list(wolves))] += 1 # make sure there's at least one wolf role
# clone is pointless in this mode
# dullahan doesn't really work in this mode either, if enabling anyway special logic to determine kill list
# needs to be added above for when dulls are added during the game
roles = list(var.ROLE_GUIDE.keys() - var.TEMPLATE_RESTRICTIONS.keys() - {"amnesiac", "clone", "dullahan"})
if not do_templates:
roles = self.roles[:]
if do_templates:
# mm only works night 1, do_templates is also only true n1
roles.remove("matchmaker")
self.roles.append("matchmaker")
while lpl:
addroles[random.choice(roles)] += 1
lpl -= 1

View File

@ -1118,6 +1118,14 @@ def deadchat_pref(cli, nick, chan, rest):
@cmd("join", "j", pm=True)
def join(cli, nick, chan, rest):
"""Either starts a new game of Werewolf or joins an existing game that has not started yet."""
# keep this and the event in fjoin() in sync
evt = Event("join", {
"join_player": join_player,
"join_deadchat": join_deadchat,
"vote_gamemode": vote_gamemode
})
if not evt.dispatch(cli, var, nick, chan, rest, forced=False):
return
if var.PHASE in ("none", "join"):
if chan == nick:
return
@ -1125,25 +1133,25 @@ def join(cli, nick, chan, rest):
if nick in var.USERS and (not var.USERS[nick]["account"] or var.USERS[nick]["account"] == "*"):
cli.notice(nick, messages["not_logged_in"])
return
if join_player(cli, nick, chan) and rest:
vote_gamemode(cli, nick, chan, rest.lower().split()[0], False)
if evt.data["join_player"](cli, nick, chan) and rest:
evt.data["vote_gamemode"](cli, nick, chan, rest.lower().split()[0], False)
else: # join deadchat
if chan == nick and nick != botconfig.NICK:
join_deadchat(cli, nick)
evt.data["join_deadchat"](cli, nick)
def join_player(cli, player, chan, who = None, forced = False):
def join_player(cli, player, chan, who=None, forced=False, *, sanity=True):
if who is None:
who = player
pl = var.list_players()
if chan != botconfig.CHANNEL:
return
return False
if not var.OPPED:
cli.notice(who, messages["bot_not_opped"].format(chan))
cli.msg("ChanServ", "op " + botconfig.CHANNEL)
return
return False
if player in var.USERS:
ident = var.USERS[player]["ident"]
@ -1155,7 +1163,7 @@ def join_player(cli, player, chan, who = None, forced = False):
host = None
acc = None
else:
return # Not normal
return False # Not normal
if not acc or acc == "*" or var.DISABLE_ACCOUNTS:
acc = None
@ -1174,11 +1182,10 @@ def join_player(cli, player, chan, who = None, forced = False):
cli.notice(who, messages["stasis"].format(
"you are" if player == who else player + " is", stasis,
"s" if stasis != 1 else ""))
return
return False
cmodes = [("+v", player)]
if var.PHASE == "none":
if var.AUTO_TOGGLE_MODES and player in var.USERS and var.USERS[player]["modes"]:
for mode in var.USERS[player]["modes"]:
cmodes.append(("-"+mode, player))
@ -1210,13 +1217,16 @@ def join_player(cli, player, chan, who = None, forced = False):
elif player in pl:
cli.notice(who, messages["already_playing"].format("You" if who == player else "They"))
return True
# if we're not doing insane stuff, return True so that one can use !join to vote for a game mode
# even if they are already joined. If we ARE doing insane stuff, return False to indicate that
# the player was not successfully joined by this call.
return sanity
elif len(pl) >= var.MAX_PLAYERS:
cli.notice(who, messages["too_many_players"])
return
elif var.PHASE != "join":
return False
elif sanity and var.PHASE != "join":
cli.notice(who, messages["game_already_running"])
return
return False
else:
if acc is not None and not botconfig.DEBUG_MODE:
for user in pl:
@ -1228,7 +1238,6 @@ def join_player(cli, player, chan, who = None, forced = False):
cli.notice(who, msg.format(user, "their", ""))
return
var.ROLES["person"].add(player)
var.ALL_PLAYERS.append(player)
if not is_fake_nick(player) or not botconfig.DEBUG_MODE:
if var.AUTO_TOGGLE_MODES and var.USERS[player]["modes"]:
@ -1238,6 +1247,13 @@ def join_player(cli, player, chan, who = None, forced = False):
var.USERS[player]["modes"] = set()
mass_mode(cli, cmodes, [])
cli.msg(chan, messages["player_joined"].format(player, len(pl) + 1))
if not sanity:
# Abandon Hope All Ye Who Enter Here
leave_deadchat(cli, player)
var.SPECTATING_DEADCHAT.discard(player)
var.SPECTATING_WOLFCHAT.discard(player)
return True
var.ROLES["person"].add(player)
if not is_fake_nick(player):
hostmask = ident + "@" + host
if hostmask not in var.JOINED_THIS_GAME and (not acc or acc not in var.JOINED_THIS_GAME_ACCS):
@ -1287,9 +1303,17 @@ def kill_join(cli, chan):
var.AFTER_FLASTGAME = None
@cmd("fjoin", admin_only=True, phases=("none", "join"))
@cmd("fjoin", admin_only=True)
def fjoin(cli, nick, chan, rest):
"""Forces someone to join a game."""
# keep this and the event in def join() in sync
evt = Event("join", {
"join_player": join_player,
"join_deadchat": join_deadchat,
"vote_gamemode": vote_gamemode
})
if not evt.dispatch(cli, var, nick, chan, rest, forced=True):
return
noticed = False
fake = False
if not var.OPPED:
@ -1297,7 +1321,7 @@ def fjoin(cli, nick, chan, rest):
cli.msg("ChanServ", "op " + botconfig.CHANNEL)
return
if not rest.strip():
join_player(cli, nick, chan, forced=True)
evt.data["join_player"](cli, nick, chan, forced=True)
for tojoin in re.split(" +",rest):
tojoin = tojoin.strip()
@ -1309,7 +1333,7 @@ def fjoin(cli, nick, chan, rest):
break
fake = True
for i in range(int(first), int(last)+1):
join_player(cli, str(i), chan, forced=True, who=nick)
evt.data["join_player"](cli, str(i), chan, forced=True, who=nick)
continue
if not tojoin:
continue
@ -1330,7 +1354,7 @@ def fjoin(cli, nick, chan, rest):
elif botconfig.DEBUG_MODE:
fake = True
if tojoin != botconfig.NICK:
join_player(cli, tojoin, chan, forced=True, who=nick)
evt.data["join_player"](cli, tojoin, chan, forced=True, who=nick)
else:
cli.notice(nick, messages["not_allowed"])
if fake:
@ -6636,7 +6660,7 @@ def transition_night(cli):
var.ROLES[chumprole].remove(chump)
var.ROLES[newrole].add(chump)
var.FINAL_ROLES[chump] = newrole
relay_wolfchat_command(cli, chump, messages["bitten_turn_wolfchat"].format(chump, newrole), var.WOLF_ROLES, is_wolf_command=True, is_kill_command=True)
relay_wolfchat_command(cli, chump, messages["wolfchat_new_member"].format(chump, newrole), var.WOLF_ROLES, is_wolf_command=True, is_kill_command=True)
# convert amnesiac
if var.NIGHT_COUNT == var.AMNESIAC_NIGHTS: