mirror of
https://github.com/pmret/papermario.git
synced 2024-11-18 08:52:40 +01:00
ninja messages + improved msg generated headers
This commit is contained in:
parent
5ac16f969a
commit
d2eb186682
12
Makefile
12
Makefile
@ -242,12 +242,12 @@ $(ASSETS_BIN:.bin=.o): $(ASSETS_BIN)
|
|||||||
$(LD) -r -b binary -o $@ $<
|
$(LD) -r -b binary -o $@ $<
|
||||||
|
|
||||||
# Messages
|
# Messages
|
||||||
$(MSG_BIN): $(MESSAGES)
|
# $(MSG_BIN): $(MESSAGES)
|
||||||
@mkdir -p $(shell dirname $@)
|
# @mkdir -p $(shell dirname $@)
|
||||||
@echo "building $@"
|
# @echo "building $@"
|
||||||
@$(PYTHON) tools/compile_messages.py $@ /dev/null $(MESSAGES)
|
# @$(PYTHON) tools/compile_messages.py $@ /dev/null $(MESSAGES)
|
||||||
$(MSG_BIN:.bin=.o): $(MSG_BIN)
|
# $(MSG_BIN:.bin=.o): $(MSG_BIN)
|
||||||
$(LD) -r -b binary -o $@ $<
|
# $(LD) -r -b binary -o $@ $<
|
||||||
|
|
||||||
# Sprites
|
# Sprites
|
||||||
# $(foreach npc, $(NPC_SPRITES), $(eval $(BUILD_DIR)/sprite/npc/$(npc):: $(shell find sprite/npc/$(npc) -type f 2> /dev/null))) # dependencies
|
# $(foreach npc, $(NPC_SPRITES), $(eval $(BUILD_DIR)/sprite/npc/$(npc):: $(shell find sprite/npc/$(npc) -type f 2> /dev/null))) # dependencies
|
||||||
|
38
configure.py
38
configure.py
@ -205,7 +205,16 @@ async def main():
|
|||||||
description="ld_addrs_h $in")
|
description="ld_addrs_h $in")
|
||||||
n.newline()
|
n.newline()
|
||||||
|
|
||||||
objects, segments = read_splat("tools/splat.yaml") # no .o extension!
|
# $msg_combine_headers
|
||||||
|
n.rule("msg_combine",
|
||||||
|
command="$python tools/msg/combine.py $out $in --headers $msg_combine_headers",
|
||||||
|
description="combine messages")
|
||||||
|
n.rule("msg",
|
||||||
|
command="$python tools/msg/parse_compile.py $in $out",
|
||||||
|
description="msg $in")
|
||||||
|
n.newline()
|
||||||
|
|
||||||
|
objects, segments = read_splat("tools/splat.yaml") # no .o extensions!
|
||||||
c_files = (f for f in objects if f.endswith(".c")) # glob("src/**/*.c", recursive=True)
|
c_files = (f for f in objects if f.endswith(".c")) # glob("src/**/*.c", recursive=True)
|
||||||
|
|
||||||
n.comment("target")
|
n.comment("target")
|
||||||
@ -218,6 +227,8 @@ async def main():
|
|||||||
generated_headers = []
|
generated_headers = []
|
||||||
|
|
||||||
def add_generated_header(h: str):
|
def add_generated_header(h: str):
|
||||||
|
generated_headers.append(h)
|
||||||
|
|
||||||
if not os.path.exists(h):
|
if not os.path.exists(h):
|
||||||
# mkdir -p
|
# mkdir -p
|
||||||
os.makedirs(os.path.dirname(h), exist_ok=True)
|
os.makedirs(os.path.dirname(h), exist_ok=True)
|
||||||
@ -232,6 +243,26 @@ async def main():
|
|||||||
|
|
||||||
n.build(add_generated_header("include/ld_addrs.h"), "ld_addrs_h", "$builddir/$target.ld")
|
n.build(add_generated_header("include/ld_addrs.h"), "ld_addrs_h", "$builddir/$target.ld")
|
||||||
|
|
||||||
|
# messages
|
||||||
|
msg_files = glob("src/**/*.msg", recursive=True) + glob("msg/**/*.msg", recursive=True)
|
||||||
|
for msg_file in msg_files:
|
||||||
|
n.build(
|
||||||
|
f"$builddir/{msg_file}.bin",
|
||||||
|
"msg",
|
||||||
|
msg_file,
|
||||||
|
implicit="tools/msg/parse_compile.py",
|
||||||
|
)
|
||||||
|
n.build(
|
||||||
|
"$builddir/msg.bin",
|
||||||
|
"msg_combine",
|
||||||
|
[f"$builddir/{msg_file}.bin" for msg_file in msg_files],
|
||||||
|
implicit="tools/msg/combine.py",
|
||||||
|
implicit_outputs=[add_generated_header(f"{msg_file}.h") for msg_file in msg_files],
|
||||||
|
variables={ "msg_combine_headers": [f"{msg_file}.h" for msg_file in msg_files] }
|
||||||
|
)
|
||||||
|
n.build("$builddir/msg.o", "bin", "$builddir/msg.bin")
|
||||||
|
|
||||||
|
# sprites
|
||||||
npc_sprite_yay0s = []
|
npc_sprite_yay0s = []
|
||||||
for sprite_id, sprite_name in enumerate(NPC_SPRITES, 1):
|
for sprite_id, sprite_name in enumerate(NPC_SPRITES, 1):
|
||||||
sources = glob(f"sprite/npc/{sprite_name}/**/*.*", recursive=True)
|
sources = glob(f"sprite/npc/{sprite_name}/**/*.*", recursive=True)
|
||||||
@ -287,8 +318,11 @@ async def main():
|
|||||||
elif f.endswith(".png"):
|
elif f.endswith(".png"):
|
||||||
build_image(f, segment)
|
build_image(f, segment)
|
||||||
elif f == "sprite/npc":
|
elif f == "sprite/npc":
|
||||||
n.build(f"$builddir/{f}.bin", "npc_sprites", npc_sprite_yay0s)
|
# combine sprites
|
||||||
|
n.build(f"$builddir/{f}.bin", "npc_sprites", npc_sprite_yay0s, implicit="tools/compile_npc_sprites.py")
|
||||||
n.build(obj(f), "bin", f"$builddir/{f}.bin")
|
n.build(obj(f), "bin", f"$builddir/{f}.bin")
|
||||||
|
elif f == "/msg":
|
||||||
|
continue # done already above
|
||||||
else:
|
else:
|
||||||
print("warning: dont know what to do with object " + f)
|
print("warning: dont know what to do with object " + f)
|
||||||
n.newline()
|
n.newline()
|
||||||
|
@ -1,823 +0,0 @@
|
|||||||
#! /usr/bin/python3
|
|
||||||
|
|
||||||
from sys import argv
|
|
||||||
from collections import OrderedDict
|
|
||||||
import re
|
|
||||||
|
|
||||||
class Message:
|
|
||||||
def __init__(self, name, section, index):
|
|
||||||
self.name = name
|
|
||||||
self.section = section
|
|
||||||
self.index = index
|
|
||||||
|
|
||||||
self.bytes = []
|
|
||||||
|
|
||||||
def try_convert_int(s):
|
|
||||||
try:
|
|
||||||
return int(s, base=0)
|
|
||||||
except:
|
|
||||||
return s
|
|
||||||
|
|
||||||
def parse_command(source):
|
|
||||||
if source[0] != "[":
|
|
||||||
return None, [], {}, source
|
|
||||||
source = source[1:] # "["
|
|
||||||
|
|
||||||
inside_brackets = ""
|
|
||||||
while source[0] != "]":
|
|
||||||
if source[0] == "\n":
|
|
||||||
return None, [], {}, source
|
|
||||||
|
|
||||||
inside_brackets += source[0]
|
|
||||||
source = source[1:]
|
|
||||||
source = source[1:] # "]"
|
|
||||||
|
|
||||||
command, *args = inside_brackets.split(" ")
|
|
||||||
|
|
||||||
positional_args = []
|
|
||||||
named_args = {}
|
|
||||||
|
|
||||||
if "=" in command:
|
|
||||||
key, value = command.split("=", 1)
|
|
||||||
command = key
|
|
||||||
named_args[key] = try_convert_int(value)
|
|
||||||
|
|
||||||
for arg in args:
|
|
||||||
if "=" in arg:
|
|
||||||
key, value = arg.split("=", 1)
|
|
||||||
named_args[key.lower()] = try_convert_int(value.lower())
|
|
||||||
else:
|
|
||||||
positional_args.append(try_convert_int(arg))
|
|
||||||
|
|
||||||
return command.lower(), positional_args, named_args, source
|
|
||||||
|
|
||||||
def color_to_code(color, ctx="normal"):
|
|
||||||
COLORS = {
|
|
||||||
"normal": {
|
|
||||||
"normal": 0x0A,
|
|
||||||
"red": 0x20,
|
|
||||||
"pink": 0x21,
|
|
||||||
"purple": 0x22,
|
|
||||||
"blue": 0x23,
|
|
||||||
"cyan": 0x24,
|
|
||||||
"green": 0x25,
|
|
||||||
"yellow": 0x26,
|
|
||||||
},
|
|
||||||
"diary": {
|
|
||||||
"normal": 0x00,
|
|
||||||
"red": 0x07,
|
|
||||||
},
|
|
||||||
"inspect": {
|
|
||||||
"dark": 0x17,
|
|
||||||
},
|
|
||||||
"button": {
|
|
||||||
"blue": 0x10,
|
|
||||||
"green": 0x11,
|
|
||||||
"red": 0x12,
|
|
||||||
"yellow": 0x13,
|
|
||||||
"gray": 0x14,
|
|
||||||
"grey": 0x14,
|
|
||||||
},
|
|
||||||
"popup": {
|
|
||||||
"red": 0x28,
|
|
||||||
"pink": 0x29,
|
|
||||||
"purple": 0x2A,
|
|
||||||
"blue": 0x2B,
|
|
||||||
"teal": 0x2C,
|
|
||||||
"green": 0x2D,
|
|
||||||
"yellow": 0x2E,
|
|
||||||
"normal": 0x2F,
|
|
||||||
},
|
|
||||||
"sign": {
|
|
||||||
"normal": 0x18,
|
|
||||||
"red": 0x19,
|
|
||||||
"blue": 0x1A,
|
|
||||||
"green": 0x1B,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if type(color) is int:
|
|
||||||
return color
|
|
||||||
|
|
||||||
return COLORS.get(ctx, {}).get(color)
|
|
||||||
|
|
||||||
CHARSET = {
|
|
||||||
"𝅘𝅥𝅮": 0x00,
|
|
||||||
"!": 0x01,
|
|
||||||
'"': 0x02,
|
|
||||||
"#": 0x03,
|
|
||||||
"$": 0x04,
|
|
||||||
"%": 0x05,
|
|
||||||
"&": 0x06,
|
|
||||||
"'": 0x07,
|
|
||||||
"(": 0x08,
|
|
||||||
")": 0x09,
|
|
||||||
"*": 0x0A,
|
|
||||||
"+": 0x0B,
|
|
||||||
",": 0x0C,
|
|
||||||
"-": 0x0D,
|
|
||||||
".": 0x0E,
|
|
||||||
"/": 0x0F,
|
|
||||||
"0": 0x10,
|
|
||||||
"1": 0x11,
|
|
||||||
"2": 0x12,
|
|
||||||
"3": 0x13,
|
|
||||||
"4": 0x14,
|
|
||||||
"5": 0x15,
|
|
||||||
"6": 0x16,
|
|
||||||
"7": 0x17,
|
|
||||||
"8": 0x18,
|
|
||||||
"9": 0x19,
|
|
||||||
":": 0x1A,
|
|
||||||
";": 0x1B,
|
|
||||||
"<": 0x1C,
|
|
||||||
"=": 0x1D,
|
|
||||||
">": 0x1E,
|
|
||||||
"?": 0x1F,
|
|
||||||
"@": 0x20,
|
|
||||||
"A": 0x21,
|
|
||||||
"B": 0x22,
|
|
||||||
"C": 0x23,
|
|
||||||
"D": 0x24,
|
|
||||||
"E": 0x25,
|
|
||||||
"F": 0x26,
|
|
||||||
"G": 0x27,
|
|
||||||
"H": 0x28,
|
|
||||||
"I": 0x29,
|
|
||||||
"J": 0x2A,
|
|
||||||
"K": 0x2B,
|
|
||||||
"L": 0x2C,
|
|
||||||
"M": 0x2D,
|
|
||||||
"N": 0x2E,
|
|
||||||
"O": 0x2F,
|
|
||||||
"P": 0x30,
|
|
||||||
"Q": 0x31,
|
|
||||||
"R": 0x32,
|
|
||||||
"S": 0x33,
|
|
||||||
"T": 0x34,
|
|
||||||
"U": 0x35,
|
|
||||||
"V": 0x36,
|
|
||||||
"W": 0x37,
|
|
||||||
"X": 0x38,
|
|
||||||
"Y": 0x39,
|
|
||||||
"Z": 0x3A,
|
|
||||||
"[": 0x3B,
|
|
||||||
"¥": 0x3C,
|
|
||||||
"]": 0x3D,
|
|
||||||
"^": 0x3E,
|
|
||||||
"_": 0x3F,
|
|
||||||
"`": 0x40,
|
|
||||||
"a": 0x41,
|
|
||||||
"b": 0x42,
|
|
||||||
"c": 0x43,
|
|
||||||
"d": 0x44,
|
|
||||||
"e": 0x45,
|
|
||||||
"f": 0x46,
|
|
||||||
"g": 0x47,
|
|
||||||
"h": 0x48,
|
|
||||||
"i": 0x49,
|
|
||||||
"j": 0x4A,
|
|
||||||
"k": 0x4B,
|
|
||||||
"l": 0x4C,
|
|
||||||
"m": 0x4D,
|
|
||||||
"n": 0x4E,
|
|
||||||
"o": 0x4F,
|
|
||||||
"p": 0x50,
|
|
||||||
"q": 0x51,
|
|
||||||
"r": 0x52,
|
|
||||||
"s": 0x53,
|
|
||||||
"t": 0x54,
|
|
||||||
"u": 0x55,
|
|
||||||
"v": 0x56,
|
|
||||||
"w": 0x57,
|
|
||||||
"x": 0x58,
|
|
||||||
"y": 0x59,
|
|
||||||
"z": 0x5A,
|
|
||||||
"{": 0x5B,
|
|
||||||
"|": 0x5C,
|
|
||||||
"}": 0x5D,
|
|
||||||
"~": 0x5E,
|
|
||||||
"°": 0x5F,
|
|
||||||
"À": 0x60,
|
|
||||||
"Á": 0x61,
|
|
||||||
"Â": 0x62,
|
|
||||||
"Ä": 0x63,
|
|
||||||
"Ç": 0x64,
|
|
||||||
"È": 0x65,
|
|
||||||
"É": 0x66,
|
|
||||||
"Ê": 0x67,
|
|
||||||
"Ë": 0x68,
|
|
||||||
"Ì": 0x69,
|
|
||||||
"Í": 0x6A,
|
|
||||||
"Î": 0x6B,
|
|
||||||
"Ï": 0x6C,
|
|
||||||
"Ñ": 0x6D,
|
|
||||||
"Ò": 0x6E,
|
|
||||||
"Ó": 0x6F,
|
|
||||||
"Ô": 0x70,
|
|
||||||
"Ö": 0x71,
|
|
||||||
"Ù": 0x72,
|
|
||||||
"Ú": 0x73,
|
|
||||||
"Û": 0x74,
|
|
||||||
"Ü": 0x75,
|
|
||||||
"ß": 0x76,
|
|
||||||
"à": 0x77,
|
|
||||||
"á": 0x78,
|
|
||||||
"â": 0x79,
|
|
||||||
"ä": 0x7A,
|
|
||||||
"ç": 0x7B,
|
|
||||||
"è": 0x7C,
|
|
||||||
"é": 0x7D,
|
|
||||||
"ê": 0x7E,
|
|
||||||
"ë": 0x7F,
|
|
||||||
"ì": 0x80,
|
|
||||||
"í": 0x81,
|
|
||||||
"î": 0x82,
|
|
||||||
"ï": 0x83,
|
|
||||||
"ñ": 0x84,
|
|
||||||
"ò": 0x85,
|
|
||||||
"ó": 0x86,
|
|
||||||
"ô": 0x87,
|
|
||||||
"ö": 0x88,
|
|
||||||
"ù": 0x89,
|
|
||||||
"ú": 0x8A,
|
|
||||||
"û": 0x8B,
|
|
||||||
"ü": 0x8C,
|
|
||||||
"¡": 0x8D,
|
|
||||||
"¿": 0x8E,
|
|
||||||
"ª": 0x8F,
|
|
||||||
"♥": 0x90,
|
|
||||||
"★": 0x91,
|
|
||||||
"↑": 0x92,
|
|
||||||
"↓": 0x93,
|
|
||||||
"←": 0x94,
|
|
||||||
"→": 0x95,
|
|
||||||
"●": 0x96,
|
|
||||||
"✖": 0x97,
|
|
||||||
"“": 0xA2,
|
|
||||||
"”": 0xA3,
|
|
||||||
"‘": 0xA4,
|
|
||||||
"’": 0xA5,
|
|
||||||
" ": 0xF7,
|
|
||||||
"Ⓐ": [0xFF, 0x24, 0xFF, 0x05, 0x10, 0x98, 0xFF, 0x25],
|
|
||||||
"Ⓑ": [0xFF, 0x24, 0xFF, 0x05, 0x11, 0x99, 0xFF, 0x25],
|
|
||||||
"Ⓢ": [0xFF, 0x24, 0xFF, 0x05, 0x12, 0xA1, 0xFF, 0x25],
|
|
||||||
"▲": [0xFF, 0x24, 0xFF, 0x05, 0x13, 0x9D, 0xFF, 0x25],
|
|
||||||
"▼": [0xFF, 0x24, 0xFF, 0x05, 0x13, 0x9E, 0xFF, 0x25],
|
|
||||||
"◀": [0xFF, 0x24, 0xFF, 0x05, 0x13, 0x9F, 0xFF, 0x25],
|
|
||||||
"▶": [0xFF, 0x24, 0xFF, 0x05, 0x13, 0xA0, 0xFF, 0x25],
|
|
||||||
"Ⓛ": [0xFF, 0x24, 0xFF, 0x05, 0x14, 0x9A, 0xFF, 0x25],
|
|
||||||
"Ⓡ": [0xFF, 0x24, 0xFF, 0x05, 0x14, 0x9B, 0xFF, 0x25],
|
|
||||||
"Ⓩ": [0xFF, 0x24, 0xFF, 0x05, 0x14, 0x9C, 0xFF, 0x25],
|
|
||||||
}
|
|
||||||
|
|
||||||
CHARSET_CREDITS = {
|
|
||||||
"A": 0x00,
|
|
||||||
"B": 0x01,
|
|
||||||
"C": 0x02,
|
|
||||||
"D": 0x03,
|
|
||||||
"E": 0x04,
|
|
||||||
"F": 0x05,
|
|
||||||
"G": 0x06,
|
|
||||||
"H": 0x07,
|
|
||||||
"I": 0x08,
|
|
||||||
"J": 0x09,
|
|
||||||
"K": 0x0A,
|
|
||||||
"L": 0x0B,
|
|
||||||
"M": 0x0C,
|
|
||||||
"N": 0x0D,
|
|
||||||
"O": 0x0E,
|
|
||||||
"P": 0x0F,
|
|
||||||
"Q": 0x10,
|
|
||||||
"R": 0x11,
|
|
||||||
"S": 0x12,
|
|
||||||
"T": 0x13,
|
|
||||||
"U": 0x14,
|
|
||||||
"V": 0x15,
|
|
||||||
"W": 0x16,
|
|
||||||
"X": 0x17,
|
|
||||||
"Y": 0x18,
|
|
||||||
"Z": 0x19,
|
|
||||||
"'": 0x1A,
|
|
||||||
".": 0x1B,
|
|
||||||
",": 0x1C,
|
|
||||||
"0": 0x1D,
|
|
||||||
"1": 0x1E,
|
|
||||||
"2": 0x1F,
|
|
||||||
"3": 0x20,
|
|
||||||
"4": 0x21,
|
|
||||||
"5": 0x22,
|
|
||||||
"6": 0x23,
|
|
||||||
"7": 0x24,
|
|
||||||
"8": 0x25,
|
|
||||||
"9": 0x26,
|
|
||||||
"©": 0x27,
|
|
||||||
"&": 0x28,
|
|
||||||
" ": 0xF7,
|
|
||||||
}
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
if len(argv) < 4:
|
|
||||||
print("usage: compile_messages.py [OUTBIN] [OUTHEADER] [INFILES]")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
_, outfile, outheader, *infiles = argv
|
|
||||||
|
|
||||||
messages = []
|
|
||||||
|
|
||||||
for filename in infiles:
|
|
||||||
message = None
|
|
||||||
with open(filename, "r") as f:
|
|
||||||
source = f.read()
|
|
||||||
lineno = 1
|
|
||||||
|
|
||||||
charset = CHARSET
|
|
||||||
font_stack = [0]
|
|
||||||
sound_stack = [0]
|
|
||||||
color_stack = [0x0A]
|
|
||||||
|
|
||||||
while len(source) > 0:
|
|
||||||
if source.startswith("\n"):
|
|
||||||
lineno += 1
|
|
||||||
source = source[1:]
|
|
||||||
continue
|
|
||||||
|
|
||||||
if message is None:
|
|
||||||
if source.startswith("//"):
|
|
||||||
while source[0] != "\n":
|
|
||||||
source = source[1:]
|
|
||||||
else:
|
|
||||||
command, positional_args, named_args, source = parse_command(source)
|
|
||||||
|
|
||||||
if not command:
|
|
||||||
print(f"{filename}:{lineno}: expected [message]")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
name = positional_args[0] if len(positional_args) > 0 else None
|
|
||||||
message = Message(name, named_args.get("section"), named_args.get("index"))
|
|
||||||
messages.append(message)
|
|
||||||
else:
|
|
||||||
command, positional_args, named_args, source = parse_command(source)
|
|
||||||
|
|
||||||
if command:
|
|
||||||
if command == "/message":
|
|
||||||
message.bytes += [0xFD]
|
|
||||||
|
|
||||||
# padding
|
|
||||||
while len(message.bytes) % 4 != 0:
|
|
||||||
message.bytes += [0x00]
|
|
||||||
|
|
||||||
message = None
|
|
||||||
elif command == "raw":
|
|
||||||
message.bytes += [*positional_args]
|
|
||||||
elif command == "func":
|
|
||||||
message.bytes += [0xFF, *positional_args]
|
|
||||||
elif command == "br":
|
|
||||||
message.bytes += [0xF0]
|
|
||||||
elif command == "prompt":
|
|
||||||
message.bytes += [0xF1]
|
|
||||||
elif command == "sleep":
|
|
||||||
if len(positional_args) == 0:
|
|
||||||
print(f"{filename}:{lineno}: {command} command requires a positional parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xF2, positional_args[0]]
|
|
||||||
elif command == "next":
|
|
||||||
message.bytes += [0xFB]
|
|
||||||
elif command == "color":
|
|
||||||
if "color" not in named_args:
|
|
||||||
print(f"{filename}:{lineno}: color command requires a 'color' parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
color = color_to_code(**named_args)
|
|
||||||
|
|
||||||
if color is None:
|
|
||||||
print(f"{filename}:{lineno}: unknown color combination {named_args}")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x05, color]
|
|
||||||
color_stack.append(color)
|
|
||||||
elif command == "/color":
|
|
||||||
color_stack.pop()
|
|
||||||
message.bytes += [0xFF, 0x05, color_stack[0]]
|
|
||||||
elif command == "style":
|
|
||||||
if "style" not in named_args:
|
|
||||||
print(f"{filename}:{lineno}: style command requires a 'style' parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFC]
|
|
||||||
|
|
||||||
style = named_args["style"]
|
|
||||||
if type(style) is int:
|
|
||||||
message.bytes += [style, *positional_args]
|
|
||||||
else:
|
|
||||||
if style == "right":
|
|
||||||
message.bytes += [0x01]
|
|
||||||
elif style == "left":
|
|
||||||
message.bytes += [0x02]
|
|
||||||
elif style == "center":
|
|
||||||
message.bytes += [0x03]
|
|
||||||
elif style == "tattle":
|
|
||||||
message.bytes += [0x04]
|
|
||||||
elif style == "choice":
|
|
||||||
if "w" not in named_args or "h" not in named_args or "x" not in named_args or "y" not in named_args:
|
|
||||||
print(f"{filename}:{lineno}: 'choice' style requires parameters: x, y, w, h")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0x05, named_args["x"], named_args["y"], named_args["w"], named_args["h"]]
|
|
||||||
elif style == "inspect":
|
|
||||||
message.bytes += [0x06]
|
|
||||||
elif style == "sign":
|
|
||||||
message.bytes += [0x07]
|
|
||||||
elif style == "lamppost":
|
|
||||||
message.bytes += [0x08]
|
|
||||||
elif style == "postcard":
|
|
||||||
message.bytes += [0x09]
|
|
||||||
elif style == "popup":
|
|
||||||
message.bytes += [0x0A]
|
|
||||||
elif style == "upgrade":
|
|
||||||
if "w" not in named_args or "h" not in named_args or "x" not in named_args or "y" not in named_args:
|
|
||||||
print(f"{filename}:{lineno}: 'upgrade' style requires parameters: x, y, w, h")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0x0C, named_args["w"], named_args["x"], named_args["h"], named_args["y"]]
|
|
||||||
elif style == "narrate":
|
|
||||||
message.bytes += [0x0D]
|
|
||||||
elif style == "epilogue":
|
|
||||||
message.bytes += [0x0E]
|
|
||||||
elif command == "font":
|
|
||||||
if "font" not in named_args:
|
|
||||||
print(f"{filename}:{lineno}: font command requires a 'font' parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
font = named_args["font"]
|
|
||||||
|
|
||||||
if font == "normal":
|
|
||||||
font = 0
|
|
||||||
elif font == "title":
|
|
||||||
font = 3
|
|
||||||
elif font == "subtitle":
|
|
||||||
font = 4
|
|
||||||
|
|
||||||
if type(font) is not int:
|
|
||||||
print(f"{filename}:{lineno}: unknown font '{font}'")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x00, font]
|
|
||||||
font_stack.append(font)
|
|
||||||
|
|
||||||
if font == 3 or font == 4:
|
|
||||||
charset = CHARSET_CREDITS
|
|
||||||
else:
|
|
||||||
charset = CHARSET
|
|
||||||
elif command == "/font":
|
|
||||||
font_stack.pop()
|
|
||||||
message.bytes += [0xFF, 0x00, font_stack[0]]
|
|
||||||
|
|
||||||
if font == 3 or font == 4:
|
|
||||||
charset = CHARSET_CREDITS
|
|
||||||
else:
|
|
||||||
charset = CHARSET
|
|
||||||
elif command == "noskip":
|
|
||||||
message.bytes += [0xFF, 0x07]
|
|
||||||
elif command == "/noskip":
|
|
||||||
message.bytes += [0xFF, 0x08]
|
|
||||||
elif command == "instant":
|
|
||||||
message.bytes += [0xFF, 0x09]
|
|
||||||
elif command == "/instant":
|
|
||||||
message.bytes += [0xFF, 0x0A]
|
|
||||||
elif command == "kerning":
|
|
||||||
if "kerning" not in named_args:
|
|
||||||
print(f"{filename}:{lineno}: kerning command requires a 'kerning' parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x0B, named_args["kerning"]]
|
|
||||||
elif command == "scroll":
|
|
||||||
if len(positional_args) == 0:
|
|
||||||
print(f"{filename}:{lineno}: scroll command requires a positional parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x0C, positional_args[0]]
|
|
||||||
elif command == "size":
|
|
||||||
if "x" not in named_args or "y" not in named_args:
|
|
||||||
print(f"{filename}:{lineno}: size command requires parameters: x, y")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x0D, named_args["x"], named_args["y"]]
|
|
||||||
elif command == "/size":
|
|
||||||
message.bytes += [0xFF, 0x0E]
|
|
||||||
elif command == "speed":
|
|
||||||
if "delay" not in named_args or "chars" not in named_args:
|
|
||||||
print(f"{filename}:{lineno}: speed command requires parameters: delay, chars")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x0F, named_args["delay"], named_args["chars"]]
|
|
||||||
elif command == "pos":
|
|
||||||
if "y" not in named_args:
|
|
||||||
print(f"{filename}:{lineno}: pos command requires parameter: y (x is optional)")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
if "x" in named_args:
|
|
||||||
message.bytes += [0xFF, 0x10, named_args["x"], named_args["y"]]
|
|
||||||
else:
|
|
||||||
message.bytes += [0xFF, 0x11, named_args["y"]]
|
|
||||||
elif command == "indent":
|
|
||||||
if len(positional_args) == 0:
|
|
||||||
print(f"{filename}:{lineno}: indent command requires a positional parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x12, positional_args[0]]
|
|
||||||
elif command == "down":
|
|
||||||
if len(positional_args) == 0:
|
|
||||||
print(f"{filename}:{lineno}: down command requires a positional parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x13, positional_args[0]]
|
|
||||||
elif command == "up":
|
|
||||||
if len(positional_args) == 0:
|
|
||||||
print(f"{filename}:{lineno}: up command requires a positional parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x14, positional_args[0]]
|
|
||||||
elif command == "image":
|
|
||||||
if len(positional_args) == 1:
|
|
||||||
message.bytes += [0xFF, 0x15, positional_args[0]]
|
|
||||||
elif len(positional_args) == 7:
|
|
||||||
message.bytes += [0xFF, 0x18, *positional_args]
|
|
||||||
else:
|
|
||||||
print(f"{filename}:{lineno}: image command requires 1 or 7 positional parameters")
|
|
||||||
exit(1)
|
|
||||||
elif command == "sprite":
|
|
||||||
if len(positional_args) != 3:
|
|
||||||
print(f"{filename}:{lineno}: sprite command requires 3 positional parameters")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x16, *positional_args]
|
|
||||||
elif command == "item":
|
|
||||||
if len(positional_args) != 2:
|
|
||||||
print(f"{filename}:{lineno}: item command requires 2 positional parameters")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x17, *positional_args]
|
|
||||||
elif command == "cursor":
|
|
||||||
if len(positional_args) != 1:
|
|
||||||
print(f"{filename}:{lineno}: cursor command requires 1 positional parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x1E, *positional_args]
|
|
||||||
elif command == "option":
|
|
||||||
if len(positional_args) != 1:
|
|
||||||
print(f"{filename}:{lineno}: option command requires 1 positional parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x21, *positional_args]
|
|
||||||
elif command == "choice":
|
|
||||||
if len(positional_args) != 1:
|
|
||||||
print(f"{filename}:{lineno}: choice command requires 1 positional parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x1E, positional_args[0], 0xFF, 0x21, positional_args[0]]
|
|
||||||
elif command == "choicecount":
|
|
||||||
if "choicecount" not in named_args:
|
|
||||||
print(f"{filename}:{lineno}: choicecount command requires a 'choicecount' parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x1F, named_args["choicecount"]]
|
|
||||||
elif command == "cancel":
|
|
||||||
if "cancel" not in named_args:
|
|
||||||
print(f"{filename}:{lineno}: cancel command requires a 'cancel' parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x20, named_args["cancel"]]
|
|
||||||
elif command == "shaky":
|
|
||||||
message.bytes += [0xFF, 0x26, 0x00]
|
|
||||||
elif command == "/shaky":
|
|
||||||
message.bytes += [0xFF, 0x27, 0x00]
|
|
||||||
elif command == "wavy":
|
|
||||||
message.bytes += [0xFF, 0x26, 0x01]
|
|
||||||
elif command == "/wavy":
|
|
||||||
message.bytes += [0xFF, 0x27, 0x01]
|
|
||||||
elif command == "shaky":
|
|
||||||
if "opacity" in named_args:
|
|
||||||
print(f"{filename}:{lineno}: shaky command doesn't accept parameter 'fade' (hint: did you mean 'faded-shaky'?)")
|
|
||||||
exit(1)
|
|
||||||
message.bytes += [0xFF, 0x26, 0x00]
|
|
||||||
elif command == "/shaky":
|
|
||||||
message.bytes += [0xFF, 0x27, 0x00]
|
|
||||||
elif command == "noise":
|
|
||||||
message.bytes += [0xFF, 0x26, 0x03, named_args.get("fade", 3)]
|
|
||||||
elif command == "/noise":
|
|
||||||
message.bytes += [0xFF, 0x27, 0x03]
|
|
||||||
elif command == "faded-shaky":
|
|
||||||
message.bytes += [0xFF, 0x26, 0x05, named_args.get("fade", 5)]
|
|
||||||
elif command == "/faded-shaky":
|
|
||||||
message.bytes += [0xFF, 0x27, 0x05]
|
|
||||||
elif command == "fade":
|
|
||||||
message.bytes += [0xFF, 0x26, 0x07, named_args.get("fade", 7)]
|
|
||||||
elif command == "/fade":
|
|
||||||
message.bytes += [0xFF, 0x27, 0x07]
|
|
||||||
elif command == "shout" or command == "shrinking":
|
|
||||||
message.bytes += [0xFF, 0x26, 0x0A]
|
|
||||||
elif command == "/shout" or command == "/shrinking":
|
|
||||||
message.bytes += [0xFF, 0x27, 0x0A]
|
|
||||||
elif command == "whisper" or command == "growing":
|
|
||||||
message.bytes += [0xFF, 0x26, 0x0B]
|
|
||||||
elif command == "/whisper" or command == "/growing":
|
|
||||||
message.bytes += [0xFF, 0x27, 0x0B]
|
|
||||||
elif command == "scream" or command == "shaky-size":
|
|
||||||
message.bytes += [0xFF, 0x26, 0x0C]
|
|
||||||
elif command == "/scream" or command == "/shaky-size":
|
|
||||||
message.bytes += [0xFF, 0x27, 0x0C]
|
|
||||||
elif command == "chortle" or command == "wavy-size":
|
|
||||||
message.bytes += [0xFF, 0x26, 0x0D]
|
|
||||||
elif command == "/chortle" or command == "/wavy-size":
|
|
||||||
message.bytes += [0xFF, 0x27, 0x0D]
|
|
||||||
elif command == "shadow":
|
|
||||||
message.bytes += [0xFF, 0x26, 0x0E]
|
|
||||||
elif command == "/shadow":
|
|
||||||
message.bytes += [0xFF, 0x27, 0x0E]
|
|
||||||
elif command == "var":
|
|
||||||
if len(positional_args) != 1:
|
|
||||||
print(f"{filename}:{lineno}: var command requires 1 positional parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x28, *positional_args]
|
|
||||||
elif command == "center":
|
|
||||||
if len(positional_args) != 1:
|
|
||||||
print(f"{filename}:{lineno}: center command requires 1 positional parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x29, *positional_args]
|
|
||||||
elif command == "volume":
|
|
||||||
if "volume" not in named_args:
|
|
||||||
print(f"{filename}:{lineno}: volume command requires a 'volume' parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x2E, named_args["volume"]]
|
|
||||||
elif command == "sound":
|
|
||||||
if "sound" not in named_args:
|
|
||||||
print(f"{filename}:{lineno}: sound command requires a 'sound' parameter")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
sound = named_args["sound"]
|
|
||||||
|
|
||||||
if sound == "normal":
|
|
||||||
sound = 0
|
|
||||||
elif sound == "bowser":
|
|
||||||
sound = 1
|
|
||||||
elif sound == "spirit":
|
|
||||||
sound = 2
|
|
||||||
|
|
||||||
if type(sound) is not int:
|
|
||||||
print(f"{filename}:{lineno}: unknown sound '{sound}'")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
message.bytes += [0xFF, 0x2F, sound]
|
|
||||||
sound_stack.append(sound)
|
|
||||||
elif command == "/sound":
|
|
||||||
sound_stack.pop()
|
|
||||||
message.bytes += [0xFF, 0x2F, sound_stack[0]]
|
|
||||||
elif command == "a":
|
|
||||||
color_code = color_to_code(named_args.get("color", "blue"), named_args.get("ctx", "button"))
|
|
||||||
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x98, 0xFF, 0x25]
|
|
||||||
elif command == "b":
|
|
||||||
color_code = color_to_code(named_args.get("color", "green"), named_args.get("ctx", "button"))
|
|
||||||
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x99, 0xFF, 0x25]
|
|
||||||
elif command == "l":
|
|
||||||
color_code = color_to_code(named_args.get("color", "gray"), named_args.get("ctx", "button"))
|
|
||||||
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x9A, 0xFF, 0x25]
|
|
||||||
elif command == "r":
|
|
||||||
color_code = color_to_code(named_args.get("color", "gray"), named_args.get("ctx", "button"))
|
|
||||||
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x9B, 0xFF, 0x25]
|
|
||||||
elif command == "z":
|
|
||||||
color_code = color_to_code(named_args.get("color", "gray"), named_args.get("ctx", "button"))
|
|
||||||
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x9C, 0xFF, 0x25]
|
|
||||||
elif command == "c-up":
|
|
||||||
color_code = color_to_code(named_args.get("color", "yellow"), named_args.get("ctx", "button"))
|
|
||||||
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x9D, 0xFF, 0x25]
|
|
||||||
elif command == "c-down":
|
|
||||||
color_code = color_to_code(named_args.get("color", "yellow"), named_args.get("ctx", "button"))
|
|
||||||
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x9E, 0xFF, 0x25]
|
|
||||||
elif command == "c-left":
|
|
||||||
color_code = color_to_code(named_args.get("color", "yellow"), named_args.get("ctx", "button"))
|
|
||||||
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x9F, 0xFF, 0x25]
|
|
||||||
elif command == "c-right":
|
|
||||||
color_code = color_to_code(named_args.get("color", "yellow"), named_args.get("ctx", "button"))
|
|
||||||
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0xA0, 0xFF, 0x25]
|
|
||||||
elif command == "start":
|
|
||||||
color_code = color_to_code(named_args.get("color", "red"), named_args.get("ctx", "button"))
|
|
||||||
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0xA1, 0xFF, 0x25]
|
|
||||||
elif command == "note":
|
|
||||||
message.bytes += [0x00]
|
|
||||||
elif command == "heart":
|
|
||||||
message.bytes += [0x90]
|
|
||||||
elif command == "star":
|
|
||||||
message.bytes += [0x91]
|
|
||||||
elif command == "arrow-up":
|
|
||||||
message.bytes += [0x92]
|
|
||||||
elif command == "arrow-down":
|
|
||||||
message.bytes += [0x93]
|
|
||||||
elif command == "arrow-left":
|
|
||||||
message.bytes += [0x94]
|
|
||||||
elif command == "arrow-right":
|
|
||||||
message.bytes += [0x95]
|
|
||||||
elif command == "circle":
|
|
||||||
message.bytes += [0x96]
|
|
||||||
elif command == "cross":
|
|
||||||
message.bytes += [0x97]
|
|
||||||
elif command == "wait":
|
|
||||||
print(f"{filename}:{lineno}: unknown command 'wait' (hint: did you mean 'prompt'?)")
|
|
||||||
exit(1)
|
|
||||||
elif command == "pause":
|
|
||||||
print(f"{filename}:{lineno}: unknown command 'pause' (hint: did you mean 'sleep'?)")
|
|
||||||
exit(1)
|
|
||||||
else:
|
|
||||||
print(f"{filename}:{lineno}: unknown command '{command}'")
|
|
||||||
exit(1)
|
|
||||||
else:
|
|
||||||
if source[0] == "\\":
|
|
||||||
source = source[1:]
|
|
||||||
|
|
||||||
if source[0] in charset:
|
|
||||||
data = charset[source[0]]
|
|
||||||
|
|
||||||
if type(data) is int:
|
|
||||||
message.bytes.append(data)
|
|
||||||
else:
|
|
||||||
message.bytes += data
|
|
||||||
|
|
||||||
source = source[1:]
|
|
||||||
else:
|
|
||||||
print(f"{filename}:{lineno}: unsupported character '{source[0]}' for current font")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
if message != None:
|
|
||||||
print(f"{filename}: missing [/message]")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
with open(outfile, "wb") as f:
|
|
||||||
messages.sort(key=lambda msg: bool(msg.section) + bool(msg.index))
|
|
||||||
|
|
||||||
names = OrderedDict()
|
|
||||||
|
|
||||||
sections = [] * 0x2E
|
|
||||||
for message in messages:
|
|
||||||
if message.section is None:
|
|
||||||
# allocate a section
|
|
||||||
for section_idx, section in enumerate(sections):
|
|
||||||
if len(section) < 0xFFF:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
section_idx = message.section
|
|
||||||
while len(sections) <= section_idx:
|
|
||||||
sections.append([])
|
|
||||||
section = sections[section_idx]
|
|
||||||
|
|
||||||
index = message.index if message.index is not None else len(section)
|
|
||||||
|
|
||||||
if message.name:
|
|
||||||
if message.name in names:
|
|
||||||
print(f"warning: multiple messages with name '{message.name}'")
|
|
||||||
|
|
||||||
names[message.name] = (section_idx, index)
|
|
||||||
|
|
||||||
section.append(bytes(message.bytes))
|
|
||||||
|
|
||||||
f.seek((len(sections) + 1) * 4) # skip past table of contents
|
|
||||||
|
|
||||||
section_offsets = []
|
|
||||||
for section in sections:
|
|
||||||
message_offsets = []
|
|
||||||
for message in section:
|
|
||||||
message_offsets.append(f.tell())
|
|
||||||
f.write(message)
|
|
||||||
|
|
||||||
section_offset = f.tell()
|
|
||||||
section_offsets.append(section_offset)
|
|
||||||
for offset in message_offsets:
|
|
||||||
f.write(offset.to_bytes(4, byteorder="big"))
|
|
||||||
f.write(section_offset.to_bytes(4, byteorder="big"))
|
|
||||||
|
|
||||||
# padding
|
|
||||||
while f.tell() % 0x10 != 0:
|
|
||||||
f.write(b'\0\0\0\0')
|
|
||||||
|
|
||||||
f.seek(0)
|
|
||||||
for offset in section_offsets:
|
|
||||||
f.write(offset.to_bytes(4, byteorder="big"))
|
|
||||||
f.write(b'\0\0\0\0')
|
|
||||||
|
|
||||||
with open(outheader, "w") as f:
|
|
||||||
f.write(
|
|
||||||
"#ifndef _MESSAGE_IDS_H_\n"
|
|
||||||
"#define _MESSAGE_IDS_H_\n"
|
|
||||||
"\n"
|
|
||||||
'#include "messages.h"\n'
|
|
||||||
"\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
for name, i in names.items():
|
|
||||||
section, index = i
|
|
||||||
f.write(f"#define MessageID_{name} MESSAGE_ID({section}, {index})\n")
|
|
||||||
|
|
||||||
f.write("\n#endif\n")
|
|
125
tools/msg/combine.py
Executable file
125
tools/msg/combine.py
Executable file
@ -0,0 +1,125 @@
|
|||||||
|
#! /usr/bin/python3
|
||||||
|
|
||||||
|
from sys import argv
|
||||||
|
from collections import OrderedDict
|
||||||
|
import re
|
||||||
|
import msgpack
|
||||||
|
import os
|
||||||
|
|
||||||
|
class Message:
|
||||||
|
def __init__(self, d: dict, header_file_index: int):
|
||||||
|
self.section = d.get("section")
|
||||||
|
self.index = d.get("index")
|
||||||
|
self.name = d.get("name")
|
||||||
|
self.bytes = d["bytes"]
|
||||||
|
self.header_file_index = header_file_index
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(argv) < 3:
|
||||||
|
print("usage: combine.py [out.bin] [compiled...] --headers [out.h]")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
_, outfile, *infiles = argv
|
||||||
|
|
||||||
|
messages = []
|
||||||
|
header_files = []
|
||||||
|
|
||||||
|
for i, infile in enumerate(infiles):
|
||||||
|
if infile == "--headers":
|
||||||
|
header_files = infiles[i+1:]
|
||||||
|
break
|
||||||
|
|
||||||
|
with open(infile, "rb") as f:
|
||||||
|
messages.extend(Message(msg, i) for msg in msgpack.unpack(f))
|
||||||
|
|
||||||
|
with open(outfile, "wb") as f:
|
||||||
|
# sectioned+indexed, followed by just sectioned, followed by just indexed, followed by named (unsectioned & unindexed)
|
||||||
|
messages.sort(key=lambda msg: bool(msg.section)<<2 + bool(msg.index))
|
||||||
|
|
||||||
|
names = set()
|
||||||
|
|
||||||
|
sections = [] * 0x2E
|
||||||
|
messages_by_file = {}
|
||||||
|
|
||||||
|
for message in messages:
|
||||||
|
if message.section is None:
|
||||||
|
# allocate a section
|
||||||
|
for section_idx, section in enumerate(sections):
|
||||||
|
if len(section) < 0xFFF:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
section_idx = message.section
|
||||||
|
while len(sections) <= section_idx:
|
||||||
|
sections.append([])
|
||||||
|
section = sections[section_idx]
|
||||||
|
|
||||||
|
index = message.index if message.index is not None else len(section)
|
||||||
|
|
||||||
|
if message.name:
|
||||||
|
if message.name in names:
|
||||||
|
print(f"warning: multiple messages with name '{message.name}'")
|
||||||
|
else:
|
||||||
|
names.add(message.name)
|
||||||
|
|
||||||
|
if message.header_file_index in messages_by_file:
|
||||||
|
messages_by_file[message.header_file_index].add(message)
|
||||||
|
else:
|
||||||
|
messages_by_file[message.header_file_index] = set([message])
|
||||||
|
|
||||||
|
section.append(message.bytes)
|
||||||
|
|
||||||
|
f.seek((len(sections) + 1) * 4) # skip past table of contents
|
||||||
|
|
||||||
|
section_offsets = []
|
||||||
|
for section in sections:
|
||||||
|
message_offsets = []
|
||||||
|
for message in section:
|
||||||
|
message_offsets.append(f.tell())
|
||||||
|
f.write(message)
|
||||||
|
|
||||||
|
section_offset = f.tell()
|
||||||
|
section_offsets.append(section_offset)
|
||||||
|
for offset in message_offsets:
|
||||||
|
f.write(offset.to_bytes(4, byteorder="big"))
|
||||||
|
f.write(section_offset.to_bytes(4, byteorder="big"))
|
||||||
|
|
||||||
|
# padding
|
||||||
|
while f.tell() % 0x10 != 0:
|
||||||
|
f.write(b'\0\0\0\0')
|
||||||
|
|
||||||
|
f.seek(0)
|
||||||
|
for offset in section_offsets:
|
||||||
|
f.write(offset.to_bytes(4, byteorder="big"))
|
||||||
|
f.write(b'\0\0\0\0')
|
||||||
|
|
||||||
|
for i, header_file in enumerate(header_files):
|
||||||
|
messages = messages_by_file.get(i, [])
|
||||||
|
|
||||||
|
h = (
|
||||||
|
f"#ifndef _MESSAGE_IDS_{i}_H_\n"
|
||||||
|
f"#define _MESSAGE_IDS_{i}_H_\n"
|
||||||
|
"\n"
|
||||||
|
'#include "messages.h"\n'
|
||||||
|
"\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
for message in messages:
|
||||||
|
h += f"#define MessageID_{message.name} MESSAGE_ID({message.section}, {message.index})\n"
|
||||||
|
|
||||||
|
h += "\n#endif\n"
|
||||||
|
h_lines = h.splitlines()
|
||||||
|
|
||||||
|
# this doesnt work properly with ninja. the build is fast enough anyway
|
||||||
|
"""
|
||||||
|
# only rewrite the header file if its content changed
|
||||||
|
with open(header_file, "r") as f:
|
||||||
|
cur_h_lines = f.read().splitlines()
|
||||||
|
is_different = cur_h_lines != h_lines
|
||||||
|
|
||||||
|
if is_different:
|
||||||
|
with open(header_file, "w") as f:
|
||||||
|
f.write(h)
|
||||||
|
"""
|
||||||
|
|
||||||
|
with open(header_file, "w") as f:
|
||||||
|
f.write(h)
|
764
tools/msg/parse_compile.py
Normal file
764
tools/msg/parse_compile.py
Normal file
@ -0,0 +1,764 @@
|
|||||||
|
#! /usr/bin/python3
|
||||||
|
|
||||||
|
from sys import argv
|
||||||
|
from collections import OrderedDict
|
||||||
|
import re
|
||||||
|
import msgpack # way faster than pickle
|
||||||
|
|
||||||
|
class Message:
|
||||||
|
def __init__(self, name, section, index):
|
||||||
|
self.name = name
|
||||||
|
self.section = section
|
||||||
|
self.index = index
|
||||||
|
|
||||||
|
self.bytes = [] # XXX: bytearray would be better
|
||||||
|
|
||||||
|
def try_convert_int(s):
|
||||||
|
try:
|
||||||
|
return int(s, base=0)
|
||||||
|
except:
|
||||||
|
return s
|
||||||
|
|
||||||
|
def parse_command(source):
|
||||||
|
if source[0] != "[":
|
||||||
|
return None, [], {}, source
|
||||||
|
source = source[1:] # "["
|
||||||
|
|
||||||
|
inside_brackets = ""
|
||||||
|
while source[0] != "]":
|
||||||
|
if source[0] == "\n":
|
||||||
|
return None, [], {}, source
|
||||||
|
|
||||||
|
inside_brackets += source[0]
|
||||||
|
source = source[1:]
|
||||||
|
source = source[1:] # "]"
|
||||||
|
|
||||||
|
command, *args = inside_brackets.split(" ")
|
||||||
|
|
||||||
|
positional_args = []
|
||||||
|
named_args = {}
|
||||||
|
|
||||||
|
if "=" in command:
|
||||||
|
key, value = command.split("=", 1)
|
||||||
|
command = key
|
||||||
|
named_args[key] = try_convert_int(value)
|
||||||
|
|
||||||
|
for arg in args:
|
||||||
|
if "=" in arg:
|
||||||
|
key, value = arg.split("=", 1)
|
||||||
|
named_args[key.lower()] = try_convert_int(value.lower())
|
||||||
|
else:
|
||||||
|
positional_args.append(try_convert_int(arg))
|
||||||
|
|
||||||
|
return command.lower(), positional_args, named_args, source
|
||||||
|
|
||||||
|
def color_to_code(color, ctx="normal"):
|
||||||
|
COLORS = {
|
||||||
|
"normal": {
|
||||||
|
"normal": 0x0A,
|
||||||
|
"red": 0x20,
|
||||||
|
"pink": 0x21,
|
||||||
|
"purple": 0x22,
|
||||||
|
"blue": 0x23,
|
||||||
|
"cyan": 0x24,
|
||||||
|
"green": 0x25,
|
||||||
|
"yellow": 0x26,
|
||||||
|
},
|
||||||
|
"diary": {
|
||||||
|
"normal": 0x00,
|
||||||
|
"red": 0x07,
|
||||||
|
},
|
||||||
|
"inspect": {
|
||||||
|
"dark": 0x17,
|
||||||
|
},
|
||||||
|
"button": {
|
||||||
|
"blue": 0x10,
|
||||||
|
"green": 0x11,
|
||||||
|
"red": 0x12,
|
||||||
|
"yellow": 0x13,
|
||||||
|
"gray": 0x14,
|
||||||
|
"grey": 0x14,
|
||||||
|
},
|
||||||
|
"popup": {
|
||||||
|
"red": 0x28,
|
||||||
|
"pink": 0x29,
|
||||||
|
"purple": 0x2A,
|
||||||
|
"blue": 0x2B,
|
||||||
|
"teal": 0x2C,
|
||||||
|
"green": 0x2D,
|
||||||
|
"yellow": 0x2E,
|
||||||
|
"normal": 0x2F,
|
||||||
|
},
|
||||||
|
"sign": {
|
||||||
|
"normal": 0x18,
|
||||||
|
"red": 0x19,
|
||||||
|
"blue": 0x1A,
|
||||||
|
"green": 0x1B,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if type(color) is int:
|
||||||
|
return color
|
||||||
|
|
||||||
|
return COLORS.get(ctx, {}).get(color)
|
||||||
|
|
||||||
|
CHARSET = {
|
||||||
|
"𝅘𝅥𝅮": 0x00,
|
||||||
|
"!": 0x01,
|
||||||
|
'"': 0x02,
|
||||||
|
"#": 0x03,
|
||||||
|
"$": 0x04,
|
||||||
|
"%": 0x05,
|
||||||
|
"&": 0x06,
|
||||||
|
"'": 0x07,
|
||||||
|
"(": 0x08,
|
||||||
|
")": 0x09,
|
||||||
|
"*": 0x0A,
|
||||||
|
"+": 0x0B,
|
||||||
|
",": 0x0C,
|
||||||
|
"-": 0x0D,
|
||||||
|
".": 0x0E,
|
||||||
|
"/": 0x0F,
|
||||||
|
"0": 0x10,
|
||||||
|
"1": 0x11,
|
||||||
|
"2": 0x12,
|
||||||
|
"3": 0x13,
|
||||||
|
"4": 0x14,
|
||||||
|
"5": 0x15,
|
||||||
|
"6": 0x16,
|
||||||
|
"7": 0x17,
|
||||||
|
"8": 0x18,
|
||||||
|
"9": 0x19,
|
||||||
|
":": 0x1A,
|
||||||
|
";": 0x1B,
|
||||||
|
"<": 0x1C,
|
||||||
|
"=": 0x1D,
|
||||||
|
">": 0x1E,
|
||||||
|
"?": 0x1F,
|
||||||
|
"@": 0x20,
|
||||||
|
"A": 0x21,
|
||||||
|
"B": 0x22,
|
||||||
|
"C": 0x23,
|
||||||
|
"D": 0x24,
|
||||||
|
"E": 0x25,
|
||||||
|
"F": 0x26,
|
||||||
|
"G": 0x27,
|
||||||
|
"H": 0x28,
|
||||||
|
"I": 0x29,
|
||||||
|
"J": 0x2A,
|
||||||
|
"K": 0x2B,
|
||||||
|
"L": 0x2C,
|
||||||
|
"M": 0x2D,
|
||||||
|
"N": 0x2E,
|
||||||
|
"O": 0x2F,
|
||||||
|
"P": 0x30,
|
||||||
|
"Q": 0x31,
|
||||||
|
"R": 0x32,
|
||||||
|
"S": 0x33,
|
||||||
|
"T": 0x34,
|
||||||
|
"U": 0x35,
|
||||||
|
"V": 0x36,
|
||||||
|
"W": 0x37,
|
||||||
|
"X": 0x38,
|
||||||
|
"Y": 0x39,
|
||||||
|
"Z": 0x3A,
|
||||||
|
"[": 0x3B,
|
||||||
|
"¥": 0x3C,
|
||||||
|
"]": 0x3D,
|
||||||
|
"^": 0x3E,
|
||||||
|
"_": 0x3F,
|
||||||
|
"`": 0x40,
|
||||||
|
"a": 0x41,
|
||||||
|
"b": 0x42,
|
||||||
|
"c": 0x43,
|
||||||
|
"d": 0x44,
|
||||||
|
"e": 0x45,
|
||||||
|
"f": 0x46,
|
||||||
|
"g": 0x47,
|
||||||
|
"h": 0x48,
|
||||||
|
"i": 0x49,
|
||||||
|
"j": 0x4A,
|
||||||
|
"k": 0x4B,
|
||||||
|
"l": 0x4C,
|
||||||
|
"m": 0x4D,
|
||||||
|
"n": 0x4E,
|
||||||
|
"o": 0x4F,
|
||||||
|
"p": 0x50,
|
||||||
|
"q": 0x51,
|
||||||
|
"r": 0x52,
|
||||||
|
"s": 0x53,
|
||||||
|
"t": 0x54,
|
||||||
|
"u": 0x55,
|
||||||
|
"v": 0x56,
|
||||||
|
"w": 0x57,
|
||||||
|
"x": 0x58,
|
||||||
|
"y": 0x59,
|
||||||
|
"z": 0x5A,
|
||||||
|
"{": 0x5B,
|
||||||
|
"|": 0x5C,
|
||||||
|
"}": 0x5D,
|
||||||
|
"~": 0x5E,
|
||||||
|
"°": 0x5F,
|
||||||
|
"À": 0x60,
|
||||||
|
"Á": 0x61,
|
||||||
|
"Â": 0x62,
|
||||||
|
"Ä": 0x63,
|
||||||
|
"Ç": 0x64,
|
||||||
|
"È": 0x65,
|
||||||
|
"É": 0x66,
|
||||||
|
"Ê": 0x67,
|
||||||
|
"Ë": 0x68,
|
||||||
|
"Ì": 0x69,
|
||||||
|
"Í": 0x6A,
|
||||||
|
"Î": 0x6B,
|
||||||
|
"Ï": 0x6C,
|
||||||
|
"Ñ": 0x6D,
|
||||||
|
"Ò": 0x6E,
|
||||||
|
"Ó": 0x6F,
|
||||||
|
"Ô": 0x70,
|
||||||
|
"Ö": 0x71,
|
||||||
|
"Ù": 0x72,
|
||||||
|
"Ú": 0x73,
|
||||||
|
"Û": 0x74,
|
||||||
|
"Ü": 0x75,
|
||||||
|
"ß": 0x76,
|
||||||
|
"à": 0x77,
|
||||||
|
"á": 0x78,
|
||||||
|
"â": 0x79,
|
||||||
|
"ä": 0x7A,
|
||||||
|
"ç": 0x7B,
|
||||||
|
"è": 0x7C,
|
||||||
|
"é": 0x7D,
|
||||||
|
"ê": 0x7E,
|
||||||
|
"ë": 0x7F,
|
||||||
|
"ì": 0x80,
|
||||||
|
"í": 0x81,
|
||||||
|
"î": 0x82,
|
||||||
|
"ï": 0x83,
|
||||||
|
"ñ": 0x84,
|
||||||
|
"ò": 0x85,
|
||||||
|
"ó": 0x86,
|
||||||
|
"ô": 0x87,
|
||||||
|
"ö": 0x88,
|
||||||
|
"ù": 0x89,
|
||||||
|
"ú": 0x8A,
|
||||||
|
"û": 0x8B,
|
||||||
|
"ü": 0x8C,
|
||||||
|
"¡": 0x8D,
|
||||||
|
"¿": 0x8E,
|
||||||
|
"ª": 0x8F,
|
||||||
|
"♥": 0x90,
|
||||||
|
"★": 0x91,
|
||||||
|
"↑": 0x92,
|
||||||
|
"↓": 0x93,
|
||||||
|
"←": 0x94,
|
||||||
|
"→": 0x95,
|
||||||
|
"●": 0x96,
|
||||||
|
"✖": 0x97,
|
||||||
|
"“": 0xA2,
|
||||||
|
"”": 0xA3,
|
||||||
|
"‘": 0xA4,
|
||||||
|
"’": 0xA5,
|
||||||
|
" ": 0xF7,
|
||||||
|
"Ⓐ": [0xFF, 0x24, 0xFF, 0x05, 0x10, 0x98, 0xFF, 0x25],
|
||||||
|
"Ⓑ": [0xFF, 0x24, 0xFF, 0x05, 0x11, 0x99, 0xFF, 0x25],
|
||||||
|
"Ⓢ": [0xFF, 0x24, 0xFF, 0x05, 0x12, 0xA1, 0xFF, 0x25],
|
||||||
|
"▲": [0xFF, 0x24, 0xFF, 0x05, 0x13, 0x9D, 0xFF, 0x25],
|
||||||
|
"▼": [0xFF, 0x24, 0xFF, 0x05, 0x13, 0x9E, 0xFF, 0x25],
|
||||||
|
"◀": [0xFF, 0x24, 0xFF, 0x05, 0x13, 0x9F, 0xFF, 0x25],
|
||||||
|
"▶": [0xFF, 0x24, 0xFF, 0x05, 0x13, 0xA0, 0xFF, 0x25],
|
||||||
|
"Ⓛ": [0xFF, 0x24, 0xFF, 0x05, 0x14, 0x9A, 0xFF, 0x25],
|
||||||
|
"Ⓡ": [0xFF, 0x24, 0xFF, 0x05, 0x14, 0x9B, 0xFF, 0x25],
|
||||||
|
"Ⓩ": [0xFF, 0x24, 0xFF, 0x05, 0x14, 0x9C, 0xFF, 0x25],
|
||||||
|
}
|
||||||
|
|
||||||
|
CHARSET_CREDITS = {
|
||||||
|
"A": 0x00,
|
||||||
|
"B": 0x01,
|
||||||
|
"C": 0x02,
|
||||||
|
"D": 0x03,
|
||||||
|
"E": 0x04,
|
||||||
|
"F": 0x05,
|
||||||
|
"G": 0x06,
|
||||||
|
"H": 0x07,
|
||||||
|
"I": 0x08,
|
||||||
|
"J": 0x09,
|
||||||
|
"K": 0x0A,
|
||||||
|
"L": 0x0B,
|
||||||
|
"M": 0x0C,
|
||||||
|
"N": 0x0D,
|
||||||
|
"O": 0x0E,
|
||||||
|
"P": 0x0F,
|
||||||
|
"Q": 0x10,
|
||||||
|
"R": 0x11,
|
||||||
|
"S": 0x12,
|
||||||
|
"T": 0x13,
|
||||||
|
"U": 0x14,
|
||||||
|
"V": 0x15,
|
||||||
|
"W": 0x16,
|
||||||
|
"X": 0x17,
|
||||||
|
"Y": 0x18,
|
||||||
|
"Z": 0x19,
|
||||||
|
"'": 0x1A,
|
||||||
|
".": 0x1B,
|
||||||
|
",": 0x1C,
|
||||||
|
"0": 0x1D,
|
||||||
|
"1": 0x1E,
|
||||||
|
"2": 0x1F,
|
||||||
|
"3": 0x20,
|
||||||
|
"4": 0x21,
|
||||||
|
"5": 0x22,
|
||||||
|
"6": 0x23,
|
||||||
|
"7": 0x24,
|
||||||
|
"8": 0x25,
|
||||||
|
"9": 0x26,
|
||||||
|
"©": 0x27,
|
||||||
|
"&": 0x28,
|
||||||
|
" ": 0xF7,
|
||||||
|
}
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(argv) < 3:
|
||||||
|
print("usage: parse_compile.py [in.msg] [out.msgpack]")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
_, filename, outfile = argv
|
||||||
|
|
||||||
|
messages = []
|
||||||
|
|
||||||
|
message = None
|
||||||
|
with open(filename, "r") as f:
|
||||||
|
source = f.read()
|
||||||
|
lineno = 1
|
||||||
|
|
||||||
|
charset = CHARSET
|
||||||
|
font_stack = [0]
|
||||||
|
sound_stack = [0]
|
||||||
|
color_stack = [0x0A]
|
||||||
|
|
||||||
|
while len(source) > 0:
|
||||||
|
if source.startswith("\n"):
|
||||||
|
lineno += 1
|
||||||
|
source = source[1:]
|
||||||
|
continue
|
||||||
|
|
||||||
|
if message is None:
|
||||||
|
if source.startswith("//"):
|
||||||
|
while source[0] != "\n":
|
||||||
|
source = source[1:]
|
||||||
|
else:
|
||||||
|
command, positional_args, named_args, source = parse_command(source)
|
||||||
|
|
||||||
|
if not command:
|
||||||
|
print(f"{filename}:{lineno}: expected [message]")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
name = positional_args[0] if len(positional_args) > 0 else None
|
||||||
|
message = Message(name, named_args.get("section"), named_args.get("index"))
|
||||||
|
messages.append(message)
|
||||||
|
else:
|
||||||
|
command, positional_args, named_args, source = parse_command(source)
|
||||||
|
|
||||||
|
if command:
|
||||||
|
if command == "/message":
|
||||||
|
message.bytes += [0xFD]
|
||||||
|
|
||||||
|
# padding
|
||||||
|
while len(message.bytes) % 4 != 0:
|
||||||
|
message.bytes += [0x00]
|
||||||
|
|
||||||
|
message = None
|
||||||
|
elif command == "raw":
|
||||||
|
message.bytes += [*positional_args]
|
||||||
|
elif command == "func":
|
||||||
|
message.bytes += [0xFF, *positional_args]
|
||||||
|
elif command == "br":
|
||||||
|
message.bytes += [0xF0]
|
||||||
|
elif command == "prompt":
|
||||||
|
message.bytes += [0xF1]
|
||||||
|
elif command == "sleep":
|
||||||
|
if len(positional_args) == 0:
|
||||||
|
print(f"{filename}:{lineno}: {command} command requires a positional parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xF2, positional_args[0]]
|
||||||
|
elif command == "next":
|
||||||
|
message.bytes += [0xFB]
|
||||||
|
elif command == "color":
|
||||||
|
if "color" not in named_args:
|
||||||
|
print(f"{filename}:{lineno}: color command requires a 'color' parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
color = color_to_code(**named_args)
|
||||||
|
|
||||||
|
if color is None:
|
||||||
|
print(f"{filename}:{lineno}: unknown color combination {named_args}")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x05, color]
|
||||||
|
color_stack.append(color)
|
||||||
|
elif command == "/color":
|
||||||
|
color_stack.pop()
|
||||||
|
message.bytes += [0xFF, 0x05, color_stack[0]]
|
||||||
|
elif command == "style":
|
||||||
|
if "style" not in named_args:
|
||||||
|
print(f"{filename}:{lineno}: style command requires a 'style' parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFC]
|
||||||
|
|
||||||
|
style = named_args["style"]
|
||||||
|
if type(style) is int:
|
||||||
|
message.bytes += [style, *positional_args]
|
||||||
|
else:
|
||||||
|
if style == "right":
|
||||||
|
message.bytes += [0x01]
|
||||||
|
elif style == "left":
|
||||||
|
message.bytes += [0x02]
|
||||||
|
elif style == "center":
|
||||||
|
message.bytes += [0x03]
|
||||||
|
elif style == "tattle":
|
||||||
|
message.bytes += [0x04]
|
||||||
|
elif style == "choice":
|
||||||
|
if "w" not in named_args or "h" not in named_args or "x" not in named_args or "y" not in named_args:
|
||||||
|
print(f"{filename}:{lineno}: 'choice' style requires parameters: x, y, w, h")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0x05, named_args["x"], named_args["y"], named_args["w"], named_args["h"]]
|
||||||
|
elif style == "inspect":
|
||||||
|
message.bytes += [0x06]
|
||||||
|
elif style == "sign":
|
||||||
|
message.bytes += [0x07]
|
||||||
|
elif style == "lamppost":
|
||||||
|
message.bytes += [0x08]
|
||||||
|
elif style == "postcard":
|
||||||
|
message.bytes += [0x09]
|
||||||
|
elif style == "popup":
|
||||||
|
message.bytes += [0x0A]
|
||||||
|
elif style == "upgrade":
|
||||||
|
if "w" not in named_args or "h" not in named_args or "x" not in named_args or "y" not in named_args:
|
||||||
|
print(f"{filename}:{lineno}: 'upgrade' style requires parameters: x, y, w, h")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0x0C, named_args["w"], named_args["x"], named_args["h"], named_args["y"]]
|
||||||
|
elif style == "narrate":
|
||||||
|
message.bytes += [0x0D]
|
||||||
|
elif style == "epilogue":
|
||||||
|
message.bytes += [0x0E]
|
||||||
|
elif command == "font":
|
||||||
|
if "font" not in named_args:
|
||||||
|
print(f"{filename}:{lineno}: font command requires a 'font' parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
font = named_args["font"]
|
||||||
|
|
||||||
|
if font == "normal":
|
||||||
|
font = 0
|
||||||
|
elif font == "title":
|
||||||
|
font = 3
|
||||||
|
elif font == "subtitle":
|
||||||
|
font = 4
|
||||||
|
|
||||||
|
if type(font) is not int:
|
||||||
|
print(f"{filename}:{lineno}: unknown font '{font}'")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x00, font]
|
||||||
|
font_stack.append(font)
|
||||||
|
|
||||||
|
if font == 3 or font == 4:
|
||||||
|
charset = CHARSET_CREDITS
|
||||||
|
else:
|
||||||
|
charset = CHARSET
|
||||||
|
elif command == "/font":
|
||||||
|
font_stack.pop()
|
||||||
|
message.bytes += [0xFF, 0x00, font_stack[0]]
|
||||||
|
|
||||||
|
if font == 3 or font == 4:
|
||||||
|
charset = CHARSET_CREDITS
|
||||||
|
else:
|
||||||
|
charset = CHARSET
|
||||||
|
elif command == "noskip":
|
||||||
|
message.bytes += [0xFF, 0x07]
|
||||||
|
elif command == "/noskip":
|
||||||
|
message.bytes += [0xFF, 0x08]
|
||||||
|
elif command == "instant":
|
||||||
|
message.bytes += [0xFF, 0x09]
|
||||||
|
elif command == "/instant":
|
||||||
|
message.bytes += [0xFF, 0x0A]
|
||||||
|
elif command == "kerning":
|
||||||
|
if "kerning" not in named_args:
|
||||||
|
print(f"{filename}:{lineno}: kerning command requires a 'kerning' parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x0B, named_args["kerning"]]
|
||||||
|
elif command == "scroll":
|
||||||
|
if len(positional_args) == 0:
|
||||||
|
print(f"{filename}:{lineno}: scroll command requires a positional parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x0C, positional_args[0]]
|
||||||
|
elif command == "size":
|
||||||
|
if "x" not in named_args or "y" not in named_args:
|
||||||
|
print(f"{filename}:{lineno}: size command requires parameters: x, y")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x0D, named_args["x"], named_args["y"]]
|
||||||
|
elif command == "/size":
|
||||||
|
message.bytes += [0xFF, 0x0E]
|
||||||
|
elif command == "speed":
|
||||||
|
if "delay" not in named_args or "chars" not in named_args:
|
||||||
|
print(f"{filename}:{lineno}: speed command requires parameters: delay, chars")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x0F, named_args["delay"], named_args["chars"]]
|
||||||
|
elif command == "pos":
|
||||||
|
if "y" not in named_args:
|
||||||
|
print(f"{filename}:{lineno}: pos command requires parameter: y (x is optional)")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if "x" in named_args:
|
||||||
|
message.bytes += [0xFF, 0x10, named_args["x"], named_args["y"]]
|
||||||
|
else:
|
||||||
|
message.bytes += [0xFF, 0x11, named_args["y"]]
|
||||||
|
elif command == "indent":
|
||||||
|
if len(positional_args) == 0:
|
||||||
|
print(f"{filename}:{lineno}: indent command requires a positional parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x12, positional_args[0]]
|
||||||
|
elif command == "down":
|
||||||
|
if len(positional_args) == 0:
|
||||||
|
print(f"{filename}:{lineno}: down command requires a positional parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x13, positional_args[0]]
|
||||||
|
elif command == "up":
|
||||||
|
if len(positional_args) == 0:
|
||||||
|
print(f"{filename}:{lineno}: up command requires a positional parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x14, positional_args[0]]
|
||||||
|
elif command == "image":
|
||||||
|
if len(positional_args) == 1:
|
||||||
|
message.bytes += [0xFF, 0x15, positional_args[0]]
|
||||||
|
elif len(positional_args) == 7:
|
||||||
|
message.bytes += [0xFF, 0x18, *positional_args]
|
||||||
|
else:
|
||||||
|
print(f"{filename}:{lineno}: image command requires 1 or 7 positional parameters")
|
||||||
|
exit(1)
|
||||||
|
elif command == "sprite":
|
||||||
|
if len(positional_args) != 3:
|
||||||
|
print(f"{filename}:{lineno}: sprite command requires 3 positional parameters")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x16, *positional_args]
|
||||||
|
elif command == "item":
|
||||||
|
if len(positional_args) != 2:
|
||||||
|
print(f"{filename}:{lineno}: item command requires 2 positional parameters")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x17, *positional_args]
|
||||||
|
elif command == "cursor":
|
||||||
|
if len(positional_args) != 1:
|
||||||
|
print(f"{filename}:{lineno}: cursor command requires 1 positional parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x1E, *positional_args]
|
||||||
|
elif command == "option":
|
||||||
|
if len(positional_args) != 1:
|
||||||
|
print(f"{filename}:{lineno}: option command requires 1 positional parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x21, *positional_args]
|
||||||
|
elif command == "choice":
|
||||||
|
if len(positional_args) != 1:
|
||||||
|
print(f"{filename}:{lineno}: choice command requires 1 positional parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x1E, positional_args[0], 0xFF, 0x21, positional_args[0]]
|
||||||
|
elif command == "choicecount":
|
||||||
|
if "choicecount" not in named_args:
|
||||||
|
print(f"{filename}:{lineno}: choicecount command requires a 'choicecount' parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x1F, named_args["choicecount"]]
|
||||||
|
elif command == "cancel":
|
||||||
|
if "cancel" not in named_args:
|
||||||
|
print(f"{filename}:{lineno}: cancel command requires a 'cancel' parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x20, named_args["cancel"]]
|
||||||
|
elif command == "shaky":
|
||||||
|
message.bytes += [0xFF, 0x26, 0x00]
|
||||||
|
elif command == "/shaky":
|
||||||
|
message.bytes += [0xFF, 0x27, 0x00]
|
||||||
|
elif command == "wavy":
|
||||||
|
message.bytes += [0xFF, 0x26, 0x01]
|
||||||
|
elif command == "/wavy":
|
||||||
|
message.bytes += [0xFF, 0x27, 0x01]
|
||||||
|
elif command == "shaky":
|
||||||
|
if "opacity" in named_args:
|
||||||
|
print(f"{filename}:{lineno}: shaky command doesn't accept parameter 'fade' (hint: did you mean 'faded-shaky'?)")
|
||||||
|
exit(1)
|
||||||
|
message.bytes += [0xFF, 0x26, 0x00]
|
||||||
|
elif command == "/shaky":
|
||||||
|
message.bytes += [0xFF, 0x27, 0x00]
|
||||||
|
elif command == "noise":
|
||||||
|
message.bytes += [0xFF, 0x26, 0x03, named_args.get("fade", 3)]
|
||||||
|
elif command == "/noise":
|
||||||
|
message.bytes += [0xFF, 0x27, 0x03]
|
||||||
|
elif command == "faded-shaky":
|
||||||
|
message.bytes += [0xFF, 0x26, 0x05, named_args.get("fade", 5)]
|
||||||
|
elif command == "/faded-shaky":
|
||||||
|
message.bytes += [0xFF, 0x27, 0x05]
|
||||||
|
elif command == "fade":
|
||||||
|
message.bytes += [0xFF, 0x26, 0x07, named_args.get("fade", 7)]
|
||||||
|
elif command == "/fade":
|
||||||
|
message.bytes += [0xFF, 0x27, 0x07]
|
||||||
|
elif command == "shout" or command == "shrinking":
|
||||||
|
message.bytes += [0xFF, 0x26, 0x0A]
|
||||||
|
elif command == "/shout" or command == "/shrinking":
|
||||||
|
message.bytes += [0xFF, 0x27, 0x0A]
|
||||||
|
elif command == "whisper" or command == "growing":
|
||||||
|
message.bytes += [0xFF, 0x26, 0x0B]
|
||||||
|
elif command == "/whisper" or command == "/growing":
|
||||||
|
message.bytes += [0xFF, 0x27, 0x0B]
|
||||||
|
elif command == "scream" or command == "shaky-size":
|
||||||
|
message.bytes += [0xFF, 0x26, 0x0C]
|
||||||
|
elif command == "/scream" or command == "/shaky-size":
|
||||||
|
message.bytes += [0xFF, 0x27, 0x0C]
|
||||||
|
elif command == "chortle" or command == "wavy-size":
|
||||||
|
message.bytes += [0xFF, 0x26, 0x0D]
|
||||||
|
elif command == "/chortle" or command == "/wavy-size":
|
||||||
|
message.bytes += [0xFF, 0x27, 0x0D]
|
||||||
|
elif command == "shadow":
|
||||||
|
message.bytes += [0xFF, 0x26, 0x0E]
|
||||||
|
elif command == "/shadow":
|
||||||
|
message.bytes += [0xFF, 0x27, 0x0E]
|
||||||
|
elif command == "var":
|
||||||
|
if len(positional_args) != 1:
|
||||||
|
print(f"{filename}:{lineno}: var command requires 1 positional parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x28, *positional_args]
|
||||||
|
elif command == "center":
|
||||||
|
if len(positional_args) != 1:
|
||||||
|
print(f"{filename}:{lineno}: center command requires 1 positional parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x29, *positional_args]
|
||||||
|
elif command == "volume":
|
||||||
|
if "volume" not in named_args:
|
||||||
|
print(f"{filename}:{lineno}: volume command requires a 'volume' parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x2E, named_args["volume"]]
|
||||||
|
elif command == "sound":
|
||||||
|
if "sound" not in named_args:
|
||||||
|
print(f"{filename}:{lineno}: sound command requires a 'sound' parameter")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
sound = named_args["sound"]
|
||||||
|
|
||||||
|
if sound == "normal":
|
||||||
|
sound = 0
|
||||||
|
elif sound == "bowser":
|
||||||
|
sound = 1
|
||||||
|
elif sound == "spirit":
|
||||||
|
sound = 2
|
||||||
|
|
||||||
|
if type(sound) is not int:
|
||||||
|
print(f"{filename}:{lineno}: unknown sound '{sound}'")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
message.bytes += [0xFF, 0x2F, sound]
|
||||||
|
sound_stack.append(sound)
|
||||||
|
elif command == "/sound":
|
||||||
|
sound_stack.pop()
|
||||||
|
message.bytes += [0xFF, 0x2F, sound_stack[0]]
|
||||||
|
elif command == "a":
|
||||||
|
color_code = color_to_code(named_args.get("color", "blue"), named_args.get("ctx", "button"))
|
||||||
|
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x98, 0xFF, 0x25]
|
||||||
|
elif command == "b":
|
||||||
|
color_code = color_to_code(named_args.get("color", "green"), named_args.get("ctx", "button"))
|
||||||
|
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x99, 0xFF, 0x25]
|
||||||
|
elif command == "l":
|
||||||
|
color_code = color_to_code(named_args.get("color", "gray"), named_args.get("ctx", "button"))
|
||||||
|
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x9A, 0xFF, 0x25]
|
||||||
|
elif command == "r":
|
||||||
|
color_code = color_to_code(named_args.get("color", "gray"), named_args.get("ctx", "button"))
|
||||||
|
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x9B, 0xFF, 0x25]
|
||||||
|
elif command == "z":
|
||||||
|
color_code = color_to_code(named_args.get("color", "gray"), named_args.get("ctx", "button"))
|
||||||
|
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x9C, 0xFF, 0x25]
|
||||||
|
elif command == "c-up":
|
||||||
|
color_code = color_to_code(named_args.get("color", "yellow"), named_args.get("ctx", "button"))
|
||||||
|
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x9D, 0xFF, 0x25]
|
||||||
|
elif command == "c-down":
|
||||||
|
color_code = color_to_code(named_args.get("color", "yellow"), named_args.get("ctx", "button"))
|
||||||
|
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x9E, 0xFF, 0x25]
|
||||||
|
elif command == "c-left":
|
||||||
|
color_code = color_to_code(named_args.get("color", "yellow"), named_args.get("ctx", "button"))
|
||||||
|
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0x9F, 0xFF, 0x25]
|
||||||
|
elif command == "c-right":
|
||||||
|
color_code = color_to_code(named_args.get("color", "yellow"), named_args.get("ctx", "button"))
|
||||||
|
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0xA0, 0xFF, 0x25]
|
||||||
|
elif command == "start":
|
||||||
|
color_code = color_to_code(named_args.get("color", "red"), named_args.get("ctx", "button"))
|
||||||
|
message.bytes += [0xFF, 0x24, 0xFF, 0x05, color_code, 0xA1, 0xFF, 0x25]
|
||||||
|
elif command == "note":
|
||||||
|
message.bytes += [0x00]
|
||||||
|
elif command == "heart":
|
||||||
|
message.bytes += [0x90]
|
||||||
|
elif command == "star":
|
||||||
|
message.bytes += [0x91]
|
||||||
|
elif command == "arrow-up":
|
||||||
|
message.bytes += [0x92]
|
||||||
|
elif command == "arrow-down":
|
||||||
|
message.bytes += [0x93]
|
||||||
|
elif command == "arrow-left":
|
||||||
|
message.bytes += [0x94]
|
||||||
|
elif command == "arrow-right":
|
||||||
|
message.bytes += [0x95]
|
||||||
|
elif command == "circle":
|
||||||
|
message.bytes += [0x96]
|
||||||
|
elif command == "cross":
|
||||||
|
message.bytes += [0x97]
|
||||||
|
elif command == "wait":
|
||||||
|
print(f"{filename}:{lineno}: unknown command 'wait' (hint: did you mean 'prompt'?)")
|
||||||
|
exit(1)
|
||||||
|
elif command == "pause":
|
||||||
|
print(f"{filename}:{lineno}: unknown command 'pause' (hint: did you mean 'sleep'?)")
|
||||||
|
exit(1)
|
||||||
|
else:
|
||||||
|
print(f"{filename}:{lineno}: unknown command '{command}'")
|
||||||
|
exit(1)
|
||||||
|
else:
|
||||||
|
if source[0] == "\\":
|
||||||
|
source = source[1:]
|
||||||
|
|
||||||
|
if source[0] in charset:
|
||||||
|
data = charset[source[0]]
|
||||||
|
|
||||||
|
if type(data) is int:
|
||||||
|
message.bytes.append(data)
|
||||||
|
else:
|
||||||
|
message.bytes += data
|
||||||
|
|
||||||
|
source = source[1:]
|
||||||
|
else:
|
||||||
|
print(f"{filename}:{lineno}: unsupported character '{source[0]}' for current font")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if message != None:
|
||||||
|
print(f"{filename}: missing [/message]")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
with open(outfile, "wb") as f:
|
||||||
|
msgpack.pack([{
|
||||||
|
"section": message.section,
|
||||||
|
"index": message.index,
|
||||||
|
"name": message.name,
|
||||||
|
"bytes": bytes(message.bytes),
|
||||||
|
} for message in messages], f)
|
Loading…
Reference in New Issue
Block a user