L1: фиксы прогона уровня 1 — уровень мутабелен, стражи, loose-плиты, порядок
Одиннадцать наблюдений первого прогона свелись к шести корням, четыре
наблюдения второго — ещё к четырём. Разбор каждого — bug_closed.md.
Первая волна:
- BUG-LVLSTATE-1: уровень стал мутабельным (эталонная копия foretable для
рестарта, pop_level_set_tile вместо таблицы оверрайдов);
- BUG-RESPAWN-1: рестарт = load_level, тайлы возвращаются из эталона;
- BUG-DEATH-1: смерть от меча доигрывается (порт control_kid, seg006:0CD1);
- BUG-GATE-ANIM-1: ворота в отрисованной комнате перерисовываются
(POP_RD_GATE, порт draw_trob seg007:01E6);
- BUG-COLL-1: полный порт check_collisions/bumped (seg004) вместо поиска
стены только в колонке переднего края;
- BUG-STANDUP-1: убран лишний guard в bumped_floor — вставание у стены
роняло Кида сквозь пол.
Вторая волна:
- BUG-RESPAWN-2: рестарт возвращает и СТРАЖЕЙ (в оригинале play_level на
каждой итерации делает load_level + pos_guards);
- BUG-LOOSE-2: падающий кусок привязан к своей комнате и долетает после
ухода Кида (do_mobs крутит mobs[] независимо от drawn_room);
- BUG-DRAWORDER-1: порядок «Кид / страж» задаётся обходом тайлов
(redraw_needed_tiles: ряды 2,1,0, колонки 0..9), а не ролью персонажа.
По BUG-DRAWORDER-1 понадобилось три захода, и два первых были неполны:
1) сам порядок — но общее окно fore-клипа осталось стражьим, и Кид
нарисовался поверх передних столбов (kid_fore_clip_restore);
2) enter_guard брал curr_col из тайла, а leave_guard пишет туда
get_tilepos(0,row) — у запомненного ТРУПА колонка была 0 при
настоящей X. Теперь колонка выводится из X, как в оригинале;
3) ветка actions_1_run_jump в set_objtile_at_char оказалась не
«упрощаемой»: в беге тайл берётся из нижнего ряда и ЛЕВОЙ колонки
габарита, поэтому бегущий Кид уходит за объекты справа. Считается
для обоих персонажей — enter_guard ставит action=1 и стражу.
Проверено в MAME: зелья/меч/плиты переживают выход из комнаты и
восстанавливаются после смерти; кнопка room5 поднимает решётку; падение с
кнопки больше не роняет в комнату 6; убитый страж жив после respawn;
Кид проходит за телом стража. make size-check — роста нет.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,12 @@
|
||||
extern void _gfx_w0_isr(void);
|
||||
|
||||
#define LVL_DATA_OFF 0x100u /* данные с 0x100; 0x00..0xFF — ISR-стаб */
|
||||
/* Эталонная копия foretable В ТОЙ ЖЕ странице: страница 16 КБ, данных
|
||||
* уровня 2.3 КБ — место даром. Нужна, потому что foretable теперь
|
||||
* МУТАБЕЛЬНАЯ (pop_level_set_tile), а рестарт уровня в оригинале —
|
||||
* это load_level() заново (play_level, seg003:57), то есть все плиты целы
|
||||
* и зелья на месте. pop_level_reset_tiles восстанавливает из неё. */
|
||||
#define LVL_PRISTINE_OFF 0x1000u
|
||||
|
||||
/* Смещения блоков blueprnt относительно начала данных (Table 6). */
|
||||
#define BP_FG 0u
|
||||
@@ -74,6 +80,9 @@ int pop_level_load(const char *path)
|
||||
dl1[i] = pg[LVL_DATA_OFF + BP_LINKLOC + i];
|
||||
dl2[i] = pg[LVL_DATA_OFF + BP_LINKMAP + i];
|
||||
}
|
||||
/* Эталон foretable — для рестарта уровня (см. LVL_PRISTINE_OFF). */
|
||||
for (i = 0; i < 24u * ROOM_TILES; i++)
|
||||
pg[LVL_PRISTINE_OFF + i] = pg[LVL_DATA_OFF + BP_FG + i];
|
||||
}
|
||||
sprinter_page_w3(saved_w3);
|
||||
close(fd);
|
||||
@@ -184,6 +193,48 @@ int8_t pop_room_col_landing(uint8_t room, uint8_t col)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* set_tile-запись в ЖИВУЮ foretable уровня (порт curr_room_tiles[…] = …).
|
||||
* В оригинале уровень — обычная структура в ОЗУ, и do_pickup (seg006:1671),
|
||||
* remove_loose (seg007:0EB8), loose_land (seg007:11E8) правят её насовсем.
|
||||
* У нас уровень в EMM-странице — пишем прямо туда, поэтому изменение
|
||||
* переживает выход из комнаты (BUG-LVLSTATE-1). Пишем БАЙТ ЦЕЛИКОМ:
|
||||
* старшие биты старого тайла (напр. 0x20 «solid loose») к новому типу
|
||||
* отношения не имеют. */
|
||||
void pop_level_set_tile(uint8_t room, uint8_t tilepos, uint8_t tile)
|
||||
{
|
||||
if (!lvl_ok || room < 1 || room > 24 || tilepos >= ROOM_TILES) return;
|
||||
gfx_w0_map(lvl_page);
|
||||
((uint8_t *)(LVL_DATA_OFF + BP_FG))[(uint16_t)(room - 1) * ROOM_TILES + tilepos]
|
||||
= tile;
|
||||
gfx_w0_unmap();
|
||||
}
|
||||
|
||||
/* Рестарт уровня (порт load_level из цикла play_level, seg003:57): вернуть
|
||||
* foretable в исходное состояние из эталонной копии. */
|
||||
void pop_level_reset_tiles(void)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t *dst;
|
||||
const uint8_t *src;
|
||||
if (!lvl_ok) return;
|
||||
gfx_w0_map(lvl_page);
|
||||
dst = (uint8_t *)(LVL_DATA_OFF + BP_FG);
|
||||
src = (const uint8_t *)LVL_PRISTINE_OFF;
|
||||
for (i = 0; i < 24u * ROOM_TILES; i++) dst[i] = src[i];
|
||||
gfx_w0_unmap();
|
||||
}
|
||||
|
||||
/* Рестарт уровня, часть вторая (тот же load_level + pos_guards, seg003:83):
|
||||
* стражи — такая же часть данных уровня, как тайлы, и перезагрузка файла
|
||||
* возвращает их всех. Убитый до смерти Кида страж после respawn снова жив
|
||||
* и стоит на исходном тайле; забывается и запомненная поза трупа
|
||||
* (guards_seq_hi = 0 -> «поднять стандартной стойкой»). */
|
||||
void pop_level_reset_guards(void)
|
||||
{
|
||||
if (!lvl_ok) return;
|
||||
gstate_init();
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
Reference in New Issue
Block a user