import asyncio import json import random import sys import discord STATE_FILE = 'state.json' CHANNEL_NAME = 'therapy-elevator' DELETION_SECONDS = 15 TYPING_DELAY = 2 SETUP_MESSAGE = 'Welcome to Nemuro Memorial Hall. Please give your name and class year for our records.' INITIAL_MESSAGE = 'All right, please begin.' BUTTERFLIES = ['🦋', 'Deeper. Go deeper.', '🥐', '🐛', '🥚', '🍃'] ELEVATOR_SHIT_PERIOD = 5 ELEVATOR_SHIT = [ '*the elevator creaks eerily*', '*menacing discordant music plays*', '*drawers rush past on the walls outside*', '*the lights flicker*', '*the elevator jolts, then continues its descent*', '*a rattling. the elevator begins to shake*', '*a squealing of cables and pulleys*', ] CRASH = ('|\n'*10) + '***the elevator crashes to the bottom***' + ('\n'*10) + '...' FINAL_MESSAGE = 'I understand. Your only choice is to revolutionize the world. The path you must take has been prepared for you.' ROSE = '🌹💍' async def try_send(channel, message): try: await channel.send(message) except discord.DiscordException as e: print(f"error sending message in channel {channel}: {e}", file=sys.stderr) async def try_move(channel, **kwargs): try: await channel.move(**kwargs) except discord.DiscordException as e: print(f"error moving channel {channel}: {e}", file=sys.stderr) await try_send(channel, "Dammit, the elevator's stuck!") def text_only(channels): return [channel for channel in channels if isinstance(channel, discord.TextChannel)] class MikageClient(discord.Client): def __init__(self): super().__init__() try: with open(STATE_FILE, encoding='utf-8') as f: self.state = json.load(f) except FileNotFoundError: self.state = {} self.save_state() def save_state(self): with open(STATE_FILE, 'w', encoding='utf-8') as f: json.dump(self.state, f) async def on_ready(self): print(f"logged in as {self.user}", file=sys.stderr) await self.change_presence(activity=discord.Game('the dueling game, for keeps')) for guild in self.guilds: await self.initialize_elevator(guild) async def on_guild_join(self, guild): print(f"joined new guild: {guild}", file=sys.stderr) await self.initialize_elevator(guild) async def initialize_elevator(self, guild): guild_id = str(guild.id) if guild_id in self.state and guild.get_channel(self.state[guild_id]['channel']) is not None: return try: top_category = guild.by_category()[0][0] channel = await guild.create_text_channel( CHANNEL_NAME, category=top_category, topic="the he/they therapist - you know, the one who lives in the morgue in the basement of that building that doesn't exist? - is in" ) await channel.move(category=top_category, beginning=True) self.state[guild_id] = {'channel': channel.id} self.save_state() await channel.send(SETUP_MESSAGE) except discord.DiscordException as e: print(f"error initializing elevator for guild {guild}: {e}", file=sys.stderr) return async def on_message(self, message): if message.guild is None: return guild_id = str(message.guild.id) if guild_id not in self.state or message.channel.id != self.state[guild_id]['channel']: return if message.author == self.user: return categories = message.guild.by_category() (category_index, (category, channels)) = [entry for entry in enumerate(categories) if message.channel in entry[1][1]][0] channels = text_only(channels) channel_index = channels.index(message.channel) if category_index == 0 and channel_index == 0: await try_send(message.channel, INITIAL_MESSAGE) if category_index == len(categories) - 1: return if channel_index == len(channels) - 1: if category_index == len(categories) - 2: await message.channel.move(category=categories[-1][0], end=True) await try_send(message.channel, CRASH) await asyncio.sleep(TYPING_DELAY) await try_send(message.channel, FINAL_MESSAGE) await asyncio.sleep(TYPING_DELAY) await try_send(message.channel, ROSE) await asyncio.sleep(DELETION_SECONDS) try: await message.channel.delete() del self.state[guild_id] self.save_state() except discord.DiscordException as e: print(f"error deleting elevator for guild {message.guild}: {e}", file=sys.stderr) return await self.initialize_elevator(message.guild) return await try_move(message.channel, category=categories[category_index+1][0], beginning=True) await try_send(message.channel, BUTTERFLIES[int(category_index*len(BUTTERFLIES)/(len(categories)-2))]) else: await try_move(message.channel, category=category, beginning=True, offset=channel_index+1) if random.randrange(ELEVATOR_SHIT_PERIOD) == 0: await try_send(message.channel, random.choice(ELEVATOR_SHIT)) client = MikageClient() with open('token', encoding='utf-8') as f: token = f.read().strip() client.run(token)