Files
Sprinter-SDCC/applications/SprPoP/docs/vanilla_vs_bugfixed.md
T
snark13 4e12aa50d1 SprPoP: падение сквозь стену больше не проходит
Портировано опциональное исправление SDLPoP (fix_glide_through_wall,
seg005 в do_fall).  В ванили персонаж, падающий после разворота в беге,
может оказаться внутри кладки и лететь «в стене» — баг оригинала,
воспроизведённый пользователем в игре и затем на host-тесте.

Решением 2026-08-31 фикс взят в ТЕКУЩИЙ билд: играбельность важнее
буквальности.  Реализация вынесена отдельной функцией
glide_through_wall_guard() в pop_map.c намеренно — при разделении
VANILLA/ENHANCED это готовая точка отвязки, достаточно не звать её в
ванильном режиме.

ПРОВЕРКА.  Набор t_wall был заранее написан так, чтобы сторожить ЧИСЛО
заходов в кладку: до фикса их было ровно два из четырнадцати стартовых
позиций, после — ноль.  Остальные 15 наборов (в том числе phys с 1733
проверками и grab) остались зелёными.  Живая проверка в MAME
пользователем: корректно.

Ожидание в тесте обновлено ОСОЗНАННО, прежнее число сохранено рядом
отдельной константой с пометкой «сколько было до фикса»: оно измерено, и
понадобится, когда появится режим VANILLA — там ожидание станет зависеть
от режима.

ЦЕНА: +57 байт в банке 3 (свободно 3043), резидент и куча не изменились.
По скорости попадание только на кадры падения: пересчёт колонки — одно
деление, дистанция до кромки считается лишь если персонаж действительно
внутри кладки.

Документы: в аудите находка 21 переведена в «портировано» с сохранением
исходного разбора; в vanilla_vs_bugfixed статус фикса стал ВЗЯТ, сводка
пересчитана (5 взято, 32 кандидата в ENHANCED).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011MsUsEFAQfsjjQpJ7RtKVY
2026-08-31 20:52:44 +03:00

20 KiB
Raw Blame History

Два поведения: VANILLA и BUGFIXED

Заведено 2026-08-31. Задача поставлена, работа НЕ начата.

Зачем

У оригинального PoP есть баги, которые игроки знают наизусть и на которых построены известные трюки. SDLPoP чинит их не молча, а ОПЦИОНАЛЬНО: каждое исправление отдельным переключателем, по умолчанию часть включена, часть нет. Мы до сих пор повторяли ваниль — сознательно, чтобы порт вёл себя как оригинал.

Задача: дать ДВА поведения на выбор, не размазывая условия по всему коду:

  • VANILLA — как в оригинале 1989 года, со всеми его багами;
  • BUGFIXED — с портированными исправлениями SDLPoP.

Что уже известно (из аудита)

Разбор расхождений — docs/sdlpop_audit.md. Оттуда прямо в эту задачу переезжает следующее.

Опциональные фиксы SDLPoP, которых у нас НЕТ

Все три относятся к прохождению сквозь препятствия и живут в do_fall (seg005) и рядом:

фикс SDLPoP что чинит
«скольжение сквозь стену» Кид падает сквозь стены после разворота в беге, особенно под зельем медленного падения
«прыжок сквозь стену над воротами» пролёт в тайл над воротами
«проваливание сквозь гобелен» падение сквозь тайл гобелена

Ни один не портирован — это и есть наше нынешнее VANILLA.

Находка 24 — отложена сюда

in_wall у нас пересчитывает только колонку, а оригинал перезагружает ещё и данные кадра (load_fram_det_col, seg006). Правка сделана и ОТКАЧЕНА 2026-08-31 по такой причине:

  • по букве оригинала находка верна;
  • но практического эффекта показать НЕ УДАЛОСЬ — все 15 наборов host-тестов дают одинаковый результат до и после, включая специально написанный тест на заход в кладку;
  • при этом правка не бесплатна: добавляет маппинг окна и перезагрузку кадра на каждое выталкивание из стены.

