From d687f84d35c8d89d4db2a940d5f68f57201f5233 Mon Sep 17 00:00:00 2001 From: Alex Bates Date: Wed, 10 Feb 2021 00:12:28 +0000 Subject: [PATCH 1/7] use star rod-style message syntax --- tools/msg/parse_compile.py | 722 ++++++++++++++++---------- tools/splat.yaml | 98 ++-- tools/splat_ext/PaperMarioMessages.py | 275 +++++----- 3 files changed, 658 insertions(+), 437 deletions(-) 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 From 46d7a144e74c62aabf7eb7c45f7ec37dccc1523d Mon Sep 17 00:00:00 2001 From: Alex Bates Date: Wed, 10 Feb 2021 00:53:14 +0000 Subject: [PATCH 2/7] fix message headers --- configure.py | 3 ++- tools/msg/combine.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/configure.py b/configure.py index cb3adf6d3f..9c52efd06b 100755 --- a/configure.py +++ b/configure.py @@ -389,6 +389,7 @@ async def main(): msg_files = [] for d in ASSET_DIRS: msg_files.extend(glob(d + "/**/*.msg", recursive=True)) + msg_files = list(set(msg_files)) # dedup for msg_file in msg_files: n.build( f"$builddir/{msg_file.split('/', 1)[1]}.bin", @@ -397,7 +398,7 @@ async def main(): implicit="tools/msg/parse_compile.py", ) msg_headers = [add_generated_header(f"$builddir/include/{msg_file.split('/', 1)[1]}.h") for msg_file in msg_files] - msg_bins = list(set([f"$builddir/{msg_file.split('/', 1)[1]}.bin" for msg_file in msg_files])) + msg_bins = [f"$builddir/{msg_file.split('/', 1)[1]}.bin" for msg_file in msg_files] n.build( "$builddir/msg.bin", "msg_combine", diff --git a/tools/msg/combine.py b/tools/msg/combine.py index a9210ec949..2a38642821 100755 --- a/tools/msg/combine.py +++ b/tools/msg/combine.py @@ -53,7 +53,7 @@ if __name__ == "__main__": sections.append([]) section = sections[section_idx] - index = message.index if message.index is not None else len(section) + message.index = index = message.index if message.index is not None else len(section) if message.name: if message.name in names: @@ -104,7 +104,7 @@ if __name__ == "__main__": ) for message in messages: - h += f"#define MessageID_{message.name} MESSAGE_ID({message.section}, {message.index})\n" + h += f"#define MSG_{message.name} MESSAGE_ID({message.section}, {message.index})\n" h += "\n#endif\n" h_lines = h.splitlines() From 87652e8abb71df69d13daf9eb9ac4ade69922f3b Mon Sep 17 00:00:00 2001 From: Alex Bates Date: Wed, 10 Feb 2021 01:36:01 +0000 Subject: [PATCH 3/7] add message naming to splat.yaml --- configure.py | 16 +++-- include/messages.h | 7 +-- src/world/area_kmr/kmr_03/8C7F90.c | 3 +- src/world/area_kmr/kmr_12/events.c | 5 +- src/world/area_kmr/kmr_12/header.c | 3 +- tools/msg/combine.py | 85 ++++++++++++++------------- tools/splat.yaml | 7 ++- tools/splat_ext/PaperMarioMessages.py | 13 +++- 8 files changed, 76 insertions(+), 63 deletions(-) diff --git a/configure.py b/configure.py index 9c52efd06b..047916b066 100755 --- a/configure.py +++ b/configure.py @@ -315,9 +315,8 @@ async def main(): description="ld_addrs_h $in") n.newline() - # $msg_combine_headers n.rule("msg_combine", - command="$python tools/msg/combine.py $out $in --headers $msg_combine_headers", + command="$python tools/msg/combine.py $out $in", description="combine messages") n.rule("msg", command="$python tools/msg/parse_compile.py $in $out", @@ -386,10 +385,11 @@ async def main(): n.build(add_generated_header("$builddir/include/ld_addrs.h"), "ld_addrs_h", "$builddir/$target.ld") # messages - msg_files = [] + msg_files = set() for d in ASSET_DIRS: - msg_files.extend(glob(d + "/**/*.msg", recursive=True)) - msg_files = list(set(msg_files)) # dedup + for f in glob(d + "/**/*.msg", recursive=True): + msg_files.add(find_asset(f[len(d)+1:])) + msg_files = list(msg_files) for msg_file in msg_files: n.build( f"$builddir/{msg_file.split('/', 1)[1]}.bin", @@ -397,15 +397,13 @@ async def main(): msg_file, implicit="tools/msg/parse_compile.py", ) - msg_headers = [add_generated_header(f"$builddir/include/{msg_file.split('/', 1)[1]}.h") for msg_file in msg_files] + #msg_headers = [add_generated_header(f"$builddir/include/{msg_file.split('/', 1)[1]}.h") for msg_file in msg_files] msg_bins = [f"$builddir/{msg_file.split('/', 1)[1]}.bin" for msg_file in msg_files] n.build( - "$builddir/msg.bin", + ["$builddir/msg.bin", add_generated_header(f"$builddir/include/message_ids.h")], "msg_combine", msg_bins, implicit="tools/msg/combine.py", - implicit_outputs=msg_headers, - variables={ "msg_combine_headers": msg_headers } ) n.build("$builddir/msg.o", "bin", "$builddir/msg.bin") diff --git a/include/messages.h b/include/messages.h index c8a8789817..869794d1b5 100644 --- a/include/messages.h +++ b/include/messages.h @@ -5,12 +5,7 @@ typedef s32 MessageID; +// Prefer editing splat.yaml's msg ids section than using this directly! #define MESSAGE_ID(section, index) (((section << 0x10) + index)) -#define MessageID_TATTLE_KMR_03 MESSAGE_ID(0x19, 0x3B) -#define MessageID_TATTLE_KMR_12 MESSAGE_ID(0x19, 0x40) - -#define MessageID_SIGN_MUSHROOM_GOOMBA_TRAP MESSAGE_ID(0x1D, 0x167) -#define MessageID_SIGN_GOOMBA_KINGS_FORTRESS_AHEAD MESSAGE_ID(0x1D, 0x168) - #endif diff --git a/src/world/area_kmr/kmr_03/8C7F90.c b/src/world/area_kmr/kmr_03/8C7F90.c index b1246aeb20..f96d6b4a2b 100644 --- a/src/world/area_kmr/kmr_03/8C7F90.c +++ b/src/world/area_kmr/kmr_03/8C7F90.c @@ -1,4 +1,5 @@ #include "kmr_03.h" +#include "message_ids.h" #include "../../partners.h" Script N(Main); @@ -61,7 +62,7 @@ MapConfig N(config) = { .entryList = N(entryList), .entryCount = ENTRY_COUNT(N(entryList)), .background = &gBackgroundImage, - .tattle = MessageID_TATTLE_KMR_03, + .tattle = MSG_kmr_03_tattle, }; Script N(Script_802406C0) = SCRIPT({ diff --git a/src/world/area_kmr/kmr_12/events.c b/src/world/area_kmr/kmr_12/events.c index 8d02050f8a..980ece82af 100644 --- a/src/world/area_kmr/kmr_12/events.c +++ b/src/world/area_kmr/kmr_12/events.c @@ -1,4 +1,5 @@ #include "kmr_12.h" +#include "message_ids.h" #include "sprite/npc/goomba.h" Script N(ExitWest) = EXIT_WALK_SCRIPT(60, 0, "kmr_07", 1); @@ -59,7 +60,7 @@ Script N(ReadWestSign) = SCRIPT({ // "Eat a Mushroom to regain your energy!" suspend group 1; DisablePlayerInput(TRUE); - ShowMessageAtScreenPos(MessageID_SIGN_MUSHROOM_GOOMBA_TRAP, 160, 40); + ShowMessageAtScreenPos(MSG_kmr_12_sign_trap, 160, 40); resume group 1; SI_FLAG(0) = FALSE; @@ -201,7 +202,7 @@ Script N(ReadEastSign) = SCRIPT({ func_802D5830(1); DisablePlayerInput(1); - ShowMessageAtScreenPos(MessageID_SIGN_GOOMBA_KINGS_FORTRESS_AHEAD, 160, 40); + ShowMessageAtScreenPos(MSG_kmr_12_sign_to_fortress, 160, 40); DisablePlayerInput(0); func_802D5830(0); }); diff --git a/src/world/area_kmr/kmr_12/header.c b/src/world/area_kmr/kmr_12/header.c index 9d6ae992db..3ff536959d 100644 --- a/src/world/area_kmr/kmr_12/header.c +++ b/src/world/area_kmr/kmr_12/header.c @@ -1,4 +1,5 @@ #include "kmr_12.h" +#include "message_ids.h" Vec4f N(entryList)[] = { { -126.0f, 0.0f, 12.0f, 90.0f }, // west, towards Red/Blue Goomba miniboss room @@ -10,7 +11,7 @@ MapConfig N(config) = { .entryList = N(entryList), .entryCount = ENTRY_COUNT(N(entryList)), .background = &gBackgroundImage, - .tattle = MessageID_TATTLE_KMR_12, + .tattle = MSG_kmr_12_tattle, }; Script N(PlayMusic) = SCRIPT({ diff --git a/tools/msg/combine.py b/tools/msg/combine.py index 2a38642821..d0ebb8be8b 100755 --- a/tools/msg/combine.py +++ b/tools/msg/combine.py @@ -16,30 +16,38 @@ class Message: if __name__ == "__main__": if len(argv) < 3: - print("usage: combine.py [out.bin] [compiled...] --headers [out.h]") + print("usage: combine.py [out.bin] [out.h] [compiled...]") exit(1) - _, outfile, *infiles = argv + _, outfile, header_file, *infiles = argv messages = [] - header_files = [] + #header_files = [] for i, infile in enumerate(infiles): - if infile == "--headers": - header_files = infiles[i+1:] - break + # 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)) + #messages.sort(key=lambda msg: bool(msg.section)<<2 + bool(msg.index)) names = set() - sections = [] * 0x2E - messages_by_file = {} + sections = [] + #messages_by_file = {} + + # this logic could probably be a bit better (i.e. read ahead, so no overwriting happens) + def section_get_unused_id(section): + max_index = 0 + for index in section: + if index > max_index: + max_index = index + return max_index + 1 for message in messages: if message.section is None: @@ -47,35 +55,45 @@ if __name__ == "__main__": for section_idx, section in enumerate(sections): if len(section) < 0xFFF: break + message.section = section_idx else: section_idx = message.section while len(sections) <= section_idx: - sections.append([]) + sections.append({}) section = sections[section_idx] - message.index = index = message.index if message.index is not None else len(section) + if message.index is None: + message.index = section_get_unused_id(section) if message.name: if message.name in names: - print(f"warning: multiple messages with name '{message.name}'") + print(f"error: multiple messages with name '{message.name}'") + exit(1) 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]) + # 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) + if message.index in section: + print(f"error: multiple messages allocated to id {section_idx:02X}:{message.index:03X}") + exit(1) + + section[message.index] = message f.seek((len(sections) + 1) * 4) # skip past table of contents section_offsets = [] for section in sections: + # convert dict into sorted list + section = [msg for idx, msg in sorted(section.items(), key=lambda ele: ele[0])] + message_offsets = [] for message in section: message_offsets.append(f.tell()) - f.write(message) + f.write(message.bytes) section_offset = f.tell() section_offsets.append(section_offset) @@ -92,34 +110,17 @@ if __name__ == "__main__": 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" + with open(header_file, "w") as f: + f.write( + f"#ifndef _MESSAGE_IDS_H_\n" + f"#define _MESSAGE_IDS_H_\n" "\n" '#include "messages.h"\n' "\n" ) for message in messages: - h += f"#define MSG_{message.name} MESSAGE_ID({message.section}, {message.index})\n" + if message.name: + f.write(f"#define MSG_{message.name} MESSAGE_ID(0x{message.section:02X}, 0x{message.index:03X})\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) + f.write("\n#endif\n") diff --git a/tools/splat.yaml b/tools/splat.yaml index 932d511a28..5035074375 100644 --- a/tools/splat.yaml +++ b/tools/splat.yaml @@ -9467,7 +9467,7 @@ segments: - 20_party_letters_luigi_diary - 21_advice_fortunes - 22_treasure_fortunes - - 23_item_descriptions # TODO: difference between 23,24,25 + - 23_item_descriptions # TODO: difference between 23,24,25 (shops, menus, pickups?) - 24_item_descriptions - 25_item_descriptions - 26_item_names @@ -9479,6 +9479,11 @@ segments: - 2C_quiz_questions - 2D_quiz_options - 2E_credits + ids: + - [0x19, 0x03B, kmr_03_tattle] + - [0x19, 0x040, kmr_12_tattle] + - [0x1D, 0x167, kmr_12_sign_trap] + - [0x1D, 0x168, kmr_12_sign_to_fortress] - [0x1C84D30, bin] # junk(?) - [0x1E00000, bin] # junk (player sprite data; can be zeroed out with no effect) - [0x1E40000, PaperMarioMapFS] diff --git a/tools/splat_ext/PaperMarioMessages.py b/tools/splat_ext/PaperMarioMessages.py index b8f212337b..ca141c7117 100644 --- a/tools/splat_ext/PaperMarioMessages.py +++ b/tools/splat_ext/PaperMarioMessages.py @@ -356,6 +356,7 @@ class N64SegPaperMarioMessages(N64Segment): def __init__(self, segment, next_segment, options): super().__init__(segment, next_segment, options) self.files = segment.get("files", []) if type(segment) is dict else [] + self.ids = segment["ids"] def split(self, rom_bytes, base_path): data = rom_bytes[self.rom_start: self.rom_end] @@ -401,7 +402,17 @@ class N64SegPaperMarioMessages(N64Segment): for j, msg_offset in enumerate(msg_offsets): if j != 0: self.f.write("\n") - self.f.write(f"#message:{i:02X}:{j:03X} {{\n ") + + msg_name = None + for section, index, goodname in self.ids: + if i == section and j == index: + msg_name = goodname + break + + if msg_name is None: + self.f.write(f"#message:{i:02X}:{j:03X} {{\n ") + else: + self.f.write(f"#message:{i:02X}:({msg_name}) {{\n ") self.write_message_markup(data[msg_offset:]) self.f.write("\n}\n") From 676d6d9a16a73c560bd2da87c4616e7bc75501b3 Mon Sep 17 00:00:00 2001 From: Alex Bates Date: Wed, 10 Feb 2021 02:36:46 +0000 Subject: [PATCH 4/7] require that msg files go in assets/msg/* --- configure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.py b/configure.py index 047916b066..2872a94511 100755 --- a/configure.py +++ b/configure.py @@ -387,7 +387,7 @@ async def main(): # messages msg_files = set() for d in ASSET_DIRS: - for f in glob(d + "/**/*.msg", recursive=True): + for f in glob(d + "/msg/**/*.msg", recursive=True): msg_files.add(find_asset(f[len(d)+1:])) msg_files = list(msg_files) for msg_file in msg_files: From f28218a6f18203abcd3b99c2cc6c270733a187db Mon Sep 17 00:00:00 2001 From: Alex Bates Date: Wed, 10 Feb 2021 13:43:55 +0000 Subject: [PATCH 5/7] complain if [end] is missing --- tools/msg/combine.py | 15 +++++++-------- tools/msg/parse_compile.py | 3 ++- tools/splat_ext/PaperMarioMessages.py | 2 ++ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tools/msg/combine.py b/tools/msg/combine.py index d0ebb8be8b..57b1123e02 100755 --- a/tools/msg/combine.py +++ b/tools/msg/combine.py @@ -65,12 +65,12 @@ if __name__ == "__main__": if message.index is None: message.index = section_get_unused_id(section) - if message.name: - if message.name in names: - print(f"error: multiple messages with name '{message.name}'") - exit(1) - else: - names.add(message.name) + # if message.name: + # if message.name in names: + # print(f"error: multiple messages with name '{message.name}'") + # exit(1) + # else: + # names.add(message.name) # if message.header_file_index in messages_by_file: # messages_by_file[message.header_file_index].add(message) @@ -78,8 +78,7 @@ if __name__ == "__main__": # messages_by_file[message.header_file_index] = set([message]) if message.index in section: - print(f"error: multiple messages allocated to id {section_idx:02X}:{message.index:03X}") - exit(1) + print(f"warning: multiple messages allocated to id {section_idx:02X}:{message.index:03X}") section[message.index] = message diff --git a/tools/msg/parse_compile.py b/tools/msg/parse_compile.py index 48afb26e90..649dedd468 100755 --- a/tools/msg/parse_compile.py +++ b/tools/msg/parse_compile.py @@ -907,7 +907,8 @@ if __name__ == "__main__": else: if source[0] == "}": if not explicit_end: - message.bytes += [0xFD] + print(f"{filename}:{lineno}: warning: string lacks an [end] command") + #message.bytes += [0xFD] explicit_end = False # padding diff --git a/tools/splat_ext/PaperMarioMessages.py b/tools/splat_ext/PaperMarioMessages.py index ca141c7117..4ab16f8a00 100644 --- a/tools/splat_ext/PaperMarioMessages.py +++ b/tools/splat_ext/PaperMarioMessages.py @@ -467,6 +467,8 @@ class N64SegPaperMarioMessages(N64Segment): else: raise ValueError(value) + self.write_markup("[end]") + def write_markup(self, markup): self.f.write(re.sub("\n", "\n ", markup)) From b2d0b2c6c8734a318c5402a6778182ff1ce6fd99 Mon Sep 17 00:00:00 2001 From: Alex Bates Date: Wed, 10 Feb 2021 13:45:00 +0000 Subject: [PATCH 6/7] MESSAGE_ID macro: 0x10 -> 16 --- include/messages.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/messages.h b/include/messages.h index 869794d1b5..96abcb73b6 100644 --- a/include/messages.h +++ b/include/messages.h @@ -6,6 +6,6 @@ typedef s32 MessageID; // Prefer editing splat.yaml's msg ids section than using this directly! -#define MESSAGE_ID(section, index) (((section << 0x10) + index)) +#define MESSAGE_ID(section, index) (((section << 16) + index)) #endif From addfc799f66c125589e88cf8b53baeb058438688 Mon Sep 17 00:00:00 2001 From: Alex Bates Date: Wed, 10 Feb 2021 14:26:58 +0000 Subject: [PATCH 7/7] use tabs in msg files --- .editorconfig | 3 +++ tools/msg/parse_compile.py | 10 ++++------ tools/splat_ext/PaperMarioMessages.py | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.editorconfig b/.editorconfig index df5214ff8c..e0291f737e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,3 +11,6 @@ indent_size = 2 [{Makefile,*.mk}] indent_style = tab + +[*.msg] +indent_style = tab diff --git a/tools/msg/parse_compile.py b/tools/msg/parse_compile.py index 649dedd468..30239cb18a 100755 --- a/tools/msg/parse_compile.py +++ b/tools/msg/parse_compile.py @@ -388,7 +388,7 @@ if __name__ == "__main__": explicit_end = False while len(source) > 0: - if source[0] == "\r": + if source[0] == "\r" or source[0] == "\t": source = source[1:] continue @@ -397,7 +397,7 @@ if __name__ == "__main__": source = source[1:] for i in range(indent_level): - if source[0] == " " or source[0] == "\t": + if source[0] == "\t": source = source[1:] else: break @@ -452,14 +452,12 @@ if __name__ == "__main__": # 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, args, source = parse_command(source) diff --git a/tools/splat_ext/PaperMarioMessages.py b/tools/splat_ext/PaperMarioMessages.py index 4ab16f8a00..22a6704816 100644 --- a/tools/splat_ext/PaperMarioMessages.py +++ b/tools/splat_ext/PaperMarioMessages.py @@ -410,9 +410,9 @@ class N64SegPaperMarioMessages(N64Segment): break if msg_name is None: - self.f.write(f"#message:{i:02X}:{j:03X} {{\n ") + self.f.write(f"#message:{i:02X}:{j:03X} {{\n\t") else: - self.f.write(f"#message:{i:02X}:({msg_name}) {{\n ") + self.f.write(f"#message:{i:02X}:({msg_name}) {{\n\t") self.write_message_markup(data[msg_offset:]) self.f.write("\n}\n") @@ -470,7 +470,7 @@ class N64SegPaperMarioMessages(N64Segment): self.write_markup("[end]") def write_markup(self, markup): - self.f.write(re.sub("\n", "\n ", markup)) + self.f.write(re.sub("\n", "\n\t", markup)) if markup == "[font:title]\n" or markup == "[font:subtitle]\n": self.root_charset = CHARSET_CREDITS