/*
 * room.c — вся логика комнаты, ОБЫЧНЫЙ HOME-файл (без --bank).
 *
 * 2026-07-15/16: изначально была банковская (--bank 1), сначала в W3
 * (huge-дефолт), потом пробовали W1 (--memory big) — оба варианта
 * упирались в проблемы (W3 конфликтует с gfx_blit_part/atlas_load,
 * которые сами трогают W3; W1-банк несовместим с CODE=W1 — трамплин
 * сам бы уехал из W1; --memory big тесно — CODE+DATA+BSS ~20КБ, не
 * лезет в один 16КБ).  После замены sprintf() на ручное hex-форматирование
 * пути (экономия ~2.9КБ — sprintf/vsprintf тянули за собой заметный
 * кусок форматирующего кода, единственный потребитель в HOME) всё
 * снова влезает в W1 обычным HOME-кодом — банк ОКАЗАЛСЯ НЕ НУЖЕН.
 * Так проще: gfx_blit_part()/atlas_load() (трогают W3 транзитивно)
 * теперь просто обычные HOME-функции, без всяких W1/W3-танцев.
 *
 * gfx_blit_part пишет ПРЯМО в текущий банк (видео-ОЗУ + теневая копия
 * при GFX_BANK_NORMAL) — перманентно, не через sprite_t.  Вызывающий
 * код обязан позвать room_draw() на КАЖДУЮ из двух страниц дабл-буфера
 * при входе в комнату, иначе heal спрайтов увидит фон только на одной
 * странице.
 */
#include <stdio.h>
#include <gfx.h>
#include "room.h"

/* 32x64 на тайл: 3*64+8=200 — сходится с разрешением DOS 320x200
 * (8px внизу — под полоску жизней/строку текста, не часть игрового
 * поля).  Уточнить точнее, когда будут готовы настоящие ассеты. */
uint8_t room_row_h[ROOM_ROWS] = {64, 64, 64};
tile_atlas_t tile_atlas[32];

int tile_atlas_load(const char *dir)
{
    static const char HEXD[] = "0123456789abcdef";
    char path[64];
    int i, count = 0;

    for (i = 0; i < 32; i++) {
        /* Вручную, не sprintf("%stile%02x.atl",...) — единственный
         * потребитель printf-семейства в этом приложении, тянул за
         * собой ~2.9КБ форматирующего кода; формат тут фиксированный
         * (2 hex-цифры). */
        char *p = path;
        const char *s = dir;
        while (*s) *p++ = *s++;
        s = "tile";
        while (*s) *p++ = *s++;
        *p++ = HEXD[(i >> 4) & 0xF];
        *p++ = HEXD[i & 0xF];
        s = ".atl";
        while (*s) *p++ = *s++;
        *p = '\0';
        if (atlas_load(&tile_atlas[i].at, path) == 0) {
            tile_atlas[i].loaded = 1;
            count++;
        } else {
            tile_atlas[i].loaded = 0;
        }
    }
    return count;
}

void tile_atlas_free(void)
{
    int i;

    for (i = 0; i < 32; i++) {
        if (tile_atlas[i].loaded) {
            atlas_free(&tile_atlas[i].at);
            tile_atlas[i].loaded = 0;
        }
    }
}

int level_load_room(level_t *lv, uint8_t room, const char *path)
{
    FILE *f = fopen(path, "rb");
    uint8_t buf[ROOM_TILES * 2 + 3];   /* fore[30]+back[30]+start_room/pos/dir */
    int i;

    if (!f)
        return -1;
    if (fread(buf, 1, sizeof(buf), f) != sizeof(buf)) {
        fclose(f);
        return -1;
    }
    fclose(f);

    for (i = 0; i < ROOM_TILES; i++) {
        tile_t *t = level_tile(lv, room, (uint8_t)(i % ROOM_COLS),
                               (uint8_t)(i / ROOM_COLS));
        t->type  = buf[i];
        t->state = buf[ROOM_TILES + i];
    }
    lv->start_room      = buf[ROOM_TILES * 2];
    lv->start_location  = buf[ROOM_TILES * 2 + 1];
    lv->start_direction = (int8_t)buf[ROOM_TILES * 2 + 2];
    return 0;
}

/* _bgi_blit_rows_raw держит ОДИН DI на весь блит (см. её шапку) —
 * вызывающий обязан резать блиты выше 16 строк на чанки, иначе окно
 * DI слишком длинное (риск сорвать кадровую цепочку IRQ/CBL).  Наши
 * тайлы 64px высотой — режем на чанки по CHUNK_H строк. */
#define CHUNK_H  16

void room_draw(level_t *lv, uint8_t room)
{
    int row, col, y = 0;

    for (row = 0; row < ROOM_ROWS; row++) {
        int x = 0;
        uint8_t fh = room_row_h[row];

        for (col = 0; col < ROOM_COLS; col++) {
            tile_t *t = level_tile(lv, room, (uint8_t)col, (uint8_t)row);
            uint8_t type = TILE_TYPE(t->type);

            if (tile_atlas[type].loaded) {
                uint8_t count = tile_atlas[type].at.count;
                uint8_t variant = 0;
                uint8_t is_var;

                if (count != 0) {
                    switch (type) {
                        case TILE_SPIKES:
                        case TILE_GATE:
                        case TILE_TAPESTRY:
                        case TILE_TAPESTRY_TOP:
                        case TILE_CHOPPER:
                        case TILE_POTION:
                            is_var = 1;
                            break;
                        default:
                            is_var = 0;
                    }
                    variant = is_var
                        ? (uint8_t)(t->state % count)
                        : (uint8_t)((room * 31u + col * 7u + row * 13u) % count);
                }
                const void *img = atlas_image(&tile_atlas[type].at, 0);
                uint8_t sub_y;

                gfx_w0_map(tile_atlas[type].at.page);
                for (sub_y = 0; sub_y < fh; sub_y = (uint8_t)(sub_y + CHUNK_H)) {
                    uint8_t chunk = (uint8_t)(fh - sub_y);
                    if (chunk > CHUNK_H)
                        chunk = CHUNK_H;
                    gfx_blit_part(x, y + sub_y, img, variant * ROOM_TILE_W,
                                 sub_y, ROOM_TILE_W, chunk);
                }
                gfx_w0_unmap();
            }
            x += ROOM_TILE_W;
        }
        y += fh;
    }
}
