Esempio n. 1
0
    def __init__(
        self,
        user: discord.User,
        future: asyncio.Future[ActiveAdventureAction],
        possible_actions: set[ActiveAdventureAction],
        *args,
        **kwargs,
    ):
        super().__init__(*args, **kwargs)

        self.user = user
        self.future = future

        north = Button(
            style=ButtonStyle.primary,
            label=_("North"),
            disabled=ActiveAdventureAction.MoveNorth not in possible_actions,
            emoji="\U00002b06",
            row=0,
        )
        east = Button(
            style=ButtonStyle.primary,
            label=_("East"),
            disabled=ActiveAdventureAction.MoveEast not in possible_actions,
            emoji="\U000027a1",
            row=0,
        )
        south = Button(
            style=ButtonStyle.primary,
            label=_("South"),
            disabled=ActiveAdventureAction.MoveSouth not in possible_actions,
            emoji="\U00002b07",
            row=0,
        )
        west = Button(
            style=ButtonStyle.primary,
            label=_("West"),
            disabled=ActiveAdventureAction.MoveWest not in possible_actions,
            emoji="\U00002b05",
            row=0,
        )

        attack = Button(
            style=ButtonStyle.secondary,
            label=_("Attack"),
            disabled=ActiveAdventureAction.AttackEnemy not in possible_actions,
            emoji="\U00002694",
            row=1,
        )
        defend = Button(
            style=ButtonStyle.secondary,
            label=_("Defend"),
            disabled=ActiveAdventureAction.Defend not in possible_actions,
            emoji="\U0001f6e1",
            row=1,
        )
        recover = Button(
            style=ButtonStyle.secondary,
            label=_("Recover"),
            disabled=ActiveAdventureAction.Recover not in possible_actions,
            emoji="\U00002764",
            row=1,
        )

        north.callback = partial(self.handle, action=ActiveAdventureAction.MoveNorth)
        east.callback = partial(self.handle, action=ActiveAdventureAction.MoveEast)
        south.callback = partial(self.handle, action=ActiveAdventureAction.MoveSouth)
        west.callback = partial(self.handle, action=ActiveAdventureAction.MoveWest)
        attack.callback = partial(self.handle, action=ActiveAdventureAction.AttackEnemy)
        defend.callback = partial(self.handle, action=ActiveAdventureAction.Defend)
        recover.callback = partial(self.handle, action=ActiveAdventureAction.Recover)

        self.add_item(north)
        self.add_item(east)
        self.add_item(south)
        self.add_item(west)
        self.add_item(attack)
        self.add_item(defend)
        self.add_item(recover)
