Уровень 4: второй тайлсет (дворец) — ассеты и переключение (шаги A и B)
Порт tbl_envir_ki[tbl_level_type[level]] (seg000:1108): оригинал под один и тот же набор id грузит РАЗНЫЙ .DAT — VDUNGEON или VPALACE. Упаковщик (toolchain/pop_pack_bg.py): - аргумент набора: `pop_pack_bg.py dungeon|palace`. Каскад каталогов — сначала свой набор, потом чужой фолбэком (в распакованном data/ res230/ 231/348 есть только в VDUNGEON, два десятка — только в VPALACE). - ОБА набора пакуются по одному объединению id, поэтому раскладка id -> (страница, idx) общая и заголовок один: коду достаточно подменить имена файлов. - PALACE_ENV_IDS: 78/80/82 (doortop_fram_bot), 81/83 (doortop_fram_top), 84 (полоска стены), 145 (stripe_id) — их рисует только палас, render_room про них не знает. - ENV_SHIFT 5 -> 4: с паласными кусками страница 2 переваливала за 16 КБ (16 996). Цена — 10 страниц EMM на набор вместо 5, при 215 свободных. - *tile.pal: 32 записи (env 0x50..0x5F + wall 0x60..0x6F) на набор. Полная kid.pal не трогается — Кид, страж, меч и зелья в других слотах. Движок: - pop_level_type() (tbl_level_type, SDLPoP data.h:840): дворцовые уровни 4, 5, 6, 10, 11, 14. Живёт в pop_level.c, потому что по типу расходятся не только атласы, но и ветки отрисовки seg008, кладка стены и модификатор пустой клетки от упавшей плиты (remove_loose, seg007:0EB8). - pop_bg_load(set): no-op при том же наборе, при смене выгружает старый (иначе текут 12 EMM-страниц) и правит 32 записи палитры в ОБЕ страницы дабл-буфера. Зовётся на старте и на границе уровня, не в кадре. - Путь к атласу склеивается на месте (bg_path): двадцать строк-имён в банке — лишние полкилобайта. Проверено в MAME: уровень 1 (подземелье) рисуется как прежде; уровень 4 (-DFIRST_LEVEL=4) — дворцовые арки, окна, пол, решётчатая дверь уровня, Кид не перекрашен. Стены пока чёрные: паласный wall_pattern — шаг C. tests-host: 5/5. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -35,7 +35,7 @@ MEMORY ?= huge # small-раскладка + банки кода в W
|
||||
# ВАЖНО: любое сравнение занятости банков имеет смысл только при ОДНОМ и том
|
||||
# же ALLOCS — иначе сравниваются не правки, а уровни оптимизации.
|
||||
ALLOCS ?= 3000
|
||||
EXTRA_FLAGS ?= --gfx 256 --max-allocs $(ALLOCS) --bank 2=pop_bg.c --bank 7=pop_room.c --bank 4=pop_cdraw.c --bank 3=pop_map.c --bank 1=guards.c --bank 5=pop_ctrl.c --bank 6=pop_trob.c $(PROF_FLAGS)
|
||||
EXTRA_FLAGS ?= --gfx 256 -I $(CURDIR)/../poc/res/bg --max-allocs $(ALLOCS) --bank 2=pop_bg.c --bank 7=pop_room.c --bank 4=pop_cdraw.c --bank 3=pop_map.c --bank 1=guards.c --bank 5=pop_ctrl.c --bank 6=pop_trob.c $(PROF_FLAGS)
|
||||
# Профилирование полосами бордюра (см. PROF() в roomtest.c) — ВКЛЮЧЕНО по
|
||||
# умолчанию, пока идёт работа с производительностью; make PROF=0 выключает.
|
||||
# Каждая фаза кадра красит бордюр в свой цвет, высота полосы на скриншоте
|
||||
@@ -52,9 +52,16 @@ LVL_DIR := $(CURDIR)/../SDLPoP/data/LEVELS
|
||||
# диске. res2000 — демо-уровень, в скоуп не входит.
|
||||
LVL_NUMS := 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
|
||||
LVL_DATA := $(foreach n,$(LVL_NUMS),$(LVL_DIR)/res20$(n).bin)
|
||||
BG_DATA := $(BG_DIR)/pop_env0.atl $(BG_DIR)/pop_env1.atl $(BG_DIR)/pop_env2.atl \
|
||||
$(BG_DIR)/pop_env3.atl $(BG_DIR)/pop_env4.atl \
|
||||
$(BG_DIR)/pop_wall.atl $(BG_DIR)/pop_fore.atl \
|
||||
# ДВА тайлсета: pop_* — подземелье (уровни 1-3, 7-9, 12, 13, 15),
|
||||
# pal_* — дворец (4-6, 10, 11, 14). Раскладка id у них общая, различаются
|
||||
# файлы и палитра тайлсета (*tile.pal, 32 записи). chtab_1 (pop_pot.atl:
|
||||
# пламя, меч-предмет, зелья) от набора не зависит — один на оба.
|
||||
BG_SETS := pop pal
|
||||
BG_PAGES := 0 1 2 3 4 5 6 7 8 9
|
||||
BG_DATA := $(foreach s,$(BG_SETS),\
|
||||
$(foreach n,$(BG_PAGES),$(BG_DIR)/$(s)_env$(n).atl) \
|
||||
$(BG_DIR)/$(s)_wall.atl $(BG_DIR)/$(s)_fore.atl \
|
||||
$(BG_DIR)/$(s)_tile.pal) \
|
||||
$(BG_DIR)/pop_pot.atl
|
||||
# ВСЕ 28 страниц Kid — иначе кадры торможения/разворота/приседа (image>23)
|
||||
# не рисуются (отрисовка пропускает незагруженную страницу). Палитра —
|
||||
@@ -93,7 +100,7 @@ hdd: $(EXAMPLE).exe
|
||||
|
||||
TC := $(PROJ_ROOT)/applications/PoP/toolchain
|
||||
$(BG_DATA): $(TC)/pop_pack_bg.py $(TC)/render_room.py
|
||||
cd $(TC) && python3 pop_pack_bg.py
|
||||
cd $(TC) && python3 pop_pack_bg.py dungeon && python3 pop_pack_bg.py palace
|
||||
$(GUARD_DATA): $(TC)/pop_pack_guard.py
|
||||
cd $(TC) && python3 pop_pack_guard.py
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
/* Загрузить 7 атласов фона. Звать ДО initgraph (как poc.c — atlas_load
|
||||
* трогает W3; проверенный порядок). Палитру pop_bg.pal грузит ПРИЛОЖЕНИЕ
|
||||
* после initgraph (gfx_pal_fload). 0 — OK, -1 — ошибка. */
|
||||
int pop_bg_load(void) __banked;
|
||||
int pop_bg_load(uint8_t set) __banked; /* 0 подземелье, 1 дворец */
|
||||
|
||||
/* Освободить EMM-страницы атласов. */
|
||||
void pop_bg_free(void) __banked;
|
||||
|
||||
@@ -450,6 +450,19 @@ uint8_t pop_level_guard(uint8_t room, uint8_t *tile, int8_t *dir,
|
||||
return (uint8_t)(t < 30);
|
||||
}
|
||||
|
||||
/* tbl_level_type (SDLPoP data.h:840). Держим ЗДЕСЬ, а не в слое фона:
|
||||
* тип уровня нужен не только атласам — по нему расходятся ветки отрисовки
|
||||
* (seg008), кладка стены (wall_pattern) и модификатор пустой клетки от
|
||||
* упавшей плиты (remove_loose, seg007:0EB8). */
|
||||
static const uint8_t LEVEL_TYPE[16] = {
|
||||
0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0
|
||||
};
|
||||
|
||||
uint8_t pop_level_type(void)
|
||||
{
|
||||
return LEVEL_TYPE[pop_current_level & 15];
|
||||
}
|
||||
|
||||
uint8_t pop_level_start_room(void) { return start_byte(BP_START + 0); }
|
||||
uint8_t pop_level_start_pos(void) { return start_byte(BP_START + 1); }
|
||||
int8_t pop_level_start_dir(void) { return (int8_t)start_byte(BP_START + 2); }
|
||||
|
||||
@@ -135,6 +135,13 @@ uint8_t pop_guard_state_x(uint8_t room);
|
||||
uint8_t pop_level_guard(uint8_t room, uint8_t *tile, int8_t *dir,
|
||||
uint8_t *color, uint8_t *skill);
|
||||
|
||||
/* tbl_level_type (SDLPoP data.h:840) — какой тайлсет у уровня:
|
||||
* 0 подземелье, 1 дворец. Дворцовые: 4, 5, 6, 10, 11, 14. Индекс —
|
||||
* НОМЕР уровня; элемент 0 — демо-уровень. Оригинал по нему выбирает и
|
||||
* .DAT окружения (tbl_envir_ki, seg000:1108), и десяток веток отрисовки
|
||||
* в seg008, и графику стража (GUARD1/GUARD2). */
|
||||
uint8_t pop_level_type(void);
|
||||
|
||||
uint8_t pop_level_start_room(void);
|
||||
uint8_t pop_level_start_pos(void);
|
||||
int8_t pop_level_start_dir(void);
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
*
|
||||
* Только DUNGEON-стиль (Фаза 1).
|
||||
*/
|
||||
/* Имена файлов атласов обоих тайлсетов нужны только здесь; макрос обязан
|
||||
* стоять ДО первого включения pop_bg_atlas.h (его тянет pop_tile.h). */
|
||||
#define POP_BG_ATLAS_NAMES
|
||||
#include <graphics.h>
|
||||
#include <gfx.h>
|
||||
#include <sprite.h>
|
||||
@@ -22,34 +25,87 @@
|
||||
#include "pop_level.h" /* pop_doorlink2 — состояние нажатия кнопки */
|
||||
#include "pop_kid.h" /* Kid.curr_col/curr_row — порядок оверлеев */
|
||||
#include "pop_cdraw.h" /* pop_cd — габарит кадра Кида (y-порядок плиты) */
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const char *const ENV_ATL[5] = {
|
||||
/* Ресурсы разложены по каталогам образа (8.3, как в DSS): BG — фон,
|
||||
* KID — персонаж, GUARD — стражи, LEVELS — уровни. Иначе корень диска
|
||||
* зарастает десятками .atl. */
|
||||
"BG\\pop_env0.atl", "BG\\pop_env1.atl", "BG\\pop_env2.atl",
|
||||
"BG\\pop_env3.atl", "BG\\pop_env4.atl"
|
||||
};
|
||||
/* ---- Тайлсет: подземелье / дворец ----------------------------------- *
|
||||
* Порт tbl_envir_ki[tbl_level_type[level]] (seg000:1108): оригинал под один
|
||||
* и тот же набор id грузит РАЗНЫЙ .DAT — VDUNGEON или VPALACE. У нас так
|
||||
* же: раскладка id -> (страница, idx) общая (упаковщик печёт оба набора по
|
||||
* одному объединению id), меняются только файлы атласов и 32 записи
|
||||
* палитры — env 0x50..0x5F и wall 0x60..0x6F. Кид, страж, меч и зелья
|
||||
* живут в других слотах, поэтому общая kid.pal не трогается. */
|
||||
static uint8_t bg_set = 0xFF; /* какой набор сейчас загружен */
|
||||
|
||||
int pop_bg_load(void) __banked
|
||||
/* Ресурсы разложены по каталогам образа (8.3, как в DSS): BG — фон, KID —
|
||||
* персонаж, GUARD — стражи, LEVELS — уровни. Иначе корень диска зарастает
|
||||
* десятками .atl. Путь склеиваем на месте: держать по строке на каждый из
|
||||
* двадцати атласов — лишние полкилобайта в банке. */
|
||||
static char bg_path_buf[20];
|
||||
|
||||
static const char *bg_path(const char *name)
|
||||
{
|
||||
char *d = bg_path_buf;
|
||||
*d++ = 'B'; *d++ = 'G'; *d++ = '\\';
|
||||
while (*name) *d++ = *name++;
|
||||
*d = 0;
|
||||
return bg_path_buf;
|
||||
}
|
||||
|
||||
/* 32 записи (env, затем wall) в ОБЕ палитры: у страниц дабл-буфера они
|
||||
* раздельные. Буфер — на стеке: gfx_pal_load отдаёт указатель BIOS ($A4),
|
||||
* а тот читает только #4000-#BFFF, то есть банковую rodata бы не увидел
|
||||
* (те же грабли, что в pop_guard_set_palette). */
|
||||
static int bg_load_tile_pal(const char *name)
|
||||
{
|
||||
uint8_t buf[64];
|
||||
int fd = open(bg_path(name), O_RDONLY);
|
||||
if (fd < 0) return -1;
|
||||
if (read(fd, buf, 64) != 64) { close(fd); return -1; }
|
||||
gfx_pal_load(0, POP_PAL_ENV, 16, buf);
|
||||
gfx_pal_load(1, POP_PAL_ENV, 16, buf);
|
||||
if (read(fd, buf, 64) != 64) { close(fd); return -1; }
|
||||
gfx_pal_load(0, POP_PAL_WALL, 16, buf);
|
||||
gfx_pal_load(1, POP_PAL_WALL, 16, buf);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Загрузить набор set (0 подземелье, 1 дворец). Повторный вызов с тем же
|
||||
* набором ничего не делает; со сменой — сначала выгружает старый, иначе
|
||||
* EMM-страницы утекут (их по 12 на набор). */
|
||||
int pop_bg_load(uint8_t set) __banked
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 5; i++)
|
||||
if (atlas_load(&pop_env[i], ENV_ATL[i]) != 0) return -1;
|
||||
if (atlas_load(&pop_wall_at, "BG\\pop_wall.atl") != 0) return -1;
|
||||
if (atlas_load(&pop_fore_at, "BG\\pop_fore.atl") != 0) return -1;
|
||||
if (atlas_load(&pop_pot_at, "BG\\pop_pot.atl") != 0) return -1;
|
||||
return 0;
|
||||
if (set >= POP_TILESETS) return -1;
|
||||
if (set == bg_set) return 0;
|
||||
if (bg_set != 0xFF) { /* смена набора — освободить старый */
|
||||
for (i = 0; i < POP_ENV_PAGES; i++) atlas_free(&pop_env[i]);
|
||||
atlas_free(&pop_wall_at);
|
||||
atlas_free(&pop_fore_at);
|
||||
}
|
||||
for (i = 0; i < POP_ENV_PAGES; i++)
|
||||
if (atlas_load(&pop_env[i], bg_path(pop_env_atl[set][i])) != 0) return -1;
|
||||
if (atlas_load(&pop_wall_at, bg_path(pop_wall_atl[set])) != 0) return -1;
|
||||
if (atlas_load(&pop_fore_at, bg_path(pop_fore_atl[set])) != 0) return -1;
|
||||
if (bg_set == 0xFF && /* chtab_1 от набора не зависит */
|
||||
atlas_load(&pop_pot_at, bg_path(POP_POT_ATL)) != 0) return -1;
|
||||
bg_set = set;
|
||||
/* Палитра — ПОСЛЕ атласов: если атлас не загрузился, цвета остаются от
|
||||
* прежнего набора и картинка хотя бы не разъезжается. */
|
||||
return bg_load_tile_pal(pop_tile_pal[set]);
|
||||
}
|
||||
|
||||
void pop_bg_free(void) __banked
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 5; i++)
|
||||
if (bg_set == 0xFF) return;
|
||||
for (i = 0; i < POP_ENV_PAGES; i++)
|
||||
atlas_free(&pop_env[i]);
|
||||
atlas_free(&pop_wall_at);
|
||||
atlas_free(&pop_fore_at);
|
||||
atlas_free(&pop_pot_at);
|
||||
bg_set = 0xFF;
|
||||
}
|
||||
|
||||
static const uint8_t SPIKES_FRAM_RIGHT[10] = {0, 134, 135, 136, 137, 138, 137, 135, 134, 0};
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "_pop_draw.h" /* pop_heal_fast */
|
||||
|
||||
/* ---- Состояние (писучее, _DATA/W2 — видно из любого банка) ---------- */
|
||||
atlas_t pop_env[5], pop_wall_at, pop_fore_at, pop_pot_at;
|
||||
atlas_t pop_env[POP_ENV_PAGES], pop_wall_at, pop_fore_at, pop_pot_at;
|
||||
|
||||
const uint8_t *pop_t_fg, *pop_t_bg, *pop_t_lfg, *pop_t_lbg;
|
||||
const uint8_t *pop_t_below, *pop_t_above, *pop_t_abovemod;
|
||||
@@ -262,7 +262,7 @@ void pop_blit_b(atlas_t *a, uint8_t idx, int x, int ybottom)
|
||||
gfx_w0_unmap();
|
||||
}
|
||||
|
||||
void pop_env_b(uint8_t id, int x, int yb) { pop_blit_b(&pop_env[id >> 5], (uint8_t)(id & 31), x, yb); }
|
||||
void pop_env_b(uint8_t id, int x, int yb) { pop_blit_b(&pop_env[id >> POP_ENV_SHIFT], (uint8_t)(id & POP_ENV_MASK), x, yb); }
|
||||
void pop_wall_b(uint8_t id, int x, int yb) { pop_blit_b(&pop_wall_at, id, x, yb); }
|
||||
void pop_fore_b(uint8_t id, int x, int yb) { pop_blit_b(&pop_fore_at, id, x, yb); }
|
||||
void pop_pot_b(uint8_t id, int x, int yb) { pop_blit_b(&pop_pot_at, id, x, yb); }
|
||||
|
||||
@@ -31,9 +31,13 @@
|
||||
#include "pop_geom.h" /* pop_rnd_t — сид кладки комнаты */
|
||||
|
||||
/* ---- Атласы фона (прямая адресация id) ------------------------------ *
|
||||
* env[id>>5] idx id&31 — chtab_6 environment; wall — chtab_7; fore —
|
||||
* передний слой; pot — chtab_1 (зелья, меч-предмет). */
|
||||
extern atlas_t pop_env[5], pop_wall_at, pop_fore_at, pop_pot_at;
|
||||
* env[id>>POP_ENV_SHIFT] idx id&POP_ENV_MASK — chtab_6 environment;
|
||||
* wall — chtab_7; fore — передний слой; pot — chtab_1 (зелья, меч).
|
||||
* Раскладка и число страниц — из pop_bg_atlas.h (генерит упаковщик).
|
||||
* Тайлсетов ДВА (подземелье/дворец), но раскладка id у них общая:
|
||||
* подменяются только файлы и 32 записи палитры (см. pop_bg_set_tileset). */
|
||||
#include "pop_bg_atlas.h"
|
||||
extern atlas_t pop_env[POP_ENV_PAGES], pop_wall_at, pop_fore_at, pop_pot_at;
|
||||
|
||||
/* ---- Текущая отрисованная комната ----------------------------------- *
|
||||
* fg — foretable-коды, bg — модификаторы; lfg/lbg — правый столбец ЛЕВОГО
|
||||
|
||||
@@ -479,7 +479,11 @@ int main(void)
|
||||
uint8_t cheat_prev = 0, immo_prev = 0, sword_prev = 0, nlvl_prev = 0;
|
||||
uint8_t xdec_prev = 0, xinc_prev = 0;
|
||||
|
||||
if (pop_bg_load() != 0) { /* атласы — ДО initgraph (снимает DSS-страницу W0) */
|
||||
/* Набор фона — по типу СТАРТОВОГО уровня. Атласы грузятся ДО initgraph
|
||||
* (тот снимает DSS-страницу W0); уровень к этому моменту ещё не прочитан,
|
||||
* поэтому тип берём напрямую от номера. */
|
||||
pop_current_level = FIRST_LEVEL;
|
||||
if (pop_bg_load(pop_level_type()) != 0) {
|
||||
puts("pop_bg_load failed");
|
||||
return 1;
|
||||
}
|
||||
@@ -757,6 +761,14 @@ int main(void)
|
||||
* пределы, и персонаж просто не виден. */
|
||||
pop_guard_free();
|
||||
pop_guard_load();
|
||||
/* Тайлсет: подземелье <-> дворец (порт tbl_envir_ki,
|
||||
* seg000:1108). Внутри — no-op, если тип не менялся;
|
||||
* при смене выгружает старые атласы и правит 32 записи
|
||||
* палитры. Только на границе уровня, не в кадре. */
|
||||
if (pop_bg_load(pop_level_type()) != 0) {
|
||||
puts("bg set load failed");
|
||||
return 1;
|
||||
}
|
||||
/* Всё состояние прошлого уровня сносит сам pop_start_level:
|
||||
* pop_trob_reset обнуляет room_seen (модификаторы комнат
|
||||
* перечитаются из НОВОЙ страницы), тайлы/стражи приезжают
|
||||
|
||||
Reference in New Issue
Block a user