First Commit
This commit is contained in:
Executable
+979
@@ -0,0 +1,979 @@
|
||||
import discord
|
||||
from random import shuffle, choices, choice
|
||||
from discord.ext import commands
|
||||
from utils.sql_commands import DatabaseManager
|
||||
from utils.bank_functions import bank_data, update_money
|
||||
from datetime import datetime, timedelta
|
||||
import asyncio
|
||||
import random
|
||||
|
||||
# --- Constants and Configs ---
|
||||
|
||||
lottery_list = ["🎁", "🎮", "🎷", "🔫", "📸", "🎃", "🏅"]
|
||||
weights = [0.15, 0.1, 0.02, 0.2, 0.1, 0.28, 0.2]
|
||||
|
||||
lottery_win = {
|
||||
"🎁": 2,
|
||||
"🎁🎁": 5,
|
||||
"🎁🎁🎁": 50,
|
||||
"🔫🔫🔫": 3,
|
||||
"📸📸📸": 5,
|
||||
"🎃🎃🎃": 7,
|
||||
"🏅🏅🏅": 10,
|
||||
"🎮🎮🎮": 25,
|
||||
"🎷🎷🎷": 1000,
|
||||
}
|
||||
|
||||
bj_values = {
|
||||
"2♦️": 2,
|
||||
"2♥️": 2,
|
||||
"2♣️": 2,
|
||||
"2♠️": 2,
|
||||
"3♦️": 3,
|
||||
"3♥️": 3,
|
||||
"3♣️": 3,
|
||||
"3♠️": 3,
|
||||
"4♦️": 4,
|
||||
"4♥️": 4,
|
||||
"4♣️": 4,
|
||||
"4♠️": 4,
|
||||
"5♦️": 5,
|
||||
"5♥️": 5,
|
||||
"5♣️": 5,
|
||||
"5♠️": 5,
|
||||
"6♦️": 6,
|
||||
"6♥️": 6,
|
||||
"6♣️": 6,
|
||||
"6♠️": 6,
|
||||
"7♦️": 7,
|
||||
"7♥️": 7,
|
||||
"7♣️": 7,
|
||||
"7♠️": 7,
|
||||
"8♦️": 8,
|
||||
"8♥️": 8,
|
||||
"8♣️": 8,
|
||||
"8♠️": 8,
|
||||
"9♦️": 9,
|
||||
"9♥️": 9,
|
||||
"9♣️": 9,
|
||||
"9♠️": 9,
|
||||
"10♦️": 10,
|
||||
"10♥️": 10,
|
||||
"10♣️": 10,
|
||||
"10♠️": 10,
|
||||
"J♦️": 10,
|
||||
"J♥️": 10,
|
||||
"J♣️": 10,
|
||||
"J♠️": 10,
|
||||
"Q♦️": 10,
|
||||
"Q♥️": 10,
|
||||
"Q♣️": 10,
|
||||
"Q♠️": 10,
|
||||
"K♦️": 10,
|
||||
"K♥️": 10,
|
||||
"K♣️": 10,
|
||||
"K♠️": 10,
|
||||
"A♦️": 11,
|
||||
"A♥️": 11,
|
||||
"A♣️": 11,
|
||||
"A♠️": 11,
|
||||
}
|
||||
|
||||
ROOMS_FILE = "active_rooms.json"
|
||||
|
||||
# --- Blackjack Classes and Helpers ---
|
||||
|
||||
|
||||
class Deck:
|
||||
def __init__(self):
|
||||
self.deck = list(bj_values.keys())
|
||||
shuffle(self.deck)
|
||||
|
||||
async def deal(self):
|
||||
return self.deck.pop()
|
||||
|
||||
|
||||
class Hand:
|
||||
def __init__(self, name, bet):
|
||||
self.cards = []
|
||||
self.value = 0
|
||||
self.aces = 0
|
||||
self.bust = False
|
||||
self.name = name
|
||||
self.bet = bet
|
||||
|
||||
async def add_card(self, card):
|
||||
self.cards.append(card)
|
||||
self.aces = ("".join(self.cards)).count("A")
|
||||
value = 0
|
||||
for card in self.cards:
|
||||
value += bj_values[card]
|
||||
self.value = value
|
||||
while self.value > 21 and self.aces:
|
||||
self.value -= 10
|
||||
self.aces -= 1
|
||||
|
||||
|
||||
async def hit(deck, hand):
|
||||
await hand.add_card(await deck.deal())
|
||||
|
||||
|
||||
async def payout(ctx, play, amount, multiplier, db):
|
||||
player_balance = int(
|
||||
db.fetch_one("SELECT WALLET FROM economy WHERE ID = %s", (ctx.author.id,)).get(
|
||||
"WALLET", 0
|
||||
)
|
||||
)
|
||||
db.execute_query(
|
||||
"UPDATE economy SET WALLET = %s WHERE ID = %s",
|
||||
(player_balance + amount * (multiplier - 1), ctx.author.id),
|
||||
)
|
||||
await ctx.reply(
|
||||
f"{play}\nBet: {amount:,}\nYou won {amount * multiplier:,} <:flooney:1194943899765051473>"
|
||||
)
|
||||
|
||||
|
||||
async def check_winner(msg: discord.Interaction, player_hand, dealer_hand, db):
|
||||
p_value, d_value = player_hand.value, dealer_hand.value
|
||||
embed = discord.Embed(description="Blackjack")
|
||||
embed.add_field(
|
||||
name="Bet: ",
|
||||
value=f"{player_hand.bet:,}<:flooney:1194943899765051473>",
|
||||
inline=True,
|
||||
)
|
||||
embed.add_field(
|
||||
name=player_hand.name,
|
||||
value=f"{', '.join(player_hand.cards)}: {player_hand.value}",
|
||||
inline=False,
|
||||
)
|
||||
embed.add_field(
|
||||
name=dealer_hand.name,
|
||||
value=f"{', '.join(dealer_hand.cards)}: {dealer_hand.value}",
|
||||
inline=False,
|
||||
)
|
||||
|
||||
# Check for Blackjack
|
||||
if p_value == 21 and len(player_hand.cards) == 2:
|
||||
if d_value == 21 and len(dealer_hand.cards) == 2:
|
||||
embed.add_field(
|
||||
name="Winner:", value="Draw (Both got Blackjack!)", inline=False
|
||||
)
|
||||
player_balance = int(
|
||||
db.fetch_one(
|
||||
"SELECT WALLET FROM economy WHERE ID = %s", (player_hand.name.id,)
|
||||
).get("WALLET", 0)
|
||||
)
|
||||
db.execute_query(
|
||||
"UPDATE economy SET WALLET = %s WHERE ID = %s",
|
||||
(player_balance + player_hand.bet, player_hand.name.id),
|
||||
)
|
||||
else:
|
||||
embed.add_field(
|
||||
name="Winner:", value=f"{player_hand.name} (Blackjack!)", inline=False
|
||||
)
|
||||
player_balance = int(
|
||||
db.fetch_one(
|
||||
"SELECT WALLET FROM economy WHERE ID = %s", (player_hand.name.id,)
|
||||
).get("WALLET", 0)
|
||||
)
|
||||
db.execute_query(
|
||||
"UPDATE economy SET WALLET = %s WHERE ID = %s",
|
||||
(player_balance + int(player_hand.bet * 3), player_hand.name.id),
|
||||
)
|
||||
elif d_value == 21 and len(dealer_hand.cards) == 2:
|
||||
embed.add_field(
|
||||
name="Winner:", value=f"{dealer_hand.name} (Blackjack!)", inline=False
|
||||
)
|
||||
else:
|
||||
if (p_value > d_value and not player_hand.bust) or dealer_hand.bust:
|
||||
embed.add_field(name="Winner:", value=f"{player_hand.name}", inline=False)
|
||||
player_balance = int(
|
||||
db.fetch_one(
|
||||
"SELECT WALLET FROM economy WHERE ID = %s", (player_hand.name.id,)
|
||||
).get("WALLET", 0)
|
||||
)
|
||||
db.execute_query(
|
||||
"UPDATE economy SET WALLET = %s WHERE ID = %s",
|
||||
(player_balance + player_hand.bet * 2, player_hand.name.id),
|
||||
)
|
||||
elif (p_value < d_value and not dealer_hand.bust) or player_hand.bust:
|
||||
embed.add_field(name="Winner:", value=f"{dealer_hand.name}", inline=False)
|
||||
else:
|
||||
embed.add_field(name="Winner:", value="Draw", inline=False)
|
||||
player_balance = int(
|
||||
db.fetch_one(
|
||||
"SELECT WALLET FROM economy WHERE ID = %s", (player_hand.name.id,)
|
||||
).get("WALLET", 0)
|
||||
)
|
||||
db.execute_query(
|
||||
"UPDATE economy SET WALLET = %s WHERE ID = %s",
|
||||
(player_balance + player_hand.bet, player_hand.name.id),
|
||||
)
|
||||
|
||||
await msg.edit_original_response(embed=embed)
|
||||
|
||||
|
||||
async def dealer(msg: discord.Interaction, player_hand, dealer_hand, cards, db):
|
||||
while dealer_hand.value < 17 and not player_hand.bust and not dealer_hand.bust:
|
||||
await hit(cards, dealer_hand)
|
||||
if dealer_hand.value > 21:
|
||||
dealer_hand.bust = True
|
||||
embed = discord.Embed(description="Blackjack")
|
||||
embed.add_field(
|
||||
name="Bet: ",
|
||||
value=f"{player_hand.bet:,}<:flooney:1194943899765051473>",
|
||||
inline=True,
|
||||
)
|
||||
embed.add_field(
|
||||
name=player_hand.name,
|
||||
value=f"{', '.join(player_hand.cards)}: {player_hand.value}",
|
||||
inline=False,
|
||||
)
|
||||
embed.add_field(
|
||||
name=dealer_hand.name,
|
||||
value=f"{', '.join(dealer_hand.cards)}: {dealer_hand.value}",
|
||||
inline=False,
|
||||
)
|
||||
await msg.edit_original_response(embed=embed)
|
||||
await check_winner(msg, player_hand, dealer_hand, db)
|
||||
|
||||
|
||||
class MyView(discord.ui.View):
|
||||
def __init__(self, player_hand, dealer_hand, cards, db):
|
||||
super().__init__()
|
||||
self.player_hand = player_hand
|
||||
self.dealer_hand = dealer_hand
|
||||
self.cards = cards
|
||||
self.db = db
|
||||
|
||||
@discord.ui.button(label="Hit", style=discord.ButtonStyle.primary, emoji="✅")
|
||||
async def hit(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
if interaction.user.id == self.player_hand.name.id:
|
||||
await hit(self.cards, self.player_hand)
|
||||
embed = discord.Embed(description="Blackjack")
|
||||
embed.add_field(
|
||||
name="Bet: ",
|
||||
value=f"{self.player_hand.bet:,}<:flooney:1194943899765051473>",
|
||||
inline=True,
|
||||
)
|
||||
embed.add_field(
|
||||
name=self.player_hand.name,
|
||||
value=f"{', '.join(self.player_hand.cards)}: {self.player_hand.value}",
|
||||
inline=False,
|
||||
)
|
||||
embed.add_field(
|
||||
name=self.dealer_hand.name,
|
||||
value=f"{(self.dealer_hand.cards)[0]}",
|
||||
inline=False,
|
||||
)
|
||||
msg = interaction
|
||||
if self.player_hand.value < 21:
|
||||
await msg.response.edit_message(embed=embed)
|
||||
else:
|
||||
await msg.response.edit_message(embed=embed, view=None)
|
||||
if self.player_hand.value > 21:
|
||||
self.player_hand.bust = True
|
||||
await dealer(
|
||||
msg, self.player_hand, self.dealer_hand, self.cards, self.db
|
||||
)
|
||||
|
||||
@discord.ui.button(label="Stand", style=discord.ButtonStyle.secondary, emoji="🛑")
|
||||
async def stand(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
if interaction.user.id == self.player_hand.name.id:
|
||||
embed = discord.Embed(description="Blackjack")
|
||||
embed.add_field(
|
||||
name="Bet: ",
|
||||
value=f"{self.player_hand.bet:,}<:flooney:1194943899765051473>",
|
||||
inline=True,
|
||||
)
|
||||
embed.add_field(
|
||||
name=self.player_hand.name,
|
||||
value=f"{', '.join(self.player_hand.cards)}: {self.player_hand.value}",
|
||||
inline=False,
|
||||
)
|
||||
embed.add_field(
|
||||
name=self.dealer_hand.name,
|
||||
value=f"{(self.dealer_hand.cards)[0]}",
|
||||
inline=False,
|
||||
)
|
||||
msg = interaction
|
||||
await msg.response.edit_message(embed=embed, view=None)
|
||||
await dealer(msg, self.player_hand, self.dealer_hand, self.cards, self.db)
|
||||
|
||||
|
||||
# --- Main Gamble Cog ---
|
||||
|
||||
|
||||
class Gamble(commands.Cog):
|
||||
"""Cog for all gambling-related commands."""
|
||||
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
self.db = DatabaseManager()
|
||||
self.active_rooms = {}
|
||||
self.room_timers = {}
|
||||
|
||||
def save_rooms(self):
|
||||
"""Save all active rooms to the database."""
|
||||
try:
|
||||
for channel_id, room in self.active_rooms.items():
|
||||
invited_str = ",".join(str(uid) for uid in room["invited"])
|
||||
self.db.execute_query(
|
||||
"REPLACE INTO gamble_rooms (channel_id, host_id, invited, inactivity) VALUES (%s, %s, %s, %s)",
|
||||
(channel_id, room["host"], invited_str, room["inactivity"]),
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"[DB ERROR] Failed to save rooms: {e}")
|
||||
|
||||
def load_rooms(self):
|
||||
"""Load all rooms from the database."""
|
||||
try:
|
||||
self.active_rooms = {}
|
||||
rows = self.db.fetch_all("SELECT * FROM gamble_rooms")
|
||||
for row in rows:
|
||||
invited = set(int(uid) for uid in row["invited"].split(",") if uid)
|
||||
self.active_rooms[int(row["channel_id"])] = {
|
||||
"host": int(row["host_id"]),
|
||||
"invited": invited,
|
||||
"inactivity": int(row["inactivity"]),
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"[DB ERROR] Failed to load rooms: {e}")
|
||||
|
||||
def delete_room(self, channel_id):
|
||||
"""Delete a room from the database and memory."""
|
||||
try:
|
||||
self.db.execute_query(
|
||||
"DELETE FROM gamble_rooms WHERE channel_id = %s", (channel_id,)
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"[DB ERROR] Failed to delete room: {e}")
|
||||
self.active_rooms.pop(channel_id, None)
|
||||
self.save_rooms()
|
||||
|
||||
async def cog_load(self):
|
||||
"""Load rooms on cog load."""
|
||||
self.load_rooms()
|
||||
|
||||
async def cog_unload(self):
|
||||
"""Save rooms on cog unload."""
|
||||
self.save_rooms()
|
||||
|
||||
async def _check_limit_and_exclusion(self, ctx, amount: int) -> bool:
|
||||
"""Returns True if user is allowed to gamble, else sends a message and returns False."""
|
||||
user = ctx.author
|
||||
if amount <= 0:
|
||||
await ctx.reply("⚠️ Bet amount must be positive.", mention_author=False)
|
||||
return False
|
||||
try:
|
||||
limit_row = self.db.fetch_one(
|
||||
"SELECT * FROM gamble_limits WHERE USERID = %s", (user.id,)
|
||||
)
|
||||
except Exception as e:
|
||||
await ctx.reply(
|
||||
"⚠️ Database error. Please try again later.", mention_author=False
|
||||
)
|
||||
print(f"[DB ERROR] Limit check: {e}")
|
||||
return False
|
||||
if limit_row:
|
||||
if (
|
||||
limit_row.get("EXCLUDED_UNTIL")
|
||||
and datetime.utcnow() < limit_row["EXCLUDED_UNTIL"]
|
||||
):
|
||||
await ctx.reply(
|
||||
"🚫 You are currently self-excluded from gambling.",
|
||||
mention_author=False,
|
||||
)
|
||||
return False
|
||||
if limit_row.get("DAILY_LIMIT") and amount > limit_row["DAILY_LIMIT"]:
|
||||
await ctx.reply(
|
||||
f"🚫 Your personal bet limit is {limit_row['DAILY_LIMIT']:,}.",
|
||||
mention_author=False,
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
async def _send_embed(
|
||||
self, ctx, description: str, color: discord.Color = discord.Color.blurple()
|
||||
):
|
||||
"""Helper to send an embed message."""
|
||||
embed = discord.Embed(description=description, color=color)
|
||||
await ctx.reply(embed=embed, mention_author=False)
|
||||
|
||||
# --- Coinflip ---
|
||||
@commands.cooldown(1, 2, commands.BucketType.user)
|
||||
@commands.command(
|
||||
name="coinflip",
|
||||
aliases=["cf", "coin_flip"],
|
||||
usage="<bet_on: heads(H) or tails(T)> <amount: integer>",
|
||||
description="Flip a coin and bet on heads or tails.",
|
||||
brief="Bet on heads or tails.",
|
||||
)
|
||||
@commands.guild_only()
|
||||
async def coin_flip(self, ctx, bet_on: str, amount: int):
|
||||
if not await self._check_limit_and_exclusion(ctx, amount):
|
||||
return
|
||||
user = ctx.author
|
||||
bet_on = "heads" if "h" in bet_on.lower() else "tails"
|
||||
reward = round(amount / 2)
|
||||
users = await bank_data(user)
|
||||
if int(users["WALLET"]) < amount:
|
||||
return await self._send_embed(
|
||||
ctx, "❌ You don't have enough money.", discord.Color.red()
|
||||
)
|
||||
coin = ["heads", "tails"]
|
||||
result = choice(coin)
|
||||
if result != bet_on:
|
||||
await update_money(user, wallet=-abs(amount))
|
||||
return await self._send_embed(
|
||||
ctx,
|
||||
f"🪙 Got **{result}**, you lost **{amount:,}**.",
|
||||
discord.Color.red(),
|
||||
)
|
||||
await update_money(user, wallet=+abs(amount))
|
||||
return await self._send_embed(
|
||||
ctx,
|
||||
f"🪙 Got **{result}**, you won **{amount + reward:,}**!",
|
||||
discord.Color.green(),
|
||||
)
|
||||
|
||||
# --- Dice ---
|
||||
@commands.cooldown(1, 2, commands.BucketType.user)
|
||||
@commands.command(
|
||||
name="dice",
|
||||
usage="<amount: integer> <bet_on: integer (1-6)>",
|
||||
description="Bet on a dice roll (choose a number 1-6).",
|
||||
brief="Bet on a dice roll.",
|
||||
)
|
||||
async def dice(self, ctx, amount: int, bet_on: int = 6):
|
||||
if not await self._check_limit_and_exclusion(ctx, amount):
|
||||
return
|
||||
user = ctx.author
|
||||
rdice = [1, 2, 3, 4, 5, 6]
|
||||
if bet_on not in rdice:
|
||||
return await self._send_embed(
|
||||
ctx, "🎲 Enter a number of dice (1 - 6).", discord.Color.orange()
|
||||
)
|
||||
users = await bank_data(user)
|
||||
if int(users["WALLET"]) < amount:
|
||||
return await self._send_embed(
|
||||
ctx, "❌ You don't have enough money.", discord.Color.red()
|
||||
)
|
||||
rand_num = choice(rdice)
|
||||
if rand_num != bet_on:
|
||||
await update_money(user, wallet=-abs(amount))
|
||||
return await self._send_embed(
|
||||
ctx,
|
||||
f"🎲 Got **{rand_num}**, you lost **{amount:,}**.",
|
||||
discord.Color.red(),
|
||||
)
|
||||
reward = round(amount / 2)
|
||||
await update_money(user, wallet=+abs(reward))
|
||||
await self._send_embed(
|
||||
ctx,
|
||||
f"🎲 Got **{rand_num}**, you won **{amount + reward:,}**!",
|
||||
discord.Color.green(),
|
||||
)
|
||||
|
||||
# --- Slots ---
|
||||
@commands.cooldown(1, 1, commands.BucketType.user)
|
||||
@commands.command(
|
||||
name="slots",
|
||||
usage="<bet: integer or 'all'>",
|
||||
description="Spin the slot machine for a chance to win big!",
|
||||
brief="Spin the slot machine.",
|
||||
)
|
||||
async def slots(self, ctx, bet):
|
||||
user = ctx.author
|
||||
player_balance = int(
|
||||
self.db.fetch_one(
|
||||
"SELECT WALLET FROM economy WHERE ID = %s", (user.id,)
|
||||
).get("WALLET", 0)
|
||||
)
|
||||
bet = int(bet.replace("all", str(player_balance)))
|
||||
if not await self._check_limit_and_exclusion(ctx, bet):
|
||||
return
|
||||
if player_balance < bet:
|
||||
await self._send_embed(
|
||||
ctx, "❌ You have insufficient funds.", discord.Color.red()
|
||||
)
|
||||
return
|
||||
|
||||
# Animation: edit the embed to show spinning, then result
|
||||
spin_emoji = "<a:slots:1381060458999713843>"
|
||||
embed = discord.Embed(
|
||||
description=f"{spin_emoji} {spin_emoji} {spin_emoji}\nSpinning...",
|
||||
color=discord.Color.blurple(),
|
||||
)
|
||||
msg = await ctx.send(embed=embed)
|
||||
await asyncio.sleep(1.2)
|
||||
|
||||
play = "".join(choices(lottery_list, weights=weights, k=3))
|
||||
result_embed = discord.Embed(
|
||||
description=f"{play[0]} {play[1]} {play[2]}",
|
||||
color=(
|
||||
discord.Color.green()
|
||||
if play in lottery_win or play.count("🎁") > 0
|
||||
else discord.Color.red()
|
||||
),
|
||||
)
|
||||
# Ensure description is always a string
|
||||
if result_embed.description is None:
|
||||
result_embed.description = ""
|
||||
|
||||
if play in lottery_win:
|
||||
mult = lottery_win[play]
|
||||
result_embed.description = (result_embed.description or "") + (
|
||||
f"\nYou won **{bet * mult:,}** <:flooney:1194943899765051473>"
|
||||
)
|
||||
await update_money(user, wallet=bet * (mult - 1))
|
||||
elif play.count("🎁") == 2:
|
||||
mult = lottery_win["🎁🎁"]
|
||||
result_embed.description = (result_embed.description or "") + (
|
||||
f"\nYou won **{bet * mult:,}** <:flooney:1194943899765051473>"
|
||||
)
|
||||
await update_money(user, wallet=bet * (mult - 1))
|
||||
elif play.count("🎁") == 1:
|
||||
mult = lottery_win["🎁"]
|
||||
result_embed.description = (result_embed.description or "") + (
|
||||
f"\nYou won **{bet * mult:,}** <:flooney:1194943899765051473>"
|
||||
)
|
||||
await update_money(user, wallet=bet * (mult - 1))
|
||||
else:
|
||||
await update_money(user, wallet=-bet)
|
||||
result_embed.description = (result_embed.description or "") + (
|
||||
f"\nYou lost **{int(bet):,}** <:flooney:1194943899765051473>"
|
||||
)
|
||||
|
||||
await msg.edit(embed=result_embed)
|
||||
|
||||
# --- Roulette ---
|
||||
@commands.cooldown(1, 2, commands.BucketType.user)
|
||||
@commands.command(
|
||||
name="roulette",
|
||||
usage="<bet_type> <amount: integer>",
|
||||
description=(
|
||||
"Bet on roulette! Options: "
|
||||
"`red`, `black`, `green`, `even`, `odd`, "
|
||||
"`1st12`, `2nd12`, `3rd12` (dozens), "
|
||||
"`col1`, `col2`, `col3` (columns), or a number (0-36)."
|
||||
),
|
||||
brief="Bet on roulette.",
|
||||
)
|
||||
async def roulette(self, ctx, bet_type: str, amount: int):
|
||||
if not await self._check_limit_and_exclusion(ctx, amount):
|
||||
return
|
||||
user = ctx.author
|
||||
colors = {
|
||||
"red": [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36],
|
||||
"black": [
|
||||
2,
|
||||
4,
|
||||
6,
|
||||
8,
|
||||
10,
|
||||
11,
|
||||
13,
|
||||
15,
|
||||
17,
|
||||
20,
|
||||
22,
|
||||
24,
|
||||
26,
|
||||
28,
|
||||
29,
|
||||
31,
|
||||
33,
|
||||
35,
|
||||
],
|
||||
"green": [0],
|
||||
}
|
||||
bet_type = bet_type.lower()
|
||||
valid_bets = [
|
||||
"red",
|
||||
"black",
|
||||
"green",
|
||||
"even",
|
||||
"odd",
|
||||
"1st12",
|
||||
"2nd12",
|
||||
"3rd12",
|
||||
"col1",
|
||||
"col2",
|
||||
"col3",
|
||||
] + [str(i) for i in range(37)]
|
||||
if bet_type not in valid_bets:
|
||||
return await self._send_embed(
|
||||
ctx,
|
||||
"Bet on 'red', 'black', 'green', 'even', 'odd', '1st12', '2nd12', '3rd12', 'col1', 'col2', 'col3', or a number (0-36).",
|
||||
discord.Color.orange(),
|
||||
)
|
||||
result = choice(range(37))
|
||||
color = (
|
||||
"green" if result == 0 else "red" if result in colors["red"] else "black"
|
||||
)
|
||||
payout = 0
|
||||
# Number bet
|
||||
if bet_type.isdigit() and int(bet_type) == result:
|
||||
payout = amount * 35
|
||||
msg = f"🎲 The ball landed on {result} ({color}). You won {payout:,}!"
|
||||
# Color bet
|
||||
elif bet_type == color:
|
||||
payout = amount * (14 if color == "green" else 2)
|
||||
msg = f"🎲 The ball landed on {result} ({color}). You won {payout:,}!"
|
||||
# Even/Odd
|
||||
elif bet_type == "even" and result != 0 and result % 2 == 0:
|
||||
payout = amount * 2
|
||||
msg = f"🎲 The ball landed on {result} ({color}). You won {payout:,}!"
|
||||
elif bet_type == "odd" and result % 2 == 1:
|
||||
payout = amount * 2
|
||||
msg = f"🎲 The ball landed on {result} ({color}). You won {payout:,}!"
|
||||
# Dozens
|
||||
elif bet_type == "1st12" and 1 <= result <= 12:
|
||||
payout = amount * 3
|
||||
msg = f"🎲 The ball landed on {result} ({color}). You won {payout:,}!"
|
||||
elif bet_type == "2nd12" and 13 <= result <= 24:
|
||||
payout = amount * 3
|
||||
msg = f"🎲 The ball landed on {result} ({color}). You won {payout:,}!"
|
||||
elif bet_type == "3rd12" and 25 <= result <= 36:
|
||||
payout = amount * 3
|
||||
msg = f"🎲 The ball landed on {result} ({color}). You won {payout:,}!"
|
||||
# Columns
|
||||
elif bet_type == "col1" and result in [i for i in range(1, 37, 3)]:
|
||||
payout = amount * 3
|
||||
msg = f"🎲 The ball landed on {result} ({color}). You won {payout:,}!"
|
||||
elif bet_type == "col2" and result in [i for i in range(2, 37, 3)]:
|
||||
payout = amount * 3
|
||||
msg = f"🎲 The ball landed on {result} ({color}). You won {payout:,}!"
|
||||
elif bet_type == "col3" and result in [i for i in range(3, 37, 3)]:
|
||||
payout = amount * 3
|
||||
msg = f"🎲 The ball landed on {result} ({color}). You won {payout:,}!"
|
||||
else:
|
||||
payout = -amount
|
||||
msg = f"🎲 The ball landed on {result} ({color}). You lost {amount:,}."
|
||||
await update_money(user, wallet=payout)
|
||||
await self._send_embed(
|
||||
ctx, msg, discord.Color.green() if payout > 0 else discord.Color.red()
|
||||
)
|
||||
|
||||
# --- Poker ---
|
||||
@commands.cooldown(1, 2, commands.BucketType.user)
|
||||
@commands.is_owner()
|
||||
@commands.command(
|
||||
name="poker",
|
||||
usage="<bet: integer>",
|
||||
description="Play a simple 5-card draw poker game against the bot.",
|
||||
brief="Play poker against the bot.",
|
||||
)
|
||||
async def poker(self, ctx, bet: int):
|
||||
if not await self._check_limit_and_exclusion(ctx, bet):
|
||||
return
|
||||
user = ctx.author
|
||||
user_data = await bank_data(user)
|
||||
if int(user_data["WALLET"]) < bet:
|
||||
await self._send_embed(
|
||||
ctx, "❌ You don't have enough money.", discord.Color.red()
|
||||
)
|
||||
return
|
||||
# Poker deck and hands
|
||||
suits = ["♠️", "♥️", "♦️", "♣️"]
|
||||
ranks = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]
|
||||
deck = [f"{r}{s}" for r in ranks for s in suits]
|
||||
random.shuffle(deck)
|
||||
player_hand = [deck.pop() for _ in range(5)]
|
||||
bot_hand = [deck.pop() for _ in range(5)]
|
||||
|
||||
# Simple hand value: count pairs, triples, etc. (not full poker logic)
|
||||
def hand_value(hand):
|
||||
values = [card[:-2] if card[:-2] != "10" else "10" for card in hand]
|
||||
counts = {v: values.count(v) for v in set(values)}
|
||||
if 4 in counts.values():
|
||||
return 7 # Four of a kind
|
||||
if sorted(counts.values()) == [2, 3]:
|
||||
return 6 # Full house
|
||||
if 3 in counts.values():
|
||||
return 3 # Three of a kind
|
||||
if list(counts.values()).count(2) == 2:
|
||||
return 2 # Two pair
|
||||
if 2 in counts.values():
|
||||
return 1 # One pair
|
||||
return 0 # High card
|
||||
|
||||
player_score = hand_value(player_hand)
|
||||
bot_score = hand_value(bot_hand)
|
||||
|
||||
if player_score > bot_score:
|
||||
await update_money(user, wallet=bet)
|
||||
msg = f"🃏 Your hand: {', '.join(player_hand)}\n🤖 Bot's hand: {', '.join(bot_hand)}\nYou win {bet:,} coins!"
|
||||
elif player_score < bot_score:
|
||||
await update_money(user, wallet=-bet)
|
||||
msg = f"🃏 Your hand: {', '.join(player_hand)}\n🤖 Bot's hand: {', '.join(bot_hand)}\nYou lose {bet:,} coins!"
|
||||
else:
|
||||
msg = f"🃏 Your hand: {', '.join(player_hand)}\n🤖 Bot's hand: {', '.join(bot_hand)}\nIt's a draw! No coins won or lost."
|
||||
await self._send_embed(
|
||||
ctx,
|
||||
msg,
|
||||
(
|
||||
discord.Color.green()
|
||||
if "win" in msg
|
||||
else discord.Color.red() if "lose" in msg else discord.Color.blurple()
|
||||
),
|
||||
)
|
||||
|
||||
# --- Higher/Lower ---
|
||||
@commands.cooldown(1, 2, commands.BucketType.user)
|
||||
@commands.command(
|
||||
name="higherlower",
|
||||
usage="<bet: integer>",
|
||||
description="Guess if the next number will be higher or lower.",
|
||||
brief="Guess higher or lower.",
|
||||
)
|
||||
async def higherlower(self, ctx, bet: int):
|
||||
if not await self._check_limit_and_exclusion(ctx, bet):
|
||||
return
|
||||
user = ctx.author
|
||||
number = random.randint(1, 100)
|
||||
await self._send_embed(
|
||||
ctx,
|
||||
f"The number is **{number}**. Will the next number be higher or lower? Type `higher` or `lower`.",
|
||||
discord.Color.blurple(),
|
||||
)
|
||||
|
||||
def check(m):
|
||||
return (
|
||||
m.author == ctx.author
|
||||
and m.channel == ctx.channel
|
||||
and m.content.lower() in ["higher", "lower"]
|
||||
)
|
||||
|
||||
try:
|
||||
guess_msg = await self.client.wait_for("message", check=check, timeout=15)
|
||||
except Exception:
|
||||
await self._send_embed(
|
||||
ctx, "Timed out. Please try again.", discord.Color.orange()
|
||||
)
|
||||
return
|
||||
next_number = random.randint(1, 100)
|
||||
win = (guess_msg.content.lower() == "higher" and next_number > number) or (
|
||||
guess_msg.content.lower() == "lower" and next_number < number
|
||||
)
|
||||
if next_number == number:
|
||||
msg = f"The next number was also **{next_number}**. It's a tie! No coins won or lost."
|
||||
elif win:
|
||||
await update_money(user, wallet=bet)
|
||||
msg = f"The next number was **{next_number}**. You win {bet:,} coins!"
|
||||
else:
|
||||
await update_money(user, wallet=-bet)
|
||||
msg = f"The next number was **{next_number}**. You lose {bet:,} coins!"
|
||||
await self._send_embed(
|
||||
ctx, msg, discord.Color.green() if win else discord.Color.red()
|
||||
)
|
||||
|
||||
# --- Scratch ---
|
||||
@commands.cooldown(1, 2, commands.BucketType.user)
|
||||
@commands.command(
|
||||
name="scratch",
|
||||
usage="<bet: integer>",
|
||||
description="Buy a scratch card for a chance to win up to 10x your bet.",
|
||||
brief="Buy a scratch card.",
|
||||
)
|
||||
async def scratch(self, ctx, bet: int):
|
||||
if not await self._check_limit_and_exclusion(ctx, bet):
|
||||
return
|
||||
user = ctx.author
|
||||
symbols = ["🍀", "💎", "⭐", "🍒", "7️⃣"]
|
||||
card = [random.choice(symbols) for _ in range(3)]
|
||||
payout = 0
|
||||
if card.count(card[0]) == 3:
|
||||
payout = bet * 10
|
||||
msg = f"Scratch Card: {' '.join(card)}\nJackpot! You win {payout:,} coins!"
|
||||
elif len(set(card)) == 2:
|
||||
payout = bet * 2
|
||||
msg = f"Scratch Card: {' '.join(card)}\nTwo of a kind! You win {payout:,} coins!"
|
||||
else:
|
||||
payout = -bet
|
||||
msg = f"Scratch Card: {' '.join(card)}\nNo match. You lose {bet:,} coins."
|
||||
await update_money(user, wallet=payout)
|
||||
await self._send_embed(
|
||||
ctx, msg, discord.Color.green() if payout > 0 else discord.Color.red()
|
||||
)
|
||||
|
||||
# --- All other user-facing responses (invite, kick, end_gameroom, etc.) ---
|
||||
# Replace ctx.reply(...) or ctx.send(...) with self._send_embed(...) for consistency.
|
||||
|
||||
@commands.command(
|
||||
name="gameroom",
|
||||
usage="[game: str] [inactivity: int (minutes)]",
|
||||
description="Create a private game room that auto-deletes after inactivity.",
|
||||
brief="Create a private game room.",
|
||||
)
|
||||
@commands.guild_only()
|
||||
async def gameroom(self, ctx, game: str = "game", inactivity: int = 10):
|
||||
"""Create a private text channel for a game session."""
|
||||
guild = ctx.guild
|
||||
overwrites = {
|
||||
guild.default_role: discord.PermissionOverwrite(read_messages=False),
|
||||
ctx.author: discord.PermissionOverwrite(
|
||||
read_messages=True, send_messages=True
|
||||
),
|
||||
}
|
||||
category = ctx.channel.category
|
||||
channel_name = f"{game}-room-{ctx.author.display_name}".replace(
|
||||
" ", "-"
|
||||
).lower()
|
||||
channel = await guild.create_text_channel(
|
||||
name=channel_name,
|
||||
overwrites=overwrites,
|
||||
category=category,
|
||||
reason="Private game room",
|
||||
)
|
||||
await channel.send(
|
||||
f"{ctx.author.mention} Your private **{game}** session has started!\n"
|
||||
f"Use `py invite <user>` and `py kick <user>` in this channel to manage access.\n"
|
||||
f"This channel will be deleted after **{inactivity} minutes of inactivity**."
|
||||
)
|
||||
|
||||
self.active_rooms[channel.id] = {
|
||||
"host": ctx.author.id,
|
||||
"invited": set([ctx.author.id]),
|
||||
"inactivity": inactivity,
|
||||
}
|
||||
self.save_rooms()
|
||||
self.reset_inactivity_timer(channel.id, inactivity)
|
||||
|
||||
def reset_inactivity_timer(self, channel_id, inactivity):
|
||||
"""Reset the inactivity timer for a game room."""
|
||||
if channel_id in self.room_timers:
|
||||
self.room_timers[channel_id].cancel()
|
||||
task = asyncio.create_task(self.inactivity_task(channel_id, inactivity))
|
||||
self.room_timers[channel_id] = task
|
||||
|
||||
async def inactivity_task(self, channel_id, inactivity):
|
||||
"""Delete the channel after inactivity period."""
|
||||
try:
|
||||
await asyncio.sleep(inactivity * 60)
|
||||
channel = self.client.get_channel(channel_id)
|
||||
if channel:
|
||||
await channel.send("Room deleted due to inactivity.")
|
||||
await channel.delete(reason="Game room inactive")
|
||||
self.delete_room(channel_id)
|
||||
self.room_timers.pop(channel_id, None)
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message):
|
||||
"""Reset inactivity timer on message in a game room."""
|
||||
if (
|
||||
hasattr(self, "active_rooms")
|
||||
and message.channel.id in self.active_rooms
|
||||
and not message.author.bot
|
||||
):
|
||||
inactivity = self.active_rooms[message.channel.id].get("inactivity", 10)
|
||||
self.reset_inactivity_timer(message.channel.id, inactivity)
|
||||
|
||||
@commands.command(
|
||||
name="invite",
|
||||
usage="<user: id|name>",
|
||||
description="Invite a user to your private game room.",
|
||||
brief="Invite a user to your game room.",
|
||||
hidden=True,
|
||||
)
|
||||
async def invite(
|
||||
self,
|
||||
ctx,
|
||||
member: discord.Member | None = None,
|
||||
*,
|
||||
identifier: str | None = None,
|
||||
):
|
||||
"""Invite a user to the game room by mention, ID, or username."""
|
||||
room = self.active_rooms.get(ctx.channel.id)
|
||||
if not room or ctx.author.id != room["host"]:
|
||||
await ctx.reply(
|
||||
"Only the host can invite others, and only in a private game room channel.",
|
||||
mention_author=False,
|
||||
)
|
||||
return
|
||||
|
||||
# If member is not provided, try to resolve by ID or name
|
||||
if member is None and identifier:
|
||||
try:
|
||||
member = ctx.guild.get_member(int(identifier))
|
||||
except ValueError:
|
||||
member = discord.utils.find(
|
||||
lambda m: m.name.lower() == identifier.lower()
|
||||
or m.display_name.lower() == identifier.lower(),
|
||||
ctx.guild.members,
|
||||
)
|
||||
if member is None:
|
||||
await ctx.reply(
|
||||
"User not found. Please use a mention, user ID, or username.",
|
||||
mention_author=False,
|
||||
)
|
||||
return
|
||||
|
||||
await ctx.channel.set_permissions(
|
||||
member, read_messages=True, send_messages=True
|
||||
)
|
||||
room["invited"].add(member.id)
|
||||
self.save_rooms()
|
||||
await ctx.send(
|
||||
f"{member.mention} has been invited to the game room!",
|
||||
allowed_mentions=discord.AllowedMentions(users=True),
|
||||
)
|
||||
|
||||
@commands.command(
|
||||
name="kick",
|
||||
usage="<user: mention>",
|
||||
description="Kick a user from your private game room.",
|
||||
brief="Kick a user from your game room.",
|
||||
hidden=True,
|
||||
)
|
||||
async def kick(self, ctx, member: discord.Member):
|
||||
"""Kick a user from the game room."""
|
||||
room = self.active_rooms.get(ctx.channel.id)
|
||||
if not room or ctx.author.id != room["host"]:
|
||||
await ctx.reply(
|
||||
"Only the host can kick others, and only in a private game room channel.",
|
||||
mention_author=False,
|
||||
)
|
||||
return
|
||||
if member.id == ctx.author.id:
|
||||
await ctx.reply("You cannot kick yourself (host).", mention_author=False)
|
||||
return
|
||||
if member.id not in room["invited"]:
|
||||
await ctx.reply(
|
||||
f"{member.mention} is not in this game room.", mention_author=False
|
||||
)
|
||||
return
|
||||
await ctx.channel.set_permissions(member, overwrite=None)
|
||||
room["invited"].discard(member.id)
|
||||
self.save_rooms()
|
||||
await ctx.reply(
|
||||
f"{member.mention} has been kicked from the game room!",
|
||||
mention_author=False,
|
||||
)
|
||||
|
||||
@commands.command(
|
||||
name="end",
|
||||
aliases=["delete"],
|
||||
description="End and delete your private game room.",
|
||||
brief="Delete your game room.",
|
||||
hidden=True,
|
||||
)
|
||||
async def end_gameroom(self, ctx):
|
||||
"""Allows the host to manually delete the game room channel."""
|
||||
room = self.active_rooms.get(ctx.channel.id)
|
||||
if not room or ctx.author.id != room["host"]:
|
||||
await ctx.reply(
|
||||
"Only the host can end this game room, and only in a private game room channel.",
|
||||
mention_author=False,
|
||||
)
|
||||
return
|
||||
await ctx.send("This game room will now be deleted by the host.")
|
||||
self.delete_room(ctx.channel.id)
|
||||
await ctx.channel.delete(reason="Game room ended by host")
|
||||
|
||||
|
||||
async def setup(client):
|
||||
await client.add_cog(Gamble(client))
|
||||
Reference in New Issue
Block a user