async def quit(self, ctx): """Quit command""" import globvars if globvars.master_state.game: # This check is to ensure a player doesn't quit right after !start # before the game is fully set up and end up breaking the game. return # The command user has joined; make them quit if globvars.master_state.pregame.is_joined(ctx.author.id): globvars.master_state.pregame.safe_remove_player(ctx.author.id) botutils.update_state_machine() await ctx.send(quit_str.format(ctx.author.name, len(globvars.master_state.pregame))) # If you are the last player to leave, then cancel the lobby timeout loop if len(globvars.master_state.pregame) == 0: lobby_timeout.cancel() # If the player has voted to start, then remove the start vote if ctx.author.id in globvars.start_votes: globvars.start_votes.remove(ctx.author.id) # Cancel the start clear timer if no one has voted to start if len(globvars.start_votes) == 0 and start_votes_timer.is_running(): start_votes_timer.cancel() # The command user has not joined else: await ctx.send(quitted_str.format(ctx.author.mention)) # Still take away the role from everyone just in case of discord sync issue await botutils.remove_alive_role(ctx.author, unlock=True)
async def end_game(self): """End the game, compute winners etc. Must be implemented. """ # Send the lobby game conclusion message await self.send_lobby_closing_message() # Remove roles await botutils.remove_all_alive_dead_roles_after_game() # Unload extensions globvars.client.unload_extension("botc.commands.abilities") globvars.client.unload_extension("botc.commands.townhall") globvars.client.unload_extension("botc.commands.debug") # Load conflicting commands for extension in CONFLICTING_CMDS: globvars.client.load_extension(extension) # Log the game await botutils.log(botutils.Level.info, "Game finished") # Stop various loops from running from botc.gameloops import nomination_loop, base_day_loop # Stop the nomination loop if it is running if nomination_loop.is_running(): nomination_loop.cancel() # Stop the base day loop if it is running if base_day_loop.is_running(): base_day_loop.cancel() # Clear the game object self.__init__() globvars.master_state.game = None # Unlock the lobby channel await botutils.unlock_lobby() # Update the global state botutils.update_state_machine()
async def fstart(self, ctx): """Force start command""" import globvars game = botutils.GameChooser().get_selected_game() # Make sure all the players are still in the guild globvars.master_state.pregame.remove_left_guild_players() if len(globvars.master_state.pregame) < game.MIN_PLAYERS: msg = fstart_min.format(ctx.author.mention, botutils.BotEmoji.x_emoji, str(game), game.MIN_PLAYERS) await ctx.send(msg) return if len(globvars.master_state.pregame) > game.MAX_PLAYERS: msg = fstart_max.format(ctx.author.mention, botutils.BotEmoji.x_emoji, str(game), game.MAX_PLAYERS) await ctx.send(msg) return globvars.master_state.game = game await globvars.master_state.game.start_game() botutils.update_state_machine() # Clear the start votes globvars.start_votes.clear()
async def fleave(self, ctx, *, member: discord.Member): """Force leave command""" import globvars # The player has joined; make them leave if globvars.master_state.pregame.is_joined(member.id): globvars.master_state.pregame.safe_remove_player(member.id) await ctx.send( fleave_str.format(member.name, len(globvars.master_state.pregame))) botutils.update_state_machine() # If you are the last player to leave, then cancel the lobby timeout loop if len(globvars.master_state.pregame) == 0: lobby_timeout.cancel() # If the player has voted to start, then remove the start vote if member.id in globvars.start_votes: globvars.start_votes.remove(member.id) # Cancel the start clear timer if no one has voted to start if len(globvars.start_votes) == 0 and start_votes_timer.is_running( ): start_votes_timer.cancel() # The player has not joined else: await ctx.send(fleaved_str.format(ctx.author.mention, member.name)) await botutils.remove_alive_role(member, unlock=True)
async def start(self, ctx): """Start command""" import globvars # The player has already voted to start if ctx.author.id in globvars.start_votes: return game = botutils.GameChooser().get_selected_game() if len(globvars.master_state.pregame) < game.MIN_PLAYERS: msg = fstart_min.format(ctx.author.mention, botutils.BotEmoji.cross, str(game), game.MIN_PLAYERS) await ctx.send(msg) return if len(globvars.master_state.pregame) > game.MAX_PLAYERS: msg = fstart_max.format(ctx.author.mention, botutils.BotEmoji.cross, str(game), game.MAX_PLAYERS) await ctx.send(msg) return # The player has not voted to start yet else: globvars.start_votes.append(ctx.author.id) # First person to vote. Start the clear start votes timer if len(globvars.start_votes) == 1: if start_votes_timer.is_running(): start_votes_timer.cancel() start_votes_timer.start() # Calculate the number of votes needed votes_needed = max(len(globvars.master_state.pregame) - 3, 3) # Reached the number of votes needed. Start the game. if len(globvars.start_votes) == votes_needed: game = botutils.GameChooser().get_selected_game() globvars.master_state.game = game await globvars.master_state.game.start_game() botutils.update_state_machine() # Clear the start votes globvars.start_votes.clear() return votes_left = votes_needed - len(globvars.start_votes) # Do not have a negative number of votes required to start if votes_left < 0: return msg = start_str.format(ctx.author.name, votes_left, "vote" if votes_left == 1 else "votes") await ctx.send(msg)
async def fstart(self, ctx): """Force start command""" import globvars game = botutils.GameChooser().get_selected_game() if len(globvars.master_state.pregame) < game.MIN_PLAYERS: msg = fstart_min.format(ctx.author.mention, botutils.BotEmoji.cross, str(game), game.MIN_PLAYERS) await ctx.send(msg) return if len(globvars.master_state.pregame) > game.MAX_PLAYERS: msg = fstart_min msg = fstart_min.format(ctx.author.mention, botutils.BotEmoji.cross, str(game), game.MAX_PLAYERS) await ctx.send(msg) return globvars.master_state.game = game await globvars.master_state.game.start_game() botutils.update_state_machine()
async def fjoin(self, ctx, *, member: discord.Member): """Force join command""" import globvars game = botutils.GameChooser().get_selected_game() # Too many players if len(globvars.master_state.pregame) >= game.MAX_PLAYERS: msg = fjoin_max msg = fjoin_max.format(ctx.author.mention, botutils.BotEmoji.cross, str(game), game.MAX_PLAYERS) await ctx.send(msg) return # The player has already joined if globvars.master_state.pregame.is_joined(member.id): await ctx.send(fjoined_str.format(ctx.author.mention, member.name)) # The player has not yet joined. Make them join. else: globvars.master_state.pregame.safe_add_player(member.id) botutils.update_state_machine() await ctx.send( fjoin_str.format(member.name, len(globvars.master_state.pregame))) # If you are the first player to join the game, then start the lobby timeout loop if len(globvars.master_state.pregame) == 1: lobby_timeout.start() await botutils.add_alive_role(member)
async def after_lobby_timeout(): """After lobby timeout""" import globvars # Only send the lobby timeout message if someone is still in the game if not lobby_timeout.is_being_cancelled(): await botutils.send_lobby(lobby_timeout_str.format(botutils.make_role_ping(ALIVE_ROLE_ID))) # Remove the alive role from everyone await botutils.remove_all_alive_roles_pregame() # Clear the master pregame state globvars.master_state.pregame.clear() botutils.update_state_machine()
async def fleave(self, ctx, *members: Union[discord.Member, str]): """Force leave command""" import globvars if members[0] == "all": count = len(globvars.master_state.pregame) - 1 for player in globvars.master_state.pregame: fetched_member = globvars.client.get_guild( SERVER_ID).get_member(player) await ctx.send( fleave_str.format( (fetched_member.name if fetched_member else player), count)) if fetched_member: await botutils.remove_alive_role(fetched_member) count -= 1 globvars.master_state.pregame.clear() lobby_timeout.cancel() if start_votes_timer.is_running(): start_votes_timer.cancel() botutils.update_state_machine() elif isinstance(members[0], discord.Member): for member in members: # The player has joined; make them leave if globvars.master_state.pregame.is_joined(member.id): globvars.master_state.pregame.safe_remove_player(member.id) await ctx.send( fleave_str.format(member.name, len(globvars.master_state.pregame))) botutils.update_state_machine() # If you are the last player to leave, then cancel the lobby timeout loop if len(globvars.master_state.pregame) == 0: lobby_timeout.cancel() # If the player has voted to start, then remove the start vote if member.id in globvars.start_votes: globvars.start_votes.remove(member.id) # Cancel the start clear timer if no one has voted to start if len(globvars.start_votes ) == 0 and start_votes_timer.is_running(): start_votes_timer.cancel() # The player has not joined else: await ctx.send( fleaved_str.format(ctx.author.mention, member.name)) await botutils.remove_alive_role(member)
async def fjoin(self, ctx, *members: Union[discord.Member, discord.User, str]): """Force join command""" import globvars game = botutils.GameChooser().get_selected_game() for member in members: if isinstance(member, str): member = botutils.get_member_from_string(member) if member is None: continue # The player is a bot if member.bot: await ctx.send(cant_fjoin_bot.format(ctx.author.mention)) return # Too many players if len(globvars.master_state.pregame) >= game.MAX_PLAYERS: msg = fjoin_max.format(ctx.author.mention, botutils.BotEmoji.x_emoji, str(game), game.MAX_PLAYERS) await ctx.send(msg) return # The player has already joined if globvars.master_state.pregame.is_joined(member.id): await ctx.send( fjoined_str.format(ctx.author.mention, member.name)) # The player has not yet joined. Make them join. else: globvars.master_state.pregame.safe_add_player(member.id) botutils.update_state_machine() await ctx.send( fjoin_str.format(member.name, len(globvars.master_state.pregame))) # If you are the first player to join the game, then start the lobby timeout loop if len(globvars.master_state.pregame) == 1: lobby_timeout.start() await botutils.add_alive_role(member)
async def join(self, ctx): """Join command""" import globvars # The command user has already joined if globvars.master_state.pregame.is_joined(ctx.author.id): await ctx.send(joined_str.format(ctx.author.mention)) # The command user has not joined yet; make them join else: globvars.master_state.pregame.safe_add_player(ctx.author.id) botutils.update_state_machine() join_replies = language["doc"]["join"]["outputs"] join_weights = language["doc"]["join"]["weights"] if join_weights: join_reply = random.choices( join_replies, weights=join_weights ) join_str = join_reply[0] else: join_str = random.choice(join_replies) emoji = random.choice(emojis) msg = emoji msg += " " msg += join_str.format( ctx.author.name, len(globvars.master_state.pregame), "player" if len(globvars.master_state.pregame) == 1 else "players" ) await ctx.send(msg) # If you are the first player to join the game, then start the lobby timeout loop if len(globvars.master_state.pregame) == 1: lobby_timeout.start() # Still give everyone the role just in case of discord sync issue await botutils.add_alive_role(ctx.author)
async def fleave(self, ctx, *, member: discord.Member): """Force leave command""" import globvars # The player has joined; make them leave. if globvars.master_state.pregame.is_joined(member.id): globvars.master_state.pregame.safe_remove_player(member.id) await ctx.send( fleave_str.format(member.name, len(globvars.master_state.pregame))) botutils.update_state_machine() # If you are the last player to leave, then cancel the lobby timeout loop if len(globvars.master_state.pregame) == 0: lobby_timeout.cancel() # The player has not joined. else: await ctx.send(fleaved_str.format(ctx.author.mention, member.name)) await botutils.remove_alive_role(member)
async def quit(self, ctx): """Quit command""" import globvars # The command user has joined; make them quit if globvars.master_state.pregame.is_joined(ctx.author.id): globvars.master_state.pregame.safe_remove_player(ctx.author.id) botutils.update_state_machine() await ctx.send( quit_str.format(ctx.author.name, len(globvars.master_state.pregame))) # If you are the last player to leave, then cancel the lobby timeout loop if len(globvars.master_state.pregame) == 0: lobby_timeout.cancel() # The command user has not joined else: await ctx.send(quitted_str.format(ctx.author.mention)) # Still take away the role from everyone just in case of discord sync issue await botutils.remove_alive_role(ctx.author)
async def sync(self, ctx): """Sync command""" # Case 1 : Game softlock if globvars.master_state.game and not globvars.master_state.game.gameloop.is_running( ) and not globvars.master_state.game.working: from botc.gamemodes.Gamemode import Gamemode globvars.master_state.game.invalidated = True try: await botutils.unlock_lobby() alive_role = globvars.client.get_guild(SERVER_ID).get_role( ALIVE_ROLE_ID) dead_role = globvars.client.get_guild(SERVER_ID).get_role( DEAD_ROLE_ID) for player in alive_role.members: await botutils.remove_alive_role(player) for player in dead_role.members: await botutils.remove_dead_role(player) except Exception as e: print(e) try: if globvars.master_state.game.gamemode == Gamemode.trouble_brewing: globvars.client.unload_extension( "botc.commands.abilities.tb") elif globvars.master_state.game.gamemode == Gamemode.bad_moon_rising: globvars.client.unload_extension( "botc.commands.abilities.bmr") elif globvars.master_state.game.gamemode == Gamemode.sects_and_violets: globvars.client.unload_extension( "botc.commands.abilities.snv") globvars.client.unload_extension("botc.commands.townhall") globvars.client.unload_extension("botc.commands.debug") except Exception as e: print(e) from botc.gameloops import (base_day_loop, master_game_loop, nomination_loop) try: # Stop the nomination loop if it is running if nomination_loop.is_running(): nomination_loop.cancel() # Stop the base day loop if it is running if base_day_loop.is_running(): base_day_loop.cancel() if master_game_loop.is_running(): master_game_loop.cancel() except Exception as e: print(e) try: from botc.Game import CONFLICTING_CMDS for cmd in CONFLICTING_CMDS: globvars.client.load_extension(cmd) except Exception: pass globvars.master_state.game = None botutils.update_state_machine() elif not globvars.master_state.game: try: await botutils.unlock_lobby() dead_role = globvars.client.get_guild(SERVER_ID).get_role( DEAD_ROLE_ID) for player in dead_role.members: await botutils.remove_dead_role(player) alive_role = globvars.client.get_guild(SERVER_ID).get_role( ALIVE_ROLE_ID) mismatched_alive_players = list( filter( lambda user: user.id not in globvars.master_state. pregame.list, alive_role.members)) for member in mismatched_alive_players: await member.remove_roles(alive_role) await botutils.add_all_alive_role() except Exception: pass try: from botc.Game import CONFLICTING_CMDS for cmd in CONFLICTING_CMDS: globvars.client.load_extension(cmd) except Exception: pass try: await botutils.unlock_lobby() except Exception: pass botutils.update_state_machine() elif globvars.master_state.game: await botutils.add_all_alive_role() await ctx.send( sync_succesful_string.format(ctx.author.mention, botutils.BotEmoji.success))
async def join(self, ctx): """Join command""" import globvars if globvars.master_state.game: # This check is to ensure a player doesn't join right after !start # before the game is fully set up and end up breaking the game. return # The command user has already joined if globvars.master_state.pregame.is_joined(ctx.author.id): await ctx.send(joined_str.format(ctx.author.mention)) # The command user has not joined yet; make them join else: user_ids = set() with sqlite3.connect("data.sqlite3") as conn: c = conn.cursor() c.execute( """ SELECT primary_user_id, secondary_user_id FROM player_map WHERE primary_user_id = :user_id OR secondary_user_id = :user_id """, { "user_id": ctx.author.id, }) for row in c.fetchall(): primary, secondary = row user_ids.add(primary) user_ids.add(secondary) for user_id in globvars.master_state.pregame: if user_id in user_ids: user = globvars.client.get_user(user_id) await ctx.send( joined_alt_str.format(ctx.author.mention, str(user))) return globvars.master_state.pregame.safe_add_player(ctx.author.id) botutils.update_state_machine() join_replies = bot_text["doc"]["join"]["outputs"] join_weights = bot_text["doc"]["join"]["weights"] if join_weights: join_reply = random.choices(join_replies, weights=join_weights) join_str = join_reply[0] else: join_str = random.choice(join_replies) emoji = random.choice(emojis) msg = emoji msg += " " msg += join_str.format( ctx.author.name, len(globvars.master_state.pregame), "player" if len(globvars.master_state.pregame) == 1 else "players") await ctx.send(msg) # If you are the first player to join the game, then start the lobby timeout loop if len(globvars.master_state.pregame) == 1: if lobby_timeout.is_running(): lobby_timeout.cancel() lobby_timeout.start() # Still give everyone the role just in case of discord sync issue await botutils.add_alive_role(ctx.author)