6673279cef
Скелет (L3-SKEL, ассеты + механика): - pop_pack_guard.py получил параметр набора (GUARD/SKEL): атлас скелета poc/res/skel/g0..g3.atl (28 кадров), палитра — из его res750.pal (на ур. 3 curr_guard_color = 0, оригинал палитру не подменяет); - pop_guard_load выбирает набор по tbl_guard_type и перезагружается ПРИ СМЕНЕ УРОВНЯ (load_lev_spr, seg000:1092) — без этого скелет рисовался атласом стража и был невидим; - load_frame: charid_4_skeleton идёт по таблице стража (seg006:529), тень — только в кадрах 150..189. Пока ветка была одна (charid_2_guard), скелет получал image из таблицы Кида (180 при 28 спрайтах) и не рисовался; - check_skel (seg002:1042), ветка charid_4 в enter_guard, возрождение в комнате 3 при падении (seg002:252), autocontrol_skeleton; - leveldoor_open (seg007:456) — новый флаг, сбрасывается стартом уровня. Цвета стражей (BUG-GUARD-COLOR-1, закрыт): - все 7 палитр res10.bin -> pop_guard_pal.h, заливка 16 слотов по guards_color комнаты перед отрисовкой (set_chtab_palette, seg003:257). Проверено в MAME: ур. 2 комн. 11 = цвет 1, комн. 7 = цвет 3, полоса HP меняется вместе со стражем. Грабля: gfx_pal_load отдаёт указатель в BIOS, а тот читает только #4000-#BFFF — таблицу из банка копируем в стек. Кэш соседних комнат (BUG-SWORD-GHOST-1, закрыт): - pop_map кэширует fg соседей слева/справа ЦЕЛИКОМ и резолвит col -10..19. Было -2..11, дальше мнимая стена: луч видимости упирался в неё (страж после follow_guard в col 12), Кид прятал меч посреди боя и не мог достать обратно. +48 байт W2. Окклюзия соперника: - pop_fore_over_char получил проход other_overlay_tile (порядок midtable, seg008:1B06) и расширение перебора объединённым прямоугольником «персонаж + клинок + брызги» — падающий скелет больше не рисуется поверх кладки и верхней грани пола; - клип полем 192 строк (reset_obj_clip, seg006:0507) для спрайта, клинка (общий pop_sword_draw) и брызг — спрайт не залезает на полосу HP; - ROOMNAV после смерти Кида делает честный pop_start_level: телепорт «оживлял» мёртвого мимо старта уровня, оставляя живого скелета рядом с вернувшейся кучей костей. Ассеты чомпера (под L3-CHOMP): весь набор кадров в атласе явным списком (101-105 низ, 111-113 верх, 106-110 фронт, 114-123 кровь mono-силуэтом) — render_room анимированные тайлы пропускает, и в атласе не было ни одного. Число EMM-страниц не изменилось. Тесты: tests-host все 5 наборов зелёные, t_char вырос до 65 проверок (резолв колонок за краем комнаты, возрождение скелета); в testkit добавлен гард «код наехал на данные» (DATA_LOC). Доски: TASKS.md разнесён на TASKS_OPEN/TASKS_CLOSED, закрытые баги с разбором корней — в bug_closed.md; заведены DRAW-CHAR (отрисовка одна на всех Char, как физика после GUARD-PHYS) и L3-COLOR (зелёная кладка уровня 3: level_var_palettes = ресурс 20, есть в MSDOS/PRINCE.DAT). В roomtest.c временно оставлен автостоп на падении соперника (отладка падений скелета) — помечен ВРЕМЕННО. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
176 lines
13 KiB
C
176 lines
13 KiB
C
/*
|
||
* pop_bg.h — отрисовка СТАТИЧЕСКОГО фона комнаты PoP композицией слоёв
|
||
* (порт seg008.c draw_tile/wall_pattern, Шаг 3). Рисует прямо в текущую
|
||
* страницу (banked GFX_BANK_TRANSPARENT — в видео-ОЗУ + теневую копию,
|
||
* 0xFF прозрачен), ОДИН раз при входе в комнату.
|
||
*
|
||
* Данные: getimage-спрайты в атласах pop_env0..4/pop_wall/pop_fore
|
||
* (toolchain/pop_pack_bg.py), палитра pop_bg.pal. Прямая адресация
|
||
* id: env[id>>5] idx id&31, wall idx=id, fore idx=id — ноль remap-таблиц.
|
||
*/
|
||
#ifndef POP_BG_H
|
||
#define POP_BG_H
|
||
|
||
#include <stdint.h>
|
||
|
||
/* ---- Вертикальный layout (PoP-экран 320×200 в нашем 320×256) --------- *
|
||
* Игровой экран 200px центрируем по высоте: сдвиг всего рисунка вниз на
|
||
* POP_YOFF = (256-200)/2 = 28px (чёрные борта сверху/снизу). Внутри 200px
|
||
* верхние POP_PLAYFIELD_H = 192 — поле тайлов/спрайтов (комната = 3 ряда),
|
||
* нижние 8 — статус-полоса (жизни/сообщения): тайлы/спрайты туда НЕ лезут.
|
||
* Сдвиг применяется на границе примитивов (blit/heal) — логика рисования
|
||
* остаётся в «room-space» y=0..191. */
|
||
#define POP_YOFF 28
|
||
#define POP_PLAYFIELD_H 192
|
||
/* Экранный y нижней границы поля (ниже — статус-полоса + борт → клип). */
|
||
#define POP_CLIP_BOTTOM (POP_YOFF + POP_PLAYFIELD_H)
|
||
|
||
/* Выбор ядра libbgi (pop_onscreen_cols / pop_heal_fast) переехал в
|
||
* `_pop_draw.h` — его включают только три рисующих модуля. Из общего
|
||
* заголовка SDCC размножал мёртвые копии этих inline'ов по всем TU: см.
|
||
* шапку `_pop_draw.h`. */
|
||
|
||
/* Загрузить 7 атласов фона. Звать ДО initgraph (как poc.c — atlas_load
|
||
* трогает W3; проверенный порядок). Палитру pop_bg.pal грузит ПРИЛОЖЕНИЕ
|
||
* после initgraph (gfx_pal_fload). 0 — OK, -1 — ошибка. */
|
||
int pop_bg_load(void) __banked;
|
||
|
||
/* Освободить EMM-страницы атласов. */
|
||
void pop_bg_free(void) __banked;
|
||
|
||
/* Нарисовать комнату: fg[30]/bg[30] — foretable-коды/backtable-модификаторы
|
||
* (по строкам, row*10+col). lcol_fg/lcol_bg — 3 тайла правого столбца
|
||
* ЛЕВОЙ соседней комнаты (для границы, напр. решётки ворот), или 0 —
|
||
* тогда левая кромка = стена. room_num — номер комнаты (зерно стен). */
|
||
void pop_room_draw(uint8_t room_num,
|
||
const uint8_t *fg, const uint8_t *bg,
|
||
const uint8_t *lcol_fg, const uint8_t *lcol_bg) __banked;
|
||
|
||
/* Задать ряд 0 комнаты СНИЗУ — для draw_tile_topright, когда тайл нижнего
|
||
* ряда стал empty (после падения loose): «стена вниз» рисуется по коду
|
||
* room_B(0, col-1). ОДИННАДЦАТЬ байт: [0..9] — колонки комнаты снизу,
|
||
* [10] — тайл (0,9) комнаты СНИЗУ-СЛЕВА (сосед угла (2,0); см.
|
||
* load_rowbelow, seg008:368). 0 — нет комнаты снизу. */
|
||
void pop_room_set_below(const uint8_t *below_row0_fg) __banked;
|
||
|
||
/* Задать ряд 2 (fg-коды + модификаторы, 10 шт.) комнаты СВЕРХУ — для полосы
|
||
* кладки у потолка (seg008 draw_room доп. верхний ряд из room_A). 0 — нет
|
||
* комнаты сверху (кромка уровня → пол). */
|
||
void pop_room_set_above(const uint8_t *above_row2_fg, const uint8_t *above_row2_mod) __banked;
|
||
|
||
/* Перерисовать передний слой (fore) тайлов футпринта Kid ПОВЕРХ него —
|
||
* звать ПОСЛЕ kid_draw. obj_x — ЛОГИЧЕСКАЯ X кадра (до ×8/7), obj_y — низ
|
||
* спрайта, w/h — размер кадра, dir — направление Kid (<0 влево). Метрики
|
||
* берутся из pop_kid (kid_fp_*). См. redraw_at_char/set_char_collision. */
|
||
void pop_fore_over_kid(int obj_x, int obj_y, uint16_t w, uint16_t h,
|
||
int8_t dir, uint8_t frame, uint8_t action) __banked;
|
||
|
||
/* Окно fore-слоя: прямоугольник СПРАЙТА (экранные координаты, y уже с
|
||
* POP_YOFF), поверх которого fore-проход возвращает куски тайлов. Ставит
|
||
* тот, кто нарисовал спрайт (kid_draw / pop_guard_draw) — он один знает
|
||
* итоговый габарит (у Kid — с учётом клинка и обрезки clip_char). Вне
|
||
* fore-проходов окно игнорируется: фон рисуется целиком. Мотивация и
|
||
* замер — в pop_bg.c у fclip_on. */
|
||
void pop_fore_set_clip(int x, int y, int w, int h) __banked;
|
||
|
||
/* То же для НЕ-Kid персонажа (страж): только слой fore + полоса потолка,
|
||
* без оверлеев поз виса/полёта/подъёма. obj_x — ЛОГИЧЕСКАЯ координата
|
||
* (до ×8/7), как у kid_fp_obj_x(). */
|
||
/* __banked: отрисовка стража уехала в СВОЙ банк (pop_gdraw.c), поэтому
|
||
* вызов стал кроссбанковым и обязан идти через трамплин. Зовётся раз в
|
||
* кадр, других вызывающих нет — цена одного трамплина здесь не видна. */
|
||
/* ex/ey/ew/eh — ОБЪЕДИНЁННЫЙ экранный прямоугольник «персонаж + клинок +
|
||
* брызги» (тот же, что уходит в pop_fore_set_clip): перебор передних тайлов
|
||
* идёт по нему, иначе меч и звёздочка удара остаются поверх кладки.
|
||
* ew == 0 — расширения нет (только габарит кадра). */
|
||
void pop_fore_over_char(int obj_x, int obj_y, uint16_t w, uint16_t h,
|
||
int8_t dir, uint8_t sword,
|
||
int ex, int ey, uint16_t ew, uint16_t eh,
|
||
uint8_t action, int8_t ccol, int8_t crow) __banked;
|
||
|
||
/* Восстановить фон там, где в прошлых кадрах рисовался ОВЕРЛЕЙ
|
||
* (draw_other_overlay/floor_overlay/полоса потолка): он выходит за
|
||
* прямоугольник Kid, поэтому kid_heal его не убирает — на второй странице
|
||
* дабл-буфера остаётся след и мерцает. Звать рядом с kid_heal. */
|
||
void pop_fore_heal(void) __banked;
|
||
|
||
/* Loose floors — динамическая отрисовка (состояние pop_loose_modif в
|
||
* pop_map). Звать на ТЕКУЩЕЙ (back) странице из pop_loose_tick.
|
||
* shake_draw — дрожащий кадр (heal+SPRITE); bake_empty — запечь пустоту
|
||
* после падения (NORMAL, в ОЗУ-копию). */
|
||
void pop_loose_shake_draw(int row, int col) __banked;
|
||
void pop_loose_bake_empty(int row, int col) __banked;
|
||
|
||
/* Плита-ПОТОЛОК (loose ряда 2 комнаты СВЕРХУ, наш ряд −1): дрожащий кадр в
|
||
* полосе у потолка / «запечь» пустоту (колодец наверх) после провала.
|
||
* Состояние — pop_ceil_modif[10] в pop_map. */
|
||
void pop_ceil_shake_draw(int col) __banked;
|
||
void pop_ceil_bake_empty(int col) __banked;
|
||
|
||
/* Кусок приземлился (loose_land) — переехал в pop_state.h: переменную
|
||
* читают по обе стороны банковой границы. */
|
||
#include "pop_state.h"
|
||
|
||
/* Пики (spike) — перерисовка тайла (row,col) на back-странице по живому
|
||
* modif (pop_trob). Звать из pop_process_trobs. См. pop_bg.c. */
|
||
void pop_spike_redraw(int row, int col) __banked;
|
||
|
||
/* Анимация факела/зелья (динамика каждый кадр; фон запечён без них):
|
||
* modif — живой room_modif тайла. Для факела col — колонка САМОГО факела
|
||
* (пламя рисуется в ячейке правого соседа). */
|
||
void pop_torch_draw(int row, int col, uint8_t modif) __banked;
|
||
void pop_potion_draw(int row, int col, uint8_t modif) __banked;
|
||
|
||
/* Ворота на ЛЕВОМ шве (col0) — перерисовать по живому modif соседа слева.
|
||
* g_lbg (lcol_bg) должен быть обновлён вызывающим. Звать из основного цикла
|
||
* на back-странице, когда сосед слева анимируется. См. pop_bg.c. */
|
||
void pop_room_redraw_seam_left(void) __banked;
|
||
|
||
/* Перерисовать ПОЛ тайла (row,col) + правую грань в соседе на back-странице
|
||
* (wipe по площади пола, БЕЗ стены ряда ниже). Для смены тайла на месте:
|
||
* кнопка нажата/отжата, floor → debris от упавшей плиты. */
|
||
void pop_floor_bake(int row, int col) __banked;
|
||
void pop_button_redraw(int row, int col) __banked; /* = pop_floor_bake (кнопка) */
|
||
|
||
/* Дверь уровня: перерисовать её ПРАВУЮ половину (row, col = правая) с
|
||
* запечкой — створка анимируется (pop_trob animate_leveldoor). */
|
||
void pop_leveldoor_redraw(int row, int col) __banked;
|
||
|
||
/* Ворота ВНУТРИ отрисованной комнаты: перерисовать по живому modif.
|
||
* (row,col) — координаты САМИХ ворот; бары рисует ячейка правого соседа
|
||
* (draw_tile, ветка lcode==4), туда и идёт wipe+redraw. Порт draw_trob
|
||
* (seg007:01E6), которым заканчивается animate_door. */
|
||
void pop_gate_redraw(int row, int col) __banked;
|
||
|
||
/* Падающий кусок loose (mob, seg007 move_loose): спавн при падении тайла
|
||
* (row,col) и покадровое продвижение+отрисовка на back-странице. tick
|
||
* зовётся каждый кадр (внутри pop_loose_tick); клип низа делает clip. */
|
||
void pop_loose_mob_spawn(int row, int col) __banked;
|
||
void pop_loose_mob_tick(void) __banked;
|
||
void pop_loose_mob_reset(void) __banked; /* убрать все куски (СТАРТ УРОВНЯ, mobs_count=0) */
|
||
|
||
/* Смена комнаты: куски продолжают падать в СВОИХ комнатах (do_mobs крутит
|
||
* mobs[] независимо от drawn_room), сбрасывается только heal-история. */
|
||
void pop_loose_mob_room_changed(void) __banked;
|
||
|
||
/* Кусок НИЖЕ Kid по obj_y → рисуется ПОВЕРХ него (порт sort_curr_objs,
|
||
* seg008:1561). Звать после kid_draw, перед fore-слоем. */
|
||
void pop_loose_mob_draw_over(void) __banked;
|
||
|
||
/* Позиция куска (колонка, y низа) для check_loose_fall_on_kid. 0 — нет. */
|
||
uint8_t pop_loose_mob_pos(int *col, int *y) __banked;
|
||
|
||
/* Детектор выхода спрайта за поле: если спрайт [x,w] с ЭКРАННЫМ верхом
|
||
* sy_top и высотой h заходит ниже поля (статус-полоса/борт) или выше
|
||
* верхнего борта — взводит внутренний флаг «борта грязные» на 2 кадра.
|
||
* Звать СРАЗУ после блита падающего объекта (Kid/кусок). */
|
||
void pop_clip_sprite(int x, int w, int sy_top, int h) __banked;
|
||
|
||
/* Почистить борта (верхний + статус-полоса/нижний) — но ТОЛЬКО в кадрах,
|
||
* где кто-то реально вышел за поле (гейт по флагу от pop_clip_sprite):
|
||
* даром в покое, O(1) при падении (не зависит от числа спрайтов). Звать
|
||
* КАЖДЫЙ кадр ПОСЛЕ kid_draw+fore на back-странице. */
|
||
void pop_room_clip_borders(void) __banked;
|
||
|
||
#endif
|