User:2 B/Debatably useful stuff

From Pikipedia, the Pikmin wiki
Revision as of 14:35, January 20, 2025 by 2 B (talk | contribs)
Jump to navigation Jump to search

Python script to clean up files from the Pikmin 3 text dump

# File from the text dump
filename = "Strings/Clean/Pikmin 3/USEng/Chat.json"

# Change these for your purposes
textbox_separator = "\n---\n"
include_pauses = False
include_sound = False
include_autoadvance = True
include_lookat = True
include_textsize = True
include_variables = False
include_ruby = True



def clean_text(lines):
    characters = ("Alph", "Brittany", "Charlie", "Louie", "Olimar", "S.S. Drake")
    emotes = ("neutral", "shocked", "happy", "sad", "mad")
    colors = {
        0x01: "orange", 0x02: "#AA0", 0x03: "cyan",
        # pikmin colors
        0x0b: "red", 0x0e: "#AA0", 0x11: "blue", 0x14: "grey", 0x17: "pink",
        # leader colors
        0x1a: "lightblue", 0x1d: "pink", 0x20: "lime"}
    buttons = [
        '\\00', '\\01', '\\02', '\\03', '\\04', '\\05', '\\06', '\\07', '\\08', '\\09',
        'photo flash', 'photo',
        '\\0c', '\\0d', '\\0e', '\\0f', '\\10', '\\11', '\\12', '\\13',
        'roll right',
        '\\15',
        'roll left', 'photo zoom', 'use onion', 'move', 'throw', 'whistle', 'dismiss', 'change type',
        'reset camera', 'lock-on', 'charge', 'switch leader', 'spray',
        '\\23', '\\24', '\\25', '\\26', '\\27', '\\28', '\\29', '\\2a', '\\2b',
        'pluck', 'cancel',
        '\\2e',
        'shake',
    ]

    text = "\x00".join(lines)
    out = ""
    i = 0
    color = False
    while i < len(text):
        if text[i] == '\x0e':
            i += 1
            tag = text[i:i+2]
            extra_size = ord(text[i+2]) // 2
            i += 3
            if tag == '\x00\x00':
                if include_ruby:
                    kanji_count = ord(text[i]) // 2
                    furigana_count = ord(text[i+1]) // 2
                    furigana = text[i+2 : i+2 + furigana_count]
                    kanji = text[i+2 + furigana_count : i+2 + furigana_count + kanji_count]
                    out += f"<ruby>{kanji}<rt>{furigana}</rt></ruby>"
                    i += kanji_count
                i += extra_size
                continue

            if tag == '\x00\x02':
                if include_textsize:
                    out += f"[text size: {hex(ord(text[i]))}]"
                i += extra_size
                continue

            if tag == '\x00\x03':
                if text[i] == '\uffff':
                    # out += "[white]"
                    if color:
                        out += f"}}}}"
                    color = False
                elif ord(text[i]) in colors:
                    # out += "[orange]"
                    if color:
                        out += f"}}}}"
                    out += f"{{{{color|2={colors[ord(text[i])]}|"
                    color = True
                else:
                    out += f"[unknown color: {hex(ord(text[i]))}]"
                i += extra_size
                continue

            if tag == '\x00\x04':
                out += textbox_separator
                i += extra_size
                continue

            if tag[0] == '\x01':
                name_len = ord(text[i]) // 2
                var_name = text[i+1 : i+1 + name_len]
                assert(text[i+1 + name_len : i+1 + name_len + 2] == "\u0100\u0000")
                if include_variables:
                    out += f"[variable: {hex(ord(text[i-2]))} \"{var_name}\"]"
                else:
                    out += "_"
                i += extra_size
                continue

            if tag == '\x07\x01':
                detail = ord(text[i])
                assert(detail & 0x00FF == 0xcd)
                button_id = (detail & 0xFF00) >> 8
                out += f"[button: {buttons[button_id] if button_id < len(buttons) else hex(button_id)}]"
                i += extra_size
                continue

            if tag == '\x15\x00':
                if include_sound:
                    detail = ord(text[i])
                    high = detail >> 8
                    low = detail & 0x00FF
                    character = characters[high]
                    out += f"[{character} thinking sound]"
                i += extra_size
                continue

            if tag == '\x15\x01':
                if include_lookat:
                    detail = ord(text[i])
                    character_name = characters[detail >> 8]
                    target = characters[detail & 0x00FF]
                    out += f"[look at: {character_name} -> {target}]"
                i += extra_size
                continue

            if tag == '\x17\x01':
                if include_pauses:
                    out += f"[pause: {ord(text[i])}]"
                i += extra_size
                continue

            if tag == '\x17\x02':
                detail = ord(text[i])
                high = detail >> 8
                low = detail & 0x00FF
                if low == 0x19:
                    character_name = characters[high]  
                    out += f"{character_name} (no icon): "
                elif low == 0x1a:
                    character_name = characters[high]  
                    out += f"{{{{icon|S.S. Drake}}}} "
                    if high != 5:
                        out += f"(speaker mismatch, should be {characters[high]}) "
                else:
                    character_name = characters[low % 5]   
                    emote = "neutral" if high == 5 else emotes[low // 5]
                    out += f"{{{{icon|{character_name}|v={emote}}}}} "
                    if high != low % 5:
                        out += f"(speaker mismatch, should be {characters[high]}) "

                i += extra_size
                continue
            
            if tag == '\x17\x03':
                if include_autoadvance:
                    out += f"[advance automatically]"
                i += extra_size
                continue

            if tag == '\x17\x04':
                name_len = ord(text[i]) // 2
                sound_name = text[i+1 : i+1 + name_len]
                if include_sound:
                    out += f"[sound: \"{sound_name}\", {ord(text[i+1 + name_len]) >> 8}]"
                i += extra_size
                continue
            
            out += f"[unknown tag: {ord(tag[0])}, {ord(tag[1])}: \"{text[i:i+extra_size]}\"]"
            i += extra_size
            continue
        
        out += text[i]
        i += 1
    return out


with open(filename, 'r') as f:
    data = eval(f.read())
    strings = data["strings"]
    for (name, lines) in strings.items():
        print("==" + name + "==\n")
        print(clean_text(lines) + "\n\n")