Files
Sprinter-SDCC/applications/PoP/roomtest/pop_state.h
T
snark13 272cf8f195 Разбор порядка отрисовки падающей плиты: найден корень, выбран вариант B
СИМПТОМ (пользователь, ур.11 к.14).  Кусок, отвалившийся от плиты нижнего
ряда, рисуется ПОВЕРХ соседней трясущейся плиты; при этом передний торец
соседа лежит поверх куска — порядок противоречив в разных частях
перекрытия.

КОРЕНЬ.  draw_mob (seg007:13E5) считает ряд объекта как
y_to_row_mod4(y) = (y+60)/63 % 4 - 1.  Из-за % 4 ряд 3 (кусок ушёл ниже
комнаты) и ряд −1 (кусок у потолка) дают ОДНО значение −1.  Оригинал
прогоняет его через get_tilepos -> get_tilepos_nominus и получает тайл 30,
а объекты с тайлом 30 рисуются в redraw_needed_tiles ПЕРВЫМИ, до всего
обхода тайлов.  Мы же передаём сырой −1 в мид-оверлей как «тайл объекта», и
гейт `row > pop_bg_obj_row` читает его как «объект в последнем ряду обхода»,
то есть «объект поверх всего», и отбрасывает возврат соседа.  Один и тот же
−1 у нас значит «сверху», у оригинала — «снизу».

Торец при этом виден потому, что приходит из ДРУГОГО слоя: draw_loose кладёт
loose_fram_bottom в backtable и foretable, минуя ptr_add_table, — тело плиты
обязан вернуть мид-оверлей, а его и выключает гейт.

ЧТО ПРОВЕРЕНО ЗАМЕРОМ (журнал решений в pop_dbg_ovl/pop_dbg_pass, зонды
ВРЕМЕННЫЕ и будут сняты):
 - на застывшем кадре: слот draw_y=194, r=−1, rt=2, оверлей позван, внутри
   отбрасывается гейтом;
 - пропуск оверлея на последнем кадре полёта ЗАКОНЕН: габарит куска уже
   ниже габарита тайла, перекрывать нечего;
 - в 13/23 кусок перекрывают 2-4 тайла (накопленно за полёт), включая СВОЮ
   клетку, — то есть «сосед справа» покрытие не исчерпывает;
 - перерисовок тайлов за кадр в 13/23: максимум 6, в покое 0.

ТУПИКИ, чтобы не ходить второй раз.  Клип объекта тут ни при чём:
add_mob_to_objtable ставит clip.right = 40, но клип применяется только при
chtab_flip_clip[chtab_id], а для chtab_6_environment там 0 — поле
игнорируется и в оригинале.  Пункт MOB-CLIP-RIGHT закрывается как
несуществующий.  Добавлять торец плиты в мид-оверлей тоже не надо: в
foretable он уже кладётся из fore_tile.

ВЫБРАН ВАРИАНТ B: классифицировать ряд объекта (вне 0..2 = корзина 30),
отдавать оверлею ориентир «раньше любого тайла» и расширить набор
перекрываемых тайлов на СВОЮ клетку.  Переносить проход отрисовки не нужно —
heal при этом не участвует, работа та же (оверлей = два блита в окне клипа),
разница с узким вариантом A всего один-два оверлея на кусок.

Заодно записана ОБЯЗАТЕЛЬНАЯ задача HEAL-WIDTH: ширины точечных heal'ов
взяты по клеткам (64), а фактический след плиты — 58/57 (замерено по
атласам: верх 32, правая грань 26 в подземелье и 25 во дворце).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:51:00 +03:00

