/**
* Конвертация карт v1 (assets/maps/*.map — RLE) в раскладку областей v2:
* src/data/maps.json — по области {width, height, tiles (RLE), decor, props,
* blocked, tall}. Раскладка тайлов v1 переносится как есть (позиции NPC,
* переходов и квестов v1 в тайлах — сходятся с раскладкой), воксельная
* генерация делает из неё мир (src/areas.ts). Прогон: node tools/convertMaps.mjs
* (от корня v2/apps/game; путь к v1 — по умолчанию ../../v1/apps/game).
*/
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import path from 'node:path';
const ROOT = fileURLToPath(new URL('..', import.meta.url));
const V1_MAPS = process.argv[2] ?? path.resolve(ROOT, '../../../v1/apps/game/assets/maps');
const OUT = path.resolve(ROOT, 'src/data/maps.json');
/** Области v1 (порядок = порядок загрузки в игре). */
const AREAS = ['meadows', 'ponds', 'zvenets', 'rust_grove', 'old_siding', 'machine_hall', 'house_elder', 'shop'];
/** RLE-пары → плоский массив (распаковка на месте — parseMap v1 не импортируется). */
function rleDecode(pairs) {
const out = [];
for (const [id, run] of pairs) {
for (let k = 0; k < run; k++) out.push(id);
}
return out;
}
/** Плоский массив → RLE-пары (на случай raw-карты v1). */
function rleEncode(flat) {
const out = [];
for (let i = 0; i < flat.length; i++) {
if (i > 0 && flat[i] === flat[i - 1]) out[out.length - 1][1]++;
else out.push([flat[i], 1]);
}
return out;
}
const maps = {};
for (const id of AREAS) {
const raw = JSON.parse(readFileSync(path.join(V1_MAPS, `${id}.map`), 'utf8'));
if (raw.format !== 'rpg-map' || raw.version !== 1) throw new Error(`${id}: не карта rpg-map`);
maps[id] = {
width: raw.width,
height: raw.height,
// RLE как есть (сериализация маленькая); генератор распакует при сборке
tiles: raw.encoding === 'rle' ? raw.tiles : rleEncode(raw.tiles),
// blocked/tall/decor/props — по сути копия (высоты в юнитах уже)
blocked: raw.blocked,
tall: raw.tall ?? {},
decor: raw.decor ?? [],
props: raw.props ?? [],
};
}
mkdirSync(path.dirname(OUT), { recursive: true });
writeFileSync(OUT, JSON.stringify(maps));
const sizes = Object.entries(maps).map(([k, m]) => `${k} ${m.width}x${m.height}`);
console.log('ok →', path.relative(ROOT, OUT));
console.log(sizes.join(', '));