easterobot 1.1.2__py3-none-any.whl → 1.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- easterobot/bot.py +15 -6
 - easterobot/commands/__init__.py +3 -0
 - easterobot/commands/base.py +4 -1
 - easterobot/commands/disable.py +1 -1
 - easterobot/commands/enable.py +1 -1
 - easterobot/commands/game.py +23 -21
 - easterobot/commands/help.py +3 -3
 - easterobot/commands/info.py +61 -0
 - easterobot/commands/reset.py +1 -1
 - easterobot/commands/search.py +14 -40
 - easterobot/config.py +71 -1
 - easterobot/games/connect.py +8 -7
 - easterobot/games/game.py +105 -34
 - easterobot/games/rock_paper_scissor.py +22 -8
 - easterobot/games/tic_tac_toe.py +8 -7
 - easterobot/hunts/hunt.py +183 -84
 - easterobot/hunts/luck.py +53 -0
 - easterobot/query.py +11 -0
 - easterobot/resources/config.example.yml +218 -9
 - easterobot/utils.py +11 -0
 - {easterobot-1.1.2.dist-info → easterobot-1.3.1.dist-info}/METADATA +9 -5
 - {easterobot-1.1.2.dist-info → easterobot-1.3.1.dist-info}/RECORD +25 -21
 - {easterobot-1.1.2.dist-info → easterobot-1.3.1.dist-info}/WHEEL +0 -0
 - {easterobot-1.1.2.dist-info → easterobot-1.3.1.dist-info}/entry_points.txt +0 -0
 - {easterobot-1.1.2.dist-info → easterobot-1.3.1.dist-info}/licenses/LICENSE +0 -0
 
    
        easterobot/hunts/hunt.py
    CHANGED
    
    | 
         @@ -3,7 +3,7 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            import asyncio
         
     | 
| 
       4 
4 
     | 
    
         
             
            import logging
         
     | 
| 
       5 
5 
     | 
    
         
             
            import time
         
     | 
| 
       6 
     | 
    
         
            -
            from collections.abc import Awaitable
         
     | 
| 
      
 6 
     | 
    
         
            +
            from collections.abc import Awaitable, Iterable, Sequence
         
     | 
| 
       7 
7 
     | 
    
         
             
            from datetime import datetime, timezone
         
     | 
| 
       8 
