/* * 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 #include #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; } }