0xE92 25 blahblahblah
''' CTD - Clocktower Text Dumper by rFx ''' import os,sys,struct,binascii f = open("CT_J.ADO","rb") data = f.read() f.close() g = open("ct_txt.txt","wb") for i in range(0,len(data)-1): if(data[i] == '\x33' and data[i+1] == '\xff'): # 6 - , . i+=6 str_offset = i str_end = data[i:].index('\xff') -1 newstr = data[i:i+str_end] strlen = len(newstr) newstr = newstr.replace("\x0a\x00","[NEWLINE]") # ASCII, . newstr = newstr.replace("\x00","") g.write("%#x\t%d\t" % (str_offset,strlen)) g.write(newstr) g.write("\n") g.close()
#!/usr/bin/env python # -*- encoding: utf-8 -*- ''' Clocktower Auto Translator by rFx ''' import os,sys,binascii,struct from translate import Translator translator = Translator(to_lang="en") #Set to English by Default f = open("ct_txt.txt","rb") g = open("ct_txt_proc2.txt","wb") proc_str = [] for line in f.readlines(): proc_str.append(line.rstrip()) for x in range(0,len(proc_str)): line = proc_str[x] o,l,instr = line.split("\t") ts = translator.translate(instr.decode("SHIFT-JIS").encode("UTF-8")) ts = ts.encode("SHIFT-JIS","replace") proc_str[x] = "%s\t%s\t%s" % (o,l,ts) g.write(proc_str[x]+"\n") #for pc in proc_str: # g.write(pc) g.close()
''' Clocktower Text Injector by rFx ''' import os,sys,struct,binascii def is_ascii(s): return all(ord(c) < 128 for c in s) def get_real_offset(offset): # high_val = offset & 0xFFFF0000 high_val /= 2 low_val = offset & 0xFFFF return high_val+low_val def get_fake_offset(offset): # mult = int(offset / 0x8000) shft_val = 0x8000 * mult low_val = offset & 0xFFFF return offset + shft_val f = open("CT_J.ADO","rb") data = f.read() f.close() offset_vals = [] adt_list = [] newdata = "" f = open("ct_txt_proc.txt","rb") lines = f.readlines() o,l,s = lines[0].split("\t") first_offset = int(o,16) o,l,s = lines[0].split("\t") last_offset_strend = int(o,16) + int(l) newdata = data[:first_offset] for i in range(0,len(lines)): line = lines[i] offset, osl, instr = line.split("\t") offset = int(offset,16) instr = instr.rstrip('\n') instr = instr.replace("[NEWLINE]","\x0a") # ASCII. instr = instr.decode("SHIFT-JIS") newstr = "" for char in instr: if(is_ascii(char)): newstr+=char+'\x00' else: newstr+=char instr = newstr instr = instr.encode("SHIFT-JIS") newstrlen = len(instr) osl = int(osl) strldiff = newstrlen - osl # if(i < len(lines)-1): nextline = lines[i+1] nextoffset,nsl,nstr = nextline.split("\t") offset_vals.append({"offset":offset,"val":strldiff}) nextoffset = int(nextoffset,16) newdata += instr+data[offset+osl:nextoffset] else: offset_vals.append({"offset":offset,"val":strldiff}) newdata += instr + data[offset+osl:] # EOF f.close() # ADO. g = open("CT.ADO","wb") g.write(newdata) g.close() # ADT. f = open("CT_J.ADT","rb") datat = f.read() f.close() g = open("CT.ADT","wb") for i in range(0,len(datat),4): cur_offset = get_real_offset(struct.unpack("<I",datat[i:i+4])[0]) final_adj = 0 for offset in offset_vals: if(cur_offset > offset["offset"]): final_adj += offset["val"] g.write(struct.pack("<I",get_fake_offset(cur_offset + final_adj))) g.close()
529B: 74 EB BC7B: 2A 2E BC8D: D0 CC BD35: 2A 2E BD62: 2A 2E D4DA: 2A 2E D4FC: 2A 2E DA58: 2A 2E DA79: 2A 2E 103DA: 2A 2E 10407: 2A 2E 104F8: 2A 2E 105BB: 2A 2E 105E8: 2A 2E 10703: 2A 2E 10730: 2A 2E 115FA: 2A 2E 116B2: 05 06 116E8: 05 06 11720: 2A 2E 11729: D0 CC 1195D: 05 06 1C50F: 20 00
''' Clocktower ADC Object File Disassembler by rFx ''' import os,sys,binascii,struct ADO_FILENAME = "CT_J.ADO" ADT_FILENAME = "CT_J.ADT" ADO_OP = { 0xFF00:"RETN", #Scene Prologue - 0 bytes of data. - Also an END value... the game looks to denote endings. 0xFF01:"UNK_01", # varying length data 0xFF02:"UNK_02", # 3 bytes of data 0xFF03:"UNK_03", # 3 bytes of data 0xFF04:"UNK_04", # 3 bytes of data 0xFF05:"UNK_05", # 3 bytes of data 0xFF06:"UNK_06", # 3 bytes of data 0xFF07:"UNK_07", # 3 bytes of data 0xFF0A:"UNK_0A", # 4 bytes of data. Looks like an offset to another link in the list? 0xFF0C:"UNK_0C", # 4 bytes of data 0xFF0D:"UNK_0D", # 4 bytes of data 0xFF10:"UNK_10", # 4 bytes of data 0xFF11:"UNK_11", # 4 bytes of data 0xFF12:"UNK_12", # 4 bytes of data 0xFF13:"UNK_13", # 4 bytes of data 0xFF14:"UNK_14", # 4 bytes of data 0xFF15:"UNK_15", # 4 bytes of data 0xFF16:"UNK_16", # 4 bytes of data 0xFF1F:"UNK_1F", # 0 bytes of data 0xFF20:"ALL", # 0 bytes of data. Only at the end of the ADO (twice) #All opcodes above this are like... prologue opcodes (basically in some other list) 0xFF21:"ALLEND", # 2 bytes of data 0xFF22:"JMP", # 2 bytes of data - I think it uses the value for the int offset in adt as destination +adds 2 0xFF23:"CALL", # 6 bytes of data 0xFF24:"EVDEF", # Not used in the game 0xFF25:"!!!!!!", #Not used in the game 0xFF26:"!!!!!!", #Not used in the game 0xFF27:"!!!!!!", #Not used in the game 0xFF28:"!!!!!!", #0 bytes of data. 0xFF29:"END_IF", # 4 bytes of data 0xFF2A:"WHILE", # 4 bytes of data 0xFF2B:"NOP", # 0 bytes of data 0xFF2C:"BREAK", # Not used in the game 0xFF2D:"ENDIF", # 2 bytes of data 0xFF2E:"ENDWHILE", # 2 bytes of data 0xFF2F:"ELSE", # 2 bytes of data 0xFF30:"MSGINIT", # 10 bytes of data 0xFF31:"MSGTYPE", # Not used in the game 0xFF32:"MSGATTR", # 16 bytes of data 0xFF33:"MSGOUT", # Varying length, our in-game text uses this. :) 0xFF34:"SETMARK", #Varying length 0xFF35:"SETWAIT", #Not used in the game 0xFF36:"MSGWAIT", #0 bytes of data 0xFF37:"EVSTART", #4 bytes of data 0xFF38:"BGFILEDISP", #Not used in the game. 0xFF39:"BGLOAD", #Varying length, normally a path to a BMP file is passed in. 0xFF3A:"PALLOAD", #Varying length. Also takes BMP files. 0xFF3B:"BGMREQ", #Varying length - loads a MIDI file into memory. 0xFF3C:"SPRCLR", #2 bytes of data. 0xFF3D:"ABSOBJANIM", #Not used in the game 0xFF3E:"OBJANIM", #Not used in the game. 0xFF3F:"ALLSPRCLR", #0 bytes of data 0xFF40:"MSGCLR", #0 bytes 0f data 0xFF41:"SCREENCLR", #0 bytes of data 0xFF42:"SCREENON", #0 bytes of data 0xFF43:"SCREENOFF", #0 bytes of data 0xFF44:"SCREENIN", # Not used in the game. 0xFF45:"SCREENOUT", # Not used in the game. 0xFF46:"BGDISP", # Always 12 bytes of data. 0xFF47:"BGANIM", #14 bytes of data. 0xFF48:"BGSCROLL",#10 bytes of data. 0xFF49:"PALSET", #10 bytes of data. 0xFF4A:"BGWAIT", #0 bytes of data. 0xFF4B:"WAIT", #4 bytes of data. 0xFF4C:"BWAIT", #Not used in the game. 0xFF4D:"BOXFILL", #14 bytes of data. 0xFF4E:"BGCLR", # Not used in the game. 0xFF4F:"SETBKCOL", #6 bytes of data. 0xFF50:"MSGCOL", #Not used in the game. 0xFF51:"MSGSPD", #2 bytes of data. 0xFF52:"MAPINIT", #12 bytes of data. 0xFF53:"MAPLOAD", #Two Paths... Sometimes NULL NULL - Loads the background blit bmp and the map file to load it. 0xFF54:"MAPDISP", #Not used in the game. 0xFF55:"SPRENT", #16 bytes of data. 0xFF56:"SETPROC", #2 bytes of data. 0xFF57:"SCEINIT", #0 bytes of data. 0xFF58:"USERCTL", #2 bytes of data. 0xFF59:"MAPATTR", #2 bytes of data. 0xFF5A:"MAPPOS", #6 bytes of data. 0xFF5B:"SPRPOS", #8 bytes of data. 0xFF5C:"SPRANIM", #8 bytes of data. 0xFF5D:"SPRDIR", #10 bytes of data. 0xFF5E:"GAMEINIT", #0 bytes of data. 0xFF5F:"CONTINIT", #0 bytes of data. 0xFF60:"SCEEND", #0 bytes of data. 0xFF61:"MAPSCROLL", #6 bytes of data. 0xFF62:"SPRLMT", #6 bytes of data. 0xFF63:"SPRWALKX", #10 bytes of data. 0xFF64:"ALLSPRDISP", #Not used in the game. 0xFF65:"MAPWRT", #Not used in the game. 0xFF66:"SPRWAIT", #2 bytes of data. 0xFF67:"SEREQ", #Varying length - loads a .WAV file. 0xFF68:"SNDSTOP", #0 bytes of data. 0xFF69:"SESTOP", #Varying length - specifies a .WAV to stop or ALL for all sounds. 0xFF6A:"BGMSTOP", #0 bytes of data. 0xFF6B:"DOORNOSET", #0 bytes of data. 0xFF6C:"RAND", #6 bytes of data. 0xFF6D:"BTWAIT", #2 bytes of data 0xFF6E:"FAWAIT", #0 bytes of data 0xFF6F:"SCLBLOCK", #Varying length - no idea. 0xFF70:"EVSTOP", #Not used in the game. 0xFF71:"SEREQPV", #Varying length - .WAV path input, I think this is to play and repeat. 0xFF72:"SEREQSPR", #Varying length - .WAV path input, I think this is like SEREQPV except different somehow. 0xFF73:"SCERESET", #0 bytes of data. 0xFF74:"BGSPRENT", #12 bytes of data. 0xFF75:"BGSPRPOS", #Not used in the game. 0xFF76:"BGSPRSET", #Not used in the game. 0xFF77:"SLANTSET", #8 bytes of data. 0xFF78:"SLANTCLR", #0 bytes of data. 0xFF79:"DUMMY", #Not used in the game. 0xFF7A:"SPCFUNC", #Varying length - usage uncertain. 0xFF7B:"SEPAN", #Varying length - guessing to set the L/R of Stereo SE. 0xFF7C:"SEVOL", #Varying length - guessing toe set the volume level of SE 0xFF7D:"BGDISPTRN", #14 bytes of data. 0xFF7E:"DEBUG", #Not used in the game. 0xFF7F:"TRACE", #Not used in the game. 0xFF80:"TMWAIT", #4 bytes of data. 0xFF81:"BGSPRANIM", #18 bytes of data. 0xFF82:"ABSSPRENT", #Not used in the game. 0xFF83:"NEXTCOM", #2 bytes of data. 0xFF84:"WORKCLR", #0 bytes of data. 0xFF85:"BGBUFCLR", #4 bytes of data. 0xFF86:"ABSBGSPRENT", #12 bytes of data. 0xFF87:"AVIPLAY", #This one is used only once - to load the intro AVI file. 0xFF88:"AVISTOP", #0 bytes of data. 0xFF89:"SPRMARK", #Only used in PSX Version. 0xFF8A:"BGMATTR",#Only used in PSX Version. #BIG GAP IN OPCODES... maybe not even in existence. 0xFFA0:"UNK_A0", #12 bytes of data. 0xFFB0:"UNK_B0", #12 bytes of data. 0xFFDF:"UNK_DF", #2 bytes of data. 0xFFE0:"UNK_E0", #0 bytes of data. 0xFFEA:"UNK_EA", #0 bytes of data. 0xFFEF:"UNK_EF" #12 bytes of data. } if(__name__=="__main__"): print("#Disassembling ADO/ADT...") #Read ADO/ADT Data to memory. f = open(ADO_FILENAME,"rb") ado_data = f.read() f.close() f = open(ADT_FILENAME,"rb") adt_data = f.read() f.close() scene_count = -1 #Skip ADO Header i = 256 while i < (len(ado_data) -1): cur_val = struct.unpack("<H",ado_data[i:i+2])[0] if(cur_val in ADO_OP.keys()): #0xFF00 if(cur_val == 0xFF00): scene_count +=1 print("#----SCENE %d (Offset %#x)" % (scene_count,i)) print(ADO_OP[cur_val]) i+=2 elif(cur_val == 0xFF1F or cur_val == 0xFF20 or cur_val == 0xFF84 or cur_val == 0xFFEA or cur_val == 0xFFE0 or cur_val == 0xFF88 or cur_val == 0xFF78 or cur_val == 0xFF73 or cur_val == 0xFF6E or cur_val == 0xFF6B or cur_val == 0xFF6A or cur_val == 0xFF68 or cur_val == 0xFF60 or cur_val == 0xFF5F or cur_val == 0xFF5E or cur_val == 0xFF57 or cur_val == 0xFF4A or cur_val == 0xFF43 or cur_val == 0xFF42 or cur_val == 0xFF41 or cur_val == 0xFF40 or cur_val == 0xFF36 or cur_val == 0xFF3F or cur_val == 0xFF36 or cur_val == 0xFF2B or cur_val == 0xFF28): print(ADO_OP[cur_val]) i+=2 #0xFF22 elif(cur_val == 0xFF22 or cur_val == 0xFF51 or cur_val == 0xFF21 or cur_val == 0xFF2D or cur_val == 0xFF2E or cur_val == 0xFF2F or cur_val == 0xFF3C or cur_val == 0xFF56 or cur_val == 0xFF58 or cur_val == 0xFF59 or cur_val == 0xFF66 or cur_val == 0xFF6D or cur_val == 0xFF83 or cur_val == 0xFFDF): i+=2 jmpdata = struct.unpack("<H",ado_data[i:i+2])[0] print("%s %d" % (ADO_OP[cur_val],jmpdata)) i+=2 #0xFF23 elif(cur_val == 0xFF23): i+=2 val_1 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_2 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_3 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 print("%s %#x %#x %#x" % (ADO_OP[cur_val],val_1,val_2,val_3)) elif cur_val == 0xFF29 or cur_val == 0xFF2A or cur_val == 0xFF37: i+=2 val_1 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_2 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 print("%s %d %d" % (ADO_OP[cur_val],val_1,val_2)) elif cur_val in range(0xFF02,0xFF08): i+=2 pri_val = struct.unpack("b",ado_data[i])[0] i+=1 sec_val = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 print("%s %d %d" % (ADO_OP[cur_val],pri_val,sec_val)) elif cur_val in range(0xFF0A,0xFF17): i+=2 pri_val = struct.unpack("<I",ado_data[i:i+4])[0] i+=4 print("%s %#x" % (ADO_OP[cur_val],pri_val)) elif (cur_val == 0xFF30): i+=2 val_1 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_2 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_3 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_4 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_5 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 print("%s %#x %#x %#x %#x %#x" % (ADO_OP[cur_val],val_1,val_2,val_3,val_4,val_5)) elif (cur_val == 0xFF33): i+=2 val_1 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_2 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 endstr_offset = ado_data[i:].index("\xff") endstr_offset -=1 instr = ado_data[i:i+endstr_offset] i+= len(instr) #Decode to UTF-8 instr = instr.replace("\x0a\x00","[NEWLINE]") instr = instr.replace("\x00","[NULL]") instr = instr.decode("SHIFT-JIS") instr = instr.encode("UTF-8") print("%s %#x %#x ``%s``" % (ADO_OP[cur_val],val_1,val_2,instr)) elif (cur_val == 0xFF32): i+=2 val_1 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_2 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_3 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_4 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_5 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_6 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_7 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_8 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 print("%s %#x %#x %#x %#x %#x %#x %#x %#x" % (ADO_OP[cur_val],val_1,val_2,val_3,val_4,val_5,val_6,val_7,val_8)) elif(cur_val == 0xFF34): i+=2 endval_offset = ado_data[i:].index("\xff") - 1 instr = ado_data[i:i+endstr_offset] i+= len(instr) print("%s %s" % (ADO_OP[cur_val],binascii.hexlify(instr))) i+=2 elif(cur_val in range(0xFF39,0xFF3C) or cur_val == 0xFF67): i+=2 val_1 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 endstr_offset = ado_data[i:].index("\xff") - 1 instr = ado_data[i:i+endstr_offset] i+= len(instr) if(instr.find("\x00\x00\x00") != -1): finstr = instr[:instr.index("\x00")] val_2 = struct.unpack("b",instr[instr.index("\x00")+1:instr.index("\x00")+2])[0] val_3 = struct.unpack("b",instr[instr.index("\x00")+2:])[0] print("%s %#x %s %#x %#x" % (ADO_OP[cur_val],val_1,finstr,val_2,val_3)) elif(instr.find("\x00\x00") != -1): finstr = instr[:instr.index("\x00")] val_2 = struct.unpack("b",instr[instr.index("\x00")+1:])[0] print("%s %#x %s %#x" % (ADO_OP[cur_val],val_1,finstr,val_2)) elif(cur_val == 0xFF69): i+=2 endstr_offset = ado_data[i:].index("\xff") - 1 instr = ado_data[i:i+endstr_offset] i+= len(instr) if(instr.find("\x00\x00\x00") != -1): finstr = instr[:instr.index("\x00")] val_2 = struct.unpack("b",instr[instr.index("\x00")+1:instr.index("\x00")+2])[0] val_3 = struct.unpack("b",instr[instr.index("\x00")+2:])[0] print("%s %s %#x %#x" % (ADO_OP[cur_val],finstr,val_2,val_3)) elif(instr.find("\x00\x00") != -1): finstr = instr[:instr.index("\x00")] val_2 = struct.unpack("b",instr[instr.index("\x00")+1:])[0] print("%s %s %#x" % (ADO_OP[cur_val],finstr,val_2)) elif(cur_val == 0xFF71 or cur_val == 0xFF72): i+=2 val_1 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_2 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_3 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 endstr_offset = ado_data[i:].index("\xff") - 1 instr = ado_data[i:i+endstr_offset] i+= len(instr) if(instr.find("\x00\x00\x00") != -1): finstr = instr[:instr.index("\x00")] val_4 = struct.unpack("b",instr[instr.index("\x00")+1:instr.index("\x00")+2])[0] val_5 = struct.unpack("b",instr[instr.index("\x00")+2:])[0] print("%s %#x %#x %#x %s %#x %#x" % (ADO_OP[cur_val],val_1,val_2,val_3,finstr,val_4,val_5)) elif(instr.find("\x00\x00") != -1): finstr = instr[:instr.index("\x00")] val_4 = struct.unpack("b",instr[instr.index("\x00")+1:])[0] print("%s %#x %#x %#x %s %#x" % (ADO_OP[cur_val],val_1,val_2,val_3,finstr,val_4)) elif(cur_val == 0xFF87): i+=2 val_1 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_2 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_3 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_4 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 val_5 = struct.unpack("<H",ado_data[i:i+2])[0] i+=2 endstr_offset = ado_data[i:].index("\xff") - 1 instr = ado_data[i:i+endstr_offset] i+= len(instr) if(instr.find("\x00\x00\x00") != -1): finstr = instr[:instr.index("\x00")] val_6 = struct.unpack("b",instr[instr.index("\x00")+1:instr.index("\x00")+2])[0] val_7 = struct.unpack("b",instr[instr.index("\x00")+2:])[0] print("%s %#x %#x %#x %#x %#x %s %#x %#x" % (ADO_OP[cur_val],val_1,val_2,val_3,val_4,val_5,finstr,val_6,val_7)) elif(instr.find("\x00\x00") != -1): finstr = instr[:instr.index("\x00")] val_6 = struct.unpack("b",instr[instr.index("\x00")+1:])[0] print("%s %#x %#x %#x %#x %#x %s %#x" % (ADO_OP[cur_val],val_1,val_2,val_3,val_4,val_5,finstr,val_6)) #NOT DONE YET else: i+=1 else: i+=1
Source: https://habr.com/ru/post/332882/
All Articles