CHEAT и POKES
в игровых программах
часть 2
(С) 1996-99, Александр Десятниченко
__________________________________________
Таким образом, наше предположение оп-
равдалось. Командой DEC A по адресу 46278
количество жизней уменьшается на единицу,
затем снова отправляется на постоянное
хранение в ячейку 48249. Что ж, попробуем
направить работу этой процедуры в свое
русло, исключив из нее команду DEC A. Про-
ще всего, конечно, забить ее нулем, кото-
рый в переводе с языка машиного кода будет
обозначать, что в этой ячейке во время вы-
полнения программы не будет осуществляться
никакой операции (NOP), ну, а на языке
бейсика это звучит еще проще - POKE
646278,0.
Теперь, если вы вставите в загрузчик
строку с таким выражением перед запуском
игры командой RANDOMIZE USR, то, сколько
бы ваш герой в игре не умирал, у него все
равно будет в запасе еще 8 жизней, другими
словами, вы сделали его бессмертным. Ана-
логично в игре выглядит и процедура, до-
бавляющая жизнь при успешной игре:
45314 LD A,(48249)
45317 CP #08
45319 RET NC
45320 AND A
45321 INC A
45322 DAA
45323 LD (48249),A
45326 CALL 47988
Oна сначала проверяет, не равно ли ко-
личество жизней восьми, и, если оно
меньше, то будет увеличено на единицу ко-
мандой INC A. Пусть не пугает вас команда
DAA, - она нужна, чтобы подготовить число
жизней к печати на экране подпрограммой,
расположенной по адресу 47988. Taкой же
CALL 47988 вы найдете и после процедур,
задающих и отнимающих жизни. Часто приме-
няются еще два способа подготовки чисел к
печати: или же количество жизней сразу за-
дается на #30 больше, чем надо, как это
сделано в WAR MACHINE (LD A,#35), или же
посредством добавления числа #30 к коли-
честву жизней непосредственно перед печат-
ью (АDD А,#30).
Во многих играх количество жизней зада-
ется, минуя аккумулятор, при помощи ре-
гистра HL. Так, в игре CORSARIOS 2 это
сделано так: LD HL,#05. Нередко и убавле-
ние жизни тоже производится через тот же
регистр:
LD HL,24851
DEC (HL)
JP P,25018
Это был фрагмент игры BATMAN 3, а в
программе P-47 the FREEDOM FIGHTER приме-
нен комбинированный метод:
LD HL,29964
LD A,(HL)
DEC A
LD (HL),A
Занимаясь обессмерчиванием игр, вскоре
вы столкнетесь и с такой ситуацией, когда,
забивая нулем команды DEC A или DEC (HL),
при первом же погибании программа выдаст
знакомое сообщение: "GAME OVER". Дело в
том, что многие программы сразу же после
отнимания делают флаговую проверку, а ко-
манда NOP в таком случае пустит программу
не в ту степь. В таком случае, а, еще луч-
ше, в любом случае, вместо NOP следует
применять однобайтные команды OR A или OR
(HL) соответственно. Такое вы уже могли
наблюдать, просматривая списки POKES, где
по адресам вместо нуля заносится 182 или
183.
А теперь о других, менее распростренен-
ных способах. В игре NETHER WORLD, напри-
мер, вы сможете обнаружить еще один способ
убавления жизней:
33547 LD A,(65405)
33550 SUB #01
33552 LD (65405),A
В таком случае достаточно вместо #01
поставить #00 и пусть себе отнимает по ну-
лю жизней каждый раз. Достаточно оригина-
лен метод отнимания жизней с помощью ко-
манды SBC, как это сделано в игре SABRINA:
LD HL,(24618)
PUSH DE
EX DE,HL
LD HL,#01
EX DE,HL
AND A
SBC HL,DE
POP DE
LD (24618),HL
Нарушить нормальную работу такого фраг-
мента труднее, но тоже можно, например,
забив нули в SBC HL,DE и единичку в LD
HL,#01. Кстати, иногда бывает, что подоб-
ные подпрограмы заканчиваются директивой
RET и вызывается из основной програмы че-
рез CALL. Tогда можно поступить проще -
поставить RET (из бейсика - 201) в самое
начало такой подпрограммы, чтобы CALL сюда
как пришел, так ни с чем и ушел, не выпол-
нив ни единиго действия. Среди хакеров це-
нится именно такой способ инфинизации игр,
когда при малом колличестве POKES достига-
ется наибольшая отдача.
В сложных, тяжелых и, как правило,
очень интересных играх часто все лимиты, в
том числе и количество жизней, хранятся в
виде отдельной таблицы, выборка из которой
производится через индексные регистры.
Так, в программе CASANOVA количество жиз-
ней задается как LD (IX+43),#05 и, соот-
ветственно, убавляется как DEC (IX+43), a
в игре TERMINATOR 2 вы можете наблюдать
такое явление: DEC (IY-5). Нередко такие
таблички хранятся отдельно и после GAME
OVER выполняется LDIR ее на рабочее место,
как это сделано в PRINCE CLUMSY или RETURN
of the JEDI:
LD HL,54079
LD DE,54059
LD BC,20
LDIR
А затем и само отнимание жизни:
LD HL,54059
LD A,(HL)
OR A
SCF
RET Z
DEC (HL)
В некоторых программах ход событий
спланирован таким образом, что количество
ошибок с каждым тяжелым случаем увеличива-
ется и, при достижении определенного зна-
чения игра заканчивается. Впервые я такое
увидел в игре HAMMER BOY:
LD A,(42097)
INC A
LD (42097),A
Кстати, в этой игре подсчет ошибок ана-
логичным образом идет в двух местах и, ес-
ли хоть в одном из них достигнет предела,
то придется начать игру сначала. Подобного
рода методы применяются также в тех случа-
ях, когда контроль над одним и тем же ли-
митом из одного и того же фрагмента прог-
раммы невозможен или же если разного рода
ошибки отнимают разное количество жизней.
Естественно, что после того, как хакеры
начали "циклить" игры, программисты
фирм-производителей начали принимать меры
против подобного рода деятельности. В
подпрограммах, уменьшающих число жизней,
начали применятся, как в игре TARGET RENE-
GADE, недокументированные команды или, как
в JUNGLE WARRIOR, сдвиг битов в байте.
Найти такие вещи намного сложнее, да и что
там говорить, если перед хорошим кодером
поставить задачу сделать отнимание жизни
так, чтобы этого никто не нашел, я думаю,
многие бы справились. В таких случаях мож-
но пойти на хитрость и сделать кое-что
другое. Так, когда-то мне не удалось найти
отнимание жизни в игре MAD MIX, зато легко
отыскался участок, где задавалось коли-
чество жизней и фрагмент, где шла проверка
оставшегося значения:
LD A,#03
LD (24624),A
.....
LD A,(24624)
AND A
RET Z
Даже этого уже достаточно, чтобы ее
обессмертить, ведь проверка идет каждый
раз после того, когда заберут жизнь. А
что, если вместо проверки сделать снова
занесение в 24624 троечки? Тем более, что
такая программка будет занимать, как и
программа проверочки, те же пять байт. Та-
ким образом игра теперь будет забирать
жизнь, но сразу же после этого, вместо
проверки, устанавливать все те же три жиз-
ни.
5. Бесконечное время, оружие, энергия.
Нередко случается, что в азарте
быстренько расстреляешь весь боекомплект,
а затем сосешь палец, пока не убьют. Ес-
тественно, возникает желание все это сде-
лать бесконечно-вечным. Ну что ж, сложного
ничего нет, тем более что делается это
примерно теми же методами. Например, в иг-
ре HAWKSTORM вам дается 50 патронов.
Исследуя машинный код, нетрудно обнаружить
LD A,50, а затем, соответственно, и завет-
ное DEC A.
Время также довольно часто задается и
отнимается стандартно, вот как это выгля-
дит в игре ROBOCOP 2:
LD HL,43224
DEC (HL)
RET NZ
Но бывают случаи и потяжелее, когда ча-
сы, минуты и секунды задаются, проверяются
и отнимаются (или увеличиваются) отдельно.
Ну и очень уж часто приходится сталки-
ваться с самым интересным видом ограниче-
ния - энергией. Начнем с самого простого
вида представления энергии - числового,
когда энергия отображается, как большое
число, например, 100 или 1000 единиц. Та-
кое можно наблюдать например, в игре CAPI-
TAN TRUENO, но, снова-таки, все стан-
дартно:
LD HL,58943
DEC (HL)
JP Z,24042
В отличие от количества жизней, чаще
отнимается сразу несколько единиц энергии,
как в игре TIME MACHINE:
LD A,(60499)
SUB #03
LD (60499),A
Порой самой трудной задачей является
определить, сколько же единиц энергии име-
ет наш персонаж в самом начале игры, чтобы
было затем от чего плясать в процессе по-
иска. Ведь часто энергия отображается на
экране в виде полосочки. Хорошо, если она
состоит из отдельных элементов и их, как в
игре FORGOTTEN WORLDS, например, можно
сосчитать. А вот когда такой градации нет,
на что только не приходится уповать, -
считать, когда медленно убивают, через
сколько ударов придет хана или, скажем,
прикидывать по пикселям приблизительно, а
потом пытаться найти что-то подобное...
Ну, а теперь самый распостраненный ме-
тод отнимания энергии из игр серии SIRWO-
OD. Итак, удалось определить, что изна-
чально дается 48 единиц энергии и хранится
она в ячейке 59850, отнимается же при по-
мощи команды SUB:
LD C,2
LD A,(59850)
SUB C
BIT 7,A
JP NZ,39989
BIT 7,C
JR Z,LOOP
CP 48
JR C,LOOP
LD A,48
LD (59850),A
JP 42272
LOOP LD (59850),A
Kак видите, в С заносится количество
отнимаемой энергии, оно и вычитается из А
с последующей проверкой. Такое отнимание
имеет много преимуществ, ведь можно вычи-
тать различное количество энергии. Такое
может быть необходимо, когда, скажем, тре-
буется, чтобы различные виды монстров на-
носили герою различной силы повреждения.
Согласитесь, это делает игру более привле-
кательной и реалистичной. В принципе, эта
подпрограмма дает много места для вашего
творчества, можно для нее подобрать нес-
колько разных POKES и каждое будет по-сво-
ему реализовывать бесконечную жизнь, ну, а
самое простое здесь, конечно же, просто
забить нулем команду SUB C. Нечто подобное
найдете и в черепашках-ниндзя (TURTLES):
LD A,(24422)
LD B,A
LD A,16
SUB B
К тому же, в этой игре одной программой
отнимается энергия всех четырех черепашек,
что, безусловно, удобно в плане обессмер-
чивания. Но когда вы попытаетесь пройти
дальше, у вас появится еще один лимит -
время, за которое черепашки должны успеть
отключить все компьютеры, значит, придется
"циклить" теперь еще и его! Не удивляй-
тесь, подобного добра вам попадется еще
немало, особенно в играх, где на каждом
новом уровне новое задание. Или вот еще
ситуация, - в игре HUMAN KILLING MACHINE
после того, как вы ее обессмертите, первые
уровни пройдутся легко, но потом, на пос-
леднем уровне, после каждого вашего удара
противник так быстро отдыхает, что вы не
успеваете ему сбить эту энергию! Значит,
придется найти место, где ему добавляют
энергию и устранить этот сюрприз.
А вот нетипичный случай отнимания энер-
гии из полной версии игры XENON:
LD HL,52262
NEG
ADD A,(HL)
LD (HL),A
RET C
LD (HL),#00
Достаточно оригинально идет работа с
энергией в игре BRONX:
LD A,(64813)
XOR (IY-107)
LD (64813),A
Снова об играх от ATLANTIS SOFTWARE
(SHOW BROTHERS), написанных на каком-то
макроязыке и компилированных в машинный
код. Все лимиты задаются здесь через HL, а
обрабатываются процедуркой, работающей с
ячейкой памяти, в которой этот лимит хра-
нится. Достаточно поставить туда RET, что-
бы обессмертить одним приемом все ограни-
чения.
И еще такая заморочка. В игре CORSARIOS
с числовым представлением энергии, судя по
экрану, дается 600 единиц. Порывшись в
программе, не удалось найти место, где бы
фигурировало такое число. Поиграв еще нем-
ножко и внимательнее присмотревшись к то-
му, как убавлялась энергия, я заметил, что
задействуются только две первые цифры, а
последний ноль там вроде как для красо-
ты... Через минуту мое предположение оп-
равдалось, так как нашлось LD HL,60, а еще
через минуту игра шла в уже обессмерченом
виде.
6. IMMORTAL как самая сильная форма
бессмертия.
По сравнению с INFINITE LIVES, слово
IMMОRTAL (неуязвимость) появилось в лекси-
коне синклеристов не так давно. В 1992-м
году в Англии была выпущена программка HA-
KER AMAZING, в которой приводились много-
численные POKES и firm cheats, среди кото-
рых попадалось и это новое словечко. Мно-
гие пользователи, испытав опубликованные
там IMMORTAL, были просто поражены их ра-
ботой, после чего это понятие прочно при-
жилось и в нашей среде. Помните, Н.Родио-
нов в игре R-TYPE назвал такое POKE мисти-
ческим?
Что же это такое? Вы, наверное, видели,
как во многих играх, после того, как ваше-
го героя ухрюкают, он снова появляется, но
при этом несколько секунд помигивает, буд-
то готовится к новым приключениям. Причем,
пока он мигает, он практически неуязвим,
то есть его не берут пули, не давят танки,
а иногда он даже не тонет в воде. Кто по-
расторопней, тот в эти секунды может даже
умудриться пропрыгать несколько площадок,
пройдя, таким образом, тяжелое место, то
самое, где ваш герой удостоился быть уби-
енным прошлый раз. А что, если сделать,
чтобы персонаж на все время игры стал та-
ким неуязвимым, только чтобы не помигивал?
Вот это и будет самый что ни на есть IM-
MORTAL! Но как его найти? Можно, ведь вре-
мя, которое персонаж помигивает, где-то
задается и отнимается. Вот пример, пожа-
луй, из самой известной игры BUBBLE
BOBBLE:
43832 BIT Z,(IY+90)
43836 JP Z,43998
Время неуязвимости хранится в табличке,
идет его проверка и, если заменить JP Z на
JP и поставить вместо 90 число 150 (в той
ячейке всегда то, что нам сейчас надо),
можно запросто сделаться неуязвимым. А те-
перь фрагмент из SOLOMON'S KEY:
49318 LD HL,(49813)
49321 LD A,L
49322 OR H
49323 JP Z,49390
49326 LD DE,(43206)
49330 CALL 49356
49333 OR A
49334 RET Z
Если в этом фрагменте заменить условный
выход RET Z на более кардинальный RET и,
таким образом, отсечь часть программы, от-
вечающую за обработку столкновений с вра-
гами, то можно будет больше на них не
отвлекаться и сосредоточиться на самом ло-
гическом задании этой очень увлекательной
игры. А в игре JACK the NIPPER 2 по адресу
41218 находится целая подпрограмма, отве-
чающая за условия столкновения с врагами,
водой и стенами и, если в этих процедурках
заменить OR A на твердое XOR A, то можно
настроить программу полностью по своему
вкусу, например, прыгать, не разбиваясь, с
любой высоты.
А теперь главный принцип поиска неуяз-
вимости. Итак, сначала надо найти, где в
игре отнимается жизнь и потом смотреть от
этого места выше, разбираясь, что выполня-
ют те участки программы, которые отработа-
ли до того, как отнялась жизнь. Таким об-
разом можно найти фрагмент, где идет обра-
ботка столкновений и затем пустить его по
своему сценарию. Обычно приходится сделать
RET для такой подпрограммы или обойти ее,
поставив безусловный JR. Иногда, правда,
бывает достаточно, как в CABAL, забить ну-
лем DEC A, или, как в F1 TORNADO SIMULA-
TOR, исправить SUB #01.
конец второй части
__________________________________________