Уровень 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:
@@ -117,3 +117,57 @@ for (short column = 9; column >= 0; --column) {
|
|||||||
туда-сюда на кадре бампа о ворота).
|
туда-сюда на кадре бампа о ворота).
|
||||||
4. `make -C roomtest/tests-host` — наборы `t_wall`/`t_char` ходят по этой же
|
4. `make -C roomtest/tests-host` — наборы `t_wall`/`t_char` ходят по этой же
|
||||||
геометрии.
|
геометрии.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## D-2. Кнопка в шве: перерисовываем, хотя оригинал не перерисовывает
|
||||||
|
|
||||||
|
### Что делает оригинал
|
||||||
|
|
||||||
|
Тайл-«трансформер» (кнопка, ворота, пика) перерисовывается только если он в
|
||||||
|
ОТРИСОВАННОЙ комнате: `redraw_11h` → `redraw_tile_height` →
|
||||||
|
`get_trob_pos_in_drawn_room` (seg007:0258), а та для `trob.room != drawn_room`
|
||||||
|
возвращает 30 — заведомо несуществующий tilepos, то есть «не рисовать».
|
||||||
|
Исключение сделано ровно одно — факелы (`animate_torch`, seg007:03CF, ветка
|
||||||
|
`trob.room == room_L && tilepos % 10 == 9`).
|
||||||
|
|
||||||
|
Кнопка соседа слева при этом ВЛИЯЕТ на картинку: `get_tile_to_draw`
|
||||||
|
(seg008:253) подменяет нажатый `tiles_15_opener` на `tiles_1_floor`, а
|
||||||
|
`load_leftroom` (seg008:360) кладёт результат в `leftroom_[row]`, откуда он
|
||||||
|
приходит в `draw_tile` как `tile_left`. У пола правая грань есть, у кнопки
|
||||||
|
нет — значит в оригинале нажатие кнопки, видимой через левый шов, меняет
|
||||||
|
картинку только при следующей ПОЛНОЙ отрисовке комнаты.
|
||||||
|
|
||||||
|
### Что делаем мы
|
||||||
|
|
||||||
|
Перерисовываем шов сразу: `seam_row_sig` (roomtest.c) подмешивает в сигнатуру
|
||||||
|
ряда бит «кнопка нажата» (`pop_doorlink2(mod) & 0x1F > 1`) для тайлов
|
||||||
|
`0x0F`/`0x06`, и change-driven редрой `pop_room_redraw_seam_left` срабатывает
|
||||||
|
на нём так же, как на openness ворот.
|
||||||
|
|
||||||
|
### Почему
|
||||||
|
|
||||||
|
Голый порт давал видимый залип (SEAM-BUTTON-STALE, roomtest/BUGS_CLOSED.md): кнопка
|
||||||
|
(1,9) комнаты 11 — она же (1,−1) комнаты 24 — оставалась нарисованной в том
|
||||||
|
состоянии, в каком была на входе в комнату, хотя связь срабатывала. Сигнатура
|
||||||
|
шва следила только за `room_modif`, а у кнопки `modif` — это ИНДЕКС LINKLOC,
|
||||||
|
константа уровня: нажатие живёт в `doorlinks2` и в сигнатуру не приходило
|
||||||
|
никогда. Добавить кнопку в сигнатуру — те же три сравнения на кадр, что уже
|
||||||
|
делались для ворот; воспроизводить артефакт оригинала смысла нет.
|
||||||
|
|
||||||
|
### Чем платим
|
||||||
|
|
||||||
|
- Резидент +200 Б (`_CODE` 24 739 → 24 939), куча W2 1795 → 1595 Б. Если
|
||||||
|
станет тесно — `seam_row_sig` переносится в банк 7 к
|
||||||
|
`pop_room_redraw_seam_left`, ценой одного трамплина на кадр.
|
||||||
|
- Сигнатура ряда стала разнотипной: для кнопки это булев бит, для остальных
|
||||||
|
тайлов — modif. Значения между собой не сравниваются (сравнивается только
|
||||||
|
ряд сам с собой), но при добавлении нового типа тайла в шов про это надо
|
||||||
|
помнить.
|
||||||
|
|
||||||
|
### Что проверять при регрессе
|
||||||
|
|
||||||
|
Уровень 5, кнопка нижних ворот комнаты 24 (она же (1,9) комнаты 11), оба
|
||||||
|
направления: нажать её из комнаты 11 и войти в 24; и наоборот — войти в 24
|
||||||
|
поверху и наступить на неё, стоя в шве. Картинка кнопки обязана совпадать
|
||||||
|
со статусом ворот в обоих случаях.
|
||||||
|
|||||||
@@ -2308,3 +2308,116 @@ draw_tile_anim(); <- СВОЯ графика тайла: челюсти
|
|||||||
и зеркало в одной комнате): лечение — обновлять в `place_mirror` не только
|
и зеркало в одной комнате): лечение — обновлять в `place_mirror` не только
|
||||||
данные уровня, но и живую карту (в `pop_map.c` уже есть внутренние точки
|
данные уровня, но и живую карту (в `pop_map.c` уже есть внутренние точки
|
||||||
записи `g_fg[tilepos]`, нужна публичная «поставить тайл в текущей комнате»).
|
записи `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):** тень выпивает и уходит, боя нет.
|
||||||
|
|||||||
@@ -98,9 +98,18 @@ void pop_check_can_guard_see_kid(void) __banked
|
|||||||
int16_t left_pos, right_pos;
|
int16_t left_pos, right_pos;
|
||||||
uint8_t tile;
|
uint8_t tile;
|
||||||
|
|
||||||
|
/* Первый множитель — порт seg003:702. ТЕНЬ боевая только на 12-м
|
||||||
|
* уровне; на 4/5/6 она Кида «не видит», и это не косметика: увидев её,
|
||||||
|
* Кид достаёт меч (control_standing, seg005:352), а сама тень идёт той
|
||||||
|
* же веткой control_standing — встаёт в боевую стойку и с кадра 150
|
||||||
|
* рисуется спрайтами СТРАЖА. Пустой слот (charid 0) — наша добавка:
|
||||||
|
* оригинал гасит его через direction = dir_56_none. */
|
||||||
if (!(Guard.charid != 0 &&
|
if (!(Guard.charid != 0 &&
|
||||||
|
(Guard.charid != CHARID_1_SHADOW ||
|
||||||
|
pop_current_level == SHADOW_FIGHT_LEVEL) &&
|
||||||
/* кадры 219..228 — подъём по лестнице: там страж Кида не видит */
|
/* кадры 219..228 — подъём по лестнице: там страж Кида не видит */
|
||||||
kid_frame != 0 && (kid_frame < 219 || kid_frame >= 229) &&
|
kid_frame != 0 && (kid_frame < 219 || kid_frame >= 229) &&
|
||||||
|
Guard.direction != DIR_56_NONE &&
|
||||||
Kid.alive < 0 && Guard.alive < 0 &&
|
Kid.alive < 0 && Guard.alive < 0 &&
|
||||||
Kid.room == Guard.room && Kid.curr_row == Guard.curr_row)) {
|
Kid.room == Guard.room && Kid.curr_row == Guard.curr_row)) {
|
||||||
can_guard_see_kid = 0;
|
can_guard_see_kid = 0;
|
||||||
|
|||||||
@@ -94,6 +94,11 @@
|
|||||||
#define SHADOW_DOOR_TILEPOS 1 /* (кол 1, ряд 0) — ворота */
|
#define SHADOW_DOOR_TILEPOS 1 /* (кол 1, ряд 0) — ворота */
|
||||||
#define SHADOW_DOOR_OPEN_MIN 80 /* openness, при которой тень идёт */
|
#define SHADOW_DOOR_OPEN_MIN 80 /* openness, при которой тень идёт */
|
||||||
|
|
||||||
|
/* Единственный уровень, где тень — БОЕВОЙ персонаж (seg003:702). На всех
|
||||||
|
* остальных (4 зеркало, 5 зелье, 6 плита) она Кида «не видит»: см.
|
||||||
|
* pop_check_can_guard_see_kid. */
|
||||||
|
#define SHADOW_FIGHT_LEVEL 12
|
||||||
|
|
||||||
/* Градаций мастерства стража (seg002: таблицы вероятностей по 12 записей). */
|
/* Градаций мастерства стража (seg002: таблицы вероятностей по 12 записей). */
|
||||||
#define NUM_GUARD_SKILLS 12
|
#define NUM_GUARD_SKILLS 12
|
||||||
|
|
||||||
|
|||||||
@@ -1156,6 +1156,24 @@ static void do_pickup(int8_t obj_type, uint8_t tilepos)
|
|||||||
{
|
{
|
||||||
pickup_obj_type = obj_type;
|
pickup_obj_type = obj_type;
|
||||||
g_fg[tilepos] = TILE_FLOOR;
|
g_fg[tilepos] = TILE_FLOOR;
|
||||||
|
/* ...и В ДАННЫХ УРОВНЯ тоже, ПРЯМО СЕЙЧАС. У оригинала curr_room_tiles —
|
||||||
|
* это сама таблица уровня, так что `= tiles_1_floor` (seg006:1671) виден
|
||||||
|
* всем в тот же миг; у нас fg живёт в двух местах (буфер отрисовки g_fg
|
||||||
|
* и EMM-страница уровня), и раньше страницу правил главный цикл — ПОЗЖЕ
|
||||||
|
* в кадре, уже после pop_process_trobs.
|
||||||
|
*
|
||||||
|
* Из-за этого зазора trob поднятого зелья успевал проснуться: код тайла
|
||||||
|
* он читает из страницы уровня, там ещё зелье — и animate_potion крутил
|
||||||
|
* фазу пузырька поверх только что обнулённого модификатора,
|
||||||
|
* bubble_next_frame(0) = 1. Модификатор оставался ЕДИНИЦЕЙ навсегда
|
||||||
|
* (room_modif персистентен), а для ПОЛА в паласе modif 1 означает «узор
|
||||||
|
* не рисовать» (seg008:499, `if (num == !!level_type) return`) — синяя
|
||||||
|
* лента пропадала на месте выпитого зелья и не возвращалась даже после
|
||||||
|
* полной перерисовки комнаты (BUG-POTION-STRIPE). Теперь тайл в
|
||||||
|
* странице — пол сразу, trob того же кадра уходит в default и снимается
|
||||||
|
* (type = −1), модификатор остаётся нулём. То же лечит и меч: там
|
||||||
|
* animate_sword делал `--mod[tp]` из нуля и получал 255. */
|
||||||
|
pop_level_set_tile(g_room, tilepos, TILE_FLOOR);
|
||||||
/* curr_room_modif[curr_tilepos] = 0 (seg006:1676): у зелья в модификаторе
|
/* curr_room_modif[curr_tilepos] = 0 (seg006:1676): у зелья в модификаторе
|
||||||
* лежал тип+фаза пузырька, у меча — счётчик блеска. Тайл стал полом —
|
* лежал тип+фаза пузырька, у меча — счётчик блеска. Тайл стал полом —
|
||||||
* мусор в модификаторе не нужен (в исходное его вернёт только рестарт). */
|
* мусор в модификаторе не нужен (в исходное его вернёт только рестарт). */
|
||||||
|
|||||||
@@ -236,6 +236,24 @@ static uint8_t guard_over_kid(void)
|
|||||||
* — изменение приходило в m[19], сигнатура его не видела, редрой не
|
* — изменение приходило в m[19], сигнатура его не видела, редрой не
|
||||||
* заказывался, и открытые ворота оставались нарисованными закрытыми
|
* заказывался, и открытые ворота оставались нарисованными закрытыми
|
||||||
* (BUG-GATE-SEAM-ROW1). */
|
* (BUG-GATE-SEAM-ROW1). */
|
||||||
|
/* Кнопка в шве (SEAM-BUTTON-STALE). Сигнатурой служил ТОЛЬКО modif, а у
|
||||||
|
* кнопки modif — это индекс LINKLOC, то есть константа уровня: нажатие живёт
|
||||||
|
* в doorlinks2 (get_doorlink_timer, seg007:0BB6). Изменение в сигнатуру не
|
||||||
|
* приходило, редрой не заказывался — и шов оставался нарисованным в том
|
||||||
|
* состоянии, в каком был на входе в комнату: кнопка (1,9) комнаты 11, она же
|
||||||
|
* (1,−1) комнаты 24, залипала нажатой (или отжатой), хотя связь срабатывала.
|
||||||
|
* Видимой её делает draw_tile: нажатый opener рисуется как ПОЛ (seg008
|
||||||
|
* get_tile_to_draw), а у пола есть правая грань, у кнопки — нет.
|
||||||
|
* Поэтому в сигнатуру ряда подмешиваем бит «кнопка нажата». */
|
||||||
|
static uint8_t seam_row_sig(const uint8_t *m, const uint8_t *lfg, uint8_t r)
|
||||||
|
{
|
||||||
|
uint8_t code = (uint8_t)(lfg[r] & 0x1F);
|
||||||
|
uint8_t mod = m[9 + r * 10];
|
||||||
|
if (code == 0x0F || code == 0x06) /* opener / closer */
|
||||||
|
return (uint8_t)((pop_doorlink2(mod) & 0x1F) > 1);
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t seam_sig[3]; /* последняя нарисованная openness гейта в шве */
|
static uint8_t seam_sig[3]; /* последняя нарисованная openness гейта в шве */
|
||||||
static uint8_t seam_rows; /* маска рядов, ждущих редроя (переживает 2 кадра) */
|
static uint8_t seam_rows; /* маска рядов, ждущих редроя (переживает 2 кадра) */
|
||||||
static uint8_t seam_redraw; /* оставшиеся кадры редроя (обе страницы) */
|
static uint8_t seam_redraw; /* оставшиеся кадры редроя (обе страницы) */
|
||||||
@@ -346,10 +364,12 @@ static void enter_room_side(uint8_t room, uint8_t side)
|
|||||||
* pop_room_load заполнил lcol_bg/rcol_bg статикой уровня — перекрываем. */
|
* pop_room_load заполнил lcol_bg/rcol_bg статикой уровня — перекрываем. */
|
||||||
{
|
{
|
||||||
uint8_t lft = pop_room_link(room, 0), rgt = pop_room_link(room, 1);
|
uint8_t lft = pop_room_link(room, 0), rgt = pop_room_link(room, 1);
|
||||||
if (lft) { uint8_t *m = pop_trob_modif(lft);
|
if (lft) { uint8_t *m = pop_trob_modif(lft), i;
|
||||||
lcol_bg[0] = m[9]; lcol_bg[1] = m[19]; lcol_bg[2] = m[29];
|
for (i = 0; i < 3; i++) {
|
||||||
/* шов рисуется в обе страницы ниже — синхр. сигнатуру */
|
lcol_bg[i] = m[9 + i * 10];
|
||||||
seam_sig[0] = m[9]; seam_sig[1] = m[19]; seam_sig[2] = m[29]; }
|
/* шов рисуется в обе страницы ниже — синхр. сигнатуру */
|
||||||
|
seam_sig[i] = seam_row_sig(m, lcol_fg, i);
|
||||||
|
} }
|
||||||
if (rgt) { uint8_t *m = pop_trob_modif(rgt);
|
if (rgt) { uint8_t *m = pop_trob_modif(rgt);
|
||||||
rcol_bg[0] = m[0]; rcol_bg[1] = m[10]; rcol_bg[2] = m[20]; }
|
rcol_bg[0] = m[0]; rcol_bg[1] = m[10]; rcol_bg[2] = m[20]; }
|
||||||
}
|
}
|
||||||
@@ -792,7 +812,7 @@ int main(void)
|
|||||||
/* Все ТРИ ряда колонки 9: ворота в шве бывают в любом из них
|
/* Все ТРИ ряда колонки 9: ворота в шве бывают в любом из них
|
||||||
* (BUG-GATE-SEAM-ROW1, см. объявление seam_sig). */
|
* (BUG-GATE-SEAM-ROW1, см. объявление seam_sig). */
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
uint8_t g = m[9 + i * 10], prev = seam_sig[i];
|
uint8_t g = seam_row_sig(m, lcol_fg, i), prev = seam_sig[i];
|
||||||
seam_sig[i] = g; /* СНАЧАЛА сохранить (обход SDCC z80 sub-store */
|
seam_sig[i] = g; /* СНАЧАЛА сохранить (обход SDCC z80 sub-store */
|
||||||
/* бага: `if(g!=s)s=g` эмитит store РАЗНОСТИ g-s, */
|
/* бага: `if(g!=s)s=g` эмитит store РАЗНОСТИ g-s, */
|
||||||
/* не g — sdcc_z80_cmp_store_a_bug) */
|
/* не g — sdcc_z80_cmp_store_a_bug) */
|
||||||
@@ -906,7 +926,9 @@ int main(void)
|
|||||||
if (pop_item_taken) { /* предмет поднят → тайл стал полом */
|
if (pop_item_taken) { /* предмет поднят → тайл стал полом */
|
||||||
item_pos = (uint8_t)(pop_item_taken - 1);
|
item_pos = (uint8_t)(pop_item_taken - 1);
|
||||||
item_bake = 2; /* запечь на ОБЕИХ страницах */
|
item_bake = 2; /* запечь на ОБЕИХ страницах */
|
||||||
pop_level_set_tile(cur_room, item_pos, TILE_FLOOR);
|
/* Тайл в странице уровня ставит САМА do_pickup (pop_map.c): здесь
|
||||||
|
* это было бы слишком поздно — между подбором и этим местом
|
||||||
|
* успевает пройти pop_process_trobs (BUG-POTION-STRIPE). */
|
||||||
pop_add_trob(cur_room, item_pos, -1); /* меч убран — блеска больше нет */
|
pop_add_trob(cur_room, item_pos, -1); /* меч убран — блеска больше нет */
|
||||||
pop_item_taken = 0;
|
pop_item_taken = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -232,6 +232,14 @@ uint8_t pop_level_tile_raw(uint8_t room, uint8_t tilepos)
|
|||||||
return tk_room_fg[room][tilepos];
|
return tk_room_fg[room][tilepos];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Запись в «данные уровня» — у теста это тот же tk_room_fg. Нужна с тех
|
||||||
|
* пор, как do_pickup правит страницу уровня сразу (BUG-POTION-STRIPE). */
|
||||||
|
void pop_level_set_tile(uint8_t room, uint8_t tilepos, uint8_t tile)
|
||||||
|
{
|
||||||
|
if (room == 0 || room >= TK_ROOMS || tilepos >= 30) return;
|
||||||
|
tk_room_fg[room][tilepos] = tile;
|
||||||
|
}
|
||||||
|
|
||||||
/* Живое состояние стражей по комнатам — как gstate в pop_level.c, только на
|
/* Живое состояние стражей по комнатам — как gstate в pop_level.c, только на
|
||||||
* 8 комнат и без данных уровня: тесту нужно ровно то, на что смотрит
|
* 8 комнат и без данных уровня: тесту нужно ровно то, на что смотрит
|
||||||
* follow_guard (есть ли в целевой комнате свой страж и не труп ли он).
|
* follow_guard (есть ли в целевой комнате свой страж и не труп ли он).
|
||||||
|
|||||||
Reference in New Issue
Block a user