Esempio n. 2
0
    async def battle(self,
                     ctx,
                     money: IntGreaterThan(-1) = 0,
                     enemy: discord.Member = None):
        _("""`[money]` - A whole number that can be 0 or greater; defaults to 0
            `[enemy]` - A user who has a profile; defaults to anyone

            Fight against another player while betting money.
            To decide the fight, the players' items, race and class bonuses and an additional number from 1 to 7 are evaluated, this serves as a way to give players with lower stats a chance at winning.

            The money is removed from both players at the start of the battle. Once a winner has been decided, they will receive their money, plus the enemy's money.
            The battle lasts 30 seconds, after which the winner and loser will be mentioned.

            If both players' stats + random number are the same, the winner is decided at random.
            The battle's winner will receive a PvP win, which shows on their profile.
            (This command has a cooldown of 90 seconds.)""")
        if enemy == ctx.author:
            return await ctx.send(_("You can't battle yourself."))
        if ctx.character_data["money"] < money:
            return await ctx.send(_("You are too poor."))

        await self.bot.pool.execute(
            'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;',
            money,
            ctx.author.id,
        )

        if not enemy:
            text = _(
                "{author} seeks a battle! The price is **${money}**.").format(
                    author=ctx.author.mention, money=money)
        else:
            text = _(
                "{author} seeks a battle with {enemy}! The price is **${money}**."
            ).format(author=ctx.author.mention,
                     enemy=enemy.mention,
                     money=money)

        async def check(user: discord.User) -> bool:
            return await has_money(self.bot, user.id, money)

        future = asyncio.Future()
        view = SingleJoinView(
            future,
            Button(
                style=ButtonStyle.primary,
                label=_("Join the battle!"),
                emoji="\U00002694",
            ),
            allowed=enemy,
            prohibited=ctx.author,
            timeout=60,
            check=check,
            check_fail_message=_(
                "You don't have enough money to join the battle."),
        )

        await ctx.send(text, view=view)

        try:
            enemy_ = await future
        except asyncio.TimeoutError:
            await self.bot.reset_cooldown(ctx)
            await self.bot.pool.execute(
                'UPDATE profile SET "money"="money"+$1 WHERE "user"=$2;',
                money,
                ctx.author.id,
            )
            return await ctx.send(
                _("Noone wanted to join your battle, {author}!").format(
                    author=ctx.author.mention))

        await self.bot.pool.execute(
            'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;', money,
            enemy_.id)

        await ctx.send(
            _("Battle **{author}** vs **{enemy}** started! 30 seconds of fighting"
              " will now start!").format(author=ctx.disp,
                                         enemy=enemy_.display_name))

        stats = [
            sum(await self.bot.get_damage_armor_for(ctx.author)) +
            random.randint(1, 7),
            sum(await self.bot.get_damage_armor_for(enemy_)) +
            random.randint(1, 7),
        ]
        players = [ctx.author, enemy_]
        if stats[0] == stats[1]:
            winner = random.choice(players)
        else:
            winner = players[stats.index(max(stats))]
        looser = players[players.index(winner) - 1]

        await asyncio.sleep(30)

        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                'UPDATE profile SET "pvpwins"="pvpwins"+1, "money"="money"+$1 WHERE'
                ' "user"=$2;',
                money * 2,
                winner.id,
            )
            await self.bot.log_transaction(
                ctx,
                from_=looser.id,
                to=winner.id,
                subject="money",
                data={"Amount": money},
                conn=conn,
            )
        await ctx.send(
            _("{winner} won the battle vs {looser}! Congratulations!").format(
                winner=winner.mention, looser=looser.mention))
