mirror of
https://github.com/wlinator/luminara.git
synced 2024-10-02 18:23:12 +00:00
Merge pull request #51 from wlinator/coinflip
feat: Add coinflip command with optional prediction
This commit is contained in:
commit
e6b3c87fac
4 changed files with 197 additions and 1 deletions
|
@ -1 +1,2 @@
|
|||
data/
|
||||
.venv/
|
||||
|
|
|
@ -78,6 +78,18 @@
|
|||
"case_type_field": "Type:",
|
||||
"case_type_field_value": "`{0}`",
|
||||
"case_type_field_value_with_duration": "`{0} ({1})`",
|
||||
"coinflip_correct_prediction_author": "Correct Prediction!",
|
||||
"coinflip_correct_prediction_description": "the coin landed on **{0}**. You predicted correctly!",
|
||||
"coinflip_flipping_animation_1": "\ud83e\ude99 Flipping...",
|
||||
"coinflip_flipping_animation_2": "\ud83e\ude99 Flipping..",
|
||||
"coinflip_flipping_animation_3": "\ud83e\ude99 Flipping.",
|
||||
"coinflip_flipping_author": "flipping a Coin",
|
||||
"coinflip_flipping_description": "the coin is in the air...",
|
||||
"coinflip_invalid_prediction_description": "please enter a valid prediction ('heads'/'h' or 'tails'/'t').",
|
||||
"coinflip_result_author": "Coin Flip Result",
|
||||
"coinflip_result_description": "the coin landed on **{0}**.",
|
||||
"coinflip_wrong_prediction_author": "Wrong Prediction",
|
||||
"coinflip_wrong_prediction_description": "the coin landed on **{0}**. Your prediction was incorrect.",
|
||||
"config_author": "Server Configuration",
|
||||
"config_birthday_channel_set": "birthday announcements will be sent in {0}.",
|
||||
"config_birthday_module_already_disabled": "the birthday module was already disabled.",
|
||||
|
@ -150,6 +162,7 @@
|
|||
"error_actionable_hierarchy_bot": "I don't have permission to perform this action on this user due to role hierarchy.",
|
||||
"error_actionable_hierarchy_user": "you don't have permission to perform this action on this user due to role hierarchy.",
|
||||
"error_actionable_self": "you can't perform this action on yourself.",
|
||||
"error_already_flipping_coin_description": "you already have a coinflip running.",
|
||||
"error_already_playing_blackjack": "you already have a game of blackjack running.",
|
||||
"error_birthdays_disabled_author": "Birthdays Disabled",
|
||||
"error_birthdays_disabled_description": "birthdays are disabled in this server.",
|
||||
|
|
182
modules/economy/coinflip.py
Normal file
182
modules/economy/coinflip.py
Normal file
|
@ -0,0 +1,182 @@
|
|||
import asyncio
|
||||
import random
|
||||
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
|
||||
import lib.format
|
||||
from lib.client import Luminara
|
||||
from lib.const import CONST
|
||||
from lib.exceptions import LumiException
|
||||
from ui.embeds import Builder
|
||||
|
||||
PREDICTION_MAPPING = {
|
||||
"h": "heads",
|
||||
"head": "heads",
|
||||
"heads": "heads",
|
||||
"t": "tails",
|
||||
"tail": "tails",
|
||||
"tails": "tails",
|
||||
}
|
||||
|
||||
COIN_FLIP_DELAY = 0.5 # seconds
|
||||
|
||||
|
||||
class ActiveCoinflips:
|
||||
def __init__(self):
|
||||
self._flips: set[int] = set()
|
||||
|
||||
def add(self, user_id: int) -> bool:
|
||||
if user_id in self._flips:
|
||||
return False
|
||||
self._flips.add(user_id)
|
||||
return True
|
||||
|
||||
def remove(self, user_id: int) -> None:
|
||||
self._flips.discard(user_id)
|
||||
|
||||
|
||||
class Coinflip(commands.Cog):
|
||||
def __init__(self, bot: Luminara) -> None:
|
||||
self.bot: Luminara = bot
|
||||
self.coinflip.usage = lib.format.generate_usage(self.coinflip)
|
||||
self.active_coinflips = ActiveCoinflips()
|
||||
|
||||
@commands.command(
|
||||
name="coinflip",
|
||||
aliases=["cf"],
|
||||
)
|
||||
@commands.guild_only()
|
||||
async def coinflip(
|
||||
self,
|
||||
ctx: commands.Context[Luminara],
|
||||
*,
|
||||
prediction: str | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Flip a coin. Optionally predict the outcome.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ctx : commands.Context[Luminara]
|
||||
The context of the command.
|
||||
prediction : str, optional
|
||||
The predicted outcome ('heads', 'h', 'tails', or 't').
|
||||
"""
|
||||
await self._coinflip(ctx, prediction)
|
||||
|
||||
@app_commands.command(name="coinflip", description="Flip a coin. Optionally predict the outcome.")
|
||||
@app_commands.guild_only()
|
||||
@app_commands.choices(
|
||||
prediction=[
|
||||
app_commands.Choice(name="Heads", value="heads"),
|
||||
app_commands.Choice(name="Tails", value="tails"),
|
||||
],
|
||||
)
|
||||
async def coinflip_slash(
|
||||
self,
|
||||
interaction: discord.Interaction,
|
||||
prediction: app_commands.Choice[str] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Flip a coin. Optionally predict the outcome.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
interaction : discord.Interaction
|
||||
The interaction of the command.
|
||||
prediction : app_commands.Choice[str], optional
|
||||
The predicted outcome ('heads' or 'tails').
|
||||
"""
|
||||
await self._coinflip(interaction, prediction.value if prediction else None)
|
||||
|
||||
async def _coinflip(self, ctx: commands.Context[Luminara] | discord.Interaction, prediction: str | None) -> None:
|
||||
if isinstance(ctx, commands.Context):
|
||||
author = ctx.author
|
||||
reply = ctx.reply
|
||||
else:
|
||||
author = ctx.user
|
||||
reply = ctx.followup.send
|
||||
|
||||
if not self.active_coinflips.add(author.id):
|
||||
raise LumiException(CONST.STRINGS["error_already_flipping_coin_description"])
|
||||
|
||||
try:
|
||||
result = random.choice(["heads", "tails"])
|
||||
|
||||
if prediction:
|
||||
prediction = PREDICTION_MAPPING.get(prediction.lower())
|
||||
if not prediction:
|
||||
raise LumiException(CONST.STRINGS["coinflip_invalid_prediction_description"])
|
||||
|
||||
flip_embed = Builder.create_embed(
|
||||
Builder.INFO,
|
||||
user_name=author.name,
|
||||
author_text=CONST.STRINGS["coinflip_flipping_author"],
|
||||
description=CONST.STRINGS["coinflip_flipping_description"],
|
||||
)
|
||||
|
||||
if isinstance(ctx, commands.Context):
|
||||
flip_message = await reply(embed=flip_embed)
|
||||
else:
|
||||
await ctx.response.send_message(embed=flip_embed)
|
||||
flip_message = await ctx.original_response()
|
||||
|
||||
# Add a short delay before starting the coin flip animation
|
||||
await asyncio.sleep(COIN_FLIP_DELAY)
|
||||
|
||||
if isinstance(flip_message, discord.Message):
|
||||
await self._animate_coin_flip(flip_message, author.name)
|
||||
|
||||
if prediction:
|
||||
predicted_correctly = prediction == result
|
||||
|
||||
embed_type = Builder.SUCCESS if predicted_correctly else Builder.ERROR
|
||||
author_text = CONST.STRINGS[
|
||||
"coinflip_correct_prediction_author" if predicted_correctly else "coinflip_wrong_prediction_author"
|
||||
]
|
||||
description = CONST.STRINGS[
|
||||
"coinflip_correct_prediction_description"
|
||||
if predicted_correctly
|
||||
else "coinflip_wrong_prediction_description"
|
||||
].format(result)
|
||||
|
||||
embed = Builder.create_embed(
|
||||
embed_type,
|
||||
user_name=author.name,
|
||||
author_text=author_text,
|
||||
description=description,
|
||||
)
|
||||
else:
|
||||
embed = Builder.create_embed(
|
||||
Builder.INFO,
|
||||
user_name=author.name,
|
||||
author_text=CONST.STRINGS["coinflip_result_author"],
|
||||
description=CONST.STRINGS["coinflip_result_description"].format(result),
|
||||
)
|
||||
|
||||
if flip_message is not None:
|
||||
await flip_message.edit(embed=embed)
|
||||
finally:
|
||||
self.active_coinflips.remove(author.id)
|
||||
|
||||
async def _animate_coin_flip(self, flip_message: discord.Message, author_name: str) -> None:
|
||||
animations = [
|
||||
CONST.STRINGS["coinflip_flipping_animation_1"],
|
||||
CONST.STRINGS["coinflip_flipping_animation_2"],
|
||||
CONST.STRINGS["coinflip_flipping_animation_3"],
|
||||
]
|
||||
for animation in animations:
|
||||
flip_embed = Builder.create_embed(
|
||||
Builder.INFO,
|
||||
user_name=author_name,
|
||||
author_text=CONST.STRINGS["coinflip_flipping_author"],
|
||||
description=animation,
|
||||
)
|
||||
await flip_message.edit(embed=flip_embed)
|
||||
await asyncio.sleep(COIN_FLIP_DELAY)
|
||||
|
||||
|
||||
async def setup(bot: Luminara) -> None:
|
||||
await bot.add_cog(Coinflip(bot))
|
|
@ -88,7 +88,7 @@ info:
|
|||
title: Luminara
|
||||
author: wlinator
|
||||
license: GNU General Public License v3.0
|
||||
version: "3.0.1"
|
||||
version: "3.1.0"
|
||||
repository_url: https://git.wlinator.org/Luminara/Lumi
|
||||
invite_url: https://discord.com/oauth2/authorize?client_id=1038050427272429588&permissions=8&scope=bot
|
||||
|
||||
|
|
Loading…
Reference in a new issue