Files
Sprinter-SDCC/applications/PoP/roomtest/pop_tile.c
T
snark13 0941ef1d90 Шаг 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>
2026-08-10 12:04:49 +03:00

370 lines
21 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_tile.c — общие ЛИСТЬЯ слоя фона: блит куска атласа, чтение тайла
* комнаты, таблица тайлов. РЕЗИДЕНТ W1 (_CODE).
*
* Мотивация раскладки (почему резидент, а не банк) — в шапке pop_tile.h:
* коротко, эти функции и таблицы нужны ОБЕИМ половинам слоя фона (горячей —
* fore-проход каждый кадр, холодной — полная отрисовка комнаты), а код и
* rodata банка видны только пока банк замаплен. W1 замаплено всегда.
*/
#include <graphics.h>
#include <gfx.h>
#include <sprite.h>
#include "pop_bg.h" /* POP_YOFF */
#include "pop_cdraw.h" /* POP_CD_TOUCH — фон тронут, персонажей перерисовать */
#include "pop_tile.h"
#include "pop_level.h" /* pop_doorlink2 — подстановка нажатой кнопки */
#include "_pop_draw.h" /* pop_heal_fast */
/* ---- Состояние (писучее, _DATA/W2 — видно из любого банка) ---------- */
atlas_t pop_env[POP_ENV_PAGES], pop_wall_at, pop_fore_at, pop_pot_at;
/* Загруженный тайлсет: 0 подземелье, 1 дворец (порт tbl_level_type в той
* части, что касается ОТРИСОВКИ). Ставит pop_bg_load; резидент — потому
* что по нему расходятся ветки и в банке 7 (полная отрисовка тайла), и в
* банке 2 (fore-проход), и в банке 3 (модификатор пустой клетки от упавшей
* плиты, remove_loose seg007:0EB8). Читать напрямую, без трамплина. */
uint8_t pop_palace;
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;
uint8_t pop_t_room;
pop_rnd_t pop_t_seed;
int pop_t_clip_top;
int pop_t_fclip_x0, pop_t_fclip_y0, pop_t_fclip_x1, pop_t_fclip_y1;
uint8_t pop_t_fclip_on;
uint8_t pop_t_bake_rest;
/* Позиция склянки внутри тайла зелья — поля fore_x/fore_y записи 0x0A той же
* таблицы. Вынесены МАКРОСАМИ (одно место правки, дублирования данных нет):
* пока таблица была `static const`, SDCC сворачивала `tile_table[10].fore_x`
* в константу, но глобальную (её читают оба банка) уже не сворачивает —
* чтение полей в рантайме стоило +150 Б и IX-кадр на 13 локалов. */
#define POT_FORE_X 2
#define POT_FORE_Y (-3)
/* ---- Таблица тайлов (piece, seg008.c:27) --------------------------- */
const piece pop_tile_table[31] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 00 empty */
{ 41, 1, 0, 42, 1, 2, 145, 0, 43, 0, 0, 0}, /* 01 floor */
{127, 1, 0, 133, 1, 2, 145, 0, 43, 0, 0, 0}, /* 02 spike */
{ 92, 1, 0, 93, 1, 2, 0, 94, 43, 95, 1, 0}, /* 03 pillar */
{ 46, 1, 0, 47, 1, 2, 0, 48, 43, 49, 3, 0}, /* 04 gate */
{ 41, 1, 1, 35, 1, 3, 145, 0, 36, 0, 0, 0}, /* 05 stuck floor */
{ 41, 1, 0, 42, 1, 2, 145, 0, 96, 0, 0, 0}, /* 06 close button */
{ 46, 1, 0, 0, 0, 2, 0, 0, 43, 49, 3, 0}, /* 07 door top w/floor */
{ 86, 1, 0, 87, 1, 2, 0, 0, 43, 88, 1, 0}, /* 08 big pillar bottom */
{ 0, 0, 0, 89, 0, 3, 0, 90, 0, 91, 1, 3}, /* 09 big pillar top */
{ 41, 1, 0, 42, 1, 2, 145, 0, 43, 12, POT_FORE_X, POT_FORE_Y}, /* 0A potion */
{ 0, 1, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0}, /* 0B loose floor */
{ 0, 0, 0, 0, 0, 2, 0, 0, 85, 49, 3, 0}, /* 0C door top */
{ 75, 1, 0, 42, 1, 2, 0, 0, 43, 77, 0, 0}, /* 0D mirror */
{ 97, 1, 0, 98, 1, 2, 145, 0, 43,100, 0, 0}, /* 0E debris */
{147, 1, 0, 42, 1, 1, 145, 0,149, 0, 0, 0}, /* 0F open button */
{ 41, 1, 0, 37, 0, 0, 0, 38, 43, 0, 0, 0}, /* 10 leveldoor left */
{ 0, 0, 0, 39, 1, 2, 0, 40, 43, 0, 0, 0}, /* 11 leveldoor right */
{ 0, 0, 0, 42, 1, 2, 145, 0, 43, 0, 0, 0}, /* 12 chomper */
{ 41, 1, 0, 42, 1, 2, 0, 0, 43, 0, 0, 0}, /* 13 torch */
{ 0, 0, 0, 1, 1, 2, 0, 2, 0, 0, 0, 0}, /* 14 wall */
{ 30, 1, 0, 31, 1, 2, 0, 0, 43, 0, 0, 0}, /* 15 skeleton */
{ 41, 1, 0, 42, 1, 2, 145, 0, 43, 0, 0, 0}, /* 16 sword */
{ 41, 1, 0, 10, 0, 0, 0, 11, 43, 0, 0, 0}, /* 17 balcony left */
{ 0, 0, 0, 12, 1, 2, 0, 13, 43, 0, 0, 0}, /* 18 balcony right */
{ 92, 1, 0, 42, 1, 2, 145, 0, 43, 95, 1, 0}, /* 19 lattice pillar */
{ 1, 0, 0, 0, 0, 0, 0, 0, 2, 9, 0,-53}, /* 1A lattice down */
{ 3, 0,-10, 0, 0, 0, 0, 0, 0, 9, 0,-53}, /* 1B lattice small */
{ 4, 0,-10, 0, 0, 0, 0, 0, 0, 9, 0,-53}, /* 1C lattice left */
{ 5, 0,-10, 0, 0, 0, 0, 0, 0, 9, 0,-53}, /* 1D lattice right */
{ 97, 1, 0, 98, 1, 2, 0, 0, 43,100, 0, 0}, /* 1E debris w/torch */
};
/* Деление координаты на ширину тайла ТАБЛИЦЕЙ (tile_div_tbl/tile_mod_tbl,
* seg006:702/23A6) — как в оригинале. Живут в резиденте, потому что нужны
* и карте (банк 3, колонка персонажа), и слою фона (банк 2, футпринт), а
* const-таблицу чужого банка не прочитать.
*
* Почему не деление: SDCC разворачивает / и % в __divsint + __modsint,
* причём __modsint внутри снова зовёт __divsint — замер в MAME дал 5 400
* тактов на один вызов при 13+ вызовах за кадр. Индекс — координата как
* есть (0..255), смещение -58 уже внутри значений: POP_TILE_DIV[x] =
* floor((x - 58) / 14), POP_TILE_MOD[x] — остаток. Сверено с SDLPoP
* побайтно. */
const int8_t POP_TILE_DIV[256] = {
-5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14,
};
const uint8_t POP_TILE_MOD[256] = {
12,13, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13, 0, 1,
2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13, 0, 1, 2, 3,
4, 5, 6, 7, 8, 9,10,11,12,13, 0, 1, 2, 3, 4, 5,
6, 7, 8, 9,10,11,12,13, 0, 1, 2, 3, 4, 5, 6, 7,
8, 9,10,11,12,13, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10,11,12,13, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,
12,13, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13, 0, 1,
2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13, 0, 1, 2, 3,
4, 5, 6, 7, 8, 9,10,11,12,13, 0, 1, 2, 3, 4, 5,
6, 7, 8, 9,10,11,12,13, 0, 1, 2, 3, 4, 5, 6, 7,
8, 9,10,11,12,13, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10,11,12,13, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,
12,13, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13, 0, 1,
};
const uint8_t POP_COL_XH[10] = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36};
const uint8_t POP_WALL_FRAM_BOTTOM[4] = {7, 9, 5, 3};
const uint8_t POP_WALL_FRAM_MAIN[4] = {8, 10, 6, 4};
const uint8_t POP_SPIKES_FRAM_LEFT[10] = {0, 128, 129, 130, 131, 132, 131, 129, 128, 0};
const uint8_t POP_LOOSE_FRAM_LEFT[12] = {41,69,41,70,70,41,41,41,70,70,70,0};
const uint8_t POP_LOOSE_FRAM_BOTTOM[12] = {43,73,43,74,74,43,43,43,74,74,74,0};
/* ---- Чомпер: номер позы и передние куски (seg008 chomper_fram1/for) ---
* Резидент, а не банк: позу считает и полная отрисовка тайла (холодная
* половина, pop_room.c), и fore-проход поверх персонажа (горячая,
* pop_bg.c) — а const-таблица банка из чужого банка не читается вовсе. */
static const uint8_t CHOMP_FRAM1[7] = {3, 2, 0, 1, 4, 3, 3};
const uint8_t POP_CHOMP_FRAM_FOR[5] = {106, 107, 108, 109, 110};
uint8_t pop_chomp_pose(uint8_t modif)
{
uint8_t m = (uint8_t)(modif & 0x7F);
if (m > 6) m = 6;
return CHOMP_FRAM1[m];
}
/* get_loose_frame (seg008:761): индекс дрожащего кадра по модификатору.
* В режиме ЗАПЕЧКИ фона отдаёт кадр ПОКОЯ — транзиентный кадр нельзя
* консервировать в ОЗУ-копию (см. pop_t_bake_rest в pop_bg.c). */
uint8_t pop_loose_frame(uint8_t m)
{
if (pop_t_bake_rest) return 0;
if (m & 0x80) { m &= 0x7F; if (m > 10) return 1; }
return m;
}
/* ---- «Фон трогали ВОТ ЗДЕСЬ» (DRAW-COST; контракт — pop_cdraw.h) ----- */
uint8_t pop_cd_dirty;
int pop_cd_dx0[2], pop_cd_dy0[2], pop_cd_dx1[2], pop_cd_dy1[2];
/* Цикл по страницам развёрнут, а x+w / y+h посчитаны один раз. Не
* вкусовщина: индекс-переменная заставляла SDCC считать адрес каждой из
* восьми ячеек сложением, а `x + w` в условии и в присваивании считались
* дважды — замер в MAME дал 6 846 тактов на вызов, а зовётся он с КАЖДОГО
* блита фона (два факела в комнате — уже 13 700 за кадр). */
void pop_cd_touch(int x, int y, int w, int h)
{
int x1 = x + w, y1 = y + h;
uint8_t d = pop_cd_dirty;
if (!(d & 1)) {
pop_cd_dx0[0] = x; pop_cd_dy0[0] = y;
pop_cd_dx1[0] = x1; pop_cd_dy1[0] = y1;
} else {
if (x < pop_cd_dx0[0]) pop_cd_dx0[0] = x;
if (y < pop_cd_dy0[0]) pop_cd_dy0[0] = y;
if (x1 > pop_cd_dx1[0]) pop_cd_dx1[0] = x1;
if (y1 > pop_cd_dy1[0]) pop_cd_dy1[0] = y1;
}
if (!(d & 2)) {
pop_cd_dx0[1] = x; pop_cd_dy0[1] = y;
pop_cd_dx1[1] = x1; pop_cd_dy1[1] = y1;
} else {
if (x < pop_cd_dx0[1]) pop_cd_dx0[1] = x;
if (y < pop_cd_dy0[1]) pop_cd_dy0[1] = y;
if (x1 > pop_cd_dx1[1]) pop_cd_dx1[1] = x1;
if (y1 > pop_cd_dy1[1]) pop_cd_dy1[1] = y1;
}
pop_cd_dirty = 3;
}
/* ---- Блит куска атласа ---------------------------------------------- */
/* Клипованный путь — ОТДЕЛЬНОЙ функцией. У него девять 16-битных локалей,
* и SDCC заводит под них кадр IX; пока он жил в общем теле, за этот кадр
* платили и блиты БЕЗ клипа (`ld -n(ix)` = 19 тактов номинала, у нас ~46).
* А блитов без клипа большинство: весь фон вне fore-прохода — факелы, зелья,
* перерисовка тайлов — идёт с pop_t_fclip_on == 0. */
static void blit_b_clip(const uint8_t *img, int x, int top, int w, int h)
{
int dx = x, dy = top, dw = w, dh = h, sx = 0, sy = 0;
if (pop_t_clip_top && dy < pop_t_clip_top) { /* полоса у потолка */
sy = pop_t_clip_top - dy; dy = pop_t_clip_top; dh -= sy;
}
if (pop_t_fclip_on) { /* окно fore-слоя */
if (dx < pop_t_fclip_x0) { int d = pop_t_fclip_x0 - dx; sx += d; dx += d; dw -= d; }
if (dy < pop_t_fclip_y0) { int d = pop_t_fclip_y0 - dy; sy += d; dy += d; dh -= d; }
if (dx + dw > pop_t_fclip_x1) dw = pop_t_fclip_x1 - dx;
if (dy + dh > pop_t_fclip_y1) dh = pop_t_fclip_y1 - dy;
}
if (dw <= 0 || dh <= 0) return;
if (dx >= 0 && dy >= 0 && dw < 256 && dh < 256 &&
dx + dw <= 320 && dy + dh <= 256 && w < 256) {
if (sx == 0 && sy == 0 && dw == w && dh == h)
gfx_blit_noclip(dx, dy, img);
else
gfx_blit_part_noclip(dx, dy, img, (uint8_t)sx, (uint8_t)sy,
(uint8_t)dw, (uint8_t)dh);
} else {
gfx_blit_part(dx, dy, img, sx, sy, dw, dh); /* край экрана */
}
/* Кусок ФОНА лёг туда, где может лежать уже нарисованный персонаж —
* пометить область (DRAW-COST, pop_cdraw.h). Признак «это не fore-проход
* поверх персонажа» — окно клипа: его ставит только он. */
if (!pop_t_fclip_on) pop_cd_touch(dx, dy, dw, dh);
}
void pop_blit_b(atlas_t *a, uint8_t idx, int x, int ybottom)
{
const uint8_t *img;
uint16_t w, h;
int top;
if (idx >= a->count)
return;
/* Грубый отсев ДО маппинга страницы: реальные w/h лежат в заголовке
* ленты, то есть в EMM-странице, и чтобы их прочитать, надо сделать
* gfx_w0_map. Берём заведомо больший габарит (кадры фона не крупнее
* 64×64) и, если он не задевает окно, уходим не заплатив ни за
* atlas_image, ни за map/unmap. */
if (pop_t_fclip_on &&
(x >= pop_t_fclip_x1 || x + 64 <= pop_t_fclip_x0 ||
ybottom + POP_YOFF + 1 <= pop_t_fclip_y0 ||
ybottom + POP_YOFF - 64 >= pop_t_fclip_y1))
return;
img = (const uint8_t *)atlas_image(a, idx);
gfx_w0_map(a->page);
w = (uint16_t)(img[0] | ((uint16_t)img[1] << 8));
h = (uint16_t)(img[2] | ((uint16_t)img[3] << 8));
top = ybottom - (int)h + 1 + POP_YOFF; /* +YOFF: центрирование */
if (w && h) {
if (!pop_t_fclip_on && !pop_t_clip_top) {
/* БЫСТРЫЙ путь: клипа нет вовсе. Так идут все блиты фона вне
* fore-прохода. Линейное ядро без клипа — ~2.9× быстрее общего
* (замер: 4617 против 13288 тактов на спрайт 32×3; gfx_blit
* платит за клип/16-бит/split, а не за пиксели). W3-скобку
* ставит сама libbgi: из кода с --w3 её вызывать нельзя. */
if (x >= 0 && top >= 0 && w < 256 && h < 256 &&
x + (int)w <= 320 && top + (int)h <= 256)
gfx_blit_noclip(x, top, img);
else
gfx_blit_part(x, top, img, 0, 0, (int)w, (int)h);
pop_cd_touch(x, top, (int)w, (int)h);
} else {
blit_b_clip(img, x, top, (int)w, (int)h);
}
}
gfx_w0_unmap();
}
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); }
void pop_heal_off(int x, int y, int w, int h)
{
pop_heal_fast(x, y + POP_YOFF, w, h);
}
/* ---- Чтение тайла отрисованной комнаты ------------------------------ */
uint8_t pop_tile_code(int row, int col)
{
if (col < 0) {
if (pop_t_lfg && row >= 0 && row < 3) return pop_t_lfg[row];
return 20; /* уровневая кромка = стена */
}
if (row < 0) { /* верхняя полоса: ряд 2 комнаты сверху */
if (row == -1 && pop_t_above && col < 10) return pop_t_above[col];
return 1; /* нет комнаты сверху → пол (кромка) */
}
if (row > 2 || col > 9) return 20;
return pop_t_fg[row * 10 + col];
}
uint8_t pop_tile_mod(int row, int col)
{
if (col < 0) {
if (pop_t_lbg && row >= 0 && row < 3) return pop_t_lbg[row];
return 0;
}
if (row == -1 && pop_t_abovemod && col < 10) return pop_t_abovemod[col];
if (row < 0 || row > 2 || col > 9) return 0;
return pop_t_bg[row * 10 + col];
}
/* Порт подстановки нажатой кнопки из get_tile_to_draw (seg008:240): opener →
* floor, closer → stuck, когда таймер связи > 1. Любой слой, который
* выбирает ветку отрисовки по типу тайла, обязан смотреть на ПОДСТАВЛЕННЫЙ
* тип (иначе кнопка, на которой стоит Kid, ведёт себя как «не пол» — напр.
* climb-оверлей уходил в draw_other_overlay и закрашивал Kid целым тайлом
* вместо узкой кромки floor_left_overlay). */
uint8_t pop_tile_code_drawn(int row, int col)
{
uint8_t code = pop_tile_code(row, col);
if (code == 0x0F) { if ((pop_doorlink2(pop_tile_mod(row, col)) & 0x1F) > 1) code = 1; }
else if (code == 0x06) { if ((pop_doorlink2(pop_tile_mod(row, col)) & 0x1F) > 1) code = 5; }
return code;
}
uint8_t pop_wall_modifier(int row, int col)
{
uint8_t lw = (col > 0) ? (pop_tile_code(row, col - 1) == 20) : 1;
uint8_t rw = (col < 9) ? (pop_tile_code(row, col + 1) == 20) : 1;
if (lw && rw) return 3; /* WWW */
if (lw) return 2; /* WWS */
if (rw) return 1; /* SWW */
return 0; /* SWS */
}
/* ---- Зелье: склянка (tiles_10_potion, seg008 draw_tile_fore) --------- *
* Тип = (modif & 0xF8) >> 3: 0 = пусто (ничего не рисуем), 2..4 — «большая»
* склянка (id 13), остальные — маленькая (id 12). Спрайты из chtab_1 (атлас
* pop_pot), поэтому НЕ из env: раньше рисовали chtab_6 id 12 (res212),
* которого в VDUNGEON нет — оттуда и «мусорный объект». Позиция оригинала:
* xh = fore_x + draw_xh, xl = 6, ybottom = fore_y + draw_main_y.
*
* Здесь, а не в банке: склянку рисует и полная отрисовка тайла (холодная
* половина), и fore-проход поверх персонажа (горячая). */
void pop_potion_flask(int row, int col, uint8_t modif)
{
uint8_t type = (uint8_t)((modif & 0xF8) >> 3);
uint8_t id = 12;
if (type == 0) return;
if (type >= 2 && type < 5) id = 13; /* большая склянка */
if (pop_palace) id += 2; /* seg008:747: во дворце склянки другие */
pop_pot_b(id, (POT_FORE_X + POP_COL_XH[col]) * 8 + 6,
POT_FORE_Y + 63 * row + 62);
}
/* Окно fore-клипа: ставит тот, кто нарисовал персонажа (pop_cdraw, банк 4),
* читает blit_b. Резидент — чтобы вызов из банка шёл без трамплина. */
void pop_fore_set_clip(int x, int y, int w, int h)
{
pop_t_fclip_x0 = x; pop_t_fclip_y0 = y;
pop_t_fclip_x1 = x + w; pop_t_fclip_y1 = y + h;
}
/* Ряд 0 комнаты СНИЗУ (fg-коды) — нужен draw_tile_topright/floorright, когда
* тайл нижнего ряда стал видимым (empty после падения loose): «стена вниз» =
* топрайт тайла room_B(0, col-1). 0 — нет комнаты снизу (кромка = стена). */
void pop_room_set_below(const uint8_t *below_row0_fg) { pop_t_below = below_row0_fg; }
/* Ряд 2 (fg-коды + модификаторы) комнаты СВЕРХУ — для полосы кладки у
* потолка (seg008 draw_room: доп. верхний ряд из room_A, draw_tile_aboveroom
* при draw_main_y=-1). 0 — нет комнаты сверху (кромка уровня → пол). */
void pop_room_set_above(const uint8_t *above_row2_fg, const uint8_t *above_row2_mod)
{ pop_t_above = above_row2_fg; pop_t_abovemod = above_row2_mod; }