Esempio n. 3
0
    async def werewolf(
        self,
        ctx,
        mode: WerewolfMode | None = "Classic",
        speed: str.title = "Normal",
        min_players: IntGreaterThan(1) = None,
    ):
        _("""
            `[mode]` - The mode to play, see below for available options. (optional and defaults to Classic)
            `[speed]` - The game speed to play, see below available options. (optional and defaults to Normal)
            `[min_players]` - The minimum players needed to play. (optional and defaults depending on the game mode: Classic: 5, Imbalanced: 5, Huntergame: 8, Villagergame: 5, Valentines: 8, IdleRPG: 5)

            Starts a game of Werewolf. Find the werewolves, before they find you!
            Your goal to win is indicated on the role you have.
            **Game modes:** `Classic` (default), `Imbalanced`, `Huntergame`, `Villagergame`, `Valentines`, `IdleRPG`. Use `{prefix}ww modes` for detailed info.
            **Game speeds** (in seconds): `Normal`: 60 (default), `Extended`: 90, `Fast`: 45, `Blitz`: 30. Use `{prefix}ww speeds` for detailed info.
            **Aliases:**
            `ww`
            **Examples:**
            `{prefix}ww Blitz` for Classic mode on Blitz speed
            `{prefix}ww Imbalanced` for Imbalanced mode on Normal speed
            `{prefix}ww Valentines Extended` for Valentines mode on Extended speed
            `{prefix}ww Huntergame Fast` for Huntergame mode on Fast speed
            """)

        # TODO:
        # Bizarro: Roles are flipped.
        # Random: Roles are reassigned randomly every night.
        # Zombie (Classic-based, another team) - There's a chance that a random player will be randomly resurrected as Zombie and they can devour any villagers or werewolves with the other zombies.

        if self.games.get(ctx.channel.id):
            return await ctx.send(_("There is already a game in here!"))

        game_modes = [
            "Classic",
            "Imbalanced",
            "Huntergame",
            "Villagergame",
            "Valentines",
            "Idlerpg",
        ]

        minimum_players = {
            "Classic": 5,
            "Imbalanced": 5,
            "Huntergame": 8,
            "Villagergame": 5,
            "Valentines": 8,
            "IdleRPG": 5,
        }

        game_speeds = ["Normal", "Extended", "Fast", "Blitz"]

        if mode not in game_modes:
            return await ctx.send(
                _("Invalid game mode. Use `{prefix}help ww` to get help on this"
                  " command.").format(prefix=ctx.prefix))
        elif mode == "Idlerpg":
            mode = "IdleRPG"

        if speed not in game_speeds:
            return await ctx.send(
                _("Invalid game speed. Use `{prefix}help ww` to get help on this"
                  " command.").format(prefix=ctx.prefix))

        if not min_players:
            # Get default of Classic mode if unexpected value happened
            min_players = minimum_players.get(mode, 5)

        self.games[ctx.channel.id] = "forming"

        additional_text = _(
            "Use `{prefix}help ww` to get help on werewolf commands. Use `{prefix}ww"
            " roles` to view descriptions of game roles and their goals to win. Use"
            " `{prefix}ww modes` and `{prefix}ww speeds` to see info about available"
            " game modes and speeds.").format(prefix=ctx.prefix)

        mode_emojis = {"Huntergame": "🔫", "Valentines": "💕"}
        mode_emoji = mode_emojis.get(mode, "")

        if (self.bot.config.game.official_tournament_channel_id
                and ctx.channel.id
                == self.bot.config.game.official_tournament_channel_id):
            # TODO: Determine threshold players when wolves can kill 2 villagers per night in mass-games
            view = JoinView(
                Button(style=ButtonStyle.primary,
                       label=_("Join the Werewolf game!")),
                message=_("You joined the Werewolf game."),
                timeout=60 * 10,
            )
            text = _(
                "**{author} started a mass-game of Werewolf!**\n**{mode}** mode on"
                " **{speed}** speed. You can join in the next 10 minutes."
                " **Minimum of {min_players} players are required.**")

            await ctx.send(
                embed=discord.Embed(
                    title=_("Werewolf Mass-game!"),
                    description=text.format(
                        author=ctx.author.mention,
                        mode=mode_emoji + mode,
                        speed=speed,
                        min_players=min_players,
                    ),
                    colour=self.bot.config.game.primary_colour,
                ).set_author(name=str(ctx.author),
                             icon_url=ctx.author.display_avatar.url).add_field(
                                 name=_("New to Werewolf?"),
                                 value=additional_text),
                view=view,
            )

            await asyncio.sleep(60 * 10)

            view.stop()
            players = list(view.joined)
        else:
            view = JoinView(
                Button(style=ButtonStyle.primary,
                       label=_("Join the Werewolf game!")),
                message=_("You joined the Werewolf game."),
                timeout=120,
            )
            view.joined.add(ctx.author)
            title = _("Werewolf game!")
            text = _(
                "**{author} started a game of Werewolf!**\n**{mode}** mode on"
                " **{speed}** speed. Minimum of"
                " **{min_players}** players are required. Starting in 2 minutes."
            )

            try:
                await ctx.send(
                    embed=discord.Embed(
                        title=title,
                        description=text.format(
                            author=ctx.author.mention,
                            mode=mode_emoji + mode,
                            speed=speed,
                            min_players=min_players,
                        ),
                        colour=self.bot.config.game.primary_colour,
                    ).set_author(
                        name=str(ctx.author),
                        icon_url=ctx.author.display_avatar.url).add_field(
                            name=_("New to Werewolf?"), value=additional_text),
                    view=view,
                )
            except discord.errors.Forbidden:
                del self.games[ctx.channel.id]
                return await ctx.send(
                    _("An error happened during the Werewolf. Missing Permission:"
                      " `Embed Links` . Please check the **Edit Channel >"
                      " Permissions** and **Server Settings > Roles** then try again!"
                      ))

            await asyncio.sleep(60 * 2)

            view.stop()
            players = list(view.joined)

        if len(players) < min_players:
            del self.games[ctx.channel.id]
            await self.bot.reset_cooldown(ctx)
            return await ctx.send(
                _("Not enough players joined... We didn't reach the minimum"
                  " {min_players} players. �").format(
                      min_players=min_players))

        players = random.shuffle(players)
        try:
            game = Game(ctx, players, mode, speed)
            self.games[ctx.channel.id] = game
            await game.run()
        except Exception as e:
            await ctx.send(
                _("An error happened during the Werewolf. Please try again!"))
            del self.games[ctx.channel.id]
            raise e

        try:
            del self.games[ctx.channel.id]
        except KeyError:  # got stuck in between
            pass
