Так-с... Недавно разобрал один формат, хотелось бы сохранить его где-нибудь в помощь потомкам
Спасибо WinKi за направление 
- все числа в тексте - шестнадцатеричные.
- если я пишу "usually", это значит, что во всех/многих случаях в моём файле там было именно это значение.
- [DW] - число типа DWord; [S] - последовательность символов (строка); [S8] - восемь символов; [US] - Unicode string (см. ниже)
- Прога для перевода будет выложена здесь: http://www.solelo.com/p4s
Entis CSX: Cotopha Image file(Wanko to Lily, system\wanko.csx, 3 813 713 bytes)Код:
Общий формат CSX-файла:
.00..40 - CSX file header
.41+ - Sections
CSX file header:
.00: [S] "Entis"#$1A#00#00
...
.0C: [DW] Should be zero
.10: [S] "Cotopha Image file"
...
.38: [DW] Contents size
...
где:
- Should be zero - поле должно быть нулём, иначе движок выдаст сообщение о неверном заголовке файла. Может быть, это версия, зарезирвированое поле, код расширения формата или ещё что-нибудь.
- Contents size - это размер всего файла, за исключением его заголовка (иными словами, это значение + 40 должно быть точно на 1 байт больше размера файла целиком).
CSX-файл состоит из секций. Их пять видов:
- image - собственно команды скрипта и текст. Самая большая секция.
- function - это таблица функций и, видимо, точек входа или ещё чего-то. Как раз то, где надо править сдвиги.
- global - не вдавался в детали, не влияет на возможность перевода.
- data - тоже самое здесь.
- linkinf - конкретно не знаю, что это такое, ибо в игре эта секция была пустой...
Секция имеет такой формат:
Код:
.00: [S8] ID
.08: [DW] Size
.0C: [DW] Unknown (usually 0)
где:
- ID - вид секции (одно из пяти). Лишнее место заполняется пробелами (20, не нулями).
- Size - размер секции без учёта заголовка.
Некоторые секции ещё читают дополнительный [DW] или несколько.Unicode stringВ файле используется общий формат для всех строк, которые, кстати, все Юникод (кроме ID секций, которые ASCII). Здесь я его обозначаю [US]:
Код:
.00: [DW] Character count
.04: [S] Unicode string
где:
- Character count - количество символов (не байт). Чтобы получить длину строки надо помножить это на 2.
- Unicode string - например, 0030 BF7D...
Linkinf sectionТак как не интересовался этой секцией, могу сказать только то, что она имеет свой заголовок (в дополнение к обычному секционному):
Код:
.00: [DW] Count 1
.04: [DW] Unknonwn
.08: [DW] Count 2
.0C: [DW] Unknown
Linkinf имеет две части, каждая из которых имеет своё количество "чего-то".
Data sectionТоже не самая интересная секция.
Код:
Имеет свой заголовок из 4 байт
.00: [DW] Records count
Record:
.00: [US] Name 1
+00: [DW] Unknown (usually 0)
.04: [DW] Unknown (usually 80)
.0С: [US] Name 2
Примеры (Name 1 => Name 2):
Код:
input => InputFilter
screen => Window
frameskin => ResourceManager
Global sectionЭта секция, опять же, не представляет особого интереса, ибо не влияет на перевод. Однако вот что о ней известно:
Код:
Имеет свой заголовок из 4 байт
.00: [DW] Records count
Record:
.00: [US] Name
+00: [DW] Unknown
.04: [DW] Unknown 2
Очень возможно, что Unknown 2 является длиной ещё одной Unicode-строки.
Function sectionА вот это самое интересное место. Здесь хранятся указатели внутрь секции image, поэтому тут нам и нужно фиксить сдвиги при изменении скрипта.
Секция состоит из двух частей. В первой хранятся просто смещения, во второй - таблица с именами и смещениями.
Все адреса в этой секции относительны секции image. То есть чтобы получить абсолютный адрес, нужно прибавить к ним адрес начала image (обычно 50).
Первая частьКод:
Имеет свой заголовок из 4 байт
.00: [DW] Records count
Record:
.00: [DW] Relative offset
где:
- Relative offset - относительныый адрес в секции image.
Вторая частьКод:
Имеет свой заголовок из 8 байт
.00: [DW] Unknown (usually 0)
.04: [DW] Records count
Record:
.00: Relative offset
.04: [US] Name
где:
- Relative offset - относительныый адрес в секции image.
Image sectionСообщения выводятся двумя функциями: Talk и Mess. Функция HitretNewPage ждёт реакции юзера и выводит следующее сообщение (на новый экран).
Особенностью использования Talk и Mess является то, что Talk (видимо) всегда используется для вывода сообщений, а не речи,
но не всегда ондо сообщение выводится только функцией Talk. Обычно сообщение делится так, что Talk выводит первые 26 символов (максимум, что умещается на экране в одной строчке), а всё остальное выводится функциями Mess (по всей видимости тоже по одной функции на одну строку).
Интересно, что любая длинная строка выводится нормально даже одной функцией. Не совсем понятно, зачем в скрипте они разбиваются таким образом.
В то же время Mess используется и для вывода речи (без начального вызова Talk). Разделить одно сообщение можно при помощи отлова HitretNewPage.
Порядок прохождения парсера по скрипту (это скрин RTF из аттача):

