Hey guys.
Since I started on the walking graphics for Bleach: The 3rd Phantom, I figured I may as well go the full mile and handle the battle screen sprites too. Unfortunately, they're in a .cpk file that I'm having some trouble puzzling.
This is the cpk and
these are the files it yields using Quick BMS. I've tried using a .cpk unpacker as well, but it just gave me a bin file I couldn't use.
It looks like all the Bleach games use this same format, so if someone can help me with this, I'll be able to fill in the other games as well.
EDIT: Nevermind; forgot you could open individual files in Tinke too.
Okay, I've gone through all the files that are .CPKs, and there are a few that won't decompress using the script I have.
Here is a .zip of the CPKs that won't work.
Here's the BMS script I'm using to extract these:
Code:
# CRI CPK archives (script 0.3)
# derived from cpk_unpack of hcs - http://hcs64_com/vgm_ripping_html
# script for QuickBMS http://quickbms_aluigi_org
quickbmsver "0.5.32"
endian big
comtype cpk
idstring "CPK "
set query_offset long 0
set query_index long 0
set query_name string "TocOffset"
callfunction query_utf 1
set toc_offset long UTF_VALUE
if toc_offset == 0
set query_name string "ITocOffset"
callfunction query_utf 1
set toc_offset long UTF_VALUE
endif
set query_name string "ContentOffset"
callfunction query_utf 1
set content_offset long UTF_VALUE
set query_name string "Files"
callfunction query_utf 1
set CpkHeader_count long UTF_VALUE
set query_name string "Align"
callfunction query_utf 1
set CpkAlignment long UTF_VALUE
goto toc_offset
getdstring signature 4
if signature != "TOC "
if signature != "ITOC"
print "Error: TOC signature not found at offset %toc_offset|x%"
cleanexit
endif
endif
set query_offset long toc_offset
set query_index long 0
set query_name string ""
callfunction query_utf 1
set CpkHeader_count2 long UTF_VALUE
set toc_entries long table_info_rows # it remains saved after the call
if CpkHeader_count == 0
math CpkHeader_count = CpkHeader_count2
endif
set query_offset long toc_offset
set query_index long 0
set query_name string "FilesL"
callfunction query_utf 1
set itoc_filesl string UTF_VALUE
set query_name string "FilesH"
callfunction query_utf 1
set itoc_filesh string UTF_VALUE
set query_name string "DataL"
callfunction query_utf 1
set itoc_datal string UTF_VALUE
xmath itoc_datal "itoc_datal + toc_offset + 8 + table_info_data_offset"
set query_name string "DataH"
callfunction query_utf 1
set itoc_datah string UTF_VALUE
xmath itoc_datah "itoc_datah + toc_offset + 8 + table_info_data_offset"
math FORCE_CONTENT_OFFSET = 1
math query_offset = itoc_datah
for query_index = 0 < itoc_filesh
callfunction EXTRACT 1
xmath content_offset "file_offset + file_size"
next query_index
math FORCE_CONTENT_OFFSET = 1
math query_offset = itoc_datal
for query_index = 0 < itoc_filesl
callfunction EXTRACT 1
xmath content_offset "file_offset + file_size"
next query_index
math FORCE_CONTENT_OFFSET = 0
math query_offset = toc_offset
for query_index = 0 < toc_entries
callfunction EXTRACT 1
next query_index
startfunction EXTRACT
if content_offset < 0 # "if" can't be unsigned
set add_offset long query_offset
elif query_offset < 0
set add_offset long content_offset
elif content_offset < query_offset
set add_offset long content_offset
else
if FORCE_CONTENT_OFFSET != 0
set add_offset long content_offset
else
set add_offset long query_offset
endif
endif
set query_name string "DirName"
callfunction query_utf 1
set file_name string UTF_VALUE
set query_name string "FileName"
callfunction query_utf 1
set file_name2 string UTF_VALUE
string file_name += /
string file_name += file_name2
set query_name string "FileSize"
callfunction query_utf 1
set file_size long UTF_VALUE
set query_name string "ExtractSize"
callfunction query_utf 1
set extract_size long UTF_VALUE
set query_name string "FileOffset"
callfunction query_utf 1
set file_offset long UTF_VALUE
math file_offset += add_offset
if CpkAlignment != 0
if file_offset % CpkAlignment
xmath file_offset "file_offset + CpkAlignment - (file_offset % CpkAlignment)"
endif
endif
if extract_size > file_size
clog file_name file_offset file_size extract_size
else
log file_name file_offset file_size
endif
endfunction
startfunction query_utf
set COLUMN_STORAGE_MASK long 0xf0
set COLUMN_STORAGE_PERROW long 0x50
set COLUMN_STORAGE_CONSTANT long 0x30
set COLUMN_STORAGE_ZERO long 0x10
set COLUMN_TYPE_MASK long 0x0f
set COLUMN_TYPE_DATA long 0x0b
set COLUMN_TYPE_STRING long 0x0a
set COLUMN_TYPE_FLOAT long 0x08
set COLUMN_TYPE_8BYTE2 long 0x07
set COLUMN_TYPE_8BYTE long 0x06
set COLUMN_TYPE_4BYTE2 long 0x05
set COLUMN_TYPE_4BYTE long 0x04
set COLUMN_TYPE_2BYTE2 long 0x03
set COLUMN_TYPE_2BYTE long 0x02
set COLUMN_TYPE_1BYTE2 long 0x01
set COLUMN_TYPE_1BYTE long 0x00
set UTF_VALUE_OFFSET long 0
set UTF_VALUE string ""
xmath offset "query_offset + 0x10" # needed by the tool
goto offset
set table_info_table_offset long offset
getdstring UTF_signature 4
if UTF_signature != "@UTF"
print "Error: not a @UTF table at %offset|x%"
cleanexit
endif
get table_info_table_size long
set table_info_schema_offset long 0x20
get table_info_rows_offset long
get table_info_string_table_offset long
get table_info_data_offset long
get table_name_string long
get table_info_columns short
get table_info_row_width short
get table_info_rows long
for i = 0 < table_info_columns
get schema_type byte
get schema_column_name long
putarray 0 i schema_type
putarray 1 i schema_column_name
putarray 2 i -1 # schema_constant_offset
xmath TMP "schema_type & COLUMN_STORAGE_MASK"
if TMP == COLUMN_STORAGE_CONSTANT
savepos schema_constant_offset
putarray 2 i schema_constant_offset
xmath TMP "schema_type & COLUMN_TYPE_MASK"
if TMP == COLUMN_TYPE_STRING
getdstring DUMMY 4
elif TMP == COLUMN_TYPE_DATA
getdstring DUMMY 8
elif TMP == COLUMN_TYPE_FLOAT
getdstring DUMMY 4
elif TMP == COLUMN_TYPE_8BYTE2
getdstring DUMMY 8
elif TMP == COLUMN_TYPE_8BYTE
getdstring DUMMY 8
elif TMP == COLUMN_TYPE_4BYTE2
getdstring DUMMY 4
elif TMP == COLUMN_TYPE_4BYTE
getdstring DUMMY 4
elif TMP == COLUMN_TYPE_2BYTE2
getdstring DUMMY 2
elif TMP == COLUMN_TYPE_2BYTE
getdstring DUMMY 2
elif TMP == COLUMN_TYPE_1BYTE2
getdstring DUMMY 1
elif TMP == COLUMN_TYPE_1BYTE
getdstring DUMMY 1
else
print "Error: unknown type for constant %TMP%"
cleanexit
endif
endif
next i
xmath TMP "table_info_string_table_offset + 8 + offset"
xmath string_table_size "table_info_data_offset - table_info_string_table_offset"
log MEMORY_FILE TMP string_table_size
for i = query_index < table_info_rows
xmath row_offset "table_info_table_offset + 8 + table_info_rows_offset + (i * table_info_row_width)"
for j = 0 < table_info_columns
getarray type 0 j
getarray column_name 1 j
getarray constant_offset 2 j
if constant_offset >= 0
math data_offset = constant_offset
else
math data_offset = row_offset
endif
xmath TMP "type & COLUMN_STORAGE_MASK"
if TMP == COLUMN_STORAGE_ZERO
set value long 0
else
goto data_offset
xmath TMP "type & COLUMN_TYPE_MASK"
if TMP == COLUMN_TYPE_STRING
get string_offset long
goto string_offset MEMORY_FILE
get value string MEMORY_FILE
elif TMP == COLUMN_TYPE_DATA
get vardata_offset long
get vardata_size long
# currently ignore it
#goto vardata_offset MEMORY_FILE
#getdstring value vardata_size MEMORY_FILE
set value string vardata_offset
elif TMP == COLUMN_TYPE_FLOAT
get value long
elif TMP == COLUMN_TYPE_8BYTE2
get DUMMY long # no 64 bit support!
get value long
elif TMP == COLUMN_TYPE_8BYTE
get DUMMY long # no 64 bit support!
get value long
elif TMP == COLUMN_TYPE_4BYTE2
get value long
elif TMP == COLUMN_TYPE_4BYTE
get value long
elif TMP == COLUMN_TYPE_2BYTE2
get value short
elif TMP == COLUMN_TYPE_2BYTE
get value short
elif TMP == COLUMN_TYPE_1BYTE2
get value byte
elif TMP == COLUMN_TYPE_1BYTE
get value byte
else
print "Error: unknown normal type %TMP%"
cleanexit
endif
if constant_offset < 0
savepos row_offset # row_offset += bytes_read
endif
endif
goto column_name MEMORY_FILE
get column_name string MEMORY_FILE
if column_name == query_name
set UTF_VALUE string value # result_value_value (qthis)
math i = table_info_rows # break
math j = table_info_columns # break
endif
next j
next i
endfunction
Just a small update: I've tried just about every other CPK unpacker I can find and haven't had much luck. Tried looking at the header between ones that have worked and ones that haven't, and I can't find anything that stands out.
If anyone has any ideas, I'd appreciate it. I'd hate only to leave this half finished.
Unfortunately I don't know enough about CPK unpackers to be of any help for this specific problem, but in the event that it doesn't work out, would GLintercept be an option for you or is that too much work? It seems quick enough, but I'm not sure how many units are in the game, or how much variety they have in their attacks. At least the frame count seems relatively small.
Here's a few example frames I pieced together in a few minutes using the data that GLintercept spit out.
I... wouldn't mind using it, but I'm not sure how it's supposed to work? I've never heard of this program before.
This thread could be useful:
http://www.vg-resource.com/thread-28571-...#pid607792
I ripped Astonishia Story from PSP using GLIntercept, but it works the same for DS. Put the contents of GLintercept into the directory of the emulator, change some text in the GLconfig.ini (not having useless icons, determine hotkey, set GLintercept to get what's on the screen -> still objects // or let it run until you press a key to stop it -> animations). You can see the text changes in the thread linked above.
Ah, and in the video configurations of your emulator -> set it to OpenGL. That should be all. Don't expect miracles, though, as I wasn't able to get Black Sigil: Blade of the Exiled (DS) to work with it. It could be the game itself which doesn't like the tool, but I haven't tested it on any other DS game so I'm not sure.
Welp, that caused my emulator to crash. Not sure why, but I'm suspecting it's one of those "my laptop is old and sucks" things.
Either way, that's a pretty slow way to do it; the game is very long, and there are a lot of characters, some of which are easily missable. It'll be much more efficient to figure out why these CPKs aren't extracting while others did.
(10-11-2016, 09:10 AM)Skyla Doragono Wrote: [ -> ]Either way, that's a pretty slow way to do it; the game is very long, and there are a lot of characters, some of which are easily missable. It'll be much more efficient to figure out why these CPKs aren't extracting while others did.
Yeah, it's fairly slow, which is why I brought up the number of units and things in the first place. CPK's would definitely be a more quick method, but this is ultimately better than nothing. You mentioned the game is long though, so it's probably not worth the time to play through it and rip it with GLintercept.
(10-11-2016, 08:49 AM)Davy Jones Wrote: [ -> ]Don't expect miracles, though, as I wasn't able to get Black Sigil: Blade of the Exiled (DS) to work with it. It could be the game itself which doesn't like the tool, but I haven't tested it on any other DS game so I'm not sure.
It only works on games which put their graphics on the 3D layer. That would be my guess as to why it didn't work on Sigil. My rule of thumb is if it can't be found in the Tile Viewer, it can be obtained with GLintercept
(and vice versa). Thanks for posting that thread though! Much appreciated!
Yeah, there are:
53 playable combat units.
5 playable non-combat units.
4 non-playable, non-combat units.
38 enemy combat units.
1 enemy non-combat unit.
With the exception of the non-combatant enemy unit, each unit has a regular attack and a special attack, and the special attack only happens if you happen to get a critical, or if you're attacking a unit that you're "effective" against. Each character also has blocking, damage, and death frames, which would mean deliberately putting non-combat units in danger (and either getting multiple game overs or save/reload abuse). In addition to this, 13 of the playable characters also have some other form they can turn into, which also has regular attack, special attack, blocking, damage, and death frames. Also, two of the playable characters are only unlocked completing mini missions between chapters in the story mode, which are stupidly hard and annoying. Speaking of those mini missions, the only way to unlock the main character's Bankai for the story mode is by completing those missions, otherwise you'd have to complete the game to get it. Oh, and there are two main heroes, which would mean playing through the game twice.
Yeah. Tiny anime game has a lot of stuff to it.