Esempio n. 4
0
    async def raidbattle(self,
                         ctx,
                         money: IntGreaterThan(-1) = 0,
                         enemy: discord.Member = None):
        _("""`[money]` - A whole number that can be 0 or greater; defaults to 0
            `[enemy]` - A user who has a profile; defaults to anyone

            Fight against another player while betting money.
            To decide the players' stats, their items, race and class bonuses and raidstats are evaluated.

            The money is removed from both players at the start of the battle. Once a winner has been decided, they will receive their money, plus the enemy's money.
            The battle is divided into rounds, in which a player attacks. The first round's attacker is chosen randomly, all other rounds the attacker is the last round's defender.

            The battle ends if one player's HP drops to 0 (winner decided), or if 5 minutes after the battle started pass (tie).
            In case of a tie, both players will get their money back.

            The battle's winner will receive a PvP win, which shows on their profile.
            (This command has a cooldown of 5 minutes)""")
        if enemy == ctx.author:
            return await ctx.send(_("You can't battle yourself."))
        if ctx.character_data["money"] < money:
            return await ctx.send(_("You are too poor."))

        await self.bot.pool.execute(
            'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;',
            money,
            ctx.author.id,
        )

        if not enemy:
            text = _("{author} seeks a raidbattle! The price is **${money}**."
                     ).format(author=ctx.author.mention, money=money)
        else:
            text = _(
                "{author} seeks a raidbattle with {enemy}! The price is **${money}**."
            ).format(author=ctx.author.mention,
                     enemy=enemy.mention,
                     money=money)

        async def check(user: discord.User) -> bool:
            return await has_money(self.bot, user.id, money)

        future = asyncio.Future()
        view = SingleJoinView(
            future,
            Button(
                style=ButtonStyle.primary,
                label=_("Join the raidbattle!"),
                emoji="\U00002694",
            ),
            allowed=enemy,
            prohibited=ctx.author,
            timeout=60,
            check=check,
            check_fail_message=_(
                "You don't have enough money to join the raidbattle."),
        )

        await ctx.send(text, view=view)

        try:
            enemy_ = await future
        except asyncio.TimeoutError:
            await self.bot.reset_cooldown(ctx)
            await self.bot.pool.execute(
                'UPDATE profile SET "money"="money"+$1 WHERE "user"=$2;',
                money,
                ctx.author.id,
            )
            return await ctx.send(
                _("Noone wanted to join your raidbattle, {author}!").format(
                    author=ctx.author.mention))

        await self.bot.pool.execute(
            'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;', money,
            enemy_.id)

        players = []

        async with self.bot.pool.acquire() as conn:
            for player in (ctx.author, enemy_):
                dmg, deff = await self.bot.get_raidstats(player, conn=conn)
                u = {"user": player, "hp": 250, "armor": deff, "damage": dmg}
                players.append(u)

        # players[0] is the author, players[1] is the enemy

        battle_log = deque(
            [(
                0,
                _("Raidbattle {p1} vs. {p2} started!").format(
                    p1=players[0]["user"], p2=players[1]["user"]),
            )],
            maxlen=3,
        )

        embed = discord.Embed(description=battle_log[0][1],
                              color=self.bot.config.game.primary_colour)

        log_message = await ctx.send(
            embed=embed)  # we'll edit this message later to avoid spam
        await asyncio.sleep(4)

        start = datetime.datetime.utcnow()
        attacker, defender = random.sample(
            players, k=2
        )  # decide a random attacker and defender for the first iteration

        while (players[0]["hp"] > 0 and players[1]["hp"] > 0
               and datetime.datetime.utcnow() <
               start + datetime.timedelta(minutes=5)):
            # this is where the fun begins
            dmg = (attacker["damage"] + Decimal(random.randint(0, 100)) -
                   defender["armor"])
            dmg = 1 if dmg <= 0 else dmg  # make sure no negative damage happens
            defender["hp"] -= dmg
            if defender["hp"] < 0:
                defender["hp"] = 0
            battle_log.append((
                battle_log[-1][0] + 1,
                _("{attacker} attacks! {defender} takes **{dmg}HP** damage.").
                format(
                    attacker=attacker["user"].mention,
                    defender=defender["user"].mention,
                    dmg=dmg,
                ),
            ))

            embed = discord.Embed(
                description=_(
                    "{p1} - {hp1} HP left\n{p2} - {hp2} HP left").format(
                        p1=players[0]["user"],
                        hp1=players[0]["hp"],
                        p2=players[1]["user"],
                        hp2=players[1]["hp"],
                    ),
                color=self.bot.config.game.primary_colour,
            )

            for line in battle_log:
                embed.add_field(
                    name=_("Action #{number}").format(number=line[0]),
                    value=line[1])

            await log_message.edit(embed=embed)
            await asyncio.sleep(4)
            attacker, defender = defender, attacker  # switch places

        players = sorted(players, key=lambda x: x["hp"])
        winner = players[1]["user"]
        looser = players[0]["user"]

        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                'UPDATE profile SET "money"="money"+$1, "pvpwins"="pvpwins"+1 WHERE'
                ' "user"=$2;',
                money * 2,
                winner.id,
            )
            await self.bot.log_transaction(
                ctx,
                from_=looser.id,
                to=winner.id,
                subject="money",
                data={"Amount": money},
                conn=conn,
            )
        await ctx.send(
            _("{p1} won the raidbattle vs {p2}! Congratulations!").format(
                p1=winner.mention, p2=looser.mention))
