import type { TileMapData } from './IsometricTileMap';
/**
* Миникарта: чистый рендер TileMapData в RGBA-картинку (без Pixi — движок
* не знает про текстуры; в пиксельную текстуру картинку превращает игра).
* Схема «вид сверху»: клетка сетки = тайл, цвет — из палитры вызывающей
* стороны (Record<id тайла, 0xRRGGBB>). Незаданные тайлы — fallbackColor.
*/
export interface MinimapMarker {
/** Тайловые координаты точки интереса. */
x: number;
y: number;
/** Цвет маркера (0xRRGGBB). */
color: number;
}
export interface MinimapOptions {
/** Цвет клетки по id тайла (0xRRGGBB). */
colors: Record<number, number>;
/** Цвет тайла без записи в colors (по умолчанию тёмный). */
fallbackColor?: number;
/** Размер клетки в пикселях (2–3 читаются лучше всего). */
cell?: number;
/** Точки интереса поверх карты (герой, переходы, NPC). */
markers?: MinimapMarker[];
}
/** Результат рендера: RGBA-байты, 4 на пиксель. */
export interface MinimapImage {
width: number;
height: number;
rgba: Uint8Array;
}
/** 0xRRGGBB → [r, g, b]. */
function rgbOf(color: number): [number, number, number] {
return [(color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff];
}
/**
* Отрисовать карту в пиксельную картинку: сетка width×height клеток
* (cell px каждая), маркеры закрашивают свою клетку поверх.
*/
export function renderMinimap(data: TileMapData, opts: MinimapOptions): MinimapImage {
const cell = opts.cell ?? 3;
const width = data.width * cell;
const height = data.height * cell;
const rgba = new Uint8Array(width * height * 4);
const put = (x: number, y: number, [r, g, b]: [number, number, number]): void => {
const i = (y * width + x) * 4;
rgba[i] = r;
rgba[i + 1] = g;
rgba[i + 2] = b;
rgba[i + 3] = 255;
};
for (let ty = 0; ty < data.height; ty++) {
for (let tx = 0; tx < data.width; tx++) {
const id = data.tiles[ty * data.width + tx]!;
const color = rgbOf(opts.colors[id] ?? opts.fallbackColor ?? 0x1a1a20);
for (let dy = 0; dy < cell; dy++) {
for (let dx = 0; dx < cell; dx++) put(tx * cell + dx, ty * cell + dy, color);
}
}
}
// Маркеры: закрашенная клетка с рамкой цвета фона — читается на любом поле.
for (const m of opts.markers ?? []) {
if (m.x < 0 || m.y < 0 || m.x >= data.width || m.y >= data.height) continue;
const [r, g, b] = rgbOf(m.color);
for (let dy = 0; dy < cell; dy++) {
for (let dx = 0; dx < cell; dx++) {
const border = dx === 0 || dy === 0 || dx === cell - 1 || dy === cell - 1;
put(m.x * cell + dx, m.y * cell + dy, border ? [20, 20, 24] : [r, g, b]);
}
}
}
return { width, height, rgba };
}