Files
Sprinter-SDCC/applications/PoP/roomtest/pop_map.h
T
snark13 79ea473910 PoP roomtest: страж замечает Кида и достаёт меч (ИИ, шаг 1)
Первый самостоятельный кусок ИИ стража (план, пункт 2).  В оригинале у
соперника нет своего диспетчера: autocontrol_* (seg002) выставляет те же
глобалы control_*, что и ввод игрока, а дальше исполняется общий control().
Инфраструктура под это встала прошлым коммитом, здесь — сама логика.

Порт:
- check_can_guard_see_kid (seg003:688) — луч видимости по ряду: стены и
  верхи дверей рвут его совсем, loose/чомпер/дыра/неподнятые ворота дают
  «вижу, но не пойду».  В guards.c (банк 1);
- Opp + loadshad_and_opp (seg006:841) и char_opp_dist (seg006:2135);
- autocontrol_guard_inactive (seg002:710) + move_* (seg002:0706..);
- ветки control(): control_guard_inactive (seg006:2123) и draw_sword
  (seg005:945) — соперник уходит сразу в seq_90 en garde;
- pop_guard_tick перестроен по play_guard_frame (seg000:1246): окно
  Char/Opp вокруг ИИ, диспетчера и play_seq.

По дороге:
- Kid.alive не выставлялся (= 0 = «мёртв» в семантике оригинала), из-за
  чего луч видимости не мог сработать в принципе — ставим -1 в kid_init;
- Kid.room не выставлялась вовсе; условие Kid.room == Guard.room всегда
  было ложным.  Ставим в enter_room (полная модель Kid.room != drawn_room
  у шва по-прежнему впереди);
- pop_tile_at — тайл текущей комнаты наружу из pop_map (луч видимости);
- control_x/y/shift открыты в шину: ИИ заполняет оси как есть, без
  flip_control_x (его «вперёд» уже в системе персонажа).

Проверено в MAME (комната 3, страж на tile 17): страж переходит из
стойки 166 в 171 stand_with_sword, sword=2, can_guard_see_kid=2; ввод
игрока не пострадал.  Клинок отдельным спрайтом пока не рисуется —
sword.atl содержит только кадры 229..237 (подъём меча Кидом), остальные
строки sword_tbl приедут с боёвкой.

Бюджет (225 кадров, комната 3): 384 168 – 384 636 тактов, 0.893–0.895
кадра, запас 45 364.  Прошлый замер 382 584 – 383 064 — шаг стоил ~1 570.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 11:09:12 +03:00

