Skip to content

Commit e9bfbfa

Browse files
committed
"half" betting changes, admin route stuff, jackpot now works (& is moved from multiplayer to economy as it uses the database)
1 parent 1a77a80 commit e9bfbfa

4 files changed

Lines changed: 206 additions & 119 deletions

File tree

cogs/admin/Admin.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -563,16 +563,29 @@ async def reset_economy(self, ctx, *, confirmation: str = None):
563563
return await ctx.reply(embed=embed)
564564

565565
try:
566-
# Delete all data from the economy table
567-
await self.db.cursor.execute("DELETE FROM economy")
566+
# Delete all user data (balances, inventory, fish collections)
567+
await self.db.db.users.delete_many({})
568568

569-
# Delete all data from active potions
570-
await self.db.cursor.execute("DELETE FROM active_potions")
569+
# Delete all active potions
570+
await self.db.db.active_potions.delete_many({})
571571

572-
# Commit the changes
573-
await self.db.conn.commit()
572+
# Reset shop data to defaults by dropping and recreating collections
573+
shop_collections = [
574+
"shop_items",
575+
"shop_potions",
576+
"shop_upgrades",
577+
"shop_fishing",
578+
"shop_bait",
579+
"shop_rod"
580+
]
574581

575-
# Reset shop data to defaults
582+
for collection in shop_collections:
583+
await self.db.db[collection].delete_many({})
584+
585+
# Reinitialize default shop items
586+
await self.db.init_collections()
587+
588+
# Reset local shop data
576589
self.shop_data = {
577590
"items": {},
578591
"potions": {},

cogs/unique/Economy.py

Lines changed: 183 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from cogs.logging.logger import CogLogger
33
from utils.db import async_db as db
44
from cogs.Help import HelpPaginator
5+
from typing import Dict, List
56
from utils.betting import parse_bet
67
import discord
78
import random
@@ -32,6 +33,7 @@ def __init__(self, pages, author, timeout=180):
3233
super().__init__(timeout=timeout)
3334
self.pages = pages
3435
self.author = author
36+
self.active_jackpots: Dict[int, Dict[int, int]] = {} # {channel_id: {bet_amount: message_id}}
3537
self.current_page = 0
3638
self.message = None
3739
self.DEFAULT_FISHING_ITEMS = {
@@ -556,41 +558,50 @@ async def leaderboard(self, ctx, scope: str = "server"):
556558
return await self._show_server_leaderboard(ctx)
557559

558560
async def _show_server_leaderboard(self, ctx):
559-
"""Show server-specific leaderboard"""
561+
"""Show server-specific leaderboard (optimized version)"""
560562
try:
561-
# Use the db instance (which is async_db)
562-
if not await db.ensure_connected():
563+
if not await self.db.ensure_connected():
563564
return await ctx.reply(embed=discord.Embed(
564565
description="❌ Database connection failed",
565566
color=0xff0000
566567
))
568+
569+
# Get all non-bot member IDs in the server
570+
member_ids = [str(member.id) for member in ctx.guild.members if not member.bot]
567571

572+
if not member_ids:
573+
return await ctx.reply(embed=discord.Embed(
574+
description="No users found in this server",
575+
color=0x2b2d31
576+
))
577+
578+
# Single database query to get all relevant users
579+
cursor = self.db.db.users.find({
580+
"_id": {"$in": member_ids},
581+
"$or": [
582+
{"wallet": {"$gt": 0}},
583+
{"bank": {"$gt": 0}}
584+
]
585+
})
586+
568587
users = []
569-
570-
# Get all users in the server and check their balances
571-
for member in ctx.guild.members:
572-
if not member.bot:
573-
try:
574-
wallet = await db.get_wallet_balance(member.id, ctx.guild.id)
575-
bank = await db.get_bank_balance(member.id, ctx.guild.id)
576-
total = wallet + bank
577-
if total > 0: # Only include users with money
578-
users.append({
579-
"member": member,
580-
"total": total
581-
})
582-
except Exception as e:
583-
print(f"DEBUG: Error getting balance for {member.id}: {e}")
584-
continue
585-
588+
async for user_doc in cursor:
589+
member = ctx.guild.get_member(int(user_doc["_id"]))
590+
if member: # Only include members still in the server
591+
total = user_doc.get("wallet", 0) + user_doc.get("bank", 0)
592+
users.append({
593+
"member": member,
594+
"total": round(total)
595+
})
596+
586597
if not users:
587598
embed = discord.Embed(
588599
description="No economy data for this server.\n💡 Users need to earn money first (work, daily, etc.)",
589600
color=0x2b2d31
590601
)
591602
return await ctx.reply(embed=embed)
592603

593-
# Sort by total wealth and take top 10
604+
# Sort and get top 10
594605
users.sort(key=lambda x: x["total"], reverse=True)
595606
users = users[:10]
596607

@@ -618,7 +629,7 @@ async def _show_server_leaderboard(self, ctx):
618629
await ctx.reply(embed=embed)
619630

620631
except Exception as e:
621-
print(f"DEBUG: Server leaderboard error: {e}")
632+
print(f"Leaderboard error: {e}")
622633
return await ctx.reply(embed=discord.Embed(
623634
description="❌ An error occurred while fetching the leaderboard",
624635
color=0xff0000
@@ -689,7 +700,7 @@ async def _show_global_leaderboard(self, ctx):
689700

690701
formatted_total = "{:,}".format(total_wealth)
691702
average_wealth = "{:,}".format(total_wealth // len(content)) if content else "0"
692-
embed.set_footer(text=f"Total Wealth: {formatted_total} {self.currency} • Average: {average_wealth} {self.currency}")
703+
embed.set_footer(text=f"Total Wealth: ${formatted_total} • Average: ${average_wealth}")
693704

694705
await ctx.reply(embed=embed)
695706

@@ -785,6 +796,155 @@ async def buy(self, ctx, item_id: str):
785796
else:
786797
await ctx.reply(f"❌ {message}")
787798

799+
@commands.command(aliases=['jp'])
800+
async def jackpot(self, ctx, bet_amount: str = "25"):
801+
"""Start a jackpot with custom entry fee. Default: 25
802+
Usage: !jackpot [bet] (supports all/max/half/percentages)"""
803+
804+
# Get user's balance
805+
user_id = ctx.author.id
806+
wallet = await self.db.get_wallet_balance(user_id)
807+
bank = await self.db.get_bank_balance(user_id)
808+
total_balance = wallet + bank
809+
810+
# Parse the bet amount
811+
parsed_amount, error = parse_bet(bet_amount, total_balance)
812+
if error:
813+
return await ctx.reply(f"❌ {error}")
814+
815+
# Check if user can afford the bet
816+
if wallet < parsed_amount:
817+
needed = parsed_amount - wallet
818+
return await ctx.reply(
819+
f"❌ You need {needed}{self.currency} more in your wallet to join this jackpot!\n"
820+
f"💡 Use `.withdraw {needed}` to move money from your bank."
821+
)
822+
823+
# Handle "all" or "max" with empty bank
824+
if bet_amount.lower() in ["all", "max"] and bank == 0:
825+
parsed_amount *= 2 # Double the bet for free
826+
await ctx.send(f"🎁 Bonus! Since your bank is empty, your bet has been doubled to **{parsed_amount}{self.currency}** for free!")
827+
828+
# Minimum bet check
829+
if parsed_amount < 10:
830+
return await ctx.reply(f"Minimum jackpot entry is 10{self.currency}!")
831+
832+
# Check for existing jackpot with this bet amount
833+
channel_jackpots = self.active_jackpots.get(ctx.channel.id, {})
834+
if parsed_amount in channel_jackpots:
835+
try:
836+
message = await ctx.channel.fetch_message(channel_jackpots[parsed_amount])
837+
return await ctx.reply(
838+
f"A jackpot with {parsed_amount}{self.currency} entry fee already exists!\n"
839+
f"{message.jump_url}"
840+
)
841+
except discord.NotFound:
842+
# Clean up expired jackpot
843+
del channel_jackpots[parsed_amount]
844+
845+
try:
846+
# Deduct the bet immediately
847+
if not await self.db.update_wallet(user_id, -parsed_amount):
848+
return await ctx.reply("❌ Failed to deduct your bet amount. Please try again.")
849+
850+
embed = discord.Embed(
851+
description=(
852+
f"🎰 **JACKPOT STARTED!** 🎰\n"
853+
f"Hosted by: {ctx.author.mention}\n"
854+
f"Entry: **{parsed_amount}{self.currency}**\n"
855+
f"React with 🎉 within **15 seconds** to join!\n\n"
856+
f"Current pot: **{parsed_amount}{self.currency}** (1 player)"
857+
),
858+
color=discord.Color.gold()
859+
)
860+
jackpot_msg = await ctx.send(embed=embed)
861+
await jackpot_msg.add_reaction("🎉")
862+
863+
# Store jackpot info
864+
if ctx.channel.id not in self.active_jackpots:
865+
self.active_jackpots[ctx.channel.id] = {}
866+
self.active_jackpots[ctx.channel.id][parsed_amount] = jackpot_msg.id
867+
868+
participants = {ctx.author.id: ctx.author} # Store as dict to avoid duplicates
869+
await asyncio.sleep(15)
870+
871+
# Clean up jackpot tracking
872+
if ctx.channel.id in self.active_jackpots and parsed_amount in self.active_jackpots[ctx.channel.id]:
873+
del self.active_jackpots[ctx.channel.id][parsed_amount]
874+
if not self.active_jackpots[ctx.channel.id]:
875+
del self.active_jackpots[ctx.channel.id]
876+
877+
try:
878+
jackpot_msg = await ctx.channel.fetch_message(jackpot_msg.id)
879+
reaction = next((r for r in jackpot_msg.reactions if str(r.emoji) == "🎉"), None)
880+
881+
if reaction:
882+
async for user in reaction.users():
883+
if not user.bot and user.id != ctx.author.id:
884+
# Check each participant's balance
885+
user_wallet = await self.db.get_wallet_balance(user.id)
886+
if user_wallet >= parsed_amount:
887+
if await self.db.update_wallet(user.id, -parsed_amount):
888+
participants[user.id] = user
889+
else:
890+
await ctx.send(f"{user.mention} couldn't join - transaction failed!")
891+
else:
892+
await ctx.send(f"{user.mention} couldn't join - insufficient funds!")
893+
894+
if len(participants) == 1:
895+
# Refund the host if no one joined
896+
await self.db.update_wallet(ctx.author.id, parsed_amount)
897+
return await ctx.send(embed=discord.Embed(
898+
description=f"❌ Only {ctx.author.mention} joined. Refunded {parsed_amount}{self.currency}",
899+
color=discord.Color.red()
900+
))
901+
902+
pot = len(participants) * parsed_amount
903+
winner_id, winner = random.choice(list(participants.items()))
904+
905+
# Calculate each participant's chance of winning
906+
win_chance = 100 / len(participants)
907+
908+
# Award the pot to the winner
909+
if not await self.db.update_wallet(winner_id, pot):
910+
await ctx.send("❌ Failed to award the jackpot prize! Please contact an admin.")
911+
# Refund all participants
912+
for uid in participants:
913+
await self.db.update_wallet(uid, parsed_amount)
914+
return
915+
916+
await ctx.send(embed=discord.Embed(
917+
description=(
918+
f"🎉 **JACKPOT RESULTS** 🎉\n"
919+
f"Entry Fee: **{parsed_amount}{self.currency}**\n"
920+
f"Total entries: **{len(participants)}**\n"
921+
f"Total pot: **{pot}{self.currency}**\n"
922+
f"Winner: {winner.mention} (had a **{win_chance:.1f}%** chance)\n\n"
923+
f"🏆 **{winner.display_name} takes {pot}{self.currency}!** 🏆"
924+
),
925+
color=discord.Color.green()
926+
))
927+
928+
except discord.NotFound:
929+
await ctx.send(embed=discord.Embed(
930+
description="❌ Jackpot message was deleted. Refunding all participants...",
931+
color=discord.Color.red()
932+
))
933+
# Refund all participants
934+
for uid in participants:
935+
await self.db.update_wallet(uid, parsed_amount)
936+
937+
except Exception as e:
938+
self.bot.logger.error(f"Jackpot error: {e}")
939+
# Clean up and attempt to refund if something went wrong
940+
if ctx.channel.id in self.active_jackpots and parsed_amount in self.active_jackpots[ctx.channel.id]:
941+
del self.active_jackpots[ctx.channel.id][parsed_amount]
942+
if not self.active_jackpots[ctx.channel.id]:
943+
del self.active_jackpots[ctx.channel.id]
944+
945+
await ctx.send("❌ An error occurred during the jackpot. Refunding participants...")
946+
await self.db.update_wallet(ctx.author.id, parsed_amount)
947+
788948
@commands.command(aliases=['cf'])
789949
@commands.cooldown(1, 3, commands.BucketType.user)
790950
async def coinflip(self, ctx, bet_amount: str, choice: str):

cogs/unique/Multiplayer.py

Lines changed: 0 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -96,94 +96,6 @@ def check(reaction, user):
9696
finally:
9797
self.active_games.discard(game_key)
9898

99-
@commands.command(aliases=['jp'])
100-
async def jackpot(self, ctx, bet: int = 25):
101-
"""Start a jackpot with custom entry fee. Default: 25
102-
Usage: !jackpot [bet]"""
103-
104-
if bet < 10:
105-
return await ctx.reply("Minimum jackpot entry is 10!")
106-
107-
# Check if there's already a jackpot with this bet amount
108-
channel_jackpots = self.active_jackpots.get(ctx.channel.id, {})
109-
if bet in channel_jackpots:
110-
try:
111-
message = await ctx.channel.fetch_message(channel_jackpots[bet])
112-
return await ctx.reply(f"A jackpot with {bet} entry fee already exists!\n{message.jump_url}")
113-
except discord.NotFound:
114-
# Clean up expired jackpot
115-
del channel_jackpots[bet]
116-
117-
try:
118-
embed = discord.Embed(
119-
description=(f"🎰 **JACKPOT STARTED!** 🎰\n"
120-
f"Hosted by: {ctx.author.mention}\n"
121-
f"Entry: **${bet}**\n"
122-
f"React with 🎉 within **15 seconds** to join!\n\n"
123-
f"Current pot: **${bet}** (1 player)"),
124-
color=discord.Color.gold()
125-
)
126-
jackpot_msg = await ctx.send(embed=embed)
127-
await jackpot_msg.add_reaction("🎉")
128-
129-
# Store jackpot info
130-
if ctx.channel.id not in self.active_jackpots:
131-
self.active_jackpots[ctx.channel.id] = {}
132-
self.active_jackpots[ctx.channel.id][bet] = jackpot_msg.id
133-
134-
participants = [ctx.author]
135-
await asyncio.sleep(15)
136-
137-
# Clean up jackpot tracking
138-
channel_jackpots = self.active_jackpots.get(ctx.channel.id, {})
139-
if bet in channel_jackpots:
140-
del channel_jackpots[bet]
141-
if not channel_jackpots:
142-
del self.active_jackpots[ctx.channel.id]
143-
144-
try:
145-
jackpot_msg = await ctx.channel.fetch_message(jackpot_msg.id)
146-
reaction = next((r for r in jackpot_msg.reactions if str(r.emoji) == "🎉"), None)
147-
148-
if reaction:
149-
async for user in reaction.users():
150-
if not user.bot and user not in participants:
151-
participants.append(user)
152-
153-
if len(participants) == 1:
154-
return await ctx.send(embed=discord.Embed(
155-
description=f"❌ Only {ctx.author.mention} joined. Refunded ${bet}",
156-
color=discord.Color.red()
157-
))
158-
159-
pot = len(participants) * bet
160-
winner = random.choice(participants)
161-
win_chance = bet / pot * 100
162-
163-
await ctx.send(embed=discord.Embed(
164-
description=(f"🎉 **JACKPOT RESULTS** 🎉\n"
165-
f"Entry Fee: **${bet}**\n"
166-
f"Total entries: **{len(participants)}**\n"
167-
f"Total pot: **${pot}**\n"
168-
f"Winner: {winner.mention} (had a **{win_chance:.1f}%** chance)\n\n"
169-
f"🏆 **{winner.display_name} takes ALL!** 🏆"),
170-
color=discord.Color.green()
171-
))
172-
173-
except discord.NotFound:
174-
await ctx.send(embed=discord.Embed(
175-
description="❌ Jackpot message was deleted. Game cancelled.",
176-
color=discord.Color.red()
177-
))
178-
179-
except Exception as e:
180-
self.logger.error(f"Jackpot error: {e}")
181-
if ctx.channel.id in self.active_jackpots:
182-
if bet in self.active_jackpots[ctx.channel.id]:
183-
del self.active_jackpots[ctx.channel.id][bet]
184-
if not self.active_jackpots[ctx.channel.id]:
185-
del self.active_jackpots[ctx.channel.id]
186-
18799
@commands.command(aliases=['slotfight', 'slotsduel', 'sb'])
188100
async def slotbattle(self, ctx, opponent: discord.Member = None):
189101
"""Challenge someone to a slot battle! Winner takes all, or the house wins if both lose."""

0 commit comments

Comments
 (0)