Commit Graph

10 Commits

Author SHA1 Message Date
snark13 6feab5d2f2 Смерть на кнопке ломает её насовсем (died_on_button, seg007:776)
Уровень 7 начинается падением; разбившись на кнопке открытия решётки
(комната 3, тайл 2,1), Кид в оригинале открывает решётку НАСОВСЕМ, а у нас
она закрывалась обратно.  Чинить пришлось три места.

1. pop_phys_tick выходил по pop_kid_dead, то есть check_press до трупа не
   доходил вовсе.  У оригинала play_kid_frame гейтится только Char.room
   != 0.  Кнопка получала одно нажатие — в кадре смерти, потому что флаг
   ставит land() уже внутри цепочки.  «Труп не шевелится» держит внутренний
   выход в kid_phys, он остался.

2. Портирован died_on_button: открывалка → пол + связь дёргается типом
   «щебень» (открыть насовсем), прочие кнопки → TILE_STUCK.  Ветки по
   Char.alive в check_press не было вовсе.

3. Рестарт уровня восстанавливал только foretable, а died_on_button
   оставляет таймер связи нажатым (trob кнопки умирает сразу — тайл уже
   пол).  Остаток переживал респавн, и кнопка рисовалась нажатой с первого
   кадра.  pop_level_reset_tiles теперь возвращает и LINKMAP.

Проверено в MAME по всему циклу: смерть → FF (открыта навсегда), респавн →
кнопка цела и не нажата, второе падение → снова ломается.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:27:36 +03:00
snark13 b49ba15666 DIED-ON-BUTTON: найдена вторая половина — физика трупа выключена целиком
Кид гибнет на кнопке открытия решётки (уровень 7, комната 3, тайл 2,1) —
в оригинале решётка открыта насовсем, у нас отжимается.  Мало того, что
died_on_button (seg007:776) не портирован: pop_phys_tick целиком выходит
по pop_kid_dead, так что check_press до трупа не доходит вовсе.  У
оригинала play_kid_frame гейтится только Char.room != 0.

Фикса пока нет — запись в BUGS_OPEN.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:11:33 +03:00
snark13 89b603ae04 Дворцовый портал: Кид скрывался за кромкой раньше времени
Уровень 4: в анимации ухода на следующий уровень контур Кида обрезался не
правой гранью портала, а раньше — брался клип подземного проёма, а
дворцовый шире.

draw_leveldoor считал кромку как xh*8 + 48, без дворцовой поправки. В
оригинале строкой ниже стоит (seg008:1429):

    if (custom->tbl_level_type[current_level]) leveldoor_right += 8;

Значение читает clip_char как правую границу клипа персонажа — отсюда
ранняя обрезка. Расхождение было осознанным и отложенным: в коде стоял
комментарий «+8 у palace-уровней — на уровне 1 не применяется», дворцовых
уровней тогда в порту не было. tbl_level_type[4] = 1, там и проявилось.

pop_palace выставляет pop_bg_load из того же tbl_level_type, что читает
оригинал, так что эквивалент дословный.

Попутно найдено и НЕ починено (заведено отдельным багом
LEVELDOOR-STARTROOM-WIPE): в той же функции оригинал в СТАРТОВОЙ комнате
кладёт затирающий прямоугольник вместо лестницы, со своей дворцовой/
подземной разницей 48/39 и сдвигом 2 px, а мы рисуем марш 144 безусловно.
Видно только при приподнятой створке входной двери, поэтому на обходах
уровней 1-4 не попалось.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 23:27:22 +03:00
snark13 67d62e3e8b Уровни 12 и 13: тень, Джафар, падающие плиты + разбор слоёв
Уровень 12 (тень) — порт seg002/seg006:
- check_shadow: подъём тени в комнате 15 по условию «меч подобран»,
  init_shad_12, вход падением (seq 7);
- autocontrol_shadow_level12: ждать Кида, бой, сближение, СЛИЯНИЕ;
- общий урон (ранил тень — ранил себя) и check_killed_shadow
  (убил тень — убил себя);
- таймер вспышки слияния 42 -> -1, sword_disappears при уходе из
  комнаты 18, появление плит в комнатах 2/13 после слияния.

Переход 12 -> 13 бесшовный: двери у уровня нет, он кончается фактом
попадания в комнату 23 (tbl_seamless_exit); флаг pop_seamless не даёт
сбросить HP.  Чит навигации по комнатам этот триггер придерживает —
иначе комнату 23 двенадцатого уровня не посмотреть в принципе.

