Как русифицировал японскую ретро-игру
Привет! Хочу поделиться историей и техническими приключениями при переводе на русский язык игры G-MODE Archives+: Kishinden STRIK-G-.
Это порт классической японской тактической RPG с кнопочных телефонов эпохи DoJa/i-mode (2005 год), "бережно" перенесённый разработчиками на движок Unity для современных платформ. Но, как часто бывает со старыми японскими играми, под капотом скрывалось множество сюрпризов, жестких лимитов и неочевидных ловушек.
Ниже рассказ о том, с какими сложностями пришлось столкнуться и как удалось заставить всё работать стабильно.
1. Начало: Казалось бы, всё просто (но нет)
Внутри игровых ресурсов нашёлся текстовый файл сценария, содержащий все диалоги, характеристики роботов, предметы и структуру меню.
Формат сценария выглядел интуитивно понятно:
#TITLE
{
@HIDDEN
BG無
BGMタイトル
SOFT1終了
{
BG無し
Mいいえ
>終了しますか?
>JUMP#_UP
Mはい
>終了しますか?
>JUMP#_END_GAME
}
MFIRST
>JUMP#DEMO_OP01
}
Казалось, достаточно просто аккуратно перевести японский текст на русский и запаковать обратно. Но при первом же запуске с переведённым файлом игра намертво вылетела.
2. Ловушка №1: Жёсткий лимит на размер файла
После тестов выяснилось: если перевести пару строчек, игра запускается. Но если перевести много, то падает.
В чём была проблема?
В коде игры разработчики когда-то зашили фиксированный размер буфера чтения данных:
this.data_size = 105950; // Ровно под оригинальный японский файл!
Русский текст в кодировке Shift-JIS весит значительно больше краткого японского текста. Всё, что превышало 105 килобайт, игра просто отрезала, из-за чего ломался индекс скриптов и всё падало с ошибкой.
Решение:
В коде размер буфера был сделан динамическим, что позволило игре загружать полный переведённый сценарий любого объёма.
3. Ловушка №2: Детективная история с зависанием на буквах «к» и «м»
Когда игра наконец запустилась, всплыла новая необъяснимая мистика. В прологе робот произносит реплику:
>«Юри...»
...и игра намертво виснет перед следующим диалогом. Если вернуть следующий диалог на японский, то сцена идёт дальше, но затем снова виснет на другой русской фразе.
Расследование:
Игра работает со старой японской кодировкой Shift-JIS. В этой кодировке:
- Русская строчная буква **`к`** кодируется как два байта: `0x84 0x7B`
- Русская строчная буква **`м`** кодируется как два байта: `0x84 0x7D`
А теперь самое интересное:
- Байт `0x7B` (123 в десятичной системе) — это символ фигурной скобки **`{`** в ASCII!
- Байт `0x7D` (125 в десятичной системе) — это символ фигурной скобки **`}`** в ASCII!
Функция парсера игры искала конец блока меню `}\r\n`, проверяя только один байт и не учитывая, что это может быть второй байт русской буквы!
Когда строка диалога заканчивалась на букву `к` или `м`, игра думала, что меню преждевременно закрылось фигурной скобкой `}`. Она выделяла память под меньшее число пунктов, и при попытке прочесть следующую строчку вылетало исключение `IndexOutOfRangeException`, замораживая игру.
Решение:
В конце строк которые заканчиваются на `к` или `м` просто ставим пробел, тем самым парсер продолжает искать дальше.
4. Ловушка №3: Ограничение на 11 байт в названиях предметов
При переводе секции предметов (`#ITEM`) игра снова выдавала окно ошибки: `Sys_Dialog("エラー")`.
В коде стояла проверка:
if (num > 11)
{
GameCanvas.Sys_Dialog("エラー");
GameCanvas.App.Terminate();
}
Японские названия предметов состояли максимум из 5-6 символов (до 11 байт). В русском языке даже слово *«Пистолет»* занимает 16 байт.
Решение:
В методе был расширен внутренний массив чтения с 32 до 128 байт и снят лимит. Теперь игра спокойно принимает красивые развёрнутые названия предметов и экипировки на русском.
5. Ловушка №4: Невидимые связи скрипта и кода игры
В старых играх очень часто игровая логика завязана на конкретные строковые литералы. При переводе нужно было соблюдать ювелирную точность:
1. Стартовое оружие героя:
Код игры ищет оружие `"パンチ"` (Удар) и `"夜叉の拳"` (Кулак Якши) прямым поиском по имени. Переведя их в базе предметов, необходимо было синхронно обновить эти имена и в коде игры.
2. Магазин и инвентарь:
Вкладки магазина «Купить» и «Продать» (`M購入` и `M売却`) обрабатываются кодом игры. Когда в скрипте они стали `MКупить` и `MПродать`, движок перестал их узнавать и магазин опустел. Потребовалось синхронизировать названия в коде игры.
3. Таблицы выпадающего лута и характеристики врагов (`#CONTAINER` и `#FM`):
Сундуки и противники ссылаются на предметы по их точным именам. Названия были строго согласованы буква в букву.
4. Финальный босс (`ウロボロス` / Уроборос):
Победа в подземелье на 99 этаже проверялась строчкой `ウロボロス`. Имя босса было обновлено в связке код + скрипт.
6. Ловушка №5: Разъехавшаяся центровка меню
Когда меню магазина и экипировки заработали на русском, вскрылся визуальный дефект: русский текст не центровался на кнопках, а прижимался влево или вылезал за границы.
Причина:
Функция измерения ширины строки в оригинале эмулировала кнопочный телефон. Она проверяла: если символ двухбайтовый - считаем его ширину как 16 пикселей.
Для слова *«Купить»* (6 букв) игра рассчитывала огромную ширину в 96px и сдвигала точку отрисовки далеко влево: `37 - (96 / 2) = -11px`.
Решение:
Метод в коде был переписан так, чтобы он запрашивал у шрифта Unity настоящую физическую ширину каждого символа. После этого все русские плашки и пункты меню встали идеально по центру пиксель-в-пиксель!
7. Завершающий штрих: Интерфейс и титульный экран
Для полной локализации оставалось привести в порядок системный интерфейс:
- Титульный экран: Надпись *«Нажмите любую кнопку»* не помещалась в рамку шириной 260px и обрезалась до одного слова *«Нажмите»*. Была увеличена ширина контейнера и отключено принудительное усечение строк.
- Боевой лог: Сообщения о победе над роботами и получении трофеев теперь выводятся полностью на русском языке.
Итог:
В результате глубокого разбора кода и скриптов игра получила полноценную, аккуратную и стабильную русификацию, сохранив всю атмосферу и механику оригинальной японской классики.
Если вы берётесь за русификацию портов японских мобильных игр - будьте готовы заглянуть глубже простого текстовика: зачастую самое интересное скрывается на стыке кодировок и старого кода!
разбор