Платить за недоказанное не стали. Вернуться к ней имеет смысл именно здесь: при работе над BUGFIXED появится сценарий, где кадр меняется перед выталкиванием, и тогда эффект станет наблюдаемым.

Готовый детектор поведения

tests/host/t_wall.c расширен с одной проверки до трёх. Ключевая — wall_stops_jump_from_left_side: она НЕ требует нуля заходов в кладку, а сторожит их ЧИСЛО (сейчас ровно два случая из четырнадцати стартовых позиций).

Это и есть переключатель ожиданий между режимами:

  • больше двух — правка сделала нас хуже ванили, регресс;
  • ровно два — ведём себя как оригинал (режим VANILLA);
  • меньше двух — кто-то портировал фикс; в режиме BUGFIXED тест должен ждать нуля.

То есть когда появится BUGFIXED, этому тесту понадобится ожидание, зависящее от режима, — и он готов стать первым таким.

Переключатель уже есть — второго не нужно

Уточнено 2026-08-31: в настройках игры ПЕРЕКЛЮЧАТЕЛЬ VANILLA/ENHANCED СУЩЕСТВУЕТ (docs/menu_settings_plan.md), просто сейчас он жёстко зафиксирован в положении VANILLA. Отдельную сущность заводить не надо — эта задача про то, чтобы наполнить смыслом уже имеющееся положение ENHANCED.

Наш «ванильный» билд уже не чистая ваниль. Часть ванильных багов у нас пофикшена по ходу портирования. Значит:

  • нельзя считать текущее поведение эталоном ванили — оно смешанное;
  • при разделении режимов придётся пройтись по уже сделанным фиксам и решить по каждому, остаётся он в VANILLA или уезжает в ENHANCED;
  • и наоборот: отдельные исправления (например, падение сквозь стену) вполне могут быть сделаны прямо в нынешнем «ванильном» билде, если сочтём, что играбельность важнее буквальности.

Что предстоит решить

  1. Что считать ванилью на практике. Составить список уже сделанных отступлений от оригинала и распределить их между режимами.
  2. Цена рантайм-проверки. Условия попадают в физику и play_seq, то есть в горячий путь. Если переключать в рантайме, проверка должна быть дешевле самого фикса: флаг в резиденте, а не вызов через банк.
  3. Что считать умолчанием. Оригинальное поведение честнее для порта, но часть фиксов SDLPoP включает по умолчанию.
  4. Как тестировать оба режима. Host-тесты гоняются одним прогоном; для двух режимов нужен либо параметр сборки тестов, либо ожидания, зависящие от флага.

Инвентаризация: что уже решено по каждому фиксу SDLPoP

Составлено 2026-08-31 обходом кода. В движке эти решения УЖЕ приняты и задокументированы прямо в комментариях — таблица лишь сводит их в одно место, чтобы при разделении режимов не перечитывать исходники.

фикс SDLPoP где у нас что взято
fix_feather_fall_affects_guards pop_map.c:941 ФИКС — перо действует только на Кида
fix_exit_door pop_map.c:1212 ФИКС — ветка фикса вместо ванильного глобала
FIX_GATE_SOUNDS pop_trob.c:579 ФИКС — условия через ИЛИ
fix_sound_priorities pop_sfx.c:196 ФИКС — в SDLPoP включён безусловно, сравниваемся с исправленным
FIX_STAND_ON_THIN_AIR pop_map.c:1499 ВАНИЛЬ — взяты 2 части из 3, третья ждёт патча seqtbl
fix_painless_fall_on_guard pop_map.c:1611 ВАНИЛЬ — намеренно
fix_jumping_over_guard pop_map.c:1612 ВАНИЛЬ — намеренно
FIX_RETREAT_WITHOUT_LEAVING_ROOM pop_map.c:3036 ВАНИЛЬ — в SDLPoP выключен по умолчанию; трюк 35 сохраняем
fix_skeleton_chomper_blood pop_map.c:3177 ВАНИЛЬ — кровь скелета в ванили есть
потеря HP скелетом при падении с двух этажей pop_map.c:676 ВАНИЛЬ — баг оригинала, сохраняем сознательно

