122 lines
3.9 KiB
Python
122 lines
3.9 KiB
Python
import fxconv
|
|
import re
|
|
|
|
def convert(input, output, params, target):
|
|
recognized = True
|
|
|
|
if params["custom-type"] == "level":
|
|
o = convert_level(input, params)
|
|
else:
|
|
recognized = False
|
|
|
|
if recognized:
|
|
fxconv.elf(o, output, "_" + params["name"], **target)
|
|
return 0
|
|
return 1
|
|
|
|
def num(value):
|
|
return fxconv.u32(value * 65536)
|
|
|
|
def convert_level(input, params):
|
|
RE_VALUES = {
|
|
"name": re.compile(r'.*'),
|
|
"finish": re.compile(r'\d+')
|
|
}
|
|
RE_ELEMENTS = {
|
|
"mirror": (True, re.compile(r'')),
|
|
"plane": (False, re.compile(r'([A-Z]+)\s+(\S+)')),
|
|
"text": (True, re.compile(r'\"([^"]+)\"')),
|
|
}
|
|
RE_POSITION = re.compile(r'(\d+)(?:-(\d+))?')
|
|
|
|
header = dict()
|
|
elements = []
|
|
|
|
with open(input, "r") as fp:
|
|
lines = [l for l in fp.read().splitlines() if l
|
|
and not l.startswith("#")]
|
|
for i, l in enumerate(lines):
|
|
if ":" not in l:
|
|
raise fxconv.FxconvError(f"invalid line '{l}': no ':'")
|
|
key, value = [x.strip() for x in l.split(":", 1)]
|
|
|
|
m_pos = RE_POSITION.fullmatch(key)
|
|
if m_pos:
|
|
start = int(m_pos[1])
|
|
end = int(m_pos[2]) if m_pos[2] else None
|
|
things = [x.strip() for x in value.strip().split(" ", 1)]
|
|
if len(things) == 1:
|
|
key, value = things[0], ""
|
|
else:
|
|
key, value = things
|
|
|
|
if key not in RE_ELEMENTS:
|
|
raise fxconv.FxconvError(f"unknown element '{key}'")
|
|
if RE_ELEMENTS[key][0] and end is None:
|
|
raise fxconv.FxconvError(f"'{key}' needs an end position")
|
|
if not RE_ELEMENTS[key][0] and end is not None:
|
|
raise fxconv.FxconvError(f"'{key}' needs no end position")
|
|
m = RE_ELEMENTS[key][1].fullmatch(value)
|
|
if not m:
|
|
raise fxconv.FxconvError(
|
|
f"invalid value for '{key}': '{value}")
|
|
elements.append((key, start, end, m))
|
|
else:
|
|
if key not in RE_VALUES:
|
|
raise fxconv.FxconvError(f"unknown key '{key}'")
|
|
if not RE_VALUES[key].fullmatch(value):
|
|
raise fxconv.FxconvError(
|
|
f"invalid value for '{key}': '{value}'")
|
|
header[key] = value
|
|
|
|
mirrors = fxconv.ObjectData()
|
|
planes = fxconv.ObjectData()
|
|
texts = fxconv.ObjectData()
|
|
mirror_count = 0
|
|
plane_count = 0
|
|
text_count = 0
|
|
|
|
for (key, start, end, m) in elements:
|
|
if key == "mirror":
|
|
mirrors += num(start * 32)
|
|
mirrors += num(end * 32)
|
|
mirror_count += 1
|
|
|
|
elif key == "plane":
|
|
kind = m[1]
|
|
shape = m[2]
|
|
|
|
assert shape.startswith("0b")
|
|
shape = "".join(c for c in shape[2:] if c != "'")
|
|
assert(len(shape) == 25)
|
|
|
|
kinds = {
|
|
"DAMAGE": 0,
|
|
"ARROW": 1,
|
|
}
|
|
assert kind in kinds
|
|
|
|
planes += num(start * 32)
|
|
planes += fxconv.u32(int(shape, 2))
|
|
planes += fxconv.u16(kinds[kind])
|
|
planes += fxconv.u16(0) # TODO: Arrow directions
|
|
plane_count += 1
|
|
|
|
elif key == "text":
|
|
string = m[1].replace("\\n", "\n").replace("\\\\", "\\")
|
|
texts += num(start * 32)
|
|
texts += num(end * 32)
|
|
texts += fxconv.string(string)
|
|
text_count += 1
|
|
|
|
o = fxconv.ObjectData()
|
|
o += fxconv.string(header.get("name", "<Untitled>"))
|
|
o += num(int(header["finish"]) * 32)
|
|
o += fxconv.u32(mirror_count)
|
|
o += fxconv.ptr(mirrors)
|
|
o += fxconv.u32(plane_count)
|
|
o += fxconv.ptr(planes)
|
|
o += fxconv.u32(text_count)
|
|
o += fxconv.ptr(texts)
|
|
return o
|