Кнопка в ШВЕ срабатывала как чужая связь (нашёл пользователь на ур. 5)
Симптом: Кид встаёт на плиту, которая физически в СОСЕДНЕЙ комнате (стоя в шве, curr_col = −1), и вместо одних ворот открываются двое — на уровне 5 плита комнаты 11 открывала и нижние ворота комнаты 24, и верхние, хотя связана только с нижними. Причина. check_press читал тайл через get_tile (тот резолвит шов в соседнюю комнату), а комнату и tilepos для trigger_button брал из координат персонажа: (своя комната, row*10 + curr_col). При curr_col = −1 это tilepos 9 СВОЕЙ комнаты — там стена с bg = 0, то есть индекс цепочки LINKLOC 0. Цепочка от нуля в данных уровня 5 ведёт на ДВА тайла: нижние ворота (link[0], next=1) и верхние (link[1]) — ровно то, что наблюдалось. Настоящая кнопка имеет индекс 9 и одну цель. В оригинале этого нет по построению: get_tile зовёт find_room_of_tile (seg006:005D) и ПЕРЕСТАВЛЯЕТ curr_room/curr_tilepos, а trigger_button работает уже с ними. У нас резолв комнаты жил только внутри get_tile, а наружу не отдавался. Фикс: tile_room_of(col,row) — комната и tilepos клетки с учётом швов (по образцу gate_modif, который так делал давно), check_press зовёт trigger_button с резолвнутыми room/tilepos. Ветка loose там же оставлена на координатах персонажа: make_loose_fall работает с g_fg своей комнаты. Два других вызова trigger_button (зацеп за кромку, севшая на кнопку плита) правки не требуют — оба ограничены колонками 0..9 своей комнаты. Заведён GATE-FORE-KID (BUGS_OPEN.md): Кид, стоящий В ПРОЁМЕ ворот, виден поверх решётки — у нас портирован только шовный случай окклюзии, а draw_tile_fore (seg008:0D15) рисует решётку поверх персонажа и внутри комнаты. Чинить в fore-слое отдельно, он горячий. tests-host 5/5, make size-check OK. Банк 3: 10648 -> 10828 Б. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
| ID | что | тип | статус |
|
| ID | что | тип | статус |
|
||||||
|----|-----|-----|--------|
|
|----|-----|-----|--------|
|
||||||
|
| [GATE-FORE-KID](#gate-fore-kid) | Кид в проёме ворот виден поверх решётки | окклюзия | открыт: портирован только шовный случай |
|
||||||
| [FORE-DUP](#fore-dup) | передний слой тайла рисуется дважды при перекрытии объектов | оптимизация | открыт: **сначала замерить**, потом чинить |
|
| [FORE-DUP](#fore-dup) | передний слой тайла рисуется дважды при перекрытии объектов | оптимизация | открыт: **сначала замерить**, потом чинить |
|
||||||
| [DIED-ON-BUTTON](#died-on-button) | `died_on_button` (seg007:776) не портирован | порт | открыт |
|
| [DIED-ON-BUTTON](#died-on-button) | `died_on_button` (seg007:776) не портирован | порт | открыт |
|
||||||
| [TORCH-ANIM-RIGHT](#torch-anim-right) | под запечённым пламенем застывают не только челюсти чомпера | **низкий** | открыт: на уровнях 1-4 такого соседства нет |
|
| [TORCH-ANIM-RIGHT](#torch-anim-right) | под запечённым пламенем застывают не только челюсти чомпера | **низкий** | открыт: на уровнях 1-4 такого соседства нет |
|
||||||
@@ -335,3 +336,45 @@ for (tile_row = x_top_row; tile_row <= char_bottom_row; ++tile_row)
|
|||||||
Если дубль мал — оставить как есть и закрыть запись.
|
Если дубль мал — оставить как есть и закрыть запись.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="gate-fore-kid"></a>
|
||||||
|
## GATE-FORE-KID. Кид, стоящий В ПРОЁМЕ ворот, виден ПОВЕРХ решётки
|
||||||
|
|
||||||
|
Нашёл пользователь 2026-08-11 (уровень 5, комната 24, верхние ворота):
|
||||||
|
Кид стоит на тайле ворот, а решётка рисуется ПОД ним — он виден целиком,
|
||||||
|
хотя должен быть за прутьями.
|
||||||
|
|
||||||
|
**Как в оригинале.** `draw_tile_fore` (seg008:0D15) первой же строкой:
|
||||||
|
|
||||||
|
```c
|
||||||
|
if (tile_left == tiles_4_gate && Kid.curr_row == drawn_row &&
|
||||||
|
Kid.curr_col == drawn_col - 1 && Kid.room != room_R) {
|
||||||
|
draw_gate_fore();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
то есть когда Кид стоит ИМЕННО на тайле ворот, их решётка дорисовывается
|
||||||
|
в **foretable** — поверх персонажа: `draw_gate_fore` (seg008) кладёт спрайт
|
||||||
|
51 (низ решётки) и дальше вверх кусками по 8 px спрайтом 52, до
|
||||||
|
`gate_top_y`, прозрачным блитом.
|
||||||
|
|
||||||
|
**Что есть у нас.** Портирован только ШОВНЫЙ случай (`pop_bg.c`,
|
||||||
|
`pop_fore_over_char`): если футпринт зашёл за левый шов и у соседа слева в
|
||||||
|
этом ряду ворота — их бары перерисовываются поверх персонажа через
|
||||||
|
`draw_gate_back`. Случая «ворота ВНУТРИ комнаты, персонаж на их тайле»
|
||||||
|
нет вовсе, отсюда симптом.
|
||||||
|
|
||||||
|
**Почему не чинится одной строкой.** Правка идёт в `pop_fore_over_char` —
|
||||||
|
самый горячий путь кадра (memory `pop_fore_layer_cost`: когда-то 78 %
|
||||||
|
кадра, окно клипа дало 3.2×). Добавлять проверку надо так, чтобы она не
|
||||||
|
стоила ничего на каждом тайле футпринта: условие дешёвое (`тайл под
|
||||||
|
персонажем == ворота`), но рисование — это ещё один блит на кадр, пока
|
||||||
|
Кид стоит в проёме. Плюс нужен свой расчёт полосы (`gate_top_y` по
|
||||||
|
живому openness), а не готовый `draw_gate_back`, который рисует ЗА
|
||||||
|
персонажем.
|
||||||
|
|
||||||
|
**Проверять:** уровень 5, комната 24 — встать в проём верхних ворот
|
||||||
|
(колонка 1 ряда 0) при частично поднятой решётке; прутья должны
|
||||||
|
перекрывать Кида. Тот же случай — любые ворота на уровнях 1-3.
|
||||||
|
|||||||
@@ -286,6 +286,26 @@ uint8_t pop_tile_at(int8_t col, int8_t row) __banked
|
|||||||
* g_link_r col0; ВНУТРИ комнаты (0..9) — текущая комната g_room (иначе после
|
* g_link_r col0; ВНУТРИ комнаты (0..9) — текущая комната g_room (иначе после
|
||||||
* перехода Kid встаёт на ту же створку уже как на внутрикомнатную и его отбивает
|
* перехода Kid встаёт на ту же створку уже как на внутрикомнатную и его отбивает
|
||||||
* обратно). Открыто ⇔ (modif>>2)+6 >= char_height (бары выше головы). */
|
* обратно). Открыто ⇔ (modif>>2)+6 >= char_height (бары выше головы). */
|
||||||
|
/* Комната и tilepos клетки (col,row) С УЧЁТОМ ШВА — порт того, что в
|
||||||
|
* оригинале делает сам get_tile: он зовёт find_room_of_tile (seg006:005D) и
|
||||||
|
* ПЕРЕСТАВЛЯЕТ curr_room/curr_tilepos, а дальше trigger_button работает уже
|
||||||
|
* с ними, а не с комнатой персонажа. Возвращает 0, если клетки нет.
|
||||||
|
*
|
||||||
|
* Кусало 2026-08-11 (нашёл пользователь на уровне 5): Кид стоит на кнопке,
|
||||||
|
* которая физически в СОСЕДНЕЙ комнате (col = −1, то есть колонка 9 левого
|
||||||
|
* соседа). Мы читали модификатор как (своя комната, tilepos 9) — там стена
|
||||||
|
* с bg = 0, то есть индекс связи 0. Цепочка от нуля в комнате 24 уровня 5
|
||||||
|
* открывает И нижние ворота, И верхние, хотя настоящая кнопка (индекс 9)
|
||||||
|
* открывает только нижние. */
|
||||||
|
static uint8_t tile_room_of(int8_t col, int8_t row, uint8_t *tp)
|
||||||
|
{
|
||||||
|
if (row < 0 || row > 2) return 0;
|
||||||
|
if (col >= 0 && col <= 9) { *tp = (uint8_t)(row * 10 + col); return g_room; }
|
||||||
|
if (col < 0 && col >= -10 && g_link_l) { *tp = (uint8_t)(row * 10 + col + 10); return g_link_l; }
|
||||||
|
if (col > 9 && col <= 19 && g_link_r) { *tp = (uint8_t)(row * 10 + col - 10); return g_link_r; }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Живой модификатор (openness) ворот в (col,row): своя комната или соседняя
|
/* Живой модификатор (openness) ворот в (col,row): своя комната или соседняя
|
||||||
* через шов. 0xFF — тайла нет (за краем уровня). */
|
* через шов. 0xFF — тайла нет (за краем уровня). */
|
||||||
static uint8_t gate_modif(int8_t col, int8_t row)
|
static uint8_t gate_modif(int8_t col, int8_t row)
|
||||||
@@ -1969,11 +1989,17 @@ static void check_press(void)
|
|||||||
if (!(kid_cur_flags() & FRAME_NEEDS_FLOOR)) return;
|
if (!(kid_cur_flags() & FRAME_NEEDS_FLOOR)) return;
|
||||||
{
|
{
|
||||||
uint8_t t = get_tile_at_char();
|
uint8_t t = get_tile_at_char();
|
||||||
uint8_t tp = (uint8_t)(Char.curr_row * 10 + Char.curr_col);
|
uint8_t tp = 0;
|
||||||
if (t == TILE_OPENER || t == TILE_CLOSER)
|
/* Кнопка может лежать в СОСЕДНЕЙ комнате — Кид стоит в шве
|
||||||
pop_trigger_button(g_room, tp, t, pop_trob_modif(g_room)[tp]);
|
* (curr_col = −1 или 10). Комнату и tilepos берём резолвнутые,
|
||||||
|
* иначе индекс связи читается из чужого тайла (см. tile_room_of). */
|
||||||
|
uint8_t btn_room = tile_room_of(Char.curr_col, Char.curr_row, &tp);
|
||||||
|
if ((t == TILE_OPENER || t == TILE_CLOSER) && btn_room)
|
||||||
|
pop_trigger_button(btn_room, tp, t, pop_trob_modif(btn_room)[tp]);
|
||||||
else if (t == TILE_LOOSE) {
|
else if (t == TILE_LOOSE) {
|
||||||
make_loose_fall(tp, 1);
|
/* loose живёт в СВОЕЙ комнате (make_loose_fall работает с g_fg),
|
||||||
|
* поэтому здесь по-прежнему координаты персонажа. */
|
||||||
|
make_loose_fall((uint8_t)(Char.curr_row * 10 + Char.curr_col), 1);
|
||||||
is_guard_notice = 1; /* seg006:1734 */
|
is_guard_notice = 1; /* seg006:1734 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user