BUG-CTRL-FRAME-1: геометрия Кида считалась по кадру стража

cur_frame — один глобал на всех персонажей (как в оригинале), владелец —
тот, кто последним прошёл load_frame.  Последним в кадре тикает страж,
поэтому к моменту control() Кида там лежал кадр СТРАЖА, а через
kid_cur_dx/dy/flags по нему считается вся геометрия управления:
dx_weight -> determine_col -> distance_to_edge_weight -> get_edge_distance
-> выбор ветки в check_jump_up.

Оригинал зовёт load_fram_det_col() (seg006:0144) сразу после
loadkid/loadshad и ДО control() — play_kid_frame (seg000:1211) и
play_guard_frame (seg000:1248).  У нас этого не было.

Замерено брейкпоинтом на pop_jump_up_seq: Kid x=156 col=6 кадр 15
(dx=0 weight_x=3) при кадре стража image17 (dx=-1 weight_x=8) дал
curr_col=7 и distance=2 вместо 6 и 10 — то есть jump_up_plain (вернулось
A=28, пустой прыжок) вместо «шаг назад на x=160 + зацеп».  Предсказание
по кадру стража совпало с намеренным до единицы.

Отсюда же плавающее поведение: кадр стража меняется каждый тик, distance
Кида скакал через порог 6 — то прыжок, то попытка зацепа с неверной X.
И «голова Кида поверх плиты (1,6)» — не баг отрисовки, а следствие позы,
которой в оригинале в этом месте не бывает.

Фикс: pop_load_fram_det_col() (pop_kid.c) + вызовы в pop_ctrl_tick и
pop_guard_tick.  determine_col — только на ветке Кида: у нас он
существует лишь для него (pop_map работает с Kid, а не с Char).

Разбор с числами — bug_closed.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Александр Петров
2026-08-04 12:55:43 +03:00
parent 5353bdaaec
commit e67117219f
7 changed files with 227 additions and 3 deletions
+34
View File
@@ -450,6 +450,40 @@ void play_seq(void)
}
}
/* load_fram_det_col (seg006:0144) = load_frame() + determine_col().
*
* Зачем это отдельной публичной точкой. cur_frame — ОДИН глобал на всех
* персонажей (так и в оригинале), и его владелец — тот, кто последним
* прошёл load_frame. В кадре последним тикает страж, поэтому к моменту
* управления Кидом в cur_frame лежит кадр СТРАЖА. А через cur_frame
* считается вся геометрия: dx_weight -> determine_col ->
* distance_to_edge_weight -> get_edge_distance, то есть буквально выбор
* ветки в check_jump_up.
*
* Оригинал от этого страхуется явно: play_kid_frame (seg000:1209) и
* play_guard_frame (seg000:1246) сразу после loadkid/loadshad зовут
* load_fram_det_col() — ДО control(). У нас этого не было, и Кид считал
* свой прыжок по кадру стража (BUG-CTRL-FRAME-1): при distance 2 вместо 10
* check_jump_up уходил в «пустой прыжок вверх» вместо «шаг назад и
* зацеп». Результат менялся от кадра к кадру — вместе с анимацией стража.
*
* determine_col у нас существует только для Кида: pop_map работает с Kid
* напрямую, а не с абстрактным Char. Поэтому вторую половину связки делаем
* только на его ветке — стражу пока хватает перезагрузки самого кадра (его
* колонку ведёт pop_guard_enter/leave). Char.curr_col синхронизируем
* руками: окно Char — копия Kid. */
void pop_load_fram_det_col(void)
{
if (!kdat_ok) return;
gfx_w0_map(kdat_page);
load_frame();
gfx_w0_unmap();
if (Char.charid == CHARID_0_KID) {
pop_determine_col();
Char.curr_col = Kid.curr_col;
}
}
/* Прокрутить последовательность КОНКРЕТНОГО персонажа (порт связки
* loadkid/play_seq/savekid, seg006). Звать вместо голого play_seq: тот
* работает с Char и сам по себе не знает, чей это персонаж. */