191 lines
7.9 KiB
Python
191 lines
7.9 KiB
Python
import colorsys
|
|
import json
|
|
import io
|
|
import logging
|
|
import textwrap
|
|
from collections import namedtuple
|
|
|
|
import flask
|
|
import lxml.etree as xmltree
|
|
import mermaid
|
|
|
|
from . import core, gamedata, jsonizer, util
|
|
|
|
pth_upgrade_schema = core.path_appdir / "basepak/rules/schemas/upgrades.xsd"
|
|
doc_upgrade_schema = xmltree.parse(pth_upgrade_schema.as_posix())
|
|
upgrade_schema = xmltree.XMLSchema(doc_upgrade_schema)
|
|
upgrade_schema_parser = xmltree.XMLParser(schema=upgrade_schema)
|
|
|
|
core.schemas.append((upgrade_schema, "rules/upgrades/**.xml"))
|
|
|
|
UpgradeData = namedtuple("UpgradeData", ["id", "name", "desc", "requires", "food", "shinies"])
|
|
|
|
## \brief Renders an upgrade tree.
|
|
# \param tree The upgrade tree to retrieve.
|
|
# \api{GET} /upgrades/`<tree>`
|
|
# \return An SVG.
|
|
@core.app.route("/upgrades/<tree>")
|
|
def get_upgrade_tree(tree):
|
|
buf_mmd = io.StringIO()
|
|
rulefile = xmltree.parse(gamedata.vfs.open(f"/rules/upgrades/{tree}.xml"), upgrade_schema_parser)
|
|
ruleset = rulefile.getroot()
|
|
|
|
unlocked = []
|
|
if len(flask.request.query_string) > 0:
|
|
for upgrade in flask.request.args.get("unlocked", "").split(","):
|
|
if len(upgrade) > 0:
|
|
unlocked.append(upgrade)
|
|
|
|
hnd_treedata = ruleset.xpath("./upgrades:TreeData", namespaces=core.xml_namespaces)[0]
|
|
hnd_name = hnd_treedata.xpath("./upgrades:Name", namespaces=core.xml_namespaces)[0]
|
|
hnd_primary_color = hnd_treedata.xpath("./upgrades:PrimaryColor", namespaces=core.xml_namespaces)[0]
|
|
|
|
buf_mmd.write(textwrap.dedent(f"""
|
|
---
|
|
title: {hnd_name.text}
|
|
securityLevel: loose
|
|
---
|
|
flowchart LR
|
|
""").lstrip())
|
|
|
|
rgb_primary_color = util.hex_to_rgb(hnd_primary_color.text)
|
|
hsv_primary_color = colorsys.rgb_to_hsv(*rgb_primary_color)
|
|
print(f"{rgb_primary_color} ----> {hsv_primary_color}")
|
|
hsv_fill_open_color = (hsv_primary_color[0], hsv_primary_color[1] / 2, hsv_primary_color[2])
|
|
rgb_fill_open_color = colorsys.hsv_to_rgb(*hsv_fill_open_color)
|
|
hsv_stroke_unlock_color = (hsv_primary_color[0], 1.0, 55)
|
|
rgb_stroke_unlock_color = colorsys.hsv_to_rgb(*hsv_stroke_unlock_color)
|
|
hsv_fill_lock_color = (hsv_primary_color[0], 0.1, min(hsv_primary_color[2] * 1.5, 255))
|
|
rgb_fill_lock_color = colorsys.hsv_to_rgb(*hsv_fill_lock_color)
|
|
print(f"{hsv_fill_lock_color}, {rgb_fill_lock_color}")
|
|
hsv_stroke_lock_color = (hsv_primary_color[0], 0.1, 55)
|
|
rgb_stroke_lock_color = colorsys.hsv_to_rgb(*hsv_stroke_lock_color)
|
|
|
|
buf_mmd.write(f" classDef open fill:{util.rgb_to_hex(*rgb_fill_open_color)},stroke:{util.rgb_to_hex(*rgb_primary_color)}\n")
|
|
buf_mmd.write(f" classDef unlocked fill:{util.rgb_to_hex(*rgb_primary_color)},stroke:{util.rgb_to_hex(*rgb_stroke_unlock_color)}\n")
|
|
buf_mmd.write(f" classDef locked fill:{util.rgb_to_hex(*rgb_fill_lock_color)},stroke:{util.rgb_to_hex(*rgb_stroke_lock_color)}\n")
|
|
|
|
tree_upgrades = []
|
|
for hnd_upgrade in ruleset.iter("{seagull:rules/upgrades}Upgrade"):
|
|
hnd_id = hnd_upgrade.xpath("./upgrades:Id", namespaces=core.xml_namespaces)[0]
|
|
hnd_upgrade_name = hnd_upgrade.xpath("./upgrades:Name", namespaces=core.xml_namespaces)[0]
|
|
hnd_desc = hnd_upgrade.xpath("./upgrades:Desc", namespaces=core.xml_namespaces)[0]
|
|
try:
|
|
hnd_requires = hnd_upgrade.xpath("./upgrades:Requirements", namespaces=core.xml_namespaces)[0]
|
|
require_list = [elem.text for elem in hnd_requires.iter("{seagull:rules/upgrades}Require")]
|
|
try:
|
|
hnd_food = hnd_requires.xpath("./upgrades:Food", namespaces=core.xml_namespaces)[0]
|
|
except IndexError:
|
|
hnd_food = None
|
|
try:
|
|
hnd_shinies = hnd_requires.xpath("./upgrades:Shinies", namespaces=core.xml_namespaces)[0]
|
|
except IndexError:
|
|
hnd_shinies = None
|
|
except IndexError:
|
|
require_list = []
|
|
hnd_food = None
|
|
hnd_shinies = None
|
|
|
|
|
|
upgrade = UpgradeData(
|
|
id=hnd_id.text,
|
|
name=hnd_upgrade_name.text,
|
|
desc=hnd_desc.text,
|
|
requires=require_list,
|
|
food=int(hnd_food.text) if hnd_food is not None else 0,
|
|
shinies=int(hnd_shinies.text) if hnd_shinies is not None else 0
|
|
)
|
|
|
|
tree_upgrades.append(upgrade)
|
|
|
|
tiers = {}
|
|
dependency_lines = []
|
|
for upgrade in tree_upgrades:
|
|
deptier = 0
|
|
upgrade_food_costs = f"🍏{upgrade.food}" if upgrade.food > 0 else ""
|
|
upgrade_shinies_costs = f"🪙{upgrade.shinies}" if upgrade.shinies > 0 else ""
|
|
buf_mmd.write(f" {upgrade.id}@{{label: \"{upgrade.name}\n<span style='font-size:0.6em'>{upgrade_food_costs}{upgrade_shinies_costs}</span>\"}}\n")
|
|
collected_tiers = []
|
|
for require in upgrade.requires:
|
|
if require in tiers:
|
|
collected_tiers.append(tiers[require])
|
|
|
|
dependency_lines.append(f" {require} --> {upgrade.id}\n")
|
|
|
|
if len(collected_tiers) > 0:
|
|
deptier = max(collected_tiers)
|
|
|
|
tier = deptier + 1
|
|
tiers[upgrade.id] = tier
|
|
|
|
all_requirements_met = True
|
|
if tier > 1:
|
|
while all_requirements_met:
|
|
for require in upgrade.requires:
|
|
all_requirements_met = require in unlocked
|
|
|
|
if not all_requirements_met:
|
|
buf_mmd.write(f" class {upgrade.id} locked\n")
|
|
elif upgrade in unlocked:
|
|
buf_mmd.write(f" class {upgrade.id} unlocked\n")
|
|
else:
|
|
buf_mmd.write(f" class {upgrade.id} open\n")
|
|
buf_mmd.write(f" click {upgrade.id} call purchase_upgrade('{tree}','{upgrade.id}')\n")
|
|
|
|
for line in dependency_lines:
|
|
buf_mmd.write(line)
|
|
|
|
buf_mmd.seek(0)
|
|
mmd_str = buf_mmd.read()
|
|
mmd_upgradetree = mermaid.Mermaid(mmd_str, height=400)
|
|
#print(mmd_str)
|
|
return mmd_upgradetree.svg_response.content
|
|
|
|
@core.app.route("/upgrades/<tree>/<upgrade>")
|
|
def get_upgrade_data(tree, upgrade):
|
|
rulefile = xmltree.parse(gamedata.vfs.open(f"/rules/upgrades/{tree}.xml"), upgrade_schema_parser)
|
|
ruleset = rulefile.getroot()
|
|
|
|
target_upgrade = None
|
|
hnd_id = None
|
|
for hnd_upgrade in ruleset.iter("{seagull:rules/upgrades}Upgrade"):
|
|
hnd_id = hnd_upgrade.xpath("./upgrades:Id", namespaces=core.xml_namespaces)[0]
|
|
if hnd_id.text == upgrade:
|
|
target_upgrade = hnd_upgrade
|
|
break
|
|
|
|
hnd_name = hnd_upgrade.xpath("./upgrades:Name", namespaces=core.xml_namespaces)[0]
|
|
hnd_desc = hnd_upgrade.xpath("./upgrades:Desc", namespaces=core.xml_namespaces)[0]
|
|
try:
|
|
hnd_requires = hnd_upgrade.xpath("./upgrades:Requirements", namespaces=core.xml_namespaces)[0]
|
|
require_list = [elem.text for elem in hnd_requires.iter("{seagull:rules/upgrades}Require")]
|
|
try:
|
|
hnd_food = hnd_requires.xpath("./upgrades:Food", namespaces=core.xml_namespaces)[0]
|
|
except IndexError:
|
|
hnd_food = None
|
|
try:
|
|
hnd_shinies = hnd_requires.xpath("./upgrades:Shinies", namespaces=core.xml_namespaces)[0]
|
|
except IndexError:
|
|
hnd_shinies = None
|
|
except IndexError:
|
|
hnd_requires = None
|
|
hnd_shinies = None
|
|
hnd_food = None
|
|
require_list = []
|
|
|
|
return flask.make_response(json.dumps({
|
|
"id": hnd_id.text,
|
|
"name": hnd_name.text,
|
|
"desc": hnd_desc.text,
|
|
"food": int(hnd_food.text) if hnd_food else 0,
|
|
"shinies": int(hnd_shinies.text) if hnd_shinies else 0,
|
|
"requires": require_list
|
|
}, cls=jsonizer.JSONizer), 200)
|
|
|
|
def get_upgrade_tree_mmd(tree):
|
|
if not gamedata.vfs.exists(f"upgrades/{tree}.mmd"):
|
|
return flask.make_response("No Upgrade Tree", 404)
|
|
|
|
with gamedata.vfs.open(f"upgrades/{tree}.mmd") as fd_upgradetree:
|
|
mmd_upgradetree = mermaid.Mermaid(fd_upgradetree.read(), height=400)
|
|
return mmd_upgradetree.svg_response.content |