L3-CHKP, зацеп в прыжке опцией, pop_tune.h; сборка 10 мин -> 1:48
L3-CHKP (чекпойнт уровня 3). Флаг взводится, когда Кид уходит ВЛЕВО ИЗ комнаты 7, а do_startpos по нему подменяет старт на комнату 2, тайл (0,6), лицом влево и снимает loose-плиту (7,0,4). Тонкость, на которой я сначала ошибся: level3_set_chkp (seg002:0665) вызван из leave_room ДО goto_other_room, поэтому `Char.room == 7` — это комната, ИЗ которой уходят, а не в которую входят. Поймал пользователь прогоном в SDLPoP: смерть В комнате 7 вернула его в стартовую 9, а плита осталась цела. Проверено в MAME: вход в 7 флаг не ставит, уход влево — ставит; респавн в комнате 2; после обычной смерти (без чекпойнта) плиты восстанавливаются как раньше. Зацеп ПРЯМО В ПРЫЖКЕ (check_grab_run_jump, seg006:1228) — портирован за выключателем POP_ENABLE_JUMP_GRAB. Это НЕ ваниль: в оригинале зацепиться можно только в начале падения (кадры 102..105), то есть Shift приходится жать уже в полёте; у SDLPoP это enable_jump_grab, и работает он лишь при включённых fixes-and-enhancements. Три точки вызова как у оригинала: check_action и обе ветки check_bumped (зацеп за верх стены вместо удара). pop_tune.h — настраиваемые константы в одном месте (аналог custom_options_type SDLPoP): чекпойнт, выключатель зацепа и отладочная крутилка POP_DBG_GATE_HOLD (сколько кадров решётка держится поднятой; оригинал 5, потолок 30 — таймер связи пятибитный, 31 = «заклинено»). Задача TUNE-1 в TASKS.md: читать это из ini рядом с exe. СБОРКА. --max-allocs-per-node снижен со 100000 (дефолт sprinter-cc) до 3000 (дефолт SDCC) через `make ALLOCS=...`, а pop_trob.c уехал в БАНК 6 — на 3000 резидент иначе не влезает (замер: конец _HOME 0xBC69 при стеке с 0xBB00). Итог: сборка с нуля 1:48 вместо >10 минут, куча 2751 Б вместо 2298. Релизная сборка — make ALLOCS=100000; сравнивать занятость банков можно только при одинаковом ALLOCS. Отдельно (вне git, SDLPoP в .gitignore): из референса вычищена вся наша отладка DBG-GRAB — трасса JMP, GRAB try/probe/fail/OK/skip, автоскриншоты seg003, печати DBG mob/mid/overlay/kidobj и счётчик dbg_shots. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,7 @@
|
||||
#include "pop_trob.h" /* room_modif + trob-список (пики/ворота) */
|
||||
#include "pop_level.h" /* pop_level_start_room — вход в дверь уровня */
|
||||
#include "pop_guard.h" /* SWORD_2_DRAWN — ветка приземления с мечом */
|
||||
#include "pop_tune.h" /* POP_ENABLE_JUMP_GRAB и прочие настройки */
|
||||
|
||||
/* ---- Тайлы / действия / seq id (подмножество PoP) ------------------ */
|
||||
#define TILE_EMPTY 0
|
||||
@@ -69,6 +70,7 @@
|
||||
#define SEQ_47_BUMP 47 /* удар в стену: dx(-4) отскок + 50-52 + stand */
|
||||
/* K4 — зацеп/вис/подтягивание/спуск */
|
||||
#define SEQ_8_GRAB_STRAIGHT 8 /* прыжок вверх и зацеп (прямо) */
|
||||
#define SEQ_9_GRAB_WHILE_JUMPING 9 /* зацеп ПРЯМО В ПРЫЖКЕ (улучшение SDLPoP) */
|
||||
#define SEQ_14_JUMP_INTO_CEILING 14 /* прыжок вверх: сверху стена/пол */
|
||||
#define SEQ_16_JUMP_UP_AND_GRAB 16 /* прыжок вверх и зацеп (нет пола сзади)*/
|
||||
#define SEQ_24_GRAB_FORWARD 24 /* прыжок вверх и зацеп (пол сзади) */
|
||||
@@ -628,6 +630,70 @@ static void check_grab(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void make_loose_fall(int pos, uint8_t modifier);
|
||||
|
||||
/* check_grab_run_jump — ЗАЦЕП ПРЯМО В ПРЫЖКЕ, при Shift, зажатом ЗАРАНЕЕ.
|
||||
*
|
||||
* ВАЖНО: в оригинальной игре этого НЕТ. Это улучшение SDLPoP
|
||||
* (`USE_JUMP_GRAB` + `fixes->enable_jump_grab`, seg006:1228), и там оно
|
||||
* выключено, пока не включены fixes-and-enhancements. Ванильное поведение:
|
||||
* зацепиться можно только в НАЧАЛЕ ПАДЕНИЯ (check_grab, кадры 102..105) —
|
||||
* то есть Shift надо успеть нажать уже в полёте. Пользователь ловил ровно
|
||||
* это и просил «чтобы работало и при заранее зажатом Shift», поэтому
|
||||
* улучшение портировано, но за выключателем POP_ENABLE_JUMP_GRAB
|
||||
* (pop_tune.h): игровая сборка сможет вернуться к оригиналу.
|
||||
*
|
||||
* Условия оригинала: действие — прыжок, кадр 22..23 (прыжок с места) или
|
||||
* 39..41 (разбег-прыжок), «вперёд» ОТПУЩЕНО, «вверх» зажато. Дальше — та
|
||||
* же проба, что у check_grab, но персонаж не падает, а сразу ставится на
|
||||
* кромку и играет seq_9.
|
||||
*
|
||||
* Упрощение против SDLPoP: там колонка захвата правится, когда тайл
|
||||
* оказался в ЧУЖОЙ комнате (curr_room != Char.room) — у нас модель
|
||||
* однокомнатная, get_tile сам резолвит колонки за швом в координатах
|
||||
* ТЕКУЩЕЙ комнаты, поэтому правка не нужна. Зато кнопка/плита за швом
|
||||
* (grab_col вне 0..9) не сработают — тайл принадлежит соседу, а
|
||||
* pop_trob_modif/g_fg у нас про свою комнату; такие случаи пропускаем. */
|
||||
static uint8_t check_grab_run_jump(void)
|
||||
{
|
||||
uint8_t frame = Kid.frame;
|
||||
uint8_t grab_tile;
|
||||
int8_t grab_col, grab_row;
|
||||
|
||||
/* Сам выключатель проверяют ТОЧКИ ВЫЗОВА (иначе SDCC ругается на
|
||||
* недостижимый код при POP_ENABLE_JUMP_GRAB = 1). */
|
||||
if (Kid.action != ACT_RUNJUMP) return 0;
|
||||
if (!((frame >= 22 && frame <= 23) || (frame >= 39 && frame <= 41))) return 0;
|
||||
if (control_x != POP_CONTROL_RELEASED || control_y != POP_CONTROL_HELD_UP) return 0;
|
||||
if (!can_grab_front_above()) return 0;
|
||||
|
||||
grab_tile = g_curr_tile; /* тайл, за который взялись */
|
||||
grab_col = g_infrontx;
|
||||
grab_row = (int8_t)(Kid.curr_row - 1); /* СНЯТЬ до play_seq: он двигает ряд */
|
||||
|
||||
Kid.x = (uint8_t)(pop_x_bump[grab_col + FIRST_ONSCREEN_COLUMN] + TILE_MIDX);
|
||||
Kid.x = (uint8_t)char_dx_forward(Kid.direction < 0 ? -12 : 2);
|
||||
Kid.y = (uint8_t)pop_y_land[Kid.curr_row + 1];
|
||||
kid_set_seq(SEQ_9_GRAB_WHILE_JUMPING);
|
||||
pop_kid_play();
|
||||
determine_col();
|
||||
grab_timer = 12;
|
||||
|
||||
/* Хвост оригинала: за что схватились — то и сработает. Нужен потому,
|
||||
* что check_press на следующем кадре уже не поможет: кадр сменится на
|
||||
* 81 (hangdrop), если Shift отпустят сразу. */
|
||||
if (grab_col >= 0 && grab_col <= 9 && grab_row >= 0 && grab_row <= 2) {
|
||||
uint8_t tp = (uint8_t)(grab_row * 10 + grab_col);
|
||||
if (grab_tile == TILE_OPENER || grab_tile == TILE_CLOSER)
|
||||
pop_trigger_button(g_room, tp, grab_tile, pop_trob_modif(g_room)[tp]);
|
||||
else if (grab_tile == TILE_LOOSE) {
|
||||
is_guard_notice = 1;
|
||||
make_loose_fall(tp, 1);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void do_fall(void)
|
||||
{
|
||||
uint8_t nrow = (uint8_t)(Kid.curr_row + 1);
|
||||
@@ -1093,6 +1159,11 @@ static void check_on_floor(void)
|
||||
static void check_action(void)
|
||||
{
|
||||
uint8_t action = Kid.action, frame = Kid.frame;
|
||||
/* Зацеп прямо в прыжке (улучшение SDLPoP, seg006:0914) — ДО всего
|
||||
* остального: если получилось, кадр уже сменён на вис. */
|
||||
if (POP_ENABLE_JUMP_GRAB && action == ACT_RUNJUMP &&
|
||||
pop_ctrl_shift_held() && check_grab_run_jump())
|
||||
return;
|
||||
if (action == ACT_BUMPED || action == ACT_HANGSTRAIGHT) {
|
||||
/* ТОЛЬКО кадр 109 (присед) — как в ванильном seg006:909. Кадры
|
||||
* вставания 110..119 сюда добавляет ОПЦИОНАЛЬНЫЙ FIX_STAND_ON_THIN_AIR,
|
||||
@@ -1378,6 +1449,13 @@ static void check_bumped_look_right(void)
|
||||
int coll_left;
|
||||
if (Kid.direction != 0) return; /* (меча в руке у нас нет) */
|
||||
if (!is_obstacle_at_col(col)) return;
|
||||
/* Прежде чем удариться о стену — попытка зацепиться за её верх
|
||||
* (seg004:0205, то же улучшение). Не вышло — тайл препятствия надо
|
||||
* перечитать: проба зацепа сбила g_curr_tile. */
|
||||
if (POP_ENABLE_JUMP_GRAB && pop_ctrl_shift_held()) {
|
||||
if (check_grab_run_jump()) return;
|
||||
if (!is_obstacle_at_col(col)) return;
|
||||
}
|
||||
wt = wall_type(g_curr_tile);
|
||||
if (!wt) return;
|
||||
coll_left = pop_x_bump[col + FIRST_ONSCREEN_COLUMN] + TILE_MIDX;
|
||||
@@ -1393,6 +1471,10 @@ static void check_bumped_look_left(void)
|
||||
int coll_left;
|
||||
if (Kid.direction >= 0) return;
|
||||
if (!is_obstacle_at_col(col)) return;
|
||||
if (POP_ENABLE_JUMP_GRAB && pop_ctrl_shift_held()) { /* seg004:0186 */
|
||||
if (check_grab_run_jump()) return;
|
||||
if (!is_obstacle_at_col(col)) return;
|
||||
}
|
||||
wt = wall_type(g_curr_tile);
|
||||
if (!wt) return;
|
||||
coll_left = pop_x_bump[col + FIRST_ONSCREEN_COLUMN] + TILE_MIDX;
|
||||
|
||||
Reference in New Issue
Block a user