SprPoP: автономное приложение, выделенное из roomtest
Порт PoP переехал в applications/SprPoP — приложение, которое собирается само: код, оригинальные данные, конверторы ресурсов и сборка внутри одной папки. Наружу знает единственный путь — корень тулчейна (SPRINTER_ROOT, по умолчанию ../..). applications/PoP/roomtest ЗАМОРОЖЕНА и остаётся архивом закрытых задач, багов и исполненных планов. Скопировано из applications/PoP/roomtest@4b74478. Перенос проверен побайтово: собранный sprpop.exe совпал с roomtest.exe того же коммита, все 39 дисковых ресурсов и все 16 генерируемых заголовков — тоже, host- тесты зелёные (15/15). Раскладка: src/ рукописный C (roomtest.c -> sprpop.c) gen/ генерируемые заголовки, в репозитории assets/orig/ оригинальные данные игры, вне репозитория (копирайт) assets/packed/ то, что ложится на диск, в раскладке диска tools/ конверторы; все пути — в одном tools/paths.py build/ выход: exe, каталоги ресурсов, hdd/, промежуточные atl/ Сборка ресурсов: assets/packed и gen — версионируемые ВХОДЫ, а не то, что пересчитывается каждым make. Автоматика построена на ОТСУТСТВИИ файла, а не на таймстемпах: git не хранит времена, и в свежем клоне сравнение по времени превращалось бы в лотерею. Недостающий ресурс или заголовок чинится сам, рекурсивным вызовом в ветку генерации. Музыка собирается из любого из четырёх наборов записей (make music-mp3, music-mt32, ...); набор входит в имя stamp'а, поэтому смена набора сама делает музыку устаревшей. Длины реплик больше не захардкожены: упаковщик печатает их в gen/pop_music_ticks.h, и шкала сцены выражена через них — иначе mt32 (реплики на 6% длиннее) молча ломал катсцену. Тулчейн: в app.mk два обратносовместимых крючка (SRC_DIR/BUILD_DIR), HDD_IMG стал ?=; команда сборки roomtest не изменилась. Корневой make host-tests переключён на SprPoP. Подгонка тайминга катсцены с принцессой (PV_MAGIC_LEAD): сцена render-bound и идёт ~49 тиков/с вместо 60, из-за чего кода реплики приходила раньше молнии. Это обход, а не лечение; разбор с замерами — docs/BUGS_OPEN.md, записи SND-PACE-DEAD, PV-RENDER-BOUND, MUS-LEFT-TEAR. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* pop_state.h — состояние, общее для банков и W1/W2. См. pop_state.c.
|
||||
*
|
||||
* Правило: если переменную читают/пишут по обе стороны банковой границы —
|
||||
* её место здесь, а НЕ в банковом модуле (там она уедет в страницу банка).
|
||||
*/
|
||||
#ifndef POP_STATE_H
|
||||
#define POP_STATE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Есть ли хоть один ЗАНЯТЫЙ слот падающего куска (active или дочистка
|
||||
* clean). Гейт холостого хода: пока кусков нет, ни обход 14 слотов в
|
||||
* pop_loose_mob_tick, ни поиск куска над головой Кида делать не нужно
|
||||
* (замер 11/15: 12 090 + 5 868 тактов на комнату, где не падает ничего).
|
||||
*
|
||||
* Живёт в резиденте, а не в pop_room.c, потому что читает его pop_map
|
||||
* (банк 3), а писучие статики банкового модуля наружу не видны. Ставит
|
||||
* отрыв куска, снимает сам обход по факту пустой таблицы. */
|
||||
extern uint8_t pop_mob_busy;
|
||||
|
||||
/* Кусок 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), переключает главный цикл. */
|
||||
/* ЧИТ БЕССМЕРТИЯ, три состояния (клавиша I по кругу):
|
||||
* 0 — выключено;
|
||||
* 1 — только БОЙ: удары мечом не отнимают HP (pop_take_hp тут ни при
|
||||
* чём, ветка живёт в hurt_by_sword, guards.c);
|
||||
* 2 — бой И мелкий урон: не проходят «минус одно деление» от падения с
|
||||
* двух этажей и от падающей плиты (pop_take_hp гасит count < 100).
|
||||
* МГНОВЕННАЯ СМЕРТЬ остаётся на любом уровне: пики, чомпер, падение с
|
||||
* трёх этажей, удар мечом вне боевой стойки — все они приходят с
|
||||
* count = 100. Чит отменяет потерю HP, а не смерть. */
|
||||
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);
|
||||
/* ВРЕМЕННО (разбор pop_phys_tick 2026-08-19, позиция P2a): физика Кида —
|
||||
* 61 266 тактов на НЕПОДВИЖНОМ персонаже. По одному зонду на звено
|
||||
* цепочки kid_phys. */
|
||||
void pop_dbg_p1(void); void pop_dbg_p2(void); void pop_dbg_p3(void);
|
||||
void pop_dbg_p4(void); void pop_dbg_p5(void); void pop_dbg_p6(void);
|
||||
void pop_dbg_p7(void); void pop_dbg_p8(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;
|
||||
Reference in New Issue
Block a user