151 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* pop_map.h — коллизия Kid с картой комнаты (Фаза K3): тайловые запросы
* + физика падения + приземление. Порт SDLPoP seg005/seg006
* (check_on_floor/start_fall/do_fall/fall_accel/fall_speed/land/in_wall).
*
* K3.2 (падение): Kid, сойдя/сбежав с края пола (тайл под ним не floor),
* начинает падать (fall_y-ускорение, Char.y растёт), приземляется на пол
* ниже (soft/medium land) или продолжает вниз. Стена под персонажем —
* in_wall (выталкивание). Бег В стену (check_bumped) — отдельным шагом.
*/
#ifndef POP_MAP_H
#define POP_MAP_H
#include <stdint.h>
/* Задать карту текущей комнаты: fg[30] = коды тайлов (row*10+col, 3×10).
* col<0/>9 или row<0/>2 трактуются как стена (край уровня). Массив
* МУТАБЕЛЬНЫЙ (loose-пол при падении → empty) — передавать ту же копию,
* что и в pop_room_draw, чтобы отрисовка видела изменения. */
void pop_map_set(uint8_t *fg) __banked;
/* Связи комнаты (0=нет соседа; иначе номер) + кромки швов для коллизии:
* lcol_fg[6] = col9 левого соседа (за col0) в [0..2] и его col8 (колонка −2)
* в [3..5]; rcol_fg[6] симметрично (col0 / col1 = колонки 10 и 11). Вторая
* колонка нужна, когда Kid стоит В шве и смотрит наружу. Звать в enter_room. */
void pop_map_set_edges(uint8_t left, uint8_t right, uint8_t up, uint8_t down,
const uint8_t *lcol_fg, const uint8_t *rcol_fg) __banked;
/* Номер ТЕКУЩЕЙ комнаты (для доступа к room_modif пик/ворот в pop_trob).
* Звать в enter_room. */
void pop_map_set_room(uint8_t room) __banked;
/* Тайл-код текущей комнаты по клетке (col 0..9, row 0..2) — порт
* get_tile(room,col,row) для текущей комнаты. Нужен лучу видимости стража
* (guards.c): он идёт по ряду между Кидом и стражем. */
uint8_t pop_tile_at(int8_t col, int8_t row) __banked;
/* HP/смерть. pop_kid_dead=1 когда Kid убит (пики); hitp_curr — текущее HP.
* pop_kid_hp_reset() ставит старт HP и снимает смерть (звать в kid_init/
* респавн). */
extern uint8_t pop_kid_dead;
extern uint8_t hitp_curr;
void pop_kid_hp_reset(void) __banked;
/* Предметы (seg005 check_get_item/get_item, seg006 do_pickup/proc_get_object).
* pop_have_sword — «меч у Кида» (порт have_sword). pop_item_taken — 0 или
* tilepos+1 только что поднятого предмета: вызывающий обязан запечь тайл
* (он стал полом) на ОБЕИХ страницах и записать override комнаты. */
extern uint8_t pop_have_sword;
extern uint8_t pop_item_taken;
/* Вспышка фона (do_flash/set_bg_attr, seg001:0908): счётчик кадров, пока
* НУЛЕВАЯ запись палитры подменена ярко-жёлтым. Тикает вызывающий. */
extern uint8_t pop_flash_time;
uint8_t pop_get_item_action(void) __banked; /* 0 нет / 1 присесть / 2 поднять меч */
void pop_proc_get_object(void) __banked; /* эффект — из play_seq (опкод GET_ITEM) */
/* Уход из комнаты ВБОК/ВВЕРХ: 0=нет; 1=left,2=right,3=up (= side+1 для
* pop_room_link). Координаты Kid уже репроецированы (x∓140 / y+189).
* Приложение переключает комнату по соответствующей связи и снимает флаг. */
extern uint8_t pop_leave_dir;
/* exit_room_timer (порт seg002 exit_room): пока >0, боковой/нижний leave
* заблокирован (декремент в pop_phys_tick). Приложение ставит =2 при входе
* в комнату (enter_room) — 2 кадра защиты от повторного/транзиентного leave
* (ping-pong у шва, транзиент отскока о ворота, баг #4/BUG-2). */
extern uint8_t pop_leave_timer;
/* Loose floors (проваливающиеся полы). pop_loose_modif[30] — состояние на
* тайл (0 покой / 0x80.. тряска / 1..11 отсчёт падения); читает pop_bg при
* отрисовке. pop_loose_tick() — анимация + перерисовка изменившихся тайлов
* на ТЕКУЩЕЙ странице; звать в основном цикле ПОСЛЕ set_draw_page(back),
* рядом с kid-отрисовкой. */
extern uint8_t pop_loose_modif[30];
void pop_loose_tick(void) __banked;
void pop_loose_reset(void) __banked; /* сброс loose-состояния при смене комнаты */
/* Установлен в tilepos+1 в кадре, когда loose-пол упал (кусок улетел ВНИЗ).
* Приложение: определить debris-приземление в комнате снизу. Снять (=0). */
extern uint8_t pop_loose_fell;
/* Плита-ПОТОЛОК: loose ряда 2 комнаты СВЕРХУ (в оригинале — тот же loose с
* отрицательным tilepos, seg006 check_press frame 79 / seg007 animate_loose).
* pop_map_set_above даёт МУТАБЕЛЬНУЮ копию ряда 2 верхнего соседа (ту же, что
* ушла в pop_room_set_above): провалившаяся плита становится в ней EMPTY —
* сверху открывается колодец. pop_ceil_modif[col] — состояние (как
* pop_loose_modif), читает pop_bg. Сигналы приложению (для персистентности
* между входами в комнату): pop_ceil_fell = col+1 провалившейся плиты,
* pop_debris_at = tilepos+1 щебня, оставшегося в ЭТОЙ комнате. Снимать (=0). */
void pop_map_set_above(uint8_t *above_row2_fg) __banked;
extern uint8_t pop_ceil_modif[10];
extern uint8_t pop_ceil_fell;
extern uint8_t pop_debris_at;
/* Взводится в кадре, когда Kid получил урон (hitp_delta<0 оригинала) —
* приложение рисует «брызги» kid_draw_splash() поверх Kid и снимает флаг. */
extern uint8_t pop_kid_hurt;
/* check_knock (seg003): по флагу knock (play_seq) тряхнуть loose-полы ряда
* приземления/удара. Зовётся из pop_phys_tick. */
void pop_check_knock(void) __banked;
/* Установлен в 1, когда Kid пересёк НИЖНЮЮ границу комнаты (провал в дыру
* или спуск-зацеп с кромки). Координаты Kid УЖЕ репроецированы в кадр
* комнаты снизу (y -= 189, curr_row = 0). Приложение решает: если есть
* links.down — сменить комнату (pop_room_load+перерисовка) и продолжить;
* иначе — выпал из уровня (респавн). Снять флаг после обработки. */
extern uint8_t pop_fell_out;
/* Пер-кадровая физика ПОСЛЕ kid_tick(play_seq): fall_accel + fall_speed +
* determine_col + check_action (триггер падения / do_fall / приземление).
* Порядок как в оригинале (seg000 play_kid_frame). */
void pop_phys_tick(void) __banked;
/* clip_char (seg006:1749), верхняя граница клипа спрайта персонажа: если тайл
* над головой — стена/пол, всё выше линии своей полосы не рисуется (Kid,
* ушедший головой под пол при спуске/висе, не просвечивает сквозь щели).
* obj_x — ЛОГИЧЕСКАЯ X кадра (до ×8/7), obj_y — низ спрайта, w/h — размер.
* Возврат: КОМНАТНЫЙ y границы, 0 = клипа нет. Зовёт kid_draw. */
int pop_clip_char_top(int obj_x, int obj_y, uint16_t w, uint16_t h) __banked;
/* Тип препятствия/края ВПЕРЕДИ по направлению (pop_edge_type после
* pop_edge_distance): для control (бежать / осторожный шаг / стоп у стены). */
#define EDGE_CLOSER 0 /* край уступа над ямой (дистанция = до кромки) */
#define EDGE_WALL 1 /* стена впереди/под персонажем */
#define EDGE_FLOOR 2 /* пол (нет препятствия рядом, дистанция = 11) */
/* Расстояние до края/стены впереди + побочно g_edge_type (pop_edge_type). */
int pop_edge_distance(void) __banked;
uint8_t pop_edge_type(void) __banked;
/* Стена впереди в пределах стопа? Если да — прижимает Kid.x к корректной
* позиции (передний край у стены, симметрично) и возвращает 1. Для
* control_running (чистый стоп у стены). */
int pop_wall_ahead(void) __banked;
/* Прыжок вверх в стойке (↑): 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) __banked;
/* ---- Вис/зацеп/спуск (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) __banked; /* grab_timer истёк — можно climb-up */
uint8_t pop_hang_climb_up_seq(void) __banked; /* seq_10 / seq_73 (подтягивание) */
int8_t pop_hang_wall(void) __banked; /* Shift в висе: 1=у стены,-1=fall,0=держ.*/
uint8_t pop_hang_fall_seq(void) __banked; /* seq_23 / seq_11 (сорваться), +Kid.x */
uint8_t pop_down_action(void) __banked; /* 1=обработано(спуск/отступ), 0=присед */
#endif