Зацеп за кромку нижнего ряда: 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>
This commit is contained in:
@@ -797,17 +797,27 @@ static void do_fall(void)
|
||||
if (nrow > 4) nrow = 4; /* защита pop_y_land[] от выхода */
|
||||
if ((uint16_t)pop_y_land[nrow] > (uint16_t)Char.y) {
|
||||
check_grab(); /* ещё летит — попытка зацепа */
|
||||
} else {
|
||||
} else if (Char.curr_row <= 2) {
|
||||
if (get_tile_at_char() == TILE_WALL)
|
||||
in_wall();
|
||||
if (tile_is_floor(g_curr_tile))
|
||||
land();
|
||||
else if (Char.curr_row < 2)
|
||||
inc_curr_row(); /* следующий ряд ВНУТРИ комнаты */
|
||||
/* curr_row==2, нет пола: продолжает падать (fall_speed двигает y);
|
||||
* пересечение нижней границы комнаты ловит check_leave_below (y>=211,
|
||||
* порт leave_room) — общий путь для провала И спуска-зацепа. */
|
||||
else
|
||||
inc_curr_row(); /* следующий ряд, ВКЛЮЧАЯ 2 -> 3 */
|
||||
/* Ряд 3 — «за нижней кромкой комнаты» (в оригинале get_tile уходит по
|
||||
* links.down и это ряд 0 комнаты снизу, seg006:005D). Нам он нужен
|
||||
* ровно за тем, за чем нужен оригиналу: пока Kid летит вдоль ряда 3,
|
||||
* check_grab пробует зацеп за тайл ряда 2 СВОЕЙ комнаты — иначе
|
||||
* спуск «повис на кромке, отпустил, зацепился этажом ниже» через
|
||||
* нижнюю границу комнаты невозможен в принципе (BUG-GRAB-SEAM-DOWN).
|
||||
* Раньше ряд залипал на 2, check_grab не звался ни разу, и Kid
|
||||
* пролетал мимо кромки, набирая fall_y > 32 — после чего окно
|
||||
* зацепа закрыто уже по скорости. */
|
||||
}
|
||||
/* curr_row == 3: тайлов своей комнаты там нет (get_tile отдаёт WALL как
|
||||
* сентинел), поэтому ни in_wall, ни land здесь звать нельзя — до y_land[4]
|
||||
* дело всё равно не доходит: check_leave_below переводит в комнату снизу
|
||||
* на y >= 211 (порт leave_room). */
|
||||
}
|
||||
|
||||
static void fall_accel(void)
|
||||
@@ -1310,7 +1320,13 @@ static void check_action(void)
|
||||
} else if (action == ACT_FREEFALL) {
|
||||
do_fall();
|
||||
} else if (action == ACT_MIDAIR) {
|
||||
/* frames 102..105: check_grab — K4 */
|
||||
/* Кадры 102..105 — НАЧАЛО падения (seg006:0619). Здесь fall_y ещё
|
||||
* не разгоняется (fall_accel работает только в ACT_FREEFALL), то есть
|
||||
* это САМОЕ ШИРОКОЕ окно зацепа: ветка стояла заглушкой, и первые
|
||||
* четыре кадра падения зацеп не работал вовсе — отсюда «иногда
|
||||
* цепляется, иногда нет» на входе в уровень 7. */
|
||||
if (frame >= 102 && frame < 106)
|
||||
check_grab();
|
||||
} else if (action != ACT_HANGCLIMB) {
|
||||
check_on_floor();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user