Данная статья, является логичным продолжением предыдущей, в которой я описал свою идею, мотивацию и начало процесса вхождения в увлекательный мир 8bit. Эта статья будет короткой, опишу процесс разгребания вступительного мультика с целью идентификации необходимых для перевода ресурсов. Ресурсов раз два и три, но тем не менее, начало есть начало.
Загружаем "PRES" в Ghidra по известному ранее адресу 0x9000, добавляем области памяти

Точка входа нам известна из прошлой статьи, это 35074 или $8902, смотреть будем в "декомпилированный" код, он компактнее, хотя и не всегда соответствует действительности
void main(void)
{
undefined *puVar1;
short in_DE;
byte (*paabVar2) [8] [32];
byte *pbVar3;
Set_Interrupts_and_Run();
CLS();
Clean8000to9000and5E00to6200();
Print_msg(&txt_FOR_CASSETTE);
Colors_Fading();
Print_msg(&txt_PRESENTS);
Colors_Fading();
Sprite(0,7,10);
Sprite(1,10,0xe);
Print_msg((HDmessage *)&txt_Delay);
Colors_Fading();
FUN_ram_9b7c(in_DE);
DAT_ram_ac2c = 200;
DAT_ram_ac2d = 0x10;
DAT_ram_ac41 = 0xe0;
DAT_ram_ac42 = 0x10;
DAT_ram_ac56 = 0xf0;
DAT_ram_ac57 = 0x10;
DAT_ram_ac6b = 200;
DAT_ram_ac6c = 0x10;
do {
FUN_ram_9a4d();
BYTE_ram_9620 = 1;
halt();
halt();
} while (0x27 < DAT_ram_ac2c);
Print_msg((HDmessage *)&txt_Delay);
Colors_Fading();
FUN_ram_9b8f(in_DE);
DAT_ram_ac2c = 0;
DAT_ram_ac2d = 0x28;
DAT_ram_ac30 = 1;
DAT_ram_ac41 = 0;
DAT_ram_ac42 = 0x28;
DAT_ram_ac45 = 1;
DAT_ram_ac6a = 0xfd;
DAT_ram_ac55 = 0xfd;
do {
FUN_ram_9a4d();
BYTE_ram_9620 = 1;
halt();
halt();
} while (DAT_ram_ac40 != -3);
Print_msg(&txt_START_TAPE);
pbVar3 = &DAT_ram_b192;
paabVar2 = SCR_BITS;
puVar1 = &DAT_ram_1b00;
do {
*(byte *)paabVar2 = *pbVar3;
paabVar2 = (byte (*) [8] [32])((short)paabVar2 + 1);
pbVar3 = pbVar3 + 1;
puVar1 = puVar1 + -1;
} while (puVar1 != (undefined *)0x0);
disableMaskableInterrupts();
setInterruptMode(0);
enableMaskableInterrupts();
return;
Нас интересуют Print_msg и Sprite. Print_msg принимает ссылку на адрес комбинированной строки в регистре HL
ram:9a9c LD HL,txt_FOR_CASSETTE
ram:9a9f CALL Print_msg
ram:9aa2 CALL Colors_Fading
ram:9aa5 LD HL,txt_PRESENTS
ram:9aa8 CALL Print_msg
ram:9aab CALL Colors_Fading
Текст может содержать в себе заголовок со всем необходимым

В тексте могут содержаться маркеры, которые могут задать 1 - координаты на экране для вывода сообщения, 2 - цвет, как фона так и текста, стандартный байт аттрибута, 3 - размер шрифта, сообщение может выводиться с увеличением высоты символа в x раз, 6 - задержка, 0 - закончили с текстом. Знакогенератор находится по адресу 0xAC7E

Со спрайтами чуть проще, координаты задаются при вызове функции, координаты измеряются не в точках а в знакоместах, как у текста, скорее всего, чтобы не заморачиваться с клэшингом. Необходимая нам процедура Sprite принимает номер спрайта и координаты в регистрах A, B, C
ram:9aae LD A,0x0
ram:9ab0 LD B,0x7
ram:9ab2 LD C,0xa
ram:9ab4 CALL Sprite
ram:9ab7 LD A,0x1
ram:9ab9 LD B,0xa
ram:9abb LD C,0xe
ram:9abd CALL Sprite
Адреса спрайтов получаются складыванием базового адреса 0xAA9c и смещение из таблицы смещений по адресу 0x9889
ram:9889 ushort[3]
ram:9889 [0] 0h, 146h, 190h
, размер спрайта содержится в начале самого спрайта, размер тоже в знакоместах
ram:aa9a HDRsprite
ram:aa9a db Ch width
ram:aa9b db 3h height
ram:aa9c ?? 0Fh
ram:aa9d ?? F0h
ram:aa9e ?? FFh
Colors_Fading осуществляет "красивую" очистку экрана, с переливающимися цветами. Вроде всё рассказал... Далее будет разбор файла самой игры, или сначала загрузчик переделаю, ещё не решил. Ниже текстовые сообщения, спрайты в заголовке статьи.



kmatveev
Круто.
Дизайнер шрифта - чёртов гений. В клетку 8*8 вставить буквы, у которых толщина линий 3 пикселя, и оно всё равно отлично читается.