8 
     | 
    
         
             
            from typing import (
         
     | 
| 
       9 
9 
     | 
    
         
             
                Any,
         
     | 
| 
         @@ -21,16 +21,128 @@ from easterobot.config import ( 
     | 
|
| 
       21 
21 
     | 
    
         
             
                RAND,
         
     | 
| 
       22 
22 
     | 
    
         
             
                agree,
         
     | 
| 
       23 
23 
     | 
    
         
             
            )
         
     | 
| 
      
 24 
     | 
    
         
            +
            from easterobot.hunts.luck import HuntLuck
         
     | 
| 
       24 
25 
     | 
    
         
             
            from easterobot.models import Egg, Hunt
         
     | 
| 
      
 26 
     | 
    
         
            +
            from easterobot.query import QueryManager
         
     | 
| 
       25 
27 
     | 
    
         | 
| 
       26 
28 
     | 
    
         
             
            logger = logging.getLogger(__name__)
         
     | 
| 
       27 
29 
     | 
    
         
             
            DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
         
     | 
| 
       28 
30 
     | 
    
         | 
| 
       29 
31 
     | 
    
         | 
| 
       30 
     | 
    
         
            -
            class  
     | 
| 
      
 32 
     | 
    
         
            +
            class HuntQuery(QueryManager):
         
     | 
| 
      
 33 
     | 
    
         
            +
                async def unlock_all_eggs(self, session: AsyncSession) -> None:
         
     | 
| 
      
 34 
     | 
    
         
            +
                    """Unlock all eggs."""
         
     | 
| 
      
 35 
     | 
    
         
            +
                    await session.execute(update(Egg).where(Egg.lock).values(lock=False))
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                async def get_egg_count_for_members(
         
     | 
| 
      
 38 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 39 
     | 
    
         
            +
                    session: AsyncSession,
         
     | 
| 
      
 40 
     | 
    
         
            +
                    guild_id: int,
         
     | 
| 
      
 41 
     | 
    
         
            +
                    user_ids: Iterable[int],
         
     | 
| 
      
 42 
     | 
    
         
            +
                ) -> dict[int, int]:
         
     | 
| 
      
 43 
     | 
    
         
            +
                    """Get egg count for members."""
         
     | 
| 
      
 44 
     | 
    
         
            +
                    res = await session.execute(
         
     | 
| 
      
 45 
     | 
    
         
            +
                        select(Egg.user_id, func.count().label("count"))
         
     | 
| 
      
 46 
     | 
    
         
            +
                        .where(
         
     | 
| 
      
 47 
     | 
    
         
            +
                            and_(
         
     | 
| 
      
 48 
     | 
    
         
            +
                                Egg.guild_id == guild_id,
         
     | 
| 
      
 49 
     | 
    
         
            +
                                Egg.user_id.in_(user_ids),
         
     | 
| 
      
 50 
     | 
    
         
            +
                            )
         
     | 
| 
      
 51 
     | 
    
         
            +
                        )
         
     | 
| 
      
 52 
     | 
    
         
            +
                        .group_by(Egg.user_id)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    )
         
     | 
| 
      
 54 
     | 
    
         
            +
                    return dict(res.all())  # type: ignore[arg-type]
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                async def get_hunt(
         
     | 
| 
      
 57 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 58 
     | 
    
         
            +
                    session: AsyncSession,
         
     | 
| 
      
 59 
     | 
    
         
            +
                    guild_id: int,
         
     | 
| 
      
 60 
     | 
    
         
            +
                    channel_id: int,
         
     | 
| 
      
 61 
     | 
    
         
            +
                ) -> Optional[Hunt]:
         
     | 
| 
      
 62 
     | 
    
         
            +
                    """Get hunt."""
         
     | 
| 
      
 63 
     | 
    
         
            +
                    hunt = await session.scalar(
         
     | 
| 
      
 64 
     | 
    
         
            +
                        select(Hunt).where(
         
     | 
| 
      
 65 
     | 
    
         
            +
                            and_(
         
     | 
| 
      
 66 
     | 
    
         
            +
                                Hunt.guild_id == guild_id,
         
     | 
| 
      
 67 
     | 
    
         
            +
                                Hunt.channel_id == channel_id,
         
     | 
| 
      
 68 
     | 
    
         
            +
                            )
         
     | 
| 
      
 69 
     | 
    
         
            +
                        )
         
     | 
| 
      
 70 
     | 
    
         
            +
                    )
         
     | 
| 
      
 71 
     | 
    
         
            +
                    return hunt  # noqa: RET504
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                async def get_hunts_after(
         
     | 
| 
      
 74 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 75 
     | 
    
         
            +
                    session: AsyncSession,
         
     | 
| 
      
 76 
     | 
    
         
            +
                    after: float,
         
     | 
| 
      
 77 
     | 
    
         
            +
                ) -> Sequence[Hunt]:
         
     | 
| 
      
 78 
     | 
    
         
            +
                    """Get all hunts after a given datetime."""
         
     | 
| 
      
 79 
     | 
    
         
            +
                    res = await session.scalars(
         
     | 
| 
      
 80 
     | 
    
         
            +
                        select(Hunt).where(Hunt.next_egg <= after),
         
     | 
| 
      
 81 
     | 
    
         
            +
                    )
         
     | 
| 
      
 82 
     | 
    
         
            +
                    return res.all()
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                async def get_max_eggs(
         
     | 
| 
      
 85 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 86 
     | 
    
         
            +
                    session: AsyncSession,
         
     | 
| 
      
 87 
     | 
    
         
            +
                    guild_id: int,
         
     | 
| 
      
 88 
     | 
    
         
            +
                ) -> int:
         
     | 
| 
      
 89 
     | 
    
         
            +
                    """Get the maximum number of eggs."""
         
     | 
| 
      
 90 
     | 
    
         
            +
                    egg_max = await session.scalar(
         
     | 
| 
      
 91 
     | 
    
         
            +
                        select(
         
     | 
| 
      
 92 
     | 
    
         
            +
                            func.count().label("max"),
         
     | 
| 
      
 93 
     | 
    
         
            +
                        )
         
     | 
| 
      
 94 
     | 
    
         
            +
                        .where(Egg.guild_id == guild_id)
         
     | 
| 
      
 95 
     | 
    
         
            +
                        .group_by(Egg.user_id)
         
     | 
| 
      
 96 
     | 
    
         
            +
                        .order_by(func.count().label("max").desc())
         
     | 
| 
      
 97 
     | 
    
         
            +
                        .limit(1)
         
     | 
| 
      
 98 
     | 
    
         
            +
                    )
         
     | 
| 
      
 99 
     | 
    
         
            +
                    return egg_max or 0
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                async def get_eggs(
         
     | 
| 
      
 102 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 103 
     | 
    
         
            +
                    session: AsyncSession,
         
     | 
| 
      
 104 
     | 
    
         
            +
                    guild_id: int,
         
     | 
| 
      
 105 
     | 
    
         
            +
                    user_id: int,
         
     | 
| 
      
 106 
     | 
    
         
            +
                ) -> int:
         
     | 
| 
      
 107 
     | 
    
         
            +
                    """Get eggs of player."""
         
     | 
| 
      
 108 
     | 
    
         
            +
                    eggs = await session.scalar(
         
     | 
| 
      
 109 
     | 
    
         
            +
                        select(func.count().label("count")).where(
         
     | 
| 
      
 110 
     | 
    
         
            +
                            and_(
         
     | 
| 
      
 111 
     | 
    
         
            +
                                Egg.guild_id == guild_id,
         
     | 
| 
      
 112 
     | 
    
         
            +
                                Egg.user_id == user_id,
         
     | 
| 
      
 113 
     | 
    
         
            +
                            )
         
     | 
| 
      
 114 
     | 
    
         
            +
                        )
         
     | 
| 
      
 115 
     | 
    
         
            +
                    )
         
     | 
| 
      
 116 
     | 
    
         
            +
                    return eggs or 0
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                async def get_luck(
         
     | 
| 
      
 119 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 120 
     | 
    
         
            +
                    session: AsyncSession,
         
     | 
| 
      
 121 
     | 
    
         
            +
                    guild_id: int,
         
     | 
| 
      
 122 
     | 
    
         
            +
                    user_id: int,
         
     | 
| 
      
 123 
     | 
    
         
            +
                    *,
         
     | 
| 
      
 124 
     | 
    
         
            +
                    sleep_hours: bool = False,
         
     | 
| 
      
 125 
     | 
    
         
            +
                ) -> HuntLuck:
         
     | 
| 
      
 126 
     | 
    
         
            +
                    """Get the luck of a member."""
         
     | 
| 
      
 127 
     | 
    
         
            +
                    luck = 1.0
         
     | 
| 
      
 128 
     | 
    
         
            +
                    egg_count = await self.get_eggs(session, guild_id, user_id)
         
     | 
| 
      
 129 
     | 
    
         
            +
                    if egg_count != 0:
         
     | 
| 
      
 130 
     | 
    
         
            +
                        egg_max = await self.get_max_eggs(session, guild_id)
         
     | 
| 
      
 131 
     | 
    
         
            +
                        if egg_max != 0:
         
     | 
| 
      
 132 
     | 
    
         
            +
                            luck = 1 - egg_count / egg_max
         
     | 
| 
      
 133 
     | 
    
         
            +
                    return HuntLuck(
         
     | 
| 
      
 134 
     | 
    
         
            +
                        egg_count=egg_count,
         
     | 
| 
      
 135 
     | 
    
         
            +
                        luck=luck,
         
     | 
| 
      
 136 
     | 
    
         
            +
                        sleep_hours=sleep_hours,
         
     | 
| 
      
 137 
     | 
    
         
            +
                        config=self.config,
         
     | 
| 
      
 138 
     | 
    
         
            +
                    )
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
            class HuntCog(commands.Cog, HuntQuery):
         
     | 
| 
       31 
142 
     | 
    
         
             
                def __init__(self, bot: Easterobot) -> None:
         
     | 
| 
       32 
143 
     | 
    
         
             
                    """Instantiate HuntCog."""
         
     | 
| 
       33 
144 
     | 
    
         
             
                    self.bot = bot
         
     | 
| 
      
 145 
     | 
    
         
            +
                    super().__init__(self.bot.config)
         
     | 
| 
       34 
146 
     | 
    
         | 
| 
       35 
147 
     | 
    
         
             
                @commands.Cog.listener()
         
     | 
| 
       36 
148 
     | 
    
         
             
                async def on_ready(self) -> None:
         
     | 
| 
         @@ -38,9 +150,7 @@ class HuntCog(commands.Cog): 
     | 
|
| 
       38 
150 
     | 
    
         
             
                    # Unlock all eggs
         
     | 
| 
       39 
151 
     | 
    
         
             
                    logger.info("Unlock all previous eggs")
         
     | 
| 
       40 
152 
     | 
    
         
             
                    async with AsyncSession(self.bot.engine) as session:
         
     | 
| 
       41 
     | 
    
         
            -
                        await  
     | 
| 
       42 
     | 
    
         
            -
                            update(Egg).where(Egg.lock).values(lock=False)
         
     | 
| 
       43 
     | 
    
         
            -
                        )
         
     | 
