Ejemplo n.º 1
0
    async def game_public_message(self):

        game_summary_embed = Embed()

        game_summary_embed.title = ("-" * 20) + f"Game {self.game.id} Summary" \
                                   + ("-" * 20)

        max_players = self.game.teams[0].size
        game_summary_embed.description = (
            "React to join!\n" + f"Created by: {self.user.mention}\n" +
            f"Mode: {self.mode_str} " +
            (f"({max_players})" if self.mode_str == "FFA" else "") + "\n" +
            f"Platform: {self.platform_choice}\n" +
            f"Platform: {self.platform_choice}\n" +
            f"Description: {self.game_description}\n")

        channel_prop = DatabaseFacade.get_property(JOIN_GAME_CHANNEL)
        channel_name = channel_prop.value

        channel: TextChannel = find(
            lambda channel: channel.name == channel_name,
            self.guild_reference.channels)

        game_message = await channel.send(embed=game_summary_embed)

        DatabaseFacade.update_game(self.game.id,
                                   message_did=str(game_message.id))
        await game_message.add_reaction(UNICODE_FORWARD_ARROW)
Ejemplo n.º 2
0
async def leave(context: commands.Context, *args):
    channel_did = str(context.channel.id)
    game: Game = DatabaseFacade.get_game_by_channel_did(channel_did)
    if game is not None:
        if len(args) > 0:
            await context.send("Usage: !leave")
            return
        player_did = str(context.author.id)
        leaver = DatabaseFacade.get_player_by_did(player_did=player_did)

        if leaver.id == game.creator_id:
            await context.send("The creator cannot leave the game; use !delete"
                               " to remove the game instead.")
            return

        DatabaseFacade.remove_player_from_game(game.id, leaver)

        game_channel_id: int = int(game.channel_id)

        game_channel: TextChannel = bot.get_channel(game_channel_id)

        await game_channel.set_permissions(context.author, read_messages=False)

        print("leave functioned properly so far....")

        await context.send(
            content=f"User {context.author.name} has left the game")

        print("sent message on channel", context.channel.id)

        return
Ejemplo n.º 3
0
    async def game_channel_message(self, channel):
        game_summary_embed = Embed()

        game_summary_embed.title = ("-" * 20) + f"Game {self.game.id} Summary" \
            + ("-" * 20)

        max_players = self.game.teams[0].size
        game_summary_embed.description = (
            f"Created by: {self.user.mention}\n" + f"Mode: {self.mode_str} " +
            (f"({max_players})" if self.mode_str == "FFA" else "") + "\n" +
            f"Platform: {self.platform_choice}\n" +
            f"Description: {self.game_description}\n" +
            ("" if self.game.mode.name == "FFA" or self.game.randomize_teams
             else f"React to join a team (team 0 = no team)"))

        game_summary_msg = await channel.send(embed=game_summary_embed)

        DatabaseFacade.update_game(self.game.id,
                                   game_message_did=str(game_summary_msg.id))

        team_emoji = [
            UNICODE_0, UNICODE_1, UNICODE_2, UNICODE_3, UNICODE_4, UNICODE_5,
            UNICODE_6
        ]

        if self.game.randomize_teams:
            pass
        else:
            for team in self.game.teams:
                emoji = team_emoji[team.number]
                await game_summary_msg.add_reaction(emoji)
Ejemplo n.º 4
0
    async def user_confirm_handler(self, message: Message):
        reactions = MessageSequence.get_reactions_added(message)

        # case should never trigger due to requires_reaction
        if len(reactions) == 0:
            print("No reaction provided to message")
            return
        elif len(reactions) > 1:
            print("ERROR: Too many reactions added")
            return
        else:
            emoji: Emoji = reactions[0].emoji

            if emoji == UNICODE_1:
                # TODO: Add game message in public channel, and pass instead of
                #  empty string
                target_mode = None
                for mode in GameMode:
                    if mode.value[3] == self.mode_str:
                        target_mode = mode

                if target_mode is not None:
                    print(f"found a mode with modestring {self.mode_str}")
                    if target_mode.value[3] == "FFA":
                        self.game = DatabaseFacade.add_game(
                            str(self.user.id),
                            self.platform_choice,
                            target_mode.value,
                            "",
                            max_size=self.team_size)
                    else:
                        self.game = DatabaseFacade.add_game(
                            str(self.user.id),
                            self.platform_choice,
                            target_mode.value,
                            "",
                        )

                    await self.create_game_channel()

                    await self.game_public_message()

                else:
                    print(f"Unrecognized mode: {self.mode_str}")
                    return None

            elif emoji == UNICODE_2:

                # wipe all data collected
                self.starter = self.initial_message
                self.platform_choice: str = None
                self.team_count: int = None
                self.team_size: int = None
                self.mode_str: str = None
                self.game_description: str = None
                self.game: Game = None

                # reset to first message
                await self.initial_message()
