def parseFeat(m, compendium, args): feat = ET.SubElement(compendium, 'feat') name = ET.SubElement(feat, 'name') name.text = m['name'] prereqs = ET.SubElement(feat,'prerequisite') if 'prerequisite' in m: prereq = [] for pre in m['prerequisite']: if 'ability' in pre: if type(pre['ability']) == list: abilityor = [] if all(next(iter(v.values())) == next(iter(pre['ability'][0].values())) for v in pre['ability']): for v in pre['ability']: for s,val in v.items(): abilityor.append(stats[s]) prereq.append("{} {} or higher".format(" or ".join(abilityor),next(iter(pre['ability'][0].values())))) else: for v in pre['ability']: for s,val in v.items(): abilityor.append("{} {} or higher".format(stats[k],val)) prereq.append(" or ".join(abilityor)) else: for k,v in pre['ability'].items(): prereq.append("{} {} or higher".format(stats[k],v)) if 'spellcasting' in pre and pre['spellcasting']: prereq.append("The ability to cast at least one spell") if 'proficiency' in pre: for prof in pre['proficiency']: for k,v in prof.items(): prereq.append("Proficiency with {} {}".format(v,k)) if 'race' in pre: for r in pre['race']: prereq.append("{}{}".format(r['name']," ({})".format(r['subrace']) if 'subrace' in r else "").title()) prereqs.text = ", ".join(prereq) if 'entries' not in m: m['entries'] = [] if 'source' in m: name = m["name"] if args.addimgs and os.path.isdir("./img") and not os.path.isfile("./items/" + name + ".png"): if not os.path.isdir("./items/"): os.mkdir("./items/") artworkpath = None if os.path.isfile("./img/items/" + m["name"] + ".jpg"): artworkpath = "./img/items/" + m["name"] + ".jpg" elif os.path.isfile("./img/items/" + m["name"] + ".png"): artworkpath = "./img/items/" + m["name"] + ".png" elif os.path.isfile("./img/items/" + m["source"] + "/" + m["name"] + ".png"): artworkpath = "./img/items/" + m["source"] + "/" + m["name"] + ".png" if artworkpath is not None: if args.verbose: print("Converting Image: " + artworkpath) with Image(filename=artworkpath) as img: img.format='png' img.save(filename="./items/" + name + ".png") imagetag = ET.SubElement(feat, 'image') imagetag.text = name + ".png" elif args.addimgs and os.path.isfile("./items/" + name + ".png"): imagetag = ET.SubElement(feat, 'image') imagetag.text = name + ".png" #source = ET.SubElement(feat, 'source') sourcetext = "{} p. {}".format( utils.getFriendlySource(m['source']), m['page']) if 'page' in m and m['page'] != 0 else utils.getFriendlySource(m['source']) if 'otherSources' in m and m["otherSources"] is not None: for s in m["otherSources"]: sourcetext += ", " sourcetext += "{} p. {}".format( utils.getFriendlySource(s["source"]), s["page"]) if 'page' in s and s["page"] != 0 else utils.getFriendlySource(s["source"]) if 'entries' in m: if args.nohtml: m['entries'].append("Source: {}".format(sourcetext)) else: m['entries'].append("<i>Source: {}</i>".format(sourcetext)) else: if args.nohtml: m['entries'] = ["Source: {}".format(sourcetext)] else: m['entries'] = ["<i>Source: {}</i>".format(sourcetext)] bodyText = ET.SubElement(feat, 'text') bodyText.text = "" if 'ability' in m: for ability in m['ability']: for k,v in ability.items(): if k in stats: bonusmod = ET.SubElement(feat, 'modifier', {'category': 'ability score'}) bonusmod.text = "{} {:+d}".format(stats[k],v) elif k == 'choose': for e in m['entries']: if type(e) == dict and e['type'] == 'list': if len(v["from"]) != 6: e['items'].insert(0,"Increase your {} score by {}, to a maximum of 20".format(" or ".join([stats[x] for x in v["from"]]),v["amount"])) if 'entries' in m: for e in m['entries']: if "colLabels" in e: bodyText.text += " | ".join([utils.remove5eShit(x) for x in e['colLabels']]) bodyText.text += "\n" for row in e['rows']: rowthing = [] for r in row: if isinstance(r, dict) and 'roll' in r: rowthing.append( "{}-{}".format( r['roll']['min'], r['roll']['max']) if 'min' in r['roll'] else str( r['roll']['exact'])) else: rowthing.append(utils.fixTags(str(r),m,args.nohtml)) bodyText.text += " | ".join(rowthing) + "\n" elif "entries" in e: subentries = [] if 'name' in e: if args.nohtml: bodyText.text += "{}: ".format(e['name']) else: bodyText.text += "<b>{}:</b> ".format(e['name']) for sube in e["entries"]: if type(sube) == str: subentries.append(utils.fixTags(sube,m,args.nohtml)) elif type(sube) == dict and "text" in sube: subentries.append(utils.fixTags(sube["text"],m,args.nohtml)) elif type(sube) == dict and sube["type"] == "list" and "style" in sube and sube["style"] == "list-hang-notitle": for item in sube["items"]: if type(item) == dict and 'type' in item and item['type'] == 'item': if args.nohtml: subentries.append("• {}: {}".format(item["name"],utils.fixTags(item["entry"],m,args.nohtml))) else: subentries.append("• <i>{}:</i> {}".format(item["name"],utils.fixTags(item["entry"],m,args.nohtml))) else: subentries.append("• {}".format(utils.fixTags(item,m,args.nohtml))) elif type(sube) == dict and sube["type"] == "list": for item in sube["items"]: if type(item) == dict and "entries" in item: ssubentries = [] for sse in item["entries"]: if type(sse) == str: ssubentries.append(utils.fixTags(sse,m,args.nohtml)) elif type(sse) == dict and "text" in sse: ssubentries.append(utils.fixTags(sse["text"],m,args.nohtml)) subentries.append("\n".join(ssubentries)) elif type(item) == dict and 'type' in item and item['type'] == 'item': if args.nohtml: subentries.append("• {}: {}".format(item["name"],utils.fixTags(item["entry"],m,args.nohtml))) else: subentries.append("• <i>{}:</i> {}".format(item["name"],utils.fixTags(item["entry"],m,args.nohtml))) else: subentries.append("• {}".format(utils.fixTags(item,m,args.nohtml))) bodyText.text += "\n".join(subentries) + "\n" else: if type(e) == dict and e["type"] == "list" and "style" in e and e["style"] == "list-hang-notitle": for item in e["items"]: if args.nohtml: bodyText.text += "• {}: {}".format(item["name"],utils.fixTags(item["entry"],m,args.nohtml)) + "\n" else: bodyText.text += "• <i>{}:</i> {}".format(item["name"],utils.fixTags(item["entry"],m,args.nohtml)) + "\n" elif type(e) == dict and e["type"] == "list": for item in e["items"]: if "entries" in item: subentries = [] for sube in item["entries"]: if type(sube) == str: subentries.append(utils.fixTags(sube,m,args.nohtml)) elif type(sube) == dict and "text" in sube: subentries.append(utils.fixTags(sube["text"],m,args.nohtml)) bodyText.text += "\n".join(subentries) + "\n" else: bodyText.text += "• {}".format(utils.fixTags(item,m,args.nohtml)) + "\n" else: bodyText.text += utils.fixTags(e,m,args.nohtml) + "\n" bodyText.text = bodyText.text.rstrip() for match in re.finditer(r'You gain proficiency in the ([^ ]*?)( and (.*?))? skill',bodyText.text): bonusmod = ET.SubElement(feat, 'proficiency') bonusmod.text = match.group(1) if match.group(2) and match.group(3): bonusmod.text = ", " + match.group(3)
def parseClass(m, compendium, args): # for eachClasss in compendium.findall('Class'): # if eachClasss.find('name').text == m['name']: # m['name'] = "{} (DUPLICATE IN {})".format(m['name'],m['source']) stats = { "str": "Strength", "dex": "Dexterity", "con": "Constitution", "int": "Intelligence", "wis": "Wisdom", "cha": "Charisma" } slots = "" numberofSkills = "" if m['source'] == "UASidekicks": m['hd'] = {"number": 1, "faces": 10} m["startingProficiencies"] = {'skills': []} Class = ET.SubElement(compendium, 'class') name = ET.SubElement(Class, 'name') name.text = m['name'] hd = ET.SubElement(Class, 'hd') hd.text = str(m['hd']['faces']) saveProficiency = [] for stat, value in stats.items(): if 'proficiency' in m and stat in m['proficiency']: saveProficiency.append("{}".format(stats[stat])) proficiency = ET.SubElement(Class, 'proficiency') proficiencyList = [] numSkills = ET.SubElement(Class, 'numSkills') for skill in m['startingProficiencies']['skills']: if 'choose' in skill and 'from' in skill['choose']: skillList = skill['choose']['from'] proficiencyList = saveProficiency + skillList proficiencytext = ", ".join(proficiencyList).title() proficiency.text = proficiencytext numberofSkills = str(skill['choose']['count']) numSkills.text = str(skill['choose']['count']) spellcastingAbility = "" if 'spellcastingAbility' in m: spellAbility = ET.SubElement(Class, 'spellAbility') spellcastingAbility = "{}".format(stats[m['spellcastingAbility']]) spellAbility.text = spellcastingAbility myattributes = {"level": "1"} autolevel = ET.SubElement(Class, 'autolevel', myattributes) featureattributes = {"optional": "YES"} StartingFeature = ET.SubElement(autolevel, 'feature', featureattributes) SFName = ET.SubElement(StartingFeature, 'name') SFName.text = "Starting " + m['name'] SFText = ET.SubElement(StartingFeature, 'text') SFText.text = "As a 1st-level " + m[ 'name'] + ", you begin play with " + str( m['hd']['faces']) + "+your Constitution modifier hit points." SFText = ET.SubElement(StartingFeature, 'text') SFText.text = "" SFText = ET.SubElement(StartingFeature, 'text') SFText.text = "You are proficient with the following items, in addition to any proficiencies provided by your race or background." SFText = ET.SubElement(StartingFeature, 'text') if "armor" in m['startingProficiencies']: armortext = ", ".join([ x if type(x) == str else x['full'] for x in m['startingProficiencies']['armor'] ]) else: armortext = "none" SFText.text = "• Armor: " + armortext SFText = ET.SubElement(StartingFeature, 'text') if "weapons" in m['startingProficiencies']: weapontext = ", ".join(m['startingProficiencies']['weapons']) else: weapontext = "none" SFText.text = "• Weapons: " + weapontext SFText = ET.SubElement(StartingFeature, 'text') if "tools" in m['startingProficiencies']: SFText.text = "• Tools: " + ", ".join( m['startingProficiencies']['tools']) else: SFText.text = "• Tools: none" SFText = ET.SubElement(StartingFeature, 'text') if numberofSkills != "": SFText.text = "• Skills: Choose " + numberofSkills + " from " + ", ".join( skillList).title() SFText = ET.SubElement(StartingFeature, 'text') SFText.text = "" SFText = ET.SubElement(StartingFeature, 'text') if 'startingEquipment' in m: SFText.text = "You begin play with the following equipment, in addition to any equipment provided by your background." for startingEquipment in m['startingEquipment']['default']: SFText = ET.SubElement(StartingFeature, 'text') SFText.text = "• " + utils.fixTags(startingEquipment, m, args.nohtml) SFText = ET.SubElement(StartingFeature, 'text') SFText.text = "" if "goldAlternative" in m['startingEquipment']: SFText = ET.SubElement(StartingFeature, 'text') SFText.text = "Alternatively, you may start with " + utils.fixTags( m['startingEquipment']['goldAlternative'], m, args.nohtml) + " gp and choose your own equipment." SFText = ET.SubElement(StartingFeature, 'text') SFText.text = "" SFText = ET.SubElement(StartingFeature, 'text') SFText.text = "Source: " + utils.getFriendlySource( m['source']) + " p. " + str(m['page']) if 'multiclassing' in m: myattributes = {"level": "1"} autolevel = ET.SubElement(Class, 'autolevel', myattributes) featureattributes = {"optional": "YES"} StartingFeature = ET.SubElement(autolevel, 'feature', featureattributes) SFName = ET.SubElement(StartingFeature, 'name') SFName.text = "Multiclass " + m['name'] SFText = ET.SubElement(StartingFeature, 'text') SFText.text = 'To multiclass as a ' + m[ 'name'] + ', you must meet the following prerequisites:' SFText = ET.SubElement(StartingFeature, 'text') if 'or' in m['multiclassing']['requirements']: MCrequirements = {} for requirement, value in m['multiclassing']['requirements']['or'][ 0].items(): MCrequirements[str(requirement)] = str(value) SFText = ET.SubElement(StartingFeature, 'text') SFText.text = "• {} {}".format(stats[requirement], MCrequirements[requirement]) else: for requirement, value in m['multiclassing']['requirements'].items( ): SFText.text = "• {} {}".format( stats[requirement], m['multiclassing']['requirements'][requirement]) SFText = ET.SubElement(StartingFeature, 'text') SFText.text = "" if 'proficienciesGained' in m['multiclassing'] or 'tools' in m[ 'multiclassing']: SFText = ET.SubElement(StartingFeature, 'text') SFText.text = "You gain the following proficiencies:" if 'proficienciesGained' in m['multiclassing']: SFText = ET.SubElement(StartingFeature, 'text') if "armor" in m['multiclassing']['proficienciesGained']: MCarmortext = ", ".join([ x if type(x) == str else x['full'] for x in m['multiclassing']['proficienciesGained']['armor'] ]) else: MCarmortext = "none" SFText.text = "• Armor: " + MCarmortext SFText = ET.SubElement(StartingFeature, 'text') if "weapons" in m['multiclassing']['proficienciesGained']: MCweapontext = ", ".join( m['multiclassing']['proficienciesGained']['weapons']) else: MCweapontext = "none" SFText.text = "• Weapons: " + MCweapontext SFText = ET.SubElement(StartingFeature, 'text') if "tools" in m['multiclassing']: MCtooltext = ", ".join(m['multiclassing']['tools']) else: MCtooltext = "none" SFText.text = "• Tools: " + MCtooltext SFText = ET.SubElement(StartingFeature, 'text') SFText.text = "" SFText = ET.SubElement(StartingFeature, 'text') SFText.text = "Source: " + utils.getFriendlySource( m['source']) + " p. " + str(m['page']) armor = ET.SubElement(Class, 'armor') armor.text = armortext weapons = ET.SubElement(Class, 'weapons') weapons.text = weapontext tools = ET.SubElement(Class, 'tools') if "tools" in m['startingProficiencies']: tools.text = ", ".join(m['startingProficiencies']['tools']) else: tools.text = "none" if 'startingEquipment' in m and "goldAlternative" in m['startingEquipment']: wealth = ET.SubElement(Class, 'wealth') wealth.text = str( utils.fixTags(m['startingEquipment']['goldAlternative'], m, args.nohtml)) if 'casterProgression' in m: FullCaster = [[3, 2, 0, 0, 0, 0, 0, 0, 0, 0], [3, 3, 0, 0, 0, 0, 0, 0, 0, 0], [3, 4, 2, 0, 0, 0, 0, 0, 0, 0], [4, 4, 3, 0, 0, 0, 0, 0, 0, 0], [4, 4, 3, 2, 0, 0, 0, 0, 0, 0], [4, 4, 3, 3, 0, 0, 0, 0, 0, 0], [4, 4, 3, 3, 1, 0, 0, 0, 0, 0], [4, 4, 3, 3, 2, 0, 0, 0, 0, 0], [4, 4, 3, 3, 3, 1, 0, 0, 0, 0], [5, 4, 3, 3, 3, 2, 0, 0, 0, 0], [5, 4, 3, 3, 3, 2, 1, 0, 0, 0], [5, 4, 3, 3, 3, 2, 1, 0, 0, 0], [5, 4, 3, 3, 3, 2, 1, 1, 0, 0], [5, 4, 3, 3, 3, 2, 1, 1, 0, 0], [5, 4, 3, 3, 3, 2, 1, 1, 1, 0], [5, 4, 3, 3, 3, 2, 1, 1, 1, 0], [5, 4, 3, 3, 3, 2, 1, 1, 1, 1], [5, 4, 3, 3, 3, 3, 1, 1, 1, 1], [5, 4, 3, 3, 3, 3, 2, 1, 1, 1], [5, 4, 3, 3, 3, 3, 2, 2, 1, 1]] HalfCaster = [[0, 0, 0, 0, 0, 0], [0, 2, 0, 0, 0, 0], [0, 3, 0, 0, 0, 0], [0, 3, 0, 0, 0, 0], [0, 4, 2, 0, 0, 0], [0, 4, 2, 0, 0, 0], [0, 4, 3, 0, 0, 0], [0, 4, 3, 0, 0, 0], [0, 4, 3, 2, 0, 0], [0, 4, 3, 2, 0, 0], [0, 4, 3, 3, 0, 0], [0, 4, 3, 3, 0, 0], [0, 4, 3, 3, 1, 0], [0, 4, 3, 3, 1, 0], [0, 4, 3, 3, 2, 0], [0, 4, 3, 3, 2, 0], [0, 4, 3, 3, 3, 1], [0, 4, 3, 3, 3, 1], [0, 4, 3, 3, 3, 2], [0, 4, 3, 3, 3, 2]] ThirdCaster = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 2, 0, 0, 0], [0, 3, 0, 0, 0], [0, 3, 0, 0, 0], [0, 3, 0, 0, 0], [0, 4, 2, 0, 0], [0, 4, 2, 0, 0], [0, 4, 2, 0, 0], [0, 4, 3, 0, 0], [0, 4, 3, 0, 0], [0, 4, 3, 0, 0], [0, 4, 3, 2, 0], [0, 4, 3, 2, 0], [0, 4, 3, 2, 0], [0, 4, 3, 3, 0], [0, 4, 3, 3, 0], [0, 4, 3, 3, 0], [0, 4, 3, 3, 1], [0, 4, 3, 3, 1]] #if 'Cantrips Known' in m['classTableGroups'][0]["colLabels"]: # print(m['classTableGroups'][0]["colLabels"][0]) # print(type(m['classTableGroups'][0]["colLabels"][0])) # print("Cantrips are known") if m['casterProgression'] == 'full': slots = FullCaster elif m['casterProgression'] == '1/2': slots = HalfCaster elif m['casterProgression'] == '1/3': slots = ThirdCaster else: slots = [[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []] for table in m['classTableGroups']: if "title" in table and table[ 'title'] == "Spell Slots per Spell Level": for lvl in range(len(table["rows"])): for c in table["rows"][lvl]: slots[lvl] = table["rows"][lvl] for table in m['classTableGroups']: cantripre = re.compile( r'{@filter ([Cc]antrips.*?)(\|.*?)?(\|.*?)?}') for i in range(len(table["colLabels"])): if cantripre.match(table["colLabels"][i]): cantrips = True for lvl in range(len(table["rows"])): slots[lvl].insert(0, table["rows"][lvl][i]) break for levelcounter in range(len(slots)): while slots[levelcounter] and slots[levelcounter][-1] == 0: slots[levelcounter].pop() level = 0 currentsubclass = 0 currentsubclassFeature = 0 for level in range(len(m['classFeatures'])): if slots: if slots[level]: attributes = {"level": str(level + 1)} autolevel = ET.SubElement(Class, 'autolevel', attributes) spellslots = ET.SubElement(autolevel, 'slots') currentspellevel = level spellslots.text = ", ".join( str(e) for e in slots[currentspellevel]) for feature in m['classFeatures'][level]: if 'name' in feature: if feature['name'] == "Ability Score Improvement": attributes = { "level": str(level + 1), "scoreImprovement": "YES" } else: attributes = {"level": str(level + 1)} if args.skipua and 'source' in feature and feature[ 'source'].startswith('UA'): if args.verbose: print("Skipping UA Feature:", m['name'], feature['name']) if "gainSubclassFeature" in feature and feature[ "gainSubclassFeature"] == True: currentsubclassFeature += 1 continue if args.onlyofficial: if 'source' in feature and feature[ 'source'] not in args.onlyofficial: if args.verbose: print("Skipping unoffical content: {} from {}".format( feature['name'], utils.getFriendlySource(feature['source']))) if "gainSubclassFeature" in feature and feature[ "gainSubclassFeature"] == True: currentsubclassFeature += 1 continue autolevel = ET.SubElement(Class, 'autolevel', attributes) attributes = {} ft = ET.SubElement(autolevel, 'feature', attributes) ftname = ET.SubElement(ft, 'name') ftname.text = utils.fixTags(feature["name"], m, args.nohtml) for subfeature in feature['entries']: flatten_json(subfeature, m, ft, args, level, attributes) if "gainSubclassFeature" in feature and feature[ "gainSubclassFeature"] == True: currentsubclass = 0 for subclass in m['subclasses']: if args.skipua and 'source' in subclass and subclass[ 'source'].startswith('UA'): if args.verbose: print("Skipping UA Subclass:", m['name'], subclass['name']) currentsubclass += 1 continue if args.onlyofficial: if 'source' in subclass and subclass[ 'source'] not in args.onlyofficial: if args.verbose: print("Skipping unoffical content: {} from {}". format( m['name'], utils.getFriendlySource( m['source']))) currentsubclass += 1 continue attributes = {"level": str(level + 1)} autolevel = ET.SubElement(Class, 'autolevel', attributes) attributes = {"optional": "YES"} subclassname = subclass['name'] ft = ET.SubElement(autolevel, 'feature', attributes) #print(subclass['source']) if currentsubclassFeature == 0: ftname = ET.SubElement(ft, 'name') ftname.text = "{}: {}".format( utils.fixTags(m['subclassTitle'], m, args.nohtml), subclassname) for subfeature in subclass['subclassFeatures'][ currentsubclassFeature]: if 'entries' in subfeature: for entry in subfeature['entries']: if type(entry) is str: fttext = ET.SubElement(ft, 'text') fttext.text = entry else: if currentsubclassFeature == 0: flatten_json(entry, m, ft, args, level, attributes) else: flatten_json(entry, m, ft, args, level, attributes, subclassname) else: print("this shouldn't happen") SFText = ET.SubElement(ft, 'text') SFText.text = "" SFText = ET.SubElement(ft, 'text') if 'page' in subclass: SFText.text = "Source: " + utils.getFriendlySource( subclass['source']) + " p. " + str( subclass['page']) else: SFText.text = "Source: " + utils.getFriendlySource( subclass['source']) currentsubclass += 1 currentsubclassFeature += 1
def parseBackground(m, compendium, args): if '_copy' in m: if args.verbose: print("COPY: " + m['name'] + " from " + m['_copy']['name'] + " in " + m['_copy']['source']) xtrsrc = "./data/backgrounds.json" try: with open(xtrsrc) as f: d = json.load(f) f.close() mcpy = m for mn in d['background']: backgroundfound = False if mn['name'] == mcpy['_copy']['name']: m = mn m['name'] = mcpy['name'] m['source'] = mcpy['source'] if "otherSources" in mcpy: m["otherSources"] = mcpy["otherSources"] m['page'] = mcpy['page'] if '_mod' in mcpy['_copy']: m = utils.modifyItem(m, mcpy['_copy']['_mod']) backgroundfound = True break if not backgroundfound: print("Could not find ", mcpy['_copy']['name']) except IOError as e: if args.verbose: print("Could not load additional source ({}): {}".format( e.errno, e.strerror)) return bg = ET.SubElement(compendium, 'background') name = ET.SubElement(bg, 'name') match = re.match(r'Variant (.*?) \((.*?)\)', m['name']) if match: name.text = "{} / {}".format(match.group(1), match.group(2)) else: name.text = m['name'] if 'entries' not in m: m['entries'] = [] if 'source' in m: name = m["name"] if args.addimgs and os.path.isdir( "./img") and not os.path.isfile("./items/" + name + ".png"): if not os.path.isdir("./items/"): os.mkdir("./items/") artworkpath = None if os.path.isfile("./img/items/" + m["name"] + ".jpg"): artworkpath = "./img/items/" + m["name"] + ".jpg" elif os.path.isfile("./img/items/" + m["name"] + ".png"): artworkpath = "./img/items/" + m["name"] + ".png" elif os.path.isfile("./img/items/" + m["source"] + "/" + m["name"] + ".png"): artworkpath = "./img/items/" + m["source"] + "/" + m[ "name"] + ".png" if artworkpath is not None: if args.verbose: print("Converting Image: " + artworkpath) with Image(filename=artworkpath) as img: img.format = 'png' img.save(filename="./items/" + name + ".png") imagetag = ET.SubElement(bg, 'image') imagetag.text = name + ".png" elif args.addimgs and os.path.isfile("./items/" + name + ".png"): imagetag = ET.SubElement(bg, 'image') imagetag.text = name + ".png" #source = ET.SubElement(bg, 'source') sourcetext = "{} p. {}".format( utils.getFriendlySource(m['source']), m['page'] ) if 'page' in m and m['page'] != 0 else utils.getFriendlySource( m['source']) if 'otherSources' in m and m["otherSources"] is not None: for s in m["otherSources"]: sourcetext += ", " sourcetext += "{} p. {}".format( utils.getFriendlySource(s["source"]), s["page"]) if 'page' in s and s[ "page"] != 0 else utils.getFriendlySource(s["source"]) if 'entries' in m: if args.nohtml: m['entries'].append("Source: {}".format(sourcetext)) else: m['entries'].append("<i>Source: {}</i>".format(sourcetext)) else: if args.nohtml: m['entries'] = ["Source: {}".format(sourcetext)] else: m['entries'] = ["<i>Source: {}</i>".format(sourcetext)] prof = ET.SubElement(bg, 'proficiency') if 'skillProficiencies' in m: profs = [] for skill in m['skillProficiencies']: for k, v in skill.items(): if k != 'choose': if v: profs.append(k.title()) prof.text = ", ".join(profs) trait = ET.SubElement(bg, 'trait') name = ET.SubElement(trait, 'name') name.text = "Description" description = ET.SubElement(trait, 'text') description.text = "" if 'entries' in m: for e in m['entries']: if type(e) == dict: if 'name' in e: trait = ET.SubElement(bg, 'trait') name = ET.SubElement(trait, 'name') name.text = e['name'] text = ET.SubElement(trait, 'text') text.text = "" else: text = description if "colLabels" in e: text.text += " | ".join( [utils.remove5eShit(x) for x in e['colLabels']]) text.text += "\n" for row in e['rows']: rowthing = [] for r in row: if isinstance(r, dict) and 'roll' in r: rowthing.append( "{}-{}".format(r['roll']['min'], r['roll'] ['max']) if 'min' in r['roll'] else str(r['roll']['exact'])) else: rowthing.append( utils.fixTags(str(r), m, args.nohtml)) text.text += " | ".join(rowthing) + "\n" elif "entries" in e: subentries = [] for sube in e["entries"]: if type(sube) == str: subentries.append( utils.fixTags(sube, m, args.nohtml)) elif type(sube) == dict and "text" in sube: subentries.append( utils.fixTags(sube["text"], m, args.nohtml)) elif type(sube) == dict and sube[ "type"] == "list" and "style" in sube and sube[ "style"] == "list-hang-notitle": for item in sube["items"]: if type(item ) == dict and 'type' in item and item[ 'type'] == 'item': if args.nohtml: subentries.append("• {}: {}".format( item["name"], utils.fixTags( item["entry"], m, args.nohtml))) else: subentries.append( "• <i>{}:</i> {}".format( item["name"], utils.fixTags( item["entry"], m, args.nohtml))) else: subentries.append("• {}".format( utils.fixTags(item, m, args.nohtml))) elif type(sube) == dict and sube["type"] == "list": for item in sube["items"]: if type(item) == dict and "entries" in item: ssubentries = [] for sse in item["entries"]: if type(sse) == str: ssubentries.append( utils.fixTags( sse, m, args.nohtml)) elif type( sse) == dict and "text" in sse: ssubentries.append( utils.fixTags( sse["text"], m, args.nohtml)) subentries.append( "\n".join(ssubentries)) elif type( item ) == dict and 'type' in item and item[ 'type'] == 'item': if args.nohtml: subentries.append("• {}: {}".format( item["name"], utils.fixTags( item["entry"], m, args.nohtml))) else: subentries.append( "• <i>{}:</i> {}".format( item["name"], utils.fixTags( item["entry"], m, args.nohtml))) else: subentries.append("• {}".format( utils.fixTags(item, m, args.nohtml))) else: if "colLabels" in sube: tabletext = "" tabletext += " | ".join([ utils.remove5eShit(x) for x in sube['colLabels'] ]) tabletext += "\n" for row in sube['rows']: rowthing = [] for r in row: if isinstance(r, dict) and 'roll' in r: rowthing.append("{}-{}".format( r['roll']['min'], r['roll'] ['max'] ) if 'min' in r['roll'] else str( r['roll']['exact'])) else: rowthing.append( utils.fixTags( str(r), m, args.nohtml)) tabletext += " | ".join(rowthing) + "\n" subentries.append(tabletext) text.text += "\n".join(subentries) + "\n" else: if type(e) == dict and e[ "type"] == "list" and "style" in e and e[ "style"] == "list-hang-notitle": for item in e["items"]: if 'entries' in item and 'entry' not in item: item['entry'] = ", ".join(item['entries']) if args.nohtml: text.text += "• {}: {}".format( item["name"], utils.fixTags(item["entry"], m, args.nohtml)) + "\n" else: text.text += "• <i>{}:</i> {}".format( item["name"], utils.fixTags(item["entry"], m, args.nohtml)) + "\n" elif type(e) == dict and e["type"] == "list": for item in e["items"]: if "entries" in item: subentries = [] for sube in item["entries"]: if type(sube) == str: subentries.append( utils.fixTags( sube, m, args.nohtml)) elif type(sube) == dict and "text" in sube: subentries.append( utils.fixTags( sube["text"], m, args.nohtml)) text.text += "\n".join(subentries) + "\n" else: text.text += "• {}".format( utils.fixTags(item, m, args.nohtml)) + "\n" else: description.text += utils.fixTags(e, m, args.nohtml) + "\n" description.text = description.text.rstrip()
def flatten(x, m, args, name=''): if args.skipua and 'source' in m and m['source'].startswith('UA'): if args.verbose: print("Skipping UA Content: ", m['name']) return if args.onlyofficial: if 'source' in m and m['source'] not in args.onlyofficial: if args.verbose: print("Skipping unoffical content: {} from {}".format( m['name'], utils.getFriendlySource(m['source']))) return skip = False options = False if type(x) is str: subtitle = '' if name == "name": text = ET.SubElement(m, 'name') #print(str(x)) #print(str(m)) text.text = utils.fixTags(x, m, args.nohtml) elif name == "text": text = ET.SubElement(m, 'text') text.text = " " + utils.fixTags(x, m, args.nohtml) elif name == "nametext": text = ET.SubElement(m, 'text') text.text = utils.fixTags(x, m, args.nohtml) elif name == "list": text = ET.SubElement(m, 'text') text.text = "• " + utils.fixTags(x, m, args.nohtml) else: text = ET.SubElement(m, 'text') text.text = utils.fixTags(x, m, args.nohtml) elif type(x) is dict: if "type" in x: if x['type'] == 'abilityDc' or x['type'] == 'abilityAttackMod': skip = True if not skip: if "name" in x: if 'subclassTitle' in d and d[ 'subclassTitle'] and 'optional' in attributes: if subclassname: SubClassFeatureName = x[ 'name'] + " (" + subclassname + ")" flatten(SubClassFeatureName, m, args, "name") else: blank = ET.SubElement(m, 'text') blank.text = "" SubClassFeatureName = x['name'] flatten(SubClassFeatureName, m, args, "nametext") else: blank = ET.SubElement(m, 'text') blank.text = "" if 'type' in x and (x['type'] == 'entries' or x['type'] == 'inset'): flatten(x['name'] + ":", m, args, "nametext") else: flatten(x['name'], m, args, "text") for a in x: if a == "type" and x[a] == "list" and "style" in x and x[ "style"] == "list-hang-notitle": blank = ET.SubElement(m, 'text') blank.text = "" for item in x["items"]: flatten(item['name'], m, args, "text") flatten(item['entry'], m, args, "list") blank = ET.SubElement(m, 'text') blank.text = "" elif "colLabels" in x: blank = ET.SubElement(m, 'text') blank.text = "" text = ET.SubElement(m, 'text') text.text = " | ".join( [utils.remove5eShit(y) for y in x['colLabels']]) for row in x['rows']: rowthing = [] for r in row: if isinstance(r, dict) and 'roll' in r: rowthing.append("{}-{}".format( r['roll']['min'], r['roll']['max'] ) if 'min' in r['roll'] else str( r['roll']['exact'])) else: rowthing.append( utils.fixTags(str(r), m, args.nohtml)) text = ET.SubElement(m, 'text') text.text = " | ".join(rowthing) elif "type" in a and x[a] == "list": flatten(x['items'], m, args, "list") elif a == "entries": flatten(x[a], m, args, "text") elif type(x) is list: i = 0 for a in x: flatten(a, m, args, name) i += 1
def parseSpell(m, compendium, args): spell = ET.SubElement(compendium, 'spell') name = ET.SubElement(spell, 'name') name.text = m['name'] level = ET.SubElement(spell, 'level') level.text = str(m['level']) school = ET.SubElement(spell, 'school') if m['school'] == 'E': school.text = 'EN' elif m['school'] == 'V': school.text = 'EV' else: school.text = m['school'] if m['school'] == 'P' and args.nohtml: spell.remove(school) if args.addimgs and os.path.isdir("./spells/"): if not os.path.isdir(os.path.join(args.tempdir, "spells")): os.mkdir(os.path.join(args.tempdir, "spells")) image = ET.SubElement(spell, 'image') if 'image' in m: artworkpath = m['image'] else: artworkpath = None slug = slugify(m["name"]) spellname = m["original_name"] if "original_name" in m else m["name"] if artworkpath and os.path.isfile("./img/" + artworkpath): artworkpath = "./img/" + artworkpath elif os.path.isfile("./img/spells/" + m["source"] + "/" + spellname + ".jpg"): artworkpath = "./img/spells/" + m[ "source"] + "/" + spellname + ".jpg" elif os.path.isfile("./img/spells/" + m["source"] + "/" + spellname + ".png"): artworkpath = "./img/spells/" + m[ "source"] + "/" + spellname + ".png" elif os.path.isfile("./img/" + m["source"] + "/" + spellname + ".png"): artworkpath = "./img/" + m["source"] + "/" + spellname + ".png" if artworkpath is not None: ext = os.path.splitext(artworkpath)[1] copyfile(artworkpath, os.path.join(args.tempdir, "spells", slug + ext)) image.text = slug + ext else: if m['school'] == 'E': artworkpath = "enchantment.png" elif m['school'] == 'V': artworkpath = "evocation.png" elif m['school'] == 'A': artworkpath = "abjuration.png" elif m['school'] == 'C': artworkpath = "conjuration.png" elif m['school'] == 'D': artworkpath = "divination.png" elif m['school'] == 'I': artworkpath = "illusion.png" elif m['school'] == 'N': artworkpath = "necromancy.png" elif m['school'] == 'T': artworkpath = "transmutation.png" elif m['school'] == 'P': artworkpath = "psionic.png" if not os.path.isfile( os.path.join(args.tempdir, "spells", artworkpath)): copyfile(os.path.join("spells", artworkpath), os.path.join(args.tempdir, "spells", artworkpath)) image.text = artworkpath ritual = ET.SubElement(spell, 'ritual') if "meta" in m and "ritual" in m["meta"] and m["meta"]["ritual"]: ritual.text = "YES" else: ritual.text = "NO" time = ET.SubElement(spell, 'time') times = [] for t in m["time"]: ttxt = "{} {}".format(t["number"], t["unit"]) if t["unit"] == "bonus": ttxt += " action" if t["number"] > 1: ttxt += "s" times.append(ttxt) time.text = ", ".join(times) srange = ET.SubElement(spell, 'range') if m["range"]["type"] == "point": if "amount" not in m["range"]["distance"]: srange.text = m["range"]["distance"]["type"].title() else: srange.text = "{} {}".format(m["range"]["distance"]["amount"], m["range"]["distance"]["type"]) if m["range"]["distance"]["amount"] == 1 and m["range"][ "distance"]["type"][-1:] == 's': srange.text = srange.text[:-1] elif m["range"]["type"] == "special": srange.text = "Special" else: dtype = m["range"]["distance"]["type"] if dtype == "feet": dtype = "foot" elif dtype[-1:] == 's': dtype = dtype[:-1] srange.text = "Self ({}-{} {})".format( m["range"]["distance"]["amount"], dtype, m["range"]["type"]) components = ET.SubElement(spell, 'components') if "components" in m: componentsList = [] for c in m["components"]: if type(m["components"][c]) is bool: componentsList.append(c.upper()) elif type(m["components"][c]) is dict: componentsList.append("{} ({})".format( c.upper(), m["components"][c]["text"])) else: componentsList.append("{} ({})".format(c.upper(), m["components"][c])) components.text = ", ".join(componentsList) duration = ET.SubElement(spell, 'duration') durations = [] for d in m["duration"]: if d["type"] == "timed": if "concentration" in d: dtxt = "Concentration, up to {} {}".format( d["duration"]["amount"], d["duration"]["type"]) else: dtxt = "{} {}".format(d["duration"]["amount"], d["duration"]["type"]) if d["duration"]["amount"] > 1: dtxt += 's' elif d["type"] == "permanent": dtxt = "Until " + " or ".join(d["ends"]) dtxt = dtxt.replace("dispel", "dispelled") dtxt = dtxt.replace("trigger", "triggered") elif d["type"] == "instant": dtxt = "Instantaneous" else: dtxt = d["type"] durations.append(dtxt) duration.text = ", ".join(durations) classes = ET.SubElement(spell, 'classes') classlist = [] if "classes" in m and "fromClassList" in m["classes"]: for c in m["classes"]["fromClassList"]: if args.srd and c['source'] != 'PHB': continue if args.skipua and c['source'].startswith('UA'): continue if args.onlyofficial and not args.onlysrc: if c['source'] not in args.allowedsrc: continue classlist.append( c["name"] + " (UA)" if c["source"].startswith("UA") else c["name"]) if "classes" in m and "fromClassListVariant" in m["classes"]: for c in m["classes"]["fromClassListVariant"]: if args.srd and c['source'] != 'PHB': continue if args.skipua and c['source'].startswith('UA'): continue if args.onlyofficial and not args.onlysrc: if c['source'] not in args.allowedsrc: continue if (c["name"] + " (UA)" if c["source"].startswith("UA") else c["name"]) not in classlist: classlist.append( c["name"] + " (UA)" if c["source"].startswith("UA") else c["name"]) if "classes" in m and "fromSubclass" in m["classes"]: for c in m["classes"]["fromSubclass"]: if args.srd: continue if args.skipua and (c["class"]["source"].startswith("UA") or c["subclass"]["source"].startswith("UA")): continue if args.onlyofficial and not args.onlysrc: if c["class"]["source"] not in args.allowedsrc or c[ "subclass"]["source"] not in args.allowedsrc: continue classlist.append("{} ({})".format( c["class"]["name"] + " (UA)" if c["class"]["source"].startswith("UA") else c["class"]["name"], c["subclass"]["name"])) classes.text = ", ".join(classlist) if "entriesHigherLevel" in m: if "entries" not in m: m["entries"] = [] for higher in m["entriesHigherLevel"]: if args.nohtml: m["entries"].append("{}:".format(higher["name"])) else: m["entries"].append("<b>{}:</b>".format(higher["name"])) m["entries"] += higher["entries"] if 'source' in m and not args.srd: sourcetext = "{} p. {}".format( utils.getFriendlySource(m['source'], args), m['page'] ) if 'page' in m and m['page'] != 0 else utils.getFriendlySource( m['source'], args) if 'otherSources' in m and m["otherSources"] is not None: for s in m["otherSources"]: if "source" not in s: continue sourcetext += ", " sourcetext += "{} p. {}".format( utils.getFriendlySource(s["source"], args), s["page"]) if 'page' in s and s[ "page"] != 0 else utils.getFriendlySource( s["source"], args) if 'entries' in m: if args.nohtml: m['entries'].append("Source: {}".format(sourcetext)) else: m['entries'].append("<i>Source: {}</i>".format(sourcetext)) else: if args.nohtml: m['entries'] = "Source: {}".format(sourcetext) else: m['entries'] = ["<i>Source: {}</i>".format(sourcetext)] if not args.nohtml: source = ET.SubElement(spell, 'source') source.text = sourcetext bodyText = ET.SubElement(spell, 'text') bodyText.text = "" if 'entries' in m: for e in m['entries']: if "colLabels" in e: if 'caption' in e: bodyText.text += "{}\n".format(e['caption']) bodyText.text += " | ".join( [utils.remove5eShit(x) for x in e['colLabels']]) bodyText.text += "\n" for row in e['rows']: rowthing = [] for r in row: if isinstance(r, dict) and 'roll' in r: rowthing.append( "{}-{}".format(r['roll']['min'], r['roll'] ['max']) if 'min' in r['roll'] else str(r['roll']['exact'])) else: rowthing.append( utils.fixTags(str(r), m, args.nohtml)) bodyText.text += " | ".join(rowthing) + "\n" elif "entries" in e: subentries = [] for sube in e["entries"]: if type(sube) == str: subentries.append(utils.fixTags(sube, m, args.nohtml)) elif type(sube) == dict and "text" in sube: subentries.append( utils.fixTags(sube["text"], m, args.nohtml)) if 'name' in e: if args.nohtml: bodyText.text += "{}: ".format(e['name']) else: bodyText.text += "<i>{}:</i> ".format(e['name']) bodyText.text += "\n".join(subentries) + "\n" else: if type(e) == dict and e[ "type"] == "list" and "style" in e and e[ "style"] == "list-hang-notitle": for item in e["items"]: bodyText.text += "• {}: {}".format( item["name"], utils.fixTags(item["entry"], m, args.nohtml)) + "\n" elif type(e) == dict and e["type"] == "list": for item in e["items"]: if "entries" in item: subentries = [] for sube in item["entries"]: if type(sube) == str: subentries.append( utils.fixTags(sube, m, args.nohtml)) elif type(sube) == dict and "text" in sube: subentries.append( utils.fixTags(sube["text"], m, args.nohtml)) bodyText.text += "\n".join( subentries) + "\n" else: bodyText.text += "• {}".format( utils.fixTags(item, m, args.nohtml)) + "\n" else: bodyText.text += utils.fixTags(e, m, args.nohtml) + "\n" bodyText.text = bodyText.text.rstrip() for match in re.finditer( r'(([0-9])+[dD]([0-9])+([ ]?[-+][ ]?[0-9]+)?)( +\+ +your spellcasting ability modifier| for each slot level above ([0-9]))?', bodyText.text): if match.group(5) and match.group(6): if "entriesHigherLevel" in m: higherslot = "" for higher in m["entriesHigherLevel"]: higherslot += " ".join(higher["entries"]) for scale in re.finditer( r'{@scaled(amage|ice) ([0-9]+)[dD]([0-9]+)(;([0-9]+)[dD]([0-9]+))?( +[-+] +[0-9]+)?\|(([0-9])-([0-9])|([0-9],?)*)\|([0-9]+)[dD]([0-9]+)}', higherslot): basecount = int(scale.group(2)) baseface = int(scale.group(3)) addcount = int(scale.group(12)) addface = int(scale.group(13)) base2count = None base2face = None if scale.group(4): base2count = int(scale.group(5)) base2face = int(scale.group(6)) if scale.group(9) and scale.group(10): scales = int(scale.group(10)) - int(scale.group(9)) else: scales = len(scale.group(8).split(',')) for i in range(scales): rolltext = "{}d{}{}".format( basecount + ((i + 1) * addcount) if addface == baseface else basecount, baseface, scale.group(7) if scale.group(7) else "") if not spell.find( "./[roll='{}']".format(rolltext)): roll = ET.SubElement(spell, 'roll') roll.text = rolltext.replace(' ', '') if base2count and base2face: rolltext = "{}d{}".format( base2count + ((i + 1) * addcount) if addface == base2face else base2count, base2face) if not spell.find( "./[roll='{}']".format(rolltext)): roll = ET.SubElement(spell, 'roll') roll.text = rolltext.replace(' ', '') else: mult = 1 for i in range(int(match.group(11)), 9): rolltext = "{}d{}".format( int(match.group(2)) * mult, match.group(3)) if not spell.find("./[roll='{}']".format(rolltext)): roll = ET.SubElement(spell, 'roll') roll.text = rolltext.replace(' ', '') mult += 1 elif match.group(5): if not spell.find("./[roll='{}+SPELL']".format( match.group(1))): roll = ET.SubElement(spell, 'roll') roll.text = "{}+SPELL".format(match.group(1)).replace( ' ', '') elif match.group(1): if not spell.find("./[roll='{}']".format(match.group(1))): roll = ET.SubElement(spell, 'roll') roll.text = "{}".format(match.group(1)).replace(' ', '')
def parseRace(m, compendium, args): if '_copy' in m: if args.verbose: print("COPY: " + m['name'] + " from " + m['_copy']['name'] + " in " + m['_copy']['source']) xtrsrc = "./data/races.json" try: with open(xtrsrc) as f: d = json.load(f) f.close() mcpy = m for mn in d['race']: racefound = False if mn['name'] == mcpy['_copy']['name'] and mn['source'] == mcpy['_copy']['source']: m = copy.deepcopy(mn) m['name'] = mcpy['name'] m['source'] = mcpy['source'] if "otherSources" in mcpy: m["otherSources"] = mcpy["otherSources"] if 'page' in mcpy: m['page'] = mcpy['page'] elif 'page' in m: del m['page'] if '_mod' in mcpy['_copy']: m = utils.modifyItem(m,mcpy['_copy']['_mod']) racefound = True break if not racefound: print("Could not find ",mcpy['_copy']['name']) except IOError as e: if args.verbose: print ("Could not load additional source ({}): {}".format(e.errno, e.strerror)) return race = ET.SubElement(compendium, 'race') name = ET.SubElement(race, 'name') name.text = m['name'] if 'entries' not in m: m['entries'] = [] if 'source' in m and not args.srd: slug = slugify(m["name"]) if args.addimgs and os.path.isdir("./img") and not os.path.isfile("./items/" + slug + ".png"): if not os.path.isdir("./items/"): os.mkdir("./items/") artworkpath = None if os.path.isfile("./img/items/" + m["name"] + ".jpg"): artworkpath = "./img/items/" + m["name"] + ".jpg" elif os.path.isfile("./img/items/" + m["name"] + ".png"): artworkpath = "./img/items/" + m["name"] + ".png" elif os.path.isfile("./img/items/" + m["source"] + "/" + m["name"] + ".png"): artworkpath = "./img/items/" + m["source"] + "/" + m["name"] + ".png" if artworkpath is not None: if args.verbose: print("Converting Image: " + artworkpath) with Image(filename=artworkpath) as img: img.format='png' img.save(filename="./items/" + slug + ".png") imagetag = ET.SubElement(race, 'image') imagetag.text = slug + ".png" elif args.addimgs and os.path.isfile("./items/" + slug + ".png"): imagetag = ET.SubElement(race, 'image') imagetag.text = slug + ".png" sourcetext = "{} p. {}".format( utils.getFriendlySource(m['source'],args), m['page']) if 'page' in m and m['page'] != 0 else utils.getFriendlySource(m['source'],args) if 'otherSources' in m and m["otherSources"] is not None: for s in m["otherSources"]: sourcetext += ", " sourcetext += "{} p. {}".format( utils.getFriendlySource(s["source"],args), s["page"]) if 'page' in s and s["page"] != 0 else utils.getFriendlySource(s["source"],args) if 'entries' in m: if args.nohtml: m['entries'].append("Source: {}".format(sourcetext)) else: m['entries'].append("<i>Source: {}</i>".format(sourcetext)) else: if args.nohtml: m['entries'] = ["Source: {}".format(sourcetext)] else: m['entries'] = ["<i>Source: {}</i>".format(sourcetext)] if not args.nohtml: source = ET.SubElement(race, 'source') source.text = sourcetext size = ET.SubElement(race, 'size') if m['size'] == 'V': size.text = 'M' else: size.text = m['size'] speed = ET.SubElement(race, 'speed') if type(m['speed']) == dict: speed.text = str(m['speed']['walk']) elif m['speed'] != "Varies": speed.text = str(m['speed']) else: speed.text = "30" ability = ET.SubElement(race, 'ability') if 'ability' in m: abils = [] for ab in m['ability']: for k,v in ab.items(): if k != 'choose': abils.append("{} {}".format(k,v).capitalize()) ability.text = ", ".join(abils) prof = ET.SubElement(race, 'proficiency') if 'skillProficiencies' in m: profs = [] for skill in m['skillProficiencies']: for k,v in skill.items(): if k != 'choose' and k != 'tool': if v: profs.append(k.title()) prof.text = ", ".join(profs) spell = ET.SubElement(race, 'spellAbility') trait = ET.SubElement(race, 'trait') name = ET.SubElement(trait, 'name') name.text = "Description" description = ET.SubElement(trait, 'text') description.text = "" if 'entries' in m: for e in m['entries']: if type(e) == dict: if 'name' in e: trait = ET.SubElement(race, 'trait') name = ET.SubElement(trait, 'name') name.text = e['name'] text = ET.SubElement(trait, 'text') text.text = "" else: text = description if "colLabels" in e: if 'caption' in e: text.text += "{}\n".format(e['caption']) text.text += " | ".join([utils.remove5eShit(x) for x in e['colLabels']]) text.text += "\n" for row in e['rows']: rowthing = [] for r in row: if isinstance(r, dict) and 'roll' in r: rowthing.append( "{}-{}".format( r['roll']['min'], r['roll']['max']) if 'min' in r['roll'] else str( r['roll']['exact'])) else: rowthing.append(utils.fixTags(str(r),m,args.nohtml)) text.text += " | ".join(rowthing) + "\n" elif "entries" in e: subentries = [] for sube in e["entries"]: if type(sube) == str: subentries.append(utils.fixTags(sube,m,args.nohtml)) elif type(sube) == dict and "text" in sube: subentries.append(utils.fixTags(sube["text"],m,args.nohtml)) elif type(sube) == dict and sube["type"] == "list" and "style" in sube and sube["style"] == "list-hang-notitle": for item in sube["items"]: if type(item) == dict and 'type' in item and (item['type'] == 'item' or item['type'] == 'itemSpell'): if args.nohtml: subentries.append("• {} {}".format(item["name"] if item["name"].endswith(':') else item["name"] + ':',utils.fixTags(item["entry"],m,args.nohtml))) else: subentries.append("• <i>{}</i> {}".format(item["name"] if item["name"].endswith(':') else item["name"] + ':',utils.fixTags(item["entry"],m,args.nohtml))) else: subentries.append("• {}".format(utils.fixTags(item,m,args.nohtml))) elif type(sube) == dict and sube["type"] == "list": for item in sube["items"]: if type(item) == dict and "entries" in item: ssubentries = [] for sse in item["entries"]: if type(sse) == str: ssubentries.append(utils.fixTags(sse,m,args.nohtml)) elif type(sse) == dict and "text" in sse: ssubentries.append(utils.fixTags(sse["text"],m,args.nohtml)) subentries.append("\n".join(ssubentries)) elif type(item) == dict and 'type' in item and item['type'] == 'item': if args.nohtml: subentries.append("• {}: {}".format(item["name"],utils.fixTags(item["entry"],m,args.nohtml))) else: subentries.append("• <i>{}:</i> {}".format(item["name"],utils.fixTags(item["entry"],m,args.nohtml))) else: subentries.append("• {}".format(utils.fixTags(item,m,args.nohtml))) else: if "colLabels" in sube: tabletext = "" if 'caption' in sube: text.text += "{}\n".format(sube['caption']) tabletext += " | ".join([utils.remove5eShit(x) for x in sube['colLabels']]) tabletext += "\n" for row in sube['rows']: rowthing = [] for r in row: if isinstance(r, dict) and 'roll' in r: rowthing.append( "{}-{}".format( r['roll']['min'], r['roll']['max']) if 'min' in r['roll'] else str( r['roll']['exact'])) else: rowthing.append(utils.fixTags(str(r),m,args.nohtml)) tabletext += " | ".join(rowthing) + "\n" subentries.append(tabletext) text.text += "\n".join(subentries) + "\n" else: if type(e) == dict and e["type"] == "list" and "style" in e and e["style"] == "list-hang-notitle": for item in e["items"]: if 'entries' in item and 'entry' not in item: item['entry'] = ", ".join(item['entries']) if args.nohtml: text.text += "• {}: {}".format(item["name"],utils.fixTags(item["entry"],m,args.nohtml)) + "\n" else: text.text += "• <i>{}:</i> {}".format(item["name"],utils.fixTags(item["entry"],m,args.nohtml)) + "\n" elif type(e) == dict and e["type"] == "list": for item in e["items"]: if "entries" in item: subentries = [] for sube in item["entries"]: if type(sube) == str: subentries.append(utils.fixTags(sube,m,args.nohtml)) elif type(sube) == dict and "text" in sube: subentries.append(utils.fixTags(sube["text"],m,args.nohtml)) text.text += "\n".join(subentries) + "\n" else: text.text += "• {}".format(utils.fixTags(item,m,args.nohtml)) + "\n" match = re.search(r'(\w+) is your spellcasting ability', text.text) if match: spell.text = match.group(1) else: description.text += utils.fixTags(e,m,args.nohtml) + "\n" description.text = description.text.rstrip()
def parseMonster(m, compendium, args): if '_copy' in m: if args.verbose: print("COPY: " + m['name'] + " from " + m['_copy']['name'] + " in " + m['_copy']['source']) xtrsrc = "./data/bestiary/bestiary-" + m['_copy']['source'].lower( ) + ".json" try: with open(xtrsrc, encoding='utf-8') as f: d = json.load(f) f.close() mcpy = copy.deepcopy(m) for mn in d['monster']: if mn['name'].lower() == mcpy['_copy']['name'].lower(): if '_copy' in mn: if args.verbose: print("ANOTHER COPY: " + mn['name'] + " from " + mn['_copy']['name'] + " in " + mn['_copy']['source']) xtrsrc2 = "./data/bestiary/bestiary-" + mn['_copy'][ 'source'].lower() + ".json" with open(xtrsrc2, encoding='utf-8') as f: d2 = json.load(f) f.close() for mn2 in d2['monster']: if mn2['name'] == mn['_copy']['name']: mn = copy.deepcopy(mn2) break m = copy.deepcopy(mn) m['name'] = mcpy['name'] if 'isNpc' in mcpy: m['isNpc'] = mcpy['isNpc'] m['source'] = mcpy['source'] if "otherSources" in mcpy: m["otherSources"] = mcpy["otherSources"] elif "otherSources" in m: del m["otherSources"] if 'size' in mcpy: m['size'] = mcpy['size'] if 'hp' in mcpy: m['hp'] = mcpy['hp'] if 'original_name' in mcpy: m['original_name'] = mcpy['original_name'] if 'page' in mcpy: m['page'] = mcpy['page'] elif 'page' in m: del m['page'] if 'image' in mcpy: m['image'] = mcpy['image'] if '_mod' in mcpy['_copy']: m = utils.modifyMonster(m, mcpy['_copy']['_mod']) break if '_trait' in mcpy['_copy']: if args.verbose: print("Adding extra traits for: " + mcpy['_copy']['_trait']['name']) traits = "./data/bestiary/traits.json" with open(traits, encoding='utf-8') as f: d = json.load(f) f.close() for trait in d['trait']: if trait['name'] == mcpy['_copy']['_trait']['name']: if '_mod' in trait['apply']: m = utils.modifyMonster(m, trait['apply']['_mod']) if '_root' in trait['apply']: for key in trait['apply']['_root']: if key == "speed" and type( trait['apply']['_root'][key]) == int: for k2 in m['speed']: m['speed'][k2] = trait['apply'][ '_root'][key] else: m[key] = trait['apply']['_root'][key] except IOError as e: if args.verbose: print("Could not load additional source ({}): {}".format( e.errno, e.strerror)) return # for eachmonsters in compendium.findall('monster'): # if eachmonsters.find('name').text == m['name']: # m['name'] = "{} (DUPLICATE IN {})".format(m['name'],m['source']) monster = ET.SubElement(compendium, 'monster') name = ET.SubElement(monster, 'name') name.text = m['name'] size = ET.SubElement(monster, 'size') size.text = m['size'] typ = ET.SubElement(monster, 'type') if isinstance(m['type'], dict): if 'swarmSize' in m['type']: typ.text = "swarm of {} {}s".format(utils.convertSize(m['size']), m['type']['type']) elif 'tags' in m['type']: subtypes = [] for tag in m['type']['tags']: if not isinstance(tag, dict): subtypes.append(tag) else: subtypes.append(tag['prefix'] + tag['tag']) typ.text = "{} ({})".format(m['type']['type'], ", ".join(subtypes)) else: typ.text = m['type']['type'] else: typ.text = m['type'] alignment = ET.SubElement(monster, 'alignment') if 'alignment' not in m: m['alignment'] = ['A'] alignment.text = utils.convertAlignList(m['alignment']) ac = ET.SubElement(monster, 'ac') acstr = [] for acs in m['ac']: if isinstance(acs, dict): if len(acstr) == 0: if 'ac' in acs: acstr.append(str(acs['ac'])) if 'from' in acs and 'condition' in acs: acstr.append( utils.fixTags( ", ".join(acs['from']) + " " + acs['condition'], m, True)) elif 'from' in acs: acstr.append(utils.fixTags(", ".join(acs['from']), m, True)) elif 'condition' in acs: acstr.append(utils.fixTags(acs['condition'], m, True)) if 'special' in acs: acstr.append(utils.fixTags(acs['special'], m, True)) continue acstr.append( utils.fixTags( "{}".format("{} {}".format( acs['ac'], "(" + ", ".join(acs['from']) + ") " + acs['condition'] if 'from' in acs and 'condition' in acs else "(" + ", ".join(acs['from']) + ")" if 'from' in acs else acs['condition'] ) if 'from' in acs or 'condition' in acs else acs['ac']), m, True)) else: acstr.append(str(acs)) if len(acstr) > 1: ac.text = "{} ({})".format(acstr[0], ", ".join(acstr[1:])) elif acstr[0]: ac.text = acstr[0] else: ac.text = "0" hp = ET.SubElement(monster, 'hp') if "special" in m['hp']: if args.nohtml and re.match(r'equal the .*?\'s Constitution modifier', m['hp']['special']): hp.text = str(utils.getAbilityMod(m['con'])) if 'trait' in m: m['trait'].insert(0, { "name": "Hit Points", "entries": [m['hp']['special']] }) else: m['trait'] = [{ "name": "Hit Points", "entries": [m['hp']['special']] }] elif args.nohtml: hpmatch = re.match( r'[0-9]+ ?(\([0-9]+[Dd][0-9]+( ?\+ ?[0-9]+)?\))?', m['hp']['special']) if hpmatch: hp.text = str(hpmatch.group(0)).rstrip() else: hp.text = "0" if 'trait' in m: m['trait'].insert(0, { "name": "Hit Points", "entries": [m['hp']['special']] }) else: m['trait'] = [{ "name": "Hit Points", "entries": [m['hp']['special']] }] else: hp.text = m['hp']['special'] else: hp.text = "{} ({})".format(m['hp']['average'], m['hp']['formula'].replace(' ', '')) speed = ET.SubElement(monster, 'speed') if type(m['speed']) == str: speed.text = m['speed'] elif 'choose' in m['speed']: lis = [] for key, value in m['speed'].items(): if key == "walk": lis.append("walk " + str(value) + " ft.") elif key == "choose": value['from'].insert(-1, 'or') lis.append("{} {} ft. {}".format(" ".join(value['from']), value['amount'], value['note'])) else: lis.append("{} {} ft.".format(key, value)) speed.text = ", ".join(lis) else: speed.text = ", ".join([ "{} {} ft.".format( key, value['number'] if isinstance(value, dict) else value) for key, value in m['speed'].items() if not isinstance(value, bool) ]) statstr = ET.SubElement(monster, 'str') statstr.text = str(m['str'] if 'str' in m else '0') statdex = ET.SubElement(monster, 'dex') statdex.text = str(m['dex'] if 'dex' in m else '0') statcon = ET.SubElement(monster, 'con') statcon.text = str(m['con'] if 'con' in m else '0') statint = ET.SubElement(monster, 'int') statint.text = str(m['int'] if 'int' in m else '0') statwis = ET.SubElement(monster, 'wis') statwis.text = str(m['wis'] if 'wis' in m else '0') statcha = ET.SubElement(monster, 'cha') statcha.text = str(m['cha'] if 'cha' in m else '0') if 'isNpc' in m and m['isNpc'] and not args.nohtml: npcroll = ET.SubElement(monster, 'role') npcroll.text = "ally" save = ET.SubElement(monster, 'save') if 'save' in m: save.text = ", ".join([ "{} {}".format(str.capitalize(key), value) for key, value in m['save'].items() ]) skill = ET.SubElement(monster, 'skill') if 'skill' in m: skills = [] for key, value in m['skill'].items(): if type(value) == str: skills.append("{} {}".format(str.capitalize(key), value)) else: if key == "other": for sk in value: if "oneOf" in sk: if args.nohtml: if 'trait' not in m: m['trait'] = [] m['trait'].insert( 0, { "name": "Skills", "entries": [ "plus one of the following: " + ", ".join([ "{} {}".format( str.capitalize(ook), oov) for ook, oov in sk["oneOf"].items() ]) ] }) else: skills.append( "plus one of the following: " + ", ".join([ "{} {}".format(str.capitalize(ook), oov) for ook, oov in sk["oneOf"].items() ])) skill.text = ", ".join(skills) if 'passive' in m: passive = ET.SubElement(monster, 'passive') passive.text = str(m['passive']) languages = ET.SubElement(monster, 'languages') if 'languages' in m: languages.text = ", ".join([x for x in m['languages']]) cr = ET.SubElement(monster, 'cr') if 'cr' in m: if isinstance(m['cr'], dict): cr.text = str(m['cr']['cr']) else: if not m['cr'] == "Unknown": cr.text = str(m['cr']) resist = ET.SubElement(monster, 'resist') if 'resist' in m: resistlist = utils.parseRIV(m, 'resist') resist.text = ", ".join(resistlist) immune = ET.SubElement(monster, 'immune') if 'immune' in m: immunelist = utils.parseRIV(m, 'immune') immune.text = ", ".join(immunelist) vulnerable = ET.SubElement(monster, 'vulnerable') if 'vulnerable' in m: vulnerablelist = utils.parseRIV(m, 'vulnerable') vulnerable.text = ", ".join(vulnerablelist) conditionImmune = ET.SubElement(monster, 'conditionImmune') if 'conditionImmune' in m: conditionImmunelist = utils.parseRIV(m, 'conditionImmune') conditionImmune.text = ", ".join(conditionImmunelist) senses = ET.SubElement(monster, 'senses') if 'senses' in m: senses.text = ", ".join([x for x in m['senses']]) if 'source' in m and not args.srd: slug = slugify(m["name"]) if args.addimgs and os.path.isdir("img") and not os.path.isfile( os.path.join(args.tempdir, "monsters", slug + ".png") ) and not os.path.isfile( os.path.join(args.tempdir, "monsters", slug + ".jpg") ) and not os.path.isfile( os.path.join(args.tempdir, "monsters", "token_" + slug + ".png")) and not os.path.isfile( os.path.join(args.tempdir, "monsters", "token_" + slug + ".jpg")): if not os.path.isdir(os.path.join(args.tempdir, "monsters")): os.mkdir(os.path.join(args.tempdir, "monsters")) #if not os.path.isdir(os.path.join(args.tempdir,"tokens")): # os.mkdir(os.path.join(args.tempdir,"tokens")) if 'image' in m: artworkpath = m['image'] else: artworkpath = None monstername = m["original_name"] if "original_name" in m else m[ "name"] if artworkpath and os.path.isfile("./img/" + artworkpath): artworkpath = "./img/" + artworkpath elif os.path.isfile("./img/bestiary/" + m["source"] + "/" + monstername + ".jpg"): artworkpath = "./img/bestiary/" + m[ "source"] + "/" + monstername + ".jpg" elif os.path.isfile("./img/bestiary/" + m["source"] + "/" + monstername + ".png"): artworkpath = "./img/bestiary/" + m[ "source"] + "/" + monstername + ".png" elif os.path.isfile("./img/vehicles/" + m["source"] + "/" + monstername + ".jpg"): artworkpath = "./img/vehicles/" + m[ "source"] + "/" + monstername + ".jpg" elif os.path.isfile("./img/vehicles/" + m["source"] + "/" + monstername + ".png"): artworkpath = "./img/vehicles/" + m[ "source"] + "/" + monstername + ".png" if artworkpath is not None: ext = os.path.splitext(artworkpath)[1] copyfile(artworkpath, os.path.join(args.tempdir, "monsters", slug + ext)) imagetag = ET.SubElement(monster, 'image') imagetag.text = slug + ext if os.path.isfile("./img/" + m["source"] + "/" + monstername + ".png") or os.path.isfile("./img/" + m["source"] + "/" + monstername + ".jpg"): if os.path.isfile("./img/" + m["source"] + "/" + monstername + ".png"): artworkpath = "./img/" + m[ "source"] + "/" + monstername + ".png" else: artworkpath = "./img/" + m[ "source"] + "/" + monstername + ".jpg" ext = os.path.splitext(artworkpath)[1] copyfile( artworkpath, os.path.join(args.tempdir, "monsters", "token_" + slug + ext)) imagetag = ET.SubElement(monster, 'token') imagetag.text = slug + ext elif os.path.isfile("./img/vehicles/tokens/" + m["source"] + "/" + monstername + ".png") or os.path.isfile( "./img/vehicles/tokens/" + m["source"] + "/" + monstername + ".jpg"): if os.path.isfile("./img/vehicles/tokens/" + m["source"] + "/" + monstername + ".png"): artworkpath = "./img/vehicles/tokens/" + m[ "source"] + "/" + monstername + ".png" else: artworkpath = "./img/vehicles/tokens/" + m[ "source"] + "/" + monstername + ".jpg" ext = os.path.splitext(artworkpath)[1] copyfile( artworkpath, os.path.join(args.tempdir, "monsters", "token_" + slug + ext)) imagetag = ET.SubElement(monster, 'token') imagetag.text = "token_" + slug + ext elif args.addimgs and os.path.isfile( os.path.join(args.tempdir, "monsters", slug + ".png")): imagetag = ET.SubElement(monster, 'image') imagetag.text = slug + ".png" elif args.addimgs and os.path.isfile( os.path.join(args.tempdir, "monsters", slug + ".jpg")): imagetag = ET.SubElement(monster, 'image') imagetag.text = slug + ".jpg" elif args.addimgs and os.path.isfile( os.path.join(args.tempdir, "monsters", "token_" + slug + ".png")): imagetag = ET.SubElement(monster, 'token') imagetag.text = "token_" + slug + ".png" elif args.addimgs and os.path.isfile( os.path.join(args.tempdir, "monsters", "token_" + slug + ".jpg")): imagetag = ET.SubElement(monster, 'token') imagetag.text = "token_" + slug + ".jpg" sourcetext = "{} p. {}".format( utils.getFriendlySource(m['source'], args), m['page'] ) if 'page' in m and m['page'] != 0 else utils.getFriendlySource( m['source'], args) if 'otherSources' in m and m["otherSources"] is not None: for s in m["otherSources"]: if "source" not in s: continue sourcetext += ", " sourcetext += "{} p. {}".format( utils.getFriendlySource(s["source"], args), s["page"]) if 'page' in s and s[ "page"] != 0 else utils.getFriendlySource( s["source"], args) #trait = ET.SubElement(monster, 'trait') #name = ET.SubElement(trait, 'name') #name.text = "Source" #text = ET.SubElement(trait, 'text') #text.text = sourcetext if not args.nohtml: srctag = ET.SubElement(monster, 'source') srctag.text = sourcetext else: sourcetext = None if 'trait' in m: for t in m['trait']: trait = ET.SubElement(monster, 'trait') name = ET.SubElement(trait, 'name') name.text = utils.remove5eShit(t['name']) if "entries" not in t: t["entries"] = [] for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(trait, 'text') text.text = e if 'action' in m and m['action'] is not None: for t in m['action']: action = ET.SubElement(monster, 'action') if 'name' in t: name = ET.SubElement(action, 'name') name.text = utils.remove5eShit(t['name']) for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(action, 'text') text.text = e for match in re.finditer( r'(((\+|\-)?[0-9]*) to hit.*?|DC [0-9]+ .*? saving throw.*?)\(([0-9Dd\+\- ]+)\) .*? damage', e): if match.group(4): attack = ET.SubElement(action, 'attack') attack.text = "{}|{}|{}".format( utils.remove5eShit(t['name']) if 'name' in t else "", match.group(2).replace(' ', '') if match.group(2) else "", match.group(4).replace(' ', '')) if 'reaction' in m and m['reaction'] is not None: for t in m['reaction']: action = ET.SubElement(monster, 'reaction') name = ET.SubElement(action, 'name') name.text = utils.remove5eShit(t['name']) for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(action, 'text') text.text = e if 'variant' in m and m['variant'] is not None: if type(m['variant']) != list: m['variant'] = [m['variant']] for t in m['variant']: action = ET.SubElement(monster, 'action') name = ET.SubElement(action, 'name') name.text = "Variant: " + utils.remove5eShit(t['name']) for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(action, 'text') text.text = e if 'legendary' in m: legendary = ET.SubElement(monster, 'legendary') if "legendaryHeader" in m: for h in m['legendaryHeader']: text = ET.SubElement(legendary, 'text') text.text = utils.remove5eShit(h) else: text = ET.SubElement(legendary, 'text') if "isNamedCreature" in m and m['isNamedCreature']: text.text = "{0} can take {1:d} legendary action{2}, choosing from the options below. Only one legendary action can be used at a time and only at the end of another creature's turn. {0} regains spent legendary action{2} at the start of its turn.".format( m['name'].split(' ', 1)[0], len(m['legendary']), "s" if len(m['legendary']) > 1 else "") else: text.text = "The {0} can take {1:d} legendary action{2}, choosing from the options below. Only one legendary action can be used at a time and only at the end of another creature's turn. The {0} regains spent legendary action{2} at the start of its turn.".format( m['type'] if type(m['type']) == str else "{} ({})".format( m['type']['type'], ", ".join(m['type']['tags'])) if 'tags' in m['type'] else m['type']['type'], len(m['legendary']), "s" if len(m['legendary']) > 1 else "") for t in m['legendary']: legendary = ET.SubElement(monster, 'legendary') name = ET.SubElement(legendary, 'name') if 'name' not in t: t['name'] = "" name.text = utils.remove5eShit(t['name']) for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(legendary, 'text') text.text = e if 'mythic' in m: mythic = ET.SubElement(monster, 'legendary') if "mythicHeader" in m: for h in m['mythicHeader']: name = ET.SubElement(mythic, 'name') name.text = "Mythic Actions" mythic = ET.SubElement(monster, 'legendary') text = ET.SubElement(mythic, 'text') text.text = utils.remove5eShit(h) for t in m['mythic']: mythic = ET.SubElement(monster, 'legendary') name = ET.SubElement(mythic, 'name') if 'name' not in t: t['name'] = "" name.text = utils.remove5eShit(t['name']) for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(mythic, "text") text.text = e if 'legendaryGroup' in m: with open("./data/bestiary/legendarygroups.json", encoding='utf-8') as f: meta = json.load(f) f.close() for l in meta['legendaryGroup']: if l['name'] != m['legendaryGroup']['name']: continue if 'lairActions' in l: legendary = ET.SubElement(monster, 'legendary') name = ET.SubElement(legendary, 'name') name.text = "Lair Actions" legendary = ET.SubElement(monster, 'legendary') for t in l['lairActions']: if type(t) == str: text = ET.SubElement(legendary, 'text') text.text = utils.fixTags(t, m, args.nohtml) continue if 'name' in t: name = ET.SubElement(legendary, 'name') name.text = "Lair Action: " + utils.remove5eShit( t['name']) if t['type'] == 'list': for i in t['items']: text = ET.SubElement(legendary, 'text') text.text = "• " + utils.fixTags(i, m, args.nohtml) continue for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(legendary, 'text') text.text = e if 'regionalEffects' in l: legendary = ET.SubElement(monster, 'legendary') name = ET.SubElement(legendary, 'name') name.text = "Regional Effects" legendary = ET.SubElement(monster, 'legendary') for t in l['regionalEffects']: if type(t) == str: text = ET.SubElement(legendary, 'text') text.text = utils.fixTags(t, m, args.nohtml) continue if 'name' in t: name = ET.SubElement(legendary, 'name') name.text = "Regional Effect: " + utils.remove5eShit( t['name']) if t['type'] == 'list': for i in t['items']: text = ET.SubElement(legendary, 'text') text.text = "• " + utils.fixTags(i, m, args.nohtml) continue #legendary = ET.SubElement(monster, 'legendary') for e in utils.getEntryString(t["entries"], m, args).split("\n"): text = ET.SubElement(legendary, 'text') text.text = e if 'mythicEncounter' in l: mythic = ET.SubElement(monster, 'legendary') name = ET.SubElement(mythic, 'name') name.text = "{} as a Mythic Encounter".format(m["name"]) for e in utils.getEntryString(l["mythicEncounter"], m, args).split("\n"): text = ET.SubElement(mythic, 'text') text.text = e if 'spellcasting' in m: spells = [] for s in m['spellcasting']: trait = ET.SubElement(monster, 'trait') name = ET.SubElement(trait, 'name') name.text = utils.remove5eShit(s['name']) for e in s['headerEntries']: text = ET.SubElement(trait, 'text') text.text = utils.fixTags(e, m, args.nohtml) if "will" in s: text = ET.SubElement(trait, 'text') willspells = s['will'] text.text = "At will: " + \ ", ".join([utils.remove5eShit(e) for e in willspells]) for spl in willspells: search = re.search(r'{@spell+ (.*?)(\|.*)?}', spl, re.IGNORECASE) if search is not None: spells.append(search.group(1)) if "daily" in s: for timeframe, lis in s['daily'].items(): text = ET.SubElement(trait, 'text') dailyspells = lis t = "{}/day{}: ".format( timeframe[0], " each" if len(timeframe) > 1 else "") text.text = t + \ ", ".join([utils.fixTags(e,m,args.nohtml) for e in dailyspells]) for spl in dailyspells: search = re.search(r'{@spell+ (.*?)(\|.*)?}', spl, re.IGNORECASE) if search is not None: spells.append(search.group(1)) if "spells" in s: slots = [] for level, obj in s['spells'].items(): text = ET.SubElement(trait, 'text') spellbois = obj['spells'] t = "• {} level ({} slots): ".format( utils.ordinal(int(level)), obj['slots'] if 'slots' in obj else 0) if level != "0" else "Cantrips (at will): " if level != "0": slots.append( str(obj['slots'] if 'slots' in obj else 0)) text.text = t + \ ", ".join([utils.fixTags(e,m,args.nohtml) for e in spellbois]) for spl in spellbois: search = re.search(r'{@spell+ (.*?)(\|.*)?}', spl, re.IGNORECASE) if search is not None: spells.append(search.group(1)) slotse = ET.SubElement(monster, 'slots') slotse.text = ", ".join(slots) if 'footerEntries' in s: for e in s['footerEntries']: text = ET.SubElement(trait, 'text') text.text = utils.fixTags(e, m, args.nohtml) spellse = ET.SubElement(monster, 'spells') spellse.text = ", ".join(spells) description = ET.SubElement(monster, 'description') description.text = "" if 'entries' in m and not args.srd: description.text += utils.getEntryString(m["entries"], m, args) if sourcetext: description.text += "\n<i>Source: {}</i>".format(sourcetext) if args.nohtml: description.text = re.sub('</?(i|b|spell)>', '', description.text) environment = ET.SubElement(monster, 'environment') if 'environment' in m: environment.text = ", ".join([x for x in m['environment']])
def parseItem(m, compendium, args): if '_copy' in m: if args.verbose: print("COPY: " + m['name'] + " from " + m['_copy']['name'] + " in " + m['_copy']['source']) xtrsrc = "./data/items.json" try: with open(xtrsrc) as f: d = json.load(f) f.close() mcpy = m for mn in d['item']: itemfound = False if mn['name'] == mcpy['_copy']['name']: m = mn m['name'] = mcpy['name'] m['source'] = mcpy['source'] if "otherSources" in mcpy: m["otherSources"] = mcpy["otherSources"] m['page'] = mcpy['page'] if '_mod' in mcpy['_copy']: m = utils.modifyItem(m, mcpy['_copy']['_mod']) itemfound = True break if not itemfound: print("Could not find ", mcpy['_copy']['name']) except IOError as e: if args.verbose: print("Could not load additional source ({}): {}".format( e.errno, e.strerror)) return itm = ET.SubElement(compendium, 'item') name = ET.SubElement(itm, 'name') name.text = m['name'] heading = ET.SubElement(itm, 'heading') headings = [] typ = ET.SubElement(itm, 'type') if 'type' in m: typ.text = m['type'] if m['type'] == "AIR": typ.text = 'G' if m['type'] == "AT": typ.text = 'G' if m['type'] == "GS": typ.text = 'G' if m['type'] == "INS": typ.text = 'G' if m['type'] == "MNT": typ.text = 'G' if m['type'] == "OTH": typ.text = 'G' if m['type'] == "SCF": if 'rod' in m['name'].lower(): typ.text = 'RD' elif 'wand' in m['name'].lower(): typ.text = 'WD' elif 'staff' in m['name'].lower(): typ.text = 'ST' typ.text = 'G' if m['type'] == "SHP": typ.text = 'G' if m['type'] == "T": typ.text = 'G' if m['type'] == "TAH": typ.text = 'G' if m['type'] == "TG": typ.text = 'G' if m['type'] == "VEH": typ.text = 'G' if m['type'] == 'GV': typ.text = 'G' headings.append("Generic Variant") if 'wondrous' in m and m['wondrous']: headings.append("Wondrous item") if 'type' not in m: typ.text = 'W' if 'tier' in m: headings.append(m['tier']) if 'curse' in m and m['curse']: headings.append("Cursed item") weight = ET.SubElement(itm, 'weight') if 'weight' in m: weight.text = str(m['weight']) if 'rarity' in m and m['rarity'] != 'None' and m[ 'rarity'] != 'Unknown' and not args.nohtml: rarity = ET.SubElement(itm, 'rarity') rarity.text = str(m['rarity']) if m['rarity'] != 'None' and m['rarity'] != 'Unknown': headings.append(m['rarity']) if 'value' in m: value = ET.SubElement(itm, 'value') if type(m['value']) == str: value.text = m['value'] else: if args.nohtml: value.text = str(m['value'] / 100) elif m['value'] >= 100: value.text = "{:g} gp".format(m['value'] / 100) elif m['value'] >= 10: value.text = "{:g} sp".format(m['value'] / 10) else: value.text = "{:g} cp".format(m['value']) prop = ET.SubElement(itm, 'property') if 'property' in m: prop.text = ",".join(m['property']) if 'staff' in m and m['staff']: headings.append('Staff') if 'type' not in m or m['type'] == 'SCF': typ.text = 'ST' if 'wand' in m and m['wand']: headings.append('Wand') if 'type' not in m or m['type'] == 'SCF': typ.text = 'WD' if 'weapon' in m and m['weapon'] and 'weaponCategory' in m: headings.append(m['weaponCategory'] + " Weapon") if 'type' in m: if m['type'] == 'LA': headings.append("Light Armor") elif m['type'] == 'MA': headings.append("Medium Armor") elif m['type'] == 'HA': headings.append("Heavy Armor") elif m['type'] == 'S': headings.append("Shield") elif m['type'] == 'SCF': headings.append("Spellcasting Focus") elif m['type'] == 'R': headings.append('Ranged Weapon') elif m['type'] == 'M': headings.append('Melee Weapon') elif m['type'] == 'A': headings.append('Ammunition') elif m['type'] == 'G': headings.append('Adventuring Gear') elif m['type'] == 'T': headings.append('Tools') elif m['type'] == 'AT': headings.append('Artisan Tools') elif m['type'] == 'GS': headings.append('Gaming Set') elif m['type'] == 'TG': headings.append('Trade Good') elif m['type'] == 'INS': headings.append('Instrument') elif m['type'] == 'MNT': headings.append('Mount') elif m['type'] == 'VEH': headings.append('Vehicle (land)') elif m['type'] == 'AIR': headings.append('Vehicle (air)') elif m['type'] == 'SHP': headings.append('Vehicle (water)') elif m['type'] == 'TAH': headings.append('Tack and Harness') elif m['type'] == 'OTH': headings.append('Other') if not args.nohtml: attunement = ET.SubElement(itm, 'attunement') if 'reqAttune' in m: if m['reqAttune'] == True: attunement.text = "Requires Attunement" else: attunement.text = "Requires Attunement " + m['reqAttune'] headings.append("({})".format(attunement.text)) if 'dmg1' in m: dmg1 = ET.SubElement(itm, 'dmg1') dmg1.text = utils.remove5eShit(m['dmg1']) if 'dmg2' in m: dmg2 = ET.SubElement(itm, 'dmg2') dmg2.text = utils.remove5eShit(m['dmg2']) if 'dmgType' in m: dmgType = ET.SubElement(itm, 'dmgType') if m['dmgType'] == 'O': dmgType.text = 'FC' elif m['dmgType'] == 'I': dmgType.text = 'PS' else: dmgType.text = m['dmgType'] if 'range' in m: rng = ET.SubElement(itm, 'range') rng.text = m['range'] if 'ac' in m: ac = ET.SubElement(itm, 'ac') ac.text = str(m['ac']) if 'bonus' in m: if 'type' in m and m['type'] in ['LA', 'MA', 'HA', 'S']: bonus = ET.SubElement(itm, 'modifier', {"category": "bonus"}) bonus.text = "ac {}".format(m['bonus']) elif 'type' in m and m['type'] in ['M', 'R', 'A']: bonus = ET.SubElement(itm, 'modifier', {"category": "bonus"}) bonus.text = "weapon attack {}".format(m['bonus']) bonus = ET.SubElement(itm, 'modifier', {"category": "bonus"}) bonus.text = "weapon damage {}".format(m['bonus']) elif 'staff' in m and m['staff']: bonus = ET.SubElement(itm, 'modifier', {"category": "bonus"}) bonus.text = "weapon attack {}".format(m['bonus']) bonus = ET.SubElement(itm, 'modifier', {"category": "bonus"}) bonus.text = "weapon damage {}".format(m['bonus']) else: print(m) if 'poison' in m and m['poison']: headings.append('Poison') if 'type' not in m: typ.text = 'G' if 'entries' not in m: m['entries'] = [] if 'resist' in m: if m['type'] == "LA" or m['type'] == "MA" or m['type'] == "HA": m['entries'].append( "You have resistance to {} damage while you wear this armor.". format(m['resist'])) elif m['type'] == "RG": m['entries'].append( "You have resistance to {} damage while wearing this ring.". format(m['resist'])) elif m['type'] == "P": m['entries'].append( "When you drink this potion, you gain resistance to {} damage for 1 hour." .format(m['resist'])) if 'stealth' in m and m['stealth']: m['entries'].append( "The wearer has disadvantage on Stealth (Dexterity) checks.") if 'strength' in m and m['type'] == "HA": m['entries'].append( "If the wearer has a Strength score lower than {}, their speed is reduced by 10 feet." .format(m['strength'])) heading.text = ", ".join(headings) if args.nohtml: try: itm.remove(heading) except: pass if 'items' in m: if 'scfType' in m: if m['scfType'] == "arcane": m['entries'].insert( 0, "An arcane focus is a special item–an orb, a crystal, a rod, a specially constructed staff, a wand-like length of wood, or some similar item–designed to channel the power of arcane spells. A sorcerer, warlock, or wizard can use such an item as a spellcasting focus." ) elif m['scfType'] == "druid": m['entries'].insert( 0, "A druidic focus might be a sprig of mistletoe or holly, a wand or scepter made of yew or another special wood, a staff drawn whole out of a living tree, or a totem object incorporating feathers, fur, bones, and teeth from sacred animals. A druid can use such an object as a spellcasting focus." ) elif m['scfType'] == "holy": m['entries'].insert( 0, "A holy symbol is a representation of a god or pantheon. It might be an amulet depicting a symbol representing a deity, the same symbol carefully engraved or inlaid as an emblem on a shield, or a tiny box holding a fragment of a sacred relic. A cleric or paladin can use a holy symbol as a spellcasting focus. To use the symbol in this way, the caster must hold it in hand, wear it visibly, or bear it on a shield." ) for i in m['items']: if args.nohtml: m['entries'].append(re.sub(r'^(.*?)(\|.*?)?$', r'\1', i)) else: m['entries'].append( re.sub(r'^(.*?)(\|.*?)?$', r'<item>\1</item>', i)) elif 'scfType' in m: if m['scfType'] == "arcane": m['entries'].insert( 0, "An arcane focus is a special item designed to channel the power of arcane spells. A sorcerer, warlock, or wizard can use such an item as a spellcasting focus." ) elif m['scfType'] == "druid": m['entries'].insert( 0, "A druid can use this object as a spellcasting focus.") elif m['scfType'] == "holy": m['entries'].insert( 0, "A holy symbol is a representation of a god or pantheon.") m['entries'].insert( 1, "A cleric or paladin can use a holy symbol as a spellcasting focus. To use the symbol in this way, the caster must hold it in hand, wear it visibly, or bear it on a shield." ) if 'lootTables' in m: if args.nohtml: m['entries'].append("Found On: {}".format(", ".join( m['lootTables']))) else: m['entries'].append("<i>Found On: {}</i> ".format(", ".join( m['lootTables']))) if 'source' in m: name = m["name"] if args.addimgs and os.path.isdir("img") and not os.path.isfile( os.path.join(args.tempdir, "items", name + ".png")) and not os.path.isfile( os.path.join(args.tempdir, "items", name + ".jpg")): if not os.path.isdir(os.path.join(args.tempdir, "items")): os.mkdir(os.path.join(args.tempdir, "items")) if 'image' in m: artworkpath = m['image'] else: artworkpath = None itemname = m["original_name"] if "original_name" in m else m["name"] if artworkpath and os.path.isfile("./img/" + artworkpath): artworkpath = "./img/" + artworkpath elif os.path.isfile("./img/items/" + m["source"] + "/" + itemname + ".jpg"): artworkpath = "./img/items/" + m[ "source"] + "/" + itemname + ".jpg" elif os.path.isfile("./img/items/" + m["source"] + "/" + itemname + ".png"): artworkpath = "./img/items/" + m[ "source"] + "/" + itemname + ".png" elif os.path.isfile("./img/" + m["source"] + "/" + itemname + ".png"): artworkpath = "./img/" + m["source"] + "/" + itemname + ".png" if artworkpath is not None: ext = os.path.splitext(artworkpath)[1] copyfile(artworkpath, os.path.join(args.tempdir, "items", name + ext)) imagetag = ET.SubElement(itm, 'image') imagetag.text = name + ext elif args.addimgs and os.path.isfile( os.path.join(args.tempdir, "items", name + ".png")): imagetag = ET.SubElement(itm, 'image') imagetag.text = name + ".png" elif args.addimgs and os.path.isfile( os.path.join(args.tempdir, "items", name + ".jpg")): imagetag = ET.SubElement(itm, 'image') imagetag.text = name + ".jpg" #source = ET.SubElement(itm, 'source') sourcetext = "{} p. {}".format( utils.getFriendlySource(m['source']), m['page'] ) if 'page' in m and m['page'] != 0 else utils.getFriendlySource( m['source']) if 'otherSources' in m and m["otherSources"] is not None: for s in m["otherSources"]: sourcetext += ", " sourcetext += "{} p. {}".format( utils.getFriendlySource(s["source"]), s["page"]) if 'page' in s and s[ "page"] != 0 else utils.getFriendlySource(s["source"]) if 'entries' in m: if args.nohtml: m['entries'].append("Source: {}".format(sourcetext)) else: m['entries'].append("<i>Source: {}</i>".format(sourcetext)) else: if args.nohtml: m['entries'] = ["Source: {}".format(sourcetext)] else: m['entries'] = ["<i>Source: {}</i>".format(sourcetext)] bodyText = ET.SubElement(itm, 'text') bodyText.text = "" if 'entries' in m: for e in m['entries']: if "colLabels" in e: bodyText.text += " | ".join( [utils.remove5eShit(x) for x in e['colLabels']]) bodyText.text += "\n" for row in e['rows']: rowthing = [] for r in row: if isinstance(r, dict) and 'roll' in r: rowthing.append( "{}-{}".format(r['roll']['min'], r['roll'] ['max']) if 'min' in r['roll'] else str(r['roll']['exact'])) else: rowthing.append( utils.fixTags(str(r), m, args.nohtml)) bodyText.text += " | ".join(rowthing) + "\n" elif "entries" in e: subentries = [] if 'name' in e: if args.nohtml: bodyText.text += "{}: ".format(e['name']) else: bodyText.text += "<b>{}:</b> ".format(e['name']) for sube in e["entries"]: if type(sube) == str: subentries.append(utils.fixTags(sube, m, args.nohtml)) elif type(sube) == dict and "text" in sube: subentries.append( utils.fixTags(sube["text"], m, args.nohtml)) elif type(sube) == dict and sube[ "type"] == "list" and "style" in sube and sube[ "style"] == "list-hang-notitle": for item in sube["items"]: if type(item) == dict and 'type' in item and item[ 'type'] == 'item': if args.nohtml: subentries.append("• {}: {}".format( item["name"], utils.fixTags(item["entry"], m, args.nohtml))) else: subentries.append("• <i>{}:</i> {}".format( item["name"], utils.fixTags(item["entry"], m, args.nohtml))) else: subentries.append("• {}".format( utils.fixTags(item, m, args.nohtml))) elif type(sube) == dict and sube["type"] == "list": for item in sube["items"]: if type(item) == dict and "entries" in item: ssubentries = [] for sse in item["entries"]: if type(sse) == str: ssubentries.append( utils.fixTags(sse, m, args.nohtml)) elif type(sse) == dict and "text" in sse: ssubentries.append( utils.fixTags( sse["text"], m, args.nohtml)) subentries.append("\n".join(ssubentries)) elif type( item) == dict and 'type' in item and item[ 'type'] == 'item': if args.nohtml: subentries.append("• {}: {}".format( item["name"], utils.fixTags(item["entry"], m, args.nohtml))) else: subentries.append("• <i>{}:</i> {}".format( item["name"], utils.fixTags(item["entry"], m, args.nohtml))) else: subentries.append("• {}".format( utils.fixTags(item, m, args.nohtml))) bodyText.text += "\n".join(subentries) + "\n" else: if type(e) == dict and e[ "type"] == "list" and "style" in e and e[ "style"] == "list-hang-notitle": for item in e["items"]: if args.nohtml: bodyText.text += "• {}: {}".format( item["name"], utils.fixTags(item["entry"], m, args.nohtml)) + "\n" else: bodyText.text += "• <i>{}:</i> {}".format( item["name"], utils.fixTags(item["entry"], m, args.nohtml)) + "\n" elif type(e) == dict and e["type"] == "list": for item in e["items"]: if "entries" in item: subentries = [] for sube in item["entries"]: if type(sube) == str: subentries.append( utils.fixTags(sube, m, args.nohtml)) elif type(sube) == dict and "text" in sube: subentries.append( utils.fixTags(sube["text"], m, args.nohtml)) bodyText.text += "\n".join(subentries) + "\n" else: bodyText.text += "• {}".format( utils.fixTags(item, m, args.nohtml)) + "\n" else: bodyText.text += utils.fixTags(e, m, args.nohtml) + "\n" bodyText.text = bodyText.text.rstrip() for match in re.finditer(r'([0-9])+[dD]([0-9])+([ ]?[-+][ ]?[0-9]+)?', bodyText.text): if not itm.find("./[roll='{}']".format(match.group(0))): roll = ET.SubElement(itm, 'roll') roll.text = "{}".format(match.group(0)).replace(' ', '')