Уровень 5: тень не дерётся, кнопка в шве, узор паласа после зелья
Три бага одной отладочной сессии, все проверены в MAME пользователем. 1. SHADOW-FIGHT-L5. Кид доставал меч, а тень вставала в боевую стойку и рисовалась спрайтами стража. В pop_check_can_guard_see_kid первым множителем стояло `Guard.charid != 0`, тогда как оригинал (seg003:702) пишет `Guard.charid != charid_1_shadow || current_level == 12`: тень боевая только на 12-м уровне. Оба симптома шли из одной ветки control_standing (seg005:352). Возвращён и пропущенный множитель `Guard.direction != dir_56_none`. 2. SEAM-BUTTON-STALE. Кнопка в шве не меняла вид ни при нажатии, ни при отжатии. Сигнатура редроя шва сравнивала room_modif, а у кнопки modif — это индекс LINKLOC, константа уровня: нажатие живёт в doorlinks2, и в сигнатуру не приходило никогда. seam_row_sig подмешивает бит нажатости. Оригинал шов в этом случае не перерисовывает вовсе — расхождение осознанное, записано как D-2 в docs/impl_diff.md. 3. BUG-POTION-STRIPE. Синяя лента паласа пропадала на месте выпитого зелья и не возвращалась даже после перезахода в комнату. У оригинала curr_room_tiles — сама таблица уровня, у нас fg живёт в двух местах, и страницу правил главный цикл уже после pop_process_trobs. В этот зазор trob зелья крутил фазу пузырька поверх обнулённого модификатора: bubble_next_frame(0) = 1, а для пола в паласе modif 1 означает «узор не рисовать» (seg008:499). do_pickup теперь правит страницу уровня сразу. Тем же лечится меч: animate_sword делал `--mod[tp]` из нуля. tests-host 5/5 (добавлена заглушка pop_level_set_tile), size-check чист. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2308,3 +2308,116 @@ draw_tile_anim(); <- СВОЯ графика тайла: челюсти
|
||||
и зеркало в одной комнате): лечение — обновлять в `place_mirror` не только
|
||||
данные уровня, но и живую карту (в `pop_map.c` уже есть внутренние точки
|
||||
записи `g_fg[tilepos]`, нужна публичная «поставить тайл в текущей комнате»).
|
||||
|
||||
---
|
||||
<a id="seam-button-stale"></a>
|
||||
## SEAM-BUTTON-STALE. Кнопка в шве не меняла вид при нажатии/отжатии — ЗАКРЫТ
|
||||
|
||||
> **Симптом (пользователь, 2026-08-11, уровень 5).** Кнопка нижних ворот
|
||||
> комнаты 24 стоит в шве: в комнате 11 это (1,9), в комнате 24 — (1,−1).
|
||||
> «Нажали её из комнаты 11, она проанимировалась — зайдя в 24, она ВСЕГДА
|
||||
> нарисована нажатой, хотя по статусу отжимается. Не нажимали, вошли в 24 и
|
||||
> наступили — ворота открываются, а визуально кнопка остаётся отжатой.»
|
||||
|
||||
**Корень.** Change-driven редрой шва (`seam_sig` в `roomtest.c`) сравнивал
|
||||
`room_modif` колонки 9 соседа. У кнопки `modif` — это ИНДЕКС LINKLOC,
|
||||
константа уровня; само нажатие живёт в `doorlinks2`
|
||||
(`get_doorlink_timer`, seg007:0BB6 — младшие 5 бит). Изменение в сигнатуру
|
||||
не приходило НИКОГДА, редрой не заказывался, и шов оставался нарисованным
|
||||
таким, каким был на входе в комнату — отсюда оба симптома сразу.
|
||||
|
||||
Видимой разницу делает `draw_tile`: нажатый opener рисуется как ПОЛ
|
||||
(порт `get_tile_to_draw`, seg008:253 — `pop_room.c:256`), а у пола правая
|
||||
грань есть, у кнопки её нет.
|
||||
|
||||
**Фикс.** `seam_row_sig()` (roomtest.c) подмешивает в сигнатуру ряда бит
|
||||
«кнопка нажата» для тайлов `0x0F`/`0x06`. Оригинал шов в этом случае не
|
||||
перерисовывает вовсе (`get_trob_pos_in_drawn_room` возвращает 30 для чужой
|
||||
комнаты) — осознанное расхождение, записано как D-2 в
|
||||
[`../docs/impl_diff.md`](../docs/impl_diff.md).
|
||||
|
||||
Цена: резидент +200 Б (`_CODE` 24 739 → 24 939), куча W2 1795 → 1595 Б.
|
||||
|
||||
**Проверено (пользователь, 2026-08-11):** «кнопка теперь отрисовывается
|
||||
правильно в обоих случаях» — оба направления — нажать из комнаты 11 и войти в 24;
|
||||
войти в 24 поверху и наступить на кнопку, стоя в шве. Картинка кнопки
|
||||
обязана совпадать со статусом ворот.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
<a id="bug-potion-stripe"></a>
|
||||
## BUG-POTION-STRIPE. Узор паласа пропадал на месте выпитого зелья — ЗАКРЫТ
|
||||
|
||||
**Наблюдение (пользователь, 2026-08-11, уровень 5).** «На стенке паласа есть
|
||||
узор — синяя в цветочек полоса, она запекается в фон и должна быть всегда.
|
||||
Но если на её фоне Кид (или Тень) выпивает зелье — полоса пропадает.»
|
||||
Воспроизведено в комнате 14 (два зелья в ряду 2, колонки 4 и 5): после
|
||||
каждого глотка узор исчезал в ячейке СПРАВА от выпитого тайла и **не
|
||||
возвращался даже после выхода из комнаты и повторного входа**.
|
||||
|
||||
**Корень.** У оригинала `curr_room_tiles` — это сама таблица уровня, поэтому
|
||||
`curr_room_tiles[curr_tilepos] = tiles_1_floor` в `do_pickup` (seg006:1671)
|
||||
виден всем в тот же миг. У нас `fg` живёт в ДВУХ местах — буфер отрисовки
|
||||
(`g_fg`) и EMM-страница уровня, — и страницу правил главный цикл ПОЗЖЕ в
|
||||
кадре, уже после `pop_process_trobs`.
|
||||
|
||||
В этот зазор успевал проснуться trob поднятого зелья: код тайла он читает из
|
||||
страницы уровня (`pop_level_tile_raw`), там ещё зелье — и `animate_potion`
|
||||
крутил фазу пузырька поверх только что обнулённого модификатора,
|
||||
`bubble_next_frame(0)` = **1**. Модификатор оставался единицей навсегда
|
||||
(`room_modif` персистентен, `room_seen` не даёт переинициализации).
|
||||
|
||||
Дальше срабатывало правило самого оригинала: для ПОЛА в паласе `modif == 1`
|
||||
означает «узор не рисовать» — `if (num == !!level_type) return;`
|
||||
(seg008:499, у нас `pop_room.c:322`). Отсюда и «не лечится перезаходом».
|
||||
|
||||
**Как подтверждено (MAME, чтение памяти, а не рассуждение):** буфер тайлов
|
||||
комнаты (`0xA342`) после подбора — `01` = пол на обеих позициях, всё верно;
|
||||
а в модификаторах на позициях 24 и 25 стояли `01 01`.
|
||||
|
||||
**Фикс.** `do_pickup` (`pop_map.c`) ставит тайл в странице уровня СРАЗУ
|
||||
(`pop_level_set_tile`). Тогда trob того же кадра уходит в `default` и
|
||||
снимается (`type = −1`), модификатор остаётся нулём. Дублирующая запись из
|
||||
главного цикла убрана. Тем же фиксом лечится МЕЧ: там `animate_sword`
|
||||
делал `--mod[tp]` из нуля и получал 255.
|
||||
|
||||
**Проверено (пользователь, 2026-08-11):** «узор теперь на месте».
|
||||
|
||||
**Ложный след, для протокола:** первым подозреваемым был `pop_floor_bake` —
|
||||
после подбора он чистит `bar` шириной 60 px при 64-пиксельной колонке, и
|
||||
уцелевший хвостик узора в 4 px выглядел как его подпись. Отвергнуто
|
||||
перезаходом в комнату: полная перерисовка идёт мимо `bake`, а узор всё
|
||||
равно не появлялся.
|
||||
|
||||
---
|
||||
|
||||
<a id="shadow-fight-l5"></a>
|
||||
## SHADOW-FIGHT-L5. Кид и Тень вставали в боевую стойку в комнате с зельем — ЗАКРЫТ
|
||||
|
||||
**Наблюдение (пользователь, 2026-08-11).** Тень выходит и пьёт зелье
|
||||
штатно, но если Кид успевал подняться в ряд 0, пока она пьёт: (а) Кид
|
||||
доставал меч, (б) Тень тоже вставала в боевую стойку и **рисовалась
|
||||
спрайтами стража**.
|
||||
|
||||
**Корень.** В `pop_check_can_guard_see_kid` (порт `check_can_guard_see_kid`,
|
||||
seg003:702) первым множителем стояло `Guard.charid != 0`, тогда как оригинал
|
||||
пишет:
|
||||
|
||||
```c
|
||||
if ((Guard.charid != charid_1_shadow || current_level == 12) && ...
|
||||
```
|
||||
|
||||
То есть ТЕНЬ — боевой персонаж только на 12-м уровне; на 4/5/6 она Кида «не
|
||||
видит». Это не косметика: `can_guard_see_kid >= 2` разворачивается в оба
|
||||
симптома через одну ветку `control_standing` (seg005:352) — Кид достаёт меч
|
||||
сам, а Тень с `charid 1 < CHARID_2_GUARD` и убранным мечом идёт в
|
||||
диспетчере `pop_control` ТОЙ ЖЕ веткой, что и Кид; с кадра 150 боевые кадры
|
||||
лежат в атласе стража.
|
||||
|
||||
**Фикс.** Порт условия целиком + возвращён пропущенный множитель
|
||||
`Guard.direction != dir_56_none` (им оригинал гасит выключенного
|
||||
персонажа). Константа `SHADOW_FIGHT_LEVEL` в `pop_guard.h`.
|
||||
|
||||
**Проверено (пользователь, 2026-08-11):** тень выпивает и уходит, боя нет.
|
||||
|
||||
Reference in New Issue
Block a user