about summary refs log tree commit diff stats
path: root/js/magic-bird/map.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/magic-bird/map.js')
-rw-r--r--js/magic-bird/map.js209
1 files changed, 209 insertions, 0 deletions
diff --git a/js/magic-bird/map.js b/js/magic-bird/map.js
new file mode 100644
index 0000000..212bbfa
--- /dev/null
+++ b/js/magic-bird/map.js
@@ -0,0 +1,209 @@
+const canvas = document.getElementById('map');
+const ctx = canvas.getContext('2d');
+canvas.width = window.innerWidth;
+canvas.height = window.innerHeight;
+
+const cellSize = 16; // Size of each cell in pixels
+const gridWidth = 100; // Number of cells in width
+const gridHeight = 100; // Number of cells in height
+
+let grid = [];
+let history = []; // undo stack
+let offsetX = 0;
+let offsetY = 0;
+let selectedNumber = 0;
+
+const initializeGrid = () => {
+    grid = Array.from({ length: gridHeight }, () => Array(gridWidth).fill(0));
+};
+
+// a hack to preload map assets
+const preLoad = [
+    'imgs/extracted-1688-map/MapParts/trees/50.png',
+    'imgs/extracted-1688-map/MapParts/hills/8.png',
+    'imgs/extracted-1688-map/MapParts/mountains/18.png',
+    'imgs/extracted-1688-map/MapParts/towns/9.png',
+    'imgs/extracted-1688-map/MapParts/cities/33.png',
+].map(src => {
+    let images = new Image();
+    images.src = src;
+    return images;
+});
+
+const drawGrid = () => {
+    ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+    if (
+        offsetX < 0 ||
+        offsetX > gridWidth * cellSize - canvas.width ||
+        offsetY < 0 ||
+        offsetY > gridHeight * cellSize - canvas.height
+    ) {
+        ctx.fillStyle = '#91f7bd';
+        ctx.fillRect(0, 0, canvas.width, canvas.height);
+    }
+
+    grid.forEach((row, i) => {
+        row.forEach((state, j) => {
+            let color = '#000';
+            let imageSrc = '';
+            switch (state) {
+                case 0:
+                    color = 'beige';
+                    break;
+                case 1:
+                    imageSrc = 'imgs/extracted-1688-map/MapParts/trees/50.png'
+                    break;
+                case 2:
+                    imageSrc = 'imgs/extracted-1688-map/MapParts/hills/8.png';
+                    break;
+                case 3:
+                    imageSrc = 'imgs/extracted-1688-map/MapParts/mountains/18.png';
+                    break;
+                case 4:
+                    imageSrc = 'imgs/extracted-1688-map/MapParts/towns/9.png';
+                    break;
+                case 5:
+                    imageSrc = 'imgs/extracted-1688-map/MapParts/cities/33.png';
+                    break;
+                case 6:
+                    color = '#f0f';
+                    break;
+                case 7:
+                    color = '#0ff';
+                    break;
+                case 8:
+                    color = '#f80';
+                    break;
+                case 9:
+                    color = '#08f';
+                    break;
+            }
+            if (imageSrc) {
+                ctx.fillStyle = 'beige';
+                ctx.fillRect(j * cellSize - offsetX, i * cellSize - offsetY, cellSize, cellSize);
+                ctx.strokeStyle = '#ddd';
+                ctx.strokeRect(j * cellSize - offsetX, i * cellSize - offsetY, cellSize, cellSize);
+                const image = new Image();
+                image.src = imageSrc;
+                ctx.drawImage(image, j * cellSize - offsetX, i * cellSize - offsetY, cellSize, cellSize);
+            } else {
+                ctx.fillStyle = color;
+                ctx.fillRect(j * cellSize - offsetX, i * cellSize - offsetY, cellSize, cellSize);
+                ctx.strokeStyle = '#ddd';
+                ctx.strokeRect(j * cellSize - offsetX, i * cellSize - offsetY, cellSize, cellSize);
+            }
+        });
+    });
+};
+
+const saveGrid = () => {
+    localStorage.setItem('grid', JSON.stringify(grid));
+};
+
+const loadGrid = () => {
+    const savedGrid = localStorage.getItem('grid');
+    if (savedGrid) {
+        grid = JSON.parse(savedGrid);
+    }
+};
+
+const handleKeyDown = (e) => {
+    switch (e.key) {
+        case 'ArrowUp':
+            offsetY -= cellSize;
+            break;
+        case 'ArrowDown':
+            offsetY += cellSize;
+            break;
+        case 'ArrowLeft':
+            offsetX -= cellSize;
+            break;
+        case 'ArrowRight':
+            offsetX += cellSize;
+            break;
+        case 'h':
+            alert(`Controls:
+                - Arrow keys to move the map
+                - Click to place a tile
+                - Number keys, 0 - 9, to select a tile type
+                - Z to undo
+                - C to clear the grid
+                - E to export the grid as json
+                - S to export the grid as a png
+                - H to display this help text
+            `);
+            break;
+        case 'z':
+            if (history.length > 0) {
+                const lastChange = history.pop(); // Pop last change from history
+                grid[lastChange.y][lastChange.x] = lastChange.state; // Revert state
+                drawGrid();
+            }
+            break;
+        case 'c':
+            if (window.confirm('Are you sure you want to clear the grid?')) {
+                initializeGrid();
+                drawGrid();
+            }
+            break;
+        case 'e':
+            const mapName = prompt('Please enter a name for the map:');
+            if (mapName) {
+                if (window.confirm(`Are you sure you want to export the grid as ${mapName}?`)) {
+                    exportGridAsJson(mapName);
+                }
+            }
+            break;
+        case 's':
+            const imgName = prompt('Please enter a name for the image:');
+            if (imgName) {
+                exportGridAsPng(imgName);
+            }
+            break;
+        default:
+            if (e.key >= '0' && e.key <= '9') {
+                selectedNumber = parseInt(e.key);
+            }
+            break;
+    }
+    drawGrid();
+};
+
+const handleCanvasClick = (e) => {
+    const x = Math.floor((e.clientX + offsetX) / cellSize);
+    const y = Math.floor((e.clientY + offsetY) / cellSize);
+    history.push({ x, y, state: grid[y][x] }); // Push current state to history
+    grid[y][x] = selectedNumber; // Set state to selectedNumber
+    drawGrid();
+};
+
+const exportGridAsJson = (mapName) => {
+    const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(grid));
+    const downloadAnchorNode = document.createElement('a');
+    downloadAnchorNode.setAttribute("href", dataStr);
+    downloadAnchorNode.setAttribute("download", `${mapName}.json`);
+    document.body.appendChild(downloadAnchorNode); // evidently this is required for firefox
+    downloadAnchorNode.click();
+    downloadAnchorNode.remove();
+};
+
+const exportGridAsPng = (imgName) => {
+    const dataUrl = canvas.toDataURL('image/png');
+    const downloadAnchorNode = document.createElement('a');
+    downloadAnchorNode.setAttribute("href", dataUrl);
+    downloadAnchorNode.setAttribute("download", `${imgName}.png`);
+    document.body.appendChild(downloadAnchorNode);
+    downloadAnchorNode.click();
+    downloadAnchorNode.remove();
+};
+
+window.addEventListener('keydown', handleKeyDown);
+canvas.addEventListener('click', handleCanvasClick);
+window.onload = () => {
+    initializeGrid();
+    loadGrid();
+    drawGrid();
+};
+
+window.onunload = saveGrid;
\ No newline at end of file
#n445'>445 446 447 448 449 450 451 452 453 454