94 lines
6.1 KiB
JavaScript
94 lines
6.1 KiB
JavaScript
// Shared world colours, minimap and full map.
|
|
let MAP_S = 2;
|
|
const MAP = { canvas: document.createElement('canvas'), image: null, w: 0, h: 0, init: 0, rr: 0, near: 0, miniT: 0, fullT: 0, x: 0, y: 0, zoom: 1, drag: null };
|
|
function resetMap() {
|
|
MAP_S = W > 4096 ? 4 : 2; MAP.w = W; MAP.h = H; MAP.fog = SET.fog;
|
|
MAP.canvas.width = Math.ceil(W / MAP_S); MAP.canvas.height = Math.ceil(H / MAP_S);
|
|
MAP.ctx = MAP.canvas.getContext('2d'); MAP.image = MAP.ctx.createImageData(MAP.canvas.width, MAP.canvas.height);
|
|
MAP.init = MAP.rr = MAP.near = MAP.miniT = MAP.fullT = 0;
|
|
if (![1, 2, 4, 8, 16].includes(SET.minimapZoom)) SET.minimapZoom = 4;
|
|
}
|
|
function mapArea(cx, cy) {
|
|
const s = MAP_S, x0 = cx * 32, y0 = cy * 32, x1 = Math.min(W, x0 + 32), y1 = Math.min(H, y0 + 32), data = MAP.image.data, mw = MAP.canvas.width;
|
|
for (let y = y0; y < y1; y += s) for (let x = x0; x < x1; x += s) {
|
|
const xx = Math.min(W - 1, x + s / 2), yy = Math.min(H - 1, y + s / 2), seen = SET.fog ? fogSeen(xx, yy) : 255;
|
|
let m = mat[yy * W + xx];
|
|
if (!m || PH[m] === PH_GAS) for (let c = 0; c < 4; c++) {
|
|
const k = mat[Math.min(H - 1, y + (c >> 1) * (s - 1)) * W + Math.min(W - 1, x + (c & 1) * (s - 1))];
|
|
if (k && PH[k] !== PH_GAS) { m = k; break; }
|
|
}
|
|
const sky = yy < surfY[xx], f = seen < 64 ? 0 : seen / 255, i = (y / s * mw + x / s) * 4;
|
|
data[i] = (m ? COLR[m] : sky ? 78 : 20) * f;
|
|
data[i + 1] = (m ? COLG[m] : sky ? 114 : 18) * f;
|
|
data[i + 2] = (m ? COLB[m] : sky ? 142 : 17) * f; data[i + 3] = 255;
|
|
}
|
|
MAP.ctx.putImageData(MAP.image, 0, 0, x0 / s, y0 / s, (x1 - x0) / s, (y1 - y0) / s);
|
|
}
|
|
function updateMap(now) {
|
|
if (!GAME.running || GAME.loading) return;
|
|
$('minimap').hidden = !SET.minimap;
|
|
if (!SET.minimap && $('m-map').hidden) return;
|
|
if (MAP.w !== W || MAP.h !== H || MAP.fog !== SET.fog) resetMap();
|
|
const nx = Math.ceil(W / 32), ny = Math.ceil(H / 32), total = nx * ny;
|
|
if (MAP.init < total) {
|
|
const end = performance.now() + 8;
|
|
do { const n = MAP.init++; mapArea(n % nx, Math.floor(n / nx)); } while (MAP.init < total && performance.now() < end);
|
|
if (MAP.init === total) MAP.fullT = MAP.miniT = 0;
|
|
} else {
|
|
mapArea(Math.max(0, Math.min(nx - 1, Math.floor(bot.x / 32))), Math.max(0, Math.min(ny - 1, Math.floor(bot.y / 32))));
|
|
const rx = Math.ceil(R.bw / 32), ry = Math.ceil(R.bh / 32), span = rx * 2 + 1;
|
|
for (let n = 0; n < 15; n++) {
|
|
const k = MAP.near++ % (span * (ry * 2 + 1)), x = Math.floor(bot.x / 32) - rx + k % span, y = Math.floor(bot.y / 32) - ry + Math.floor(k / span);
|
|
if (x >= 0 && y >= 0 && x < nx && y < ny) mapArea(x, y);
|
|
}
|
|
for (let n = 0; n < 8; n++) { const k = MAP.rr++ % total; mapArea(k % nx, Math.floor(k / nx)); }
|
|
}
|
|
if (SET.minimap && now >= MAP.miniT) { MAP.miniT = now + 100; drawMap($('mini-canvas'), bot.x, bot.y, 1 / SET.minimapZoom, false); }
|
|
if (!$('m-map').hidden && now >= MAP.fullT) { MAP.fullT = now + 1000; drawFullMap(); }
|
|
}
|
|
function drawMap(c, x, y, z, full) {
|
|
const ctx = c.getContext('2d'), w = c.width, h = c.height;
|
|
ctx.imageSmoothingEnabled = false; ctx.fillStyle = '#080706'; ctx.fillRect(0, 0, w, h);
|
|
ctx.drawImage(MAP.canvas, w / 2 - x * z, h / 2 - y * z, W * z, H * z);
|
|
const marker = (mx, my, colour, label) => {
|
|
const px = w / 2 + (mx - x) * z, py = h / 2 + (my - y) * z;
|
|
if (px < 0 || py < 0 || px > w || py > h) return;
|
|
ctx.fillStyle = '#080706'; ctx.fillRect(px - 4, py - 4, 8, 8); ctx.fillStyle = colour; ctx.fillRect(px - 2, py - 2, 4, 4);
|
|
if (full) { ctx.font = '13px sans-serif'; ctx.lineWidth = 3; ctx.strokeStyle = '#080706'; const ly = label === 'Trade dock' ? py + 17 : py - 7; ctx.strokeText(label, px + 7, ly); ctx.fillText(label, px + 7, ly); }
|
|
};
|
|
for (const m of machines) if (m && m.type === 'dock' && (!SET.fog || fogSeen(m.x, m.y) >= 64)) marker(m.x + m.w / 2, m.y + m.h / 2, '#e59a52', 'Trade dock');
|
|
marker(bot.x, bot.y, '#c9fff2', 'You are here');
|
|
}
|
|
function mapFit() { const c = $('map-canvas'); return Math.min(c.clientWidth / W, c.clientHeight / H); }
|
|
function drawFullMap() {
|
|
if (GAME.loading || !GAME.running || $('m-map').hidden || !MAP.image) return;
|
|
const c = $('map-canvas'); c.width = Math.max(1, c.clientWidth); c.height = Math.max(1, c.clientHeight);
|
|
MAP.zoom = Math.max(mapFit(), Math.min(4, MAP.zoom));
|
|
const hx = c.width / (2 * MAP.zoom), hy = c.height / (2 * MAP.zoom);
|
|
MAP.x = hx >= W / 2 ? W / 2 : Math.max(hx, Math.min(W - hx, MAP.x));
|
|
MAP.y = hy >= H / 2 ? H / 2 : Math.max(hy, Math.min(H - hy, MAP.y));
|
|
drawMap(c, MAP.x, MAP.y, MAP.zoom, true);
|
|
}
|
|
function openMap() {
|
|
if (!GAME.running || GAME.loading) return;
|
|
openModal('m-map'); MAP.x = bot.x; MAP.y = bot.y; MAP.zoom = mapFit(); drawFullMap();
|
|
}
|
|
function zoomMap(factor, px, py) {
|
|
const c = $('map-canvas'), old = MAP.zoom, z = Math.max(mapFit(), Math.min(4, old * factor));
|
|
MAP.x += ((px === undefined ? c.width / 2 : px) - c.width / 2) * (1 / old - 1 / z);
|
|
MAP.y += ((py === undefined ? c.height / 2 : py) - c.height / 2) * (1 / old - 1 / z);
|
|
MAP.zoom = z; drawFullMap();
|
|
}
|
|
function zoomMinimap(d) { SET.minimapZoom = Math.max(1, Math.min(16, SET.minimapZoom * (d > 0 ? 0.5 : 2))); saveSettings(); MAP.miniT = 0; }
|
|
$('mini-plus').onclick = () => zoomMinimap(1);
|
|
$('mini-minus').onclick = () => zoomMinimap(-1);
|
|
$('mini-map').onclick = openMap;
|
|
$('map-plus').onclick = () => zoomMap(2);
|
|
$('map-minus').onclick = () => zoomMap(0.5);
|
|
$('map-centre').onclick = () => { MAP.x = bot.x; MAP.y = bot.y; drawFullMap(); };
|
|
$('map-canvas').addEventListener('wheel', e => { e.preventDefault(); const r = e.currentTarget.getBoundingClientRect(); zoomMap(e.deltaY < 0 ? 1.25 : 0.8, e.clientX - r.left, e.clientY - r.top); }, { passive: false });
|
|
$('map-canvas').onpointerdown = e => { if (e.button !== 0) return; MAP.drag = [e.clientX, e.clientY]; e.currentTarget.setPointerCapture(e.pointerId); };
|
|
$('map-canvas').onpointermove = e => { if (!MAP.drag) return; MAP.x -= (e.clientX - MAP.drag[0]) / MAP.zoom; MAP.y -= (e.clientY - MAP.drag[1]) / MAP.zoom; MAP.drag = [e.clientX, e.clientY]; drawFullMap(); };
|
|
$('map-canvas').onpointerup = $('map-canvas').onpointercancel = () => { MAP.drag = null; };
|
|
window.addEventListener('resize', drawFullMap);
|