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:
@@ -19,6 +19,7 @@
|
||||
#include "pop_geom.h" /* pop_y_to_row, TILE_SIZEX — тайл объекта */
|
||||
#include "pop_guard.h"
|
||||
#include "pop_cheat.h"
|
||||
#include "pop_tune.h"
|
||||
|
||||
__sfr __at (0xFE) io_border;
|
||||
|
||||
@@ -60,7 +61,7 @@ __sfr __at (0xFE) io_border;
|
||||
* останется нулём, и трамплин прыгнет по 0xC000 в мусор (см. шапку
|
||||
* runtime/bank.s). Проверено 2026-08-05: с n_banks=4 и пятым банком игра
|
||||
* доходила до конца загрузки ресурсов и вставала намертво в DSS. */
|
||||
const uint8_t n_banks = 5;
|
||||
const uint8_t n_banks = 6;
|
||||
|
||||
/* Режим читов (pop_cheat.h): на время разработки включаем в main. */
|
||||
uint8_t pop_cheats;
|
||||
@@ -369,6 +370,12 @@ static void find_start_level_door(uint8_t room)
|
||||
}
|
||||
}
|
||||
|
||||
/* checkpoint (seg000:270): взводится, когда Кид уходит ВЛЕВО в комнату 7
|
||||
* уровня 3 (level3_set_chkp, seg002:0665); по нему do_startpos подменяет
|
||||
* стартовую позицию. Сбрасывается началом игры и прохождением уровня —
|
||||
* ровно как в оригинале (seg003:37 и seg003:413). */
|
||||
static uint8_t pop_checkpoint;
|
||||
|
||||
static void pop_start_level(void)
|
||||
{
|
||||
uint8_t entry_pose = pop_level_entry_pose(pop_current_level);
|
||||
@@ -376,6 +383,16 @@ static void pop_start_level(void)
|
||||
uint8_t pos = pop_level_start_pos();
|
||||
int8_t dir = (int8_t)~pop_level_start_dir();
|
||||
uint8_t seq = SEQ_TURN;
|
||||
/* Особое событие: старт с чекпойнта (do_startpos, seg003:0141).
|
||||
* Числа — в pop_tune.h. Плиту снимаем ПОСЛЕ pop_level_reset_tiles()
|
||||
* ниже, иначе рестарт её вернёт. */
|
||||
uint8_t chkp = (uint8_t)(pop_current_level == POP_CHKP_LEVEL && pop_checkpoint);
|
||||
if (chkp) {
|
||||
start_room = POP_CHKP_RESPAWN_ROOM;
|
||||
pos = POP_CHKP_RESPAWN_TILEPOS;
|
||||
dir = (int8_t)~POP_CHKP_RESPAWN_DIR; /* стартует в ПРОТИВОположную
|
||||
* и разворачивается seq_5 */
|
||||
}
|
||||
|
||||
/* Рестарт уровня = load_level() заново (play_level, seg003:57): в
|
||||
* исходное возвращаются И модификаторы (пики/ворота), И сами тайлы —
|
||||
@@ -386,6 +403,12 @@ static void pop_start_level(void)
|
||||
pop_level_reset_guards();
|
||||
pop_guard_reset(); /* start_level: Guard.direction = none */
|
||||
pop_loose_mob_reset(); /* start_level: mobs_count = 0 (seg003:88) */
|
||||
/* «Особое событие: убрать loose-плиту» (do_startpos): без этого путь в
|
||||
* комнату-чекпойнт после респавна остался бы непройденным. */
|
||||
if (chkp)
|
||||
pop_level_set_tile(POP_CHKP_CLEAR_ROOM,
|
||||
(uint8_t)(POP_CHKP_CLEAR_ROW * 10 + POP_CHKP_CLEAR_COL),
|
||||
TILE_EMPTY);
|
||||
|
||||
/* Кнопку жмём ДО отрисовки комнаты — как в оригинале (do_startpos
|
||||
* отрабатывает раньше первого draw_room), иначе шов кадр показывал бы
|
||||
@@ -450,6 +473,7 @@ int main(void)
|
||||
}
|
||||
pop_next_level = pop_current_level; /* current_level = next_level (load_lev_spr) */
|
||||
pop_kid_hp_newgame(); /* init_game: hitp_beg_lev = start_hitp */
|
||||
pop_checkpoint = 0; /* init_game (seg003:37) */
|
||||
|
||||
initgraph();
|
||||
gfx_set_visible_page(0);
|
||||
@@ -618,7 +642,25 @@ int main(void)
|
||||
}
|
||||
} else if (pop_leave_dir) { /* L3: уход вбок/вверх (координаты уже репроецированы) */
|
||||
uint8_t nb = pop_room_link(cur_room, (uint8_t)(pop_leave_dir - 1));
|
||||
uint8_t left = (uint8_t)(pop_leave_dir == 1);
|
||||
pop_leave_dir = 0;
|
||||
/* level3_set_chkp (seg002:0665). ВНИМАНИЕ на комнату: оригинал
|
||||
* зовёт его из leave_room ДО goto_other_room, то есть Char.room
|
||||
* там ещё СТАРАЯ. Значит условие `Char.room == 7` читается как
|
||||
* «Кид УХОДИТ ИЗ комнаты 7 влево» (в комнату 2), а не «входит в
|
||||
* неё». Смысл: чекпойнт даётся за то, что комната 7 пройдена
|
||||
* НАСКВОЗЬ, и респавн ставится туда, куда Кид только что попал.
|
||||
*
|
||||
* Сначала я поставил проверку на комнату НАЗНАЧЕНИЯ — и это
|
||||
* поймал пользователь прогоном в SDLPoP: он умер В комнате 7, но
|
||||
* влево из неё не выходил, и оригинал вернул его в стартовую
|
||||
* комнату 9, а плита осталась цела. Заодно тут запоминается
|
||||
* достигнутый потолок HP: смерть после чекпойнта его не отбирает. */
|
||||
if (left && pop_current_level == POP_CHKP_LEVEL &&
|
||||
cur_room == POP_CHKP_ROOM) {
|
||||
pop_checkpoint = 1;
|
||||
hitp_beg_lev = hitp_max;
|
||||
}
|
||||
if (nb) {
|
||||
enter_room(nb);
|
||||
gfx_set_draw_page(back);
|
||||
@@ -659,6 +701,7 @@ int main(void)
|
||||
* поднятая на уровне «жизнь» (большая склянка) переезжает
|
||||
* дальше, а урон — нет (do_startpos дольёт до потолка). */
|
||||
hitp_beg_lev = hitp_max;
|
||||
pop_checkpoint = 0; /* уровень пройден (seg003:413) */
|
||||
if (pop_level_load_num(pop_next_level) != 0) {
|
||||
pop_next_level = pop_current_level; /* файла нет — остаёмся */
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user