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:
@@ -23,7 +23,9 @@ sprinter-cc / libc / libbgi. Действуют правила корневог
|
||||
исходнике, а не додумывать.
|
||||
3. Расхождение нашей реализации с SDLPoP — по умолчанию **баг у нас**, пока
|
||||
не доказано обратное (наша платформа/ABI требует отличия — тогда явно
|
||||
зафиксировать почему в комментарии).
|
||||
зафиксировать почему в комментарии **и записью в `docs/impl_diff.md`**:
|
||||
что делает оригинал, что делаем мы, чем платим, что проверять при
|
||||
регрессе).
|
||||
|
||||
Карта сегментов: `seg005` control-диспетчер, `seg006` play_kid/коллизия/
|
||||
seqtbl, `seg007` mob/loose/падающие объекты, `seg008` отрисовка тайлов/
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|----------|-------|
|
||||
| [`../roomtest/TASKS_OPEN.md`](../roomtest/TASKS_OPEN.md) | **Что берётся в работу сейчас** (не в этой папке, но входная точка) |
|
||||
| [`../roomtest/bug_list.md`](../roomtest/bug_list.md) | Открытые баги roomtest (закрытые — в `bug_closed.md` рядом) |
|
||||
| [`impl_diff.md`](impl_diff.md) | **Осознанные расхождения с SDLPoP**: где мы сделали не дословно и почему |
|
||||
| [`levels_plan.md`](levels_plan.md) | Следующий этап: уровни 2+, второй тайлсет, читы SDLPoP |
|
||||
| [`layout_plan_v2.md`](layout_plan_v2.md) | Раскладка кода по окнам/банкам/страницам + замеры скорости отрисовки |
|
||||
| [`room_model_plan.md`](room_model_plan.md) | `kid_room ≠ drawn_room` (straddle): сделан S1, остальное впереди |
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
# Осознанные расхождения с SDLPoP
|
||||
|
||||
Правило подпроекта (`../CLAUDE.md`): расхождение нашей реализации с
|
||||
`SDLPoP/src/` — по умолчанию **баг у нас**. Этот файл — список исключений:
|
||||
мест, где мы сознательно сделали иначе, потому что платформа/ABI/бюджет
|
||||
кадра требуют другого, а НАБЛЮДАЕМОЕ поведение обязано совпадать.
|
||||
|
||||
Формат записи: что делает оригинал → что делаем мы → почему → чем платим и
|
||||
что проверять при регрессе. Если запись перестала быть верной (портировали
|
||||
дословно, отказались от обхода) — удалять, а не оставлять «для истории»:
|
||||
история в git.
|
||||
|
||||
---
|
||||
|
||||
## D-1. История флагов перекрытия у бокового шва: сдвиг вместо тега комнаты
|
||||
|
||||
**Файлы:** `roomtest/pop_map.c` (`pop_coll_shift`, `pop_coll_invalidate`,
|
||||
`check_collisions`), `roomtest/roomtest.c` (`enter_room_side`).
|
||||
**Связанный баг:** BUG-GATE-PASS-1 (`roomtest/bug_closed.md`).
|
||||
**Дата:** 2026-08-09.
|
||||
|
||||
### Как в оригинале
|
||||
|
||||
`check_collisions` (seg004:0004) вместе с `get_row_collision_data`
|
||||
(seg004:0185) держит **10 слотов** флагов перекрытия и рядом —
|
||||
**параллельный массив номера комнаты**:
|
||||
|
||||
```c
|
||||
row_coll_flags_ptr[tile_col] = curr_flags; /* tile_col — колонка ВНУТРИ разрешённой комнаты (0..9) */
|
||||
row_coll_room_ptr [tile_col] = curr_room; /* и номер этой комнаты */
|
||||
...
|
||||
for (short column = 9; column >= 0; --column) {
|
||||
if (curr_row_coll_room[column] >= 0 &&
|
||||
prev_coll_room[column] == curr_row_coll_room[column]) {
|
||||
if ((prev_coll_flags[column] & 0x0F) == 0 &&
|
||||
(curr_row_coll_flags[column] & 0x0F) != 0)
|
||||
bump_col_left_of_wall = column;
|
||||
...
|
||||
```
|
||||
|
||||
Ключ слота — пара **(колонка в своей комнате, номер комнаты)**. Решётка
|
||||
комнаты 8 и до перехода 8→6, и после лежит в слоте 9 с `room = 8`: история
|
||||
переживает смену комнаты, переход флага 0→1 виден, `bumped()` срабатывает.
|
||||
Комнату оригинал резолвит на лету через `find_room_of_tile` (seg006:005D),
|
||||
никакого кэша всех комнат у него нет.
|
||||
|
||||
### Что делаем мы
|
||||
|
||||
Индекс — **колонка ОТРИСОВАННОЙ комнаты**, диапазон −2…11 (14 слотов,
|
||||
`COLL_C0`/`COLL_N`/`COLL_IDX`), номер комнаты рядом не хранится. При смене
|
||||
комнаты тот же физический тайл менял бы слот на ±10, поэтому раньше история
|
||||
просто выбрасывалась (`pop_coll_invalidate` → `prev = 3` = «уже
|
||||
перекрывал» → бампа нет). Именно это и был BUG-GATE-PASS-1.
|
||||
|
||||
Теперь при **боковом** переходе история не выбрасывается, а
|
||||
**перенумеровывается**: `pop_coll_shift(∓10)` сдвигает `coll_curr`,
|
||||
`coll_above`, `coll_below` на 10 слотов и заполняет освободившиеся
|
||||
тройками. `enter_room_side` зовёт её сразу после `pop_map_set_edges`.
|
||||
|
||||
Корректность держится на том, что `check_leave` двигает `Char.x` ровно на
|
||||
∓140 = 10 тайлов по 14 px, и координата грани (`pop_x_bump[col + …]`)
|
||||
сдвигается на те же 140 вместе с габаритом Кида, — **сами флаги
|
||||
инвариантны**, меняется только номер слота. Сдвигаются `curr/above/below`,
|
||||
а не `prev`: `prev` на следующем кадре всё равно перезапишет
|
||||
`move_coll_to_prev`, выбирая источник как раз из этих трёх.
|
||||
|
||||
Переходы **вверх/вниз** и все прочие входы в комнату (старт уровня,
|
||||
респавн, чит-навигация) остаются на полной инвалидации: там колонки не
|
||||
сдвигаются, но тайлы под ними принадлежат другой комнате — история
|
||||
действительно недействительна.
|
||||
|
||||
### Почему не дословно (вариант A)
|
||||
|
||||
Дословный порт — 10 слотов + параллельный массив номера комнаты, индекс по
|
||||
колонке разрешённой комнаты, бамп только при совпадении номеров; тогда
|
||||
`pop_coll_invalidate` не нужен вовсе, история сама «не совпадает» там, где
|
||||
колонка сменила комнату.
|
||||
|
||||
Не взяли по одной причине: **десяти слотов нам не хватит**. Оригинал
|
||||
перебирает узкое окно вокруг Кида (от `col(char_x_left_coll) − 1` до
|
||||
`col(char_x_right_coll) + 2`), поэтому коллизии слотов у него практически
|
||||
не случаются. Мы намеренно считаем все четырнадцать колонок сразу
|
||||
(FIX_COLL_FLAGS из SDLPoP — чтобы не оставалось протухших ячеек), а при
|
||||
таком переборе колонки −2/−1 и 8/9 сядут в одни и те же слоты 8/9. То
|
||||
есть вариант A тянет за собой ещё и сужение окна перебора — то есть отказ
|
||||
от FIX_COLL_FLAGS, — и это заметно рискованнее точечного сдвига.
|
||||
|
||||
### Чем платим
|
||||
|
||||
- Расхождение структур: если в будущем понадобится знать, из какой комнаты
|
||||
пришёл тайл конкретного слота, этого у нас нет — придётся идти в вариант A.
|
||||
- Сдвиг работает только для чисто горизонтальных переходов на ровно 10
|
||||
колонок. Любая будущая диагональ/иная ширина комнаты его сломает молча.
|
||||
- `coll_last_row`: `pop_coll_invalidate` прячет прошлый ряд, чтобы
|
||||
`pop_coll_shift` мог отменить инвалидацию. Порядок вызовов в
|
||||
`enter_room_side` (сначала `pop_map_set_edges`, потом `pop_coll_shift`)
|
||||
стал значимым.
|
||||
|
||||
### Что проверять при регрессе
|
||||
|
||||
Это сердце коллизии, вокруг которого разбирался BUG-SEAM-PINGPONG. После
|
||||
любой правки здесь — прогон швов:
|
||||
|
||||
1. Уровень 1, комнаты 6 ↔ 8, закрытая решётка, **обе** стороны.
|
||||
2. Оба режима подхода: мелким шагом (упереться) и с разбега (не пройти
|
||||
насквозь).
|
||||
3. Проверить, что пинг-понг у шва не вернулся (экран не перескакивает
|
||||
туда-сюда на кадре бампа о ворота).
|
||||
4. `make -C roomtest/tests-host` — наборы `t_wall`/`t_char` ходят по этой же
|
||||
геометрии.
|
||||
@@ -9,7 +9,9 @@
|
||||
Перед реализацией ЛЮБОЙ функции и по ЛЮБОМУ вопросу «как в оригинале» —
|
||||
СНАЧАЛА прочитай соответствующий код SDLPoP и портируй по нему; не пиши
|
||||
по памяти и не угадывай константы/порядок слоёв. Расхождение с SDLPoP =
|
||||
по умолчанию баг у нас.
|
||||
по умолчанию баг у нас; ОСОЗНАННЫЕ расхождения (платформа/бюджет требуют
|
||||
иначе) перечислены в `../docs/impl_diff.md` — новое туда же записью, а не
|
||||
только комментарием в коде.
|
||||
|
||||
**Что в работе сейчас — `TASKS_OPEN.md`** (доска задач: приоритеты, критерии
|
||||
готовности); сделанное с протоколами замеров — `TASKS_CLOSED.md`. Баги —
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
| ID | что | тип | статус |
|
||||
|----|-----|-----|--------|
|
||||
| [BUG-CHEAT-FIGHT-1](#bug-cheat-fight-1) | `+`/`−` в бою с вынутым мечом → Кид теряет управление | Major (чит) | открыт |
|
||||
| [BUG-GATE-PASS-1](#bug-gate-pass-1) | проход сквозь закрытую решётку шва (комн. 8 -> 6) | Major | **воспроизведён, корень найден 2026-08-08**: история флагов коллизии не привязана к комнате |
|
||||
| [BUG-GATE-PASS-1](#bug-gate-pass-1) | проход сквозь закрытую решётку шва (комн. 8 -> 6) | Major | **фикс сделан 2026-08-09** (сдвиг истории флагов, вариант B) — ждёт приёмки в MAME |
|
||||
| [BUG-SPIKE-1](#bug-spike-1) | пики залипают выдвинутыми рядом с Кидом | **низкий** | маловоспроизводимый: ни сценарием, ни попиксельной подгонкой X не поднимается |
|
||||
| [BUG-CHOMP-JUMP-1](#bug-chomp-jump-1) | прыжок с места вплотную к чомперу: кадр с отступом назад | **низкий** | маловоспроизводимый: на повторе не поднялся; на пререлиз |
|
||||
| [T-1](#t-1) | пики перерисовываются безусловно | оптимизация | открыт |
|
||||
@@ -255,17 +255,42 @@ if (curr_row_coll_room[column] >= 0 &&
|
||||
есть ПОДАВЛЯЕТ бамп на кадре входа. А к следующему кадру Кид уже за
|
||||
плоскостью ворот — перехода 0->1 не будет никогда.
|
||||
|
||||
### Что делать
|
||||
### Фикс сделан 2026-08-09 (вариант B — сдвиг истории), ЖДЁТ ПРИЁМКИ В MAME
|
||||
|
||||
Порт индексации оригинала: хранить флаги в 10 слотах ПО КОЛОНКЕ РАЗРЕШЁННОЙ
|
||||
комнаты плюс параллельный массив её номера, и сравнивать prev/curr только при
|
||||
совпадении номеров. Тогда `pop_coll_invalidate()` не нужен вовсе — история
|
||||
сама «не совпадает» там, где колонка сменила комнату.
|
||||
Рассматривались два пути:
|
||||
|
||||
- **A, дословный порт.** 10 слотов + параллельный массив номера комнаты,
|
||||
индекс по колонке разрешённой комнаты, бамп только при совпадении номеров;
|
||||
`pop_coll_invalidate()` тогда не нужен вовсе. **Не взят:** оригиналу
|
||||
хватает десяти слотов только потому, что он перебирает узкое окно вокруг
|
||||
Кида, а мы намеренно считаем все четырнадцать колонок (FIX_COLL_FLAGS,
|
||||
чтобы не оставалось протухших ячеек) — при таком переборе колонки −2/−1 и
|
||||
8/9 сядут в одни слоты 8/9. То есть A тянет за собой ещё и сужение окна.
|
||||
- **B, сдвиг истории (сделано).** Индексацию оставляем свою, но при
|
||||
БОКОВОМ переходе историю не выбрасываем, а перенумеровываем на 10 слотов:
|
||||
`check_leave` двигает `x` ровно на ∓140 = 10 тайлов, координата грани
|
||||
(`pop_x_bump`) едет на те же 140 вместе с габаритом Кида, значит сами
|
||||
флаги инвариантны — меняется только номер слота.
|
||||
|
||||
Реализация: `pop_coll_shift(int8_t dcol)` в `pop_map.c` сдвигает
|
||||
`coll_curr/above/below` (не `prev` — его на следующем кадре всё равно
|
||||
перезапишет `move_coll_to_prev`), освободившиеся слоты = 3 («уже
|
||||
перекрывал», бампа нет — ровно то, что в оригинале даёт несовпадение номера
|
||||
комнаты). `enter_room_side` зовёт её сразу после `pop_map_set_edges`:
|
||||
`side == 0` (ушёл влево) → `+10`, `side == 1` (вправо) → `−10`. Переходы
|
||||
вверх/вниз и все прочие входы в комнату остаются на полной инвалидации —
|
||||
там колонки не сдвигаются, но тайлы под ними уже из другой комнаты.
|
||||
|
||||
Расхождение с дословным вариантом A записано в `../docs/impl_diff.md` (D-1).
|
||||
|
||||
**Осторожно:** это сердце коллизии, вокруг которого разбирался
|
||||
BUG-SEAM-PINGPONG (см. `bug_closed.md`). После правки обязателен прогон
|
||||
швов: комнаты 6/8 первого уровня в обе стороны, осторожный шаг и разбег, плюс
|
||||
проверка, что пинг-понг не вернулся.
|
||||
BUG-SEAM-PINGPONG (см. `bug_closed.md`). Приёмка:
|
||||
|
||||
1. Комнаты 6 ↔ 8 уровня 1, закрытая решётка, **обе** стороны.
|
||||
2. Мелким шагом (упереться) И с разбега (не пройти насквозь) — сценарий
|
||||
выше воспроизводится с `Kid.x = 170`, комната 8, ряд 0, лицом вправо.
|
||||
3. Пинг-понг у шва не вернулся (экран не перескакивает туда-сюда).
|
||||
4. `make -C tests-host` — прошли все 5 наборов (2026-08-09).
|
||||
|
||||
**Инструмент для сверки готов:** SDLPoP собран с трассой, включается
|
||||
`POP_TRACE=1` (правки в `seg000.c` play_kid_frame, `seg004.c` bumped,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -28,6 +28,15 @@ void pop_map_set(uint8_t *fg) __banked;
|
||||
* get_tile отдавал мнимую стену (BUG-SWORD-GHOST-1). Звать в enter_room. */
|
||||
void pop_map_set_edges(uint8_t left, uint8_t right, uint8_t up, uint8_t down) __banked;
|
||||
|
||||
/* БОКОВОЙ переход в соседнюю комнату: перенумеровать историю флагов
|
||||
* перекрытия вместо того, чтобы её выбросить (иначе Кид с разбега проходит
|
||||
* сквозь закрытые ворота шва — BUG-GATE-PASS-1). dcol — на сколько
|
||||
* изменились номера колонок: ушли ВПРАВО −10, ВЛЕВО +10. Звать СРАЗУ после
|
||||
* pop_map_set_edges и только для боковых переходов; вверх/вниз и все прочие
|
||||
* входы в комнату остаются на полной инвалидации. Разбор — bug_closed.md,
|
||||
* расхождение с дословным портом — ../docs/impl_diff.md. */
|
||||
void pop_coll_shift(int8_t dcol) __banked;
|
||||
|
||||
/* check_skel: тайл скелета -> пол + пометка перерисовки (обе страницы). */
|
||||
void pop_skel_wake_tile(uint8_t tilepos) __banked;
|
||||
|
||||
|
||||
@@ -283,6 +283,12 @@ static void enter_room_side(uint8_t room, uint8_t side)
|
||||
* pop_map_set_edges) — отдельной копии в приложении нет. */
|
||||
pop_map_set_edges(pop_room_link(room, 0), pop_room_link(room, 1),
|
||||
pop_room_link(room, 2), pop_room_link(room, 3));
|
||||
/* Боковой переход: колонки сдвинулись ровно на 10 (x ∓140), флаги
|
||||
* перекрытия при этом инвариантны — историю перенумеровываем, а не
|
||||
* теряем. Без этого решётка шва не бампит на кадре входа и Кид с
|
||||
* разбега проходит сквозь закрытые ворота (BUG-GATE-PASS-1). */
|
||||
if (side == 0) pop_coll_shift(+10); /* ушёл ВЛЕВО: col += 10 */
|
||||
else if (side == 1) pop_coll_shift(-10); /* ушёл ВПРАВО: col −= 10 */
|
||||
pop_room_set_below(below_fg);
|
||||
/* Ряд 2 верхнего соседа → полоса кладки у потолка (row0). fg — статика
|
||||
* уровня, mod — живой room_modif (ленивая инициализация). */
|
||||
|
||||
Reference in New Issue
Block a user