Ejemplo n.º 5
0
async def prop(context: commands.Context,
               prop_name: str,
               prop_value: str = None):
    if prop_value is None:
        prop = DatabaseFacade.get_property(prop_name)
        if prop is not None:
            await context.send(content=f"Value: {prop.value}")
        else:
            await context.send(f"Property undefined: {prop_name}")
    else:
        DatabaseFacade.set_property(prop_name, prop_value)
        await context.send(content=f"set property {prop_name} to {prop_value}")
Ejemplo n.º 6
0
async def showgame(context: commands.Context, game_id: str):
    try:
        game_id = int(game_id)
    except ValueError:
        await context.send("usage: !game <game_id>")
        return

    retrieved_game = DatabaseFacade.get_game_by_id(game_id)
    await context.send("Game loaded:\n" + str(retrieved_game))
    return
Ejemplo n.º 7
0
    async def create_game_channel(self):
        game_category = DatabaseFacade.get_property(
            GAME_CATEGORY_PROPERTY_NAME)

        print(f"Searching for category: {game_category.value}")

        game_id: str = str(self.game.id)
        game_category = find(lambda cat: cat.name == game_category.value,
                             self.guild_reference.categories)

        print("Game categories: ")
        for category in self.guild_reference.categories:
            print(category.name)

        channel: TextChannel = await self.guild_reference.create_text_channel(
            name=f"Game-{game_id}", category=game_category)

        DatabaseFacade.update_game(self.game.id, channel_did=str(channel.id))

        await channel.set_permissions(self.user, read_messages=True)
        await self.game_channel_message(channel)
Ejemplo n.º 8
0
async def delete(context: commands.Context, *args):
    channel_did = str(context.channel.id)
    game: Game = DatabaseFacade.get_game_by_channel_did(channel_did)
    if game is not None:
        if len(args) > 0:
            await context.send("usage: !delete")
            return
        else:

            caller_did = str(context.author.id)
            caller = DatabaseFacade.get_player_by_did(caller_did)

            join_game_message_id = int(game.message_did)
            print(f"looking for join message with id {join_game_message_id}")

            join_game_channel_prop = DatabaseFacade.get_property(
                JOIN_GAME_CHANNEL)

            join_game_channel = discord.utils.find(
                lambda channel: channel.name == join_game_channel_prop.value,
                context.guild.text_channels)
            print(f"got join channel with name {join_game_channel.name}")

            join_game_message = await join_game_channel.fetch_message(
                join_game_message_id)

            if caller.id != game.creator_id:
                await context.send("Only the creator can delete a game")
                return

            DatabaseFacade.delete_game_by_id(game.id)

            print(f"deleting channel {context.channel.name}")
            await context.channel.delete()

            print(f"join_game_message has id")
            await join_game_message.delete()
            return
Ejemplo n.º 9
0
async def kick(context: commands.Context, mentioned: User, *args):
    channel_did = str(context.channel.id)
    game: Game = DatabaseFacade.get_game_by_channel_did(channel_did)
    if game is not None:
        if len(args) > 0:
            await context.send("usage: !kick <@user>\nCan only be used by the"
                               " creator of the game")
            return
        else:

            caller_did = str(context.author.id)
            caller = DatabaseFacade.get_player_by_did(caller_did)

            if caller.id != game.creator_id:
                await context.send("!kick can only be used by the creator.")
                return

            mentioned_did = str(mentioned.id)
            kicked = DatabaseFacade.get_player_by_did(mentioned_did)

            if kicked.id == game.creator.id:
                await context.send("!kick cannot be used to remove the creator"
                                   )
                return

            success = DatabaseFacade.remove_player_from_game(game.id, kicked)

            if not success:
                await context.send(
                    f"Cannot kick user {mentioned.name}; user is not in game")
                return

            game_channel: TextChannel = bot.get_channel(context.channel.id)

            await game_channel.set_permissions(mentioned, read_messages=False)

            await context.send(
                content=f"User {mentioned.name} has been kicked.")