Вложение:
Cotopha parser jumps.rar [3.3 КБ]
Скачиваний: 311
Теперь вкратце о каждой функции.
TalkКод:
.00: [US] "Talk"
+00: [DW] Unknown (usually 01 02 00 06)
.04: [US] Message
MessКод:
.00: [US] "Mess"
+00: [DW] Unknown (usually 01 02 00 06)
.04: [US] Message
HitretNewPageКод:
.00: [US] "HitretNewPage"
Этого достаточно для изменения строк.
Где и что изменять?При изменении строки в секции image нужно изменить следующие места в CSX-файле:
- @38 - размер всего CSX-файлла без заголовка.
- "image" section:
- - @08 - размер секции;
- - длину Unicode-строки в самом скрипте.
- - подправить расстояния в коротких прыжках, см. ниже.
- "function" section:
- - изменить адреса в первой части секции;
- - сделать тоже самое во второй части.
Короткие прыжкиВ скрипте также могут встретиться функции прыжков. Обычно там указывается относительное расстояние прыжка (то есть сколько байт пропустить). Из-за этого нужно не только изменять адреса в таблице смещений (функций, см. выше), но и отслеживать в скрипте эти прыжки и править расстояния в них при необходимости.
Например, есть функция
IsGameClear, у которой расстояние записано здесь:
[us] IsGameClear [w] [dw] distance (то есть 2 неизвестных байта после имени функции, затем смещение размера DWord). Тот же синтаксис имеют аналогичные функции:
ChkFlagOn,
ChkSelect и
OnFlag.
Имена функций, как обычно, в Юникоде (для английских названий символ есть просто его код + 0x00 для 2-го байта).
Ещё один момент. Функции прыжков иногда могут ссылаться на специальный код, который в этом контексте
тоже является прыжком. Этот код - один байт =
0x06 и следом за ним 4 байта расстояния дял прыжка:
[b.] 0x06 [dw] distance. Так что такие "прыжки" тоже нужно отслеживать и подправлять.
Вообще, скрипты изобилуют прыжками - к примеру, в
Yosuga no Sora всего 4 выбора, однако в самом скрипте находится аж 22 прыжка.
В заключение...Радует то, что движок везде использует Unicode, поэтому проблем с любым языком (в том числе и с нашей любимой кириллицей) нет. Очень любопытен факт, что, если отключить жесткие переносы в японском стиле через небольшой хак, то движок будет сам переносить русские и английские слова и даже
добавлять в них переносы.
Кстати, движок работает и без установленной японском локали.
На этом всё.