diff --git a/ToolsTOR.py b/ToolsTOR.py index 50f63e2..aefa0dc 100644 --- a/ToolsTOR.py +++ b/ToolsTOR.py @@ -59,19 +59,13 @@ class ToolsTOR(ToolsTales): super().__init__("TOR", tbl, "Tales-Of-Rebirth") with open("../{}/Data/{}/Misc/{}".format(self.repo_name, self.gameName, self.tblFile), encoding="utf-8") as f: - - jsonRaw = json.load(f) - self.jsonTblTags ={ k1:{ int(k2,16) if (k1 != "TBL") else k2:v2 for k2,v2 in jsonRaw[k1].items()} for k1,v1 in jsonRaw.items()} - - - - self.itable = dict([[i, struct.pack(">H", int(j))] for j, i in self.jsonTblTags['TBL'].items()]) - self.itags = dict([[i, j] for j, i in self.jsonTblTags['TAGS'].items()]) - if "NAME" in self.jsonTblTags.keys(): - self.inames = dict([[i, j] for j, i in self.jsonTblTags['NAME'].items()]) + jsonRaw = json.load(f) + + for k, v in jsonRaw.items(): + self.jsonTblTags[k] = {int(k2, 16): v2 for k2, v2 in v.items()} - if "COLOR" in self.jsonTblTags.keys(): - self.icolors = dict([[i, j] for j, i in self.jsonTblTags['COLOR'].items()]) + for k, v in self.jsonTblTags.items(): + self.ijsonTblTags[k] = {v2: k2 for k2, v2 in v.items()} self.id = 1 #byteCode @@ -479,100 +473,73 @@ class ToolsTOR(ToolsTales): #Convert a bytes object to text using TAGS and TBL in the json file def bytes_to_text(self, theirsce: Theirsce, offset=-1, end_strings = b"\x00"): - - finalText = '' - TAGS = self.jsonTblTags['TAGS'] - + finalText = "" + tags = self.jsonTblTags['TAGS'] + chars = self.jsonTblTags['TBL'] + if (offset > 0): theirsce.seek(offset, 0) - - pos = theirsce.tell() - b = theirsce.read(1) - while b != end_strings: - #print(hex(fileRead.tell())) - b = ord(b) - - if (b >= 0x99 and b <= 0x9F) or (b >= 0xE0 and b <= 0xEB): - c = (b << 8) + ord(theirsce.read(1)) - - # if str(c) not in json_data.keys(): - # json_data[str(c)] = char_index[decode(c)] - try: - finalText += (self.jsonTblTags['TBL'][str(c)]) - except KeyError: - b_u = (c >> 8) & 0xff - b_l = c & 0xff - finalText += ("{%02X}" % b_u) - finalText += ("{%02X}" % b_l) - elif b == 0x1: - finalText += ("\n") - elif b in (0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xB, 0xC, 0xD, 0xE, 0xF): - b2 = struct.unpack("" % (tag_name, b2)) - else: - finalText += "<%02X:%08X>" % (b, b2) - elif chr(b) in self.PRINTABLE_CHARS: - finalText += chr(b) - elif b >= 0xA1 and b < 0xE0: - finalText += struct.pack("B", b).decode("cp932") - elif b in (0x13, 0x17, 0x1A): - tag_name = f"Unk{b:02X}" - hex_value = "" - - while theirsce.read(1) != b"\x80": - theirsce.seek(theirsce.tell()-1) - mark = theirsce.read(1) - hex_value += mark.hex() - if mark == "\x38": - hex_value += f"{struct.unpack('> 8, c & 0xFF)) + continue + + if b == 0x1: + finalText += ("\n") + continue + + # ASCII text + if chr(b) in self.PRINTABLE_CHARS: + finalText += chr(b) + continue + + # cp932 text + if 0xA0 < b < 0xE0: + finalText += struct.pack("B", b).decode("cp932") + continue + + if b == 0x81: next_b = theirsce.read(1) if next_b == b"\x40": finalText += " " else: finalText += "{%02X}" % b finalText += "{%02X}" % ord(next_b) - else: - finalText += "{%02X}" % b - b = theirsce.read(1) + continue + + # Simple Tags + if 0x3 <= b <= 0xF: + parameter = theirsce.read_uint32() + + tag_name = tags.get(b, f"{b:02X}") + tag_param = self.jsonTblTags.get(tag_name.upper(), {}).get(parameter, None) + + if tag_param is not None: + finalText += tag_param + else: + finalText += f"<{tag_name}:{self.hex2(parameter)}>" + + continue + + # Variable tags (same as above but using rsce bytecode as parameter) + if 0x13 <= b <= 0x1A: + tag_name = f"unk{b:02X}" + parameter = "".join([f"{c:02X}" for c in theirsce.read_tag_bytes()]) + + finalText += f"<{tag_name}:{parameter}>" + continue + + # None of the above + finalText += "{%02X}" % b - end = theirsce.tell() - size = theirsce.tell() - pos - 1 - theirsce.seek(pos) - hex_string = theirsce.read(size).hex() - hex_values = ' '.join(a+b for a,b in zip(hex_string[::2], hex_string[1::2])) - theirsce.seek(end) - #return finalText, hex_values return finalText def get_Node_Bytes(self, entry_node): diff --git a/ToolsTales.py b/ToolsTales.py index ea38d7f..5158a4e 100644 --- a/ToolsTales.py +++ b/ToolsTales.py @@ -31,7 +31,8 @@ class ToolsTales: VALID_VOICEID = ['VSM_', 'voice_', 'VCT_'] def __init__(self, gameName, tblFile, repo_name): - + self.jsonTblTags = {} + self.ijsonTblTags = {} self.gameName = gameName self.repo_name = repo_name self.basePath = os.getcwd() @@ -493,67 +494,55 @@ class ToolsTales: #Convert text to Bytes object to reinsert text into THEIRSCE and other files def text_to_bytes(self, text): + multi_regex = (self.HEX_TAG + "|" + self.COMMON_TAG + r"|(\n)") + tokens = [sh for sh in re.split(multi_regex, text) if sh] - - - unames = [] - - splitLineBreak = text.split('\x0A') - nb = len(splitLineBreak) - - bytesFinal = b'' - i=0 - for line in splitLineBreak: - string_hex = re.split(self.HEX_TAG, line) - string_hex = [sh for sh in string_hex if sh] - #print(string_hex) - for s in string_hex: - if re.match(self.HEX_TAG, s): - bytesFinal += struct.pack("B", int(s[1:3], 16)) + output = b'' + for t in tokens: + # Hex literals + if re.match(self.HEX_TAG, t): + output += struct.pack("B", int(t[1:3], 16)) + + # Tags + elif re.match(self.COMMON_TAG, t): + tag, param, *_ = t[3][1:-1].split(":") + [None] + + if param is not None: + output += struct.pack("B", self.ijsonTblTags["TAGS"].get(tag, int(tag, 16))) + # FIXME + if tag.lower() in ("unk13", "unk17", "unk1a"): + splat = re.findall("..", param) + i = 0 + while i < len(splat): + if splat[i] == "38" and i + 2 < len(splat): + output += bytes.fromhex(splat[i]) + output += bytes.fromhex(splat[i + 2]) + output += bytes.fromhex(splat[i + 1]) + i += 3 + else: + output += bytes.fromhex(splat[i]) + i += 1 + + output += bytes.fromhex("80") + elif "unk" in tag.lower: + output += bytes.fromhex(param + "80") + else: + output += struct.pack("=2 and i> 3) & 3 + + if size_mask == 1: data += self.read(1) + elif size_mask == 2: data += self.read(2) + elif size_mask == 3: data += self.read(4) + + elif opcode < 0xF0: + data += self.read(1) + + elif opcode < 0xF8: + if (0xF2 <= opcode < 0xF5) or opcode == 0xF7: + data += self.read(2) + elif opcode == 0xF5: + data += self.read(4) + elif opcode == 0xF6: + data += self.read(1) + for _ in range(data[-1]): + if ord(data[-1]) & 8 != 0: + data += self.read(2) + else: + data += self.read(3) + + elif opcode < 0xFC: + data += self.read(2) + + self.read(1) + return data + def read_opcode(self): pos = self.tell() opcode = self.read_uint8()