<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Fantasy City Ruler - Basic</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Fantasy City Ruler</h1>

    <div id="resource-bar">
        <span>Gold: <span id="gold">100</span></span> |
        <span>Mana: <span id="mana">50</span></span> |
        <span>Pop: <span id="population">0</span> / <span id="population-cap">5</span></span>
    </div>

    <div id="build-menu">
        <h2>Build</h2>
        <button data-building="House" data-cost-gold="50" data-cost-mana="0">House (+5 Pop Cap) - 50G</button>
        <button data-building="Mine" data-cost-gold="75" data-cost-mana="10">Mine (+2 Gold/sec) - 75G, 10M</button>
        <button data-building="Mana Well" data-cost-gold="30" data-cost-mana="60">Mana Well (+1 Mana/sec) - 30G, 60M</button>
        <!-- Add more buildings later -->
    </div>

    <div id="city-grid-container">
        <h2>Your City</h2>
        <div id="city-grid">
            <!-- Grid cells will be generated by JS -->
        </div>
    </div>

    <div id="message-log">
        <h2>Log</h2>
        <ul id="messages">
            <li>Welcome, Ruler! Build your city.</li>
        </ul>
    </div>

    <script src="script.js"></script>
</body>
</html>
body {
    font-family: sans-serif;
    display: flex;
    flex-direction: column;
    align-items: center;
    background-color: #f4f1e9;
    color: #3a3a3a;
}

#resource-bar {
    background-color: #d4cba8;
    padding: 10px 20px;
    border-radius: 5px;
    margin-bottom: 15px;
    border: 1px solid #a89e80;
    font-weight: bold;
}

#resource-bar span span { /* Target the value spans */
    color: #0056b3; /* Example color for values */
}
#resource-bar span #mana {
     color: #8a2be2; /* BlueViolet for mana */
}


#build-menu, #city-grid-container, #message-log {
    width: 80%;
    max-width: 700px;
    background-color: #e8e0c9;
    border: 1px solid #c8bda1;
    border-radius: 8px;
    padding: 15px;
    margin-bottom: 15px;
}

h1, h2 {
    text-align: center;
    color: #5a4d35;
}

#build-menu button {
    display: block;
    margin: 5px auto;
    padding: 8px 12px;
    background-color: #a4885a;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    transition: background-color 0.2s;
}

#build-menu button:hover {
    background-color: #8a6d40;
}

#build-menu button:disabled {
    background-color: #cccccc;
    cursor: not-allowed;
}

#city-grid {
    display: grid;
    grid-template-columns: repeat(10, 1fr); /* 10x10 grid */
    grid-template-rows: repeat(10, 1fr);
    width: 400px; /* Fixed size grid */
    height: 400px;
    margin: 15px auto;
    border: 2px solid #a89e80;
    gap: 2px; /* Small gap between cells */
    background-color: #c8bda1; /* Grid background */
}

.grid-cell {
    background-color: #f0ead6; /* Empty cell color */
    border: 1px solid #d8ccb0;
    cursor: pointer;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 1.5em; /* For building emojis/letters */
    transition: background-color 0.2s;
}

.grid-cell:hover {
    background-color: #e0d8c5;
}

