Adam Goldsmith
edb8e40988
rather than using temporary png files and combining them together later, merge files together in SVG and then just render once
212 lines
7.6 KiB
Python
Executable File
212 lines
7.6 KiB
Python
Executable File
#!/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")
|
|
subprocess.call(["inkscape", "-z", "-f", outfile + ".svg", "-w",
|
|
str(baseX * CARD_WIDTH * 4), "-e", outfile + ".png"])
|
|
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)
|