Esempio n. 5
0
    async def activebattle(self,
                           ctx,
                           money: IntGreaterThan(-1) = 0,
                           enemy: discord.Member = None):
        _("""`[money]` - A whole number that can be 0 or greater; defaults to 0
            `[enemy]` - A user who has a profile; defaults to anyone

            Fight against another player while betting money.
            To decide players' stats, their items, race and class bonuses are evaluated.

            The money is removed from both players at the start of the battle. Once a winner has been decided, they will receive their money, plus the enemy's money.
            The battle takes place in rounds. Each round, both players have to choose their move using the reactions.
            Players can attack (тЪФя╕П), defend (ЁЯЫбя╕П) or recover HP (тЭдя╕П).

            The battle ends if one player's HP drops to 0 (winner decided), or a player does not move (forfeit).
            In case of a forfeit, neither of the players will get their money back.

            The battle's winner will receive a PvP win, which shows on their profile.
            (This command has a cooldown of 10 minutes.)""")
        if enemy == ctx.author:
            return await ctx.send(_("You can't battle yourself."))
        if ctx.character_data["money"] < money:
            return await ctx.send(_("You are too poor."))

        await self.bot.pool.execute(
            'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;',
            money,
            ctx.author.id,
        )

        if not enemy:
            text = _(
                "{author} seeks an active battle! The price is **${money}**."
            ).format(author=ctx.author.mention, money=money)
        else:
            text = _(
                "{author} seeks an active battle with {enemy}! The price is **${money}**."
            ).format(author=ctx.author.mention,
                     enemy=enemy.mention,
                     money=money)

        async def check(user: discord.User) -> bool:
            return await has_money(self.bot, user.id, money)

        future = asyncio.Future()
        view = SingleJoinView(
            future,
            Button(
                style=ButtonStyle.primary,
                label=_("Join the activebattle!"),
                emoji="\U00002694",
            ),
            allowed=enemy,
            prohibited=ctx.author,
            timeout=60,
            check=check,
            check_fail_message=_(
                "You don't have enough money to join the activebattle."),
        )

        await ctx.send(text, view=view)

        try:
            enemy_ = await future
        except asyncio.TimeoutError:
            await self.bot.reset_cooldown(ctx)
            await self.bot.pool.execute(
                'UPDATE profile SET "money"="money"+$1 WHERE "user"=$2;',
                money,
                ctx.author.id,
            )
            return await ctx.send(
                _("Noone wanted to join your activebattle, {author}!").format(
                    author=ctx.author.mention))

        players = {
            ctx.author: {
                "hp": 0,
                "damage": 0,
                "defense": 0,
                "lastmove": "",
                "action": None,
            },
            enemy_: {
                "hp": 0,
                "damage": 0,
                "defense": 0,
                "lastmove": "",
                "action": None,
            },
        }

        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;',
                money,
                enemy_.id,
            )

            for p in players:
                classes = [
                    class_from_string(i) for i in await conn.fetchval(
                        'SELECT class FROM profile WHERE "user"=$1;', p.id)
                ]
                if any(c.in_class_line(Ranger) for c in classes if c):
                    players[p]["hp"] = 120
                else:
                    players[p]["hp"] = 100

                attack, defense = await self.bot.get_damage_armor_for(
                    p, conn=conn)
                players[p]["damage"] = int(attack)
                players[p]["defense"] = int(defense)

        moves = {
            "\U00002694": "attack",
            "\U0001f6e1": "defend",
            "\U00002764": "recover",
        }

        msg = await ctx.send(
            _("Battle {p1} vs {p2}").format(p1=ctx.author.mention,
                                            p2=enemy_.mention),
            embed=discord.Embed(
                title=_("Let the battle begin!"),
                color=self.bot.config.game.primary_colour,
            ),
        )

        def is_valid_move(r, u):
            return str(
                r.emoji) in moves and u in players and r.message.id == msg.id

        for emoji in moves:
            await msg.add_reaction(emoji)

        while players[ctx.author]["hp"] > 0 and players[enemy_]["hp"] > 0:
            await msg.edit(embed=discord.Embed(description=_(
                "{prevaction}\n{player1}: **{hp1}** HP\n{player2}: **{hp2}**"
                " HP\nReact to play.").format(
                    prevaction="\n".join(
                        [i["lastmove"] for i in players.values()]),
                    player1=ctx.author.mention,
                    player2=enemy_.mention,
                    hp1=players[ctx.author]["hp"],
                    hp2=players[enemy_]["hp"],
                )))
            players[
                ctx.author]["action"], players[enemy_]["action"] = None, None
            players[ctx.author]["lastmove"], players[enemy_]["lastmove"] = (
                _("{user} does nothing...").format(user=ctx.author.mention),
                _("{user} does nothing...").format(user=enemy_.mention),
            )

            while (not players[ctx.author]["action"]) or (
                    not players[enemy_]["action"]):
                try:
                    r, u = await self.bot.wait_for("reaction_add",
                                                   timeout=30,
                                                   check=is_valid_move)
                    try:
                        await msg.remove_reaction(r.emoji, u)
                    except discord.Forbidden:
                        pass
                except asyncio.TimeoutError:
                    await self.bot.reset_cooldown(ctx)
                    await self.bot.pool.execute(
                        'UPDATE profile SET "money"="money"+$1 WHERE "user"=$2 or "user"=$3;',
                        money,
                        ctx.author.id,
                        enemy_.id,
                    )
                    return await ctx.send(
                        _("Someone refused to move. Activebattle stopped."))
                if not players[u]["action"]:
                    players[u]["action"] = moves[str(r.emoji)]
                else:
                    playerlist = list(players.keys())
                    await ctx.send(
                        _("{user}, you already moved! Waiting for {other}'s move..."
                          ).format(
                              user=u.mention,
                              other=playerlist[1 -
                                               playerlist.index(u)].mention,
                          ))
            plz = list(players.keys())
            for idx, user in enumerate(plz):
                other = plz[1 - idx]
                if players[user]["action"] == "recover":
                    heal_hp = round(players[user]["damage"] * 0.25) or 1
                    players[user]["hp"] += heal_hp
                    players[user]["lastmove"] = _(
                        "{user} healed themselves for **{hp} HP**.").format(
                            user=user.mention, hp=heal_hp)
                elif (players[user]["action"] == "attack"
                      and players[other]["action"] != "defend"):
                    eff = random.choice([
                        players[user]["damage"],
                        int(players[user]["damage"] * 0.5),
                        int(players[user]["damage"] * 0.2),
                        int(players[user]["damage"] * 0.8),
                    ])
                    players[other]["hp"] -= eff
                    players[user]["lastmove"] = _(
                        "{user} hit {enemy} for **{eff}** damage.").format(
                            user=user.mention, enemy=other.mention, eff=eff)
                elif (players[user]["action"] == "attack"
                      and players[other]["action"] == "defend"):
                    eff = random.choice([
                        int(players[user]["damage"]),
                        int(players[user]["damage"] * 0.5),
                        int(players[user]["damage"] * 0.2),
                        int(players[user]["damage"] * 0.8),
                    ])
                    eff2 = random.choice([
                        int(players[other]["defense"]),
                        int(players[other]["defense"] * 0.5),
                        int(players[other]["defense"] * 0.2),
                        int(players[other]["defense"] * 0.8),
                    ])
                    if eff - eff2 > 0:
                        players[other]["hp"] -= eff - eff2
                        players[user]["lastmove"] = _(
                            "{user} hit {enemy} for **{eff}** damage.").format(
                                user=user.mention,
                                enemy=other.mention,
                                eff=eff - eff2)
                        players[other]["lastmove"] = _(
                            "{enemy} tried to defend, but failed.".format(
                                enemy=other.mention))

                    else:
                        players[user]["lastmove"] = _(
                            "{user}'s attack on {enemy} failed!").format(
                                user=user.mention, enemy=other.mention)
                        players[other]["lastmove"] = _(
                            "{enemy} blocked {user}'s attack.".format(
                                enemy=other.mention, user=user.mention))
                elif players[user]["action"] == players[other][
                        "action"] == "defend":
                    players[ctx.author]["lastmove"] = _(
                        "You both tried to defend.")
                    players[enemy_]["lastmove"] = _(
                        "It was not very effective...")

        if players[ctx.author]["hp"] <= 0 and players[enemy_]["hp"] <= 0:
            await self.bot.pool.execute(
                'UPDATE profile SET "money"="money"+$1 WHERE "user"=$2 or "user"=$3;',
                money,
                ctx.author.id,
                enemy_.id,
            )
            return await ctx.send(_("You both died!"))
        if players[ctx.author]["hp"] > players[enemy_]["hp"]:
            winner, looser = ctx.author, enemy_
        else:
            looser, winner = ctx.author, enemy_
        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                'UPDATE profile SET "pvpwins"="pvpwins"+1, "money"="money"+$1 WHERE'
                ' "user"=$2;',
                money * 2,
                winner.id,
            )
            await self.bot.log_transaction(
                ctx,
                from_=looser.id,
                to=winner.id,
                subject="money",
                data={"Amount": money},
                conn=conn,
            )
        await msg.edit(embed=discord.Embed(description=_(
            "{prevaction}\n{player1}: **{hp1}** HP\n{player2}: **{hp2}**"
            " HP\nReact to play.").format(
                prevaction="\n".join([i["lastmove"]
                                      for i in players.values()]),
                player1=ctx.author.mention,
                player2=enemy_.mention,
                hp1=players[ctx.author]["hp"],
                hp2=players[enemy_]["hp"],
            )))
        await ctx.send(
            _("{winner} won the active battle vs {looser}! Congratulations!").
            format(
                winner=winner.mention,
                looser=looser.mention,
            ))
