papermario/tools/build/msg/parse_compile.py
AltoXorg 9b96f91dc6
JP pm_msg (#1135)
* implement jp msg

* replace

* .
2023-12-25 22:15:30 +09:00

2101 lines
72 KiB
Python
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env 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, *raw_args = inside_brackets.split(" ")
args = []
named_args = {}
for arg in raw_args:
if "=" in arg:
key, value = arg.split("=", 1)
if "," in value:
named_args[key.lower()] = [try_convert_int(v) for v in value.lower().split(",")]
else:
named_args[key.lower()] = try_convert_int(value.lower())
else:
if "," in arg:
args.append([try_convert_int(value) for value in arg.lower().split(",")])
else:
args.append(try_convert_int(arg.lower()))
# args = []
# for arg in raw_args:
# args.append(try_convert_int(arg.lower()))
return command.lower(), args, named_args, source
def color_to_code(color, style):
COLORS = {
"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(
style,
{
# [style:left], [style:right]
"normal": 0x0A,
"red": 0x20,
"pink": 0x21,
"purple": 0x22,
"blue": 0x23,
"cyan": 0x24,
"green": 0x25,
"yellow": 0x26,
},
).get(color)
CHARSET_STANDARD = {
# "𝅘𝅥𝅮": 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,
" ": 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,
" ": 0xF8,
}
CHARSET_KANA = {
"": 0x00,
"": 0x01,
"": 0x02,
"": 0x03,
"": 0x04,
"": 0x05,
"": 0x06,
"": 0x07,
"": 0x08,
"": 0x09,
"": 0x0A,
"": 0x0B,
"": 0x0C,
"": 0x0D,
"": 0x0E,
"": 0x0F,
"": 0x10,
"": 0x11,
"": 0x12,
"": 0x13,
"": 0x14,
"": 0x15,
"": 0x16,
"": 0x17,
"": 0x18,
"": 0x19,
"": 0x1A,
"": 0x1B,
"": 0x1C,
"": 0x1D,
"": 0x1E,
"": 0x1F,
"": 0x20,
"": 0x21,
"": 0x22,
"": 0x23,
"": 0x24,
"": 0x25,
"": 0x26,
"": 0x27,
"": 0x28,
"": 0x29,
"": 0x2A,
"": 0x2B,
"": 0x2C,
"": 0x2D,
"": 0x2E,
"": 0x2F,
"": 0x30,
"": 0x31,
"": 0x32,
"": 0x33,
"": 0x34,
"": 0x35,
"": 0x36,
"": 0x37,
"": 0x38,
"": 0x39,
"": 0x3A,
"": 0x3B,
"": 0x3C,
"": 0x3D,
"": 0x3E,
"": 0x3F,
"": 0x40,
"": 0x41,
"": 0x42,
"": 0x43,
"": 0x44,
"": 0x45,
"": 0x46,
"": 0x47,
"": 0x48,
"": 0x49,
"": 0x4A,
"": 0x4B,
"": 0x4C,
"": 0x4D,
"": 0x4E,
"": 0x4F,
"": 0x50,
"": 0x51,
"": 0x52,
"": 0x53,
"": 0x54,
"": 0x55,
"": 0x56,
"": 0x57,
"": 0x58,
"": 0x59,
"": 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,
"": 0x98,
"": 0x99,
"": 0x9A,
"": 0x9B,
"": 0x9C,
"": 0x9D,
"": 0x9E,
"": 0x9F,
"": 0xA0,
"": 0xA1,
"": 0xA2,
"": 0xA3,
"~": 0xA3,
# "―": 0xA4,
# "―": 0xA5,
# "―": 0xA6,
"": 0xA7,
"0": 0xA7,
"": 0xA8,
"1": 0xA8,
"": 0xA9,
"2": 0xA9,
"": 0xAA,
"3": 0xAA,
"": 0xAB,
"4": 0xAB,
"": 0xAC,
"5": 0xAC,
"": 0xAD,
"6": 0xAD,
"": 0xAE,
"7": 0xAE,
"": 0xAF,
"8": 0xAF,
"": 0xB0,
"9": 0xB0,
"[up]": 0xB1,
"[down]": 0xB2,
"[left]": 0xB3,
"[right]": 0xB4,
"": 0xB5,
"!": 0xB5,
"": 0xB6,
"?": 0xB6,
"": 0xB7,
"+": 0xB7,
"": 0xB8,
"": 0xB9,
"/": 0xB9,
"": 0xBA,
".": 0xBA,
"": 0xBB,
"&": 0xBB,
"": 0xBC,
"#": 0xBC,
"[heart]": 0xBD,
"[star]": 0xBE,
"": 0xBF,
"(": 0xBF,
"": 0xC0,
")": 0xC0,
"": 0xC1,
"": 0xC2,
"": 0xC3,
"[hiragana smalln]": 0xC4,
"[katakana smalln]": 0xC5,
"": 0xC6,
# 0xC7 is unused
" ": 0xF7,
" ": 0xF8,
}
CHARSET_LATIN = {
"A": 0x00,
"": 0x00,
"B": 0x01,
"": 0x01,
"C": 0x02,
"": 0x02,
"D": 0x03,
"": 0x03,
"E": 0x04,
"": 0x04,
"F": 0x05,
"": 0x05,
"G": 0x06,
"": 0x06,
"H": 0x07,
"": 0x07,
"I": 0x08,
"": 0x08,
"J": 0x09,
"": 0x09,
"K": 0x0A,
"": 0x0A,
"L": 0x0B,
"": 0x0B,
"M": 0x0C,
"": 0x0C,
"N": 0x0D,
"": 0x0D,
"O": 0x0E,
"": 0x0E,
"P": 0x0F,
"": 0x0F,
"Q": 0x10,
"": 0x10,
"R": 0x11,
"": 0x11,
"S": 0x12,
"": 0x12,
"T": 0x13,
"": 0x13,
"U": 0x14,
"": 0x14,
"V": 0x15,
"": 0x15,
"W": 0x16,
"": 0x16,
"X": 0x17,
"": 0x17,
"Y": 0x18,
"": 0x18,
"Z": 0x19,
"": 0x19,
"z": 0x1A,
"": 0x1A,
" ": 0xF7,
" ": 0xF8,
}
CHARSET_KANJI = {
"": 0x00,
"": 0x01,
"": 0x02,
"": 0x03,
"": 0x04,
"": 0x05,
"西": 0x06,
"": 0x07,
"": 0x08,
"": 0x09,
"": 0x0A,
"": 0x0B,
"": 0x0C,
"": 0x0D,
"": 0x0E,
"": 0x0F,
"": 0x10,
"": 0x11,
"": 0x12,
"": 0x13,
"": 0x14,
"": 0x15,
"": 0x16,
"": 0x17,
"": 0x18,
"": 0x19,
"": 0x1A,
"": 0x1B,
"": 0x1C,
"": 0x1D,
"": 0x1E,
"": 0x1F,
"": 0x20,
"": 0x21,
"": 0x22,
"": 0x23,
"": 0x24,
"": 0x25,
"": 0x26,
"": 0x27,
"": 0x28,
"": 0x29,
"": 0x2A,
"": 0x2B,
"": 0x2C,
"": 0x2D,
"": 0x2E,
"": 0x2F,
"": 0x30,
"": 0x31,
"": 0x32,
"": 0x33,
"": 0x34,
"": 0x35,
"": 0x36,
"": 0x37,
"": 0x38,
"": 0x39,
"": 0x3A,
"": 0x3B,
"": 0x3C,
"": 0x3D,
"": 0x3E,
"": 0x3F,
"使": 0x40,
"": 0x41,
"": 0x42,
"": 0x43,
"": 0x44,
"": 0x45,
"": 0x46,
"": 0x47,
"": 0x48,
"": 0x49,
"": 0x4A,
"": 0x4B,
"": 0x4C,
"": 0x4D,
"": 0x4E,
"": 0x4F,
"": 0x50,
"": 0x51,
"": 0x52,
"": 0x53,
"": 0x54,
"": 0x55,
"": 0x56,
"": 0x57,
"": 0x58,
"": 0x59,
"": 0x5A,
"": 0x5B,
"": 0x5C,
"": 0x5D,
"": 0x5E,
"": 0x5F,
"": 0x60,
"[circle]": 0x61,
"[cross]": 0x62,
"": 0x63,
"": 0x64,
"": 0x65,
"": 0x66,
"": 0x67,
"": 0x68,
"": 0x69,
"[note]": 0x6A,
"": 0x6B,
"": 0x6C,
"": 0x6D,
"": 0x6E,
"": 0x6F,
"": 0x70,
"": 0x71,
"": 0x72,
"": 0x73,
"": 0x74,
"": 0x75,
"": 0x76,
"": 0x77,
"": 0x78,
"x": 0x78,
" ": 0xF7,
" ": 0xF8,
}
CHARSET_BUTTONS = {
"[~a]": 0x00,
"[~b]": 0x01,
"[~start]": 0x02,
"[~c-up]": 0x03,
"[~c-down]": 0x04,
"[~c-left]": 0x05,
"[~c-right]": 0x06,
"[~z]": 0x07,
"[~l]": 0x08,
"[~r]": 0x09,
}
def check_if_correct_charset(char, cur_charset, filename, lineno):
warn_msg = f"{filename}:{lineno}: Warning: character '{char}' is present but is completely in a wrong charset currently set. Add {{}} before the character to silence this warning."
if char == " " or char == " ":
return -1, cur_charset
elif char in CHARSET_KANA and cur_charset is not CHARSET_KANA:
print(warn_msg.format("[Charset Kana]"))
return 0, CHARSET_KANA
elif char in CHARSET_LATIN and cur_charset is not CHARSET_LATIN:
print(warn_msg.format("[Charset Latin]"))
return 1, CHARSET_LATIN
elif char in CHARSET_KANJI and cur_charset is not CHARSET_KANJI:
print(warn_msg.format("[Charset Kanji]"))
return 2, CHARSET_KANJI
elif char in CHARSET_BUTTONS and cur_charset is not CHARSET_BUTTONS:
print(warn_msg.format("[Charset Buttons]"))
return 3, CHARSET_BUTTONS
return -1, cur_charset
def strip_c_comments(text):
def replacer(match):
s = match.group(0)
if s.startswith("/"):
return " "
else:
return s
pattern = re.compile(
r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
re.DOTALL | re.MULTILINE,
)
return re.sub(pattern, replacer, text)
if __name__ == "__main__":
if len(argv) < 3:
print("usage: parse_compile.py [version] [in.msg] [out.msgpack] [--c]")
exit(1)
version = argv[1]
filename = argv[2]
outfile = argv[3]
is_output_format_c = "--c" in argv
messages = []
message = None
with open(filename, "r") as f:
source = strip_c_comments(f.read())
lineno = 1
directive = ""
indent_level = 0
if version == "jp":
charset = CHARSET_KANA
else:
charset = CHARSET_STANDARD
font_stack = [0]
sound_stack = [0]
color_stack = [0x0A]
fx_stack = []
style = None
explicit_end = False
choiceindex = -1
while len(source) > 0:
if source[0] == "\r" or source[0] == "\t":
source = source[1:]
continue
if source[0] == "\n":
lineno += 1
source = source[1:]
for i in range(indent_level):
if source[0] == "\t":
source = source[1:]
else:
break
continue
if message is None:
directive = ""
while source[0] != " ":
if source[0] == "\n":
lineno += 1
elif source[0] == "\r":
pass
else:
directive += source[0]
source = source[1:]
directive = directive.split(":")
if directive[0] != "#message":
print(f"{filename}:{lineno}: expected #message directive")
exit(1)
if is_output_format_c:
if len(directive) != 2:
print(f"{filename}:{lineno}: expected #message:NAME directive")
exit(1)
message = Message(directive[1], None, None)
else:
if len(directive) != 3:
print(f"{filename}:{lineno}: expected #message:SECTION:INDEX directive")
exit(1)
section = int(directive[1], 16)
if directive[2].startswith("(") and directive[2].endswith(")"):
name = directive[2][1:-1]
index = None
else:
name = None
index = int(directive[2], 16)
directive = ""
message = Message(name, section, index)
messages.append(message)
if version == "jp":
charset = CHARSET_KANA
else:
charset = CHARSET_STANDARD
while source[0] != "{":
source = source[1:]
if source[0] == "\n":
lineno += 1
elif source[0] == "\r":
pass
elif source[0] == "{":
break
elif source[0] != " " and source[0] != "\t":
print(f"{filename}:{lineno}: expected opening brace ('{{')")
exit(1)
source = source[1:] # {
# count indent level
indent_level = 0
"""
while source[0] == " " or source[0] == "\t" or source[0] == "\n" or source[0] == "\r":
if source[0] == " " or source[0] == "\t":
indent_level += 1
source = source[1:]
"""
else:
command, args, named_args, source = parse_command(source)
if command:
if command == "end":
message.bytes += [0xFD]
explicit_end = True
elif command == "raw":
message.bytes += [*args]
elif command == "br":
message.bytes += [0xF0]
elif command == "wait":
message.bytes += [0xF1]
elif command == "pause":
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
message.bytes += [0xF2, args[0]]
elif command == "next":
message.bytes += [0xFB]
elif command == "yield":
message.bytes += [0xFF, 0x04]
elif command == "savecolor":
message.bytes += [0xFF, 0x24]
elif command == "restorecolor":
message.bytes += [0xFF, 0x25]
elif command == "color":
if len(args) != 1:
print(f"{filename}:{lineno}: color command requires 1 parameter")
exit(1)
color = color_to_code(args[0], style)
if color is None:
print(f"{filename}:{lineno}: unknown color")
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":
message.bytes += [0xFC]
style = args[0]
args = args[1:]
if type(style) is int:
message.bytes += [style, *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":
pos = named_args.get("pos")
if not isinstance(pos, list) or len(pos) != 2:
print(f"{filename}:{lineno}: 'choice' style requires pos=_,_")
exit(1)
size = named_args.get("size")
if not isinstance(size, list) or len(size) != 2:
print(f"{filename}:{lineno}: 'choice' style requires size=_,_")
exit(1)
message.bytes += [
0x05,
pos[0],
pos[1],
size[0],
size[1],
]
elif style == "inspect":
message.bytes += [0x06]
elif style == "sign":
message.bytes += [0x07]
elif style == "lamppost":
height = named_args.get("height")
if not isinstance(height, int):
print(f"{filename}:{lineno}: 'lamppost' style requires height=_")
exit(1)
message.bytes += [0x08, height]
elif style == "postcard":
index = named_args.get("index")
if not isinstance(index, int):
print(f"{filename}:{lineno}: 'postcard' style requires index=_")
exit(1)
message.bytes += [0x09, index]
elif style == "popup":
message.bytes += [0x0A]
elif style == "popup2":
message.bytes += [0x0B]
elif style == "upgrade":
pos = named_args.get("pos")
if not isinstance(pos, list) or len(pos) != 2:
print(f"{filename}:{lineno}: 'upgrade' style requires pos=_,_")
exit(1)
size = named_args.get("size")
if not isinstance(size, list) or len(size) != 2:
print(f"{filename}:{lineno}: 'upgrade' style requires size=_,_")
exit(1)
message.bytes += [
0x0C,
pos[0],
pos[1],
size[0],
size[1],
]
elif style == "narrate":
message.bytes += [0x0D]
elif style == "epilogue":
message.bytes += [0x0E]
elif command == "font":
if len(args) != 1:
print(f"{filename}:{lineno}: font command requires 1 parameter")
exit(1)
font = args[0]
if font == "standard":
font = 0
elif font == "menu":
font = 1
elif font == "menu2":
font = 2
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:
if version == "jp":
charset = CHARSET_KANA
else:
charset = CHARSET_STANDARD
# 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 == "charset":
if version != "jp":
print(f"{filename}:{lineno}: charset command is only supported in the JP version")
exit(1)
if len(args) != 1:
print(f"{filename}:{lineno}: charset command requires 1 parameter")
exit(1)
arg_charset = args[0]
if arg_charset == "kana":
arg_charset = 0
elif arg_charset == "latin":
arg_charset = 1
elif arg_charset == "kanji":
arg_charset = 2
elif arg_charset == "buttons":
arg_charset = 3
if type(arg_charset) is not int:
print(f"{filename}:{lineno}: unknown charset '{arg_charset}'")
exit(1)
message.bytes += [0xF3 + arg_charset]
if arg_charset == 0:
charset = CHARSET_KANA
elif arg_charset == 1:
charset = CHARSET_LATIN
elif arg_charset == 2:
charset = CHARSET_KANJI
elif arg_charset == 3:
charset = CHARSET_BUTTONS
elif command == "inputoff":
message.bytes += [0xFF, 0x07]
elif command == "inputon":
message.bytes += [0xFF, 0x08]
elif command == "delayoff":
message.bytes += [0xFF, 0x09]
elif command == "delayon":
message.bytes += [0xFF, 0x0A]
elif command == "charwidth":
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
message.bytes += [0xFF, 0x0B, args[0]]
elif command == "scroll":
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
message.bytes += [0xFF, 0x0C, args[0]]
elif command == "size":
args = args[0]
if len(args) == 1:
args.append(args[0])
if len(args) != 2:
print(f"{filename}:{lineno}: {command} command requires 2 parameters")
exit(1)
message.bytes += [0xFF, 0x0D, args[0], args[1]]
elif command == "sizereset":
message.bytes += [0xFF, 0x0E]
elif command == "speed":
delay = named_args.get("delay")
if not isinstance(delay, int):
print(f"{filename}:{lineno}: {command} command requires delay=_")
exit(1)
chars = named_args.get("chars")
if not isinstance(delay, int):
print(f"{filename}:{lineno}: {command} command requires chars=_")
exit(1)
message.bytes += [0xFF, 0x0F, delay, 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 == "setposx":
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
message.bytes += [0xFF, 0x10, args[0] >> 8, args[0] & 0xFF]
elif command == "setposy":
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
message.bytes += [0xFF, 0x11, *args]
elif command == "right":
if len(args) == 0:
if version == "jp":
charset_byte, charset = check_if_correct_charset("[right]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0xB4]
else:
message.bytes += [0x95]
else:
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
message.bytes += [0xFF, 0x12, args[0]]
elif command == "down":
if len(args) == 0:
if version == "jp":
charset_byte, charset = check_if_correct_charset("[down]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0xB2]
else:
message.bytes += [0x93]
else:
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
message.bytes += [0xFF, 0x13, args[0]]
elif command == "up":
if len(args) == 0:
if version == "jp":
charset_byte, charset = check_if_correct_charset("[up]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0xB1]
else:
message.bytes += [0x92]
else:
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
message.bytes += [0xFF, 0x14, args[0]]
elif command == "inlineimage":
index = named_args.get("index")
if not isinstance(index, int):
print(f"{filename}:{lineno}: {command} command requires index=_")
exit(1)
message.bytes += [0xFF, 0x15, index]
elif command == "animsprite":
spriteid = named_args.get("spriteid")
raster = named_args.get("raster")
# TODO: named sprite id and raster
if not isinstance(spriteid, int):
print(f"{filename}:{lineno}: {command} command requires spriteid=_")
exit(1)
if not isinstance(raster, int):
print(f"{filename}:{lineno}: {command} command requires raster=_")
exit(1)
message.bytes += [
0xFF,
0x16,
spriteid >> 8,
spriteid & 0xFF,
raster,
]
elif command == "itemicon":
itemid = named_args.get("itemid")
# TODO: itemname
if not isinstance(itemid, int):
print(f"{filename}:{lineno}: {command} command requires itemid=_")
exit(1)
message.bytes += [0xFF, 0x17, itemid >> 8, itemid & 0xFF]
elif command == "image":
index = named_args.get("index")
pos = named_args.get("pos") # xx,y
hasborder = named_args.get("hasborder")
alpha = named_args.get("alpha")
fadeamount = named_args.get("fadeamount")
if not isinstance(index, int):
print(f"{filename}:{lineno}: {command} command requires index=_")
exit(1)
if not isinstance(pos, list) or len(pos) != 2:
print(f"{filename}:{lineno}: {command} command requires pos=_,_")
exit(1)
if not isinstance(hasborder, int):
print(f"{filename}:{lineno}: {command} command requires hasborder=_")
exit(1)
if not isinstance(alpha, int):
print(f"{filename}:{lineno}: {command} command requires alpha=_")
exit(1)
if not isinstance(fadeamount, int):
print(f"{filename}:{lineno}: {command} command requires fadeamount=_")
exit(1)
message.bytes += [
0xFF,
0x18,
index,
pos[0] >> 8,
pos[0] & 0xFF,
pos[1],
hasborder,
alpha,
fadeamount,
]
elif command == "hideimage":
fadeamount = named_args.get("fadeamount", 0)
if not isinstance(fadeamount, int):
print(f"{filename}:{lineno}: {command} command requires fadeamount=_")
exit(1)
message.bytes += [0xFF, 0x19, fadeamount]
elif command == "animdelay":
index = named_args.get("index")
delay = named_args.get("delay")
if not isinstance(index, int):
print(f"{filename}:{lineno}: {command} command requires index=_")
exit(1)
if not isinstance(delay, int):
print(f"{filename}:{lineno}: {command} command requires delay=_")
exit(1)
message.bytes += [0xFF, 0x1A, 0, index, delay]
elif command == "animloop":
if len(args) != 2:
print(f"{filename}:{lineno}: {command} command requires 2 parameters")
exit(1)
message.bytes += [0xFF, 0x1B, args[0], args[1]]
elif command == "animdone":
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
message.bytes += [0xFF, 0x1C, args[0]]
elif command == "setcursorpos":
index = named_args.get("index")
pos = named_args.get("pos")
if not isinstance(index, int):
print(f"{filename}:{lineno}: {command} command requires index=_")
exit(1)
if not isinstance(pos, list) or len(pos) != 2:
print(f"{filename}:{lineno}: {command} command requires pos=_,_")
exit(1)
message.bytes += [0xFF, 0x1D, index, pos, pos]
elif command == "cursor":
if len(args) != 1:
print(f"{filename}:{lineno}: cursor command requires 1 parameter")
exit(1)
message.bytes += [0xFF, 0x1E, *args]
elif command == "option" and choiceindex == -1:
if len(args) != 1:
print(f"{filename}:{lineno}: option command requires 1 parameter")
exit(1)
message.bytes += [0xFF, 0x21, *args]
elif command == "endchoice" and choiceindex == -1:
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
message.bytes += [0xFF, 0x1F, args[0]]
elif command == "setcancel":
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
message.bytes += [0xFF, 0x20, args[0]]
# elif command == "startfx":
# message.bytes += [0xFF, 0x26, resolve_effect(args[0]), *args[1:]]
# elif command == "endfx":
# message.bytes += [0xFF, 0x27, resolve_effect(args[0]), *args[1:]]
elif command == "/fx":
message.bytes += [0xFF, 0x27, fx_stack.pop()]
elif command == "shake":
fx_stack.append(0x00)
message.bytes += [0xFF, 0x26, 0x00]
elif command == "/shake":
fx_stack.pop()
message.bytes += [0xFF, 0x27, 0x00]
elif command == "wave":
fx_stack.append(0x01)
message.bytes += [0xFF, 0x26, 0x01]
elif command == "/wave":
fx_stack.pop()
message.bytes += [0xFF, 0x27, 0x01]
elif command == "noiseoutline":
fx_stack.append(0x02)
message.bytes += [0xFF, 0x26, 0x02]
elif command == "/noiseoutline":
fx_stack.pop()
message.bytes += [0xFF, 0x27, 0x02]
elif command == "static":
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
fx_stack.append(0x03)
message.bytes += [0xFF, 0x26, 0x03, args[0]]
elif command == "/static":
fx_stack.pop()
message.bytes += [0xFF, 0x27, 0x03]
elif command == "blur":
_dir = named_args.get("dir")
if _dir == "x":
_dir = 0
elif _dir == "y":
_dir = 1
elif _dir == "xy":
_dir = 2
if not isinstance(_dir, int):
print(f"{filename}:{lineno}: {command} command requires dir=_")
exit(1)
fx_stack.append(0x05)
message.bytes += [0xFF, 0x26, 0x05, _dir]
elif command == "/blur":
fx_stack.pop()
message.bytes += [0xFF, 0x27, 0x05]
elif command == "rainbow":
fx_stack.append(0x06)
message.bytes += [0xFF, 0x26, 0x06]
elif command == "/rainbow":
fx_stack.pop()
message.bytes += [0xFF, 0x27, 0x06]
elif command == "ditherfade":
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
fx_stack.append(0x07)
message.bytes += [0xFF, 0x26, 0x07, args[0]]
elif command == "/ditherfade":
fx_stack.pop()
message.bytes += [0xFF, 0x27, 0x07]
elif command == "printrising":
fx_stack.append(0x0A)
message.bytes += [0xFF, 0x26, 0x0A]
elif command == "/printrising":
fx_stack.pop()
message.bytes += [0xFF, 0x27, 0x0A]
elif command == "printgrowing":
fx_stack.append(0x0B)
message.bytes += [0xFF, 0x26, 0x0B]
elif command == "/printgrowing":
fx_stack.pop()
message.bytes += [0xFF, 0x27, 0x0B]
elif command == "sizejitter":
fx_stack.append(0x0C)
message.bytes += [0xFF, 0x26, 0x0C]
elif command == "/sizejitter":
fx_stack.pop()
message.bytes += [0xFF, 0x27, 0x0C]
elif command == "sizewave":
fx_stack.append(0x0D)
message.bytes += [0xFF, 0x26, 0x0D]
elif command == "/sizewave":
fx_stack.pop()
message.bytes += [0xFF, 0x27, 0x0D]
elif command == "dropshadow":
fx_stack.append(0x0E)
message.bytes += [0xFF, 0x26, 0x0E]
elif command == "/dropshadow":
fx_stack.pop()
message.bytes += [0xFF, 0x27, 0x0E]
elif command == "var":
if len(args) != 1:
print(f"{filename}:{lineno}: var command requires 1 parameter")
exit(1)
message.bytes += [0xFF, 0x28, *args]
elif command == "centerx":
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
message.bytes += [0xFF, 0x29, *args]
elif command == "rewindoff":
message.bytes += [0xFF, 0x2A, 0]
elif command == "rewindon":
message.bytes += [0xFF, 0x2A, 1]
elif command == "customvoice":
soundids = named_args.get("soundids")
if not isinstance(soundids, list) or len(pos) != 2:
print(f"{filename}:{lineno}: {command} command requires soundids=_,_")
exit(1)
message.bytes += [
0xFF,
0x2C,
soundids[0] >> 24,
(soundids[0] >> 16) & 0xFF,
(soundids[0] >> 8) & 0xFF,
soundids[0] & 0xFF,
soundids[1] >> 24,
(soundids[1] >> 16) & 0xFF,
(soundids[1] >> 8) & 0xFF,
soundids[1] & 0xFF,
]
elif command == "volume":
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
message.bytes += [0xFF, 0x2E, *args]
elif command == "voice":
if len(args) != 1:
print(f"{filename}:{lineno}: {command} command requires 1 parameter")
exit(1)
sound = args[0]
if sound == "normal":
sound = 0
elif sound == "bowser":
sound = 1
elif sound == "star" or sound == "spirit":
sound = 2
if type(sound) is not int:
print(f"{filename}:{lineno}: unknown voice '{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("blue", "button")
assert color_code is not None
if version == "jp":
message.bytes += [
0xFF,
0x24,
0xFF,
0x05,
color_code,
0xF6,
0x00,
0xFF,
0x25,
]
else:
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"),
)
assert color_code is not None
if version == "jp":
message.bytes += [
0xFF,
0x24,
0xFF,
0x05,
color_code,
0xF6,
0x01,
0xFF,
0x25,
]
else:
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"),
)
assert color_code is not None
if version == "jp":
message.bytes += [
0xFF,
0x24,
0xFF,
0x05,
color_code,
0xF6,
0x08,
0xFF,
0x25,
]
else:
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"),
)
assert color_code is not None
if version == "jp":
message.bytes += [
0xFF,
0x24,
0xFF,
0x05,
color_code,
0xF6,
0x09,
0xFF,
0x25,
]
else:
message.bytes += [
0xFF,
0x24,
0xFF,
0x05,
color_code,
0x9B,
0xFF,
0x25,
]
elif command == "z":
color_code = color_to_code("grey", "button")
assert color_code is not None
if version == "jp":
message.bytes += [
0xFF,
0x24,
0xFF,
0x05,
color_code,
0xF6,
0x07,
0xFF,
0x25,
]
else:
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"),
)
assert color_code is not None
if version == "jp":
message.bytes += [
0xFF,
0x24,
0xFF,
0x05,
color_code,
0xF6,
0x03,
0xFF,
0x25,
]
else:
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"),
)
assert color_code is not None
if version == "jp":
message.bytes += [
0xFF,
0x24,
0xFF,
0x05,
color_code,
0xF6,
0x04,
0xFF,
0x25,
]
else:
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"),
)
assert color_code is not None
if version == "jp":
message.bytes += [
0xFF,
0x24,
0xFF,
0x05,
color_code,
0xF6,
0x05,
0xFF,
0x25,
]
else:
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"),
)
assert color_code is not None
if version == "jp":
message.bytes += [
0xFF,
0x24,
0xFF,
0x05,
color_code,
0xF6,
0x06,
0xFF,
0x25,
]
else:
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"),
) #
assert color_code is not None
if version == "jp":
message.bytes += [
0xFF,
0x24,
0xFF,
0x05,
color_code,
0xF6,
0x02,
0xFF,
0x25,
]
else:
message.bytes += [
0xFF,
0x24,
0xFF,
0x05,
color_code,
0xA1,
0xFF,
0x25,
]
elif command == "~a":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[~a]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0x00]
else:
message.bytes += [0x98]
elif command == "~b":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[~b]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0x01]
else:
message.bytes += [0x99]
elif command == "~l":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[~l]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0x08]
else:
message.bytes += [0x9A]
elif command == "~r":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[~r]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0x09]
else:
message.bytes += [0x9B]
elif command == "~z":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[~z]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0x07]
else:
message.bytes += [0x9C]
elif command == "~c-up":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[~c-up]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0x03]
else:
message.bytes += [0x9D]
elif command == "~c-down":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[~c-down]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0x04]
else:
message.bytes += [0x9E]
elif command == "~c-left":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[~c-left]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0x05]
else:
message.bytes += [0x9F]
elif command == "~c-right":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[~c-right]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0x06]
else:
message.bytes += [0xA0]
elif command == "~start":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[~start]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0x02]
else:
message.bytes += [0xA1]
elif command == "note":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[note]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0x6A]
else:
message.bytes += [0x00]
elif command == "heart":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[heart]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0xBD]
else:
message.bytes += [0x90]
elif command == "star":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[star]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0xBE]
else:
message.bytes += [0x91]
elif command == "left":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[left]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0xB3]
else:
message.bytes += [0x94]
elif command == "circle":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[circle]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0x61]
else:
message.bytes += [0x96]
elif command == "cross":
if version == "jp":
charset_byte, charset = check_if_correct_charset("[cross]", charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0x62]
else:
message.bytes += [0x97]
elif command == "katakana":
if version != "jp":
print(f"{filename}:{lineno}: Command katakana is only supported in the JP version")
exit(1)
kana_char = args[0]
if kana_char == "smalln":
charset_byte, charset = check_if_correct_charset(
"[katakana smalln]", charset, filename, lineno
)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0xC5]
else:
print(f"{filename}:{lineno}: Invalid or unimplemented katakana character name {kana_char}")
exit(1)
elif command == "hiragana":
if version != "jp":
print(f"{filename}:{lineno}: Command hiragana is only supported in the JP version")
exit(1)
kana_char = args[0]
if kana_char == "smalln":
charset_byte, charset = check_if_correct_charset(
"[hiragana smalln]", charset, filename, lineno
)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
message.bytes += [0xC4]
else:
print(f"{filename}:{lineno}: Invalid or unimplemented hiragana character name {kana_char}")
exit(1)
elif command == "fullspace":
message.bytes += [0xF8]
elif command == "halfspace":
message.bytes += [0xF9]
elif command == "savepos":
message.bytes += [0xFF, 0x22]
elif command == "restorepos":
message.bytes += [0xFF, 0x23]
elif command == "enablecdownnext":
message.bytes += [0xFF, 0x2B]
elif command == "beginchoice":
choiceindex = 0
message.bytes += [0xFF, 0x09] # delayoff
elif command == "option" and choiceindex >= 0:
message.bytes += [0xFF, 0x1E, choiceindex] # cursor n
message.bytes += [0xFF, 0x21, choiceindex] # option n
choiceindex += 1
elif command == "endchoice" and choiceindex >= 0:
cancel = named_args.get("cancel")
message.bytes += [0xFF, 0x21, 255] # option 255
message.bytes += [0xFF, 0x0A] # delayon
if isinstance(cancel, int):
message.bytes += [0xFF, 0x20, cancel] # setcancel n
message.bytes += [0xFF, 0x1F, choiceindex] # endchoice n
choiceindex = -1
elif command == "animation" and choiceindex >= 0:
# TODO
print(f"{filename}:{lineno}: '{command}' tag is not yet implemented")
exit(1)
else:
print(f"{filename}:{lineno}: unknown command '{command}'")
exit(1)
else:
if source[0] == "}":
if not explicit_end:
print(f"{filename}:{lineno}: warning: string lacks an [end] command")
# message.bytes += [0xFD]
explicit_end = False
# sanity check
for b in message.bytes:
if not isinstance(b, int):
print(b)
# padding
while len(message.bytes) % 4 != 0:
message.bytes += [0x00]
message = None
source = source[1:] # }
indent_level = 0
choiceindex = -1
continue
if source[0] == "\\":
source = source[1:]
if version == "jp" and charset is not CHARSET_CREDITS:
charset_byte, charset = check_if_correct_charset(source[0], charset, filename, lineno)
if charset_byte != -1:
message.bytes += [0xF3 + charset_byte]
elif (
source[0] not in CHARSET_KANA
and source[0] not in CHARSET_LATIN
and source[0] not in CHARSET_KANJI
and source[0] not in CHARSET_BUTTONS
):
print(f"{filename}:{lineno}: unsupported character '{source[0]}' for current font")
exit(1)
data = charset[source[0]]
if type(data) is int:
message.bytes.append(data)
else:
message.bytes += data
source = source[1:]
else:
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 [end]")
exit(1)
if is_output_format_c:
with open(outfile, "w") as f:
f.write(f"#include <ultra64.h>\n")
for message in messages:
f.write(f"static s8 {message.name}[] = {{\n")
for b in message.bytes:
f.write(f"0x{b:02X},")
f.write(f"\n}};\n")
else:
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,
)