| 
      
 153 
     | 
    
         
            +
                        await self.unlock_all_eggs(session)
         
     | 
| 
       44 
154 
     | 
    
         
             
                        await session.commit()
         
     | 
| 
       45 
155 
     | 
    
         | 
| 
       46 
156 
     | 
    
         
             
                    # Start hunt
         
     | 
| 
         @@ -150,7 +260,7 @@ class HuntCog(commands.Cog): 
     | 
|
| 
       150 
260 
     | 
    
         
             
                    emb = embed(
         
     | 
| 
       151 
261 
     | 
    
         
             
                        title="Un œuf a été découvert !",
         
     | 
| 
       152 
262 
     | 
    
         
             
                        description=description
         
     | 
| 
       153 
     | 
    
         
            -
                        + f"\n\nTirage du  
     | 
| 
      
 263 
     | 
    
         
            +
                        + f"\n\nTirage du vainqueur : <t:{next_hunt:.0f}:R>",
         
     | 
| 
       154 
264 
     | 
    
         
             
                        thumbnail=emoji.url,
         
     | 
| 
       155 
265 
     | 
    
         
             
                    )
         
     | 
| 
       156 
266 
     | 
    
         | 
| 
         @@ -179,35 +289,20 @@ class HuntCog(commands.Cog): 
     | 
