Я перевел King's Bounty 1990 для DOS на русский язык
Я давний фанат KB и хочу чтобы больше людей про нее узнали — все-таки классика, предтеча Героев и просто крутая недушная стратегия, которая проходится за пару вечеров. Отличной игре нужна отличная локализация.
Пост довольно технический, но совсем уж в дебри лезть не буду.
Для начала объясню, с чем мы вообще имеем дело. Наша платформа — DOS. Это на самом деле хорошо, потому что она легко эмулируется на любой ОС через DOSBox и вообще хорошо изучена — не какая-то экзотика. В игре три файла:
- KB.EXE — основной исполняемый файл, в нем вперемешку лежит весь код игры, включая тексты.
- 256.CC — графика игры для режима 256 цветов (основной).
- 416.CC — графика игры для режимов в 4 и 16 цветов.
Кроме того, моя версия была с файлом KB!.COM, который запускал оригинальный KB.EXE и тут же на ходу его патчил, снимая защиту от копирования.
А, да, версии... У игры есть несколько ревизий, которые не отличаются геймплейно, но версия 1995 года поставляется уже без защиты от копирования и без сжатия, что упростило бы жизнь. Но тогда я этого не знал.
Инструментарий
Я программист, но в архитектуре DOS, ассемблере и низкоуровневом программировании в целом не разбираюсь, так что моим основным инструментом был Claude. Без него бы потратил в десять раз больше времени и забил бы на половине.
Основная сложность проекта в том, что KB.EXE, где лежит все, что нам нужно, это просто огромная простыня байтов, которую крайне сложно «провернуть назад» и превратить во что-то читаемое. Программы-дизассемблеры (в моем случае Ghidra) могут в этом помочь, но нет гарантии, что они распутают прям все.
Первые проблемы
Сложности начались сразу же — дизассемблер не смог найти в файле ни одной строки, которую предполагалось переводить. Дальнейшие раскопки показали, что файл сжат и разжимается при открытии. Причем не каким-то известным архиватором, а кастомной поделкой New World Computing. Ладно хоть алгоритм стандартный LZW.
Claude написал скрипт на Python и смог разжать файл с 80 до 108 КБ.
Но это не все! Строки опять не находились. Выяснилось, что файл сжат еще раз, теперь уже стандартным EXEPACK. Ладно, написали скрипт и для этого, файл распух до невероятных 113 КБ. Строки находятся, можно работать!
Шрифт
Мы хотим добавить в игру кириллицу, но в шрифте-то ее нет. К счастью, тут обошлось без особых проблем, CC оказался просто набором картинок сжатых тем же LZW, так что Claude без проблем сделал экспортер и импортер нужного куска.
Шрифт, видимо, был сделан специально для игры, я не смог найти такой же, так что просто нарисовал к нему кириллицу:
С дизайном шрифта мне сильно помог Дмитрий Сивухин, за что ему отдельное спасибо. Кое-какие идеи я заимствовал из классического IBM BIOS 8x8.
Как видите, заглавные Й и Ё получились так себе, так что в игре они не представлены, если только игрок не решит использовать их в имени персонажа.
Зачем в шрифте слово «бьют:» спросите вы? Это на потом.
Начинаем перевод
Итак, на самом базовом уровне выглядит это так. Допустим, нам нужно перевести стартовый экран игры с именами разработчиков. Мы ищем в KB.EXE последовательность байтов которую можно прочитать как «Jon Van Caneghem» и подменяем ее своими байтами, которые обозначают другие ячейки в картинке со шрифтом, так, чтобы читалось «Джон Ван Канегем».
Конечно, все не так просто, потому что эти байты могут означать что угодно, это просто числа в огромной простыне чисел. К счастью, есть некоторые эвристики, которые помогают понять где что — к концу перевода у меня уже был отличный инструментарий.
Все патчи записываются в отдельный файл с адресами и значениями.
Защита от копирования
Тут все решилось довольно просто. С игрой уже поставлялся маленький COM-файл, который ее снимает, а в поздних версиях она попросту отключена. Мы нашли тот единственный байт, что он подменяет и добавили в список патчей.
Релокация строк
Теперь — реальные сложности. Из-за того, что все строки в файле идут подряд, при переводе их можно оставить той же длины или уменьшить, но нельзя увеличивать, поскольку тогда они залезут на соседние байты и все сломается. Я думаю вы уже можете представить какой это космический гемор.
Вот начинает герой с крестьянами (peasants). Теоретический лимит на имя юнита — 10 символов (barbarians), он точно будет влезать во все окна. Но в слове «peasants» 8 символов, а «крестьяне» уже 9. Да, можно до какой-то поры изворачиваться, придумывать нелепые сокращения, обрезать слова или творчески менять перевод («мужики», как в пиратке Героев 2), но это все недостойные тру локализации полумеры.
Реальное решение — найти в игре неиспользованный кусок памяти, вписать правильную строку туда и подменить изначальную ссылку на нее, то есть релоцировать строку, а не просто ее заменить. Замечу, что я не мог просто дописать их куда-то в конец, потому что... сложно это, короче.
После пары дней экспериментов, крашей и зависаний релокация все-таки завелась.
Перевод
В игре не очень много текста — чуть меньше тысячи коротеньких строк, так что много времени он не занял. Черновой перевод делал Claude, а я редактировал. Большая часть художественного текста это биографии злодеев.
Чисто переводческих проблем было немного — в игре простой язык и незамысловатый нарратив. Некоторая заминка возникла с кличкой Ареха Огнедышащего «Mastermind», в итоге он стал «Тёмным гением».
Кое-какие сложности доставили заклинания. Лимит по буквам там 12 или 13 символов (зависит от цены). Не сразу смог подобрать хороший перевод к «Time Stop» — остановился на варианте «Стазис», забраковав «Хроностаз».
«Raise Control» превратился в «Дар лидерства», что как по мне очень логично — заклинание дает лидерство.
Больше проблем было чисто редакторского характера — моноширинный шрифт и так выглядит не ахти, а с рваным правым краем и висячими предлогами и союзами еще хуже. Так что я старался переформулировать текст так, чтобы он смотрелся аккуратно.
Два самых некрасивых с точки зрения верстки экрана в игре — победа и поражение. Текст сжат в узкую колонку без полей и выглядит ужасно. Пришлось чинить.
Экран боя
Сообщения о том, кто кого атакует — сложное испытание для русской грамматики.
Английская версия — «Militia vs Peasants killing 793» с вариациями для стрельбы и для длинных имен существ — тоже довольно кривая грамматически. По русски будет «Ополченцы против Крестьяне убивают 793». Абсолютно ужасно да еще и не влезает в лимит символов (35).
Мой универсальный ответ на несогласованные существительные — двоеточие: «Ополченцы бьют: Крестьяне, убито 120». Читается норм, но есть проблема — это 36 символов. Наши опции: убрать двоеточие, убрать запятую, заменить «убито» на «пало». Мне ни одна из них не понравилась, поэтому я выбрал секретную четвертую опцию — добавить в шрифт специальную строку для этого случая, упихав «бьют:» в 4 символа вместо 5.
Немного повозиться пришлось с сообщениями от заклинаний. По умолчанию числа никак не согласовать с названием заклинания: «8 Vampires cloned» превращается в «8 Вампиры клонировано» и хоть что ты тут делай.
На помощь приходит тот же инструмент что мы использовали для снятия защиты от копирования — прямая замена байтов. Это я полностью отдал на откуп Claude — ему-то все равно слова читать или байты. Путем некоторого шаманства фраза превращается в «Вампиры клонированы: 8». Можно жить.
Мелочевка разная
Подобные микро-патчи встречаются еще на нескольких экранах. Например, в жилище существ переставлены местами слова в первой строке:
А на экране армии ходы заменяются на «Летает»:
Города и замки
Мы подходим к этапу которого я боялся когда еще только приступал к локализации — названия городов и замков. Сам перевод большой сложности не представляет — проблема с заклинаниями «Врата замка» и «Врата города». В оригинальной игре мы выбираем букву на клавиатуре, которая соответствует первой букве в названии замка, например F перенесет вас в замок Faxis. Причем названий на экране нет, просто список букв:
Как такое локализовывать — непонятно. Подменять буквы? Перехватывать вызовы с клавиатуры? А как их пересортировать? А что если на клавиатуре кириллицы нет? Да и вообще кириллические хоткеи дурной тон. А они еще и в коде расположены так, что их не подвигаешь особо...
В итоге было принято радикальное решение — написать новый интерфейс. Claude накидал решение на ассемблере и после пары раундов дебага все заработало! Для патча использовали ту же самую область памяти, что и для релоцированных строк.
Имя игрока
И напоследок нужно было, конечно, разрешить игроку задавать имя кириллицей. А точнее — принудительно переключать на нее, потому что игра работает только в латинской раскладке.
Дело решил еще один коротенький патч на ассемблере из двух кусочков — один перехватывает ввод и заменяет латиницу на кириллицу в поле ввода имени, а второй задает таблицу транслитерации для имени файла сохранения, валидного для DOS.
Патчер
Несмотря на то, что игра является abandonware, нигде не продается и ее можно свободно скачать в куче мест, я не большой фанат идеи выкладывать готовый билд или вообще что-то лицензионно сомнительное на свой GitHub.
Поэтому в качестве завершающего аккорда я портировал все на TypeScript (изначально код был написан на Python) и сделал веб-версию патчера.
Как играть
Не дольше, чем поставить игру в Стиме так-то:
- Скачать оригинальные файлы, например с My Abandonware. Нужна версия 1990 года, другие не подойдут.
- Сходить на страницу патчера и кинуть туда архив и скачать русскую версию.
- Скачать DOSBox и открыть им папку с русской версией.
Не могу гарантировать что все будет на 100% гладко, прямые патчи бинарника дело опасное все-таки, но я полностью прошел игру без всяких проблем. Другие тестеры тоже ничего не нашли.
Несколько советов
- Мануал не нужен, во всем можно разобраться прямо из игры. Она вообще не особо сложная. Кнопка O (Помощь) показывает список всех команд. Они разные на карте мира и в бою.
- Игра рассчитана на наличие цифрового блока на клавиатуре (нумпада), но если его нет, то это не страшно. В 90% случаев он не нужен. Когда надо атаковать кого-то по диагонали используйте клавиши 1, 3, 7 и 9. Они расположены мнемонически удобно (1 и 3 меньше, значит бьют вниз, направление сторон совпадает), так что адаптируетесь быстро.
- Кнопкой F можно летать по карте мира. Но это работает только если у вас все армии летающие (кроме фей, они дохлые слишком).
- Записывайте, в каком городе какие заклинания продаются, чтобы потом не таскаться по всей карте в поисках клонирования или стазиса.
Заключение
Это был классный проект на пару недель и я рад, что я внес свой вклад в сохранение и распространение классических игр. Я считаю, что локализация получилась отличная, но если у вас другие мысли — я открыт для обратной связи, доведем до идеальной.
Мой основной проект сейчас Master of Luna — фентезийная 4х стратегия. Она уже в Steam в раннем доступе. Я часто пишу про ее разработку на своем канале.
Еще подпишитесь на канал Дмитрия, он лучший специалист по пиксельным шрифтам, которого я знаю и вообще дизайнер классный.
Ну все, до скорого!
UPD
В комментария много вопросов было про уже существующий перевод В. Мирончика 2004 года. К сожалению, он плохой. Автор остановился на прямой замене строк, то есть все обрезано по длине оригинала. Очень много странно переведенных слов (rogue → торговец). Биографии злодеев вообще оставлены без перевода.
Конечно в 2004 году инструменты были не те, что сейчас, так что автора можно понять, но я посчитал, что игра заслуживает большего.