Ejemplo n.º 10
0
async def teams(context: commands.Context):
    game: Game = DatabaseFacade.get_game_by_channel_did(str(
        context.channel.id))
    if game is not None:
        reply = f"#######Game {game.id}#######\n"
        if len(game.teams) == 1:
            reply += "FFA Games do not have teams"
        elif game.randomize_teams:
            reply += (f"Teams will be randomized when the game is started (use"
                      f" {bot.command_prefix}start to start it)")
        else:
            for team in game.teams[1:]:
                if team.number == 0:
                    reply += "Undecided:\n"
                else:
                    reply += f"Team {team.number}:\n"

                for player in team.players:
                    user: User = await bot.fetch_user(int(player.did))
                    reply += f" - {user.display_name}\n"

        await context.send(reply)
    else:
        await context.send("This channel no longer has an associated game")
Ejemplo n.º 11
0
async def start(context: commands.Context):
    game: Game = DatabaseFacade.get_game_by_channel_did(str(
        context.channel.id))
    if game.player_number != game.teams[0].size:
        await context.send("Cannot start game until game is full "
                           f"(current: {game.player_number}, "
                           f"needed: {game.teams[0].size})")
        # return
    elif game is not None:
        DatabaseFacade.start_game(game.id)

    start_embed = Embed()
    start_embed.title = "Starting game..."
    start_embed.description = (f"Game begun at {game.started_at} with teams:")
    print("counting teams: ", len(game.teams))

    if game.teams_available:
        if game.randomize_teams:
            for team in game.teams[1:]:
                empty_slots = team.size - len(team.players)
                if empty_slots > len(game.teams[0].players):
                    await context.send(
                        f"ERROR: Insufficient number of players "
                        f"to fill teams; ran out on team "
                        f"{team.number}")
                players = random.sample(game.teams[0].players, k=empty_slots)
                for player in players:
                    print(f"adding player {player.id} to team {team.number}")
                    DatabaseFacade.add_player_to_team(game.id, team.number,
                                                      player)
        else:
            if sum([len(team.players)
                    for team in game.teams[1:]]) < len(game.teams[0]):
                await context.send(
                    "All players must be in a team before game can"
                    " begin")
                return

        for team in game.teams[1:]:
            print("Players:", team.players, ":", int(team.players[0].did))
            player_names = [
                await bot.fetch_user(int(player.did)).name
                for player in team.players
            ]

            if len(player_names) > 0:
                player_string = "\n".join(player_names)
            else:
                player_string = "(no players)"
            start_embed.add_field(name=f"Team {team.number}",
                                  value=f"{player_string}",
                                  inline=False)
    else:
        player_names = [
            await bot.fetch_user(int(player.did)).name
            for player in game.teams[0].players
        ]
        if len(player_names) > 0:
            player_string = "\n".join(player_names)
        else:
            player_string = "(no players)"
        start_embed.add_field(name="Randomized teams",
                              value=f"Players:\n {player_string}",
                              inline=False)

    await context.send(embed=start_embed)
