From ea57a035430c74acedd68947b4851bd0150b7db8 Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Fri, 17 Jul 2026 21:07:20 +0300 Subject: [PATCH] =?UTF-8?q?applications/PoP/roomtest:=20K4=20=E2=80=94=20?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B5=D0=BF/=D0=B2=D0=B8=D1=81/=D0=BF=D0=BE?= =?UTF-8?q?=D0=B4=D1=82=D1=8F=D0=B3=D0=B8=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5/?= =?UTF-8?q?=D1=81=D0=BF=D1=83=D1=81=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Порт SDLPoP seg004/005/006 «hang state»: - pop_map: check_grab (зацеп за уступ в падении по Shift → seq_15 → вис), can_grab/can_grab_front_above + tile-запросы над/за персонажем; pop_jump_up_seq (check_jump_up: ↑ в стойке = чистый прыжок seq_28/14 ЛИБО прыжок-с-зацепом seq_8/24/16 за уступ выше → запрыгнуть на этаж); pop_hang_* (climb_up seq_10/73, hang_fall seq_23/11, hang-у-стены); pop_down_action (спуск seq_68 у края лицом от края / отступ / присед). - pop_ctrl: control_hanging/can_climb_up/hang_fall, control_jumpup, jump_up через pop_jump_up_seq, down_pressed через pop_down_action; pop_ctrl_shift_held() для check_grab. Ключевой фикс check_bumped (seg004 guard'ы): не бампить при action hang_climb/hang_straight, на кадрах подъёма/спуска 135..148 И на кадрах виса 87..99. Без последнего спуск (seq_68) на кадре frame_91 (action ещё midair, act(hang_climb) идёт следующим опкодом) ловил отскок у стены и рвал цепочку hang→hang_fall→seq_11, приземляя не туда. Проверено в MAME (HDD-тест, покадровая трасса через мост): прыжок-с- зацепом [row2 col4]→вис→подтягивание→[row1 col3]; спуск [row1 col3]→ [row2 col4] с корректной позицией у стены (x=122, совпадает с SDLPoP). Co-Authored-By: Claude Opus 4.8 --- applications/PoP/roomtest/pop_ctrl.c | 64 +++++-- applications/PoP/roomtest/pop_ctrl.h | 4 + applications/PoP/roomtest/pop_map.c | 245 ++++++++++++++++++++++++++- applications/PoP/roomtest/pop_map.h | 16 +- 4 files changed, 307 insertions(+), 22 deletions(-) diff --git a/applications/PoP/roomtest/pop_ctrl.c b/applications/PoP/roomtest/pop_ctrl.c index 5a6d2a1..05baddc 100644 --- a/applications/PoP/roomtest/pop_ctrl.c +++ b/applications/PoP/roomtest/pop_ctrl.c @@ -50,6 +50,7 @@ #define SEQ_44_STEP_ON_EDGE 44 #define SEQ_14_JUMP_INTO_CEILING 14 /* прыжок вверх: сверху стена/пол */ #define SEQ_28_JUMP_NOTHING_ABOVE 28 /* прыжок вверх: сверху пусто */ +#define SEQ_25_HANG_AGAINST_WALL 25 /* вис у стены (Shift в висе) */ #define FRAME_7_RUN 7 #define FRAME_11_RUN 11 @@ -131,20 +132,19 @@ static void back_pressed(void) static void down_pressed(void) { control_down = CONTROL_IGNORE; /* без авто-повтора */ - /* climb-down у края (seq_68) — K4 (зацеп/спуск); пока просто присед. */ - crouch(); + /* У края пола (край сзади) со зацепом снизу — спуск на этаж (seq_68); + * у передней кромки — отступ; иначе присед. Решает pop_down_action. */ + if (!pop_down_action()) + crouch(); } -/* Вертикальный прыжок вверх (seg005 jump_up, упрощённо): сверху сплошное - * (стена/пол) → seq_14 (в потолок), иначе seq_28 (пусто сверху). Зацеп за - * уступ сверху-впереди (can_grab) — K4.2, пока чистый вертикальный прыжок. */ +/* Прыжок вверх в стойке (seg005 check_jump_up): чистый вертикальный прыжок + * ЛИБО прыжок-с-зацепом за уступ выше (запрыгнуть на этаж вверх). Выбор seq + * + выравнивание Kid.x — в pop_jump_up_seq (pop_map). */ static void jump_up(void) { control_up = release_arrows(); - if (pop_above_solid()) - seqtbl_offset_char(SEQ_14_JUMP_INTO_CEILING); - else - seqtbl_offset_char(SEQ_28_JUMP_NOTHING_ABOVE); + seqtbl_offset_char(pop_jump_up_seq()); } static void up_pressed(void) @@ -250,6 +250,43 @@ static void control_running(void) } } +/* ---- Вис (seg005 control_hanging/can_climb_up/hang_fall) ---------- * + * Тайловые решения (можно ли подтянуться, куда сорваться) — в pop_map; + * здесь управление осями control_*. */ +static void hang_fall(void) +{ + control_down = release_arrows(); + seqtbl_offset_char(pop_hang_fall_seq()); /* seq_23/seq_11 (+ выравнивание x) */ +} + +static void can_climb_up(void) +{ + control_up = control_shift2 = release_arrows(); + seqtbl_offset_char(pop_hang_climb_up_seq()); /* seq_10 / seq_73 */ +} + +static void control_hanging(void) +{ + if (control_y == CONTROL_HELD && pop_hang_grab_ready()) { + can_climb_up(); /* ↑ — подтянуться */ + } else if (control_shift == CONTROL_HELD) { + int8_t w = pop_hang_wall(); + if (w > 0) seqtbl_offset_char(SEQ_25_HANG_AGAINST_WALL); /* у стены */ + else if (w < 0) hang_fall(); /* сорваться */ + /* w==0: сверху пол — держимся (ничего) */ + } else { + hang_fall(); /* отпустил Shift — сорваться */ + } +} + +/* control_jumpup (seg005): в старте прыжка вверх ←/→ или forward → перевести + * в прыжок с места. */ +static void control_jumpup(void) +{ + if (control_x == CONTROL_HELD_FORWARD || control_forward == CONTROL_HELD) + standing_jump(); +} + /* control() — диспетчер по кадру (seg005.c:252), Kid жив, без меча. */ static void control(void) { @@ -261,11 +298,11 @@ static void control(void) else if (f < 4) control_startrun(); else if (f >= FRAME_67_JUMPUP1 && f < FRAME_70_JUMPHANG) - ; /* control_jumpup — K4 */ + control_jumpup(); else if (f < FRAME_15_STAND) control_running(); else if (f >= FRAME_87_HANG1 && f < 100) - ; /* control_hanging — K4 */ + control_hanging(); else if (f == FRAME_109_CROUCH) control_crouched(); } @@ -358,6 +395,11 @@ void pop_ctrl_close(void) kbd_raw_close(); } +int8_t pop_ctrl_shift_held(void) +{ + return (int8_t)(control_shift == CONTROL_HELD); +} + void pop_ctrl_tick(void) { rest_ctrl_1(); diff --git a/applications/PoP/roomtest/pop_ctrl.h b/applications/PoP/roomtest/pop_ctrl.h index 727cfc8..f3a41a2 100644 --- a/applications/PoP/roomtest/pop_ctrl.h +++ b/applications/PoP/roomtest/pop_ctrl.h @@ -28,4 +28,8 @@ void pop_ctrl_close(void); * kid_tick() (play_seq продолжит с новой последовательности). */ void pop_ctrl_tick(void); +/* control_shift зажат ПРЯМО СЕЙЧАС? — для check_grab в физике (pop_map): + * зацеп за уступ в падении по Shift. Валидно после pop_ctrl_tick. */ +int8_t pop_ctrl_shift_held(void); + #endif diff --git a/applications/PoP/roomtest/pop_map.c b/applications/PoP/roomtest/pop_map.c index 54bf482..50bc22f 100644 --- a/applications/PoP/roomtest/pop_map.c +++ b/applications/PoP/roomtest/pop_map.c @@ -18,9 +18,15 @@ #include #include "pop_kid.h" #include "pop_map.h" +#include "pop_ctrl.h" /* pop_ctrl_shift_held() — для check_grab */ /* ---- Тайлы / действия / seq id (подмножество PoP) ------------------ */ #define TILE_EMPTY 0 +#define TILE_GATE 4 +#define TILE_DOORTOP_FLOOR 7 /* tapestry (пол сверху) */ +#define TILE_DOORTOP 12 /* tapestry top */ +#define TILE_MIRROR 13 +#define TILE_CHOMPER 18 #define TILE_WALL 20 #define ACT_STAND 0 #define ACT_RUNJUMP 1 @@ -37,6 +43,18 @@ #define SEQ_20_MEDIUM_LAND 20 #define SEQ_21_FALL_RUNJUMP 21 #define SEQ_47_BUMP 47 /* удар в стену: dx(-4) отскок + 50-52 + stand */ +/* K4 — зацеп/вис/подтягивание/спуск */ +#define SEQ_8_GRAB_STRAIGHT 8 /* прыжок вверх и зацеп (прямо) */ +#define SEQ_14_JUMP_INTO_CEILING 14 /* прыжок вверх: сверху стена/пол */ +#define SEQ_16_JUMP_UP_AND_GRAB 16 /* прыжок вверх и зацеп (нет пола сзади)*/ +#define SEQ_24_GRAB_FORWARD 24 /* прыжок вверх и зацеп (пол сзади) */ +#define SEQ_28_JUMP_NOTHING_ABOVE 28 /* прыжок вверх: сверху пусто */ +#define SEQ_10_CLIMB_UP 10 /* подтягивание из виса */ +#define SEQ_11_RELEASE_LEDGE_LAND 11 /* сорваться и встать (конец спуска) */ +#define SEQ_15_GRAB_LEDGE_MIDAIR 15 /* зацеп за уступ в падении */ +#define SEQ_23_RELEASE_LEDGE_FALL 23 /* отпустить уступ и падать */ +#define SEQ_68_CLIMB_DOWN 68 /* спуск через зацеп (не приседание) */ +#define SEQ_73_CLIMB_UP_TO_GATE 73 /* подъём к закрытой калитке */ #define FRAME_NEEDS_FLOOR 0x40 #define FRAME_WEIGHT_X 0x1F @@ -52,6 +70,7 @@ static const int16_t y_land[5] = {-8, 55, 118, 181, 244}; static const int8_t dir_front[2] = {-1, 1}; /* [dir+1]: dir=-1->-1, 0->+1 */ +static const int8_t dir_behind[2] = {1, -1}; /* [dir+1]: назад по направлению */ static const int16_t x_bump[20] = { -12, 2, 16, 30, 44, 58, 72, 86, 100, 114, 128, 142, 156, 170, 184, 198, 212, 226, 240, 254 @@ -66,6 +85,7 @@ uint8_t pop_fell_out; /* 1 = Kid упал за низ комнаты static const uint8_t *g_fg; /* fg[30], row*10+col */ static uint8_t g_curr_tile; /* = curr_tile2: тайл последнего get_tile */ static uint8_t g_obj_xl; /* позиция внутри тайла (get_tile_div_mod) */ +static uint8_t grab_timer; /* после зацепа (12): блокирует climb-up */ void pop_map_set(const uint8_t *fg) { g_fg = fg; } @@ -100,6 +120,30 @@ static uint8_t get_tile_infrontof_char(void) return get_tile(g_infrontx, Kid.curr_row); } +/* ---- Тайлы НАД/ЗА персонажем (для зацепа/спуска, seg006) ----------- */ +static uint8_t get_tile_above_char(void) +{ + return get_tile(Kid.curr_col, (int8_t)(Kid.curr_row - 1)); +} + +static uint8_t get_tile_behind_char(void) +{ + return get_tile((int8_t)(dir_behind[Kid.direction + 1] + Kid.curr_col), + Kid.curr_row); +} + +static uint8_t get_tile_front_above_char(void) +{ + g_infrontx = (int8_t)(dir_front[Kid.direction + 1] + Kid.curr_col); + return get_tile(g_infrontx, (int8_t)(Kid.curr_row - 1)); +} + +static uint8_t get_tile_behind_above_char(void) +{ + return get_tile((int8_t)(dir_behind[Kid.direction + 1] + Kid.curr_col), + (int8_t)(Kid.curr_row - 1)); +} + static uint8_t wall_type(uint8_t t) { switch (t) { @@ -233,12 +277,59 @@ static void start_fall(void) in_wall(); } +/* ---- Зацеп (seg006 can_grab/check_grab) --------------------------- * + * can_grab: можно ли зацепиться за g_curr_tile (curr_tile2) СКВОЗЬ through- + * тайл? Kid-only (без loose/opener-модификаторов). */ +static uint8_t can_grab(uint8_t through) +{ + if (through == TILE_WALL) return 0; /* сквозь стену нельзя */ + if (through == TILE_DOORTOP && Kid.direction >= 0) return 0; /* верх двери, лицом вправо */ + if (tile_is_floor(through)) return 0; /* сквозь пол нельзя */ + if (g_curr_tile == TILE_DOORTOP_FLOOR && Kid.direction < 0) return 0; + if (!tile_is_floor(g_curr_tile)) return 0; /* не за что цепляться */ + return 1; +} + +static uint8_t can_grab_front_above(void) +{ + uint8_t through = get_tile_above_char(); + get_tile_front_above_char(); /* g_curr_tile = спереди-сверху */ + return can_grab(through); +} + +/* check_grab (seg006:0A28): в падении при зажатом Shift — зацепиться за + * уступ спереди-сверху (seq_15), если скорость падения ещё мала и высота + * подходящая. Выравнивает передний край по кромке, гасит fall_y, взводит + * grab_timer (блок climb-up на несколько кадров). */ +static void check_grab(void) +{ + uint8_t old_x; + if (!pop_ctrl_shift_held()) return; /* Shift не зажат */ + if ((uint8_t)Kid.fall_y >= 32) return; /* падает слишком быстро */ + if ((uint16_t)y_land[Kid.curr_row + 1] > (uint16_t)(Kid.y + 25)) return; + old_x = Kid.x; + Kid.x = (uint8_t)char_dx_forward(-8); + determine_col(); + if (!can_grab_front_above()) { + Kid.x = old_x; /* не за что — назад */ + determine_col(); + } else { + Kid.x = (uint8_t)char_dx_forward((int8_t)distance_to_edge_weight()); + Kid.y = (uint8_t)y_land[Kid.curr_row + 1]; + Kid.fall_y = 0; + kid_set_seq(SEQ_15_GRAB_LEDGE_MIDAIR); + play_seq(); + determine_col(); + grab_timer = 12; /* (TODO: sound grab) */ + } +} + static void do_fall(void) { uint8_t nrow = (uint8_t)(Kid.curr_row + 1); if (nrow > 4) nrow = 4; /* защита y_land[] от выхода */ if ((uint16_t)y_land[nrow] > (uint16_t)Kid.y) { - /* ещё летит (check_grab — K4) */ + check_grab(); /* ещё летит — попытка зацепа */ } else { if (get_tile_at_char() == TILE_WALL) in_wall(); @@ -306,13 +397,68 @@ int pop_edge_distance(void) uint8_t pop_edge_type(void) { return g_edge_type; } -/* Тайл НАД персонажем (curr_row-1, curr_col) сплошной (стена/пол)? — выбор - * seq прыжка вверх: solid -> seq_14 (в потолок), иначе seq_28 (пусто сверху). - * K4.1 упрощение: без grab-логики (уступ сверху-впереди) — та в K4.2. */ -uint8_t pop_above_solid(void) +/* ---- Прыжок вверх с зацепом (seg005 check_jump_up и производные) --- * + * pop_jump_up_seq выбирает seq для ↑ в стойке: чистый прыжок (seq_28 в + * пустоту / seq_14 в потолок) ЛИБО прыжок-и-зацеп за уступ выше (seq_8/ + * 24 — с полом сзади, seq_16 — без), и выравнивает Kid.x. control_up + * гасит caller (pop_ctrl). Порт: check_jump_up/grab_up_with_floor_behind/ + * jump_up_or_grab/grab_up_no_floor_behind/jump_up (без super-high-jump). */ +static uint8_t grab_up_with_floor_behind(void) { - uint8_t t = get_tile(Kid.curr_col, (int8_t)(Kid.curr_row - 1)); - return (t == TILE_WALL || tile_is_floor(t)); + int distance = distance_to_edge_weight(); + int edge_distance = pop_edge_distance(); /* побочно ставит g_edge_type */ + if (distance < 4 && edge_distance < 4 && g_edge_type != EDGE_WALL) { + Kid.x = (uint8_t)char_dx_forward((int8_t)distance); + return SEQ_8_GRAB_STRAIGHT; + } + Kid.x = (uint8_t)char_dx_forward((int8_t)(distance - 4)); + return SEQ_24_GRAB_FORWARD; +} + +static uint8_t jump_up_plain(void) /* seg005 jump_up (без super) */ +{ + int distance = pop_edge_distance(); /* ставит g_edge_type */ + int8_t col; + uint8_t t; + if (distance < 4 && g_edge_type == EDGE_WALL) + Kid.x = (uint8_t)char_dx_forward((int8_t)(distance - 3)); + col = get_tile_div_mod(dx_weight() - 6); + t = get_tile(col, (int8_t)(Kid.curr_row - 1)); + if (t != TILE_WALL && !tile_is_floor(t)) + return SEQ_28_JUMP_NOTHING_ABOVE; + return SEQ_14_JUMP_INTO_CEILING; +} + +static uint8_t grab_up_no_floor_behind(void) +{ + get_tile_above_char(); + Kid.x = (uint8_t)char_dx_forward((int8_t)(distance_to_edge_weight() - 10)); + return SEQ_16_JUMP_UP_AND_GRAB; +} + +static uint8_t jump_up_or_grab(void) +{ + int distance = distance_to_edge_weight(); + if (distance < 6) + return jump_up_plain(); + if (!tile_is_floor(get_tile_behind_char())) + return grab_up_no_floor_behind(); + Kid.x = (uint8_t)char_dx_forward((int8_t)(distance - TILE_SIZEX)); + determine_col(); /* load_fram_det_col */ + return grab_up_with_floor_behind(); +} + +uint8_t pop_jump_up_seq(void) +{ + uint8_t through = get_tile_above_char(); + get_tile_front_above_char(); /* g_curr_tile = спереди-сверху */ + if (can_grab(through)) + return grab_up_with_floor_behind(); + through = get_tile_behind_above_char(); + get_tile_above_char(); /* g_curr_tile = сверху */ + if (can_grab(through)) + return jump_up_or_grab(); + return jump_up_plain(); } /* Стена впереди достаточно близко для стопа бега? Детект (без сдвига — @@ -323,6 +469,78 @@ int pop_wall_ahead(void) return (g_edge_type == EDGE_WALL && d <= 2); } +/* ---- Вис (control_hanging из seg005) — тайловые решения ------------ * + * Управление держится в pop_ctrl (control_*), сюда вынесены только + * тайловые предикаты + выбор seq (+ выравнивание Kid.x). */ + +/* grab_timer истёк — можно подтягиваться? */ +uint8_t pop_hang_grab_ready(void) { return grab_timer == 0; } + +/* can_climb_up: тайл над персонажем — обычный подъём (seq_10) либо подъём + * к закрытой калитке/зеркалу/чомперу (seq_73). */ +uint8_t pop_hang_climb_up_seq(void) +{ + uint8_t t = get_tile_above_char(); + if (((t == TILE_MIRROR || t == TILE_CHOMPER) && Kid.direction == 0) || + (t == TILE_GATE && Kid.direction != 0)) + return SEQ_73_CLIMB_UP_TO_GATE; + return SEQ_10_CLIMB_UP; +} + +/* Shift в висе: 1 = висит у стены/двери (caller играет seq_25); -1 = + * сорваться (hang_fall); 0 = сверху пол, остаётся висеть (ничего). */ +int8_t pop_hang_wall(void) +{ + uint8_t t = get_tile_at_char(); + if (Kid.action != ACT_HANGSTRAIGHT && + (t == TILE_WALL || + (Kid.direction < 0 && (t == TILE_DOORTOP_FLOOR || t == TILE_DOORTOP)))) + return 1; + if (!tile_is_floor(get_tile_above_char())) + return -1; + return 0; +} + +/* hang_fall (seg005:0A46): сорваться. Нет пола ни сзади, ни под + * персонажем — seq_23 (отпустить и падать); иначе прижать к стене (-7) + * и seq_11 (встать, конец спуска). Меняет Kid.x, возвращает seq. */ +uint8_t pop_hang_fall_seq(void) +{ + uint8_t behind = get_tile_behind_char(); + uint8_t at; + if (!tile_is_floor(behind) && !tile_is_floor(get_tile_at_char())) + return SEQ_23_RELEASE_LEDGE_FALL; + at = get_tile_at_char(); + if (at == TILE_WALL || + (Kid.direction < 0 && (at == TILE_DOORTOP_FLOOR || at == TILE_DOORTOP))) + Kid.x = (uint8_t)char_dx_forward(-7); + return SEQ_11_RELEASE_LEDGE_LAND; +} + +/* down_pressed (seg005:04C7) tile-часть: 1 = обработано (НЕ приседать — + * либо спуск seq_68 через зацеп, либо отступ от передней кромки), 0 = + * приседать. Меняет Kid.x. Kid развёрнут от края (край сзади) у кромки + * пола + под соседним тайлом есть за что зацепиться → спуск на этаж вниз. */ +uint8_t pop_down_action(void) +{ + if (!tile_is_floor(get_tile_infrontof_char()) && distance_to_edge_weight() < 3) { + Kid.x = (uint8_t)char_dx_forward(5); /* у передней кромки — отступ */ + determine_col(); + return 1; + } + if (!tile_is_floor(get_tile_behind_char()) && distance_to_edge_weight() >= 8) { + uint8_t through = get_tile_behind_char(); + get_tile_at_char(); /* g_curr_tile = под персонажем */ + if (can_grab(through) && + (Kid.direction >= 0 || get_tile_at_char() != TILE_GATE)) { + Kid.x = (uint8_t)char_dx_forward((int8_t)(distance_to_edge_weight() - 9)); + kid_set_seq(SEQ_68_CLIMB_DOWN); + return 1; + } + } + return 0; +} + /* ---- Диспетчер ----------------------------------------------------- */ static void check_on_floor(void) { @@ -357,7 +575,17 @@ static void check_action(void) static void check_bumped(void) { uint8_t t; int8_t tcol; int d; - if (Kid.action == ACT_FREEFALL || Kid.action == ACT_HANGCLIMB) return; + /* Не бампим в падении/висе/подтягивании (seg004 check_bumped guard'ы: + * action hang_climb/hang_straight + кадры подъёма 135..148 — иначе + * climb-up у стены прерывается отскоком). FREEFALL — наш guard: стену + * в падении держит do_fall/in_wall. */ + if (Kid.action == ACT_FREEFALL || Kid.action == ACT_HANGCLIMB || + Kid.action == ACT_HANGSTRAIGHT) return; + if (Kid.frame >= 135 && Kid.frame < 149) return; /* кадры подъёма/спуска */ + /* Кадры виса 87..99: в спуске (seq_68) кадр frame_91 идёт ДО act(hang_climb), + * т.е. action ещё midair — без этого guard'а bump у стены рвёт цепочку + * hang->hang_fall->seq_11 (правильное приземление). */ + if (Kid.frame >= 87 && Kid.frame < 100) return; t = get_tile_at_char(); tcol = Kid.curr_col; if (!wall_type(t)) { t = get_tile_infrontof_char(); tcol = g_infrontx; } if (!wall_type(t)) return; @@ -374,6 +602,7 @@ static void check_bumped(void) void pop_phys_tick(void) { + if (grab_timer) grab_timer--; fall_accel(); fall_speed(); determine_col(); diff --git a/applications/PoP/roomtest/pop_map.h b/applications/PoP/roomtest/pop_map.h index bf804b2..7cc239a 100644 --- a/applications/PoP/roomtest/pop_map.h +++ b/applications/PoP/roomtest/pop_map.h @@ -41,8 +41,18 @@ uint8_t pop_edge_type(void); * control_running (чистый стоп у стены). */ int pop_wall_ahead(void); -/* Тайл над персонажем сплошной (стена/пол)? — выбор seq вертикального - * прыжка вверх (K4.1). */ -uint8_t pop_above_solid(void); +/* Прыжок вверх в стойке (↑): seq чистого прыжка (seq_28/seq_14) ЛИБО + * прыжка-с-зацепом за уступ выше (seq_8/24/16) + выравнивание Kid.x. + * check_jump_up/grab_up (K4.4). control_up гасит caller. */ +uint8_t pop_jump_up_seq(void); + +/* ---- Вис/зацеп/спуск (K4.2/K4.3) — тайловые решения для pop_ctrl --- * + * Управление (control_hanging/can_climb_up/hang_fall/down_pressed) в + * pop_ctrl; здесь — предикаты + выбор seq (+ выравнивание Kid.x). */ +uint8_t pop_hang_grab_ready(void); /* grab_timer истёк — можно climb-up */ +uint8_t pop_hang_climb_up_seq(void); /* seq_10 / seq_73 (подтягивание) */ +int8_t pop_hang_wall(void); /* Shift в висе: 1=у стены,-1=fall,0=держ.*/ +uint8_t pop_hang_fall_seq(void); /* seq_23 / seq_11 (сорваться), +Kid.x */ +uint8_t pop_down_action(void); /* 1=обработано(спуск/отступ), 0=присед */ #endif