Выкладываю изменённые файлы для самостоятельной вставки русской паузы на всякий случай (можно через CDmage), а также программу сжатия и написал что разобрал для перевода меню паузы.
Текстура с меню паузы и координатами хранятся в \PSX\DATA\CORE.DAT, также в SLUS_012.79 изменил координаты относительно экрана и адрес начала информации о символах. Информацию по структуре файла и сжатию нашёл здесь:
). Подробности:
# Структура .DAT
В начале заголовки отдельных записей (т. е. части файла) по 32 байта:
00, 4 байта (LE): тип записи, 08 - сжатая LZSS текстура с перестановкой (swizzle), 07 - просто сжатые LZSS данные.
04, 4 байта (LE): реальный размер записи, нужно потому что всё выровнено до 2048 байт, для сжатых данных он может указываться больше.
08, Остальные байты: зависит от типа, для типа 08 - u16 x, y, w, h - координаты и размеры в framebuffer (его 1 пиксель == 4 байта), для типа 07 - 4 байта (LE) - адрес загрузки в RAM (например, 0x80181500).
Здесь нет позиции записи в файле, она высчитывается как сумма размеров предыдущих записей выровненных до 2048 байт.
# Текстура с меню паузы
Хранится в CORE.DAT 0x26000-0x267FF в сжатом виде. Заголовок с 0x1C0, я указывал новый размер записи с 0x1C4, т. к. сжатая текстура стала больше, но не превысила выровненный размер, поэтому всё в порядке.
Моим компрессором разжать через командную строку:
LZSS.exe -d CORE.DAT core26000.bin -p 0x26000
Сжать после обработки:
LZSS.exe -c core26000.bin core26000_comp.bin
Потом вставить в CORE.DAT с 0x26000 и после вставленных данных выставить нули до 0x267FF чтобы затереть остатки и изменить размер в 0x1C4, можно указать без учёта двух нулей, которые добавляет моя программа, они нужны для остановки, указание размера чуть больше не проблема.
Для разжатого файла можно сделать перестановку туда и обратно (unswizzle и swizzle), но в данном случае и так нормально. Открыть в CrystalTile2: View > Tile Viewer, Tile form: GBA 4bpp, width 128, height 32, в Palette загрузить палитру (Import, я приложил palette_gray.pal) с прозрачным цветом и оттенками серого от чёрного к белому, для прозрачного у меня magenta. В 1-м куске целое слово PAUSE, во 2-м куске отдельные буквы для OPTION EXIT. Правый клик мыши по кускам и Export/Import для сохранения/вставки изображения. Я использовал Photoshop и сохранял как PNG, при импорте кол-во цветов само уменьшалось (лучше это делать вручную). Слово "ПАУЗА" расположил как и оригинал, а буквы "ОПЦИНАЗД" каждые 16 пикселей по всей длине (слева было свободно - прозрачный цвет, но место не должно использоваться игрой), по высоте чуть больше.
Для просмотра результата можно запустить игру в pcsx-redux, выбрать Debug > VRAM viewers > Show main VRAM viewer, в этом окне View > View VRAM in 4 bits и Enable greyscale, движение мышью с зажатой средней кнопкой - перемещение, колёсико меняет масштаб, наверху коориданты, по которым найдёте текстуру в 576:224, они указаны в CORE.DAT с 0x1C8.
# Координаты текста меню паузы
Основные данные в CORE.DAT 0x27000-0x297FF в сжатом виде. Заголовок с 0x200, я не изменял размер, т. к. в сжатом виде получилось меньше, но вообще стоит указать размер новой сжатой записи и также добавить нули после вставленного, если остались прошлые данные. В разжатом виде с 0x4850 до конца идут данные (оригинал):
00 E0 78 10 00 00 01 01 # Целый PAUSE
A8 E0 10 10 10 00 06 00 98 E0 10 10 00 00 06 00 # Для OPTION, не по порядку
B8 E0 10 10 1F 00 06 00 D0 E0 10 10 44 00 06 00 # ...
98 E0 10 10 34 00 06 00 C8 E0 08 10 2E 00 06 01 # ...
B8 E0 10 10 22 00 04 00 C8 E0 08 10 1C 00 04 00 # Для EXIT, не по порядку
F0 E0 10 10 0D 00 04 00 E0 E0 10 10 00 00 04 01 # ...
Во время игры копируются в RAM 0x80185D50 (в заголовке CORE.DAT 0x208 указано 0x80181500, поэтому 0x80181500 + 0x4850 == 0x80185D50), для расстановки и теста можно менять в эмуляторе. Структура из записей по 8 байтов описывают часть текстуры, по 1 байту:
00: координата X относительно текстуры в пикселях текстуры (т. е. для 4bpp по 4 бита, не нужно пересчитывать).
01: координата Y относительно framebuffer.
02 и 03: ширина и высота вырезаемой области из текстуры в пикселях.
04 и 05: координаты X, Y на экране относительно координаты слова (задаётся в SLUS_012.79).
06: кол-во записей, считая эту запись, но учитывается только значение 1-й записи, у остальных просто указано столько же.
07: == 01 в последней записи и == 00 в остальных. Не знаю зачем.
В моём переводе получилось:
00 E0 78 10 00 00 01 01 # ПАУЗА
80 E0 10 10 00 00 05 00 90 E0 10 10 0F 00 05 00 # ОПЦИИ
A0 E0 10 10 1E 00 05 00 B0 E0 10 10 2F 00 05 00 # ...
B0 E0 10 10 3F 00 05 01
C0 E0 10 10 00 00 05 00 D0 E0 10 10 0F 00 05 00 # НАЗАД
E0 E0 10 10 1E 00 05 00 D0 E0 10 10 2B 00 05 00 # ...
F0 E0 10 10 3B 00 05 01
Слово НАЗАД вышло длиннее и кол-во букв разное, поэтому нужно отредактировать SLUS_012.79.
В отладчике с 80031AA4 код вызывающий 3 раза функцию 800317FC для отображения каждого слова. Перед вызовом задаются регистры: $a0 адрес на данные, которые меняли выше, и координаты X, Y начала слова на экране в $a1, $a2. Из-за сдвига слова "НАЗАД", нужно изменить адрес данных в инструкции "80031AE4: li $a0, 0x80185D88" на 0x80185D80, а для координаты X ниже в "80031AEC: move $a1, 0x008A" поставить 0x007A. В итоге в файле SLUS_012.79 найти 88 5d 84 34 8a 00 05 24 и заменить на 80 5d 84 34 7a 00 05 24.
# Сжатие LZSS
Оно простое, если вы видели LZSS сжатие. Я изменил свой компрессор для Clock Tower 2. Компилировал через MinGW64 из MSYS2, но можно легко добавить в пустой консольный проект Visual Studio. Алгоритм сжатия простой, поэтому размер сжатого примерно как в оригинальной игре, но у VIT сжатие лучше.
Как я понял, если указать размер сжатых данных в заголовке больше, чем их есть, но при это дальше нули до указанного размера, то за пределами разжатых данных не будет испорченных данных, но будет перезапись байтов с таким же значением, т. к. 00 00 распознаются как копировать 2 байта с текущей позиции.