Ejemplo n.º 12
0
async def on_raw_reaction_add(payload: discord.RawReactionActionEvent):
    user = bot.get_user(payload.user_id)

    # DEBUG output, enable if needed.
    # print("RAW reaction received")
    # print("From user:"******"(" + str(payload.user_id) + ")")
    # print("reaction:", payload.emoji)
    # print("emoji name:", payload.emoji.name)
    # print("emoji id:", payload.emoji.id)
    # print(payload.emoji.name, "?=", UNICODE_1, ":", payload.emoji.name == UNICODE_1)
    # print("payload channel: {}".format(payload.channel_id))

    guild: Guild = bot.get_guild(payload.guild_id)

    # Looks like all possible send targets inherit from Messageable, and EITHER
    # GuildChannel or PrivateChannel (all 3 of which are in discord.abc)
    channel: discord.TextChannel = bot.get_channel(payload.channel_id)
    print(f"channel: {channel}")
    message: Message = await channel.fetch_message(payload.message_id)

    if not user.bot:

        create_game_prop = DatabaseFacade.get_property(
            property_name=CREATE_GAME_CHANNEL)

        # if the above evaluated true, then channel should have a name
        # attribute at this point.
        create_game_channel_name = create_game_prop.value

        join_game_prop = DatabaseFacade.get_property(
            property_name=JOIN_GAME_CHANNEL)

        join_game_channel_name = join_game_prop.value

        if type(channel) == DMChannel:
            print("checked as DMChannel")
            message_sequence: MessageSequenceTest \
                = message_states.get_user_sequence(user)

            # if the user has a sequence with the bot already...
            if message_sequence is not None:
                # pass the message along to the sequence's handler
                await message_sequence.run_next_handler(message)
                return
            # otherwise... just ignore them I think?
            else:
                return
        # this is the message the bot put in the create a game channel
        elif channel.name == create_game_channel_name:
            print("checked as a create game message")
            reactions = message.reactions
            for reaction in reactions:
                try:
                    await message.remove_reaction(reaction.emoji, user)
                except Exception as e:
                    print(f"ERROR: While removing reaction, got exception of "
                          f"type {type(e)}")

            new_game_sequence = NewGameSequence(user, guild)
            await message_states.add_user_sequence(user, new_game_sequence)
            await new_game_sequence.start_sequence()
        elif channel.name == join_game_channel_name:
            print("checked as a join game message")
            # reaction was added on a message in the games channel
            game: Game = DatabaseFacade.get_game_by_message_did(str(
                message.id))

            user_as_player = DatabaseFacade.get_player_by_did(str(user.id))
            if game is not None:
                DatabaseFacade.add_player_to_game(game.id, user_as_player)
                game_channel: TextChannel = bot.get_channel(
                    int(game.channel_id))
                await game_channel.set_permissions(user, read_messages=True)

                if game.is_full():
                    print("game is full, clearing all messages")
                    await message.clear_reactions()
            else:
                print(f"Game not found with message_did: {message.id}")

        # this should become a check against all of the game's private channel
        # messages, which I'll probably build team swapping into
        elif channel.category.name == DatabaseFacade.get_property(
                GAME_CATEGORY_PROPERTY_NAME).value:
            print("CHECKED as a channel in the game category")
            if message.author.bot:
                game: Game = DatabaseFacade.get_game_by_game_message_did(
                    str(message.id))

                user_as_player = DatabaseFacade.get_player_by_did(str(user.id))

                emoji_name = payload.emoji.name
                print("")
                if emoji_name == UNICODE_0:
                    team_number = 0
                elif emoji_name == UNICODE_1:
                    team_number = 1
                elif emoji_name == UNICODE_2:
                    team_number = 2
                elif emoji_name == UNICODE_3:
                    team_number = 3
                elif emoji_name == UNICODE_4:
                    team_number = 4
                elif emoji_name == UNICODE_5:
                    team_number = 5
                elif emoji_name == UNICODE_6:
                    team_number = 6
                else:
                    print(f"React with bad emoji: {emoji_name}")
                    try:
                        await message.remove_reaction(payload.emoji, user)
                    except Exception as e:
                        print(
                            f"ERROR: While removing reaction, got exception of "
                            f"type {type(e)}")

                    return

                if DatabaseFacade.add_player_to_team(game.id, team_number,
                                                     user_as_player):
                    await channel.send(
                        content=f"{user.display_name} joined team "
                        f"{team_number}")
                else:
                    await channel.send(
                        content=f"Could not add {user.display_name} to team "
                        f"{team_number}: team is full or does not exist.")

                try:
                    await message.remove_reaction(payload.emoji, user)
                except Exception as e:
                    print(f"ERROR: While removing reaction, got exception of "
                          f"type {type(e)}")

        else:
            print("CHECKED as other message")
Ejemplo n.º 13
0
bot = commands.Bot(command_prefix='!', intent=intent)

# message sequence related code
message_states = UserMessageStates()

CONNECTION_STRING = os.getenv("DATABASE_URL")
BOT_TOKEN = os.getenv("TOKEN")

# some command line args provided
if len(sys.argv) > 1:

    # setting up the database connection string
    if len(sys.argv) == 3:
        BOT_TOKEN = sys.argv[1]
        database = DatabaseFacade(connection_string=sys.argv[2])
    else:
        print(
            "Incorrect number of args; requires connection string in position 2"
        )
        exit()
# no command line args provided
elif len(sys.argv) == 1:

    # establish that a connection string is available
    if CONNECTION_STRING is None:
        # getenv failed
        print(
            "No command line args, and connection string environment variable"
            " missing")
        exit()