|
| 
       179 
289 
     | 
    
         | 
| 
       180 
290 
     | 
    
         
             
                    # Get if hunt is valid
         
     | 
| 
       181 
291 
     | 
    
         
             
                    async with AsyncSession(self.bot.engine) as session:
         
     | 
| 
       182 
     | 
    
         
            -
                         
     | 
| 
       183 
     | 
    
         
            -
                            select(Hunt).where(
         
     | 
| 
       184 
     | 
    
         
            -
                                and_(
         
     | 
| 
       185 
     | 
    
         
            -
                                    Hunt.guild_id == guild.id,
         
     | 
| 
       186 
     | 
    
         
            -
                                    Hunt.channel_id == channel.id,
         
     | 
| 
       187 
     | 
    
         
            -
                                )
         
     | 
| 
       188 
     | 
    
         
            -
                            )
         
     | 
| 
       189 
     | 
    
         
            -
                        )
         
     | 
| 
      
 292 
     | 
    
         
            +
                        hunt = await self.get_hunt(session, guild.id, channel.id)
         
     | 
| 
       190 
293 
     | 
    
         | 
| 
       191 
     | 
    
         
            -
             
     | 
| 
       192 
     | 
    
         
            -
             
     | 
| 
       193 
     | 
    
         
            -
             
     | 
| 
       194 
     | 
    
         
            -
             
     | 
| 
       195 
     | 
    
         
            -
             
     | 
| 
       196 
     | 
    
         
            -
             
     | 
| 
       197 
     | 
    
         
            -
                        # Process the winner
         
     | 
| 
       198 
     | 
    
         
            -
                        async with AsyncSession(self.bot.engine) as session:
         
     | 
| 
      
 294 
     | 
    
         
            +
                        # The egg was not collected
         
     | 
| 
      
 295 
     | 
    
         
            +
                        if not hunters or not hunt:
         
     | 
| 
      
 296 
     | 
    
         
            +
                            button.label = "L'œuf n'a pas été ramassé"
         
     | 
| 
      
 297 
     | 
    
         
            +
                            button.style = discord.ButtonStyle.danger
         
     | 
| 
      
 298 
     | 
    
         
            +
                            logger.info("No Hunter for %s", message_url)
         
     | 
| 
      
 299 
     | 
    
         
            +
                        else:
         
     | 
| 
       199 
300 
     | 
    
         
             
                            # Get the count of egg by user
         
     | 
| 
       200 
     | 
    
         
            -
                             
     | 
| 
       201 
     | 
    
         
            -
                                 
     | 
| 
       202 
     | 
    
         
            -
                                . 
     | 
