Шаг D: паласные ветки отрисовки + потерянный верх ворот

Порт семи мест seg008, расходящихся по tbl_level_type, плюс общая дыра
порта, которая на дворце стала видна.

Паласные ветки (все — «в подземелье этого нет»):
- doortop_fram_top / doortop_fram_bot (seg008:413, 506): декоративная панель
  над воротами.  У шва она и есть тот «ковёр», которого не хватало.
- stripe_id соседа слева (seg008:486): орнаментная лента под окнами.  Она
  непрерывная, потому что stripe_id = 145 у пола, кнопок, зелья, loose,
  чомпера и меча; без неё лента шла кусками (только blueline).
- полоска на стене id 84 (seg008:510), при (modifier & 0x80) == 0.
- blueline_fram3: условие `num == !!level_type` — в подземелье пропускается
  num==0, в паласе num==1 (seg008:501).
- левая половина кнопки-opener без пола (id 148) — только подземелье
  (seg008:628).
- склянка зелья: id += 2 во дворце (seg008:747).
- remove_loose возвращает ТИП УРОВНЯ, и он ложится модификатором пустой
  клетки от упавшей плиты (seg007:846/1083).

Потерянный вывод (НЕ паласное расхождение, просто заметили здесь):
draw_tile_anim_topright (seg008:0568) не был портирован вовсе — верх ворот,
который рисует тайл НАД ними: маска 68 (mono, чёрным) + door_fram_top
[(modifier>>2) % 8] = 60..67.  Ids 60..68 в атлас не паковались.  Симптом —
чёрный клин над воротами; нашёлся сравнением с эталоном SDLPoP
(--screenshot) и трассой add_backtable.

Флаг тайлсета pop_palace вынесен в резидент (pop_tile.c): по нему расходятся
ветки в банке 7 (полная отрисовка), банке 2 (fore-проход) и банке 3
(модификатор пустой клетки) — читается напрямую, без трамплина.

Известное расхождение: модификатора ряда СНИЗУ у нас нет (pop_t_below —
только fg), поэтому паласная панель над воротами в комнате снизу не
рисуется.  Помечено в коде.

