Users browsing this thread:
Bleach Fighting Sprites
#1
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. Cute


EDIT: Nevermind; forgot you could open individual files in Tinke too.
Reply
Thanked by:
#2
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
Reply
Thanked by:
#3
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.
Reply
Thanked by:
#4
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.

[Image: FbHx1Mn.png]
Reply
Thanked by:
#5
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.
Reply
Thanked by:
#6
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.
[Image: dariC.png][Image: tumblr_mlf109xOe81rmu6i5o1_250.gif][Image: b0KxM.gif]
Reply
Thanked by: Skyla Doragono
#7
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.
Reply
Thanked by:
#8
(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!
Reply
Thanked by: Skyla Doragono
#9
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.
Reply
Thanked by:


Forum Jump: