BUG-GATE-PASS-1: история флагов коллизии переживает боковой переход
Оригинал (seg004:0004) индексирует флаги перекрытия колонкой ВНУТРИ разрешённой комнаты и хранит рядом её номер, поэтому решётка комнаты 8 остаётся в своём слоте и после перехода 8->6: переход флага 0->1 виден, bumped() срабатывает. У нас индекс — колонка отрисованной комнаты, тот же тайл менял слот, и enter_room вынужден был выбрасывать историю целиком — на кадре входа бампа не было, и Кид с разбега уходил сквозь закрытые ворота. Вариант B (сдвиг вместо тега комнаты): при БОКОВОМ переходе история не выбрасывается, а перенумеровывается на 10 слотов. check_leave двигает x ровно на ∓140 = 10 тайлов, координата грани едет на те же 140 вместе с габаритом Кида — сами флаги инвариантны, меняется только номер слота. Сдвигаются curr/above/below (prev на следующем кадре всё равно перезапишет move_coll_to_prev), освободившиеся слоты = 3 «уже перекрывал». Вверх/вниз и прочие входы в комнату — по-прежнему полная инвалидация. Дословный вариант A (10 слотов + массив номеров комнат) не взят: он тянет за собой сужение окна перебора колонок, то есть отказ от FIX_COLL_FLAGS. Заведён docs/impl_diff.md — список осознанных расхождений с SDLPoP; правило «фиксировать расхождение» в обоих CLAUDE.md теперь указывает туда. tests-host: все 5 наборов прошли. Приёмка в MAME впереди. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -236,7 +236,8 @@ void pop_map_set_edges(uint8_t left, uint8_t right, uint8_t up, uint8_t down) __
|
||||
}
|
||||
/* смена комнаты — колонки перепроецированы, прошлые флаги перекрытия
|
||||
* недействительны (в оригинале prev_coll_room != curr_row_coll_room и
|
||||
* бампа на кадре входа нет). */
|
||||
* бампа на кадре входа нет). БОКОВОЙ переход это отменяет: вызывающий
|
||||
* сразу зовёт pop_coll_shift(∓10) и историю не теряет. */
|
||||
pop_coll_invalidate();
|
||||
}
|
||||
|
||||
@@ -1373,10 +1374,67 @@ static int8_t bump_col_l; /* bump_col_left_of_wall (Kid лицом ВПРА
|
||||
static int8_t bump_col_r; /* bump_col_right_of_wall (Kid лицом ВЛЕВО) */
|
||||
static int coll_xl, coll_xr; /* char_x_left_coll / char_x_right_coll */
|
||||
|
||||
/* Ряд, к которому относилась история ДО последней инвалидации — чтобы
|
||||
* pop_coll_shift мог её восстановить (см. ниже). */
|
||||
static int8_t coll_last_row = COLL_ROW_NONE;
|
||||
|
||||
/* Смена комнаты: колонки перепроецированы, прошлые флаги недействительны.
|
||||
* В оригинале это несовпадение prev_coll_room и curr_row_coll_room —
|
||||
* на кадре входа бампа нет. */
|
||||
static void pop_coll_invalidate(void) { coll_prev_row = COLL_ROW_NONE; }
|
||||
* на кадре входа бампа нет. Безопасный дефолт для ЛЮБОГО входа в комнату
|
||||
* (старт уровня, респавн, чит-навигация, переход вверх/вниз); боковой
|
||||
* переход тут же отменяет его через pop_coll_shift. */
|
||||
static void pop_coll_invalidate(void)
|
||||
{
|
||||
coll_last_row = coll_prev_row;
|
||||
coll_prev_row = COLL_ROW_NONE;
|
||||
}
|
||||
|
||||
/* БОКОВОЙ переход: историю не выбрасываем, а СДВИГАЕМ (BUG-GATE-PASS-1).
|
||||
*
|
||||
* Оригинал (seg004:0004) индексирует флаги колонкой ВНУТРИ разрешённой
|
||||
* комнаты и хранит рядом номер этой комнаты (row_coll_room_ptr), сравнивая
|
||||
* prev/curr только при совпадении номеров. Решётка комнаты 8 и до перехода
|
||||
* 8->6, и после лежит в слоте 9 с room = 8 — история переживает переход,
|
||||
* переход флага 0->1 виден, bumped() срабатывает. У нас индекс — колонка
|
||||
* ОТРИСОВАННОЙ комнаты, поэтому тот же тайл менял слот, история терялась, и
|
||||
* Кид с разбега проходил сквозь закрытые ворота шва.
|
||||
*
|
||||
* Физически колонки сдвигаются ровно на 10 (check_leave двигает x на ∓140 =
|
||||
* 10 тайлов по 14 px), и координата грани (pop_x_bump) сдвигается на те же
|
||||
* 140 вместе с габаритом Кида — значит САМИ ФЛАГИ инвариантны, меняется
|
||||
* только их номер слота. Отсюда весь фикс — перенумерация.
|
||||
*
|
||||
* Сдвигаем curr/above/below, а не prev: prev на следующем кадре всё равно
|
||||
* перезапишет move_coll_to_prev, выбирая источник как раз из этих трёх.
|
||||
* Освободившиеся слоты — 3 («уже перекрывал»), то есть бампа по ним нет:
|
||||
* ровно то, что в оригинале даёт несовпадение номера комнаты.
|
||||
*
|
||||
* dcol — насколько изменились НОМЕРА колонок: уход вправо −10, влево +10.
|
||||
* Отличия от дословного порта варианта A — applications/PoP/docs/impl_diff.md. */
|
||||
static void coll_shift_one(uint8_t *a, int8_t dcol)
|
||||
{
|
||||
int8_t i, j;
|
||||
if (dcol < 0) { /* источник правее — идём вперёд */
|
||||
for (i = 0; i < COLL_N; i++) {
|
||||
j = (int8_t)(i - dcol);
|
||||
a[i] = (j < COLL_N) ? a[j] : 3;
|
||||
}
|
||||
} else { /* источник левее — идём назад */
|
||||
for (i = COLL_N - 1; i >= 0; --i) {
|
||||
j = (int8_t)(i - dcol);
|
||||
a[i] = (j >= 0) ? a[j] : 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pop_coll_shift(int8_t dcol) __banked
|
||||
{
|
||||
if (coll_last_row == COLL_ROW_NONE) return; /* истории и не было */
|
||||
coll_prev_row = coll_last_row; /* отменить инвалидацию */
|
||||
coll_shift_one(coll_curr, dcol);
|
||||
coll_shift_one(coll_above, dcol);
|
||||
coll_shift_one(coll_below, dcol);
|
||||
}
|
||||
|
||||
/* set_char_collision (seg006:0723), горизонтальная часть: габарит персонажа
|
||||
* в комнатных координатах. char_x_left = obj_x/2 + 58 (минус полуширина при
|
||||
@@ -1445,7 +1503,12 @@ static void check_collisions(void)
|
||||
/* Вне рядов комнаты (падение мимо пола) get_tile отдаёт WALL во всех
|
||||
* колонках — считать по нему нечего. Стену в падении держит
|
||||
* do_fall/in_wall, выход из комнаты — check_leave_below. */
|
||||
if (Char.curr_row < 0 || Char.curr_row > 2) { coll_prev_row = COLL_ROW_NONE; return; }
|
||||
if (Char.curr_row < 0 || Char.curr_row > 2) {
|
||||
/* И coll_last_row тоже: curr/above/below остались от старого кадра,
|
||||
* сдвигать их при боковом переходе нечего (поведение как раньше). */
|
||||
coll_prev_row = coll_last_row = COLL_ROW_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
set_char_collision();
|
||||
move_coll_to_prev(Char.curr_row);
|
||||
|
||||
Reference in New Issue
Block a user