Уровень 13 (Джафар): guard_notice_timer (фора после встречи),
on_guard_killed + Jaffar_exit, check_fall_flo (гряда плит сверху) и три
исключения loose-механики.  Плюс спрайты визиря VIZIER.DAT — без них он
рисовался обычным стражем; заодно цвет из данных комнаты применяется
только к обычному стражу, как в оригинале.

Падающие плиты — семь дефектов, найденных прогонами:
- MOB_MAX 4 -> 14: check_fall_flo роняет шесть плит разом, лишние
  терялись без щебня;
- одиночные сигналы посадки/провала больше не затираются в кадре;
- честный loose_fall: сбитая плита рождается в том же кадре, от места
  удара, с половинной скоростью;
- при снятии плиты метится и сосед справа (висел передний торец);
- heal и отрисовка кусков разнесены на два прохода;
- куски рисуются ПОСЛЕ фона, порядок между собой — по убыванию y
  (compare_curr_objs для пары 0x80 сортирует наоборот);
- wall_pattern убран из ceil_over_kid_tile: у оригинала узор из
  draw_tile_bottom идёт в фон, а не в передний слой.

Хост-тесты: два новых набора, t_shadow (45 проверок) и t_jaffar (44).
TK_ROOMS 8 -> 24 — спецсобытия адресуют комнаты по реальным номерам.

Осознанные расхождения (docs/impl_diff.md): нет мигания Кида спрайтами
тени при слиянии, чит навигации не запускает бесшовный переход, чит K
убивает через штатный путь смерти.

Открытым остаётся разбор слоёв: MOB-CLIP-RIGHT, MID-OVERLAY-LAYER,
GUARD-FALLOUT-VICTORY, BG-ONCE (BUGS_OPEN.md / TASKS_OPEN.md).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 18:21:52 +03:00
snark13 d7d18aef77 Зелье медленного падения (перо) + цвет пузырьков по типу зелья
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>
2026-08-12 12:13:29 +03:00
snark13 b5951c9b5c Зацеп за кромку нижнего ряда: do_fall пускает ряд до 3 + check_grab в midair
Уровень 7, комната 14: спуск с ряда 0 на ряд 2 через зацеп (повис на кромке
кнопки (0,2), отпустил, взялся за (2,2)) не работал ни при какой фазе и
задержке — Кид пролетал мимо и разгонялся до fall_y = 33, после чего окно
зацепа закрыто уже по скорости.

Корень: do_fall не давал curr_row выйти за 2, а check_grab целится в тайл
ряда curr_row-1 — то есть ряд 2 своей комнаты становится целью только при
curr_row == 3.  В оригинале (seg005:0030) inc_curr_row безусловный, а
get_tile для ряда 3 уходит по links.down (find_room_of_tile, seg006:005D).

- pop_map.c do_fall: inc_curr_row теперь 2 -> 3; ветка «достиг y_land»
  гейтится по curr_row <= 2 (при ряде 3 ни in_wall, ни land звать нельзя —
  тайлов своей комнаты там нет, а до y_land[4] дело не доходит: комнату
  меняет check_leave_below на y >= 211).
- pop_map.c check_action: восстановлена ветка ACT_MIDAIR (кадры 102..105,
  seg006:0619) — первые четыре кадра падения, где fall_y ещё не разогнан,
  зацеп не работал вовсе.  Отсюда же «иногда цепляется, иногда нет».
- tests-host/t_grab.c: регресс grab_below_room_edge_window_exists — сцена
  комнаты 14 + переход в 15 по pop_fell_out.  До фикса ни одного зацепа,
  после — окно из 8 фаз X при задержках 0..5 кадров; проверяется и
  играбельность (зацеп при «отпустил и сразу зажал Shift»).
- roomtest.c + pop_guard.h: чит-навигация ставит Кида на верхний ряд в
  комнате 14 уровня 7 (GRAB_DOWN_LEVEL/ROOM) — снизу этот спуск не проверить.
  Общее правило (снизу вверх) не тронуто: в верхнем ряду пола чаще нет и Кид
  проваливается сразу после телепорта.

Проверено: tests-host 5/5 (55 в [grab]), size-check OK, живьём в MAME —
Кид повис на кромке (2,2): frame=91 y=55 row=0 room=15.

Доски: GRAB-BELOW-ROOM в BUGS_CLOSED, GRAB-KBD-TIMING в BUGS_OPEN (отложен
пользователем до готовности всех уровней), план L7-FEATHER в TASKS_OPEN.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 11:58:17 +03:00
snark13 9ecea17ba6 Уровень 6: переход на 7-й, портал, многокомнатное падение плиты
Всё проверено пользователем в MAME.