Esempio n. 6
0
    def __init__(
        self,
        user: discord.User,
        future: asyncio.Future[BlackJackAction],
        *args,
        **kwargs,
    ) -> None:
        self.user = user
        self.future = future

        # Buttons to show
        self.hit = kwargs.pop("hit", False)
        self.stand = kwargs.pop("stand", False)
        self.double_down = kwargs.pop("double_down", False)
        self.change_deck = kwargs.pop("change_deck", False)
        self.split = kwargs.pop("split", False)

        super().__init__(*args, **kwargs)

        # Row 1 is primary actions
        hit = Button(
            style=ButtonStyle.primary,
            label="Hit",
            disabled=not self.hit,
            emoji="\U00002934",
            row=0,
        )
        stand = Button(
            style=ButtonStyle.primary,
            label="Stand",
            disabled=not self.stand,
            emoji="\U00002935",
            row=0,
        )
        double_down = Button(
            style=ButtonStyle.primary,
            label="Double Down",
            disabled=not self.double_down,
            emoji="\U000023ec",
            row=0,
        )

        # Row 2 is the two split actions
        change_deck = Button(
            style=ButtonStyle.secondary,
            label="Change Deck",
            disabled=not self.change_deck,
            emoji="\U0001F501",
            row=1,
        )
        split = Button(
            style=ButtonStyle.secondary,
            label="Split",
            disabled=not self.split,
            emoji="\U00002194",
            row=1,
        )

        hit.callback = partial(self.handle, action=BlackJackAction.Hit)
        stand.callback = partial(self.handle, action=BlackJackAction.Stand)
        double_down.callback = partial(self.handle, action=BlackJackAction.DoubleDown)
        change_deck.callback = partial(self.handle, action=BlackJackAction.ChangeDeck)
        split.callback = partial(self.handle, action=BlackJackAction.Split)

        self.add_item(hit)
        self.add_item(stand)
        self.add_item(double_down)
        self.add_item(change_deck)
        self.add_item(split)
