Elethor Stats Comparison

Spire simulator

目前為 2025-03-23 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Elethor Stats Comparison
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Spire simulator
// @author       Eugene
// @match        https://elethor.com/*
// @grant        none
// @license      GPL-3.0-or-later
// ==/UserScript==
/*
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */
(function() {
    'use strict';

    const stats = [
        'MIN DAMAGE',
        'MAX DAMAGE',
        'HEALTH',
        'BREACH',
        'BARRIER',
        'CRIT CHANCE',
        'CRIT DAMAGE',
        'BLOCK CHANCE',
        'BLOCK AMOUNT'
    ];
let simulationLogs = []; // Store combat log elements for each simulation

    // Object to store selected modifiers
    let selectedModifiers = {};
// Functions to handle localStorage
function saveToLocalStorage(key, data) {
    try {
        localStorage.setItem(key, JSON.stringify(data));
    } catch (error) {
        console.error('Error saving to localStorage:', error);
    }
}

function loadFromLocalStorage(key) {
    try {
        const data = localStorage.getItem(key);
        return data ? JSON.parse(data) : null;
    } catch (error) {
        console.error('Error loading from localStorage:', error);
        return null;
    }
}
   // Function to calculate final stats after confirm modifiers is pressed.
// It processes modifiers in the following order for each stat:
//  1. Add up all Base [stat] modifiers (floored) and add to starting value.
//  2. Apply Base [firstStat] MINUS [secondStat] modifiers if applicable.
//  3. Sum all Increased [stat] modifiers, floor that sum, and then multiply by (1 + (floored sum)/100).
//  4. Floor the final result.
function calculateTotalStats() {
    // Create a copy of userStats (as numbers) so we can work with each key
    const totals = {};
    for (const key in userStats) {
        totals[key] = parseFloat(userStats[key]) || 0;
    }

    console.log('Starting calculation with base stats:', {...totals});
    console.log('Processing modifiers:', Object.keys(selectedModifiers).length, selectedModifiers);

    // --- Step 1: Process Base [stat] modifiers (excluding MINUS) ---
    Object.values(selectedModifiers).forEach(modifier => {
        if (modifier.name.startsWith('Base ') && !modifier.name.includes('MINUS')) {
            // Determine the stat key from the modifier
            const modKey = modifier.name.replace('Base ', '').toLowerCase().replace(/ /g, '_');
            const addValue = Math.floor(parseFloat(modifier.value));

            console.log(`Applying Base modifier: ${modifier.name} (${addValue}) from ${modifier.tree}:${modifier.anchor}`);

            if (modKey === 'damage') {
                // For damage, add to both min_damage and max_damage
                if (totals['min_damage'] !== undefined) {
                    totals['min_damage'] += addValue;
                }
                if (totals['max_damage'] !== undefined) {
                    totals['max_damage'] += addValue;
                }
            } else if (modKey === 'block') {
                // For Base Block, assume it applies to block_amount
                if (totals['block_amount'] !== undefined) {
                    totals['block_amount'] += addValue;
                }
            } else {
                // Otherwise, add to the matching stat if it exists
                if (totals[modKey] !== undefined) {
                    totals[modKey] += addValue;
                }
            }
        }
    });

    // --- Step 2: Apply Base [stat1] MINUS [stat2] Modifiers ---
    Object.values(selectedModifiers).forEach(modifier => {
        if (/^Base\s+/i.test(modifier.name) && /MINUS/i.test(modifier.name)) {
            const modStr = modifier.name.replace(/^Base\s+/i, '');
            const parts = modStr.split(/\s+MINUS\s+/i);
            if (parts.length !== 2) return;

            const stat1 = parts[0].toLowerCase().replace(/ /g, '_');
            const stat2 = parts[1].toLowerCase().replace(/ /g, '_');
            const modValue = Math.floor(parseFloat(modifier.value));

            console.log(`Applying MINUS modifier: ${modifier.name} (${modValue}) from ${modifier.tree}:${modifier.anchor}`);

            if (stat1 === 'breach' && stat2 === 'barrier') {
                if (totals['breach'] !== undefined) totals['breach'] += modValue;
                if (totals['barrier'] !== undefined) totals['barrier'] -= modValue;
            } else if (stat1 === 'barrier' && stat2 === 'breach') {
                if (totals['breach'] !== undefined) totals['breach'] -= modValue;
                if (totals['barrier'] !== undefined) totals['barrier'] += modValue;
            } else if (stat1 === 'health' && stat2 === 'damage') {
                if (totals['health'] !== undefined) totals['health'] += modValue;
                if (totals['min_damage'] !== undefined) totals['min_damage'] -= Math.floor(modValue / 3);
                if (totals['max_damage'] !== undefined) totals['max_damage'] -= Math.floor(modValue / 3);
            } else if (stat1 === 'damage' && stat2 === 'health') {
                if (totals['min_damage'] !== undefined) totals['min_damage'] += modValue;
                if (totals['max_damage'] !== undefined) totals['max_damage'] += modValue;
                if (totals['health'] !== undefined) totals['health'] -= Math.floor(modValue * 3);
            }
        }
    });

    // --- Step 3: Process Increased [stat] modifiers ---
    const incSums = {}; // e.g., incSums['health'] = total increased percentage (before dividing by 100)
    Object.values(selectedModifiers).forEach(modifier => {
        if (/^Increase(d)?\s+/.test(modifier.name)) {
            const statKey = modifier.name.replace(/^Increase(d)?\s+/, '').toLowerCase().replace(/ /g, '_');
            // Sum raw values
            incSums[statKey] = (incSums[statKey] || 0) + parseFloat(modifier.value);
            console.log(`Adding Increased modifier: ${modifier.name} (${modifier.value}) from ${modifier.tree}:${modifier.anchor}`);
        }
    });

    // Now apply increased modifiers for each stat
    for (const stat in incSums) {
        // Floor the sum for the increased modifiers
        const totalIncrease = Math.floor(incSums[stat]);
        // Compute multiplier
        const multiplier = 1 + totalIncrease / 100;
        console.log(`Applying Increased modifier for ${stat}: +${totalIncrease}% (x${multiplier.toFixed(2)})`);

        // Special case: if stat is "damage" then apply to both min_damage and max_damage
        if (stat === 'damage') {
            if (totals['min_damage'] !== undefined) {
                totals['min_damage'] = Math.floor(totals['min_damage'] * multiplier);
            }
            if (totals['max_damage'] !== undefined) {
                totals['max_damage'] = Math.floor(totals['max_damage'] * multiplier);
            }
        } else if (stat === 'block') {
            if (totals['block_amount'] !== undefined) {
                totals['block_amount'] = Math.floor(totals['block_amount'] * multiplier);
            }
        } else {
            if (totals[stat] !== undefined) {
                totals[stat] = Math.floor(totals[stat] * multiplier);
            }
        }
    }

    console.log('Final calculated stats:', {...totals});

    // Return the totals as strings (if needed)
    const finalTotals = {};
    for (const key in totals) {
        finalTotals[key] = totals[key].toString();
    }
    return finalTotals;
}

function logSelectedModifiers() {
    console.log('Currently selected modifiers:');
    Object.entries(selectedModifiers).forEach(([key, mod]) => {
        console.log(`${key}: ${mod.name} (${mod.value})`);
    });
}

    // Object to store all stat values
    let monsterStats = {};
    let modifiersData = {};
    let userStats = {};
    let autoMonsterStats = false;
    let currentFloor = 1;
    // We'll also use this container for simulation results.
    let simulationResultsContainer = null;

    function calculateDamageMultiplier(breach, barrier) {
        if (breach > barrier) {
            return 4 * (2 / Math.PI) * Math.atan((breach - barrier) / Math.sqrt(breach * barrier)) + 1;
        } else {
            return Math.max(0.25, (2 / Math.PI) * Math.atan((breach - barrier) / Math.sqrt(breach * barrier)) + 1);
        }
    }

   function calculateDamage(attacker, defender) {
    // If attacker is the player, use totalUserStats
    if (attacker === userStats) {
        attacker = calculateTotalStats();
    }

    const baseDamage = (parseFloat(attacker.min_damage) + parseFloat(attacker.max_damage)) / 2;
    const multiplier = calculateDamageMultiplier(parseFloat(attacker.breach), parseFloat(defender.barrier));
    let damage = baseDamage * multiplier;

    const critRoll = Math.random() * 100;
    if (critRoll <= parseFloat(attacker.crit_chance)) {
        damage = damage * (parseFloat(attacker.crit_damage) / 100);
    }
    const blockRoll = Math.random() * 100;
    if (blockRoll <= parseFloat(defender.block_chance)) {
        damage = Math.max(0, damage - parseFloat(defender.block_amount));
    }

    return Math.round(damage);
}
const simulationLogOverlay = document.createElement('div');
simulationLogOverlay.style.cssText = `
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(22, 28, 36, 0.95);
    color: #ecf0f1;
    padding: 40px 20px 20px 20px;
    overflow-y: auto;
    display: none;
    z-index: 10000;
    box-sizing: border-box;
`;
simulationLogOverlay.id = 'simulation-log-overlay';
const backButton = document.createElement('button');
backButton.textContent = 'Back to results';
backButton.style.cssText = `
    position: absolute;
    top: 10px;
    right: 10px;
    padding: 5px 10px;
    background: #e67e22;
    border: none;
    border-radius: 4px;
    color: white;
    cursor: pointer;
`;
backButton.addEventListener('click', () => {
    simulationLogOverlay.style.display = 'none';
    simulationResultsContainer.style.display = 'block';
});
simulationLogOverlay.appendChild(backButton);
    // Modified simulateCombat that returns the combat log element.
   function simulateCombat() {
    const combatLog = document.createElement('div');
    combatLog.style.cssText = `
        margin-top: 20px;
        padding: 10px;
        background: rgba(44, 62, 80, 0.95);
        border-radius: 4px;
        max-height: 400px;
        overflow-y: auto;
        font-family: monospace;
        line-height: 1.4;
    `;

    // Get the total stats with all modifiers applied
    const totalUserStats = calculateTotalStats();

    let userHealth = parseFloat(totalUserStats.health);
    let monsterHealth = parseFloat(monsterStats.health);
    let round = 1;
    let monsterDefeated = false;

    function logAttack(attacker, defender, isUser) {
        const baseDamage = (parseFloat(attacker.min_damage) + parseFloat(attacker.max_damage)) / 2;
        const multiplier = calculateDamageMultiplier(parseFloat(attacker.breach), parseFloat(defender.barrier));
        let damage = baseDamage * multiplier;

        const critRoll = Math.random() * 100;
        const isCrit = critRoll <= parseFloat(attacker.crit_chance);
        if (isCrit) {
            damage = damage * (parseFloat(attacker.crit_damage) / 100);
        }
        const blockRoll = Math.random() * 100;
        const isBlocked = blockRoll <= parseFloat(defender.block_chance);
        const originalDamage = damage;
        if (isBlocked) {
            damage = Math.max(0, damage - parseFloat(defender.block_amount));
        }

        const color = isUser ? '#2ecc71' : '#e74c3c';
        const attacker_name = isUser ? 'You' : 'Monster';
        const defender_name = isUser ? 'Monster' : 'You';

        let log = `<div style="color: ${color}; margin-bottom: 10px;">`;
        log += `<div><b>Round ${round} - ${attacker_name}'s Attack</b></div>`;
        log += `<div>Base Damage: ${Math.round(baseDamage)} (${attacker.min_damage}-${attacker.max_damage})</div>`;
        log += `<div>Breach vs Barrier: ${attacker.breach} vs ${defender.barrier} (x${multiplier.toFixed(2)})</div>`;

        if (isCrit) {
            log += `<div>Critical Hit! (${attacker.crit_chance}% chance, +${attacker.crit_damage}% damage)</div>`;
        }
        if (isBlocked) {
            log += `<div>Attack Blocked! (${defender.block_chance}% chance, ${defender.block_amount} blocked)</div>`;
            log += `<div>Damage Reduced: ${Math.round(originalDamage)} → ${Math.round(damage)}</div>`;
        }

        const finalDamage = Math.round(damage);
        const newHealth = isUser ? Math.max(0, monsterHealth - finalDamage) : Math.max(0, userHealth - finalDamage);
        log += `<div><b>Final Damage: ${finalDamage}</b></div>`;
        log += `<div>${defender_name}'s Health: ${isUser ? monsterHealth : userHealth} → ${newHealth}</div>`;
        log += '</div>';

        combatLog.innerHTML += log;
        return finalDamage;
    }

    // Use totalUserStats for the player's attacks and defense
    while (userHealth > 0) {
        const userDamage = logAttack(totalUserStats, monsterStats, true);
        monsterHealth -= userDamage;

        if (monsterHealth <= 0) {
            monsterDefeated = true;
            break;
        }

        const monsterDamage = logAttack(monsterStats, totalUserStats, false);
        userHealth -= monsterDamage;

        round++;
    }

    const winner = monsterDefeated ? 'You win!' : 'Monster wins!';
    combatLog.innerHTML += `<div style="color: #f1c40f; margin-top: 10px; font-weight: bold; font-size: 1.2em;">${winner}</div>`;

    return combatLog;
}
    // Function to fetch modifiers data from API
    async function fetchModifiers() {
        try {
            const response = await fetch('https://elethor.com/game/neo-spire/modifiers');
            const data = await response.json();
            return data.modifiers || {};
        } catch (error) {
            console.error('Error fetching modifiers:', error);
            return null;
        }
    }

    // Function to create modifiers list (unchanged)
   // Modify the createModifiersList function to add Deselect buttons

function createModifiersList(modifiers) {
 const savedModifiers = loadFromLocalStorage('selectedModifiers') || {};
    selectedModifiers = savedModifiers;

    const container = document.createElement('div');
    container.style.cssText = `
        display: flex;
        gap: 20px;
        padding: 10px;
        font-family: Arial, sans-serif;
        color: #ecf0f1;
        max-height: 80vh;
        overflow-y: auto;
        width: 600px;
    `;

    ['Defense', 'Offense'].forEach(tree => {
        const treeData = modifiers[tree];
        if (!treeData) return;

        const treeSection = document.createElement('div');
        treeSection.style.cssText = `flex: 1; min-width: 0;`;
        treeSection.innerHTML = `<h3 style="color: #3498db; margin: 10px 0;">${tree}</h3>`;

        Object.entries(treeData).forEach(([anchor, options]) => {
            const anchorSection = document.createElement('div');
            anchorSection.style.cssText = `
                margin-bottom: 15px;
                padding: 8px;
                background: rgba(44, 62, 80, 0.5);
                border-radius: 4px;
            `;

            // Create header container for anchor name and deselect button
            const headerContainer = document.createElement('div');
            headerContainer.style.cssText = `
                display: flex;
                justify-content: space-between;
                align-items: center;
                margin-bottom: 5px;
            `;

            // Add anchor name
            const anchorName = document.createElement('div');
            anchorName.style.cssText = `color: #f1c40f;`;
            anchorName.textContent = anchor;
            headerContainer.appendChild(anchorName);

            // Add deselect button
            const deselectButton = document.createElement('button');
            deselectButton.textContent = 'Deselect';
            deselectButton.style.cssText = `
                padding: 2px 6px;
                background: #e74c3c;
                border: none;
                border-radius: 3px;
                color: white;
                cursor: pointer;
                font-size: 0.8em;
                transition: background 0.2s;
            `;
            deselectButton.addEventListener('mouseenter', () => { deselectButton.style.background = '#c0392b'; });
            deselectButton.addEventListener('mouseleave', () => { deselectButton.style.background = '#e74c3c'; });

            // Add click event for deselect button
            deselectButton.addEventListener('click', () => {
                // Deselect all options in this anchor
                optionsContainer.querySelectorAll('div').forEach(div => {
                    div.style.backgroundColor = '';
                    div.style.color = '#ecf0f1';
                });

                // Remove this anchor's selection from selectedModifiers
                const compositeKey = `${tree}:${anchor}`;
                if (selectedModifiers[compositeKey]) {
                    delete selectedModifiers[compositeKey];
                    console.log(`Deselected modifier at ${compositeKey}`);
                    console.log('Remaining selected modifiers:', {...selectedModifiers});
 saveToLocalStorage('selectedModifiers', selectedModifiers);
                }
            });

            headerContainer.appendChild(deselectButton);
            anchorSection.appendChild(headerContainer);

            const optionsContainer = document.createElement('div');
            optionsContainer.style.cssText = `
                display: flex;
                flex-wrap: wrap;
                gap: 10px;
                margin-top: 5px;
            `;

            options.forEach(option => {
                const optionDiv = document.createElement('div');
                optionDiv.style.cssText = `
                    padding: 5px;
                    border-left: 2px solid #3498db;
                    padding-left: 8px;
                    flex: 1;
                    min-width: 150px;
                    max-width: calc(50% - 5px);
                    cursor: pointer;
                    transition: background-color 0.3s;
                `;
                optionDiv.dataset.tree = tree;
                optionDiv.dataset.anchor = anchor;
                optionDiv.dataset.optionIndex = options.indexOf(option);

                // Modified click event handler for modifiers
                optionDiv.addEventListener('click', () => {
                    // Only unselect options in CURRENT anchor and tree
                    optionsContainer.querySelectorAll('div').forEach(div => {
                        div.style.backgroundColor = '';
                        div.style.color = '#ecf0f1';
                    });
                    optionDiv.style.backgroundColor = '#2980b9';
                    optionDiv.style.color = '#fff';

                    // Use a composite key that includes both tree and anchor
                    const compositeKey = `${tree}:${anchor}`;
                    selectedModifiers[compositeKey] = { ...option, tree: tree, anchor: anchor };

                    console.log('Selected modifier:', compositeKey, selectedModifiers[compositeKey]);
                    console.log('All selected modifiers:', {...selectedModifiers});
saveToLocalStorage('selectedModifiers', selectedModifiers);
                });
                optionDiv.innerHTML = `
                    <div style="font-weight: bold;">${option.name}</div>
                    <div style="color: #95a5a6; font-size: 0.9em;">Cost: ${option.cost} | Value: ${option.value}</div>
                `;
                optionsContainer.appendChild(optionDiv);
            });
            anchorSection.appendChild(optionsContainer);
            treeSection.appendChild(anchorSection);
        });

        container.appendChild(treeSection);
    });

    // At the end of createModifiersList, highlight previously selected options
    Object.entries(selectedModifiers).forEach(([compositeKey, modData]) => {
        const [tree, anchor] = compositeKey.split(':');
        const optionIndex = modData.optionIndex;

        // Find and highlight the selected option
        const options = container.querySelectorAll(`div[data-tree="${tree}"][data-anchor="${anchor}"]`);
        options.forEach(option => {
            if (parseInt(option.dataset.optionIndex) === optionIndex) {
                option.style.backgroundColor = '#2980b9';
                option.style.color = '#fff';
            }
        });
    });

    return container;
}

    // Function to fetch monster stats from API
    async function fetchMonsterStats(floor) {
        try {
            const response = await fetch(`https://elethor.com/game/neo-spire/${floor}`);
            const data = await response.json();
            if (data && data.floor && data.floor.stats) {
                return data.floor.stats;
            } else {
                console.error('Invalid data format from API');
                return null;
            }
        } catch (error) {
            console.error('Error fetching monster stats:', error);
            return null;
        }
    }

    // Function to update monster stat inputs
    function updateMonsterStatInputs(stats) {
        if (!stats) return;
        document.querySelectorAll('input[data-stat]').forEach(input => {
            if (input.dataset.type === 'monster') {
                const statKey = input.dataset.stat.toLowerCase().replace(/ /g, '_');
                if (stats[statKey] !== undefined) {
                    input.value = stats[statKey];
                    const event = new Event('input', { bubbles: true });
                    input.dispatchEvent(event);
                }
            }
        });
    }

    // Define updateTotalStats in a scope accessible to event listeners
    function updateTotalStats() {
        const totalStats = calculateTotalStats();
        document.querySelectorAll('span[data-stat]').forEach(span => {
            const stat = span.dataset.stat.toLowerCase().replace(/ /g, '_');
            span.textContent = totalStats[stat] || '-';
        });
    }

    // Create stats table and simulation controls
    function createStatsTable() {
        const tableContainer = document.createElement('div');
        tableContainer.style.cssText = `
            padding: 10px;
            font-family: Arial, sans-serif;
            color: #ecf0f1;
            flex: 1;
        `;

        const table = document.createElement('table');
        table.style.cssText = `
            border-collapse: collapse;
            width: 100%;
        `;

        // Auto monster stats controls (unchanged)
        const autoStatsContainer = document.createElement('div');
        autoStatsContainer.style.cssText = `
            display: flex;
            align-items: center;
            margin-bottom: 10px;
            padding: 8px;
            background: rgba(44, 62, 80, 0.5);
            border-radius: 4px;
        `;
        const autoStatsCheckbox = document.createElement('input');
        autoStatsCheckbox.type = 'checkbox';
        autoStatsCheckbox.id = 'auto-monster-stats';
        autoStatsCheckbox.style.cssText = `margin-right: 8px;`;
        const autoStatsLabel = document.createElement('label');
        autoStatsLabel.htmlFor = 'auto-monster-stats';
        autoStatsLabel.textContent = 'Auto Monster Stats';
        autoStatsLabel.style.cssText = `margin-right: 15px; color: #3498db;`;
        const floorLabel = document.createElement('label');
        floorLabel.htmlFor = 'floor-input';
        floorLabel.textContent = 'Floor:';
        floorLabel.style.cssText = `margin-right: 8px; color: #3498db;`;
        const floorInput = document.createElement('input');
        floorInput.type = 'number';
        floorInput.id = 'floor-input';
        floorInput.min = '1';
        floorInput.value = '1';
        floorInput.style.cssText = `
            width: 60px;
            background: #2c3e50;
            border: 1px solid #34495e;
            color: #ecf0f1;
            padding: 4px;
            border-radius: 3px;
        `;
        const fetchButton = document.createElement('button');
        fetchButton.textContent = 'Fetch';
        fetchButton.style.cssText = `
            margin-left: 8px;
            padding: 4px 8px;
            background: #3498db;
            border: none;
            border-radius: 4px;
            color: white;
            cursor: pointer;
            font-weight: bold;
            transition: background 0.3s;
        `;
        fetchButton.addEventListener('mouseenter', () => { fetchButton.style.background = '#2980b9'; });
        fetchButton.addEventListener('mouseleave', () => { fetchButton.style.background = '#3498db'; });
        autoStatsCheckbox.addEventListener('change', async (e) => {
            autoMonsterStats = e.target.checked;
            document.querySelectorAll('input[data-type="monster"]').forEach(input => {
                input.disabled = autoMonsterStats;
                input.style.opacity = autoMonsterStats ? '0.5' : '1';
            });
            if (autoMonsterStats) {
                currentFloor = parseInt(floorInput.value) || 1;
                const stats = await fetchMonsterStats(currentFloor);
                if (stats) { updateMonsterStatInputs(stats); }
            }
        });
        floorInput.addEventListener('input', (e) => { currentFloor = parseInt(e.target.value) || 1; });
        fetchButton.addEventListener('click', async () => {
            if (autoMonsterStats) {
                currentFloor = parseInt(floorInput.value) || 1;
                const stats = await fetchMonsterStats(currentFloor);
                if (stats) { updateMonsterStatInputs(stats); }
            }
        });
        autoStatsContainer.appendChild(autoStatsCheckbox);
        autoStatsContainer.appendChild(autoStatsLabel);
        autoStatsContainer.appendChild(floorLabel);
        autoStatsContainer.appendChild(floorInput);
        autoStatsContainer.appendChild(fetchButton);
        tableContainer.appendChild(autoStatsContainer);

        // Add "Number of simulations" input above simulate combat
        const simulationControls = document.createElement('div');
        simulationControls.style.cssText = 'margin-bottom: 10px; display: flex; align-items: center; gap: 10px;';
        const numSimLabel = document.createElement('label');
        numSimLabel.htmlFor = 'num-simulations';
        numSimLabel.textContent = 'Number of simulations:';
        numSimLabel.style.cssText = 'color: #3498db;';
        simulationControls.appendChild(numSimLabel);
        const numSimInput = document.createElement('input');
        numSimInput.type = 'number';
        numSimInput.id = 'num-simulations';
        numSimInput.value = '10';
        numSimInput.style.cssText = `
            width: 60px;
            background: #2c3e50;
            border: 1px solid #34495e;
            color: #ecf0f1;
            padding: 4px;
            border-radius: 3px;
        `;
        simulationControls.appendChild(numSimInput);
        tableContainer.appendChild(simulationControls);

        // Create header row for the stat table
        const header = document.createElement('tr');
        ['STAT', 'MONSTER', 'YOU', 'TOTAL YOU'].forEach(text => {
            const th = document.createElement('th');
            th.textContent = text;
            th.style.cssText = `
                padding: 8px;
                text-align: left;
                border-bottom: 2px solid #34495e;
                color: #3498db;
            `;
            header.appendChild(th);
        });
        table.appendChild(header);

        // Create stat rows
        stats.forEach(stat => {
            const row = document.createElement('tr');
            const nameCell = document.createElement('td');
            nameCell.textContent = stat;
            nameCell.style.cssText = `padding: 8px; border-bottom: 1px solid #34495e;`;
            const monsterCell = document.createElement('td');
            const monsterInput = document.createElement('input');
            monsterInput.type = 'text';
            monsterInput.dataset.stat = stat;
            monsterInput.dataset.type = 'monster';
           monsterInput.addEventListener('input', (e) => {
    const value = e.target.value;
    const statKey = stat.toLowerCase().replace(/ /g, '_');
    monsterStats[statKey] = value;

    saveToLocalStorage('monsterStats', monsterStats); // Save monster stats
    console.log('Monster stats updated:', monsterStats);
});

            monsterInput.style.cssText = `
                width: 80px;
                background: #2c3e50;
                border: 1px solid #34495e;
                color: #ecf0f1;
                padding: 4px;
                border-radius: 3px;
            `;
            monsterCell.appendChild(monsterInput);
            monsterCell.style.cssText = `padding: 8px; border-bottom: 1px solid #34495e;`;
            const yourCell = document.createElement('td');
            const yourInput = document.createElement('input');
            yourInput.type = 'text';
            yourInput.dataset.stat = stat;
           yourInput.addEventListener('input', (e) => {
    const value = e.target.value;
    const statKey = stat.toLowerCase().replace(/ /g, '_');
    userStats[statKey] = value;

    saveToLocalStorage('userStats', userStats); // Save user stats
    console.log('User stats updated:', userStats);
});
            yourInput.style.cssText = `
                width: 80px;
                background: #2c3e50;
                border: 1px solid #34495e;
                color: #ecf0f1;
                padding: 4px;
                border-radius: 3px;
            `;
            yourCell.appendChild(yourInput);
            yourCell.style.cssText = `padding: 8px; border-bottom: 1px solid #34495e;`;
            row.appendChild(nameCell);
            row.appendChild(monsterCell);
            row.appendChild(yourCell);
            const totalCell = document.createElement('td');
            const totalSpan = document.createElement('span');
            totalSpan.dataset.stat = stat;
            totalSpan.textContent = '-';
            totalSpan.style.cssText = `color: #2ecc71; font-weight: bold;`;
            totalCell.appendChild(totalSpan);
            totalCell.style.cssText = `padding: 8px; border-bottom: 1px solid #34495e;`;
            row.appendChild(totalCell);
            row.addEventListener('mouseenter', () => { row.style.backgroundColor = 'rgba(52, 73, 94, 0.5)'; });
            row.addEventListener('mouseleave', () => { row.style.backgroundColor = ''; });
            table.appendChild(row);
        });
        tableContainer.appendChild(table);

        // Add simulate button and modify its event listener for multiple simulations
        const simulateButton = document.createElement('button');
        simulateButton.textContent = 'Simulate Combat';
        simulateButton.style.cssText = `
            margin-top: 10px;
            padding: 8px 16px;
            background: #2ecc71;
            border: none;
            border-radius: 4px;
            color: white;
            cursor: pointer;
            width: 100%;
            font-weight: bold;
            transition: background 0.3s;
        `;
        simulateButton.addEventListener('mouseenter', () => { simulateButton.style.background = '#27ae60'; });
        simulateButton.addEventListener('mouseleave', () => { simulateButton.style.background = '#2ecc71'; });
        simulateButton.addEventListener('click', () => {
    // Clear previous simulation results and logs
    simulationResultsContainer.innerHTML = '';
    simulationLogs = []; // reset stored logs

    // Calculate total stats before running simulations
    const totalUserStats = calculateTotalStats();

    const numSims = parseInt(document.getElementById('num-simulations').value) || 1;
    for (let i = 0; i < numSims; i++) {
        const combatLog = simulateCombat();
        // Initially hide each combat log (they will be shown in the overlay)
        combatLog.style.display = 'none';
        combatLog.id = `combat-log-${i}`;
        simulationLogs.push(combatLog);

        // Extract final result text from combat log
        const finalLine = combatLog.querySelector('div[style*="color: #f1c40f"]');
        const resultText = finalLine ? finalLine.textContent : 'Unknown';

        // Create simulation result entry
        const simResultDiv = document.createElement('div');
        simResultDiv.style.cssText = 'margin-bottom: 10px; padding: 5px; background: rgba(44, 62, 80, 0.5); border-radius: 4px;';
        simResultDiv.innerHTML = `<strong>Simulation ${i + 1}:</strong> ${resultText}`;
        const logsButton = document.createElement('button');
        logsButton.textContent = 'Logs';
        logsButton.style.cssText = 'margin-left: 10px; padding: 2px 6px;';
        logsButton.addEventListener('click', () => {
            // When clicked, hide the results container and show the overlay with the combat log
            simulationResultsContainer.style.display = 'none';
            // Clear any previous content except the back button in the overlay
            simulationLogOverlay.innerHTML = '';
            simulationLogOverlay.appendChild(backButton);
            simulationLogOverlay.appendChild(simulationLogs[i]);
            simulationLogs[i].style.display = 'block';
            simulationLogOverlay.style.display = 'block';
        });
        simResultDiv.appendChild(logsButton);
        simulationResultsContainer.appendChild(simResultDiv);
    }
});
        tableContainer.appendChild(simulateButton);

        // Add confirm modifiers button (unchanged)
        const confirmButton = document.createElement('button');
        confirmButton.textContent = 'Confirm Modifiers';
        confirmButton.style.cssText = `
            margin-top: 10px;
            margin-bottom: 10px;
            padding: 8px 16px;
            background: #e67e22;
            border: none;
            border-radius: 4px;
            color: white;
            cursor: pointer;
            width: 100%;
            font-weight: bold;
            transition: background 0.3s;
        `;
        confirmButton.addEventListener('mouseenter', () => { confirmButton.style.background = '#d35400'; });
        confirmButton.addEventListener('mouseleave', () => { confirmButton.style.background = '#e67e22'; });
        confirmButton.addEventListener('click', () => {
    logSelectedModifiers();
    updateTotalStats();
});
        tableContainer.appendChild(confirmButton);

        // Add drag functionality for the table container
        let isDragging = false, currentX, currentY, initialX, initialY, xOffset = 0, yOffset = 0;
        tableContainer.addEventListener('mousedown', dragStart);
        document.addEventListener('mousemove', drag);
        document.addEventListener('mouseup', dragEnd);
        function dragStart(e) {
            initialX = e.clientX - xOffset;
            initialY = e.clientY - yOffset;
            if (e.target === tableContainer) { isDragging = true; }
        }
        function drag(e) {
            if (isDragging) {
                e.preventDefault();
                currentX = e.clientX - initialX;
                currentY = e.clientY - initialY;
                xOffset = currentX;
                yOffset = currentY;
                setTranslate(currentX, currentY, tableContainer);
            }
        }
        function setTranslate(xPos, yPos, el) {
            el.style.transform = `translate3d(${xPos}px, ${yPos}px, 0)`;
        }
        function dragEnd() {
            initialX = currentX;
            initialY = currentY;
            isDragging = false;
        }

        document.body.appendChild(tableContainer);
    }

    // Main container creation on page load
    window.addEventListener('load', async () => {
        const mainContainer = document.createElement('div');
// Load saved stats from localStorage
const savedUserStats = loadFromLocalStorage('userStats') || {};
const savedMonsterStats = loadFromLocalStorage('monsterStats') || {};

userStats = savedUserStats;
monsterStats = savedMonsterStats;

mainContainer.style.cssText = `
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(22, 28, 36, 0.95);
    z-index: 9999;
    box-shadow: 0 0 10px rgba(0,0,0,0.5);
    overflow: auto;
`;


        // Create content container with side-by-side layout
        const contentContainer = document.createElement('div');
        contentContainer.style.cssText = `
            display: flex;
            flex-direction: row;
            gap: 20px;
            padding: 20px;
        `;

        // Create simulation results container (to be shown on the left)
        simulationResultsContainer = document.createElement('div');
        simulationResultsContainer.id = 'simulation-results';
        simulationResultsContainer.style.cssText = `
            flex: 1;
            background: rgba(22, 28, 36, 0.95);
            color: #ecf0f1;
            padding: 10px;
            border: 1px solid #2c3e50;
            border-radius: 4px;
            max-height: 400px;
            overflow-y: auto;
        `;
        contentContainer.appendChild(simulationResultsContainer);

        // Create and append stats table
        createStatsTable();
// After table creation, populate input fields with saved values
document.querySelectorAll('input[data-stat]').forEach(input => {
    const statKey = input.dataset.stat.toLowerCase().replace(/ /g, '_');

    if (input.dataset.type === 'monster' && monsterStats[statKey] !== undefined) {
        input.value = monsterStats[statKey];
        const event = new Event('input', { bubbles: true });
        input.dispatchEvent(event); // Ensure any dependent calculations trigger
    }

    if (input.dataset.type === 'user' && userStats[statKey] !== undefined) {
        input.value = userStats[statKey];
        const event = new Event('input', { bubbles: true });
        input.dispatchEvent(event);
    }
});

        const statsTable = document.querySelector('div[style*="font-family: Arial"]');
        if (statsTable) {
            contentContainer.appendChild(statsTable);
        }

        // Create and append modifiers list
        const modifiers = await fetchModifiers();
        if (modifiers) {
            modifiersData = modifiers;
            const modifiersList = createModifiersList(modifiers);
            contentContainer.appendChild(modifiersList);
        }

        mainContainer.appendChild(contentContainer);

       
document.body.appendChild(simulationLogOverlay);
        document.body.appendChild(mainContainer);

    });
})();