1. Переход 6 -> 7 падением.  leave_room (seg002:0504) для «вниз» на уровне 6
   из комнаты 1 даёт особый результат −2, главный цикл (seg000:0893) читает
   его как ++next_level; вход на 7-м (set_start_pos, seg003:0196) ставит Кида
   в комнату 17 и сразу переводит экран на комнату под ней.  Проверка ОБЯЗАНА
   идти раньше связи вниз: у комнаты 1 сосед снизу есть (шахта, комната 3).

2. BUG-BALCONY-RIGHT: правая половина портала не рисовалась.  id 12 стоял в
   FORE_ENV_IDS (в tile_table он fore_id ЗЕЛЬЯ), но зелье рисуется из
   chtab_1, а в chtab_6 под этим номером — правая часть арки балкона 32x62,
   идущая в backtable.  Спрайт уезжал в fore-атлас, env-страница получала
   дырку (idx 12: w=0 h=0).  Найдено трассой POP_TRACE_BT + чтением каталога
   .atl; дифф комнаты с оригиналом 1151 -> 375.

3. BUG-BELOWROW-WALL: жёлтые треугольники в шахте падения.  load_rowbelow
   (seg008:368) при отсутствующей комнате снизу подставляет tiles_0_empty
   колонкам 1..9 и tiles_20_wall только левому краю; у нас стеной забивались
   все 11 позиций.

4. BUG-MOB-MULTIROOM: честный mob_down_a_row (seg007:1387) — кусок переходит
   в комнату снизу и летит дальше.  Плита (1,7) комнаты 6 пролетает шахту
   комнаты 7 и жмёт кнопку (2,7) комнаты 11, открывая ворота комнаты 18.

5. BUG-MOB-STALE-PAGE: чистка следа куска стояла под гейтом «в отрисованной
   комнате» — улетевший вниз оставлял себя на одной из страниц навсегда.

6. BUG-CHAR-STALE-PAGE: тень застывала на двух страницах в РАЗНЫХ позах.
   Прямоугольник и valid пишутся внутри `if (w && h)`, а снимок состояния
   брался безусловно — при нулевом спрайте слот залипал «тихим».  Остаток
   (почему спрайт нулевой) заведён как SPRITE-ZERO-W0 в BUGS_OPEN.

NEXT_SESSION переписан: следующая задача — зацеп за край пола в свободном
падении (вход на уровень 7).  tests-host 5/5, size-check чист.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 23:01:58 +03:00
snark13 36a60f54ba Кнопка в ШВЕ срабатывала как чужая связь (нашёл пользователь на ур. 5)
Симптом: Кид встаёт на плиту, которая физически в СОСЕДНЕЙ комнате (стоя в
шве, curr_col = −1), и вместо одних ворот открываются двое — на уровне 5
плита комнаты 11 открывала и нижние ворота комнаты 24, и верхние, хотя
связана только с нижними.

Причина.  check_press читал тайл через get_tile (тот резолвит шов в
соседнюю комнату), а комнату и tilepos для trigger_button брал из
координат персонажа: (своя комната, row*10 + curr_col).  При curr_col = −1
это tilepos 9 СВОЕЙ комнаты — там стена с bg = 0, то есть индекс цепочки
LINKLOC 0.  Цепочка от нуля в данных уровня 5 ведёт на ДВА тайла: нижние
ворота (link[0], next=1) и верхние (link[1]) — ровно то, что наблюдалось.
Настоящая кнопка имеет индекс 9 и одну цель.

В оригинале этого нет по построению: get_tile зовёт find_room_of_tile
(seg006:005D) и ПЕРЕСТАВЛЯЕТ curr_room/curr_tilepos, а trigger_button
работает уже с ними.  У нас резолв комнаты жил только внутри get_tile, а
наружу не отдавался.

Фикс: tile_room_of(col,row) — комната и tilepos клетки с учётом швов (по
образцу gate_modif, который так делал давно), check_press зовёт
trigger_button с резолвнутыми room/tilepos.  Ветка loose там же оставлена
на координатах персонажа: make_loose_fall работает с g_fg своей комнаты.

Два других вызова trigger_button (зацеп за кромку, севшая на кнопку плита)
правки не требуют — оба ограничены колонками 0..9 своей комнаты.

Заведён GATE-FORE-KID (BUGS_OPEN.md): Кид, стоящий В ПРОЁМЕ ворот, виден
поверх решётки — у нас портирован только шовный случай окклюзии, а
draw_tile_fore (seg008:0D15) рисует решётку поверх персонажа и внутри
комнаты.  Чинить в fore-слое отдельно, он горячий.

