| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
Сегодня мы поговорим об игрушках. Да-да, именно о них, родимых. Бывает так, что купил игрушку, вставил диск в CD-ROM, установил ее, а затем очнулся на утро следующего (или не следующего) дня. Честно говоря, рассказывать о магии игр можно долго. Но наша задача заключается в препарировании криво написанных игр. Можно отложить в сторону твой любимый ArtMoney, SoftIce, Advanced HEX Editor и приняться потрошить игрушку непосредственно.
Помнится, играл я как-то раз в очень простую, но очень интересную игру. Ее название я, естественно, не помню. Игра была про войну. Ты находишься на каком-то острове в какой-то башне с круговым обзором, у тебя есть несколько видов оружия и боеприпасы к ним. А над тобою пролетают самолеты, мимо тебя проплывают корабли, на твой остров высаживается десант... На определенном этапе я никак не мог сбить 5 юнкерсов, выходило максимум 4. Пришлось поковырять саму игрушку. Оказалось, что описания всех миссий лежат в ini-файлах открытым текстом. Я подредактировал количество самолетов, которое необходимо сбить для прохождения миссии. А потом понеслось... Пулемет стал бить на гораздо большие расстояния и наносить урон в десятки раз больший, самолеты летели один за одним, а нужно было сбить 5-6 и т.д. Я изощрялся довольно долго, до тех пор пока... не прошел игру. Вот такая история... Ну а сейчас мы приступим к препарированию другой, более популярной игры. Итак, игрушка жанра квест, изданная далеко не вчера, "ГЭГ-2".
Честно говоря, в первый "ГЭГ" я не играл, поэтому не могу сравнить продукты двух разных команд, выпущенных под одним лейблом. Главное, что препарируемая игра сделана настолько плохо (или хорошо, если посмотреть с другой стороны), что из нее можно сотворить что угодно: от пародии на нее саму до нового квеста.
Начинаем разбирать игрушку.
Посмотрим, какие файлы мы можем редактировать непосредственно с помощью "блокнота" (хотя я предпочитаю "бред"):
?map.vco - описание сцен, комнат, размещения предметов (? заменяет число от 1 до 12, остальные значения не тестировал)
sequences.dat - описание действий
sound.dat - распределение звуков и фоновых шумов по локациям
В папках graph и sound лежат картинки (форматы BMP и JPG) и звуки (формат WAV) соответственно.
Нам пока этого достаточно, т.к. материала для изучения довольно много.
Начнем с самого интересного - описания действий. Здесь был использован скриптовый язык, напоминающий c/c++.
Всякое действие начинается с ключевого слова begin и заканчивается ключевым словом end. Далее идет описание типа действия: просмотр, клик, комбинирование предметов, использование правильного или неправильного предмета. А затем описывается результат самого действия. Т.е. мы имеем схему:
begin
<описание типа действия>
<результат действия>
end
В тексте скрипта могут использоваться комментарии (/* */).
Просмотр описывается следующим образом:
view <номер сцены (sn)> <3 числа (ln1,ln2,ln3) - номер локации>
Стоит заметить, что изображение данной локации будет лежать по адресу graph\sn\ln1_ln2_ln3.jpg
Клик:
click <номер предмета (in)>
Комбинирование предметов:
comb <номер первого предмета (1in)> <номер второго предмета (2in)>
Использование правильного предмета:
item <номер действующего предмета (sin)> zone <номер принимающего предмета (din)>
Использование неправильного предмета:
Иногда требуется выполнить действие после неправильного применения предмета, например, предупредить об опасности неверного выбора (надеюсь, никто не станет засовывать ножницы в розетку).
wrong_item zone <номер принимающего предмета (din)>
Где прописаны все эти номера, я еще не знаю (надеюсь, к концу статьи я смогу это выяснить). Скажу одно: никакой защиты от внесения изменений не предусмотрено, поэтому можно творить практически что угодно.
Все скрипты построены на использовании условных операторов if и if_not, аргументами которых являются булевозначные флаги. Общий вид такого оператора:
if[<флаг>] {
<действие 1>
} else[] {
<действие 2>
}
Имя флага должно состоять из латинских букв и цифр, причем первым символом должна быть буква (хотя это не проверялось, но идентификаторы в большинстве компиляторов и интерпретаторов строятся именно по такому принципу).
Установка флага производится оператором set_flag[<флаг>], а его сброс - kill_flag[<флаг>].
del_item[<(in)>] - удаление предмета из инвентаря.
add_item[<(in)> <путь>] - добавление предмета в инвентарь. После добавления окно инвентаря не закрывается. Путь - путь к графическому файлу с изображением предмета из папки graph.
add_item[<(in)> <путь> break] - добавление предмета в инвентарь. После добавления окно инвентаря закрывается. Путь - путь к графическому файлу с изображением предмета из папки graph.
ch_view[<(sn_1)> <(ln1_1)> <(ln2_1)> <(ln3_1)> <(sn_2)> <(ln1_2)> <(ln2_2)> <(ln3_2)>] - замена одного вида локации на другой. Например, при построении пирамиды из 3х кубиков, на применение 1го кубика можно поменять пустой фон на фон с одним кубиком, аналогично и для других кубиков.
ch_anim[<(sn)> <(ln1)> <(ln2)> <(ln3)> <путь_1> <путь_2>] - замена анимации. Статической картинкой считается анимация, состоящая из одного фрейма. Например, после применения скорпиона на тиски, их вид дополняется торчащим жалом скорпиона. Путь_1 - путь к меняемой картинке из папки graph, путь_2 - путь к меняющей картинке из папки graph, (x,y) - координаты места, куда следует поместить картинку.
ch_zone[<(din_1)> <(din_2)>] - замена предмета первого предмета на второй (например, закрытой двери на открытую).
jump[<(sn)> <(ln1)> <(ln2)> <(ln3)>] - переместиться в выбранную локацию.
wav[<имя_звукового_файла> $] - проигрывание звукового файла, следующее действие задерживается до конца выполнения этого.
wav[<имя_звукового_файла>] - проигрывание звукового файла с параллельным исполнением следующего действия.
avi[<имя_видеофайла>] - проигрывание видеоролика. Все видеофайлы запакованы в video\video.dv.
pop[<имя_звукового_файла>] - реплика попугая. При этом с плеча свешивается попугай. Кстати, вся анимация предметов, а также и попугая, выполнена в спрайтах, в формате BMP. Можно исользовать знак $ с результатом, аналогичным его использованию в функции wav.
anim[ <путь_к_первому_фрейму> <количество_фреймов> wait] - проигрывание анимации. Может использоваться и без wait, назначение этого ключевого слова мной не было определено.
kill_point_sound[<(sn)> <(ln1)> <(ln2)> <имя_звукового_файла>] - удаление заданного фонового звука в локации.
add_point_sound[<(sn)> <(ln1)> <(ln2)> <имя_звукового_файла> <относительная_громкость>] - добавление заданного фонового звука в локации. Относительная громкость - отрицательное число, обычно кратное 100.
close_inv[] - закрыть окно инвентаря.
Теперь обладая знанием этого скриптового языка можно открыть "упрямую" дверь, получить любой предмет, заставить глюки появляться постоянно (особенно относится к доске почета завода 8))).
Формат файла sound.dat еще проще, чем лом в разрезе:
<(sn)> <(ln1)> <(ln2)> <относительная_громкость> <имя_звукового_файла>
Т.е. таким образом мы можем положить любые фоновые звуки на любую локацию.
Остается загадочным формат записи информации о предметах, находящихся в конкретной локации. За это отвечают файлы ?map.vco. Например, неизвестно, есть ли альтернативы ключевому словосочетанию original cursor, что означают числа в area 1 140 124 484 (возможно, второе и третье числа - координаты левого верхнего угла предмета по x и y), что обозначает ключевое слово bong, почему используется только размер size - 100 100.
А теперь поговорим о некоторых ляпах программистов из SGsoft:
begin /*попытаться сунуть арканоида в комп директора*/
item 15 zone 8
if_not[noCD]
{
set_flag[noCD]
pop[p_nocd.wav]
} else[]
{
if_not[noCD2]
{
set_flag[noCD2]
}
} else[]
{
kill_flag[noCD]
kill_flag[noCD2]
}
end
Как мы видим, тут мы на каждый третий раз напоминаем, что в компьютере директора нет CD-ROM'а. Тут представлен несколько запутанный текст подпрограммы. Можно было бы сделать текст более читаемым и снизить нагрузку на интерпретатор, только сообщение будет возникать каждый второй раз (но это некритично):
begin /*попытаться сунуть арканоида в комп директора*/
item 15 zone 8
if_not[noCD]
{
set_flag[noCD]
set_flag[noCD2]
pop[p_nocd.wav]
}
if_not[noCD2]
{
kill_flag[noCD]
}
kill_flag[noCD2]
end
А вот файлик video/video.dv имеет формат streamed data library v0.3. С этим мы разберемся немного позже. Я предлагаю каждому читателю самостоятельно поэкспериментировать над игрушкой. Первостепенных задач несколько: выяснить, где и как хранятся номера предметов, где и как хранятся переходы с одной локации на другую, найти способ распаковки файла с видеороликами, выяснить назначения файла 0B340A19.fil (или аналогичного ему) на диске (хотя есть подозрения, что он относится к системе защиты Gefest). Результаты можно присылать на почтовый ящик журнала, мы их обязательно опубликуем.
|
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |