summary refs log tree commit diff stats
path: root/tinyc/tcctok.h
Commit message (Expand)AuthorAgeFilesLines
* Fix typosFederico Ceratto2015-02-151-1/+1
* Removes executable bit for text files.Grzegorz Adam Hankiewicz2013-03-161-0/+0
* tiny C support; cosmetic improvements for the docsAraq2010-08-281-0/+469
'n48' href='#n48'>48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 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;