| 
       203 
     | 
    
         
            -
             
     | 
| 
       204 
     | 
    
         
            -
                                        Egg.guild_id == guild.id,
         
     | 
| 
       205 
     | 
    
         
            -
                                        Egg.user_id.in_(hunter.id for hunter in hunters),
         
     | 
| 
       206 
     | 
    
         
            -
                                    )
         
     | 
| 
       207 
     | 
    
         
            -
                                )
         
     | 
| 
       208 
     | 
    
         
            -
                                .group_by(Egg.user_id)
         
     | 
| 
      
 301 
     | 
    
         
            +
                            eggs = await self.get_egg_count_for_members(
         
     | 
| 
      
 302 
     | 
    
         
            +
                                session,
         
     | 
| 
      
 303 
     | 
    
         
            +
                                guild_id=guild.id,
         
     | 
| 
      
 304 
     | 
    
         
            +
                                user_ids=[hunter.id for hunter in hunters],
         
     | 
| 
       209 
305 
     | 
    
         
             
                            )
         
     | 
| 
       210 
     | 
    
         
            -
                            eggs: dict[int, int] = dict(res.all())  # type: ignore[arg-type]
         
     | 
| 
       211 
306 
     | 
    
         
             
                            logger.info("Winner draw for %s", message_url)
         
     | 
| 
       212 
307 
     | 
    
         | 
| 
       213 
308 
     | 
    
         
             
                            ranked_hunters = self.rank_players(hunters, eggs)
         
     | 
| 
         @@ -219,7 +314,6 @@ class HuntCog(commands.Cog): 
     | 
|
| 
       219 
314 
     | 
    
         
             
                                loser = ranked_hunters[1]
         
     | 
| 
       220 
315 
     | 
    
         | 
| 
       221 
316 
     | 
    
         
             
                                if RAND.random() < self.bot.config.hunt.game:
         
     | 
| 
       222 
     | 
    
         
            -
                                    # TODO(dashstrom): edit timer during dual
         
     | 
| 
       223 
317 
     | 
    
         
             
                                    # Update button
         
     | 
| 
       224 
318 
     | 
    
         
             
                                    button.label = "Duel en cours ..."
         
     | 
| 
       225 
319 
     | 
    
         
             
                                    button.style = discord.ButtonStyle.gray
         
     | 
| 
         @@ -250,50 +344,56 @@ class HuntCog(commands.Cog): 
     | 
|
| 
       250 
344 
     | 
    
         
             
                                )
         
     | 
| 
       251 
345 
     | 
    
         
             
                                await session.commit()
         
     | 
| 
       252 
346 
     | 
    
         | 
| 
       253 
     | 
    
         
            -
             
     | 
| 
       254 
     | 
    
         
            -
             
     | 
| 
       255 
     | 
    
         
            -
             
     | 
| 
       256 
     | 
    
         
            -
             
     | 
| 
       257 
     | 
    
         
            -
             
     | 
| 
       258 
     | 
    
         
            -
             
     | 
| 
       259 
     | 
    
         
            -
             
     | 
| 
       260 
     | 
    
         
            -
             
     | 
| 
       261 
     | 
    
         
            -
             
     | 
| 
       262 
     | 
    
         
            -
             
     | 
| 
       263 
     | 
    
         
            -
             
     | 
| 
      
 347 
     | 
    
         
            +
                            # Show the embed to loser
         
     | 
| 
      
 348 
     | 
    
         
            +
                            if loser:
         
     | 
| 
      
 349 
     | 
    
         
            +
                                loser_name = loser.display_name
         
     | 
| 
      
 350 
     | 
    
         
            +
                                if len(hunters) == 2:  # noqa: PLR2004
         
     | 
| 
      
 351 
     | 
    
         
            +
                                    text = f"{loser_name} rate un œuf"
         
     | 
| 
      
 352 
     | 
    
         
            +
                                else:
         
     | 
| 
      
 353 
     | 
    
         
            +
                                    text = agree(
         
     | 
| 
      
 354 
     | 
    
         
            +
                                        "{1} et {0} autre chasseur ratent un œuf",
         
     | 
| 
      
 355 
     | 
    
         
            +
                                        "{1} et {0} autres chasseurs ratent un œuf",
         
     | 
| 
      
 356 
     | 
    
         
            +
                                        len(hunters) - 2,
         
     | 
| 
      
 357 
     | 
    
         
            +
                                        loser_name,
         
     | 
| 
      
 358 
     | 
    
         
            +
                                    )
         
     | 
