100 lines
3.2 KiB
JavaScript
100 lines
3.2 KiB
JavaScript
import { MAP_H, MAP_W, SIZE } from "./mapUtils.js";
|
|
|
|
export const DEFAULT_WORLD_PADDING_X = MAP_W;
|
|
export const DEFAULT_WORLD_PADDING_Y = MAP_H;
|
|
|
|
const NEGATIVE_ONE_FIELDS = new Set([
|
|
"adminId",
|
|
"prefectureRegionId",
|
|
"regionId",
|
|
"municipalityId",
|
|
]);
|
|
|
|
function isCellField(value) {
|
|
return ArrayBuffer.isView(value) && typeof value.length === "number" && value.length === SIZE;
|
|
}
|
|
|
|
function defaultForField(name, Constructor) {
|
|
if (name === "sea") return 1;
|
|
if (name === "elevation") return 0.08;
|
|
if (name === "seaLevel") return undefined;
|
|
if (NEGATIVE_ONE_FIELDS.has(name)) return -1;
|
|
if (Constructor === Float32Array || Constructor === Float64Array) return 0;
|
|
return 0;
|
|
}
|
|
|
|
function makeWorldField(name, source, worldWidth, worldHeight, originX, originY) {
|
|
const Constructor = source.constructor;
|
|
const out = new Constructor(worldWidth * worldHeight);
|
|
const fallback = defaultForField(name, Constructor);
|
|
if (fallback !== 0) out.fill(fallback);
|
|
|
|
for (let y = 0; y < MAP_H; y++) {
|
|
const srcRow = y * MAP_W;
|
|
const dstRow = (originY + y) * worldWidth + originX;
|
|
for (let x = 0; x < MAP_W; x++) out[dstRow + x] = source[srcRow + x];
|
|
}
|
|
return out;
|
|
}
|
|
|
|
export function createWorldMap(initialMap, options = {}) {
|
|
const paddingX = Number.isFinite(options.paddingX) ? Math.max(0, Math.floor(options.paddingX)) : DEFAULT_WORLD_PADDING_X;
|
|
const paddingY = Number.isFinite(options.paddingY) ? Math.max(0, Math.floor(options.paddingY)) : DEFAULT_WORLD_PADDING_Y;
|
|
const worldWidth = MAP_W + paddingX * 2;
|
|
const worldHeight = MAP_H + paddingY * 2;
|
|
const originX = paddingX;
|
|
const originY = paddingY;
|
|
const fields = {};
|
|
|
|
for (const [name, value] of Object.entries(initialMap || {})) {
|
|
if (isCellField(value)) fields[name] = makeWorldField(name, value, worldWidth, worldHeight, originX, originY);
|
|
}
|
|
|
|
if (!fields.sea) {
|
|
fields.sea = new Uint8Array(worldWidth * worldHeight);
|
|
fields.sea.fill(1);
|
|
}
|
|
if (!fields.elevation) {
|
|
fields.elevation = new Float32Array(worldWidth * worldHeight);
|
|
fields.elevation.fill(0.08);
|
|
}
|
|
|
|
return {
|
|
seed: initialMap?.seed ?? 0,
|
|
width: worldWidth,
|
|
height: worldHeight,
|
|
originX,
|
|
originY,
|
|
sourceWidth: initialMap?.width || MAP_W,
|
|
sourceHeight: initialMap?.height || MAP_H,
|
|
sourceMap: initialMap,
|
|
fields,
|
|
invalidatedRects: [],
|
|
humanPatchHistory: [],
|
|
generatedRects: [{
|
|
x0: originX,
|
|
y0: originY,
|
|
x1: originX + MAP_W,
|
|
y1: originY + MAP_H,
|
|
terrainType: initialMap?.terrainTemplate?.terrainType || initialMap?.terrainDebug?.terrainType || "auto",
|
|
label: initialMap?.terrainTemplate?.terrainTypeLabel || initialMap?.terrainDebug?.terrainTypeLabel || "Initial generation",
|
|
}],
|
|
};
|
|
}
|
|
|
|
export function createInitialCamera(world) {
|
|
return {
|
|
x: world?.originX || 0,
|
|
y: world?.originY || 0,
|
|
};
|
|
}
|
|
|
|
export function clampCameraToWorld(camera, world, viewWidth = MAP_W, viewHeight = MAP_H) {
|
|
if (!camera || !world) return { x: 0, y: 0 };
|
|
const maxX = Math.max(0, world.width - viewWidth);
|
|
const maxY = Math.max(0, world.height - viewHeight);
|
|
return {
|
|
x: Math.min(Math.max(Math.round(camera.x || 0), 0), maxX),
|
|
y: Math.min(Math.max(Math.round(camera.y || 0), 0), maxY),
|
|
};
|
|
}
|