diff --git a/app/cogs/palworld.py b/app/cogs/palworld.py new file mode 100755 index 00000000..ac54dc3a --- /dev/null +++ b/app/cogs/palworld.py @@ -0,0 +1,215 @@ +from discord import option +from discord.ext import commands, tasks +import discord +import requests +from bs4 import BeautifulSoup +import re +import os + + +class PalWorld(commands.Cog): + def __init__(self, bot): + self.bot: commands.Bot = bot + # self.poll_server_population.start() + + palworld = discord.SlashCommandGroup("palworld", "Palworld related commands") + + async def get_all_pals(ctx: discord.AutocompleteContext): + """ + returns a list of all pals in the game, which can then be passed to the /ship command for auto complete + """ + import requests + from bs4 import BeautifulSoup + + all_pals = [] + + url = "https://paldex.io/palworld/pals/" + response = requests.get(url) + + soup = BeautifulSoup(response.text, "html.parser") + + x = soup.find_all( + "p", + class_="text-base lg:text-lg group-hover:underline underline-offset-4 text-center", + ) + for pal in x: + all_pals.append(pal.text) + + return sorted(set(all_pals)) + + @palworld.command( + guild_ids=None, + name="paldeck", + description="Looks up data about a pal", + contexts={ + discord.InteractionContextType.guild, + discord.InteractionContextType.bot_dm, + discord.InteractionContextType.private_channel, + }, + integration_types={ + discord.IntegrationType.guild_install, + discord.IntegrationType.user_install, + }, + ) + async def pal_lookup( + self, + ctx: discord.ApplicationContext, + pal: discord.Option( + str, + autocomplete=discord.utils.basic_autocomplete(get_all_pals), + description="Pal to look up", + ), + ): + pal_url = "https://paldex.io/palworld/pals/%s/" % pal.lower().replace(" ", "-") + response = requests.get(pal_url) + soup = BeautifulSoup(response.text, "html.parser") + + elements = {} + + pal_elements = soup.find("div", class_="flex flex-row flex-wrap gap-3") + for div in pal_elements: + pal_element_badge = div.find("img", class_="rounded-full w-8 h-8 m-2") + element_type = pal_element_badge.find_next("p").text + element_icon = pal_element_badge["src"] + elements[element_type] = element_icon + + primary_element = list(elements.keys())[0] + + # https://discordpy.readthedocs.io/en/latest/api.html?highlight=colour#discord.Colour + color_lookup = { + "Dark": discord.Color.dark_purple(), + "Dragon": discord.Color.purple(), + "Earth": discord.Color.greyple(), + "Electricity": discord.Color.yellow(), + "Fire": discord.Color.red(), + "Leaf": discord.Color.green(), + "Ice": discord.Color.blue(), + "Normal": discord.Color.lighter_grey(), + "Water": discord.Color.dark_blue(), + } + + embed = discord.Embed( + description="-------", + color=color_lookup[primary_element], + type="rich", + title=pal.capitalize(), + ) + + embed.set_author( + name=", ".join(elements.keys()), + icon_url=elements[primary_element], + url=pal_url, + ) + + embed.set_thumbnail( + url=soup.find( + "img", + class_="rounded-full w-32 h-32 border-2 border-amber-500 aspect-square", + )["src"] + ) + + # embed.add_field(name="Work Skills", value="-----", inline=False) + # work skills + skills_emojis = { + "Cooling": "❄️", + "Farming": "🚜", + "Gathering": "🍃", + "Generating Electricity": "⚡️", + "Handwork": "🤚", + "Kindling": "🔥", + "Lumbering": "🪵", + "Medicine Production": "💉", + "Mining": "⛏️", + "Planting": "🌱", + "Transporting": "📦", + "Watering": "💦", + } + + skill_table = soup.find("div", class_="flex flex-col gap-2") + for div in skill_table.find_all( + "div", class_=re.compile(".*border-amber-300\s+break-all") + ): + skill_name = div.find("p", class_="text-base sm:text-lg").text + skill_level = div.find( + "p", class_="text-base sm:text-lg mr-2 md:mr-4" + ).text.split("Lv")[-1] + + embed.add_field( + name=skills_emojis[skill_name] + " " + skill_name, + value="%s" % (int(skill_level) * "⭐️"), + inline=True, + ) + + # Partner Skill + embed.add_field(name="Partner Skill", value="-----", inline=False) + skill_name = soup.find("h2", string="Partner Skill").find_next( + "p", class_=re.compile(".*text-xl.*") + ) + skill_description = skill_name.find_next("p", class_="text-lg mr-4").text + embed.add_field( + name=skill_name.text, + value=skill_description, + inline=False, + ) + + # Drops + embed.add_field(name="Drops", value="-----", inline=False) + for div in soup.find_all( + "div", + class_="inline-flex flex-col gap-1 items-center bg-black-300 border border-amber-300 break-all p-2", + ): + item = div.text + item_name = item.split("Quantity")[0].split("Drop Chance") + amount = item.split("Quantity")[-1].split("Drop Chance") + embed.add_field( + name=" ".join(item_name), + value="", + inline=False, + ) + + await ctx.defer() + await ctx.send_followup(embed=embed) + + @palworld.command( + guild_ids=None, + name="elements", + description="Posts an infographic about which Pal elements are weak/strong against which", + contexts={ + discord.InteractionContextType.guild, + discord.InteractionContextType.bot_dm, + discord.InteractionContextType.private_channel, + }, + integration_types={ + discord.IntegrationType.guild_install, + discord.IntegrationType.user_install, + }, + ) + async def post_medpen_guide(self, ctx: discord.ApplicationContext): + await ctx.respond( + "https://img.game8.co/3822502/5ae8382d16bd390dd19f343e87680d51.png/show" + ) + + # @tasks.loop(seconds=60) + # async def poll_server_population(self): + # # Wait until the bot is ready before we actually start executing code + # await self.bot.wait_until_ready() + + # from source_rcon import SourceRcon + # from loguru import logger + + # logger.disable("source_rcon") + + # rcon = SourceRcon("192.168.1.200", 25575, os.getenv("pal_rcon_pass")) + # num_players = len(rcon.send_command("ShowPlayers").split("\n")[1:-1]) + + # # channel = self.bot.get_channel(1201389692759842816) # test server + # channel = self.bot.get_channel(1199397770746925239) + + # if str(num_players) in channel.name.split("/")[0]: + # return + + # await channel.edit(name="Palworlders (%s/16 online)" % num_players) + + +def setup(bot): + bot.add_cog(PalWorld(bot))