diff --git a/tools/msg/parse_compile.py b/tools/msg/parse_compile.py index 5cd2c786e1..48afb26e90 100755 --- a/tools/msg/parse_compile.py +++ b/tools/msg/parse_compile.py @@ -21,21 +21,22 @@ def try_convert_int(s): def parse_command(source): if source[0] != "[": - return None, [], {}, source + return None, [], source source = source[1:] # "[" inside_brackets = "" while source[0] != "]": if source[0] == "\n": - return None, [], {}, source + return None, [], source inside_brackets += source[0] source = source[1:] source = source[1:] # "]" - command, *args = inside_brackets.split(" ") + command, *raw_args = inside_brackets.split(":") - positional_args = [] + """ + args = [] named_args = {} if "=" in command: @@ -48,22 +49,18 @@ def parse_command(source): key, value = arg.split("=", 1) named_args[key.lower()] = try_convert_int(value.lower()) else: - positional_args.append(try_convert_int(arg)) + args.append(try_convert_int(arg)) + """ - return command.lower(), positional_args, named_args, source + args = [] + for arg in raw_args: + args.append(try_convert_int(arg.lower())) -def color_to_code(color, ctx="normal"): + return command.lower(), args, source + +def color_to_code(color, style): + """ COLORS = { - "normal": { - "normal": 0x0A, - "red": 0x20, - "pink": 0x21, - "purple": 0x22, - "blue": 0x23, - "cyan": 0x24, - "green": 0x25, - "yellow": 0x26, - }, "diary": { "normal": 0x00, "red": 0x07, @@ -96,14 +93,50 @@ def color_to_code(color, ctx="normal"): "green": 0x1B, } } + """ + COLORS = {} if type(color) is int: return color - return COLORS.get(ctx, {}).get(color) + return COLORS.get(ctx, { + # [style:left], [style:right] + "normal": 0x0A, + "red": 0x20, + "pink": 0x21, + "purple": 0x22, + "blue": 0x23, + "cyan": 0x24, + "green": 0x25, + "yellow": 0x26, + }).get(color) + +def resolve_effect(fx): + if type(fx) is int: + return fx + + FX = { + "jitter": 0x00, + "wavy": 0x01, + "noise": 0x02, + "fadednoise": 0x03, # 1 arg + "unknown": 0x04, + "fadedjitter": 0x05, # 1 arg + "rainbow": 0x06, + "faded": 0x07, # 1 arg + "wavyb": 0x08, + "rainbowb": 0x09, + "shrinking": 0x0a, + "growing": 0x0b, + "sizejitter": 0x0c, + "sizewave": 0x0d, + "dropshadow": 0x0e, + } + + return FX.get(fx) CHARSET = { - "๐… ": 0x00, + #"๐… ": 0x00, "!": 0x01, '"': 0x02, "#": 0x03, @@ -247,29 +280,29 @@ CHARSET = { "ยก": 0x8D, "ยฟ": 0x8E, "ยช": 0x8F, - "โ™ฅ": 0x90, - "โ˜…": 0x91, - "โ†‘": 0x92, - "โ†“": 0x93, - "โ†": 0x94, - "โ†’": 0x95, - "โ—": 0x96, - "โœ–": 0x97, + # "โ™ฅ": 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], + # "โ’ถ": [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 = { @@ -317,6 +350,19 @@ CHARSET_CREDITS = { " ": 0xF7, } +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 [in.msg] [out.msgpack]") @@ -328,88 +374,144 @@ if __name__ == "__main__": message = None with open(filename, "r") as f: - source = f.read() + source = strip_c_comments(f.read()) lineno = 1 + directive = "" + indent_level = 0 + charset = CHARSET font_stack = [0] sound_stack = [0] color_stack = [0x0A] + style = None + explicit_end = False while len(source) > 0: - if source.startswith("\n"): - lineno += 1 + if source[0] == "\r": 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 source[0] == "\n": + lineno += 1 + source = source[1:] - if not command: - print(f"{filename}:{lineno}: expected [message]") + for i in range(indent_level): + if source[0] == " " or 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" or 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) + + 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) - 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) + 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:] + + # TODO: lookahead at all lines until "}" to determine lowest indent value + if indent_level == 4: + break else: - command, positional_args, named_args, source = parse_command(source) + command, args, source = parse_command(source) if command: - if command == "/message": + if command == "end": message.bytes += [0xFD] - - # padding - while len(message.bytes) % 4 != 0: - message.bytes += [0x00] - - message = None + explicit_end = True elif command == "raw": - message.bytes += [*positional_args] - elif command == "func": - message.bytes += [0xFF, *positional_args] + message.bytes += [*args] + #elif command == "func": + # message.bytes += [0xFF, *args] elif command == "br": message.bytes += [0xF0] - elif command == "prompt": + elif command == "wait": message.bytes += [0xF1] - elif command == "sleep": - if len(positional_args) == 0: - print(f"{filename}:{lineno}: {command} command requires a positional parameter") + elif command == "pause": + if len(args) != 1: + print(f"{filename}:{lineno}: {command} command requires 1 parameter") exit(1) - message.bytes += [0xF2, positional_args[0]] + message.bytes += [0xF2, args[0]] elif command == "next": message.bytes += [0xFB] + elif command == "func_04": + message.bytes += [0xFF, 0x04] + elif command == "pushcolor": + message.bytes += [0xFF, 0x24] + elif command == "popcolor": + message.bytes += [0xFF, 0x25] elif command == "color": - if "color" not in named_args: - print(f"{filename}:{lineno}: color command requires a 'color' parameter") + if len(args) != 1: + print(f"{filename}:{lineno}: color command requires 1 parameter") exit(1) - color = color_to_code(**named_args) + color = color_to_code(args[0], style) if color is None: - print(f"{filename}:{lineno}: unknown color combination {named_args}") + 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 == "/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"] + style = args[0] + args = args[1:] if type(style) is int: - message.bytes += [style, *positional_args] + message.bytes += [style, *args] else: if style == "right": message.bytes += [0x01] @@ -420,37 +522,45 @@ if __name__ == "__main__": 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") + if len(args) != 4: + print(f"{filename}:{lineno}: 'choice' style requires 4 parameters") exit(1) - message.bytes += [0x05, named_args["x"], named_args["y"], named_args["w"], named_args["h"]] + message.bytes += [0x05, *args] elif style == "inspect": message.bytes += [0x06] elif style == "sign": message.bytes += [0x07] elif style == "lamppost": - message.bytes += [0x08] + if len(args) != 1: + print(f"{filename}:{lineno}: 'lamppost' style requires 1 parameter") + exit(1) + + message.bytes += [0x08, args[0]] elif style == "postcard": - message.bytes += [0x09] + if len(args) != 1: + print(f"{filename}:{lineno}: 'lamppost' style requires 1 parameter") + exit(1) + + message.bytes += [0x09, args[0]] 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") + if len(args) != 4: + print(f"{filename}:{lineno}: 'upgrade' style requires 4 parameters") exit(1) - message.bytes += [0x0C, named_args["w"], named_args["x"], named_args["h"], named_args["y"]] + message.bytes += [0x0C, *args] 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") + if len(args) != 1: + print(f"{filename}:{lineno}: font command requires 1 parameter") exit(1) - font = named_args["font"] + font = args[0] if font == "normal": font = 0 @@ -470,203 +580,213 @@ if __name__ == "__main__": charset = CHARSET_CREDITS else: charset = CHARSET - elif command == "/font": - font_stack.pop() - message.bytes += [0xFF, 0x00, font_stack[0]] + # 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": + # if font == 3 or font == 4: + # charset = CHARSET_CREDITS + # else: + # charset = CHARSET + elif command == "inputoff": message.bytes += [0xFF, 0x07] - elif command == "/noskip": + elif command == "inputon": message.bytes += [0xFF, 0x08] - elif command == "instant": + elif command == "delayoff": message.bytes += [0xFF, 0x09] - elif command == "/instant": + elif command == "delayon": message.bytes += [0xFF, 0x0A] elif command == "kerning": - if "kerning" not in named_args: - print(f"{filename}:{lineno}: kerning command requires a 'kerning' parameter") + if len(args) != 1: + print(f"{filename}:{lineno}: {command} command requires 1 parameter") exit(1) - message.bytes += [0xFF, 0x0B, named_args["kerning"]] + message.bytes += [0xFF, 0x0B, args[0]] elif command == "scroll": - if len(positional_args) == 0: - print(f"{filename}:{lineno}: scroll command requires a positional parameter") + if len(args) != 1: + print(f"{filename}:{lineno}: {command} command requires 1 parameter") exit(1) - message.bytes += [0xFF, 0x0C, positional_args[0]] + message.bytes += [0xFF, 0x0C, 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") + if len(args) != 2: + print(f"{filename}:{lineno}: {command} command requires 2 parameters") exit(1) - message.bytes += [0xFF, 0x0D, named_args["x"], named_args["y"]] - elif command == "/size": + message.bytes += [0xFF, 0x0D, *args] + elif command == "sizereset": 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") + if len(args) != 2: + print(f"{filename}:{lineno}: {command} command requires 2 parameters") 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)") + message.bytes += [0xFF, 0x0F, *args] + # 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 == "setprintpos": + if len(args) != 2: + print(f"{filename}:{lineno}: {command} command requires 2 parameters") 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"]] + message.bytes += [0xFF, 0x10, *args] + elif command == "setprinty": + if len(args) != 1: + print(f"{filename}:{lineno}: {command} command requires 1 parameter") + exit(1) + + message.bytes += [0xFF, 0x11, *args] elif command == "indent": - if len(positional_args) == 0: - print(f"{filename}:{lineno}: indent command requires a positional parameter") + if len(args) != 1: + print(f"{filename}:{lineno}: indent command requires 1 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") + message.bytes += [0xFF, 0x12, args[0]] + # elif command == "image": + # if len(args) == 1: + # message.bytes += [0xFF, 0x15, args[0]] + # elif len(args) == 7: + # message.bytes += [0xFF, 0x18, *args] + # else: + # print(f"{filename}:{lineno}: image command requires 1 or 7 parameters") + # exit(1) + elif command == "image1": + if len(args) != 1: + print(f"{filename}:{lineno}: {command} command requires 1 parameters") 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") + message.bytes += [0xFF, 0x15, *args] + elif command == "image7": + if len(args) != 7: + print(f"{filename}:{lineno}: {command} command requires 7 parameters") 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) + message.bytes += [0xFF, 0x18, *args] elif command == "sprite": - if len(positional_args) != 3: - print(f"{filename}:{lineno}: sprite command requires 3 positional parameters") + if len(args) != 3: + print(f"{filename}:{lineno}: sprite command requires 3 parameters") exit(1) - message.bytes += [0xFF, 0x16, *positional_args] + message.bytes += [0xFF, 0x16, *args] elif command == "item": - if len(positional_args) != 2: - print(f"{filename}:{lineno}: item command requires 2 positional parameters") + if len(args) != 2: + print(f"{filename}:{lineno}: item command requires 2 parameters") exit(1) - message.bytes += [0xFF, 0x17, *positional_args] + message.bytes += [0xFF, 0x17, *args] elif command == "cursor": - if len(positional_args) != 1: - print(f"{filename}:{lineno}: cursor command requires 1 positional parameter") + if len(args) != 1: + print(f"{filename}:{lineno}: cursor command requires 1 parameter") exit(1) - message.bytes += [0xFF, 0x1E, *positional_args] + message.bytes += [0xFF, 0x1E, *args] elif command == "option": - if len(positional_args) != 1: - print(f"{filename}:{lineno}: option command requires 1 positional parameter") + if len(args) != 1: + print(f"{filename}:{lineno}: option command requires 1 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") + message.bytes += [0xFF, 0x21, *args] + elif command == "endchoice": + if len(args) != 1: + print(f"{filename}:{lineno}: {command} command requires 1 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") + 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, 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] + 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 == "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") + if len(args) != 1: + print(f"{filename}:{lineno}: var command requires 1 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") + message.bytes += [0xFF, 0x28, *args] + elif command == "func_29": + if len(args) != 1: + print(f"{filename}:{lineno}: {command} command requires 1 parameter") exit(1) - message.bytes += [0xFF, 0x29, *positional_args] + message.bytes += [0xFF, 0x29, *args] elif command == "volume": - if "volume" not in named_args: - print(f"{filename}:{lineno}: volume command requires a 'volume' parameter") + if len(args) != 1: + print(f"{filename}:{lineno}: {command} command requires 1 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") + message.bytes += [0xFF, 0x2E, *args] + elif command == "speechsound": + if len(args) != 1: + print(f"{filename}:{lineno}: {command} command requires 1 parameter") exit(1) - sound = named_args["sound"] + sound = args[0] - if sound == "normal": - sound = 0 - elif sound == "bowser": - sound = 1 - elif sound == "spirit": - sound = 2 + # if sound == "normal": + # sound = 0 + # elif sound == "bowser": + # sound = 1 + # elif sound == "star": + # sound = 2 if type(sound) is not int: print(f"{filename}:{lineno}: unknown sound '{sound}'") @@ -674,67 +794,131 @@ if __name__ == "__main__": message.bytes += [0xFF, 0x2F, sound] sound_stack.append(sound) - elif command == "/sound": - sound_stack.pop() - message.bytes += [0xFF, 0x2F, sound_stack[0]] + # 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 == "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] + message.bytes += [0x98] 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] + message.bytes += [0x99] 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] + message.bytes += [0x9a] 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] + message.bytes += [0x9b] 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] + message.bytes += [0x9c] 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] + message.bytes += [0x9d] 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] + message.bytes += [0x9e] 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] + message.bytes += [0x9f] 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] + message.bytes += [0xa0] 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] + message.bytes += [0xa1] 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": + elif command == "up": + if len(args) == 1: + message.bytes += [0xFF, 0x14, args[0]] + else: + message.bytes += [0x92] + elif command == "down": + if len(args) == 1: + message.bytes += [0xFF, 0x13, args[0]] + else: + message.bytes += [0x93] + elif command == "left": message.bytes += [0x94] - elif command == "arrow-right": + elif command == "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) + # 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) + elif command == "func_1a": + if len(args) != 3: + print(f"{filename}:{lineno}: {command} command requires 3 parameters") + exit(1) + + message.bytes += [0xFF, 0x1A, *args] + elif command == "func_1b": + if len(args) != 2: + print(f"{filename}:{lineno}: {command} command requires 2 parameters") + exit(1) + + message.bytes += [0xFF, 0x1B, *args] + elif command == "func_1c": + if len(args) != 1: + print(f"{filename}:{lineno}: {command} command requires 1 parameter") + exit(1) + + message.bytes += [0xFF, 0x1C, *args] + elif command == "startanim": + message.bytes += [0xFF, 0x22] + elif command == "endanim": + message.bytes += [0xFF, 0x23] + elif command == "func_2b": + message.bytes += [0xFF, 0x2b] else: print(f"{filename}:{lineno}: unknown command '{command}'") exit(1) else: + if source[0] == "}": + if not explicit_end: + message.bytes += [0xFD] + explicit_end = False + + # padding + while len(message.bytes) % 4 != 0: + message.bytes += [0x00] + + message = None + source = source[1:] # } + indent_level = 0 + continue + if source[0] == "\\": source = source[1:] diff --git a/tools/splat.yaml b/tools/splat.yaml index 659e839478..932d511a28 100644 --- a/tools/splat.yaml +++ b/tools/splat.yaml @@ -9432,55 +9432,55 @@ segments: - start: 0x1B83000 type: PaperMarioMessages files: - - intro - - end/postgame - - toad_town/gate - - toad_town/castle - - toad_town/bridge - - toad_town/train - - toad_town/warehouse - - toad_town/docks - - toad_town/minigames - - castle_grounds - - shooting_star_summit - - prologue - - chapter1 - - chapter2 - - chapter3 - - chapter4 - - chapter5 - - chapter6 - - chapter7 - - chapter8 - - peach_interludes - - koopa_koot_quests - - advice/russ_t - - toad_town/bulletin_news - - toad_town/bulletin_gossip - - world/map_tattles - - world/npc_tattles - - world/entity_tattles - - battle/enemy_tattles - - ui/misc - - ui/choices - - ui/pause - - diary_letters - - advice/merlon - - advice/merluvlee - - item/descriptions_23 # TODO: difference between 23,24,25 - - item/descriptions_24 - - item/descriptions_25 - - item/names - - shops - - partner_descriptions - - battle/enemy_names - - battle/mario_moves - - battle/partner_moves - - quiz/questions - - quiz/options - - end/credits - - [0x1C84D30, bin] - - [0x1E00000, bin] # sprites here; Star Rod considers this a copy of sprite/npc.bin, but that doesnt appear to be true + - 00_introduction + - 01_postgame_celebration + - 02_toad_town_gate_sector + - 03_toad_town_castle_sector + - 04_toad_town_bridge_sector + - 05_toad_town_train_sector + - 06_toad_town_warehouse_sector + - 07_toad_town_docks_sector + - 08_minigames + - 09_castle_grounds + - 0A_shooting_star_summit + - 0B_prologue + - 0C_chapter_1 + - 0D_chapter_2 + - 0E_chapter_3 + - 0F_chapter_4 + - 10_chapter_5 + - 11_chapter_6 + - 12_chapter_7 + - 13_chapter_8 + - 14_peach_segments + - 15_koopa_koot_favors + - 16_russ_t_advice + - 17_news_bulletin + - 18_gossip_bulletin + - 19_map_tattles + - 1A_npc_tattles + - 1B_entity_tattles + - 1C_enemy_tattles + - 1D_menus + - 1E_choices + - 1F_pause + - 20_party_letters_luigi_diary + - 21_advice_fortunes + - 22_treasure_fortunes + - 23_item_descriptions # TODO: difference between 23,24,25 + - 24_item_descriptions + - 25_item_descriptions + - 26_item_names + - 27_shop_messages + - 28_partner_descriptions + - 29_enemy_names + - 2A_mario_moves + - 2B_partner_moves + - 2C_quiz_questions + - 2D_quiz_options + - 2E_credits + - [0x1C84D30, bin] # junk(?) + - [0x1E00000, bin] # junk (player sprite data; can be zeroed out with no effect) - [0x1E40000, PaperMarioMapFS] - [0x27FEE22, bin] - [0x2800000] diff --git a/tools/splat_ext/PaperMarioMessages.py b/tools/splat_ext/PaperMarioMessages.py index 9ef1f0d342..b8f212337b 100644 --- a/tools/splat_ext/PaperMarioMessages.py +++ b/tools/splat_ext/PaperMarioMessages.py @@ -1,8 +1,9 @@ from segtypes.n64.segment import N64Segment from pathlib import Path +import re CHARSET = { - 0x00: "๐… ", + 0x00: "[note]", 0x01: "!", 0x02: '"', 0x03: "#", @@ -146,142 +147,163 @@ CHARSET = { 0x8D: "ยก", 0x8E: "ยฟ", 0x8F: "ยช", - 0x90: "โ™ฅ", - 0x91: "โ˜…", - 0x92: "โ†‘", - 0x93: "โ†“", - 0x94: "โ†", - 0x95: "โ†’", - 0x96: "โ—", - 0x97: "โœ–", + 0x90: "[heart]", + 0x91: "[star]", + 0x92: "[up]", + 0x93: "[down]", + 0x94: "[left]", + 0x95: "[right]", + 0x96: "[circle]", + 0x97: "[cross]", + 0x98: "[a]", + 0x99: "[b]", + 0x9A: "[l]", + 0x9B: "[r]", + 0x9C: "[z]", + 0x9D: "[c-up]", + 0x9E: "[c-down]", + 0x9F: "[c-left]", + 0xA0: "[c-right]", + 0xA1: "[start]", 0xA2: "โ€œ", 0xA3: "โ€", 0xA4: "โ€˜", 0xA5: "โ€™", 0xF7: " ", 0xF0: "[br]\n", - 0xF1: "[prompt]", - 0xF2: {None: lambda d: (f"[sleep {d[0]}]", 1)}, + 0xF1: "[wait]", + 0xF2: {None: lambda d: (f"[pause:{d[0]}]", 1)}, 0xFB: "[next]\n", 0xFC: { - 0x01: "[style=right]\n", - 0x02: "[style=left]\n", - 0x03: "[style=center]\n", - 0x04: "[style=tattle]\n", - 0x05: {None: lambda d: (f"[style=choice x={d[0]} y={d[1]} w={d[2]} h={d[3]}]\n", 4)}, - 0x06: "[style=inspect]\n", - 0x07: "[style=sign]\n", - 0x08: "[style=lamppost]\n", - 0x09: "[style=postcard]\n", - 0x0A: "[style=popup]\n", - 0x0C: {None: lambda d: (f"[style=upgrade x={d[1]} y={d[3]} w={d[0]} h={d[2]}]\n", 4)}, - 0x0D: "[style=narrate]\n", - 0x0E: "[style=epilogue]\n", + 0x01: "[style:right]\n", + 0x02: "[style:left]\n", + 0x03: "[style:center]\n", + 0x04: "[style:tattle]\n", + 0x05: {None: lambda d: (f"[style:choice:{d[0]}:{d[1]}:{d[2]}:{d[3]}]\n", 4)}, + 0x06: "[style:inspect]\n", + 0x07: "[style:sign]\n", + 0x08: {None: lambda d: (f"[style:lamppost:{d[0]}]\n", 1)}, + 0x09: {None: lambda d: (f"[style:postcard:{d[0]}]\n", 1)}, + 0x0A: "[style:popup]\n", + 0x0C: {None: lambda d: (f"[style:upgrade:{d[0]}:{d[1]}:{d[2]}:{d[3]}]\n", 4)}, + 0x0D: "[style:narrate]\n", + 0x0E: "[style:epilogue]\n", }, 0xFF: { 0x00: { - 0: "[font=normal]", - 3: "[font=title]\n", - 4: "[font=subtitle]\n", + 0: "[font:normal]", + 3: "[font:title]\n", + 4: "[font:subtitle]\n", }, + 0x04: "[func_04]", 0x05: { - 0x0A: "[color=normal]", - 0x20: "[color=red]", - 0x21: "[color=pink]", - 0x22: "[color=purple]", - 0x23: "[color=blue]", - 0x24: "[color=cyan]", - 0x25: "[color=green]", - 0x26: "[color=yellow]", + # 0x0A: "[color:normal]", + # 0x20: "[color:red]", + # 0x21: "[color:pink]", + # 0x22: "[color:purple]", + # 0x23: "[color:blue]", + # 0x24: "[color:cyan]", + # 0x25: "[color:green]", + # 0x26: "[color:yellow]", - 0x00: "[color=normal ctx=diary]", - 0x07: "[color=red ctx=diary]", + # 0x00: "[color=normal ctx=diary]", + # 0x07: "[color=red ctx=diary]", - 0x17: "[color=dark ctx=inspect]", + # 0x17: "[color=dark ctx=inspect]", - 0x18: "[color=normal ctx=sign]", - 0x19: "[color=red ctx=sign]", - 0x1A: "[color=blue ctx=sign]", - 0x1B: "[color=green ctx=sign]", + # 0x18: "[color=normal ctx=sign]", + # 0x19: "[color=red ctx=sign]", + # 0x1A: "[color=blue ctx=sign]", + # 0x1B: "[color=green ctx=sign]", - 0x28: "[color=red ctx=popup]", - 0x29: "[color=pink ctx=popup]", - 0x2A: "[color=purple ctx=popup]", - 0x2B: "[color=blue ctx=popup]", - 0x2C: "[color=teal ctx=popup]", - 0x2D: "[color=green ctx=popup]", - 0x2E: "[color=yellow ctx=popup]", - 0x2F: "[color=normal ctx=popup]", + # 0x28: "[color=red ctx=popup]", + # 0x29: "[color=pink ctx=popup]", + # 0x2A: "[color=purple ctx=popup]", + # 0x2B: "[color=blue ctx=popup]", + # 0x2C: "[color=teal ctx=popup]", + # 0x2D: "[color=green ctx=popup]", + # 0x2E: "[color=yellow ctx=popup]", + # 0x2F: "[color=normal ctx=popup]", + + None: lambda d: (f"[color:0x{d[0]:X}]", 1), }, - 0x07: "[noskip]\n", - 0x08: "[/noskip]\n", - 0x09: "[instant]\n", - 0x0A: "[/instant]\n", - 0x0B: {None: lambda d: (f"[kerning={d[0]}]", 1)}, - 0x0C: {None: lambda d: (f"[scroll {d[0]}]", 1)}, - 0x0D: {None: lambda d: (f"[size x={d[0]} y={d[0]}]\n", 2)}, - 0x0E: "[/size]\n", - 0x0F: {None: lambda d: (f"[speed delay={d[0]} chars={d[1]}]", 2)}, - 0x10: {None: lambda d: (f"[pos x={d[0]} y={d[1]}]", 2)}, - 0x11: {None: lambda d: (f"[pos y={d[0]}]", 1)}, - 0x12: {None: lambda d: (f"[indent {d[0]}]", 1)}, - 0x13: {None: lambda d: (f"[down {d[0]}]", 1)}, - 0x14: {None: lambda d: (f"[up {d[0]}]", 1)}, - 0x15: {None: lambda d: (f"[image {d[0]}]\n", 1)}, - 0x16: {None: lambda d: (f"[sprite {d[0]} {d[1]} {d[2]}]\n", 3)}, - 0x17: {None: lambda d: (f"[item {d[0]} {d[1]}]\n", 2)}, - 0x18: {None: lambda d: (f"[image {d[0]} {d[1]} {d[2]} {d[3]} {d[4]} {d[5]} {d[6]}]\n", 7)}, - 0x1E: {None: lambda d: (f"[cursor {d[0]}]", 1)}, - 0x1F: {None: lambda d: (f"[choicecount={d[0]}]", 1)}, - 0x20: {None: lambda d: (f"[cancel={d[0]}]", 1)}, - 0x21: {None: lambda d: (f"[option {d[0]}]", 1)}, - 0x24: {0xFF: {0x05: { - 0x10: {0x98: {0xFF: {0x25: "โ’ถ"}}}, - 0x11: {0x99: {0xFF: {0x25: "โ’ท"}}}, - 0x12: {0xA1: {0xFF: {0x25: "โ“ˆ"}}}, - 0x13: { - 0x9D: {0xFF: {0x25: "โ–ฒ"}}, - 0x9E: {0xFF: {0x25: "โ–ผ"}}, - 0x9F: {0xFF: {0x25: "โ—€"}}, - 0xA0: {0xFF: {0x25: "โ–ถ"}}, - }, - 0x14: {0x9C: {0xFF: {0x25: "โ“"}}}, - }}}, + 0x07: "[inputOff]\n", + 0x08: "[inputOn]\n", + 0x09: "[delayOff]\n", + 0x0A: "[delayOn]\n", + 0x0B: {None: lambda d: (f"[kerning:{d[0]}]", 1)}, + 0x0C: {None: lambda d: (f"[scroll:{d[0]}]", 1)}, + 0x0D: {None: lambda d: (f"[size:{d[0]}:{d[0]}]\n", 2)}, + 0x0E: "[sizeReset]\n", + 0x0F: {None: lambda d: (f"[speed:{d[0]}:{d[1]}]", 2)}, + 0x10: {None: lambda d: (f"[setPrintPos:{d[0]}:{d[1]}]", 2)}, + 0x11: {None: lambda d: (f"[setPrintY:{d[0]}]", 1)}, + 0x12: {None: lambda d: (f"[indent:{d[0]}]", 1)}, + 0x13: {None: lambda d: (f"[down:{d[0]}]", 1)}, + 0x14: {None: lambda d: (f"[up:{d[0]}]", 1)}, + 0x15: {None: lambda d: (f"[image1:{d[0]}]\n", 1)}, + 0x16: {None: lambda d: (f"[sprite:{d[0]}:{d[1]}:{d[2]}]\n", 3)}, + 0x17: {None: lambda d: (f"[item:{d[0]}:{d[1]}]\n", 2)}, + 0x18: {None: lambda d: (f"[image7:{d[0]}:{d[1]}:{d[2]}:{d[3]}:{d[4]}:{d[5]}:{d[6]}]\n", 7)}, + 0x1A: {None: lambda d: (f"[func_1A:{d[0]}:{d[1]}:{d[2]}]", 3)}, + 0x1B: {None: lambda d: (f"[func_1B:{d[0]}:{d[1]}]", 2)}, + 0x1C: {None: lambda d: (f"[func_1C:{d[0]}]", 1)}, + 0x1E: {None: lambda d: (f"[cursor:{d[0]}]", 1)}, + 0x1F: {None: lambda d: (f"[endChoice:{d[0]}]", 1)}, + 0x20: {None: lambda d: (f"[setCancel:{d[0]}]", 1)}, + 0x21: {None: lambda d: (f"[option:{d[0]}]", 1)}, + 0x22: "[startAnim]", + 0x23: "[endAnim]", + # 0x24: {0xFF: {0x05: { + # 0x10: {0x98: {0xFF: {0x25: "โ’ถ"}}}, + # 0x11: {0x99: {0xFF: {0x25: "โ’ท"}}}, + # 0x12: {0xA1: {0xFF: {0x25: "โ“ˆ"}}}, + # 0x13: { + # 0x9D: {0xFF: {0x25: "โ–ฒ"}}, + # 0x9E: {0xFF: {0x25: "โ–ผ"}}, + # 0x9F: {0xFF: {0x25: "โ—€"}}, + # 0xA0: {0xFF: {0x25: "โ–ถ"}}, + # }, + # 0x14: {0x9C: {0xFF: {0x25: "โ“"}}}, + # }}}, + 0x24: "[pushColor]", + 0x25: "[popColor]", 0x26: { - 0x00: "[shaky]", - 0x01: "[wavy]", - 0x03: {None: lambda d: (f"[noise fade={d[0]}]", 1)}, - 0x05: {None: lambda d: (f"[faded-shaky fade={d[0]}]", 1)}, - 0x07: {None: lambda d: (f"[fade={d[0]}]", 1)}, - 0x0A: "[shout]", - 0x0B: "[whisper]", - 0x0C: "[scream]", - 0x0D: "[chortle]", - 0x0E: "[shadow]", + 0x00: "[startFX:jitter]", + 0x01: "[startFX:wavy]", + 0x03: {None: lambda d: (f"[startFX:fadedNoise:{d[0]}]", 1)}, + 0x05: {None: lambda d: (f"[startFX:fadedJitter:{d[0]}]", 1)}, + 0x07: {None: lambda d: (f"[startFX:faded:{d[0]}]", 1)}, + 0x0A: "[startFX:shrinking]", + 0x0B: "[startFX:growing]", + 0x0C: "[startFX:sizeJitter]", + 0x0D: "[startFX:sizeWave]", + 0x0E: "[startFX:dropShadow]", }, 0x27: { - 0x00: "[/shaky]", - 0x01: "[/wavy]", - 0x03: "[/noise]", - 0x05: "[/faded-shaky]", - 0x07: "[/fade]", - 0x0A: "[/shout]", - 0x0B: "[/whisper]", - 0x0C: "[/scream]", - 0x0D: "[/chortle]", - 0x0E: "[/shadow]", + 0x00: "[endFX:jitter]", + 0x01: "[endFX:wavy]", + 0x03: "[endFX:fadedNoise]", + 0x05: "[endFX:fadedJitter]", + 0x07: "[endFX:faded]", + 0x0A: "[endFX:shrinking]", + 0x0B: "[endFX:growing]", + 0x0C: "[endFX:sizeJitter]", + 0x0D: "[endFX:sizeWave]", + 0x0E: "[endFX:dropShadow]", }, - 0x28: {None: lambda d: (f"[var {d[0]}]", 1)}, - 0x29: {None: lambda d: (f"[center {d[0]}]", 1)}, - 0x2E: {None: lambda d: (f"[volume={d[0]}]", 1)}, + 0x28: {None: lambda d: (f"[var:{d[0]}]", 1)}, + 0x29: {None: lambda d: (f"[func_29:{d[0]}]", 1)}, + 0x2B: "[func_2B]", + 0x2E: {None: lambda d: (f"[volume:{d[0]}]", 1)}, 0x2F: { - 1: "[sound=bowser]\n", - 2: "[sound=spirit]\n", - None: lambda d: (f"[sound={d[0]}]\n", 1), + #1: "[speechSound:bowser]\n", + #2: "[speechSound:star]\n", + None: lambda d: (f"[speechSound:{d[0]}]\n", 1), }, - None: lambda d: (f"[func 0x{d[0]:X}]", 1), + #None: lambda d: (f"[func_{d[0]:02X}]", 1), }, - None: lambda d: (f"[raw 0x{d[0]:02X}]", 1), + None: lambda d: (f"[raw:0x{d[0]:02X}]", 1), } CHARSET_CREDITS = { @@ -349,6 +371,12 @@ class N64SegPaperMarioMessages(N64Segment): section_offsets.append(offset) pos += 4 + msg_dir = Path(base_path, self.options["assets_dir"], self.name) + msg_dir.mkdir(parents=True, exist_ok=True) + + # delete existing files + self.delete_dir_childs(msg_dir) + for i, section_offset in enumerate(section_offsets): name = f"{i:02X}" if len(self.files) >= i: @@ -367,15 +395,24 @@ class N64SegPaperMarioMessages(N64Segment): self.log(f"Reading {len(msg_offsets)} messages in section {name} (0x{i:02X})") - path = Path(base_path, self.options["assets_dir"], self.name, name + ".msg") - path.parent.mkdir(parents=True, exist_ok=True) + path = msg_dir / Path(name + ".msg") + with open(path, "w") as self.f: for j, msg_offset in enumerate(msg_offsets): if j != 0: self.f.write("\n") - self.f.write(f"[message section=0x{i:02X} index={j}]\n") + self.f.write(f"#message:{i:02X}:{j:03X} {{\n ") self.write_message_markup(data[msg_offset:]) - self.f.write("\n[/message]\n") + self.f.write("\n}\n") + + @staticmethod + def delete_dir_childs(path): + for f in path.iterdir(): + if f.is_dir(): + N64SegPaperMarioMessages.delete_dir_childs(f) + f.rmdir() + else: + f.unlink() def get_ld_files(self): return [(self.options["assets_dir"], self.name, ".data", self.rom_start)] @@ -420,9 +457,9 @@ class N64SegPaperMarioMessages(N64Segment): raise ValueError(value) def write_markup(self, markup): - self.f.write(markup) + self.f.write(re.sub("\n", "\n ", markup)) - if markup == "[font=title]\n" or markup == "[font=subtitle]\n": + if markup == "[font:title]\n" or markup == "[font:subtitle]\n": self.root_charset = CHARSET_CREDITS - elif markup == "[font=normal]": + elif markup == "[font:normal]": self.root_charset = CHARSET