| 
      
 359 
     | 
    
         
            +
                                emb = embed(
         
     | 
| 
      
 360 
     | 
    
         
            +
                                    title=text,
         
     | 
| 
      
 361 
     | 
    
         
            +
                                    description=action.fail.text(loser),
         
     | 
| 
      
 362 
     | 
    
         
            +
                                    image=action.fail.gif,
         
     | 
| 
       264 
363 
     | 
    
         
             
                                )
         
     | 
| 
       265 
     | 
    
         
            -
             
     | 
| 
       266 
     | 
    
         
            -
             
     | 
| 
       267 
     | 
    
         
            -
             
     | 
| 
       268 
     | 
    
         
            -
             
     | 
| 
       269 
     | 
    
         
            -
             
     | 
| 
       270 
     | 
    
         
            -
             
     | 
| 
       271 
     | 
    
         
            -
             
     | 
| 
       272 
     | 
    
         
            -
             
     | 
| 
       273 
     | 
    
         
            -
             
     | 
| 
       274 
     | 
    
         
            -
             
     | 
| 
       275 
     | 
    
         
            -
             
     | 
| 
       276 
     | 
    
         
            -
             
     | 
| 
       277 
     | 
    
         
            -
             
     | 
| 
       278 
     | 
    
         
            -
             
     | 
| 
       279 
     | 
    
         
            -
             
     | 
| 
       280 
     | 
    
         
            -
                                 
     | 
| 
       281 
     | 
    
         
            -
             
     | 
| 
       282 
     | 
    
         
            -
             
     | 
| 
       283 
     | 
    
         
            -
             
     | 
| 
       284 
     | 
    
         
            -
             
     | 
| 
       285 
     | 
    
         
            -
             
     | 
| 
       286 
     | 
    
         
            -
             
     | 
| 
       287 
     | 
    
         
            -
             
     | 
| 
       288 
     | 
    
         
            -
                                 
     | 
| 
       289 
     | 
    
         
            -
             
     | 
| 
       290 
     | 
    
         
            -
             
     | 
| 
       291 
     | 
    
         
            -
             
     | 
| 
       292 
     | 
    
         
            -
             
     | 
| 
       293 
     | 
    
         
            -
             
     | 
| 
       294 
     | 
    
         
            -
                             
     | 
| 
       295 
     | 
    
         
            -
             
     | 
| 
       296 
     | 
    
         
            -
             
     | 
| 
      
 364 
     | 
    
         
            +
                                await channel.send(
         
     | 
| 
      
 365 
     | 
    
         
            +
                                    embed=emb,
         
     | 
| 
      
 366 
     | 
    
         
            +
                                    reference=message,
         
     | 
| 
      
 367 
     | 
    
         
            +
                                    delete_after=300,
         
     | 
| 
      
 368 
     | 
    
         
            +
                                )
         
     | 
| 
      
 369 
     | 
    
         
            +
             
     | 
| 
      
 370 
     | 
    
         
            +
                            if winner:
         
     | 
| 
      
 371 
     | 
    
         
            +
                                # Send embed for the winner
         
     | 
| 
      
 372 
     | 
    
         
            +
                                winner_eggs = eggs.get(winner.id, 0) + 1
         
     | 
| 
      
 373 
     | 
    
         
            +
                                emb = embed(
         
     | 
| 
      
 374 
     | 
    
         
            +
                                    title=f"{winner.display_name} récupère un œuf",
         
     | 
| 
      
 375 
     | 
    
         
            +
                                    description=action.success.text(winner),
         
     | 
| 
      
 376 
     | 
    
         
            +
                                    image=action.success.gif,
         
     | 
| 
      
 377 
     | 
    
         
            +
                                    thumbnail=emoji.url,
         
     | 
| 
      
 378 
     | 
    
         
            +
                                    egg_count=winner_eggs,
         
     | 
| 
      
 379 
     | 
    
         
            +
                                )
         
     | 
| 
      
 380 
     | 
    
         
            +
                                await channel.send(embed=emb, reference=message)
         
     | 
| 
      
 381 
     | 
    
         
            +
             
     | 
| 
      
 382 
     | 
    
         
            +
                                # Update button
         
     | 