109 lines
6.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* pop_state.h — состояние, общее для банков и W1/W2. См. pop_state.c.
*
* Правило: если переменную читают/пишут по обе стороны банковой границы —
* её место здесь, а НЕ в банковом модуле (там она уедет в страницу банка).
*/
#ifndef POP_STATE_H
#define POP_STATE_H
#include <stdint.h>
/* Кусок loose приземлился (loose_land, seg007:11E8): 0 = нет, иначе
* tilepos+1 тайла, на который он лёг. Ставит отрисовка mob (банк),
* разбирает логика loose-полов (pop_map, W1/W2). */
extern uint8_t pop_loose_landed;
/* Кусок loose ушёл ниже поля своей комнаты: 0 = нет, иначе col+1; комната
* отправления — pop_loose_exit_room. Ставит отрисовка mob (банк 7),
* разбирает главный цикл (посадка в комнате снизу). */
extern uint8_t pop_loose_exit;
extern uint8_t pop_loose_exit_room;
/* Тайл СОСЕДНЕЙ (не отрисованной) комнаты изменился — перечитать кромки.
* Подробности — в pop_state.c. */
extern uint8_t pop_neigh_dirty;
/* Бесшовный переход между уровнями (seamless): подробности в pop_state.c.
* Ставится главным циклом при попадании в комнату-выход, гасится стартом
* уровня — он же единственный, кто на флаг смотрит. */
extern uint8_t pop_seamless;
/* Держатель бесшовного перехода после ЧИТ-телепорта (см. pop_state.c).
* Ставит pop_dbg_roomnav, снимает первая смена комнаты обычным ходом. */
extern uint8_t pop_nav_hold;
/* Чит «бессмертие» (I): Кида бьют, но HP не убавляется. Читают пути урона
* (боёвка в банке, пики в pop_map), переключает главный цикл. */
extern uint8_t pop_immortal;
/* Габариты ПОСЛЕДНЕЙ нарисованной двери уровня — порт глобалов
* leveldoor_right / leveldoor_ybottom (seg008 draw_leveldoor). Их ставит
* отрисовка (банк pop_bg), а читает clip_char (pop_map, W1/W2): кадры
* подъёма по лестнице (224..228) обрезаются по правому косяку проёма и по
* низу поднятой створки. Дверь рисуется ПОД персонажем, поэтому перекрыть
* его не может — оригинал именно режет спрайт.
* right — экранный X правой кромки; ybottom — room-space Y (без POP_YOFF).
* 0 = двери в отрисованной комнате нет. */
extern int pop_leveldoor_right;
extern int pop_leveldoor_ybottom;
/* droppedout (seg006:1140): Кида СПИХНУЛИ с уступа в бою — он падает из
* боевой стойки. Ставит start_fall (pop_map, банк 3), читает ИИ стража
* (guards.c, банк 1): по этому флагу страж решает, идти ли за упавшим вниз
* (guard_follows_kid_down, seg002:09F8). Отсюда и место в общем модуле —
* банки друг другу данные не отдают. */
extern uint8_t pop_droppedout;
/* leveldoor_open (seg007:456): 1 — дверь уровня открыта полностью. Пишет
* анимация двери (банк 6), читает подъём скелета (банк 1). Word, как в
* оригинале: на уровне 8 в него же СЧИТАЕТСЯ задержка до мыши (см.
* pop_state.c и pop_check_mouse в guards.c). */
extern uint16_t pop_leveldoor_open;
/* Отладочная «пустышка» для брейкпоинтов из банков — см. pop_state.c.
* Звать из отлаживаемого места под нужным `if`, брейкпоинт ставить на
* _pop_dbg_trap (резидент W1, адрес однозначен). */
extern uint8_t pop_dbg_hits;
void pop_dbg_trap(void);
#endif
/* Зеркало уровня 4 (jumped_through_mirror, seg003). 1 — Кид ТОЛЬКО ЧТО
* пролетел сквозь зеркало (ставит is_obstacle в pop_map, банк 3), и
* следующий pop_check_mirror родит тень; 0 — обычное состояние.
* Межбанковый: пишет pop_map, читает pop_map же, но через главный цикл. */
extern int8_t pop_jumped_mirror;
/* ВРЕМЕННО: маркеры фаз кадра (замер). */
void pop_dbg_m1(void); void pop_dbg_m2(void);
void pop_dbg_m3(void); void pop_dbg_m4(void);
/* ВРЕМЕННО: состав перерисовок в самом тяжёлом кадре (замер). */
extern uint8_t pop_dbg_rdmax[10];
extern uint8_t pop_dbg_rdmax_tot;
/* ВРЕМЕННО: маркеры внутренних замеров. */
void pop_dbg_m5(void); void pop_dbg_m6(void);
void pop_dbg_m7(void); void pop_dbg_m8(void);
void pop_dbg_m9(void); void pop_dbg_m10(void);
void pop_dbg_m11(void); void pop_dbg_m12(void);
void pop_dbg_m13(void); void pop_dbg_m14(void);
void pop_dbg_m15(void);
void pop_dbg_kind(uint8_t k); void pop_dbg_m16(void);
void pop_dbg_b1(void); void pop_dbg_b2(void); void pop_dbg_b3(void);
void pop_dbg_b4(void); void pop_dbg_b5(void); void pop_dbg_b6(void);
void pop_dbg_wh(uint16_t wh);
/* ВРЕМЕННО: трасса kidobj (см. pop_state.c). Порядок байт:
* 0 obj_tilepos, 1 frame, 2 action, 3 curr_col, 4 char_col_left,
* 5 char_col_right, 6 char_top_row, 7 char_bottom_row, 8 комната. */
extern int8_t pop_dbg_obj[9];
/* ВРЕМЕННО: разбор оверлея падающего куска (см. pop_state.c). */
extern uint8_t pop_dbg_pass[14];
extern uint8_t pop_dbg_ovl[14 * 4];
extern uint8_t pop_dbg_tiles[14];
void pop_dbg_kidobj(void) __banked;