/* Building styles */
.grid-cell.House { background-color: #b8a98f; content: '🏠'; }
.grid-cell.Mine { background-color: #8d8d8d; content: '⛏️'; }
.grid-cell.Mana.Well { background-color: #a890d8; content: '💧'; } /* Might need pseudo element for emoji */

/* Add emojis using ::after pseudo-elements for better control */
.grid-cell.House::after { content: '🏠'; }
.grid-cell.Mine::after { content: '⛏️'; }
.grid-cell.ManaWell::after { content: '💧'; } /* Use CSS safe class name */


#message-log ul {
    list-style: none;
    padding: 0;
    height: 100px;
    overflow-y: scroll;
    border: 1px solid #ccc;
    background-color: #fff;
    padding: 5px;
}

#message-log li {
    margin-bottom: 5px;
    font-size: 0.9em;
    border-bottom: 1px dashed #eee;
    padding-bottom: 3px;
}
#message-log li.event {
    color: purple;
    font-weight: bold;
}
document.addEventListener('DOMContentLoaded', () => {
    // --- DOM Elements ---
    const goldDisplay = document.getElementById('gold');
    const manaDisplay = document.getElementById('mana');
    const populationDisplay = document.getElementById('population');
    const populationCapDisplay = document.getElementById('population-cap');
    const buildMenu = document.getElementById('build-menu');
    const cityGrid = document.getElementById('city-grid');
    const messageList = document.getElementById('messages');

    // --- Game State ---
    let resources = {
        gold: 100,
        mana: 50,
        population: 0,
        populationCap: 5
    };
    let income = {
        gold: 1, // Base income
        mana: 0
    };
    const gridRows = 10;
    const gridCols = 10;
    let gridData = Array(gridRows).fill(null).map(() => Array(gridCols).fill(null)); // null = empty
    let selectedBuilding = null;

    // --- Event State ---
    let currentEvent = null; // { name, description, effect, duration }
    let eventTimer = null;
    const EVENT_CHANCE_PER_TICK = 0.01; // 1% chance per second

    // --- Building Definitions ---
    // Simple definitions - expand later
    const buildingDefs = {
        'House': { cost: { gold: 50, mana: 0 }, provides: { populationCap: 5 }, requiresPop: 0, symbol: '🏠', cssClass: 'House' },
        'Mine': { cost: { gold: 75, mana: 10 }, provides: { income: { gold: 2 } }, requiresPop: 1, symbol: '⛏️', cssClass: 'Mine' },
        'Mana Well': { cost: { gold: 30, mana: 60 }, provides: { income: { mana: 1 } }, requiresPop: 1, symbol: '💧', cssClass: 'ManaWell' } // CSS safe name
    };

    // --- Initialization ---
    function initGame() {
        renderResources();
        renderGrid();
        setupEventListeners();
        logMessage("Game Initialized. Start building!");
        // Start the main game loop (updates every second)
        setInterval(gameTick, 1000);
    }

    // --- Rendering Functions ---
    function renderResources() {
        goldDisplay.textContent = Math.floor(resources.gold);
        manaDisplay.textContent = Math.floor(resources.mana);
        populationDisplay.textContent = resources.population;
        populationCapDisplay.textContent = resources.populationCap;

        // Update button disabled state based on resources
        buildMenu.querySelectorAll('button').forEach(button => {
            const buildingType = button.dataset.building;
            if (!buildingType) return;
            const def = buildingDefs[buildingType];
            button.disabled = resources.gold < def.cost.gold || resources.mana < def.cost.mana;
        });
    }

    function renderGrid() {
        cityGrid.innerHTML = ''; // Clear grid
        for (let r = 0; r < gridRows; r++) {
            for (let c = 0; c < gridCols; c++) {
                const cell = document.createElement('div');
                cell.classList.add('grid-cell');
                cell.dataset.r = r;
                cell.dataset.c = c;

                const buildingType = gridData[r][c];
                if (buildingType) {
                    const def = buildingDefs[buildingType];
                    cell.classList.add(def.cssClass); // Add class for styling/emoji
                    // cell.textContent = def.symbol; // Add symbol directly (alternative to CSS pseudo-elements)
                    cell.title = buildingType; // Tooltip
                } else {
                    cell.addEventListener('click', handleGridCellClick);
                }
                cityGrid.appendChild(cell);
            }
        }
    }

    function logMessage(message, type = 'info') {
        const li = document.createElement('li');
        li.textContent = message;
        if(type === 'event') {
            li.classList.add('event');
        }
        messageList.prepend(li); // Add to top
        // Keep log from getting too long (optional)
        while (messageList.children.length > 20) {
            messageList.removeChild(messageList.lastChild);
        }
    }

    // --- Event Listeners ---
    function setupEventListeners() {
        // Build Menu Buttons
        buildMenu.querySelectorAll('button').forEach(button => {
            button.addEventListener('click', () => {
                selectedBuilding = button.dataset.building;
                // Optional: Add visual feedback for selection
                logMessage(`Selected: ${selectedBuilding}. Click on an empty grid cell to build.`);
            });
        });
    }

    function handleGridCellClick(event) {
        if (!selectedBuilding) return; // Nothing selected to build

        const cell = event.target;
        const r = parseInt(cell.dataset.r);
        const c = parseInt(cell.dataset.c);

        if (gridData[r][c] !== null) {
            logMessage("Cell is already occupied!");
            return;
        }

        const def = buildingDefs[selectedBuilding];

        // Check cost
        if (resources.gold < def.cost.gold || resources.mana < def.cost.mana) {
            logMessage("Not enough resources!");
            selectedBuilding = null; // Deselect
            return;
        }
        // Check population requirement
        if (resources.population + def.requiresPop > resources.populationCap) {
             logMessage("Not enough population capacity for workers!");
             // Don't deselect - they might build a house first
             return;
        }


        // --- Place Building ---
        // Deduct cost
        resources.gold -= def.cost.gold;
        resources.mana -= def.cost.mana;

        // Add building to grid
        gridData[r][c] = selectedBuilding;

        // Apply building benefits
         resources.population += def.requiresPop; // Assign population
        if (def.provides.populationCap) {
            resources.populationCap += def.provides.populationCap;
        }
        if (def.provides.income) {
            income.gold += def.provides.income.gold || 0;
            income.mana += def.provides.income.mana || 0;
        }

        logMessage(`Built ${selectedBuilding} at (${r},${c}).`);
        selectedBuilding = null; // Deselect after building
        renderGrid(); // Update grid visuals immediately
        renderResources(); // Update resource display and buttons
    }


    // --- Game Loop ---
    function gameTick() {
        let currentIncome = { ...income }; // Start with base income

        // Apply event effects
        if (currentEvent) {
            currentIncome = applyEventEffect(currentIncome);
            currentEvent.duration--;
            if (currentEvent.duration <= 0) {
                endCurrentEvent();
            }
        } else {
             // Try to trigger a new event
             if (Math.random() < EVENT_CHANCE_PER_TICK) {
                triggerRandomEvent();
             }
        }


        // Add resources based on calculated income
        resources.gold += currentIncome.gold;
        resources.mana += currentIncome.mana;


        // --- Update UI ---
        renderResources(); // Update resource display every tick

        // NOTE: Grid rendering is only done after building, not every tick, for performance.
    }

    // --- Magical Events ---
    function triggerRandomEvent() {
        const events = [
            { name: "Mana Surge", description: "Ley lines flare! Mana income doubled!", effect: (inc) => ({ ...inc, mana: inc.mana * 2 }), duration: 15 }, // 15 seconds
            { name: "Gold Rush", description: "Prospectors strike gold! Gold income doubled!", effect: (inc) => ({ ...inc, gold: inc.gold * 2 }), duration: 20 },
            { name: "Minor Curse", description: "A minor curse saps motivation. Gold income halved.", effect: (inc) => ({ ...inc, gold: inc.gold * 0.5 }), duration: 30 },
            { name: "Magical Dampening", description: "The ambient magic fades. Mana income halved.", effect: (inc) => ({ ...inc, mana: inc.mana * 0.5 }), duration: 25 },
        ];

        currentEvent = events[Math.floor(Math.random() * events.length)];
        logMessage(`EVENT: ${currentEvent.description} (Lasts ${currentEvent.duration}s)`, 'event');
    }

    function applyEventEffect(baseIncome) {
        if (!currentEvent || !currentEvent.effect) return baseIncome;
        return currentEvent.effect(baseIncome);
    }

    function endCurrentEvent() {
        if (!currentEvent) return;
        logMessage(`EVENT ENDED: ${currentEvent.name}`, 'event');
        currentEvent = null;
    }

    // --- Start Game ---
    initGame();
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.