| 
      
 383 
     | 
    
         
            +
                                button.label = (
         
     | 
| 
      
 384 
     | 
    
         
            +
                                    f"L'œuf a été ramassé par {winner.display_name}"
         
     | 
| 
      
 385 
     | 
    
         
            +
                                )
         
     | 
| 
      
 386 
     | 
    
         
            +
                                button.style = discord.ButtonStyle.success
         
     | 
| 
      
 387 
     | 
    
         
            +
                                logger.info(
         
     | 
| 
      
 388 
     | 
    
         
            +
                                    "Winner is %s (%s) with %s",
         
     | 
| 
      
 389 
     | 
    
         
            +
                                    winner,
         
     | 
| 
      
 390 
     | 
    
         
            +
                                    winner.id,
         
     | 
| 
      
 391 
     | 
    
         
            +
                                    agree("{0} egg", "{0} eggs", winner_eggs),
         
     | 
| 
      
 392 
     | 
    
         
            +
                                )
         
     | 
| 
      
 393 
     | 
    
         
            +
                            else:
         
     | 
| 
      
 394 
     | 
    
         
            +
                                button.label = "L'œuf a été cassé"
         
     | 
| 
      
 395 
     | 
    
         
            +
                                button.style = discord.ButtonStyle.danger
         
     | 
| 
      
 396 
     | 
    
         
            +
                                logger.info("No winner %s", message_url)
         
     | 
| 
       297 
397 
     | 
    
         | 
| 
       298 
398 
     | 
    
         
             
                    # Remove emoji and edit view
         
     | 
| 
       299 
399 
     | 
    
         
             
                    button.emoji = None
         
     | 
| 
         @@ -361,19 +461,19 @@ class HuntCog(commands.Cog): 
     | 
|
| 
       361 
461 
     | 
    
         
             
                async def loop_hunt(self) -> None:
         
     | 
| 
       362 
462 
     | 
    
         
             
                    """Manage the schedule of run."""
         
     | 
| 
       363 
463 
     | 
    
         
             
                    # Create a async session
         
     | 
| 
       364 
     | 
    
         
            -
                    async with AsyncSession(
         
     | 
| 
       365 
     | 
    
         
            -
                        self.bot.engine, expire_on_commit=False
         
     | 
| 
       366 
     | 
    
         
            -
                    ) as session:
         
     | 
| 
      
 464 
     | 
    
         
            +
                    async with AsyncSession(self.bot.engine) as session:
         
     | 
| 
       367 
465 
     | 
    
         
             
                        # Find hunt with next egg available
         
     | 
| 
       368 
466 
     | 
    
         
             
                        now = time.time()
         
     | 
| 
       369 
     | 
    
         
            -
                        hunts = (
         
     | 
| 
       370 
     | 
    
         
            -
             
     | 
| 
       371 
     | 
    
         
            -
                        ).all()
         
     | 
| 
      
 467 
     | 
    
         
            +
                        hunts = await self.get_hunts_after(session, now)
         
     | 
| 
      
 468 
     | 
    
         
            +
                        hunt_ids = [hunt.channel_id for hunt in hunts]
         
     | 
| 
       372 
469 
     | 
    
         | 
| 
       373 
470 
     | 
    
         
             
                        # For each hunt, set the next run and store the channel ids
         
     | 
| 
       374 
471 
     | 
    
         
             
                        if hunts:
         
     | 
| 
       375 
472 
     | 
    
         
             
                            for hunt in hunts:
         
     | 
| 
       376 
     | 
    
         
            -
                                 
     | 
| 
      
 473 
     | 
    
         
            +
                                delta = self.bot.config.hunt.cooldown.rand()
         
     | 
| 
      
 474 
     | 
    
         
            +
                                if self.bot.config.in_sleep_hours():
         
     | 
| 
      
 475 
     | 
    
         
            +
                                    delta *= self.bot.config.sleep.divide_hunt
         
     | 
| 
      
 476 
     | 
    
         
            +
                                next_egg = now + delta
         
     | 
| 
       377 
477 
     | 
    
         
             
                                dt_next = datetime.fromtimestamp(next_egg, tz=timezone.utc)
         
     | 
| 
       378 
478 
     | 
    
         
             
                                logger.info(
         
     | 
| 
       379 
479 
     | 
    
         
             
                                    "Next hunt at %s on %s",
         
     | 
| 
         @@ -382,7 +482,6 @@ class HuntCog(commands.Cog): 
     | 
|
| 
       382 
482 
     | 
    
         
             
                                )
         
     | 
