PoP: roomtest — объекты/обломки/переходы комнат + арт

Порт Prince of Persia (applications/PoP/roomtest): развитие уровня,
объекты (loose-полы/обломки), переходы между комнатами, фон-упаковка;
планы (room_model/size_optimization), bug_list, pop_trob.
Арт third_party/16x16-RPG-characters.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 19:38:23 +03:00
parent 3d586af031
commit 86d7615841
33 changed files with 2199 additions and 64 deletions
+53
View File
@@ -20,12 +20,16 @@ extern void _gfx_w0_isr(void);
/* Смещения блоков blueprnt относительно начала данных (Table 6). */
#define BP_FG 0u
#define BP_BG 720u
#define BP_LINKLOC 1440u /* doorlink1 (LINKLOC), 256 Б */
#define BP_LINKMAP 1696u /* doorlink2 (LINKMAP), 256 Б */
#define BP_LINKS 1952u
#define BP_START 2112u
#define ROOM_TILES 30u
#define MIN_SIZE (BP_START + 3u) /* минимум, чтобы прочитать старт */
static uint8_t lvl_blk, lvl_page, lvl_ok;
/* Копии таблиц дверных связей в W2 (LINKMAP мутабельна — таймеры кнопок). */
static uint8_t dl1[256], dl2[256];
int pop_level_load(const char *path)
{
@@ -47,11 +51,17 @@ int pop_level_load(const char *path)
/* Файл целиком в offset 0x100 (ESTEX READ пишет в W3 — как atlas_load). */
n = read(fd, pg + LVL_DATA_OFF, 16384 - LVL_DATA_OFF);
if (n >= (int)MIN_SIZE) { /* пропатчить ISR-стаб */
uint16_t i;
stub = (uint16_t)&_gfx_w0_isr;
pg[0x38] = 0xC3; /* JP _gfx_w0_isr */
pg[0x39] = (uint8_t)(stub & 0xFF);
pg[0x3A] = (uint8_t)(stub >> 8);
pg[0x66] = 0xED; pg[0x67] = 0x45; /* RETN (NMI-хвост) */
/* Скопировать таблицы дверных связей в W2 (страница ещё в W3). */
for (i = 0; i < 256; i++) {
dl1[i] = pg[LVL_DATA_OFF + BP_LINKLOC + i];
dl2[i] = pg[LVL_DATA_OFF + BP_LINKMAP + i];
}
}
sprinter_page_w3(saved_w3);
close(fd);
@@ -154,6 +164,49 @@ int8_t pop_room_col_landing(uint8_t room, uint8_t col)
return res;
}
uint8_t pop_doorlink1(uint8_t i) { return dl1[i]; }
uint8_t pop_doorlink2(uint8_t i) { return dl2[i]; }
void pop_doorlink2_set(uint8_t i, uint8_t v) { dl2[i] = v; }
uint8_t pop_level_tile(uint8_t room, uint8_t tilepos)
{
uint8_t v;
if (!lvl_ok || room < 1 || room > 24 || tilepos >= ROOM_TILES) return 0;
gfx_w0_map(lvl_page);
v = (uint8_t)(room_fg_ptr(room)[tilepos] & 0x1F);
gfx_w0_unmap();
return v;
}
/* Батч-доступ: смаппить страницу уровня в W0 ОДИН раз, прочитать много
* тайлов через pop_level_tile_raw, размаппить один раз. Экономит N свапов
* окна 0 в горячих циклах (pop_process_trobs звал pop_level_tile на каждый
* trob каждый кадр). Между begin/end НЕЛЬЗЯ рисовать/звать код, которому
* нужно окно 0 в исходном состоянии — только сырые чтения уровня. */
void pop_level_access_begin(void) { if (lvl_ok) gfx_w0_map(lvl_page); }
void pop_level_access_end(void) { if (lvl_ok) gfx_w0_unmap(); }
uint8_t pop_level_tile_raw(uint8_t room, uint8_t tilepos)
{
if (!lvl_ok || room < 1 || room > 24 || tilepos >= ROOM_TILES) return 0;
return (uint8_t)(room_fg_ptr(room)[tilepos] & 0x1F);
}
void pop_level_room_bg(uint8_t room, uint8_t *out30)
{
const uint8_t *rbg;
uint8_t i;
if (!out30) return;
if (!lvl_ok || room < 1 || room > 24) {
for (i = 0; i < ROOM_TILES; i++) out30[i] = 0;
return;
}
gfx_w0_map(lvl_page);
rbg = room_bg_ptr(room);
for (i = 0; i < ROOM_TILES; i++) out30[i] = rbg[i];
gfx_w0_unmap();
}
uint8_t pop_room_link(uint8_t room, uint8_t side)
{
uint8_t v;