easterobot 1.1.1__tar.gz → 1.3.1__tar.gz
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-1.1.1 → easterobot-1.3.1}/.dockerignore +4 -1
- {easterobot-1.1.1 → easterobot-1.3.1}/.github/workflows/tests.yml +13 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/Dockerfile +10 -5
- {easterobot-1.1.1 → easterobot-1.3.1}/PKG-INFO +10 -1
- {easterobot-1.1.1 → easterobot-1.3.1}/README.rst +9 -0
- easterobot-1.3.1/conftest.py +44 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/docker-compose.yml +1 -1
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/bot.py +15 -6
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/commands/__init__.py +3 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/commands/base.py +4 -1
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/commands/disable.py +2 -1
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/commands/edit.py +2 -1
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/commands/enable.py +2 -1
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/commands/game.py +26 -22
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/commands/help.py +6 -3
- easterobot-1.3.1/easterobot/commands/info.py +61 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/commands/reset.py +2 -1
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/commands/search.py +17 -40
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/config.py +72 -2
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/games/connect.py +8 -7
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/games/game.py +105 -34
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/games/rock_paper_scissor.py +22 -8
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/games/tic_tac_toe.py +8 -7
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/hunts/hunt.py +183 -84
- easterobot-1.3.1/easterobot/hunts/luck.py +53 -0
- easterobot-1.3.1/easterobot/query.py +11 -0
- easterobot-1.3.1/easterobot/resources/config.example.yml +443 -0
- easterobot-1.3.1/easterobot/utils.py +11 -0
- easterobot-1.3.1/entrypoint.sh +6 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/pyproject.toml +7 -5
- easterobot-1.3.1/tests/constants.py +8 -0
- easterobot-1.3.1/tests/test_search.py +49 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/tools/chatgpt.txt +2 -2
- {easterobot-1.1.1 → easterobot-1.3.1}/uv.lock +27 -1
- easterobot-1.1.1/conftest.py +0 -13
- easterobot-1.1.1/easterobot/resources/config.example.yml +0 -234
- easterobot-1.1.1/entrypoint.sh +0 -6
- {easterobot-1.1.1 → easterobot-1.3.1}/.editorconfig +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/.github/actions/setup-project/action.yml +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/.github/workflows/docs.yml +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/.github/workflows/lint.yml +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/.github/workflows/publish.yml +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/.gitignore +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/.pre-commit-config.yaml +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/.vscode/extensions.json +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/.vscode/ltex.dictionary.en-US.txt +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/.vscode/ltex.hiddenFalsePositives.en-US.txt +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/.vscode/settings.json +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/LICENSE +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/docs/conf.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/docs/index.rst +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/docs/references.rst +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/docs/resources/favicon.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/__init__.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/__main__.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/alembic/env.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/alembic/script.py.mako +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/alembic/versions/2f0d4305e320_init_database.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/alembic/versions/940c3b9c702d_add_lock_on_eggs.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/cli.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/commands/basket.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/commands/top.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/games/__init__.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/hunts/__init__.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/hunts/rank.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/info.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/logger.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/models.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/py.typed +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/alembic.ini +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/credits.txt +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_01.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_02.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_03.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_04.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_05.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_06.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_07.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_08.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_09.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_10.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_11.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_12.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_13.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_14.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_15.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_16.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_17.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_18.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_19.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/eggs/egg_20.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/icons/arrow.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/icons/end.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/icons/versus.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/emotes/icons/wait.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/logging.conf +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/easterobot/resources/logo.png +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/tests/__init__.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/tests/test_cli.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/tests/test_config.py +0 -0
- {easterobot-1.1.1 → easterobot-1.3.1}/tools/cropping.py +0 -0
@@ -37,3 +37,16 @@ jobs:
|
|
37
37
|
|
38
38
|
- name: Run tests
|
39
39
|
run: uv run poe test
|
40
|
+
docker:
|
41
|
+
name: Docker build
|
42
|
+
runs-on: ubuntu-latest
|
43
|
+
|
44
|
+
steps:
|
45
|
+
- name: Checkout code
|
46
|
+
uses: actions/checkout@v4
|
47
|
+
|
48
|
+
- name: Set up Docker
|
49
|
+
uses: docker/setup-buildx-action@v3
|
50
|
+
|
51
|
+
- name: Build services with Docker Compose
|
52
|
+
run: docker compose -f docker-compose.yml build
|
@@ -2,8 +2,8 @@
|
|
2
2
|
FROM python:3.12-slim
|
3
3
|
|
4
4
|
# Metadata for clarity and documentation
|
5
|
-
LABEL maintainer="
|
6
|
-
LABEL description="Docker image for easterobot
|
5
|
+
LABEL maintainer="dashstrom.pro@gmail.com"
|
6
|
+
LABEL description="Docker image for easterobot, a discord bot for easter events"
|
7
7
|
|
8
8
|
# Add the UV binary
|
9
9
|
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
|
@@ -17,9 +17,6 @@ RUN mkdir /data
|
|
17
17
|
# Make it read-only
|
18
18
|
RUN chown easterobot:easterobot /data
|
19
19
|
|
20
|
-
# Use non-root user for security
|
21
|
-
USER easterobot
|
22
|
-
|
23
20
|
# Change the working directory to the `src` directory
|
24
21
|
WORKDIR /src
|
25
22
|
|
@@ -32,8 +29,16 @@ RUN uv sync --frozen --no-install-project
|
|
32
29
|
# Copy the project into the image
|
33
30
|
COPY . .
|
34
31
|
|
32
|
+
# Fix permissions
|
33
|
+
RUN find /src -type d -exec chmod 755 {} \;
|
34
|
+
RUN find /src -type f -exec chmod 644 {} \;
|
35
|
+
RUN chmod +x /src/entrypoint.sh
|
36
|
+
|
35
37
|
# Sync the project
|
36
38
|
RUN uv sync --frozen
|
37
39
|
|
40
|
+
# Use non-root user for security
|
41
|
+
USER easterobot
|
42
|
+
|
38
43
|
# Default command (use exec form for signal handling)
|
39
44
|
CMD ["/src/entrypoint.sh"]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: easterobot
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.3.1
|
4
4
|
Summary: Discord bot for Easter.
|
5
5
|
Project-URL: Homepage, https://github.com/Dashstrom/easterobot
|
6
6
|
Project-URL: Repository, https://github.com/Dashstrom/easterobot
|
@@ -121,6 +121,9 @@ from `PyPI <https://pypi.org/project>`_
|
|
121
121
|
cd easterobot
|
122
122
|
echo "DISCORD_TOKEN=YOU_MUST_PUT_YOUR_TOKEN_HERE" > .env
|
123
123
|
|
124
|
+
# Can be unsafe (and for each update)
|
125
|
+
chmod -R 700 . && mkdir data -p && chmod 777 data
|
126
|
+
|
124
127
|
# Run the docker container
|
125
128
|
docker compose up -d
|
126
129
|
|
@@ -130,6 +133,12 @@ from `PyPI <https://pypi.org/project>`_
|
|
130
133
|
# Remove the container (not the data)
|
131
134
|
docker compose down --rmi all
|
132
135
|
|
136
|
+
# Update
|
137
|
+
git reset --hard HEAD && git pull
|
138
|
+
|
139
|
+
# One-line update
|
140
|
+
docker compose down --rmi all && git reset --hard HEAD && git pull && chmod -R 700 . && mkdir data -p && chmod 777 data && docker compose up -d
|
141
|
+
|
133
142
|
Configuration directory
|
134
143
|
#######################
|
135
144
|
|
@@ -83,6 +83,9 @@ from `PyPI <https://pypi.org/project>`_
|
|
83
83
|
cd easterobot
|
84
84
|
echo "DISCORD_TOKEN=YOU_MUST_PUT_YOUR_TOKEN_HERE" > .env
|
85
85
|
|
86
|
+
# Can be unsafe (and for each update)
|
87
|
+
chmod -R 700 . && mkdir data -p && chmod 777 data
|
88
|
+
|
86
89
|
# Run the docker container
|
87
90
|
docker compose up -d
|
88
91
|
|
@@ -92,6 +95,12 @@ from `PyPI <https://pypi.org/project>`_
|
|
92
95
|
# Remove the container (not the data)
|
93
96
|
docker compose down --rmi all
|
94
97
|
|
98
|
+
# Update
|
99
|
+
git reset --hard HEAD && git pull
|
100
|
+
|
101
|
+
# One-line update
|
102
|
+
docker compose down --rmi all && git reset --hard HEAD && git pull && chmod -R 700 . && mkdir data -p && chmod 777 data && docker compose up -d
|
103
|
+
|
95
104
|
Configuration directory
|
96
105
|
#######################
|
97
106
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
"""Configuration for all tests."""
|
2
|
+
|
3
|
+
from collections.abc import AsyncIterator
|
4
|
+
from typing import Any
|
5
|
+
|
6
|
+
import py
|
7
|
+
import pytest
|
8
|
+
import pytest_asyncio
|
9
|
+
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession
|
10
|
+
|
11
|
+
from easterobot import __author__
|
12
|
+
from easterobot.bot import Easterobot
|
13
|
+
from easterobot.config import MConfig
|
14
|
+
|
15
|
+
|
16
|
+
@pytest.fixture(autouse=True)
|
17
|
+
def _add_author(doctest_namespace: dict[str, Any]) -> None:
|
18
|
+
"""Update doctest namespace."""
|
19
|
+
doctest_namespace["author"] = __author__
|
20
|
+
|
21
|
+
|
22
|
+
@pytest.fixture
|
23
|
+
def bot(tmpdir: py.path.LocalPath) -> Easterobot:
|
24
|
+
"""Get a bot ready-to-use."""
|
25
|
+
return Easterobot.generate(str(tmpdir), env=True)
|
26
|
+
|
27
|
+
|
28
|
+
@pytest.fixture
|
29
|
+
def engine(bot: Easterobot) -> AsyncEngine:
|
30
|
+
"""Get a bot ready-to-use."""
|
31
|
+
return bot.engine
|
32
|
+
|
33
|
+
|
34
|
+
@pytest_asyncio.fixture
|
35
|
+
async def session(engine: AsyncEngine) -> AsyncIterator[AsyncSession]:
|
36
|
+
"""Get a bot ready-to-use."""
|
37
|
+
async with AsyncSession(engine, expire_on_commit=False) as session:
|
38
|
+
yield session
|
39
|
+
|
40
|
+
|
41
|
+
@pytest.fixture
|
42
|
+
def config(bot: Easterobot) -> MConfig:
|
43
|
+
"""Get a bot ready-to-use."""
|
44
|
+
return bot.config
|
@@ -1,7 +1,6 @@
|
|
1
1
|
"""Main program."""
|
2
2
|
|
3
3
|
import logging
|
4
|
-
import logging.config
|
5
4
|
import pathlib
|
6
5
|
import shutil
|
7
6
|
from getpass import getpass
|
@@ -37,7 +36,8 @@ from .config import (
|
|
37
36
|
T = TypeVar("T")
|
38
37
|
|
39
38
|
logger = logging.getLogger(__name__)
|
40
|
-
INTENTS = discord.Intents.
|
39
|
+
INTENTS = discord.Intents.default()
|
40
|
+
INTENTS.message_content = True
|
41
41
|
|
42
42
|
|
43
43
|
class Easterobot(discord.ext.commands.Bot):
|
@@ -47,15 +47,24 @@ class Easterobot(discord.ext.commands.Bot):
|
|
47
47
|
|
48
48
|
def __init__(self, config: MConfig) -> None:
|
49
49
|
"""Initialise Easterbot."""
|
50
|
+
# Initialize intents
|
51
|
+
intents = discord.Intents.default()
|
52
|
+
if config.message_content:
|
53
|
+
intents.message_content = True
|
54
|
+
|
55
|
+
# Remove warning about VoiceClient
|
56
|
+
discord.VoiceClient.warn_nacl = False
|
57
|
+
|
58
|
+
# Initialize Bot
|
50
59
|
super().__init__(
|
51
60
|
command_prefix=".",
|
52
61
|
description="Bot discord pour faire la chasse aux œufs",
|
53
62
|
activity=discord.Game(name="rechercher des œufs"),
|
54
63
|
intents=INTENTS,
|
55
64
|
)
|
56
|
-
self.config = config
|
57
65
|
|
58
66
|
# Attributes
|
67
|
+
self.config = config
|
59
68
|
self.app_commands: list[discord.app_commands.AppCommand] = []
|
60
69
|
self.app_emojis: dict[str, discord.Emoji] = {}
|
61
70
|
|
@@ -89,9 +98,9 @@ class Easterobot(discord.ext.commands.Bot):
|
|
89
98
|
cls,
|
90
99
|
destination: Union[Path, str],
|
91
100
|
*,
|
92
|
-
token: Optional[str],
|
93
|
-
env: bool,
|
94
|
-
interactive: bool,
|
101
|
+
token: Optional[str] = None,
|
102
|
+
env: bool = False,
|
103
|
+
interactive: bool = False,
|
95
104
|
) -> "Easterobot":
|
96
105
|
"""Generate all data."""
|
97
106
|
destination = Path(destination).resolve()
|
@@ -12,6 +12,7 @@ from easterobot.commands.game import (
|
|
12
12
|
tictactoe_command,
|
13
13
|
)
|
14
14
|
from easterobot.commands.help import help_command
|
15
|
+
from easterobot.commands.info import info_command
|
15
16
|
from easterobot.commands.reset import reset_command
|
16
17
|
from easterobot.commands.search import search_command
|
17
18
|
from easterobot.commands.top import top_command
|
@@ -24,6 +25,7 @@ __all__ = [
|
|
24
25
|
"egg_command_group",
|
25
26
|
"enable_command",
|
26
27
|
"help_command",
|
28
|
+
"info_command",
|
27
29
|
"reset_command",
|
28
30
|
"rockpaperscissor_command",
|
29
31
|
"search_command",
|
@@ -33,4 +35,5 @@ __all__ = [
|
|
33
35
|
|
34
36
|
|
35
37
|
async def setup(bot: Easterobot) -> None:
|
38
|
+
egg_command_group.name = bot.config.group
|
36
39
|
bot.tree.add_command(egg_command_group)
|
@@ -170,7 +170,10 @@ def controlled_command( # noqa: C901, PLR0915
|
|
170
170
|
try:
|
171
171
|
await f(cast(Context, interaction), *args, **kwargs)
|
172
172
|
except InterruptedCommandError:
|
173
|
-
logger.
|
173
|
+
logger.warning(
|
174
|
+
"InterruptedCommandError occur for %s",
|
175
|
+
event_repr,
|
176
|
+
)
|
174
177
|
async with (
|
175
178
|
AsyncSession(interaction.client.engine) as session,
|
176
179
|
cooldown_lock,
|
@@ -9,7 +9,8 @@ from .base import Context, controlled_command, egg_command_group
|
|
9
9
|
|
10
10
|
|
11
11
|
@egg_command_group.command(
|
12
|
-
name="disable",
|
12
|
+
name="disable",
|
13
|
+
description="Désactiver la chasse aux œufs dans le salon",
|
13
14
|
)
|
14
15
|
@controlled_command(cooldown=True, manage_channels=True)
|
15
16
|
async def disable_command(ctx: Context) -> None:
|
@@ -13,7 +13,8 @@ from .base import Context, controlled_command, egg_command_group
|
|
13
13
|
|
14
14
|
|
15
15
|
@egg_command_group.command(
|
16
|
-
name="edit",
|
16
|
+
name="edit",
|
17
|
+
description="Editer le nombre d'œufs d'un membre",
|
17
18
|
)
|
18
19
|
@controlled_command(cooldown=True, administrator=True)
|
19
20
|
async def edit_command(
|
@@ -9,7 +9,8 @@ from .base import Context, controlled_command, egg_command_group
|
|
9
9
|
|
10
10
|
|
11
11
|
@egg_command_group.command(
|
12
|
-
name="enable",
|
12
|
+
name="enable",
|
13
|
+
description="Activer la chasse dans le salon",
|
13
14
|
)
|
14
15
|
@controlled_command(
|
15
16
|
cooldown=True,
|
@@ -130,25 +130,28 @@ async def game_dual( # noqa: C901, D103, PLR0912
|
|
130
130
|
await session.commit()
|
131
131
|
|
132
132
|
# Play the game
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
e.
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
e.
|
147
|
-
|
133
|
+
winner = None
|
134
|
+
try:
|
135
|
+
game = cls(ctx.user, member, msg)
|
136
|
+
await ctx.client.game.run(game)
|
137
|
+
winner = await game.wait_winner()
|
138
|
+
finally:
|
139
|
+
# Give eggs to the winner or remove previous one
|
140
|
+
async with lock:
|
141
|
+
for e in e1:
|
142
|
+
e.lock = False
|
143
|
+
if winner:
|
144
|
+
e.user_id = winner.id
|
145
|
+
for e in e2:
|
146
|
+
e.lock = False
|
147
|
+
if winner:
|
148
|
+
e.user_id = winner.id
|
149
|
+
await session.commit()
|
148
150
|
|
149
151
|
|
150
152
|
@egg_command_group.command(
|
151
|
-
name="connect4",
|
153
|
+
name="connect4",
|
154
|
+
description="Lancer une partie de puissance 4",
|
152
155
|
)
|
153
156
|
@controlled_command(cooldown=True, channel_permissions={"send_messages": True})
|
154
157
|
async def connect4_command(
|
@@ -161,12 +164,13 @@ async def connect4_command(
|
|
161
164
|
|
162
165
|
|
163
166
|
@egg_command_group.command(
|
164
|
-
name="tictactoe",
|
167
|
+
name="tictactoe",
|
168
|
+
description="Lancer une partie de morpion",
|
165
169
|
)
|
166
|
-
@controlled_command(cooldown=True)
|
170
|
+
@controlled_command(cooldown=True, channel_permissions={"send_messages": True})
|
167
171
|
async def tictactoe_command(
|
168
172
|
ctx: Context,
|
169
|
-
member: discord.Member,
|
173
|
+
member: Optional[discord.Member] = None,
|
170
174
|
bet: app_commands.Range[int, 0] = 0,
|
171
175
|
) -> None:
|
172
176
|
"""Run a tictactoe."""
|
@@ -175,12 +179,12 @@ async def tictactoe_command(
|
|
175
179
|
|
176
180
|
@egg_command_group.command(
|
177
181
|
name="rockpaperscissor",
|
178
|
-
description="Lancer une partie de pierre papier ciseaux
|
182
|
+
description="Lancer une partie de pierre papier ciseaux",
|
179
183
|
)
|
180
|
-
@controlled_command(cooldown=True)
|
184
|
+
@controlled_command(cooldown=True, channel_permissions={"send_messages": True})
|
181
185
|
async def rockpaperscissor_command(
|
182
186
|
ctx: Context,
|
183
|
-
member: discord.Member,
|
187
|
+
member: Optional[discord.Member] = None,
|
184
188
|
bet: app_commands.Range[int, 0] = 0,
|
185
189
|
) -> None:
|
186
190
|
"""Run a rockpaperscissor."""
|
@@ -7,8 +7,11 @@ from easterobot.hunts.hunt import embed
|
|
7
7
|
from .base import Context, controlled_command, egg_command_group
|
8
8
|
|
9
9
|
|
10
|
-
@egg_command_group.command(
|
11
|
-
|
10
|
+
@egg_command_group.command(
|
11
|
+
name="help",
|
12
|
+
description="Obtenir l'aide des commandes",
|
13
|
+
)
|
14
|
+
@controlled_command(cooldown=True, channel_permissions={"send_messages": True})
|
12
15
|
async def help_command(ctx: Context) -> None:
|
13
16
|
"""Help command."""
|
14
17
|
emb = embed(
|
@@ -30,4 +33,4 @@ async def help_command(ctx: Context) -> None:
|
|
30
33
|
value=f"{option.description}",
|
31
34
|
inline=False,
|
32
35
|
)
|
33
|
-
await ctx.response.send_message(embed=emb
|
36
|
+
await ctx.response.send_message(embed=emb)
|
@@ -0,0 +1,61 @@
|
|
1
|
+
"""Command basket."""
|
2
|
+
|
3
|
+
import asyncio
|
4
|
+
from typing import Optional
|
5
|
+
|
6
|
+
import discord
|
7
|
+
from discord import app_commands
|
8
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
9
|
+
|
10
|
+
from easterobot.commands.base import (
|
11
|
+
Context,
|
12
|
+
controlled_command,
|
13
|
+
egg_command_group,
|
14
|
+
)
|
15
|
+
from easterobot.hunts.hunt import embed
|
16
|
+
from easterobot.hunts.rank import Ranking
|
17
|
+
|
18
|
+
|
19
|
+
@egg_command_group.command(
|
20
|
+
name="info",
|
21
|
+
description="Avoir des informations sur la chance d'un joueur",
|
22
|
+
)
|
23
|
+
@app_commands.describe(
|
24
|
+
user="Joueur a inspecter",
|
25
|
+
)
|
26
|
+
@controlled_command(cooldown=True)
|
27
|
+
async def info_command(
|
28
|
+
ctx: Context, user: Optional[discord.Member] = None
|
29
|
+
) -> None:
|
30
|
+
"""Show current user basket."""
|
31
|
+
# Delay the response
|
32
|
+
await ctx.response.defer(ephemeral=True)
|
33
|
+
|
34
|
+
# Set the user of the basket
|
35
|
+
hunter = user or ctx.user
|
36
|
+
|
37
|
+
async with AsyncSession(ctx.client.engine) as session:
|
38
|
+
ranking, member_luck = await asyncio.gather(
|
39
|
+
Ranking.from_guild(session, ctx.guild_id),
|
40
|
+
ctx.client.hunt.get_luck(
|
41
|
+
session=session,
|
42
|
+
guild_id=hunter.guild.id,
|
43
|
+
user_id=hunter.id,
|
44
|
+
sleep_hours=False,
|
45
|
+
),
|
46
|
+
)
|
47
|
+
hunter_rank = ranking.get(hunter.id)
|
48
|
+
|
49
|
+
await ctx.followup.send(
|
50
|
+
embed=embed(
|
51
|
+
title=f"Informations sur {hunter.display_name}",
|
52
|
+
description=(
|
53
|
+
f"Classement : {hunter_rank.badge}\n"
|
54
|
+
f"Nombre d'oeufs : `{hunter_rank.eggs}`\n"
|
55
|
+
f"Chance brute : `{member_luck.luck:.0%}`\n"
|
56
|
+
f"Chance de trouver un oeuf : `{member_luck.discovered:.0%}`\n"
|
57
|
+
f"Chance de se faire voler : `{member_luck.spotted:.0%}`"
|
58
|
+
),
|
59
|
+
),
|
60
|
+
ephemeral=True,
|
61
|
+
)
|
@@ -14,7 +14,8 @@ from .base import Context, Interaction, controlled_command, egg_command_group
|
|
14
14
|
|
15
15
|
|
16
16
|
@egg_command_group.command(
|
17
|
-
name="reset",
|
17
|
+
name="reset",
|
18
|
+
description="Réinitialiser la chasse aux œufs",
|
18
19
|
)
|
19
20
|
@controlled_command(cooldown=True, administrator=True)
|
20
21
|
async def reset_command(ctx: Context) -> None:
|
@@ -4,10 +4,10 @@ import logging
|
|
4
4
|
from typing import Any
|
5
5
|
|
6
6
|
import discord
|
7
|
-
from sqlalchemy import
|
7
|
+
from sqlalchemy import select
|
8
8
|
from sqlalchemy.ext.asyncio import AsyncSession
|
9
9
|
|
10
|
-
from easterobot.config import
|
10
|
+
from easterobot.config import agree
|
11
11
|
from easterobot.hunts.hunt import embed
|
12
12
|
from easterobot.models import Egg, Hunt
|
13
13
|
|
@@ -21,7 +21,10 @@ from .base import (
|
|
21
21
|
logger = logging.getLogger("easterobot")
|
22
22
|
|
23
23
|
|
24
|
-
@egg_command_group.command(
|
24
|
+
@egg_command_group.command(
|
25
|
+
name="search",
|
26
|
+
description="Rechercher un œuf",
|
27
|
+
)
|
25
28
|
@controlled_command(cooldown=True, channel_permissions={"send_messages": True})
|
26
29
|
async def search_command(ctx: Context) -> None:
|
27
30
|
"""Search command."""
|
@@ -34,7 +37,7 @@ async def search_command(ctx: Context) -> None:
|
|
34
37
|
"La chasse aux œufs n'est pas activée dans ce salon",
|
35
38
|
ephemeral=True,
|
36
39
|
)
|
37
|
-
|
40
|
+
raise InterruptedCommandError
|
38
41
|
try:
|
39
42
|
await ctx.response.defer(ephemeral=False)
|
40
43
|
except discord.errors.NotFound as err:
|
@@ -42,39 +45,15 @@ async def search_command(ctx: Context) -> None:
|
|
42
45
|
name = ctx.user.display_name
|
43
46
|
|
44
47
|
async with AsyncSession(ctx.client.engine) as session:
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
.
|
50
|
-
.group_by(Egg.user_id)
|
51
|
-
.order_by(func.count().label("max").desc())
|
52
|
-
.limit(1)
|
53
|
-
)
|
54
|
-
egg_max = egg_max or 0
|
55
|
-
egg_count = await session.scalar(
|
56
|
-
select(func.count().label("count")).where(
|
57
|
-
and_(
|
58
|
-
Egg.guild_id == ctx.guild.id,
|
59
|
-
Egg.user_id == ctx.user.id,
|
60
|
-
)
|
61
|
-
)
|
48
|
+
luck = await ctx.client.hunt.get_luck(
|
49
|
+
guild_id=ctx.guild_id,
|
50
|
+
user_id=ctx.user.id,
|
51
|
+
session=session,
|
52
|
+
sleep_hours=ctx.client.config.in_sleep_hours(),
|
62
53
|
)
|
63
|
-
if egg_count is None:
|
64
|
-
egg_count = 0
|
65
|
-
ratio = egg_count / egg_max if egg_max != 0 else 1.0
|
66
|
-
|
67
|
-
discovered = ctx.client.config.commands.search.discovered
|
68
|
-
prob_d = (discovered.max - discovered.min) * (1 - ratio) + discovered.min
|
69
54
|
|
70
|
-
|
71
|
-
|
72
|
-
sample_s = RAND.random()
|
73
|
-
spotted = ctx.client.config.commands.search.spotted
|
74
|
-
prob_s = (spotted.max - spotted.min) * ratio + spotted.min
|
75
|
-
logger.info("discovered: %.2f > %.2f", prob_d, sample_d)
|
76
|
-
if prob_s > sample_s and egg_count > spotted.shield:
|
77
|
-
logger.info("spotted: %.2f > %.2f", prob_s, sample_s)
|
55
|
+
if luck.sample_discovered():
|
56
|
+
if luck.sample_spotted():
|
78
57
|
|
79
58
|
async def send_method(
|
80
59
|
*args: Any, **kwargs: Any
|
@@ -88,7 +67,6 @@ async def search_command(ctx: Context) -> None:
|
|
88
67
|
send_method=send_method,
|
89
68
|
)
|
90
69
|
else:
|
91
|
-
logger.info("found: %.2f > %.2f", prob_s, sample_s)
|
92
70
|
emoji = ctx.client.egg_emotes.rand()
|
93
71
|
async with AsyncSession(ctx.client.engine) as session:
|
94
72
|
session.add(
|
@@ -105,7 +83,7 @@ async def search_command(ctx: Context) -> None:
|
|
105
83
|
"%s (%s) got an egg for a total %s in %s",
|
106
84
|
ctx.user,
|
107
85
|
ctx.user.id,
|
108
|
-
agree("{0} egg", "{0} eggs", egg_count),
|
86
|
+
agree("{0} egg", "{0} eggs", luck.egg_count),
|
109
87
|
ctx.channel.jump_url,
|
110
88
|
)
|
111
89
|
await ctx.followup.send(
|
@@ -113,15 +91,14 @@ async def search_command(ctx: Context) -> None:
|
|
113
91
|
title=f"{name} récupère un œuf",
|
114
92
|
description=ctx.client.config.hidden(ctx.user),
|
115
93
|
thumbnail=emoji.url,
|
116
|
-
egg_count=egg_count + 1,
|
94
|
+
egg_count=luck.egg_count + 1,
|
117
95
|
)
|
118
96
|
)
|
119
97
|
else:
|
120
|
-
logger.info("failed: %.2f > %.2f", prob_d, sample_d)
|
121
98
|
await ctx.followup.send(
|
122
99
|
embed=embed(
|
123
100
|
title=f"{name} repart bredouille",
|
124
101
|
description=ctx.client.config.failed(ctx.user),
|
125
|
-
egg_count=egg_count,
|
102
|
+
egg_count=luck.egg_count,
|
126
103
|
)
|
127
104
|
)
|