-

   rss_rss_hh_new

 - e-mail

 

 -

 LiveInternet.ru:
: 17.03.2011
:
:
: 51

:


[] Clocktower The First Fear

, 31 2017 . 17:15 +
survival horror, , , -.


ClockTower ( Clocktower The First Fear) , Human Entertainment Super Nintendo.



point and click adventure, survival horror. , , . , , , , .

, , - ( , ), - , ( Resident Evil 3 ):



, , , , , ( Illbleed).

1994 SNES, PSX 1997 , Wonderswan ( Wonderswan), , , PC ( PC 1999 ).

, ROM SNES Aeon Genesis (, ), SNES PC, , FMV- .. , PSX, .

CD!

1


, :



BG, - .MAP, , , :



DATA, PTN PYX , , , - .

FACE, bmp , :



, :



PATTERN ABM. , , .

SCE : CT.ADO CT.ADT. , , .

SNDDATA MIDI WAV .

VISUAL , .. BMP. .



, DATA.BIN, , . , ct32.exe.

CD, :



, . , , , (.. CD).

2 NoCD


IDA, , RegQueryValueEx, . ?



, .

.

, , , :



, ! NOREG. , , , , . , , NOREG. jz 0xEB ( JMP).

:



!

3


, ? , , . (, CD), , - (, DATA?). :



, SHIFT-JIS ( ), 0x80-0x8F - .

notepad++, Google Translate:



, , . !



, PTN PYX . SCE.



, CT.ADT ( 0x100, 4 ).

CT.ADO





- ASCII, , SHIFT-JIS. , . , .

4 ADO/ADT


, ADT, , ADO:



(ADC Object File), 0xFF 256, , , . , -!

, , , ADT. , , , - .

.BMP, , :

39FF ( , 0x0100, , WORD), ASCII, , . BMP FACE, 0xFF39!

:



! , . Shift-JIS, , :



! 0xFF33, 16- (0x0F00), Shift-JIS.

: , SHIFT-JIS , . , . , , (0x0a) 0x00. ASCII 0x00 ( ). ASCII (0-127) , .

, , - (, ( 0x28FF).

, , ADO . , , . switch , ( case), , ( ).

(0xFF20, 0xFF87) ADO, , . , , .



, , :



, . , ! .



, . JMP

, JMP (0xFF22) 0x17.

IDA ADO_offset, , 0x1B32. , ? :



!

0x17 * 4 = 0x5C, ADT . , CALL (0xFF23) , - ADT 0xFF00. , , ( +2 ). - RETN? , .

, ADT , ADO. ? , , , ( ).



, , ADC (CT.ADO) 0x8000 int16, 0x8000, 32 . ADO . , , ( NOP).



32 ( , ; ), ADT - ( ADT 4 ).



, , , - :



ADT, , ADO ( RETN 0x253F4). ADT 0x453F4. , , , .

, ADT ( : , 0x8000 ). , . , ( ).

4: CTTDTI


, ADO. , ADT, . ADO , - , . , ADO . ?

, , , , , - :

0xE92 25 blahblahblah

cttd.py:

'''
 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()

CT.ADO CT_J.ADO, .

ADO, 0xFF33, 6 ( ), , , .

, 0x0a ( ) [NEWLINE]. , , , , .

- : translator. Python, Google Translate, , :

cttt.py:

#!/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()

, ASCII , , , . , ADO ( ADT, , ), ADT ADO:

ctti.py:

'''
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(" offset["offset"]):
			final_adj += offset["val"]
	g.write(struct.pack("code>

, :



!

, , - Clocktower rtf .



! :



׸ !

- , IDA , :





, ADO , , .



struct a1 malloc, , . , , :



( cmp5) ADO 5 * 0x8000, ADO EOF ( ). ADO 0x28000. ? ! SCE

ADO 5 6, , ? , ADT



, ADT 0x00 struct_head + 0x2A 0x7D0 ? 0x7D0??? , 0x8000.

0x4800 ADT. , ADT , , 0x2E, ADO !

struct 0x2A 0x2E:



! - -.

, . ?

CT32.exe :

 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

5 SCEDASM SCE


, /.

- :

'''
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("

, , ADO/ADT.

6 PSX


PSX ADO/ADT. , PSX PC.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332882/

:  

: [1] []
 

:
: 

: ( )

:

  URL