Esempio n. 7
0
 async def btn_rebase(self, button: Button, interaction: Interaction):
     button.style = ButtonStyle.green
     await interaction.response.edit_message(view=self)
     self.stop()
     await self.get_commit_and_confirm("rebase")
Esempio n. 8
0
            await self.bot.reset_cooldown(ctx)
            return await ctx.send(_("You are too poor."))

        await self.bot.pool.execute(
            'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;',
            prize,
            ctx.author.id,
        )

        if (self.bot.config.game.official_tournament_channel_id
                and ctx.channel.id
                == self.bot.config.game.official_tournament_channel_id):
            view = JoinView(
                Button(
                    style=ButtonStyle.primary,
                    label="Join the tournament!",
                    emoji="\U00002694",
                ),
                message=_("You joined the tournament."),
                timeout=60 * 10,
            )
            await ctx.send(
                "A mass-tournament has been started. The tournament starts in 10 minutes! The"
                f" prize is **${prize}**!",
                view=view,
            )
            await asyncio.sleep(60 * 10)
            view.stop()
            participants = []
            async with self.bot.pool.acquire() as conn:
                for u in view.joined:
Esempio n. 9
0
    async def hungergames(self, ctx):
        _("""Starts the hunger games

            Players will be able to join via the :shallow_pan_of_food: emoji.
            The game is controlled via both random actions and possibly chosen actions.
            Players may choose an action if they get a direct message from the bot. If no action is chosen by the player, the bot chooses one for them.

            Not every player will get the opportunity to choose an action. Sometimes nobody gets to choose, so don't be discouraged. """
          )
        if self.games.get(ctx.channel.id):
            return await ctx.send(_("There is already a game in here!"))

        self.games[ctx.channel.id] = "forming"

        if ctx.channel.id == self.bot.config.game.official_tournament_channel_id:
            view = JoinView(
                Button(
                    style=ButtonStyle.primary,
                    label="Join the Hunger Games!",
                    emoji="\U0001f958",
                ),
                message=_("You joined the Hunger Games."),
                timeout=60 * 10,
            )
            await ctx.send(
                f"{ctx.author.mention} started a mass-game of Hunger Games!",
                view=view,
            )
            await asyncio.sleep(60 * 10)
            view.stop()
            players = list(view.joined)
        else:
            view = JoinView(
                Button(
                    style=ButtonStyle.primary,
                    label="Join the Hunger Games!",
                    emoji="\U0001f958",
                ),
                message=_("You joined the Hunger Games."),
                timeout=60 * 2,
            )
            view.joined.add(ctx.author)
            text = _("{author} started a game of Hunger Games!")
            await ctx.send(text.format(author=ctx.author.mention), view=view)
            await asyncio.sleep(60 * 2)
            view.stop()
            players = list(view.joined)

        if len(players) < 2:
            del self.games[ctx.channel.id]
            await self.bot.reset_cooldown(ctx)
            return await ctx.send(_("Not enough players joined..."))

        game = GameBase(ctx, players=players)
        self.games[ctx.channel.id] = game
        try:
            await game.main()
        except Exception as e:
            await ctx.send(
                _("An error happened during the hungergame. Please try again!")
            )
            raise e
        finally:
            try:
                del self.games[ctx.channel.id]
            except KeyError:  # got stuck in between
                pass
Esempio n. 10
0
                      attacking_cost=attacking_cost,
                      leading_guild_money=leading_guild_money,
                  ))
        else:
            if not await ctx.confirm(
                    _("**{city}** has excellent infrastructure and attacking it would cost **${attacking_cost}**, do you want to proceed?"
                      ).format(city=city, attacking_cost=attacking_cost)):
                await self.bot.reset_alliance_cooldown(ctx)
                return

        # Gather the fighters
        attackers = []
        attacking_users = []

        view = JoinView(
            Button(style=ButtonStyle.primary, label=_("Join the attack!")),
            message=_("You joined the attack."),
            timeout=60 * 10,
        )

        await ctx.send(
            _("**{user}** wants to attack **{city}** with **{alliance_name}**'s"
              " alliance.").format(user=ctx.author,
                                   city=city,
                                   alliance_name=alliance_name),
            view=view,
        )

        await asyncio.sleep(60 * 10)

        view.stop()