import math import json import discord from gwendolyn.utils import cap class LookupFuncs(): def __init__(self, bot): self.bot = bot self.saves = ["strength_save","dexterity_save","constitution_save","intelligence_save","wisdom_save","charisma_save"] self.abilities = ["acrobatics","animal_handling","arcana","athletics","deception","history","insight","intimidation","investigation","medicine","nature","perception","performance","persuasion","religion","sleight_of_hand","stealth","survival"] # Calculates D&D stat modifier def modifier(self, statistic): mods = math.floor((statistic-10)/2) if mods >= 0: mods = "+"+str(mods) return(str(mods)) # Looks up a monster async def monsterFunc(self, ctx, query): query = cap(query) self.bot.log("Looking up "+query) # 1-letter monsters don't exist if len(query) < 2: self.bot.log("Monster name too short") await ctx.send("I don't know that monster...") else: # Opens "monsters.json" data = json.load(open('gwendolyn/resources/lookup/monsters.json', encoding = "utf8")) for monster in data: if "name" in monster and str(query) == monster["name"]: self.bot.log("Found it!") # Looks at the information about the monster and returns that information # in separate variables, allowing Gwendolyn to know where to separate # the messages if monster["subtype"] != "": types = (monster["type"]+" ("+monster["subtype"]+")") else: types = monster["type"] con_mod = math.floor((monster["constitution"]-10)/2) hit_dice = monster["hit_dice"] stats = ("**Str:** "+str(monster["strength"])+" ("+self.modifier(monster["strength"])+")\t**Dex:** "+str(monster["dexterity"])+" ("+self.modifier(monster["dexterity"])+")\t**Con:** "+str(monster["constitution"])+" ("+self.modifier(monster["constitution"])+")\n**Int: **"+str(monster["intelligence"])+" ("+self.modifier(monster["intelligence"])+")\t**Wis: **"+str(monster["wisdom"])+" ("+self.modifier(monster["wisdom"])+")\t**Cha: **"+str(monster["charisma"])+" ("+self.modifier(monster["charisma"])+")") saving_throws = "" for save in self.saves: if save in monster: if monster[save] >= 0: saving_throws += " "+cap(save[:3])+" +"+str(monster[save])+"," else: saving_throws += " "+cap(save[:3])+" "+str(monster[save])+"," if saving_throws != "": saving_throws = "\n**Saving Throws**"+saving_throws[:-1] skills = "" for skill in self.abilities: if skill in monster: if monster[skill] >= 0: skills += " "+cap(skill.replace("_"," "))+" +"+str(monster[skill])+"," else: skills += " "+cap(skill.replace("_"," "))+" "+str(monster[skill])+"," if skills != "": skills = "\n**Skills**"+skills[:-1] vulnerabilities = monster["damage_vulnerabilities"] if vulnerabilities != "": vulnerabilities = "\n**Damage Vulnerabilities** "+vulnerabilities resistances = monster["damage_resistances"] if resistances != "": resistances = "\n**Damage Resistances** "+resistances immunities = monster["damage_immunities"] if immunities != "": immunities = "\n**Damage Immunities** "+immunities c_immunities = monster["condition_immunities"] if c_immunities != "": c_immunities = "\n**Condition Immunities** "+c_immunities specialAbilities = "" if "special_abilities" in monster: for ability in monster["special_abilities"]: specialAbilities += "\n\n***"+ability["name"]+".*** "+ability["desc"] act = "" if "actions" in monster: for action in monster["actions"]: act += "\n\n***"+action["name"]+".*** "+action["desc"] react = "" if "reactions" in monster: for reaction in monster["reactions"]: react += "\n\n***"+reaction["name"]+".*** "+reaction["desc"] legendaryActions = "" if "legendary_actions" in monster: for action in monster["legendary_actions"]: legendaryActions += "\n\n***"+action["name"]+".*** "+action["desc"] if con_mod < 0: hit_dice += (" - "+str(con_mod * int(monster["hit_dice"].replace("d"," ").split()[0])*(-1))) if con_mod > 0: hit_dice += (" + "+str(con_mod * int(monster["hit_dice"].replace("d"," ").split()[0]))) new_part = "\n--------------------" monster_type = monster["size"]+" "+types+", "+monster["alignment"]+"*" basic_info = "\n**Armor Class** "+str(monster["armor_class"])+"\n**Hit Points** "+str(monster["hit_points"])+" ("+hit_dice+")\n**Speed **"+monster["speed"]+new_part+"\n" info = (monster_type+new_part+basic_info+stats+new_part+saving_throws+skills+vulnerabilities+resistances+immunities+c_immunities+"\n**Senses** "+monster["senses"]+"\n**Languages** "+monster["languages"]+"\n**Challenge** "+monster["challenge_rating"]) monsterInfo = [(info, query), (specialAbilities, "Special Abilities"), (act, "Actions"), (react, "Reactions"), (legendaryActions, "Legendary Actions")] self.bot.log("Returning monster information") # Sends the received information. Separates into separate messages if # there is too much text await ctx.send(f"Result for \"{query}\"") for text, title in monsterInfo: if text != "": if len(text) < 2000: em = discord.Embed(title = title, description = text, colour=0xDEADBF) await ctx.channel.send(embed = em) else: index = text[:2000].rfind(".")+1 em1 = discord.Embed(title = title, description = text[:index], colour=0xDEADBF) await ctx.channel.send(embed = em1) em2 = discord.Embed(title = "", description = text[index+1:], colour=0xDEADBF) await ctx.channel.send(embed = em2) break else: self.bot.log("Monster not in database") await ctx.send("I don't know that monster...") # Looks up a spell async def spellFunc(self, ctx, query): query = cap(query) self.bot.log("Looking up "+query) # Opens "spells.json" data = json.load(open('gwendolyn/resources/lookup/spells.json', encoding = "utf8")) if query in data: self.bot.log("Returning spell information") sendMessage = (f"***{query}***\n*{data[query]['level']} level {data[query]['school']}\nCasting Time: {data[query]['casting_time']}\nRange:{data[query]['range']}\nComponents:{data[query]['components']}\nDuration:{data[query]['duration']}*\n \n{data[query]['description']}") else: self.bot.log("I don't know that spell (error code 501)") sendMessage = "I don't think that's a spell (error code 501)" if len(sendMessage) > 2000: await ctx.send(sendMessage[:2000]) await ctx.send(sendMessage[2000:]) else: await ctx.send(sendMessage)