#!/usr/bin/env python3 import json import math import os import subprocess import sys from lxml import etree if getattr(sys, 'frozen', False): # we are running in a bundle bundle_dir = sys._MEIPASS else: # we are running in a normal Python environment bundle_dir = os.path.dirname(os.path.abspath(__file__)) CARD_WIDTH = 181 CARD_HEIGHT = 253 def setText(tree, id, text): element = tree.find('.//*[@id="' + id + '"]') if element is None: print("id", id, "not found") return elif element.tag == "{http://www.w3.org/2000/svg}flowRoot": for e in element.findall("{http://www.w3.org/2000/svg}flowPara"): element.remove(e) # clear child paragraphs lines = str(text).splitlines() for line in lines: etree.SubElement(element, "{http://www.w3.org/2000/svg}flowPara").text=line else: element.text = str(text) def removeElement(tree, id): mark = tree.find('.//*[@id="' + id + '"]') if mark is not None: mark.getparent().remove(mark) def makeSVG(base, properties): tree = etree.parse(base) for id, text in properties.items(): if id not in ["count", "art"]: setText(tree, id, text) # remove HP mark if there is no hp if "hp" not in properties: removeElement(tree, "hpMark") # remove setup box if there is no setup if "setup" not in properties: removeElement(tree, "setupBox") if "art" in properties: art = tree.find('.//*[@id="art"]') if art is not None: art.set("{http://www.w3.org/1999/xlink}href", "file://" + bundle_dir + "/" + properties["art"]) return tree def addCardToBase(svg, baseImg, baseX, cardNum): for e in svg.findall('{http://www.w3.org/2000/svg}g'): e.set("transform", e.get("transform", "") + " translate(" + \ str((cardNum % baseX) * CARD_WIDTH) + " " + \ str(int(cardNum / baseX) * CARD_HEIGHT) + ")") baseImg.getroot().append(svg.getroot()) def makeFace(baseImage, baseX, cardNum, base, card): fig = makeSVG(base, card) addCardToBase(fig, baseImage, baseX, cardNum) def makeFaces(deckJson, outfile): baseX = math.ceil(math.sqrt(len(deckJson['deck']) + len(deckJson['character']) * 2)) baseImage = etree.ElementTree( etree.Element('svg', attrib={'width': str(baseX * CARD_WIDTH) + "pt", 'height': str(baseX * CARD_HEIGHT) + "pt", 'version': "1.2", 'xmlns': "http://www.w3.org/2000/svg"})) cardType = deckJson["type"] cardNum = 0 # Make a card for each hero character card if cardType == "hero": for card in deckJson['character']: makeFace(baseImage, baseX, cardNum, os.path.join("images", cardType, "charFront.svg"), card) cardNum += 1 makeFace(baseImage, baseX, cardNum, os.path.join("images", cardType, "charBack.svg"), card) cardNum += 1 # Make a character and instructions card for each villain card elif cardType == "villain": for card in deckJson['character']: front = card["front"] front["name"] = card["name"] back = card["back"] back["name"] = card["name"] makeFace(baseImage, baseX, cardNum, os.path.join("images", cardType, "character.svg"), front) cardNum += 1 makeFace(baseImage, baseX, cardNum, os.path.join("images", cardType, "character.svg"), back) cardNum += 1 makeFace(baseImage, baseX, cardNum, os.path.join("images", cardType, "instructions.svg"), front) cardNum += 1 makeFace(baseImage, baseX, cardNum, os.path.join("images", cardType, "instructions.svg"), back) cardNum += 1 # Make a card for each card for card in deckJson['deck']: makeFace(baseImage, baseX, cardNum, os.path.join("images", cardType, "card.svg"), card) cardNum += 1 baseImage.write(outfile + ".svg") command = ["inkscape", "-z", "-f", outfile + ".svg", "-w", str(baseX * CARD_WIDTH * 5), "-e", outfile + ".png"] print("To regenerate PNG after editing SVG, run:\n " + " ".join(command)) subprocess.run(command) return baseX def makeCardJson(template, nickname, description, cardID): card = template.copy() card.update({"Nickname": nickname, "Description": description, "CardID": cardID}) return card def makeDoubleSidedCardJson(template, nickname, descriptionFront, descriptionBack, cardID): cardBack = makeCardJson(template, nickname, descriptionBack, cardID + 1) card = template.copy() card.update({"Nickname": nickname, "Description": descriptionFront, "CardID": cardID, "States": {"2": cardBack}}) return card def makeJson(deckJson, imgWidth, outfile): with open(bundle_dir + "/templates/deck.json") as f: outJson = json.load(f) with open(bundle_dir + "/templates/card.json") as f: cardTemplate = json.load(f) # number of cards in x and y direction outJson['ObjectStates'][0]['CustomDeck']['1'].update( {"NumWidth": imgWidth, "NumHeight": imgWidth, #"FaceURL": "http://adam-desktop.dyn.wpi.edu:8000/" + outfile + ".png", "FaceURL": "file://" + os.getcwd() + "/" + outfile + ".png", "BackURL": "http://cloud-3.steamusercontent.com/ugc/156906385556221451/CE2C3AFE1759790CB0B532FFD636D05A99EC91F4/"}) # decks start at (10 * deck id) cardNum = 100 if deckJson["type"] == "hero": for card in deckJson['character']: outJson['ObjectStates'][0]['DeckIDs'].append(cardNum) cardOut = makeDoubleSidedCardJson( cardTemplate, card['name'], "Active", "Incapacitated", cardNum) outJson['ObjectStates'][0]['ContainedObjects'].append(cardOut) cardNum += 2 elif deckJson["type"] == "villain": for card in deckJson['character']: outJson['ObjectStates'][0]['DeckIDs'].append(cardNum) cardOut = makeDoubleSidedCardJson( cardTemplate, card['name'], "Front", "Back", cardNum) outJson['ObjectStates'][0]['ContainedObjects'].append(cardOut) cardNum += 2 outJson['ObjectStates'][0]['DeckIDs'].append(cardNum) cardOut = makeDoubleSidedCardJson( cardTemplate, card['name'] + " instructions", "Front", "Back", cardNum) outJson['ObjectStates'][0]['ContainedObjects'].append(cardOut) cardNum += 2 for card in deckJson['deck']: for i in range(0, card.get('count', 1)): outJson['ObjectStates'][0]['DeckIDs'].append(cardNum) # add a card object thing for each card, and give it a name cardOut = makeCardJson(cardTemplate, card['name'], card.get('keywords', ""), cardNum) outJson['ObjectStates'][0]['ContainedObjects'].append(cardOut) cardNum += 1 with open(outfile + ".json", "w") as f: json.dump(outJson, f) if __name__ == '__main__': if len(sys.argv) < 3: print("not enough arguments!") inputJson = input("Input file: ") outfile = input("Output file (no suffix): ") else: inputJson = sys.argv[1] outfile = sys.argv[2] with open(inputJson) as f: deckJson = json.load(f) imgWidth = makeFaces(deckJson, outfile) makeJson(deckJson, imgWidth, outfile)