def fixTags(s): s = re.sub(r'{@([bi]) (.*?)}',r'<\1>\2</\1>', s) s = re.sub(r'{@spell (.*?)}', r'<spell>\1</spell>', s) s = re.sub(r'{@link (.*?)\|(.*?)?}', r'<a href="\2">\1</a>', s) def createMLinks(matchobj): return "<a href=\"/monster/{}\">{}</a>".format(matchobj.group(1),matchobj.group(2)) s = re.sub(r'{@creature (.*?)\|\|(.*?)?}', createMLinks, s) def createMLink(matchobj): return "<a href=\"/monster/{}\">{}</a>".format(matchobj.group(1),matchobj.group(1).title()) s = re.sub(r'{@creature (.*?)}', createMLink, s) def createILink(matchobj): return "<a href=\"/item/{}\">{}</a>".format(matchobj.group(1),matchobj.group(1).title()) s = re.sub(r'{@item (.*?)(\|.*?)?}', createILink, s) def createCLink(matchobj): return "<a href=\"/page/{}\">{}</a>".format(matchobj.group(1),matchobj.group(1).title()) s = re.sub(r'{@class (.*?)}', createCLink, s) s = re.sub(r'{@condition (.*?)}', createCLink, s) if '{@' in s: s = utils.remove5eShit(s) if re.search(r'{[@=](.*?)}',s): s = fixTags(s) return s
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'] if args.nohtml: heading = ET.SubElement(itm, 'detail') else: 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'] == "FD": 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'] == "MR": typ.text = 'W' 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']: magic = ET.SubElement(itm, 'magic') magic.text = "1" headings.append("Wondrous item (tattoo)" if 'tattoo' in m and m['tattoo'] else "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']).title() if m['rarity'] != 'None' and m['rarity'] != 'Unknown': headings.append(str(m['rarity']).title()) if 'value' in m: value = ET.SubElement(itm, 'value') 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']) 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 m['weaponCategory'] == 'martial': if 'property' in m: m['property'].append('M') else: m['property'] = ['M'] prop = ET.SubElement(itm, 'property') if 'property' in m: if 'AF' in m['property']: headings.append("Ammunication (futuristic)") m['property'] = list(filter(lambda x: (x != 'AF'), m['property'])) if 'A' not in m['property']: m['property'].append('A') if 'RLD' in m['property']: headings.append("Reload") m['property'] = list(filter(lambda x: (x != 'RLD'), m['property'])) if 'LD' not in m['property']: m['property'].append('LD') if 'BF' in m['property']: headings.append("Burst Fire") m['property'] = list(filter(lambda x: (x != 'BF'), m['property'])) if 'R' not in m['property']: m['property'].append('R') prop.text = ",".join(m['property']) 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'] == 'FD': headings.append('Food and Drink') elif m['type'] == 'MR': headings.append('Magic Rune') 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 'tattoo' in m and m['tattoo']: m['entries'].append( "Produced by a special needle, this magic tattoo features designs that emphasize one color{}." .format(" ({})".format(m['color']) if 'color' in m else '')) m['entries'].append({ "type": "entries", "name": "Tattoo Attunement", "entries": [ "To attune to this item, you hold the needle to your skin where you want the tattoo to appear, pressing the needle there throughout the attunement process. When the attunement is complete, the needle turns into the ink that becomes the tattoo, which appears on the skin.", "If your attunement to the tattoo ends, the tattoo vanishes, and the needle reappears in your space." ] }) if 'resist' in m: if 'type' 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'])) elif 'tattoo' in m and m['tattoo']: m['entries'].append({ "type": "entries", "name": "Damage Resistance", "entries": [ "While the tattoo is on your skin, you have resistance to {} damage" .format(m['resist']) ] }) m['entries'].append({ "type": "entries", "name": "Damage Absorption", "entries": [ "When you take {} damage, you can use your reaction to gain immunity against that instance of the damage, and you regain a number of hit points equal to half the damage you would have taken. Once this reaction is used, it can't be used again until the next dawn." .format(m['resist']) ] }) if 'stealth' in m and m['stealth']: stealth = ET.SubElement(itm, 'stealth') stealth.text = "1" m['entries'].append( "The wearer has disadvantage on Stealth (Dexterity) checks.") if 'strength' in m: strength = ET.SubElement(itm, 'strength') strength.text = str(m['strength'] or '') if 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 and not args.srd: 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 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, "items", slug + ".png")) and not os.path.isfile( os.path.join(args.tempdir, "items", slug + ".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" elif os.path.isfile("./img/" + m["source"] + "/" + itemname + ".jpg"): artworkpath = "./img/" + m["source"] + "/" + itemname + ".jpg" elif os.path.isfile("./img/items/" + "/" + itemname + ".jpg"): artworkpath = "./img/items/" + "/" + itemname + ".jpg" elif os.path.isfile("./img/items/" + "/" + itemname + ".png"): artworkpath = "./img/items/" + "/" + itemname + ".png" elif os.path.isfile("./img/" + "/" + itemname + ".png"): artworkpath = "./img/" + "/" + itemname + ".png" elif os.path.isfile("./img/" + "/" + itemname + ".jpg"): artworkpath = "./img/" + "/" + itemname + ".jpg" if artworkpath is not None: ext = os.path.splitext(artworkpath)[1] copyfile(artworkpath, os.path.join(args.tempdir, "items", slug + ext)) imagetag = ET.SubElement(itm, 'image') imagetag.text = slug + ext elif args.addimgs and os.path.isfile( os.path.join(args.tempdir, "items", slug + ".png")): imagetag = ET.SubElement(itm, 'image') imagetag.text = slug + ".png" elif args.addimgs and os.path.isfile( os.path.join(args.tempdir, "items", slug + ".jpg")): imagetag = ET.SubElement(itm, 'image') imagetag.text = 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"]: 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(itm, 'source') source.text = sourcetext bodyText = ET.SubElement(itm, 'text') bodyText.text = "" if 'entries' in m: for e in m['entries']: if type(e) == dict and e['type'] == 'table': if 'caption' in e: bodyText.text += "{}\n".format(e['caption']) if 'colLabels' in e: bodyText.text += " | ".join( [utils.remove5eShit(x) for x in e['colLabels']]) + "\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'] == 'table': if 'caption' in sube: subentries.append("{}".format(sube['caption'])) if 'colLabels' in sube: subentries.append(" | ".join([ utils.remove5eShit(x) for x in sube['colLabels'] ])) 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)) subentries.append(" | ".join(rowthing)) 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))) elif type(item) == dict and item[ "type"] == "list" and "style" in item and item[ "style"] == "list-hang-notitle": for subitem in item["items"]: if args.nohtml: subentries.append("• {}: {}".format( subitem["name"], utils.fixTags( subitem["entry"], m, args.nohtml)) + "\n") else: subentries.append( "• <i>{}:</i> {}".format( subitem["name"], utils.fixTags( subitem["entry"], m, args.nohtml)) + "\n") 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 type(item) == dict: 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" else: bodyText.text += "• {}".format( utils.fixTags(item, 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(' ', '')
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') id = ET.SubElement(monster, 'id') id.text = m['source'].lower() + "-" + re.sub(r'\W+', '', m['name']).lower() 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') savelist = ET.SubElement(monster, 'savelist') if 'save' in m: savestr = ET.SubElement(savelist, 'str') savestr.text = m['save'].get('str', '') savedex = ET.SubElement(savelist, 'dex') savedex.text = m['save'].get('dex', '') savecon = ET.SubElement(savelist, 'con') savecon.text = m['save'].get('con', '') saveint = ET.SubElement(savelist, 'int') saveint.text = m['save'].get('int', '') savewis = ET.SubElement(savelist, 'wis') savewis.text = m['save'].get('wis', '') savecha = ET.SubElement(savelist, 'cha') savecha.text = m['save'].get('cha', '') 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 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 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 parseMonster(m, compendium, args): if '_copy' in m: if args.verbose: print("COPY: " + m['name']) return 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']) else: 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'] alignment = ET.SubElement(monster, 'alignment') alignment.text = utils.convertAlignList(m['alignment']) ac = ET.SubElement(monster, 'ac') acstr = [] for acs in m['ac']: if isinstance(acs, dict): if 'from' in acs: acstr.append("{} ({})".format( acs['ac'], utils.remove5eShit(acs['from'][0]))) elif 'condition' in acs: acstr.append("{} ({})".format( acs['ac'], utils.remove5eShit(acs['condition']))) else: acstr.append(str(acs)) ac.text = ", ".join(acstr) hp = ET.SubElement(monster, 'hp') if "special" in m['hp']: hp.text = m['hp']['special'] else: hp.text = "{} ({})".format(m['hp']['average'], m['hp']['formula']) speed = ET.SubElement(monster, 'speed') if 'choose' in m['speed']: lis = [] for key, value in m['speed'].items(): if key == "walk": lis.append(str(value) + " ft.") elif key == "choose": value['from'].insert(-1, 'or') lis.append( "{} {} ft.".format( ", ".join( value['from']), value['amount'])) 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']) statdex = ET.SubElement(monster, 'dex') statdex.text = str(m['dex']) statcon = ET.SubElement(monster, 'con') statcon.text = str(m['con']) statint = ET.SubElement(monster, 'int') statint.text = str(m['int']) statwis = ET.SubElement(monster, 'wis') statwis.text = str(m['wis']) statcha = ET.SubElement(monster, 'cha') statcha.text = str(m['cha']) 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: skill.text = ", ".join(["{} {}".format(str.capitalize( key), value) for key, value in m['skill'].items()]) 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 isinstance(m['cr'], dict): cr.text = str(m['cr']['cr']) else: 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: trait = ET.SubElement(monster, 'trait') name = ET.SubElement(trait, 'name') name.text = "Source" text = ET.SubElement(trait, 'text') text.text = "{} p. {}".format( m['source'], m['page']) if 'page' in m and m['page'] != 0 else m['source'] 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']) for e in t['entries']: if "colLabels" in e: text = ET.SubElement(trait, 'text') text.text = " | ".join([utils.remove5eShit(x) for x in e['colLabels']]) 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.remove5eShit(r)) text = ET.SubElement(trait, 'text') text.text = " | ".join(rowthing) else: text = ET.SubElement(trait, 'text') text.text = utils.remove5eShit(e) if 'action' in m: for t in m['action']: action = ET.SubElement(monster, 'action') name = ET.SubElement(action, 'name') name.text = utils.remove5eShit(t['name']) for e in t['entries']: if isinstance(e, dict): if "colLabels" in e: text = ET.SubElement(action, 'text') text.text = " | ".join( [utils.remove5eShit(x) for x in e['colLabels']]) 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.remove5eShit(r)) text = ET.SubElement(action, 'text') text.text = " | ".join(rowthing) else: for i in e["items"]: text = ET.SubElement(action, 'text') if 'name' in i: text.text = "{}{}".format( i['name'] + " ", utils.remove5eShit(i['entry'])) else: text.text = "\n".join( utils.remove5eShit(x) for x in i) else: text = ET.SubElement(action, 'text') text.text = utils.remove5eShit(e) if 'legendary' in m: for t in m['legendary']: legendary = ET.SubElement(monster, 'legendary') name = ET.SubElement(legendary, 'name') name.text = utils.remove5eShit(t['name']) for e in t['entries']: if isinstance(e, dict): if "colLabels" in e: text = ET.SubElement(legendary, 'text') text.text = " | ".join( [utils.remove5eShit(x) for x in e['colLabels']]) 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.remove5eShit(r)) text = ET.SubElement(legendary, 'text') text.text = " | ".join(rowthing) else: for i in e["items"]: text = ET.SubElement(legendary, 'text') text.text = "{} {}".format( i['name'], utils.remove5eShit(i['entry'])) else: text = ET.SubElement(legendary, 'text') text.text = utils.remove5eShit(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.remove5eShit(e) 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.remove5eShit(e) 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.remove5eShit(e) 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) spellse = ET.SubElement(monster, 'spells') spellse.text = ", ".join(spells) environment = ET.SubElement(monster, 'environment') if 'environment' in m: environment.text = ", ".join([x for x in m['environment']])
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 parseEntries(m, args): bodyText = "" for e in m['entries']: if "colLabels" in e: if 'caption' in e: bodyText += "{}\n".format(e['caption']) bodyText += " | ".join( [utils.remove5eShit(x) for x in e['colLabels']]) bodyText += "\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 += " | ".join(rowthing) + "\n" elif "entries" in e: subentries = [] if 'name' in e: if args.nohtml: bodyText += "{}: ".format(e['name']) else: bodyText += "<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 += "\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 += "• {}: {}".format( item["name"], utils.fixTags(item["entry"], m, args.nohtml)) + "\n" else: bodyText += "• <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 += "\n".join(subentries) + "\n" else: bodyText += "• {}".format( utils.fixTags(item, m, args.nohtml)) + "\n" else: bodyText += utils.fixTags(e, m, args.nohtml) + "\n" bodyText = bodyText.rstrip() return bodyText