Pull to refresh

Продолжаем разбирать квест Harvester 1996 года

Self Promo

Всем добра.



В прошлый раз я остановился на том, что внедрил Tahoma11 в игру и был доволен.
image

Сразу стали видны минусы, шрифт не вписывается в стиль игры.
Появились новые заморочки:
  • внедрить красивый русский шрифт, стилизованный под оригинальный,
  • разобраться с пропуском почти всех видео в dosbox.

Инструменты: IDA, dosbox + debugger, winhex.

Квест про шрифты


Сперва шрифт. Всё тем же художником форума был нарисован красивый, стилизованный под оригинал русский шрифт.
Всего в игре их шесть:
image
image
image
image
image
image

Так как шрифт 8-битный, то каждый пиксель символа — это один байт, содержащий индекс цвета в палитре. Существует таблица ширин каждого символа в заголовке, одна строка всех символов шрифта образуют ряд (тоже прописан в заголовке), несколько рядов образуют высоту.
Размер блока данных равен (высота * ряд) байт, а соответствующая картинка равна (высота * ряд) пикселей.

Возник небольшой ступор как их засунуть в данные игры. Свой тестовый Tahoma11 я рисовал попиксельно глядя на увеличенный оригинал. Цвет использовал только белый.
К этому моменту у меня был подготовлен инструмент попиксельной отрисовки каждой буквы с выбором цвета, но есть гигантское НО. Если мелкий шрифт еще кое-как можно было перерисовать вручную, то большой шрифт с размерами 40x50 пикселей уже не представлялось как в разумные сроки. В каждой букве еще использовалось несколько цветов из палитры в 256 цветов, что еще усложняло задачу ручной отрисовки.

Пришлось делать импорт данных из BMP.
Алгоритм получился следующий. Товарищ художник (Ogr 2) предусмотрел разный фон для каждой буквы, то есть есть зацепка для автоматического сбора данных о ширине каждой буквы. Позже он стал добавлять одну служебную строку с разными цветами, чтобы можно было сосчитать ширину каждого символа.

Итак процесс.
Пробежался по одному ряду байт русского шрифта в BMP и на границе между символами поймал изменение цвета пикселя, составил таблицу ширин.
Высота — это количество рядов из пикселей. Так как у нас каждый шрифт находится в отдельном файле, то ничего не мешает увеличить высоту, просто добавив нулей в конец блока данных. Количество нулей равно количеству байт ряда. После этого остается исправить байт высота и вуаля, новая высота готова, подогнали под нужный размер.
Следующим пунктом идет ширина каждого символа, необходимо согласовать ширины. Сдвигаем данные, выравниваем ширину.
Теперь у нас всё готово для импорта, делаем цикл по высоте, цикл по ширине и копируем байты из BMP прямо в блок данных игры.

Итог получился отличным, но почему-то каждое действие ведет к каким-то последствиям.
Вылезла проблема — суммарная ширина русских букв оказалась намного шире, чем было у разработчиков и движковая система переноса выдала такой вот результат:


В движке жестко забито, что длина ряда — 39 символов. Если выведешь строку из 40+ символов подряд, то игра зависает, если меньше, то вылезает за границы интерфейса.

Начался путь дебага.
Был откинут дос заголовок, LE файл вставлен в IDA. Бонусом разработчики оставили в EXE файле всю debug информацию, то есть видны все названия всех функций.
Прямой поиск чисел 38, 39, 40 в IDA ни к чему не привели. Отладка прыгала в районе функций «Talk to» и конкретно я тестировал «Talk to Hank», я трассировал трассировал и вытрассировал наконец замечательный блок, в результате математики которого было заветное число 39.

Блок выглядел примерно вот так:
cseg01:00059D94 lea ecx, [eax-1]

cseg01:00059D97 sar edx, 1Fh
cseg01:00059D9A mov eax, ebp
cseg01:00059D9C idiv ecx

В результате деления IDIV в EAX оказывается число 39, которое дальше используется для переноса строк, движок вставляет каждые 39 символов код 0Ah, перенос строки.

Две последние команды сперва я заменил на
mov al, 36
но это же получилась ошибка, в AH что-то оставалось и строка получилась длиной в вечность, весь текст развернуло в одну строк, второй раз я прописал уже
mov ax, 36

и вуаля:


Позже оказалось, что 36 тоже много и пришлось прописать 35, на этом квест со строками и шрифтом закончен.

Квест про пропуски видео

Проблема. Глобальная проблема. В dosbox с большим количеством циклов игра идет ровно и хорошо, но практически все видео пропускаются сразу же после начала показа. Это неприемлемо.
Можно было уменьшить количество циклов, тогда пропуски видео прекращались, но игра превращалась в слайд-шоу.
Process Monitor показывал, что видео начинало читаться, видео показывалось, но спустя секунду прекращалось.
Вглядывание в IDA и трассировка показали, что блок декодирования видео шел в цикле и постоянно проходил через несколько строк:


Как оказалось, во время воспроизведения игра проверяла нажатие кнопок ESC, левой и правой кнопки мыши. Если пропустить диалог кликом мышки и начиналось воспроизведение видео, то почему-то в буфере оставался этот клик, который и приводил к прерыванию видео. За-NOP-ив переходы от мышки и оставив выход из видео только по клавише ESC удалось победить очень противный баг игры.
Tags:
Hubs:
Total votes 26: ↑25 and ↓1 +24
Views 5.9K
Comments Leave a comment