tests-host 5/5, make size-check OK.  Банк 3: 10648 -> 10828 Б.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 17:32:11 +03:00
snark13 096517d8aa MIRROR-FG-STALE закрыт как НЕ БАГ (проверено пользователем)
Прогон читом ROOMNAV: телепорт в комнату 4 сразу после нажатия кнопки —
зеркала нет вовсе (тайл ставится в момент, когда дверь ДОРИСОВАЛА открытие,
43 тика анимации, телепорт успевает раньше); обычный вход в комнату —
зеркало на месте и непроходимо, кроме правильного прыжка, то есть коллизия
его видит.  Сценария «постановка при игроке в комнате» в реальном
прохождении нет: дверь выхода стоит не в комнате зеркала, а при входе
комната и снимок room_fg берутся из данных уровня разом.

Решение пользователя: телепорт по комнатам — отладочный режим, чинить нечего.
Запись целиком уехала в BUGS_CLOSED.md вместе с протоколом и с указанием, чем
лечить, если симптом всё же всплывёт на моде/уровне, где кнопка и зеркало в
одной комнате.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 16:22:04 +03:00
snark13 5348feb5f4 Доски приведены в соответствие с кодом; bug_list/bug_closed → BUGS_OPEN/BUGS_CLOSED
Доска отставала от кода на три задачи — планировать по ней было нельзя.
Сверка проведена грепом по исходникам, а не по записям:

- L4-MIRROR ЗАКРЫТА: шаги 1-5 сделаны и проверены пользователем в MAME
  (зеркало в атласе, постановка тайла, отражение, прыжок сквозь зеркало с
  рождением тени, левый клип тени).  Протокол с разбором решений — в архиве;
- L3-CHOMP и L3-SKEL закрыты ещё 2026-08-08/07 (коммиты dc0bd47, 4d4323f,
  db4106a, 1461ed5), на доске значились как предстоящие;
- тайлсет palace (шаг 2 levels_plan) в коде есть целиком — pop_bg_load(type),
  pal_*.atl, дворцовый wall_pattern, решётки 25-29 и в tile_table, и в
  коллизии (tile_is_floor совпадает с seg006:0628);
- в GUARD-PHYS остаток пересобран по факту: check_chomped_guard сделан,
  скелет в check_guard_fallout сделан, ветки ТЕНИ нет — она уехала в L5-SHADOW.

Приёмки: по решению пользователя уровни 1-4 приняты SMOKE-тестами, полные
обходы всех комнат делаются по готовности ВСЕХ уровней — L3-PASS/L4-PASS как
отдельные задачи отменены, вместо них политика приёмок в архиве.

Новая цель — уровень 5.  Инвентарь res2005.bin: НИ ОДНОГО нового тайла, всё
портировано на уровнях 1-4.  Единственная новая механика — спецсобытие «тень
крадёт зелье» (комната 24): заведена задача L5-SHADOW с портом по SDLPoP
(check_shadow / do_init_shad / do_auto_moves + shad_drink_move /
autocontrol_shadow_level5 + ветка тени в check_guard_fallout), включая
готовые константы и то, что у нас уже есть под это.

Заведён MIRROR-FG-STALE (низкий): place_mirror пишет тайл в данные уровня, но
не в снимок room_fg, по которому работает коллизия — если зеркало поставлено,
пока игрок В комнате 4, оно невидимо для коллизии (тень не родится).  В
обычном прохождении недостижимо: дверь выхода в другой комнате.  Записан
точный сценарий воспроизведения читом ROOMNAV и фикс на несколько строк.

Правило «в _OPEN только незакрытое» теперь выполняется буквально:
- bug_list.md → BUGS_OPEN.md, bug_closed.md → BUGS_CLOSED.md (ссылки
  обновлены во всех документах и в комментарии pop_trob.c);
- из TASKS_OPEN убраны блоки закрытых задач (L3-CHOMP, L3-SKEL, L3-PASS,
  L4-MIRROR, DRAW-CHAR), справка по связности комнат уехала в архив;
- из BUGS_OPEN убраны 8 строк таблицы закрытых багов, закрытый T-2 (уехал в
  BUGS_CLOSED) и раздел «уровень 3 — неначатые задачи» (обе записи закрыты);
  сводная таблица пересобрана по реально открытым записям.

Все внутренние ссылки проверены скриптом: битых якорей 0.  make size-check
OK (65 программ), tests-host 5/5.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 16:10:10 +03:00