tests-host: 5/5 (добавлен include-путь до pop_bg_atlas.h и стаб pop_palace).
Проверено в MAME: уровень 4 совпадает с эталоном SDLPoP в рядах 0-1
попиксельно (кроме фазы пламени); уровень 1 не изменился.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-10 12:04:49 +03:00
parent 89400ff1d4
commit 0941ef1d90
11 changed files with 101 additions and 11 deletions
+67 -9
View File
@@ -91,6 +91,7 @@ int pop_bg_load(uint8_t set) __banked
if (bg_set == 0xFF && /* chtab_1 от набора не зависит */
atlas_load(&pop_pot_at, bg_path(POP_POT_ATL)) != 0) return -1;
bg_set = set;
pop_palace = (uint8_t)(set == 1);
/* Палитра — ПОСЛЕ атласов: если атлас не загрузился, цвета остаются от
* прежнего набора и картинка хотя бы не разъезжается. */
return bg_load_tile_pal(pop_tile_pal[set]);
@@ -156,10 +157,34 @@ static uint8_t potion_type(uint8_t modif) { return (uint8_t)((modif & 0xF8) >> 3
/* Дворец? — по ЗАГРУЖЕННОМУ набору (pop_palace ставит pop_bg_load), а не по
* номеру уровня: так ветки отрисовки и картинки заведомо согласованы даже в
* момент смены. */
#define PALACE (pop_palace)
/* Декоративная панель над воротами — ТОЛЬКО в паласе (в подземелье над
* воротами не рисуется ничего). Индекс — модификатор тайла doortop.
* seg008:407 doortop_fram_top / seg008:453 doortop_fram_bot. */
static const uint8_t DOORTOP_FRAM_TOP[4] = {0, 81, 83, 0};
static const uint8_t DOORTOP_FRAM_BOT[4] = {78, 80, 82, 0};
/* Верх ворот: его рисует тайл НАД воротами (draw_tile_anim_topright,
* seg008:0568). Кадр — по открытости соседа снизу-слева; 68 — маска,
* mono-блит чёрным «продавливает» фон под створкой.
* Без этого над воротами оставался чёрный клин — виден у шва во дворце,
* где сверху идёт декоративная панель doortop. */
static const uint8_t DOOR_FRAM_TOP[8] = {60, 61, 62, 63, 64, 65, 66, 67};
#define GATE_TOP_MASK 68
/* topright тайла снизу-слева (seg008.c:410). */
static void draw_topright(uint8_t tt, int x, int dby)
static void draw_topright(uint8_t tt, uint8_t tmod, int x, int dby)
{
if (tt == 7 || tt == 12) return;
if (tt == 7 || tt == 12) { /* верх ворот */
if (!PALACE) return; /* подземелье: ничего (seg008:413) */
if (DOORTOP_FRAM_TOP[tmod & 3])
pop_env_b(DOORTOP_FRAM_TOP[tmod & 3], x, dby);
return;
}
if (tt == 20) { pop_wall_b(2, x, dby); return; }
if (pop_tile_table[tt].topright_id)
pop_env_b(pop_tile_table[tt].topright_id, x, dby);
@@ -236,7 +261,7 @@ static void draw_tile(int row, int col)
int dmy = dby - 3;
const piece *t = &pop_tile_table[code];
const piece *lt = &pop_tile_table[lcode];
uint8_t rbl_code;
uint8_t rbl_code, rbl_mod;
uint8_t wmod;
/* тайл снизу-слева (для topright). Ниже нижнего ряда — берём ряд 0
@@ -250,11 +275,28 @@ static void draw_tile(int row, int col)
* load_rowbelow (seg008:368). См. BUG-SEAM-WEDGE-1. */
if (lc < 0) rbl_code = pop_t_below ? (uint8_t)(pop_t_below[10] & 0x1F) : 20;
else rbl_code = pop_t_below ? (uint8_t)(pop_t_below[lc] & 0x1F) : 1;
} else rbl_code = pop_tile_code(row + 1, col - 1);
/* Модификатора ряда снизу у нас нет (pop_t_below — только fg), а он
* нужен паласной панели над воротами. Ставим 0 = «панели нет»:
* случай узкий (ворота в комнате СНИЗУ, по диагонали от пустого
* тайла нижнего ряда), но расхождение с оригиналом честное. */
rbl_mod = 0;
} else {
rbl_code = pop_tile_code(row + 1, col - 1);
rbl_mod = pop_tile_mod(row + 1, col - 1);
}
/* --- draw_tile_anim_topright (seg008:0568): верх ВОРОТ снизу-слева.
* Условие дословно: свой тайл пуст / верх большой колонны / верх двери,
* а снизу-слева — ворота. --- */
if ((code == 0 || code == 9 || code == 12) && rbl_code == 4) {
uint8_t om = (rbl_mod > 188) ? 188 : rbl_mod;
pop_env_b(GATE_TOP_MASK, x, dby); /* маска (mono, чёрным) */
pop_env_b(DOOR_FRAM_TOP[(om >> 2) & 7], x, dby);
}
/* --- floorright (seg008.c:392) — только can_see_bottomleft --- */
if (code == 0 || code == 9 || code == 12 || code == 26) {
draw_topright(rbl_code, x, dby);
draw_topright(rbl_code, rbl_mod, x, dby);
/* floor-right тень (blitters_9_black) на ЧЁРНОМ фоне = no-op
* (чёрный силуэт по чёрному) — не рисуем. Если tile_left имеет
* floor_right: lt->floor_right. */
@@ -263,6 +305,10 @@ static void draw_tile(int row, int col)
/* --- draw_tile_right (seg008.c:456) --- */
if (code != 20) {
if (lcode == 20) {
/* Полоска на стене (seg008:510) — только палас и только если у
* стены не взведён старший бит модификатора. */
if (PALACE && (lmod & 0x80) == 0)
pop_env_b(84, x + 3 * 8, dmy - 27);
pop_wall_b(1, x, pop_tile_table[20].right_y + dmy); /* грань стены */
} else if (lcode == 0) {
if (lmod <= 3 && BLUELINE_FRAM1[lmod])
@@ -271,15 +317,26 @@ static void draw_tile(int row, int col)
uint8_t num;
pop_env_b(42, x, pop_tile_table[1].right_y + dmy); /* правый треуг. пола */
num = (lmod <= 3) ? lmod : 0;
if (num != 0) /* dungeon: level_type=0 */
/* seg008:501 — `if (num == !!level_type) return;`: в подземелье
* пропускается num==0, в паласе num==1. */
if (num != (PALACE ? 1 : 0))
pop_env_b(BLUELINE_FRAM3[num], x, dmy - 20); /* силуэт кладки */
} else if (lcode == 7 || lcode == 12) {
/* Низ декоративной панели над воротами (seg008:506) — только
* палас; в подземелье у doortop right_id нулевой и ветка пустая. */
if (PALACE && DOORTOP_FRAM_BOT[lmod & 3])
pop_env_b(DOORTOP_FRAM_BOT[lmod & 3], x, lt->right_y + dmy);
} else {
if (lt->right_id)
pop_env_b(lt->right_id, x, lt->right_y + dmy);
/* Орнаментная лента соседа (seg008:486) — только палас. Она и
* даёт непрерывную полосу под окнами: stripe_id = 145 у пола,
* кнопок, зелья, loose, чомпера и меча. */
if (PALACE && lt->stripe_id)
pop_env_b(lt->stripe_id, x, dmy - 27);
/* Основание факела (seg008:489): рисует ПРАВЫЙ сосед. */
if (lcode == 19 || lcode == 30)
pop_env_b(146, x, dby - 28);
/* stripe — только палас, dungeon пропускает */
}
}
@@ -325,8 +382,9 @@ static void draw_tile(int row, int col)
uint8_t base_id = t->base_id;
if (code == 11) /* loose: левая грань (анимир.) */
base_id = POP_LOOSE_FRAM_LEFT[pop_loose_frame(pop_loose_modif[row * 10 + col])];
else if (code == 0x0F && lcode == 0) /* opener, слева пусто */
base_id = 148; /* левая половина без пола */
else if (code == 0x0F && lcode == 0 && !PALACE) /* opener, слева пусто */
base_id = 148; /* левая половина без пола — только */
/* подземелье (seg008:628) */
if (base_id)
pop_env_b(base_id, x, t->base_y + dmy);
}