L7-FEATHER: тип 3 (уровень 7, комната 1) больше не пустой TODO.
- pop_map.c: pop_feather — счётчик кадров эффекта (POP_FEATHER_FRAMES = 225,
ванильный порог do_timers seg003:0517; привязку к звуку взять неоткуда).
fall_accel — ускорение 1 / потолок 4 (seg006:057C) вместо 3 / 33.
proc_get_object case 3: взвести эффект + зелёная вспышка на 3 кадра.
- pop_kid.c: опкод JMP_IF_FEATHER (0xF7) больше не пропускает адрес
безусловно — под пером прыгает по нему, то есть seqtbl уводит падение и
удар в ветки stepfloat/bumpfloat (плавные кадры, без урона).
- roomtest.c: pop_flash_red -> pop_flash_color (жёлтый/красный/ЗЕЛЁНЫЙ);
сброс pop_feather в pop_start_level (seg003:189).
- Цвет пузырька по ТИПУ зелья (seg008:652), чего у нас не было вовсе:
3/4 зелёный, 5/6 СИНИЙ, остальные красный. Mono-блиттера с параметром
цвета в libbgi нет, поэтому цвет запекается при упаковке: pop_pack_bg.py
кладёт те же 7 кадров ещё дважды (id 30..36 зелёные, 40..46 синие),
pop_potion_draw выбирает набор. Атлас 23 -> 37 спрайтов (+423 Б).
- Синее зелье «−HP» приведено к оригиналу (seg006:1892): своей вспышки не
ставит (красный кадр даёт общий flash_if_hurt — иначе экран красился
дважды), а на уровне зелий забирает ПОЛОВИНУ запаса HP.
Такое зелье стоит уже на пройденном уровне 2 (комната 13, тайл (1,3)),
а также ур.8 комн.2 и весь ур.15 — до сих пор оно было красным.
Тесты: phys_feather_fall_is_slow_and_harmless (обычное падение с двух рядов
разгоняется и стоит HP, под пером скорость <= 4 и HP целое); tests-host
5/5 (1727 в [phys]), size-check OK.
Расхождения с ванилью — в docs/impl_diff.md (перо ловит только Кида;
синее зелье без своей вспышки).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Проверять физику Кида глазами в MAME дорого и ненадёжно: ошибка почти
всегда не в одной функции, а в РАСХОЖДЕНИИ ТРАЕКТОРИИ через несколько
кадров. Харнесс гоняет тот же кадр, что и главный цикл
(pop_ctrl_tick -> kid_tick -> pop_phys_tick -> pop_loose_tick), и
сравнивает трассу состояния с эталоном.
- scene.c/.h — раннер: комната + стартовая поза + скрипт ввода -> трасса;
sc_kid_at_x задаёт точный X (исход часто зависит от фазы внутри тайла).
- stubs.c/.h — libc/libbgi/соседние модули; read() реально отдаёт
kid_data.bin (иначе kdat_ok=0 и play_seq молчит — трасса замирает).
- t_phys.c — 9 характеризующих сценариев, 1723 сверки (golden/).
- t_grab.c — окно зацепа: существует, достижимо коротким шагом, не
зависит от рисунка нажатий.
- record_golden.py — снятие эталона по одному сценарию за прогон.
- testkit/host-tests.mk — CODE_LOC настраиваемый, EXTRA_INC/EXTRA_CFLAGS.
Именно харнесс дал доказательство, что физика зацепа у нас верна, и тем
самым перевёл поиск BUG-GRAB-1 на клавиатуру.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>