IMMORTAL #2
(C) Ржавельщик.
________________________________
Вместо предисловия.
Продолжать эту рубрику изна-
чально не входило в мои планы,
однако недавно я наткнулся на
интересную фразу в ON-LINE, а
именно: "...прочитал вышеизло-
женное и понял,что вряд-ли когда
смогу объяснить что-нибудь не
хакеру..." (за точность цитаты
не ручаюсь, но смысл такой).
После этого перечел я свой
опус... м-да, некоторые пробелы
имеются.
Для начала закончу. В первой
части я забыл упомянуть об одной
маленькой гадости, которая носит
название "двоично - десятичное
представление чисел". Что кроет-
ся за этим заковыристым терми-
ном? А вот что: иногда, для
удобства расчетов или для неких
других целей число приводится в
особый вид при помощи команды
DAA (#27). При таком представле-
нии полубайты содержат код деся-
тичной цифры от 0 до 9. Таким
образом в байт можно поместить
числа до #99. Чaсто программу
строят так, что она работает с
"квазидесятичной" системой сче-
та. Это значит, что содержимое
регистра следует считать деся-
тичным, т.е. #35=35 #99=99 и
т.д. Короче, если в начале игры
дается время 60 секунд, то ис-
кать следует не #3e #3c #32 (LD
a,60...), а #3e #60 #32 т.е. LD
a,#60 !!!. Очень популярен сей
изврат в программах с часами (в
основном - в гонках). Пример: в
Wec le Mons на старте счетчик
показывает 66.0 с. Поиск LD A,66
не дал результата. Применив кон-
цепцию двоично - десятичного
представления (BCD) ищем LD
A,#66... Облом - нет такой буквы
в этом слове. Отсюда следует
утюжок, что секунды выставляются
вместе с десятыми долями, через
регистровую пару.
Следует отметить, что так как
стандартные команды обработки
двубайтных чисел здесь не приме-
няются, на intel'овский стандарт
расположения "длинного" числа в
памяти часто забивают и байты
могут стоять хоть в шахматном
порядке. Найденная в конечном
итоге процедура установки време-
ни выглядела так:
LD HL,#1066
LD (addr),HL
Ну вот, пожалуй на этом можно
закончить вводный курс анатомии
программ для начинающих хакеров.
Напоследок скажу только, что на-
иболее сложную структуру обычно
имеют текстовушки (если они в
кодах) и вообще всяческие адвен-
тюры, а самую неудобоваримую -
откомпилированные с BASIC'а.
________________
А теперь, собственно, то, ра-
ди чего я затеял продолжение
этой статейки.
Полагаю, что многие, воодуше-
вившись перспективой легкой жиз-
ни, лихо сломали все свои (и чу-
жие) игры, вошли во вкус и, из-
ломав в пыль все, до чего сумели
дотянутья, уперлись дебугером в
такой риторический вопрос: Куда
ставить будем? А по этому поводу
"...у меня есть библиотечка!".
Возможно Вы уже попробовали спо-
соб выбора INFINIT'а при помощи
ADM'а (не слишком удобно, а?),
при помощи теневика scorpoin'а
(кхм... удобно конечно, но все
же как то...) или сделали самую
большую подборку игр жанра "щас
я вам всем покажу".
Дальнейшее посвящается вопро-
су - куда будем ставить. Однако
сразу скажу, что я как не соби-
рался переписывать брошюрку
"тайники ZX", так и не собираюсь
писать пособие "Как сделать
интру". Интрами я вообще не ба-
луюсь (почти). Надеюсь, что не
оскорблю Вас в лучших чувствах,
если покажу как делается выбор
бессмертия из BASIC'а. Наверняка
Вам приходилось видеть в ленточ-
ных версиях такой вариант: лоа-
дер стопится нажатием на BREAK;
из строки, содержащей REM и
POKE's, удаляется REM и лоадер
запускается снова. В дисковой
версии LOAD'ер не очень то тор-
мознешь, ввиду этого можно вста-
вить в него такие строки:
30 PRINT "inf.lives ? (Y/N)"
40 LET K$=inkey$:IF K$="y" OR
K$-"Y" THEN POKE addr,n:
GOTO 60
50 GOTO 40
Запомнили? Хорошо. Никогда
так не делайте - это безграмотно
и громоздко. Более правильно за-
дать этот коварный вопрос из ко-
дов и считать ответ из кодов же.
Особенно это актуально для 128-х
игрушек с кодовым лоадером, в
которых требуется изменить со-
держимое нескольких страниц па-
мяти. Вот пример кодовой менюшки
для такого случая:
LD BC,#000E - L5D83
LD DE,L5D9B )
XOR A ) печать
CALL #203C )
LD BC,#0010 ) меню
LD A,#00 )
LD DE,L5DAA )
CALL #203C -
JR L5DBB
DEFB #80
DEFB #16,#0A,#0A L5D9B
DEFM "1.INF.LIVES"
DEFB #FF
DEFB #16,#0C,#0A L5DAA
DEFM "2.NORMAL GAME"
DEFB #FF
LD BC,#F7FE - L5DBB
IN A,(C) )
BIT 0,A ) опрос
JR Z,L5DC9 )
BIT 1,A ) клавиш
RET Z )
JR L5DBB -
LD BC,#7FFD L5DC9
LD A,#14
DI
OUT (C),A
XOR A
LD (#C7CA),A
LD A,#16
DI
LD BC,#7FFD
OUT (C),A
XOR A
LD (#C472),A
RET
LD A,#02
CALL #1601
JR L5D83
Коментарии: процедура #203C
выполняет печать сообщения по
адресу DE, длиной BC в текущий
поток, который устанавливается
процедурой #1601 (A содержит но-
мер потока). Основной экран -
поток 2, служебный - 1. Обратите
внимание на процедуру по L5DC9,
это и есть "обессмерчивание".
Данный фрагмент вызывается
CALL'ом после загрузки програм-
мы, и по RET происходит запуск
игры (кстати, этот фрагмент взят
из моей версии ARMYMOVE1'&2 в од-
ном флаконе).
# Как видите, ничего сложного в
такой менюшке нет, а на бейсике
ее не реализовать, так как здесь
производится переключение стра-
ниц RAM. Естественно, возможны и
другие варианты построения по-
добной процедуры, особенно по
части печати меню. Могу предста-
вить, как расфыркались считающие
себя профессионалами дочитав до
CALL #203C. Обычно для оной цели
используют нечто такого вида:
LD HL,addr
LD A,(HL) <-LOOP
OR A
RET Z
RST #10
INC HL
JR LOOP
Оба варианта понимают управ-
ляющие коды и используют пере-
менные BASIC'а. Если же Вас в
самый неудачный момент свалил
страшный приступ лени, то можно
попробовать скомпоновать BASIC и
коды, чтобы упростить задачу пе-
чати и опроса клавиш. Представ-
ляю Вашему вниманию настоящий
шедевр ленивости:
0 REM (кодовый лоадер)
15 PRINT AT PI*PI, PI*PI; "INF.
LIVES (Y/N)": PAUSE NOT PI:
IF INKEY$ ="y" THEN POKE VAL
"23908",VAL "182"
20 BORDER NOT PI:CLEAR VAL "2449
9":RANDOMIZE USR VAL "23872"
В кодах по 23907 стояло #3e
#35, а после - LD (addr),A. Вы
конечно помните, что #35<->DEC
(HL), а 182<->OR (HL). При отве-
те "Y" DEC менялось на OR и пос-
ле загрузки ставилось в коды иг-
рушки. Кстати, при всем велико-
лепии BASIC'а, это явление пред-
ставляло собой монолоадер.
По принципу своего действия
данная программка вплотную при-
мыкает к столь любимым многими
хакерами INTRO. Обычно INTRO
грузится и отрабатывает до заг-
рузки основной программы, изме-
няя пару байт в лоадере. Так как
оно имеет солидный объем (бегу-
щая строка, музыка и т.д.) то Вы
имеете возможность всласть поиз-
деваться над пользователем, на-
мекнув, что если он отгадает за-
гадку и нажмет на клавиатуте от-
вет (слово из 11-и букв), то,
может быть, получит бессмертие.
Для полноты курса рассмотрим
примерчик:
LD BC,#7FFE - LOOP
IN A,(C) ) опрос
BIT 0,A ) space
JR NZ,L61ED -
DI
IM 1
CALL #6B2E
LD HL,#4000
LD DE,#4001
LD BC,#1AFF
LDIR
RET
NOP L61ED
LD A,#FD
IN A,(#FE)
BIT 4,A ->"G"
JR NZ,L621E
LD A,#BF
IN A,(#FE)
BIT 1,A ->"L"
JR NZ,L621E
LD A,#FB
IN A,(#FE)
BIT 2,A ->"E"
JR NZ,L621E
LD A,#7F
IN A,(#FE)
BIT 3,A ->"N"
JR NZ,L621E
LD A,#22
LD (#5D73),A
LD B,#27
OR #F8 L6217
OUT (#FE),A
INC A
DJNZ L6217
JR LOOP L621E
Работает эта штучка так: если
нажато "space", то продолжается
загрузка, если нет - идет опрос
клавиатуры. Когда нажата первая
клавиша пароля, программа прове-
ряет, нажата ли следующая. Если
не нажата первая буква, то про-
исходит выход из программы опро-
са на зацикливание. Когда нажаты
все буквы пароля, в загрузчике
меняется байт и интра, весело
помигав бордюром, выходит на за-
цикливание. В бегущей строке,
поближе к концу, говорится, что
если пользователь знает как зо-
вут вокалиста DEICIDE, он может
это немедленно подтвердить и по-
лучить за свой культурный уро-
вень вечную жизнь.
Одна тонкость: ничего, произ-
водящего явно видимый эффект,
последовательно с такой прог-
раммкой ставить нельзя, так как
каждая правильно нажатая клавиша
увеличивает время выполнения
цикла, что приведет к подторма-
живанию в работе последовательно
стоящих операций цикла (напри-
мер, будет дергаться мультипли-
кация). Это позволит выявить код
методом перебора. Бегущая строка
и музыка в этом примере стоят в
цикле прерывания.
При определенном навыке по-
добную процедурку можно втиснуть
и в саму игру, хотя пожалуй это
уже дурной тон (тем более, что
во многих играх и так есть фир-
менный CHEAT MODE).
Ну вот, теперь, кажется, дей-
ствительно конец. Надеюсь, что
прочитанное пошло Вам на пользу
и Вы не собираетесь умирать от
скуки.