import logging import discord from discord.ext import commands from utils.bank_functions import * from discord.ext import commands from datetime import datetime, timedelta from random import randint from typing import Literal import datetime async def check_transfer( ctx: commands.Context, payer_balance: int, receiver_balance: int, member: discord.Member, amount: int, ) -> bool: """Check if a transfer is valid. Args: - ctx (commands.Context): The context of the invoked command. - payer_balance (int): The balance of the payer. - receiver_balance (int): The balance of the receiver. - member (discord.Member): The member to check against. - amount (int): The amount to transfer. Returns: - bool: Whether the transfer is valid. """ if payer_balance is None or receiver_balance is None: await ctx.reply("Bank account doesn't exist.") return False if payer_balance >= amount > 0: payer_balance = payer_balance - amount receiver_balance = receiver_balance + amount if ctx.author.id != member.id: return True else: await ctx.reply("You cannot give yourself money.") return False else: await ctx.reply( f"You do not have {int(amount):,}<:flooney:1194943899765051473>.\nYou have {int(payer_balance):,}<:flooney:1194943899765051473>." ) return False class Economy(commands.Cog): def __init__(self, client): self.client = client self.db = DatabaseManager("") r""" .----------------. .----------------. .----------------. .----------------. .-----------------. | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | | | __ | || | ________ | || | ____ ____ | || | _____ | || | ____ _____ | | | | / \ | || | |_ ___ `. | || ||_ \ / _|| || | |_ _| | || ||_ \|_ _| | | | | / /\ \ | || | | | `. \ | || | | \/ | | || | | | | || | | \ | | | | | | / ____ \ | || | | | | | | || | | |\ /| | | || | | | | || | | |\ \| | | | | | _/ / \ \_ | || | _| |___.' / | || | _| |_\/_| |_ | || | _| |_ | || | _| |_\ |_ | | | ||____| |____|| || | |________.' | || ||_____||_____|| || | |_____| | || ||_____|\____| | | | | | || | | || | | || | | || | | | | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | '----------------' '----------------' '----------------' '----------------' '----------------' """ @commands.command( name="give_money", aliases=["addmoney"], usage=" ", ) @commands.is_owner() @commands.cooldown(3, 2 * 60, commands.BucketType.user) async def add_money( self, ctx: commands.Context, member: discord.Member, amount_str: str ): """Add money to a user's bank.""" if member.bot: return await ctx.reply("You can't add money to a bot", mention_author=False) if not member: member = ctx.author try: amount = int(amount_str) except ValueError: return await ctx.reply("Please enter a valid amount") if amount <= 0: return await ctx.reply("Please enter an amount greater than 0") limit = 1_000_000 if amount > limit: return await ctx.reply(f"You cannot add money more than {limit:,}") await update_money(member, amount) await ctx.reply( f"You added {amount:,} in {member.mention}'s bank.", mention_author=False ) @commands.command( aliases=["remoney"], usage=" ", ) @commands.is_owner() @commands.cooldown(3, 2 * 60, commands.BucketType.user) async def remove_money( self, ctx, member: discord.Member, amount_str: str, mode: str = "bank" ): mode = mode.lower() if member.bot: return await ctx.reply( "You can't remove money from a bot", mention_author=False ) try: amount = int(amount_str) if amount <= 0: raise ValueError except ValueError: return await ctx.reply("Please enter a valid amount") if mode not in ["wallet", "bank"]: return await ctx.reply("Please enter either wallet or bank only") user_balance = await bank_data(member) current_balance = user_balance["BANK" if mode == "bank" else "WALLET"] if current_balance < amount: return await ctx.reply( f"You can only remove {current_balance:,} from {member.mention}'s {mode}" ) if mode == "bank": await update_money(member, bank=-amount) else: await update_money(member, wallet=-amount) await ctx.reply( f"You removed {amount:,} from {member.mention}'s {mode}", mention_author=False, ) @commands.command(usage="") @commands.is_owner() @commands.cooldown(2, 3 * 60, commands.BucketType.user) async def reset_money(self, ctx, member: discord.Member): if member.bot: return await ctx.reply( "Bots don't have bank accounts", mention_author=False ) await reset_bank(member) return await ctx.reply( f"{member.mention}'s account has been reset", mention_author=False ) r""" .----------------. .----------------. .-----------------. .----------------. | .--------------. || .--------------. || .--------------. || .--------------. | | | ______ | || | __ | || | ____ _____ | || | ___ ____ | | | | |_ _ \ | || | / \ | || ||_ \|_ _| | || | |_ ||_ _| | | | | | |_) | | || | / /\ \ | || | | \ | | | || | | |_/ / | | | | | __'. | || | / ____ \ | || | | |\ \| | | || | | __'. | | | | _| |__) | | || | _/ / \ \_ | || | _| |_\ |_ | || | _| | \ \_ | | | | |_______/ | || ||____| |____|| || ||_____|\____| | || | |____||____| | | | | | || | | || | | || | | | | '--------------' || '--------------' || '--------------' || '--------------' | '----------------' '----------------' '----------------' '----------------' """ @commands.command( name="balance", aliases=["bal"], brief="Check your money", description="Check how much money you have.", ) async def _balance( self, ctx: commands.Context, member: discord.Member | None = None ): """ Check how much money you have. """ target: discord.Member | discord.User = member or ctx.author # Ensure the target is not a bot if target.bot: return # Get the user's data user_data = await bank_data(target) wallet_balance = user_data.get("WALLET", 0) bank_balance = user_data.get("BANK", 0) # Create an account if one does not exist if bank_balance is None or wallet_balance is None: await create_account(target) user_data = await bank_data(target) wallet_balance = user_data.get("WALLET", 0) bank_balance = user_data.get("BANK", 0) # Reply with the user's balance await ctx.reply( f"{target.mention} has {bank_balance:,}<:flooney:1194943899765051473> in their bank and " f"{wallet_balance:,}<:flooney:1194943899765051473> in their wallet." ) @commands.command(name="give") async def _give(self, ctx, target: discord.Member, amount: int): """Give money to another user.""" payer_wallet = int((await bank_data(ctx.author)).get("WALLET", 0)) receiver_wallet = int((await bank_data(target)).get("WALLET", 0)) if await check_transfer(ctx, payer_wallet, receiver_wallet, target, amount): await update_money(target, wallet=amount) await update_money(ctx.author, wallet=-amount) await ctx.reply( f"You gave {target} {amount:,} flooneys.", mention_author=False ) @commands.command(name="transfer") async def _transfer(self, ctx, target: discord.Member, amount: int): """ Transfer money from your bank account to another user's bank account. """ payer_bank = int((await bank_data(ctx.author)).get("BANK", 0)) receiver_bank = int((await bank_data(target)).get("BANK", 0)) if await check_transfer(ctx, payer_bank, receiver_bank, target, amount): await update_money(target, bank=amount) await update_money(ctx.author, bank=-amount) await ctx.reply( f"Transferred {amount:,} flooneys to {target}.", mention_author=False ) @commands.command( name="deposit", aliases=["dep"], brief="Deposit money", description="Deposit money from your wallet to the bank", ) async def _deposit(self, ctx, amount: int | Literal["all"] = 0) -> None: """Deposit money from your wallet to your bank account. Amount can be an integer or 'all' to deposit all money from wallet.""" user_data = await bank_data(ctx.author) if user_data is None: await create_account(ctx) user_data = await bank_data(ctx.author) wallet_balance = int(user_data.get("WALLET", 0)) if amount == "all": amount = wallet_balance if 0 <= amount <= wallet_balance: await update_money(ctx.author, bank=amount, wallet=-amount) await ctx.reply("Transaction successful.") else: await ctx.reply("Insufficient funds in wallet") @commands.command(name="withdraw", brief="Withdraw money from bank to wallet") async def _withdraw(self, ctx, amount: int | Literal["all"] = 0) -> None: """Withdraw money from your bank account to your wallet. Amount can be an integer or 'all' to withdraw all money from bank.""" user_data = await bank_data(ctx.author) if user_data is None: await create_account(ctx) user_data = await bank_data(ctx.author) bank_balance = int(user_data.get("BANK", 0)) if amount == "all": amount = bank_balance if 0 <= amount <= bank_balance: await update_money(ctx.author, bank=-amount, wallet=amount) await ctx.reply("Transaction successful.") else: await ctx.reply("Insufficient funds") @commands.command(aliases=["lb"]) @commands.guild_only() async def leaderboard(self, ctx): users_data = self.db.fetch_all( "SELECT * FROM economy ORDER BY BANK + WALLET DESC" ) leaderboard_entries = [] position = 1 for user_data in users_data: user_id = int(user_data["ID"]) user = ctx.guild.get_member(user_id) or self.client.get_user(user_id) if user is None: try: user = await self.client.fetch_user(user_id) user_display = ( user.display_name if hasattr(user, "display_name") else str(user) ) except Exception: user_display = f"User {user_id}" else: user_display = ( user.display_name if hasattr(user, "display_name") else str(user) ) total_balance = int(user_data["BANK"]) + int(user_data["WALLET"]) flooney_icon = "<:flooney:1194943899765051473>" if position <= 3: entry = f"{['🥇', '🥈', '🥉'][position-1]}**{position} {user_display}** -- {total_balance:,}{flooney_icon} " else: entry = ( f"**{position} {user_display}** -- {total_balance:,}{flooney_icon}" ) leaderboard_entries.append(entry) position += 1 if position > 10: break embed = discord.Embed( title=f"Top {len(leaderboard_entries)} Richest Users - Leaderboard", description="\n".join(leaderboard_entries), color=discord.Color(0x00FF00), timestamp=datetime.datetime.utcnow(), ) embed.set_footer(text=f"GLOBAL - {ctx.guild.name}") await ctx.reply(embed=embed, mention_author=False) r""" .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | | | ______ | || | _________ | || | _______ | || | _____ | || | ____ | || | ________ | || | _____ | || | ______ | || | __ | || | _____ | || | _____ | || | ____ ____ | | | | |_ __ \ | || | |_ ___ | | || | |_ __ \ | || | |_ _| | || | .' `. | || | |_ ___ `. | || | |_ _| | || | .' ___ | | || | / \ | || | |_ _| | || | |_ _| | || | |_ _||_ _| | | | | | |__) | | || | | |_ \_| | || | | |__) | | || | | | | || | / .--. \ | || | | | `. \ | || | | | | || | / .' \_| | || | / /\ \ | || | | | | || | | | | || | \ \ / / | | | | | ___/ | || | | _| _ | || | | __ / | || | | | | || | | | | | | || | | | | | | || | | | | || | | | | || | / ____ \ | || | | | _ | || | | | _ | || | \ \/ / | | | | _| |_ | || | _| |___/ | | || | _| | \ \_ | || | _| |_ | || | \ `--' / | || | _| |___.' / | || | _| |_ | || | \ `.___.'\ | || | _/ / \ \_ | || | _| |__/ | | || | _| |__/ | | || | _| |_ | | | | |_____| | || | |_________| | || | |____| |___| | || | |_____| | || | `.____.' | || | |________.' | || | |_____| | || | `._____.' | || ||____| |____|| || | |________| | || | |________| | || | |______| | | | | | || | | || | | || | | || | | || | | || | | || | | || | | || | | || | | || | | | | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' """ @commands.command(name="daily", help="Claim your daily pocket money") async def claim_daily_money(self, ctx: commands.Context) -> None: """Claim your daily pocket money. You can claim once every 24 hours.""" try: user_data = await bank_data(ctx.author) last_claim = user_data.get("DAILY") now = discord.utils.utcnow() # Modern, timezone-aware # Convert last_claim to datetime if it's a timestamp (int or float) if last_claim: if isinstance(last_claim, (int, float)): last_claim_dt = datetime.datetime.fromtimestamp( last_claim, tz=datetime.timezone.utc ) elif isinstance(last_claim, str): try: last_claim_dt = datetime.datetime.fromtimestamp( float(last_claim), tz=datetime.timezone.utc ) except Exception: last_claim_dt = None elif isinstance(last_claim, datetime.datetime): # If it's naive, make it aware if last_claim.tzinfo is None: last_claim_dt = last_claim.replace(tzinfo=datetime.timezone.utc) else: last_claim_dt = last_claim else: last_claim_dt = None else: last_claim_dt = None if not last_claim_dt or (now - last_claim_dt).total_seconds() >= 86400: daily_reward = randint(200, 1000) await update_money(ctx.author, daily_reward) # Save the new timestamp as a float (UNIX time) await update_daily_timestamp(ctx.author, now) await ctx.reply( f"Your daily pocket money is {daily_reward:,}<:flooney:1194943899765051473>", mention_author=False, ) else: next_claim = last_claim_dt + timedelta(days=1) time_left = next_claim - now hours, remainder = divmod(int(time_left.total_seconds()), 3600) minutes, seconds = divmod(remainder, 60) await ctx.reply( f"Already claimed today. You need to wait **{hours}H {minutes}M {seconds}S**.", mention_author=False, ) except Exception as e: logging.error(f"Error in daily claim: {e}") await ctx.reply( f"An error occurred while claiming your daily reward. {e}", mention_author=False, ) r""" .----------------. .----------------. .----------------. .----------------. | .--------------. || .--------------. || .--------------. || .--------------. | | | _____ | || | ____ | || | ______ | || | _______ | | | | |_ _| | || | .' `. | || | |_ _ \ | || | / ___ | | | | | | | | || | / .--. \ | || | | |_) | | || | | (__ \_| | | | | _ | | | || | | | | | | || | | __'. | || | '.___`-. | | | | | |_' | | || | \ `--' / | || | _| |__) | | || | |`\____) | | | | | `.___.' | || | `.____.' | || | |_______/ | || | |_______.' | | | | | || | | || | | || | | | | '--------------' || '--------------' || '--------------' || '--------------' | '----------------' '----------------' '----------------' '----------------' """ async def setup(client): await client.add_cog(Economy(client))