async def delete_tree(self, ctx, *, input_tree_name): """Delete tree of input_tree_name.""" user = find_or_insert_user(ctx.author.id) tree_index = find_tree_index(user, input_tree_name) if tree_index == None: await ctx.send(embed=error_embed( ctx.author, f"You do not have a tree with the name {input_tree_name}.")) return # get parts and move to inventory tree_name_output = user["trees"][tree_index]["name"] # iterate over tree to return parts to inventory inventory_parts = [] for key, value in user["trees"][tree_index].items(): if key == "name" or key == "background_color": continue part_for_inventory = value part_for_inventory["type"] = key inventory_parts.append(part_for_inventory) # add old part to inventory user["inventory"].extend(inventory_parts) # delete tree user["trees"].pop(tree_index) user_col.update_one({"user_id": ctx.author.id}, {"$set": user}) await ctx.send( embed=info_embed(ctx.author, f"Deleted tree {tree_name_output}."))
async def change_color(self, ctx, hex_code, *, input_tree_name): """Replaces the background color with a new color.""" user = find_or_insert_user(ctx.author.id) tree_index = find_tree_index(user, input_tree_name) if tree_index == None: await ctx.send(embed=error_embed( ctx.author, f"You do not have a tree with the name {input_tree_name}.")) return # convert to rgb try: h = hex_code.lstrip("#") user["trees"][tree_index]["background_color"] = tuple( int(h[i:i + 2], 16) for i in (0, 2, 4)) except: await ctx.send( embed=error_embed(ctx.author, f"{hex_code} is not valid.")) return user_col.update_one({"user_id": ctx.author.id}, {"$set": user}) tree_to_display = find_tree(user, input_tree_name) im_tree = create_tree_image(user, tree_to_display) embed = tree_embed(user, ctx.author, tree_to_display) await ctx.send(file=im_tree, embed=embed)
async def rename_tree(self, ctx, input_tree_name, *, new_name): """Rename tree of input_tree_name.""" if len(new_name) > 50: await ctx.send(embed=error_embed( ctx.author, "Tree Name cannot be over 50 characters long.")) return user = find_or_insert_user(ctx.author.id) tree_index = find_tree_index(user, input_tree_name) if tree_index == None: await ctx.send(embed=error_embed( ctx.author, f"You do not have a tree with the name {input_tree_name}.")) return user["trees"][tree_index]["name"] = new_name user_col.update_one({"user_id": ctx.author.id}, {"$set": user}) tree_to_display = find_tree(user, new_name) im_tree = create_tree_image(user, tree_to_display) embed = tree_embed(user, ctx.author, tree_to_display) await ctx.send(file=im_tree, embed=embed)
async def delete_inventory_part(self, ctx, input_inventory_num: int): """Delete a part from the inventory.""" user = find_or_insert_user(ctx.author.id) inventory_num = input_inventory_num - 1 # check for proper inventory number if input_inventory_num <= 0: await ctx.send(embed=error_embed( ctx.author, "Inventory numbers must be over 0.")) return elif len(user["inventory"]) - 1 < inventory_num: await ctx.send(embed=error_embed( ctx.author, f"Your inventory only goes up to {len(user['inventory'])}, but #{input_inventory_num} was entered." )) return user["inventory"].pop(inventory_num) user_col.update_one({"user_id": ctx.author.id}, {"$set": user}) await ctx.send(embed=info_embed( ctx.author, f"Part at #{input_inventory_num} has been removed."))
async def reset_tree(self, ctx, *, input_tree_name): """Resets the tree of input_tree_name.""" user = find_or_insert_user(ctx.author.id) tree_index = find_tree_index(user, input_tree_name) if tree_index == None: await ctx.send(embed=error_embed( ctx.author, f"You do not have a tree with the name {input_tree_name}.")) return # Reset tree and update in db tree_for_name = find_tree(user, input_tree_name) user["trees"][tree_index] = default_tree.copy() user["trees"][tree_index]["name"] = tree_for_name["name"] user_col.update_one({"user_id": ctx.author.id}, {"$set": user}) tree_to_display = find_tree(user, input_tree_name) im_tree = create_tree_image(user, tree_to_display) embed = tree_embed(user, ctx.author, tree_to_display) await ctx.send(file=im_tree, embed=embed)
async def buy_part_with_username(self, ctx, part_name, member: discord.User = None): """Buy a part from a player's shop with their username.""" user = find_or_insert_user(ctx.author.id) if len(user["inventory"]) >= 100: await ctx.send(embed=error_embed( ctx.author, "You have reached the limit of 100 parts in your inventory.")) return if member == None: member = ctx.author seller = user_col.find_one({"user_id": member.id}) if seller == None: await ctx.send( embed=error_embed(ctx.author, f"{member} has no parts listed.") ) return # get correct spelling of list in seller all_parts = seller["parts"] part_to_buy = None for part in all_parts: if part["name"].lower() == part_name.lower(): part_to_buy = part if part_to_buy == None: await ctx.send(embed=error_embed( ctx.author, f"{member} does not have a part named {part_name}.")) return if part_to_buy["price"] > user["balance"]: await ctx.send(embed=error_embed( ctx.author, f"You only have ${user['balance']}, but {part_to_buy['name']} costs ${part_to_buy['price']}." )) return # give part and remove money from user part_to_buy["creator"] = str(member) user["inventory"].append(part_to_buy) user["balance"] -= part_to_buy["price"] user_col.update_one({"user_id": ctx.author.id}, {"$set": user}) # give money to seller seller_tree_account = user_col.find_one({"user_id": member.id}) seller_tree_account["balance"] += part_to_buy["price"] user_col.update_one({"user_id": member.id}, {"$set": seller_tree_account}) await ctx.send(embed=info_embed( ctx.author, f"You bought {member}'s {part_to_buy['name']}."))
async def daily_reward(self, ctx): """Get a random amount of money every 24 hours.""" user = find_or_insert_user(ctx.author.id) reward = randint(50, 100) user["balance"] += reward user_col.update_one({"user_id" : ctx.author.id}, {"$set" : user}) await ctx.send(embed=info_embed(ctx.author, f"Added ${reward} to your balance! Your new balance is ${user['balance']}."))
async def clear_inventory(self, ctx): """Deletes all of the parts in the inventory.""" user = find_or_insert_user(ctx.author.id) user["inventory"].clear() user_col.update_one({"user_id": ctx.author.id}, {"$set": { "inventory": [] }}) await ctx.send(embed=info_embed(ctx.author, "Cleared your inventory."))
async def replace_part(self, ctx, input_inventory_num: int, *, input_tree_name): """Replaces a part of the tree of input_tree_name with the new input_inventory_num.""" user = find_or_insert_user(ctx.author.id) inventory_num = input_inventory_num - 1 if input_inventory_num <= 0: await ctx.send(embed=error_embed( ctx.author, "Inventory numbers must be over 0.")) return elif len(user["inventory"]) - 1 < inventory_num: await ctx.send(embed=error_embed( ctx.author, f"Your inventory only goes up to {len(user['inventory'])}, but #{input_inventory_num} was entered." )) return tree_index = find_tree_index(user, input_tree_name) if tree_index == None: await ctx.send(embed=error_embed( ctx.author, f"You do not have a tree with the name {input_tree_name}.")) return # get new part from user part = user["inventory"].pop(inventory_num) # set tree part to new part part_type = part.pop("type") # add old part to inventory part_for_inventory = user["trees"][tree_index][part_type] part_for_inventory["type"] = part_type user["inventory"].append(part_for_inventory) # add new part to tree user["trees"][tree_index][part_type] = part user_col.update_one({"user_id": ctx.author.id}, {"$set": user}) tree_to_display = find_tree(user, input_tree_name) im_tree = create_tree_image(user, tree_to_display) embed = tree_embed(user, ctx.author, tree_to_display) await ctx.send(file=im_tree, embed=embed)
async def display_tree(self, ctx, *, input_tree_name): """Displays the tree of input_tree_name.""" user = find_or_insert_user(ctx.author.id) tree_to_display = find_tree(user, input_tree_name) if tree_to_display == None: await ctx.send(embed=error_embed( ctx.author, f"You do not have a tree with the name {input_tree_name}.")) return im_tree = create_tree_image(user, tree_to_display) embed = tree_embed(user, ctx.author, tree_to_display) await ctx.send(file=im_tree, embed=embed)
async def find_top_balance(self, ctx): """Send top 10 balances.""" author = find_or_insert_user(ctx.author.id) author_position = user_col.find({"balance" : {"$gt" : author["balance"]}}).count() leaderboard_codeblock = "```\n" minutes_since_update = (datetime.now() - self.last_leaderboard_update).total_seconds() / 60 for i, (username, balance) in enumerate(self.top_users): leaderboard_codeblock += f"{i+1}: {username} | ${balance}\n" leaderboard_codeblock += "```" embed = discord.Embed(title="Top Balances", color=16776960)\ .add_field(name="Leaderboard", value=leaderboard_codeblock)\ .set_footer(text=f"{ctx.author}'s Current Position: {author_position+1}\nLast Updated: {minutes_since_update : .1f} minutes ago") await ctx.send(embed=embed)
async def create_tree(self, ctx, *, input_tree_name): """Creates a new tree.""" user = find_or_insert_user(ctx.author.id) if len(input_tree_name) > 50: await ctx.send(embed=error_embed( ctx.author, "Tree Name cannot be over 50 characters long.")) return if len(user["trees"]) >= 3: await ctx.send(embed=error_embed( ctx.author, "You are already at the max number of trees! To reset a tree, use the reset [Tree Name] command. To delete a tree, use the delete [Tree Name] command." )) return if find_tree(user, input_tree_name) != None: await ctx.send(embed=error_embed( ctx.author, f"A tree with the name {input_tree_name} already exists.")) return new_tree = default_tree.copy() new_tree["name"] = input_tree_name user["trees"].append(new_tree) user_col.update_one({"user_id": ctx.author.id}, {"$set": user}) tree_to_display = find_tree(user, input_tree_name) if tree_to_display == None: await ctx.send(embed=error_embed( ctx.author, f"You do not have a tree with the name {input_tree_name}.")) return im_tree = create_tree_image(user, tree_to_display) embed = tree_embed(user, ctx.author, tree_to_display) await ctx.send(file=im_tree, embed=embed)
async def delete_part_listing(self, ctx, part_name): """Delete a listing from the player's shop.""" user = find_or_insert_user(ctx.author.id) part_for_removal = None for i, part in enumerate(user["parts"]): if part["name"].lower() == part_name.lower(): part_for_removal = part["name"] break if part_for_removal == None: await ctx.send(embed=error_embed( ctx.author, f"Part {part_name} was not found.")) return user["parts"].pop(i) user_col.update_one({"user_id": ctx.author.id}, {"$set": user}) await ctx.send( embed=info_embed(ctx.author, f"Unlisted part {part_for_removal}."))
async def list_inventory(self, ctx, input_inventory_num: int = None): """Lists the entire inventory 25 items at a time.""" user = find_or_insert_user(ctx.author.id) # information on specific part if input_inventory_num != None: inventory_num = input_inventory_num - 1 # check for proper inventory number if input_inventory_num <= 0: await ctx.send(embed=error_embed( ctx.author, "Inventory numbers must be over 0.")) return elif len(user["inventory"]) - 1 < inventory_num: await ctx.send(embed=error_embed( ctx.author, f"Your inventory only goes up to {len(user['inventory'])}, but #{input_inventory_num} was entered." )) return inventory_part = user["inventory"][inventory_num] part_picture = bytes_to_file(inventory_part["image"]) embed = inventory_part_embed(inventory_part, inventory_part["creator"]) await ctx.send(file=part_picture, embed=embed) return embed = discord.Embed(title=f"{ctx.author}'s Inventory", color=255) total_part_lists = ceil(len(user["inventory"]) / 25) i = 1 for part in user["inventory"][:26]: embed = embed.add_field(name=part["type"], value=f"{i} : {part['creator']}'s {part['name']}", inline=False)\ .set_footer(text=f"Page 1 / {total_part_lists}") i += 1 inventory_message = await ctx.send(embed=embed) # only one page needs to be displayed if len(user["inventory"]) <= 25: return await inventory_message.add_reaction("⬅️") await inventory_message.add_reaction("➡️") def check(reaction, user): return reaction.message.id == inventory_message.id and user.id == ctx.author.id and str( reaction.emoji) in ["⬅️", "➡️"] current_part_list = 1 while True: try: reaction, reaction_user = await self.bot.wait_for( "reaction_add", check=check, timeout=60) # check for arrow reactions if str(reaction.emoji) == "⬅️" and current_part_list > 1: current_part_list -= 1 inventory_index_first = (current_part_list - 1) * 25 inventory_index_last = (current_part_list * 25) + 1 embed = discord.Embed(title=f"{ctx.author}'s Inventory", color=255)\ .set_footer(text=f"Page {current_part_list} / {total_part_lists}") j = inventory_index_first for part in user["inventory"][ inventory_index_first:inventory_index_last]: embed = embed.add_field( name=part["type"], value=f"{j+1} : {part['creator']}'s {part['name']}", inline=False) j += 1 await inventory_message.edit(embed=embed) await inventory_message.remove_reaction( reaction, reaction_user) elif str(reaction.emoji ) == "➡️" and current_part_list < total_part_lists: current_part_list += 1 inventory_index_first = (current_part_list - 1) * 25 inventory_index_last = (current_part_list * 25) + 1 embed = discord.Embed(title=f"{ctx.author}'s Inventory", color=255)\ .set_footer(text=f"Page {current_part_list} / {total_part_lists}") j = inventory_index_first for part in user["inventory"][ inventory_index_first:inventory_index_last]: embed = embed.add_field( name=part["type"], value=f"{j+1} : {part['creator']}'s {part['name']}", inline=False) j += 1 await inventory_message.edit(embed=embed) await inventory_message.remove_reaction( reaction, reaction_user) except asyncio.TimeoutError: await inventory_message.clear_reaction("⬅️") await inventory_message.clear_reaction("➡️") break
async def create_part_listing(self, ctx, part_type, part_name, list_price: int): """List a part on the player's shop.""" part_type = part_type.lower() if part_type not in valid_parts: await ctx.send( embed=error_embed(ctx.author, "Enter base, trunk, or leaves.")) return if len(part_name) > 50: await ctx.send(embed=error_embed( ctx.author, "Part Name cannot be over 50 characters long.")) return if list_price < 0 or list_price > 10000: await ctx.send(embed=error_embed( ctx.author, "List Price cannot be less than $0 or over $10,000.")) return if part_type == "base" and await check_attachment(ctx, 15, 3) == False: return elif part_type in ["trunk", "leaves"] and await check_attachment( ctx, 15, 12) == False: return user = find_or_insert_user(ctx.author.id) parts = user["parts"] if len(parts) >= 15: await ctx.send(embed=error_embed( ctx.author, "You have exceeded the limit of 15 parts.")) return for part in parts: if part["name"].lower() == part_name.lower(): await ctx.send(embed=error_embed( ctx.author, f"You have already listed a part with the name {part['name']}." )) return # get image file with aiohttp attachment_bytes = await ctx.message.attachments[0].read() parts.append({ "image": attachment_bytes, "name": part_name, "type": part_type, "price": list_price }) user_col.update_one({"user_id": ctx.author.id}, {"$set": user}) im_part = bytes_to_file(attachment_bytes) embed = discord.Embed(title=f"New {part_type} Listing", color=255)\ .set_author(name= str(ctx.author))\ .add_field(name="Name", value=part_name)\ .add_field(name="List Price", value=list_price)\ .set_image(url="attachment://image.png") await ctx.send(file=im_part, embed=embed)