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 make_nightfall(self): """Transition the game into night phase""" # Initialize the master switches at the start of a phase import botc.switches botc.switches.init_switches() # Initialize the temporary night data set self.init_temporary_night_data() # Stop all tasks of the day phase if nomination_loop.is_running(): nomination_loop.cancel() if base_day_loop.is_running(): base_day_loop.cancel() # Move the chrono forward by one phase self._chrono.next() # Prepare the phase announcement message embed = discord.Embed(description=nightfall, color=CARD_NIGHT) embed.set_footer(text=copyrights_str) embed.set_image(url=nightfall_image) embed.timestamp = datetime.datetime.utcnow() await botutils.send_lobby(message="", embed=embed) # Reset the nomination data for the previous day phase for player in self.sitting_order: player.reset_nomination()
async def fstop(self, ctx): """Fstop command""" from botc.gameloops import nomination_loop, base_day_loop, debate_timer # 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() # Stop the debate timer loop if it is running if debate_timer.is_running(): debate_timer.cancel() # Stop the gameplay loop if it is running import globvars if globvars.master_state.game.gameloop.is_running(): globvars.master_state.game.gameloop.cancel() feedback = documentation["doc"]["fstop"]["feedback"] await ctx.send(feedback.format(botutils.BotEmoji.check)) else: feedback = documentation["cmd_warnings"]["no_game_running"] await ctx.send( feedback.format(ctx.author.mention, botutils.BotEmoji.cross))
async def fnight(self, ctx): """Fnight command""" import globvars if globvars.master_state.game.current_phase == Phase.day: from botc.gameloops import (base_day_loop, debate_timer, nomination_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() # Stop the debate timer loop if it is running if debate_timer.is_running(): debate_timer.cancel() import botc.switches botc.switches.master_proceed_to_night = True msg = game_text["doc"]["fnight"]["feedback"].format( botutils.BotEmoji.success) await ctx.send(msg)
async def fnomination(self, ctx): """fnomination command""" import globvars if globvars.master_state.game.current_phase == Phase.day: from botc.gameloops import base_day_loop if base_day_loop.is_running(): base_day_loop.cancel() import botc.switches botc.switches.master_proceed_to_nomination = True msg = game_text["doc"]["fnomination"]["feedback"].format(botutils.BotEmoji.success) await ctx.send(msg)
async def nominate(self, ctx, *, nominated: PlayerConverter()): """Nominate command usage: nominate <player> characters: living players """ import globvars from botc.gameloops import nomination_loop, base_day_loop player = BOTCUtils.get_player_from_id(ctx.author.id) # A nomination is currently going on. The player cannot nominate. if nomination_loop.is_running(): msg = nomination_ongoing.format(ctx.author.mention, botutils.BotEmoji.cross) await ctx.send(msg) return # The day has not reached nomination phase yet. The player cannot nominate. elif base_day_loop.is_running(): msg = nominations_not_open.format(ctx.author.mention, botutils.BotEmoji.cross) await ctx.send(msg) return if player.can_nominate(): if nominated.can_be_nominated(): # The player cannot nominate again today player.toggle_has_nominated() # The nominated player cannot be nominated again today nominated.toggle_was_nominated() await nominated.role.true_self.on_being_nominated( player, nominated) else: msg = cannot_be_nominated_again.format(ctx.author.mention, botutils.BotEmoji.cross, nominated.game_nametag) await ctx.send(msg) else: msg = cannot_nominate_again.format(ctx.author.mention, botutils.BotEmoji.cross) await ctx.send(msg)
async def votestop(self, ctx): """Votestop command""" import globvars if ctx.author.id in globvars.votestop_votes: return globvars.votestop_votes.append(ctx.author.id) votes_needed = math.ceil(len(globvars.master_state.game.player_obj_list) / 2) if not votestop_votes_timer.is_running(): votestop_votes_timer.start() await send_lobby(votestop_vote.format(ctx.author.mention, votes_needed - len(globvars.votestop_votes), "" if votes_needed - len(globvars.votestop_votes) == 1 else "s")) if len(globvars.votestop_votes) >= votes_needed: votestop_votes_timer.cancel() from botc.gameloops import (base_day_loop, debate_timer, nomination_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() # Stop the debate timer loop if it is running if debate_timer.is_running(): debate_timer.cancel() # Stop the gameplay loop if it is running import globvars if globvars.master_state.game.gameloop.is_running(): globvars.master_state.game.gameloop.cancel()
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 time(self, ctx): """Time command usage: time can be used by all players or in DM """ import globvars # Day phase if globvars.master_state.game.current_phase == Phase.day: # Day phase: pre-nomination (base day phase) if base_day_loop.is_running(): start_time = base_day_loop.next_iteration total_duration = calculate_base_day_duration( globvars.master_state.game) __time_elapsed = ( datetime.datetime.now(datetime.timezone.utc) - start_time).seconds time_left = total_duration - __time_elapsed msg = time_day_base.format( display_time(total_duration), "is" if time_left == 1 or (time_left >= 60 and time_left < 120) else "are", display_time(time_left)) await ctx.send(msg) # Day phase: nomination loop is running elif nomination_loop.is_running(): # We are in the debate phase if debate_timer.is_running(): end_time = debate_timer.next_iteration total_duration = DEBATE_TIME time_left = ( end_time - datetime.datetime.now(datetime.timezone.utc)).seconds msg = time_debate.format(display_time(total_duration), display_time(time_left)) await ctx.send(msg) # We are in the active voting phase else: msg = time_voting await ctx.send(msg) # Day phase: waiting for a nomination else: start_time = globvars.master_state.game.nomination_iteration_date[ 0] duration = globvars.master_state.game.nomination_iteration_date[ 1] time_left = duration - (datetime.datetime.now() - start_time).seconds msg = time_nomination.format(display_time(duration), display_time(time_left)) await ctx.send(msg) # Night phase elif globvars.master_state.game.current_phase == Phase.night: min_night_duration = BASE_NIGHT max_night_duration = BASE_NIGHT + NIGHT_MULTIPLER * INCREMENT __time_elapsed = ( datetime.datetime.now() - globvars.master_state.game.night_start_time).seconds time_left = max_night_duration - __time_elapsed msg = time_night.format( display_time(min_night_duration), display_time(max_night_duration), "is" if time_left == 1 or (time_left >= 60 and time_left < 120) else "are", display_time(time_left)) await ctx.send(msg) # Dawn phase elif globvars.master_state.game.current_phase == Phase.dawn: min_dawn_duration = BASE_DAWN max_dawn_duration = BASE_DAWN + DAWN_MULTIPLIER * INCREMENT __time_elapsed = ( datetime.datetime.now() - globvars.master_state.game.dawn_start_time).seconds time_left = max_dawn_duration - __time_elapsed msg = time_dawn.format( display_time(min_dawn_duration), display_time(max_dawn_duration), "is" if time_left == 1 or (time_left >= 60 and time_left < 120) else "are", display_time(time_left)) await ctx.send(msg)