This repository has been archived on 2020-09-21. You can view files and clone it, but cannot push or open issues or pull requests.
SotMDeckBuilder/SotMDeckBuilder.py

216 lines
7.7 KiB
Python
Raw Normal View History

#!/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:
2017-08-03 18:14:48 -04:00
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")
2017-07-13 23:21:58 -04:00
# 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
2017-07-13 23:21:58 -04:00
# 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
2017-07-13 23:21:58 -04:00
# 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
2017-07-13 23:21:58 -04:00
def makeCardJson(template, nickname, description, cardID):
card = template.copy()
card.update({"Nickname": nickname,
2017-08-03 18:15:09 -04:00
"Description": description,
"CardID": cardID})
2017-07-13 23:21:58 -04:00
return card
def makeDoubleSidedCardJson(template, nickname, descriptionFront,
2017-08-03 18:15:09 -04:00
descriptionBack, cardID):
2017-07-13 23:21:58 -04:00
cardBack = makeCardJson(template, nickname, descriptionBack, cardID + 1)
card = template.copy()
card.update({"Nickname": nickname,
2017-08-03 18:15:09 -04:00
"Description": descriptionFront,
"CardID": cardID,
"States": {"2": cardBack}})
2017-07-13 23:21:58 -04:00
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
2017-07-13 23:21:58 -04:00
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
2017-07-13 23:21:58 -04:00
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)