from typing import Tuple cv64_char_dict = {"\n": (0x01, 0), " ": (0x02, 4), "!": (0x03, 2), '"': (0x04, 5), "#": (0x05, 6), "$": (0x06, 5), "%": (0x07, 8), "&": (0x08, 7), "'": (0x09, 4), "(": (0x0A, 3), ")": (0x0B, 3), "*": (0x0C, 4), "+": (0x0D, 5), ",": (0x0E, 3), "-": (0x0F, 4), ".": (0x10, 3), "/": (0x11, 6), "0": (0x12, 5), "1": (0x13, 3), "2": (0x14, 5), "3": (0x15, 4), "4": (0x16, 5), "5": (0x17, 5), "6": (0x18, 5), "7": (0x19, 5), "8": (0x1A, 5), "9": (0x1B, 5), ":": (0x1C, 3), ";": (0x1D, 3), "<": (0x1E, 3), "=": (0x1F, 4), ">": (0x20, 3), "?": (0x21, 5), "@": (0x22, 8), "A": (0x23, 7), "B": (0x24, 6), "C": (0x25, 5), "D": (0x26, 7), "E": (0x27, 5), "F": (0x28, 6), "G": (0x29, 6), "H": (0x2A, 7), "I": (0x2B, 3), "J": (0x2C, 3), "K": (0x2D, 6), "L": (0x2E, 6), "M": (0x2F, 8), "N": (0x30, 7), "O": (0x31, 6), "P": (0x32, 6), "Q": (0x33, 8), "R": (0x34, 6), "S": (0x35, 5), "T": (0x36, 6), "U": (0x37, 6), "V": (0x38, 7), "W": (0x39, 8), "X": (0x3A, 6), "Y": (0x3B, 7), "Z": (0x3C, 6), "[": (0x3D, 3), "\\": (0x3E, 6), "]": (0x3F, 3), "^": (0x40, 6), "_": (0x41, 5), "a": (0x43, 5), "b": (0x44, 6), "c": (0x45, 4), "d": (0x46, 6), "e": (0x47, 5), "f": (0x48, 5), "g": (0x49, 5), "h": (0x4A, 6), "i": (0x4B, 3), "j": (0x4C, 3), "k": (0x4D, 6), "l": (0x4E, 3), "m": (0x4F, 8), "n": (0x50, 6), "o": (0x51, 5), "p": (0x52, 5), "q": (0x53, 5), "r": (0x54, 4), "s": (0x55, 4), "t": (0x56, 4), "u": (0x57, 5), "v": (0x58, 6), "w": (0x59, 8), "x": (0x5A, 5), "y": (0x5B, 5), "z": (0x5C, 4), "{": (0x5D, 4), "|": (0x5E, 2), "}": (0x5F, 3), "`": (0x61, 4), "「": (0x62, 3), "」": (0x63, 3), "~": (0x65, 3), "″": (0x72, 3), "°": (0x73, 3), "∞": (0x74, 8)} # [0] = CV64's in-game ID for that text character. # [1] = How much space towards the in-game line length limit it contributes. def cv64_string_to_bytearray(cv64text: str, a_advance: bool = False, append_end: bool = True) -> bytearray: """Converts a string into a bytearray following CV64's string format.""" text_bytes = bytearray(0) for i, char in enumerate(cv64text): if char == "\t": text_bytes.extend([0xFF, 0xFF]) else: if char in cv64_char_dict: text_bytes.extend([0x00, cv64_char_dict[char][0]]) else: text_bytes.extend([0x00, 0x21]) if a_advance: text_bytes.extend([0xA3, 0x00]) if append_end: text_bytes.extend([0xFF, 0xFF]) return text_bytes def cv64_text_truncate(cv64text: str, textbox_len_limit: int) -> str: """Truncates a string at a given in-game text line length.""" line_len = 0 for i in range(len(cv64text)): if cv64text[i] in cv64_char_dict: line_len += cv64_char_dict[cv64text[i]][1] else: line_len += 5 if line_len > textbox_len_limit: return cv64text[0x00:i] return cv64text def cv64_text_wrap(cv64text: str, textbox_len_limit: int) -> Tuple[str, int]: """Rebuilds a string with some of its spaces replaced with newlines to ensure the text wraps properly in an in-game textbox of a given length.""" words = cv64text.split(" ") new_text = "" line_len = 0 num_lines = 1 for i in range(len(words)): word_len = 0 word_divider = " " if line_len != 0: line_len += 4 else: word_divider = "" for char in words[i]: if char in cv64_char_dict: line_len += cv64_char_dict[char][1] word_len += cv64_char_dict[char][1] else: line_len += 5 word_len += 5 if word_len > textbox_len_limit or char in ["\n", "\t"]: word_len = 0 line_len = 0 if num_lines < 4: num_lines += 1 if line_len > textbox_len_limit: word_divider = "\n" line_len = word_len if num_lines < 4: num_lines += 1 new_text += word_divider + words[i] return new_text, num_lines