| 
       383 
483 
     | 
    
         
             
                                hunt.next_egg = next_egg
         
     | 
| 
       384 
484 
     | 
    
         
             
                            await session.commit()
         
     | 
| 
       385 
     | 
    
         
            -
                        hunt_ids = [hunt.channel_id for hunt in hunts]
         
     | 
| 
       386 
485 
     | 
    
         | 
| 
       387 
486 
     | 
    
         
             
                    # Call start_hunt for each hunt
         
     | 
| 
       388 
487 
     | 
    
         
             
                    if hunt_ids:
         
     | 
    
        easterobot/hunts/luck.py
    ADDED
    
    | 
         @@ -0,0 +1,53 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            """Luck module."""
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            import logging
         
     | 
| 
      
 4 
     | 
    
         
            +
            from dataclasses import dataclass
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            from easterobot.config import RAND, MConfig
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            logger = logging.getLogger(__name__)
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            @dataclass
         
     | 
| 
      
 12 
     | 
    
         
            +
            class HuntLuck:
         
     | 
| 
      
 13 
     | 
    
         
            +
                egg_count: int
         
     | 
| 
      
 14 
     | 
    
         
            +
                luck: float
         
     | 
| 
      
 15 
     | 
    
         
            +
                sleep_hours: bool
         
     | 
| 
      
 16 
     | 
    
         
            +
                config: MConfig
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                @property
         
     | 
| 
      
 19 
     | 
    
         
            +
                def discovered(self) -> float:
         
     | 
| 
      
 20 
     | 
    
         
            +
                    """Discovered probability."""
         
     | 
| 
      
 21 
     | 
    
         
            +
                    prob = self.config.commands.search.discovered.probability(self.luck)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    if self.sleep_hours:
         
     | 
| 
      
 23 
     | 
    
         
            +
                        prob /= self.config.sleep.divide_discovered
         
     | 
| 
      
 24 
     | 
    
         
            +
                    return prob
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                @property
         
     | 
| 
      
 27 
     | 
    
         
            +
                def spotted(self) -> float:
         
     | 
| 
      
 28 
     | 
    
         
            +
                    """Spotted probability."""
         
     | 
| 
      
 29 
     | 
    
         
            +
                    prob = self.config.commands.search.spotted.probability(self.luck)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    if self.sleep_hours:
         
     | 
| 
      
 31 
     | 
    
         
            +
                        prob /= self.config.sleep.divide_spotted
         
     | 
| 
      
 32 
     | 
    
         
            +
                    return prob
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def sample_discovered(self) -> bool:
         
     | 
| 
      
 35 
     | 
    
         
            +
                    """Get if player get detected."""
         
     | 
| 
      
 36 
     | 
    
         
            +
                    if self.egg_count <= self.config.commands.search.discovered.shield:
         
     | 
| 
      
 37 
     | 
    
         
            +
                        logger.info("discovered: shield with %s eggs", self.egg_count)
         
     | 
| 
      
 38 
     | 
    
         
            +
                        return True
         
     | 
| 
      
 39 
     | 
    
         
            +
                    sample = RAND.random()
         
     | 
| 
      
 40 
     | 
    
         
            +
                    logger.info(
         
     | 
| 
      
 41 
     | 
    
         
            +
                        "discovered: expect over %.2f got %.2f",
         
     | 
| 
      
 42 
     | 
    
         
            +
                        self.discovered,
         
     | 
| 
      
 43 
     | 
    
         
            +
                        sample,
         
     | 
| 
      
 44 
     | 
    
         
            +
                    )
         
     | 
| 
      
 45 
     | 
    
         
            +
                    return self.discovered > sample
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                def sample_spotted(self) -> bool:
         
     | 
| 
      
 48 
     | 
    
         
            +
                    """Get if player get spotted."""
         
     | 
| 
      
 49 
     | 
    
         
            +
                    if self.egg_count <= self.config.commands.search.spotted.shield:
         
     | 
| 
      
 50 
     | 
    
         
            +
                        logger.info("spotted: shield with %s eggs", self.egg_count)
         
     | 
| 
      
 51 
     | 
    
         
            +
                        return True
         
     | 
| 
      
 52 
     | 
    
         
            +
                    sample = RAND.random()
         
     | 
| 
      
 53 
     | 
    
         
            +
                    return self.spotted < sample
         
     |