Фиксы, которым нужна правка байткода

FIX_STAND_ON_THIN_AIR не взят НЕ потому, что мы выбрали ваниль, а потому что его нельзя применить наполовину: он состоит из трёх частей, и третья — правка самого байткода seqtbl (смещения в последовательности вставания). Взяв только первые две, мы получим вставание, уносящее весовую точку в стену, то есть ХУЖЕ ванили.

Это выполнимо, и раньше здесь стояла неверная оценка (уточнено 2026-08-31): байткод можно менять и у нас. Способов три:

  1. Патч в рантайме — после загрузки kid.ani в EMM-страницу пропатчить нужные байты прямо там. Речь о единицах байт, страница уже наша, и патч обратим — то есть режим переключается без пересборки ресурсов. Это и делает фикс пригодным для VANILLA/ENHANCED.
  2. Патч в упаковщике — готовить два варианта kid.ani. Привязывает режим к файлам на диске, поэтому хуже: переключатель в меню перестаёт быть чисто кодовым.
  3. Две копии в одной странице — и это, пожалуй, лучший вариант (решено 2026-08-31). kid.ani целиком около 4 КБ, а страница EMM — 16 КБ, то есть обе версии байткода спокойно помещаются рядом в уже выделенной странице. Переключение режима сводится к смене базового смещения, патчить ничего не нужно, откат мгновенный.

Для сравнения: у SDLPoP рабочая таблица и неизменная копия оригинала существуют раздельно (seqtbl и original_seqtbl), причём вторая нужна для сверки — то есть сама идея «оригинальный байткод отдельно, рабочий отдельно» там уже заложена.

Общее правило для BUGFIXED: фиксы, требующие правки seqtbl, доступны через рантайм-патч страницы; закладывать это стоит сразу, чтобы не упереться при первом же таком фиксе.

Вывод для разделения режимов

Четыре фикса уже взяты, шесть позиций оставлены ванильными. Значит нынешний билд — это не VANILLA, а «ваниль плюс четыре исправления». При разделении:

  • взятые четыре надо либо оставить в обоих режимах (если считаем их безусловными улучшениями), либо увести в ENHANCED и вернуть ванильное поведение в VANILLA — второе честнее, но потребует обратной работы;
  • ванильные шесть — кандидаты в ENHANCED; FIX_STAND_ON_THIN_AIR тоже, но ему дополнительно нужен рантайм-патч байткода.

ВСЕ исправления SDLPoP и их статус у нас

Полный перечень опциональных исправлений оригинала, какие есть в SDLPoP (43 позиции), со статусом в нашем порте. Названия — идентификаторы опций SDLPoP, описание — своими словами.

Статусы: ВЗЯТ — портирован; ВАНИЛЬ — сознательно не берём, держим поведение оригинала; НЕТ — не реализован, кандидат в ENHANCED; НЕДОСТУПЕН — требует правки байткода seqtbl (см. ограничение выше); В РАБОТЕ — решено делать сейчас.

Стены и препятствия

опция что чинит статус
fix_glide_through_wall проход сквозь стену при падении после разворота в беге ВЗЯТ 2026-08-31 — glide_through_wall_guard() в pop_map.c, точка отвязки для VANILLA
fix_jump_through_wall_above_gate прыжок в тайл над воротами НЕТ
fix_drop_through_tapestry проваливание сквозь гобелен НЕТ
fix_running_jump_through_tapestry прыжок с разбега сквозь гобелен НЕТ
fix_turn_running_near_wall разворот в беге вплотную к стене НЕТ
fix_wall_bump_triggers_tile_below удар о стену срабатывает на тайл ниже НЕТ
fix_bigpillar_climb подъём на большую колонну НЕТ
fix_land_against_gate_or_tapestry приземление вплотную к воротам или гобелену НЕТ
fix_caped_prince_sliding_through_gate проскальзывание сквозь ворота НЕТ

Падение, прыжки, зацепы

