# Economy Packs Module # Contains pack opening, daily rewards, and donation commands from the original economy.py import logging from discord.ext import commands from discord import app_commands, Member import discord import datetime # Import specific utilities needed by this module import random from api_calls import db_get, db_post from helpers.constants import PD_PLAYERS_ROLE_NAME, PD_PLAYERS, IMAGES from helpers import ( get_team_by_owner, display_cards, give_packs, legal_channel, get_channel, get_cal_user, refresh_sheet, roll_for_cards, int_timestamp, get_context_user, ) from helpers.discord_utils import get_team_embed, get_emoji from discord_ui import SelectView, SelectOpenPack logger = logging.getLogger("discord_app") class Packs(commands.Cog): """Pack management, daily rewards, and donation system for Paper Dynasty.""" def __init__(self, bot): self.bot = bot @commands.hybrid_group(name="donation", help="Mod: Give packs for PD donations") @commands.has_any_role(PD_PLAYERS_ROLE_NAME) async def donation(self, ctx: commands.Context): if ctx.invoked_subcommand is None: await ctx.send( "To buy packs, visit https://ko-fi.com/manticorum/shop and include your discord username!" ) @donation.command( name="premium", help="Mod: Give premium packs", aliases=["p", "prem"] ) async def donation_premium(self, ctx: commands.Context, num_packs: int, gm: Member): if ctx.author.id != self.bot.owner_id: await ctx.send("Wait a second. You're not in charge here!") return team = await get_team_by_owner(gm.id) p_query = await db_get("packtypes", params=[("name", "Premium")]) if p_query["count"] == 0: await ctx.send("Oof. I couldn't find a Premium Pack") return total_packs = await give_packs( team, num_packs, pack_type=p_query["packtypes"][0] ) await ctx.send( f"The {team['lname']} now have {total_packs['count']} total packs!" ) @donation.command( name="standard", help="Mod: Give standard packs", aliases=["s", "sta"] ) async def donation_standard( self, ctx: commands.Context, num_packs: int, gm: Member ): if ctx.author.id != self.bot.owner_id: await ctx.send("Wait a second. You're not in charge here!") return team = await get_team_by_owner(gm.id) p_query = await db_get("packtypes", params=[("name", "Standard")]) if p_query["count"] == 0: await ctx.send("Oof. I couldn't find a Standard Pack") return total_packs = await give_packs( team, num_packs, pack_type=p_query["packtypes"][0] ) await ctx.send( f"The {team['lname']} now have {total_packs['count']} total packs!" ) @commands.hybrid_command(name="lastpack", help="Replay your last pack") @commands.check(legal_channel) @commands.has_any_role(PD_PLAYERS_ROLE_NAME) async def last_pack_command(self, ctx: commands.Context): team = await get_team_by_owner(get_context_user(ctx).id) if not team: await ctx.send( "I don't see a team for you, yet. You can sign up with the `/newteam` command!" ) return p_query = await db_get( "packs", params=[ ("opened", True), ("team_id", team["id"]), ("new_to_old", True), ("limit", 1), ], ) if not p_query["count"]: await ctx.send("I do not see any packs for you, bub.") return pack_name = p_query["packs"][0]["pack_type"]["name"] if pack_name == "Standard": pack_cover = IMAGES["pack-sta"] elif pack_name == "Premium": pack_cover = IMAGES["pack-pre"] else: pack_cover = None c_query = await db_get("cards", params=[("pack_id", p_query["packs"][0]["id"])]) if not c_query["count"]: await ctx.send("Hmm...I didn't see any cards in that pack.") return await display_cards( c_query["cards"], team, ctx.channel, ctx.author, self.bot, pack_cover=pack_cover, ) @app_commands.command( name="comeonmanineedthis", description="Daily check-in for cards, currency, and packs", ) @commands.has_any_role(PD_PLAYERS) @commands.check(legal_channel) async def daily_checkin(self, interaction: discord.Interaction): await interaction.response.defer() team = await get_team_by_owner(interaction.user.id) if not team: await interaction.edit_original_response( content="I don't see a team for you, yet. You can sign up with the `/newteam` command!" ) return current = await db_get("current") now = datetime.datetime.now() midnight = int_timestamp( datetime.datetime(now.year, now.month, now.day, 0, 0, 0) ) daily = await db_get( "rewards", params=[ ("name", "Daily Check-in"), ("team_id", team["id"]), ("created_after", midnight), ], ) logger.debug(f"midnight: {midnight} / now: {int_timestamp(now)}") logger.debug(f"daily_return: {daily}") if daily: await interaction.edit_original_response( content="Looks like you already checked in today - come back at midnight Central!" ) return await db_post( "rewards", payload={ "name": "Daily Check-in", "team_id": team["id"], "season": current["season"], "week": current["week"], "created": int_timestamp(now), }, ) current = await db_get("current") check_ins = await db_get( "rewards", params=[ ("name", "Daily Check-in"), ("team_id", team["id"]), ("season", current["season"]), ], ) check_count = check_ins["count"] % 5 # 2nd, 4th, and 5th check-ins if check_count == 0 or check_count % 2 == 0: # Every fifth check-in if check_count == 0: greeting = await interaction.edit_original_response( content="Hey, you just earned a Standard pack of cards!" ) pack_channel = get_channel(interaction, "pack-openings") p_query = await db_get("packtypes", params=[("name", "Standard")]) if not p_query: await interaction.edit_original_response( content=f"I was not able to pull this pack for you. " f"Maybe ping {get_cal_user(interaction).mention}?" ) return # Every second and fourth check-in else: greeting = await interaction.edit_original_response( content="Hey, you just earned a player card!" ) pack_channel = interaction.channel p_query = await db_get( "packtypes", params=[("name", "Check-In Player")] ) if not p_query: await interaction.edit_original_response( content=f"I was not able to pull this card for you. " f"Maybe ping {get_cal_user(interaction).mention}?" ) return await give_packs(team, 1, p_query["packtypes"][0]) p_query = await db_get( "packs", params=[ ("opened", False), ("team_id", team["id"]), ("new_to_old", True), ("limit", 1), ], ) if not p_query["count"]: await interaction.edit_original_response( content=f"I do not see any packs in here. {await get_emoji(interaction, 'ConfusedPsyduck')}" ) return pack_ids = await roll_for_cards( p_query["packs"], extra_val=check_ins["count"] ) if not pack_ids: await greeting.edit( content=f"I was not able to create these cards {await get_emoji(interaction, 'slight_frown')}" ) return all_cards = [] for p_id in pack_ids: new_cards = await db_get("cards", params=[("pack_id", p_id)]) all_cards.extend(new_cards["cards"]) if not all_cards: await interaction.edit_original_response( content=f"I was not able to pull these cards {await get_emoji(interaction, 'slight_frown')}" ) return await display_cards( all_cards, team, pack_channel, interaction.user, self.bot ) await refresh_sheet(team, self.bot) return # 1st, 3rd check-ins else: d_1000 = random.randint(1, 1000) m_reward = 0 if d_1000 < 500: m_reward = 10 elif d_1000 < 900: m_reward = 15 elif d_1000 < 990: m_reward = 20 else: m_reward = 25 team = await db_post(f"teams/{team['id']}/money/{m_reward}") await interaction.edit_original_response( content=f"You just earned {m_reward}₼! That brings your wallet to {team['wallet']}₼!" ) @app_commands.command( name="open-packs", description="Open packs from your inventory" ) @app_commands.checks.has_any_role(PD_PLAYERS) async def open_packs_slash(self, interaction: discord.Interaction): if interaction.channel.name in [ "paper-dynasty-chat", "pd-news-ticker", "pd-network-news", ]: await interaction.response.send_message( f"Please head to down to {get_channel(interaction, 'pd-bot-hole')} to run this command.", ephemeral=True, ) return owner_team = await get_team_by_owner(interaction.user.id) if not owner_team: await interaction.response.send_message( "I don't see a team for you, yet. You can sign up with the `/newteam` command!" ) return p_query = await db_get( "packs", params=[("team_id", owner_team["id"]), ("opened", False)] ) if p_query["count"] == 0: await interaction.response.send_message( "Looks like you are clean out of packs, friendo. You can earn them by playing PD games or by " "donating to the league." ) return # Pack types that are auto-opened and should not appear in the manual open menu AUTO_OPEN_TYPES = {"Check-In Player"} # Group packs by type and customization (e.g. Standard, Standard-Orioles, Standard-2012, Premium) p_count = 0 p_data = { "Standard": [], "Premium": [], "Daily": [], "MVP": [], "All Star": [], "Mario": [], "Team Choice": [], } logger.debug("Parsing packs...") for pack in p_query["packs"]: p_group = None logger.debug(f"pack: {pack}") logger.debug(f"pack cardset: {pack['pack_cardset']}") if pack["pack_type"]["name"] in AUTO_OPEN_TYPES: logger.debug( f"Skipping auto-open pack type: {pack['pack_type']['name']}" ) continue if pack["pack_team"] is None and pack["pack_cardset"] is None: p_group = pack["pack_type"]["name"] # Add to p_data if this is a new pack type if p_group not in p_data: p_data[p_group] = [] elif pack["pack_team"] is not None: if pack["pack_type"]["name"] == "Standard": p_group = f"Standard-Team-{pack['pack_team']['id']}-{pack['pack_team']['sname']}" elif pack["pack_type"]["name"] == "Premium": p_group = f"Premium-Team-{pack['pack_team']['id']}-{pack['pack_team']['sname']}" elif pack["pack_type"]["name"] == "Team Choice": p_group = f"Team Choice-Team-{pack['pack_team']['id']}-{pack['pack_team']['sname']}" elif pack["pack_type"]["name"] == "MVP": p_group = f"MVP-Team-{pack['pack_team']['id']}-{pack['pack_team']['sname']}" if pack["pack_cardset"] is not None: p_group += f"-Cardset-{pack['pack_cardset']['id']}" elif pack["pack_cardset"] is not None: if pack["pack_type"]["name"] == "Standard": p_group = f"Standard-Cardset-{pack['pack_cardset']['id']}-{pack['pack_cardset']['name']}" elif pack["pack_type"]["name"] == "Premium": p_group = f"Premium-Cardset-{pack['pack_cardset']['id']}-{pack['pack_cardset']['name']}" elif pack["pack_type"]["name"] == "Team Choice": p_group = f"Team Choice-Cardset-{pack['pack_cardset']['id']}-{pack['pack_cardset']['name']}" elif pack["pack_type"]["name"] == "All Star": p_group = f"All Star-Cardset-{pack['pack_cardset']['id']}-{pack['pack_cardset']['name']}" elif pack["pack_type"]["name"] == "MVP": p_group = f"MVP-Cardset-{pack['pack_cardset']['id']}-{pack['pack_cardset']['name']}" elif pack["pack_type"]["name"] == "Promo Choice": p_group = f"Promo Choice-Cardset-{pack['pack_cardset']['id']}-{pack['pack_cardset']['name']}" logger.info(f"p_group: {p_group}") if p_group is not None: p_count += 1 if p_group not in p_data: p_data[p_group] = [pack] else: p_data[p_group].append(pack) if p_count == 0: await interaction.response.send_message( "Looks like you are clean out of packs, friendo. You can earn them by playing PD games or by " "donating to the league." ) return # Display options and ask which group to open embed = get_team_embed("Unopened Packs", team=owner_team) embed.description = owner_team["lname"] select_options = [] for key in p_data: if len(p_data[key]) > 0: pretty_name = None # Not a specific pack if "-" not in key: pretty_name = key elif "Team" in key: pretty_name = f"{key.split('-')[0]} - {key.split('-')[3]}" elif "Cardset" in key: pretty_name = f"{key.split('-')[0]} - {key.split('-')[3]}" else: # Pack type name contains a hyphen (e.g. "Check-In Player") pretty_name = key if pretty_name is not None: embed.add_field(name=pretty_name, value=f"Qty: {len(p_data[key])}") select_options.append( discord.SelectOption(label=pretty_name, value=key) ) view = SelectView( select_objects=[SelectOpenPack(select_options, owner_team)], timeout=15 ) await interaction.response.send_message(embed=embed, view=view) async def setup(bot): """Setup function for the Packs cog.""" await bot.add_cog(Packs(bot))