b5d2a81ee3
Одиннадцать наблюдений первого прогона свелись к шести корням, четыре
наблюдения второго — ещё к четырём. Разбор каждого — 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>
80 lines
3.2 KiB
C
80 lines
3.2 KiB
C
/*
|
|
* pop_redraw.c — пометки перерисовки тайлов и их разбор. См. pop_redraw.h.
|
|
*
|
|
* Живёт в W1/W2 (НЕ в резиденте W3): пометки ставит логика, которая должна
|
|
* оставаться достижимой из будущих __banked-модулей. Сам разбор зовёт
|
|
* pop_bg (резидент W3) — это законно, потому что разбор дёргает только
|
|
* главный цикл.
|
|
*/
|
|
#include <stdint.h>
|
|
#include "pop_redraw.h"
|
|
#include "pop_bg.h"
|
|
|
|
#define NTILES 30
|
|
#define NCOLS 10
|
|
|
|
static uint8_t rd_kind[NTILES], rd_cnt[NTILES];
|
|
static uint8_t rda_kind[NCOLS], rda_cnt[NCOLS];
|
|
/* Сколько всего непустых пометок: без него проход по 40 ячейкам крутился бы
|
|
* КАЖДЫЙ кадр впустую (замер 2026-07-27 на прежнем rest-цикле: ~12 % кадра). */
|
|
static uint8_t rd_pending;
|
|
|
|
void pop_redraw_reset(void)
|
|
{
|
|
uint8_t i;
|
|
for (i = 0; i < NTILES; i++) { rd_kind[i] = 0; rd_cnt[i] = 0; }
|
|
for (i = 0; i < NCOLS; i++) { rda_kind[i] = 0; rda_cnt[i] = 0; }
|
|
rd_pending = 0;
|
|
}
|
|
|
|
void pop_set_redraw(uint8_t tilepos, uint8_t kind, uint8_t pages)
|
|
{
|
|
if (tilepos >= NTILES) return;
|
|
if (!rd_cnt[tilepos]) rd_pending++;
|
|
rd_kind[tilepos] = kind;
|
|
if (pages > rd_cnt[tilepos]) rd_cnt[tilepos] = pages;
|
|
}
|
|
|
|
void pop_set_redraw_above(uint8_t col, uint8_t kind, uint8_t pages)
|
|
{
|
|
if (col >= NCOLS) return;
|
|
if (!rda_cnt[col]) rd_pending++;
|
|
rda_kind[col] = kind;
|
|
if (pages > rda_cnt[col]) rda_cnt[col] = pages;
|
|
}
|
|
|
|
/* redraw_needed (seg008:0178): пройти пометки и нарисовать. row/col ведём
|
|
* бегущими счётчиками, а не через i/10 и i%10 — у Z80 нет деления, и SDCC
|
|
* выносит __divuchar/__moduchar в вершину цикла как общее подвыражение
|
|
* аргументов (30*2 делений за кадр даже когда рисовать нечего). */
|
|
void pop_redraw_needed(void)
|
|
{
|
|
uint8_t i, row = 0, col = 0, left = 0;
|
|
if (!rd_pending) return;
|
|
for (i = 0; i < NTILES; i++) {
|
|
if (rd_cnt[i]) {
|
|
switch (rd_kind[i]) {
|
|
case POP_RD_SPIKE: pop_spike_redraw(row, col); break;
|
|
case POP_RD_LOOSE: pop_loose_shake_draw(row, col); break;
|
|
case POP_RD_LOOSE_GONE: pop_loose_bake_empty(row, col); break;
|
|
case POP_RD_FLOOR: pop_floor_bake(row, col); break;
|
|
case POP_RD_LEVELDOOR: pop_leveldoor_redraw(row, col); break;
|
|
case POP_RD_GATE: pop_gate_redraw(row, col); break;
|
|
default: break;
|
|
}
|
|
if (--rd_cnt[i]) left++;
|
|
else rd_kind[i] = 0;
|
|
}
|
|
if (++col == 10) { col = 0; row++; }
|
|
}
|
|
for (i = 0; i < NCOLS; i++) {
|
|
if (rda_cnt[i]) {
|
|
if (rda_kind[i] == POP_RDA_CEIL) pop_ceil_shake_draw(i);
|
|
else pop_ceil_bake_empty(i);
|
|
if (--rda_cnt[i]) left++;
|
|
else rda_kind[i] = 0;
|
|
}
|
|
}
|
|
rd_pending = left;
|
|
}
|