опция что чинит статус
fix_stand_on_thin_air стояние на воздухе после отмены падения НЕТ — нужен рантайм-патч seqtbl (см. выше)
fix_jump_distance_at_edge дальность прыжка у самой кромки НЕТ
fix_edge_distance_check_when_climbing проверка расстояния до кромки при подъёме НЕТ
fix_grab_falling_speed зацеп на слишком большой скорости падения НЕТ
fix_drop_2_rooms_climbing_loose_tile провал через две комнаты при подъёме на шаткой плите НЕТ
fix_infinite_down_bug бесконечное падение вниз НЕТ
fix_falling_through_floor_during_sword_strike провал сквозь пол во время удара мечом НЕТ
fix_safe_landing_on_spikes безопасное приземление на невыдвинутые пики НЕТ
fix_dead_floating_in_air мёртвый зависает в воздухе НЕТ

Бой и стражи

опция что чинит статус
fix_painless_fall_on_guard падение на стража с высоты без урона ВАНИЛЬ
fix_jumping_over_guard перепрыгивание через стража ВАНИЛЬ
fix_skeleton_chomper_blood кровь скелета в челюстях ВАНИЛЬ
fix_push_guard_into_wall вталкивание стража в стену НЕТ
fix_guard_following_through_closed_gates страж идёт сквозь закрытые ворота НЕТ
fix_doortop_disabling_guard верх двери отключает стража НЕТ
fix_offscreen_guards_disappearing стражи пропадают за краем экрана НЕТ
fix_unintended_sword_strike непреднамеренный удар мечом НЕТ
fix_two_coll_bug двойная проверка столкновения НЕТ
fix_move_after_sheathe движение сразу после убирания меча НЕТ

Ворота, двери, плиты

опция что чинит статус
fix_exit_door дверь выхода с уровня ВЗЯТ
fix_gate_sounds звуки ворот ВЗЯТ
fix_gate_drawing_bug отрисовка ворот НЕТ
fix_press_through_closed_gates нажатие плиты сквозь закрытые ворота НЕТ
fix_chompers_not_starting челюсти не заводятся НЕТ
fix_loose_left_of_potion шаткая плита слева от зелья НЕТ
fix_hidden_floors_during_flashing скрытые полы во время вспышки НЕТ
fix_retreat_without_leaving_room отступление без смены комнаты (трюк 35) ВАНИЛЬ

Зелья, перо, спецэффекты

опция что чинит статус
fix_feather_fall_affects_guards перо действует и на стражей ВЗЯТ
fix_feather_interrupted_by_leveldoor перо прерывается дверью уровня НЕТ
fix_move_after_drink движение сразу после питья НЕТ
fix_quicksave_during_feather быстрое сохранение под пером НЕТ
fix_hang_on_teleport зависание при телепорте НЕТ (телепортов у нас нет)

Интерфейс и ввод

опция что чинит статус
fix_one_hp_stops_blinking индикатор перестаёт мигать на одном HP НЕТ
fix_register_quick_input учёт быстрого ввода НЕТ

Отдельно: приоритеты звуков

fix_sound_priorities в SDLPoP включён БЕЗУСЛОВНО (не опция), и мы сравниваемся с исправленным вариантом — pop_sfx.c:196. Статус: ВЗЯТ, вернуть ванильное поведение отдельным режимом было бы дополнительной работой.

Сводка

статус сколько
ВЗЯТ 5
ВАНИЛЬ (сознательно) 4
требует патча seqtbl (выполнимо) 1
НЕТ (кандидаты в ENHANCED) 32

Список кандидатов на BUGFIXED

Пополняется по мере аудита. Пока:

  • три опциональных фикса SDLPoP выше;
  • находка 24 (перезагрузка кадра в in_wall);
  • находка 21 из аудита — общая рамка «мы намеренно повторяем ваниль».

Не относятся сюда находки, где мы расходимся с оригиналом НЕ в его пользу (ранги А и Б аудита): их надо чинить в обоих режимах, потому что это не баги оригинала, а наши.