diff --git a/applications/PoP/poc/res/bg/pal_wall.atl b/applications/PoP/poc/res/bg/pal_wall.atl index 1c82e43..f3a72c2 100644 Binary files a/applications/PoP/poc/res/bg/pal_wall.atl and b/applications/PoP/poc/res/bg/pal_wall.atl differ diff --git a/applications/PoP/roomtest/pop_bg.c b/applications/PoP/roomtest/pop_bg.c index c6c40a5..7e8f162 100644 --- a/applications/PoP/roomtest/pop_bg.c +++ b/applications/PoP/roomtest/pop_bg.c @@ -120,10 +120,45 @@ static void draw_right_mark(uint16_t dv, int arg1, int row, int col) #define WP_N 40 static uint8_t wp_a[WP_N], wp_b[WP_N], wp_ok[WP_N]; +/* ---- Цвета дворцовой кладки (gen_palace_wall_colors, seg000:1942) ---- * + * Тело стены во дворце — не кирпичи-спрайты, а СПЛОШНЫЕ ЗАЛИВКИ; их цвета + * разыгрываются на КОМНАТУ: сид = номер комнаты, 3 ряда × 4 подряда × 11 + * колонок. Подряды 1 и 3 берут 0x61..0x64, подряды 0 и 2 — 0x66..0x69 + * (это слоты wall-палитры, во дворце они песочные); соседние по горизонтали + * не повторяются. Одиннадцать колонок, а не десять: заливки 3 и 5 берут + * цвет СЛЕДУЮЩЕЙ колонки. + * + * Не static: таблицу читает и холодная половина слоя (pop_room.c, банк 7). + * Writable-данные банка живут в _DATA/W2 и видны отовсюду — в отличие от + * const-таблиц, которые из чужого банка не прочитать. */ +uint8_t pop_pal_wall_col[3 * 44]; + +static void gen_palace_wall_colors(uint8_t room) +{ + pop_rnd_t saved = pop_t_seed; + uint8_t row, sub, col; + uint8_t *p = pop_pal_wall_col; + pop_prandom_set(pop_t_seed, room); + prandom(1); /* сброс, как в оригинале */ + for (row = 0; row < 3; row++) + for (sub = 0; sub < 4; sub++) { + uint8_t base = (uint8_t)((sub & 1) ? 0x61 : 0x66); + uint8_t prev = 0; /* 0 — «цвета ещё не было» */ + for (col = 0; col < 11; col++) { + uint8_t c; + do { c = (uint8_t)(base + prandom(3)); } while (c == prev); + *p++ = c; + prev = c; + } + } + pop_t_seed = saved; +} + static void wall_pattern_reset(void) /* смена комнаты — сид другой */ { uint8_t i; for (i = 0; i < WP_N; i++) wp_ok[i] = 0; + if (pop_palace) gen_palace_wall_colors(pop_t_room); } /* Выходы wall_rnd — в файловых статиках: возвращать девять значений @@ -219,11 +254,97 @@ static const uint8_t WP_PARTS[4] = { WP_RND | WP_MID | WP_BOT | WP_RIGHT | WP_LEFT, /* 3 WWW */ }; +/* ---- Кладка ДВОРЦА (seg008:1946) ------------------------------------ * + * Тело стены — не кирпичи-спрайты, а шесть СПЛОШНЫХ ЗАЛИВОК цветами из + * pop_pal_wall_col, поверх — пять разделителей chtab_7 (mono, цвет 6). + * Геометрия дословно из add_wipetable(layer, left, bottom, height, width): + * прямоугольник = x..x+width-1, (bottom-height+1)..bottom. + * + * Порядок prandom важен так же, как в подземелье: при which_part == 0 + * разыгрывается ОДНО значение, и нижний разделитель берёт ПЕРВОЕ из серии, + * а не пятое. */ +static uint8_t wpp_d[5]; /* пять prandom(2), 0..2 */ + +static void wall_rnd_palace(int row, int col) +{ + int idx = (col >= 0 && col < 10) ? (row + 1) * 10 + col : -1; + pop_rnd_t saved; + uint8_t i; + if (idx >= 0 && idx < WP_N && wp_ok[idx]) { + uint8_t a = wp_a[idx]; + wpp_d[0] = (uint8_t)(a & 3); wpp_d[1] = (uint8_t)((a >> 2) & 3); + wpp_d[2] = (uint8_t)((a >> 4) & 3); wpp_d[3] = (uint8_t)((a >> 6) & 3); + wpp_d[4] = wp_b[idx]; + return; + } + saved = pop_t_seed; + pop_prandom_set(pop_t_seed, pop_t_room + TBL_LINE[row < 0 ? 2 : row] + col); + prandom(1); /* сброс */ + for (i = 0; i < 5; i++) wpp_d[i] = (uint8_t)prandom(2); + pop_t_seed = saved; + if (idx >= 0 && idx < WP_N) { + wp_a[idx] = (uint8_t)(wpp_d[0] | (wpp_d[1] << 2) | + (wpp_d[2] << 4) | (wpp_d[3] << 6)); + wp_b[idx] = wpp_d[4]; + wp_ok[idx] = 1; + } +} + +/* Заливка куска стены. x/ytop — уже ЭКРАННЫЕ (с POP_YOFF). В fore-проходе + * режем по окну клипа: без этого заливка легла бы поверх областей, которые + * в этом кадре никто не восстанавливает. */ +static void wpp_fill(int x, int ytop, int w, int h, uint8_t colour) +{ + int x2 = x + w - 1, y2 = ytop + h - 1; + if (pop_t_fclip_on) { + if (x < pop_t_fclip_x0) x = pop_t_fclip_x0; + if (ytop < pop_t_fclip_y0) ytop = pop_t_fclip_y0; + if (x2 >= pop_t_fclip_x1) x2 = pop_t_fclip_x1 - 1; + if (y2 >= pop_t_fclip_y1) y2 = pop_t_fclip_y1 - 1; + } + if (pop_t_clip_top && ytop < pop_t_clip_top) ytop = pop_t_clip_top; + if (x < 0) x = 0; + if (ytop < 0) ytop = 0; + if (x2 > 319) x2 = 319; + if (y2 > 255) y2 = 255; + if (x2 < x || y2 < ytop) return; + setfillstyle(SOLID_FILL, colour); + bar(x, ytop, x2, y2); + if (!pop_t_fclip_on) pop_cd_touch(x, ytop, x2 - x + 1, y2 - ytop + 1); +} + +static void wall_pattern_palace(int row, int col, int which_part) +{ + int xh = POP_COL_XH[col]; + int dbys = 63 * row + 65; /* база БЕЗ POP_YOFF — для блитов */ + int dmys = dbys - 3; + int dby = dbys + POP_YOFF, dmy = dmys + POP_YOFF; /* экранные — для заливок */ + /* Цвета лежат по рядам 0..2; полоса у потолка (row −1) — это ряд 2 + * комнаты сверху, оригинал и сид для неё берёт по ряду 2. */ + const uint8_t *cl = pop_pal_wall_col + 44 * (row < 0 ? 2 : row) + col; + wall_rnd_palace(row, col); + if (which_part) { + wpp_fill(xh * 8, dmy - 59, 32, 20, cl[0]); + wpp_fill(xh * 8, dmy - 39, 16, 21, cl[11]); + wpp_fill((xh + 2) * 8, dmy - 39, 16, 21, cl[12]); + wpp_fill(xh * 8, dmy - 18, 8, 19, cl[22]); + wpp_fill((xh + 1) * 8, dmy - 18, 24, 19, cl[23]); + pop_wall_b((uint8_t)(wpp_d[0] + 3), (xh + 3) * 8, dmys - 53); + pop_wall_b((uint8_t)(wpp_d[1] + 6), xh * 8, dmys - 34); + pop_wall_b((uint8_t)(wpp_d[2] + 9), xh * 8, dmys - 13); + pop_wall_b((uint8_t)(wpp_d[3] + 12), xh * 8, dmys); + } + wpp_fill(xh * 8, dby - 2, 32, 3, cl[33]); + pop_wall_b((uint8_t)((which_part ? wpp_d[4] : wpp_d[0]) + 15), xh * 8, dbys); +} + static void wall_pattern(int row, int col, int which_part) { int xh = POP_COL_XH[col]; int dby = 63 * row + 65; - uint8_t parts = WP_PARTS[pop_wall_modifier(row, col)]; + uint8_t parts; + if (pop_palace) { wall_pattern_palace(row, col, which_part); return; } + parts = WP_PARTS[pop_wall_modifier(row, col)]; wall_rnd(row, col); if (which_part) { @@ -359,7 +480,10 @@ static void fore_only_tile(int row, int col) if (!FORE_ANY[code]) return; /* ранний выход, как в оригинале */ t = &pop_tile_table[code]; if (code == 20) { - pop_wall_b(POP_WALL_FRAM_MAIN[pop_wall_modifier(row, col)], x, dmy); + /* Во дворце тело стены даёт wall_pattern заливками, а спрайтовая + * грань не рисуется вовсе (seg008:711). */ + if (!pop_palace) + pop_wall_b(POP_WALL_FRAM_MAIN[pop_wall_modifier(row, col)], x, dmy); wall_pattern(row, col, 1); return; } @@ -399,7 +523,8 @@ static void ceil_over_kid_tile(int col) int x = POP_COL_XH[col] * 8; int dby = 63 * (-1) + 65; /* = 2 */ if (code == 20) { /* draw_tile_bottom: стена */ - pop_wall_b(POP_WALL_FRAM_BOTTOM[pop_wall_modifier(-1, col)], x, dby); + if (!pop_palace) /* seg008:576 */ + pop_wall_b(POP_WALL_FRAM_BOTTOM[pop_wall_modifier(-1, col)], x, dby); wall_pattern(-1, col, 0); } else if (t->bottom_id) { pop_env_b(t->bottom_id, x, dby); @@ -535,7 +660,8 @@ static void overlay_mid_tile(int row, int col) } if (code == 20) { /* draw_tile_bottom */ uint8_t wmod = pop_wall_modifier(row, col); - pop_wall_b(POP_WALL_FRAM_BOTTOM[wmod], x, dby); + if (!pop_palace) /* seg008:576 */ + pop_wall_b(POP_WALL_FRAM_BOTTOM[wmod], x, dby); wall_pattern(row, col, 0); } else if (t->bottom_id) { pop_env_b(t->bottom_id, x, dby); diff --git a/applications/PoP/roomtest/pop_room.c b/applications/PoP/roomtest/pop_room.c index cc8e408..29b4006 100644 --- a/applications/PoP/roomtest/pop_room.c +++ b/applications/PoP/roomtest/pop_room.c @@ -363,7 +363,9 @@ static void draw_tile(int row, int col) /* --- draw_tile_bottom (seg008.c:570) --- */ if (code == 20) { wmod = pop_wall_modifier(row, col); - pop_wall_b(POP_WALL_FRAM_BOTTOM[wmod], x, dby); /* сплошная нижняя грань */ + if (!PALACE) /* во дворце тело стены даёт */ + pop_wall_b(POP_WALL_FRAM_BOTTOM[wmod], x, dby); /* wall_pattern */ + /* заливками (seg008:576) */ pop_wall_pattern_b(row, col, 0); } else if (t->bottom_id) { pop_env_b(t->bottom_id, x, dby); @@ -422,7 +424,8 @@ static void draw_tile(int row, int col) /* --- draw_tile_fore (seg008.c:690) --- */ if (code == 20) { wmod = pop_wall_modifier(row, col); - pop_wall_b(POP_WALL_FRAM_MAIN[wmod], x, dmy); /* основная грань */ + if (!PALACE) /* seg008:711 */ + pop_wall_b(POP_WALL_FRAM_MAIN[wmod], x, dmy); /* основная грань */ pop_wall_pattern_b(row, col, 1); } if (code == 0x12) { /* чомпер: передние зубья + кровь. diff --git a/applications/PoP/toolchain/pop_pack_bg.py b/applications/PoP/toolchain/pop_pack_bg.py index 1b203fc..82a0f30 100644 --- a/applications/PoP/toolchain/pop_pack_bg.py +++ b/applications/PoP/toolchain/pop_pack_bg.py @@ -95,6 +95,7 @@ GATE_ANIM_ENV_IDS = {50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 67} GATE_TOP_ENV_IDS = {60, 61, 62, 63, 64, 65, 66, 67} GATE_TOP_MASK_ID = 68 + # НАЖАТАЯ кнопка-closer (get_tile_to_draw seg008:2FE: при таймере связи >1 # tiles_6_closer рисуется как tiles_5_stuck). tile_table[5] = база 41 (уже # есть), правая грань 35, нижняя 36 — оба id встречаются ТОЛЬКО в этом @@ -131,6 +132,16 @@ POT_MASK_COLOR = VGA16_PAL_BASE + 0 # чёрный (blitters_40h_mono без POT_BUBBLE_COLOR = VGA16_PAL_BASE + 12 # ярко-красный (color 12: «лечение») CHOMPER_BLOOD_COLOR = VGA16_PAL_BASE + 12 # тот же mono-цвет 12 (seg008:678) +# Кладка ДВОРЦА (wall_pattern, seg008:1928, ветка palace): тело стены — +# сплошные заливки цветом из palace_wall_colors, а поверх идут ПЯТЬ +# разделителей chtab_7 id 3..17 (prandom(2) + 3/6/9/12/15), и рисуются они +# blitters_46h_mono_6 — mono-блитом ОДНИМ цветом 6 общей 16-цветной палитры +# экрана. В подземелье те же id — обычные спрайты кирпичей (wall_fram_main/ +# bottom), поэтому силуэтом пакуем ТОЛЬКО дворцовый набор. +PALACE_WALL_MONO_IDS = set(range(3, 18)) +PALACE_WALL_MONO_COLOR = VGA16_PAL_BASE + 6 + + # Основание факела (seg008:489 draw_tile_right: при левом соседе-факеле # рисуется chtab_6 id 146). В статический render_room не попадает. TORCH_ENV_IDS = {146} @@ -505,7 +516,12 @@ def main(): print(f" (env стр {pg}: пусто)") # WALL -> idx=id - wall_entries = {id: load_indexed(R.CHTAB_WALL, id) for id in wall_ids} + wall_entries = {id: load_indexed( + R.CHTAB_WALL, id, False, + PALACE_WALL_MONO_COLOR + if (set_name == "palace" and id in PALACE_WALL_MONO_IDS) + else None) + for id in wall_ids} cnt, sz = pack_atlas(os.path.join(OUT_DIR, prefix + "wall.atl"), wall_entries) total_bytes += sz print(f" {prefix}wall.atl: {len(wall_ids)} спрайтов, каталог {cnt}, {sz} Б")