Manarion 助手

Manarion 游戏数据计算器

// ==UserScript==
// @name         Manarion helper
// @name:zh-CN   Manarion 助手
// @name:en      Manarion helper
// @namespace    http://tampermonkey.net/
// @version      0.0.2.1
// @description  game Manarion calculation tool with combat/gathering efficiency calculator
// @description:zh-CN  Manarion 游戏数据计算器
// @description:en     game Manarion calculation tool with combat/gathering efficiency calculator
// @author       LemonApostle
// @match        https://manarion.com/*
// @match        https://*.manarion.com/*
// @icon         https://s2.loli.net/2025/05/28/YmWGhwXJVHonOsI.png
// @grant        GM_xmlhttpRequest
// @connect      api.manarion.com
// @run-at       document-end
// @license      MIT
// @homepage     https://greasyfork.org/zh-CN/scripts/546781-manarion-helper
// @supportURL   https://greasyfork.org/zh-CN/scripts/546781-manarion-helper/feedback

// ==/UserScript==

(function() {
    'use strict';

    function getFullHTMLContent() { return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>计算器</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
        }
        
        .container {
            background: rgba(255, 255, 255, 0.95);
            border-radius: 15px;
            padding: 30px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.2);
        }
        
        h1 {
            color: #333;
            text-align: center;
            margin-bottom: 30px;
            font-size: 2.5em;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
        }
        
        .input-section {
            background: #f8f9fa;
            padding: 20px;
            border-radius: 10px;
            margin-bottom: 20px;
            border-left: 4px solid #667eea;
        }
        
        .input-group {
            display: flex;
            gap: 10px;
            align-items: center;
            margin-bottom: 15px;
        }
        
        input[type="text"] {
            flex: 1;
            padding: 12px;
            border: 2px solid #ddd;
            border-radius: 8px;
            font-size: 16px;
            transition: border-color 0.3s;
        }
        
        input[type="text"]:focus {
            outline: none;
            border-color: #667eea;
            box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
        }
        
        button {
            background: linear-gradient(45deg, #667eea, #764ba2);
            color: white;
            border: none;
            padding: 12px 24px;
            border-radius: 8px;
            cursor: pointer;
            font-size: 16px;
            font-weight: 600;
            transition: transform 0.2s, box-shadow 0.2s;
        }
        
        button:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
        }
        
        button:disabled {
            background: #ccc;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }
        .usage-note {
            background: #e3f2fd;
            border: 1px solid #bbdefb;
            border-radius: 6px;
            padding: 10px;
            margin-bottom: 15px;
            color: #1565c0;
            font-size: 14px;
        }

        .calc-input {
            display: flex;
            align-items: center;
            margin: 10px 0;
            gap: 10px;
            padding-right: 600px;
        }

        .calc-input label {
            min-width: 200px;
            font-weight: 500;
        }

        .calc-input.with-select label {
            min-width: 180px;
        }

        .calc-input.with-select select {
            min-width: 100px;
            margin-right: 10px;
        }

        .calc-button {
            background: linear-gradient(45deg, #667eea, #764ba2);
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 600;
            transition: transform 0.2s, box-shadow 0.2s;
            min-width: 120px;
            margin-left: auto;
        }

        .calc-button:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
        }

        .calc-button:disabled {
            background: #ccc;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }

        #gatheringType {
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
            margin-right: 10px;
        }

        #gatheringType2 {
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
            margin-right: 10px;
        }
        
        .player-info {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 10px;
            margin-bottom: 15px;
        }
        
        .info-card {
            background: #ffffff;
            border: 1px solid #e0e0e0;
            padding: 12px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        
        .info-card h3 {
            margin: 0 0 10px 0;
            font-size: 1.1em;
            color: #333;
            border-bottom: 1px solid #eee;
            padding-bottom: 5px;
        }
        
        .stat-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin: 4px 0;
            padding: 2px 0;
        }
        
        .stat-label {
            font-size: 0.9em;
            color: #666;
            font-weight: 500;
            min-width: 80px;
        }
        
        .stat-value {
            font-weight: bold;
            color: #333;
        }
        
        .stat-input {
            width: 80px;
            padding: 3px 6px;
            border: 1px solid #ddd;
            border-radius: 4px;
            text-align: right;
            font-size: 0.9em;
            background: #f9f9f9;
        }
        
        .stat-input:focus {
            outline: none;
            border-color: #667eea;
            background: white;
        }
        
        .loading {
            text-align: center;
            color: #667eea;
            font-size: 1.2em;
            padding: 20px;
        }
        
        .error {
            background: #f8d7da;
            color: #721c24;
            padding: 15px;
            border-radius: 8px;
            border-left: 4px solid #dc3545;
            margin: 10px 0;
        }
        
        .success {
            background: #d4edda;
            color: #155724;
            padding: 15px;
            border-radius: 8px;
            border-left: 4px solid #28a745;
            margin: 10px 0;
        }
        
        .rarity-6 { background: linear-gradient(135deg, #ff6b6b, #ee5a24); }
        .rarity-5 { background: linear-gradient(135deg, #ffa726, #fb8c00); }
        .rarity-4 { background: linear-gradient(135deg, #ab47bc, #8e24aa); }
        .rarity-3 { background: linear-gradient(135deg, #42a5f5, #1e88e5); }
        
        .calculator-section {
            background: #f8f9fa;
            padding: 20px;
            border-radius: 10px;
            margin-top: 20px;
            border-left: 4px solid #28a745;
        }
        
        .calc-input {
            margin: 10px 0;
        }
        
        .calc-result {
            background: #e8f5e8;
            padding: 15px;
            border-radius: 8px;
            margin-top: 15px;
            font-weight: bold;
            color: #2e7d2e;
        }
    </style>
</head>
<body>
    <div class="container">
        <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px;">
            <h1 style="margin: 0; flex: 1; text-align: center;">🏰 Manarion 数据计算器</h1>
            <button id="langToggle" onclick="toggleLanguage()" style="
                background: rgba(255, 255, 255, 0.9);
                color: #667eea;
                border: 2px solid #667eea;
                padding: 8px 16px;
                border-radius: 20px;
                cursor: pointer;
                font-size: 14px;
                font-weight: 600;
                transition: all 0.3s;
                min-width: 60px;
            " onmouseover="this.style.background='#667eea'; this.style.color='white';" 
            onmouseout="this.style.background='rgba(255, 255, 255, 0.9)'; this.style.color='#667eea';">
                中/EN
            </button>
        </div>
        
        <div class="input-section">
            <h3>📊 获取玩家数据</h3>
            <div class="input-group">
                <input type="text" id="playerName" placeholder="输入玩家名称或ID" value="LemonApostle">
                <button onclick="fetchPlayerData()">获取数据</button>
            </div>
            <div id="message"></div>
        </div>
        
        <div id="playerData" style="display:none;">
            <div class="player-info">
                <div class="info-card">
                    <h3>基本信息</h3>
                    <div id="basicInfo"></div>
                </div>

                <div class="info-card">
                    <h3>采集加成</h3>
                    <div id="gatheringBoosts"></div>
                </div>
                
                <div class="info-card">
                    <h3>法典加成</h3>
                    <div id="codexBoosts"></div>
                </div>

                <div class="info-card">
                    <h3>其他装备加成</h3>
                    <div id="otherEquipmentBoosts"></div>
                </div>
                
                <div class="info-card">
                    <h3>农场</h3>
                    <div id="farmBoosts"></div>
                </div>

                <div class="info-card">
                    <h3>市场价格</h3>
                    <div id="marketPrice"></div>
                </div>

                <div class="info-card">
                    <h3>需要自己补充的内容</h3>
                    <div id="needToSupplement"></div>
                </div>

            </div>
            
        </div>
        
        <div class="calculator-section">
            <h3>🧮 数据计算器</h3>
            <div class="usage-note">
                <strong>使用说明:</strong> 填完必要的数据后,先点击"更新数据"按钮,再点击其他计算按钮。
            </div>
            <div class="calc-input">
                <label>获取当前所有数据:</label>
                <button class="calc-button" onclick="getAllCurrentValues()">更新数据</button>
            </div>
            <div class="calc-input">
                <label>战斗计算:</label>
                <button class="calc-button" onclick="calculateCombatEfficiency()">计算战斗效率</button>
            </div>
            <div class="calc-input with-select">
                <label>采集效率计算:</label>
                <select id="gatheringType">
                    <option value="mining">挖矿</option>
                    <option value="fishing">钓鱼</option>
                    <option value="woodcutting">伐木</option>
                </select>
                <button class="calc-button" onclick="calculateGatheringEfficiency()">计算采集效率</button>
            </div>
            <div class="calc-input">
                <label>回响药水最佳等级计算:</label>
                <button class="calc-button" onclick="calculateResonancePotionLevel()">计算等级</button>
            </div>
            <div class="calc-input with-select">
                <label>采集投资回报率计算:</label>
                <select id="gatheringType2">
                    <option value="mining">挖矿</option>
                    <option value="fishing">钓鱼</option>
                    <option value="woodcutting">伐木</option>
                </select>
                <button class="calc-button" onclick="calculateGatheringROI()">计算采集投资回报率</button>
            </div>
            <div class="calc-input">
                <label>采集装备替换检测:</label>
                <button class="calc-button" onclick="calculateGatherEquipReplace()">检测采集装备替换</button>
            </div>
            <div class="calc-input">
                <label>战斗装备替换检测:</label>
                <button class="calc-button" onclick="calculateBattlerEquipReplace()">检测战斗装备替换</button>
            </div>
            <div id="calcResults"></div>
        </div>
    </div>

    <script>
let values = null;
let globalPlayerData = null;
let globalMarketData = null;

function loadGlobalData() {
    try {
        const savedValues = localStorage.getItem('manarion-values');
        const savedPlayerData = localStorage.getItem('manarion-player-data');
        const savedMarketData = localStorage.getItem('manarion-market-data');
        if (savedValues) {
            values = JSON.parse(savedValues);
            console.log('✅ manarion_helper_values LOAD');
            if (values && values.ui) {
                const gatheringType1 = document.getElementById('gatheringType');
                const gatheringType2 = document.getElementById('gatheringType2');
                if (gatheringType1 && values.ui.lastGatheringType) {
                    gatheringType1.value = values.ui.lastGatheringType;
                }
                if (gatheringType2 && values.ui.lastGatheringType2) {
                    gatheringType2.value = values.ui.lastGatheringType2;
                }
            }
        }
        if (savedPlayerData) {
            globalPlayerData = JSON.parse(savedPlayerData);
            const playerNameInput = document.getElementById('playerName');
            if (playerNameInput && globalPlayerData.Name) {
                playerNameInput.value = globalPlayerData.Name;
            }
            console.log('✅ manarion_helper_player_data LOAD');
        }
        if (savedMarketData) {
            globalMarketData = JSON.parse(savedMarketData);
            console.log('✅ manarion_helper_market_data LOAD');
        }
    } catch (error) {
        console.log('❌ manarion_helper_load_data ERROR');
    }
}

function saveGlobalData() {
    try {
        if (values !== null) {
            localStorage.setItem('manarion-values', JSON.stringify(values));
        }
        if (globalPlayerData !== null) {
            localStorage.setItem('manarion-player-data', JSON.stringify(globalPlayerData));
        }
        if (globalMarketData !== null) {
            localStorage.setItem('manarion-market-data', JSON.stringify(globalMarketData));
        }
        console.log('💾 marion_helper_save_data SUCCESS');
    } catch (error) {
        console.log('❌ manarion_helper_save_data ERROR');
    }
}

function removeGlobalData() {
    try {
        localStorage.removeItem('manarion-values');
        localStorage.removeItem('manarion-player-data');
        localStorage.removeItem('manarion-market-data');
        globalMarketData = null;
        globalPlayerData = null;
        values = null;
        console.log('💾 manarion_helper_remove_data SUCCESS');
    } catch (error) {
        console.log('❌ manarion_helper_remove_data ERROR');
    }
}

function toggleLanguage() {
    console.log('TODO')
}

async function fetchPlayerData() {
    const playerName = document.getElementById('playerName').value.trim();
    let data = null, marketData = null;
    if (!playerName) {
        showMessage('请输入玩家名称', 'error');
        return;
    }
    
    showMessage('正在获取数据...', 'loading');
    
    try {
        const playerUrl = \`https://api.manarion.com/players/\${encodeURIComponent(playerName)}\`;
        
        data = await window.fetchDataWithGM(playerUrl);
        
    } catch (error) {
        console.error('获取数据失败:', error);
        showExampleData();
        showMessage('无法获取数据。可能原因:1. API暂时不可用 2. 玩家名称不存在 3. 网络连接问题', 'error');
        return;
    }
    
    marketData = await fetchMarketData();
    showMessage('数据获取成功!', 'success');
    globalPlayerData = data;
    displayData(data, marketData);
    saveGlobalData();
}

async function fetchMarketData() {
    try {
        const marketUrl = 'https://api.manarion.com/market';
        const marketData = await window.fetchDataWithGM(marketUrl);
        globalMarketData = marketData;
        return marketData;
    } catch (error) {
        console.warn('获取市场价格失败:', error);
        return null;
    }
}

// region example data
function showExampleData() {
    const examplePlayerData = {"ID":2582,"Banned":false,"Title":"Scholar","TitleColor":"#b1d852","Name":"LemonApostle","ProfileText":"","Level":2269,"Zone":"blazing_core","Enemy":58000,"MagicType":"water","ActionType":"battle","MiningLevel":636,"FishingLevel":2442,"WoodcuttingLevel":701,"GatherActions":1599128,"Kills":241570,"Deaths":821,"EventActions":138637,"EventPoints":10867920.089814264,"BattleQuestNumber":415,"GatherQuestNumber":903,"BaseBoosts":{"1":1600,"100":100,"101":17,"102":13,"103":16,"105":0,"106":0,"108":85,"11":724583,"124":1800,"130":2600,"131":2600,"132":2600,"133":17,"140":416,"141":27,"142":2,"143":0,"144":0,"145":0,"146":0,"2":1800,"22":13,"23":6,"24":11,"3":19047,"30":1100,"31":69562,"32":500,"4":19112,"40":36000,"41":26000,"42":36000,"43":36000,"44":26000,"45":36000,"46":40000,"47":36000,"48":31000,"49":22000,"5":19194,"50":36000,"6":19246,"69":1,"7":18966,"70":1},"TotalBoosts":{"1":1600,"10":0,"100":299,"101":56,"102":52,"103":55,"105":0,"106":0,"107":0,"108":231,"11":763724,"12":0,"120":4683,"121":1398,"122":0,"123":0,"124":1800,"130":2600,"131":2600,"132":2600,"133":17,"140":416,"141":27,"142":2,"143":0,"144":0,"145":0,"146":0,"2":1800,"21":0,"22":13,"23":6,"24":11,"3":118166.33,"30":1.6534,"31":42.319828,"32":1.297,"4":101749.68000000001,"40":46.6062,"41":25.868000000000002,"42":29.2158,"43":36.0982,"44":16.444000000000003,"45":29.253,"46":24.76,"47":41.803,"48":19.414,"49":31.699399999999997,"5":96850.66,"50":46.2424,"6":101426.94,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":1,"7":84603.74,"70":1,"71":0,"8":2666813,"80":0,"81":39,"82":0,"83":38,"84":0,"85":0,"86":39,"9":2535942},"SigilBoost":108,"GuildID":86,"LastFatigue":1753980262,"UnfatiguedStreak":492529,"HighestEnemy":58000,"Equipment":{"1":{"ID":5025890,"Name":"Heirloom Staff of Water +16 (3046)","IsEquipped":true,"Level":3046,"Rarity":6,"Slot":1,"Boosts":{"11":21745,"120":562,"3":11089,"40":27909,"41":26178,"5":12022,"6":10837,"8":770006,"81":39},"Quality":0.99403,"UpgradeChance":0.04681,"Infusions":16},"2":{"ID":4951400,"Name":"Heirloom Robes +14 (2492)","IsEquipped":true,"Level":2492,"Rarity":6,"Slot":2,"Boosts":{"101":39,"121":466,"4":8821,"49":22310,"50":22010,"6":8642,"7":9083,"9":108884},"Quality":0.99292,"UpgradeChance":0.04852,"Infusions":14},"3":{"ID":4969542,"Name":"Heirloom Sandals +14 (2163)","IsEquipped":true,"Level":2163,"Rarity":6,"Slot":3,"Boosts":{"103":39,"120":401,"3":7623,"40":18591,"43":18751,"6":8244,"7":9253,"9":85431},"Quality":0.99324,"UpgradeChance":0.04643,"Infusions":14},"4":{"ID":4940806,"Name":"Heirloom Gloves +14 (2149)","IsEquipped":true,"Level":2149,"Rarity":6,"Slot":4,"Boosts":{"102":39,"121":400,"3":7535,"4":7931,"42":19947,"50":18620,"6":7661,"9":90438},"Quality":0.99402,"UpgradeChance":0.04116,"Infusions":14},"5":{"ID":4937498,"Name":"Heirloom Hood +15 (2167)","IsEquipped":true,"Level":2167,"Rarity":6,"Slot":5,"Boosts":{"100":39,"120":388,"3":7516,"43":19540,"47":18825,"5":8153,"6":7681,"9":88907},"Quality":0.99269,"UpgradeChance":0.0501,"Infusions":15},"6":{"ID":5030783,"Name":"Heirloom Cloak +16 (3057)","IsEquipped":true,"Level":3057,"Rarity":6,"Slot":6,"Boosts":{"120":547,"3":10676,"4":10889,"49":27906,"5":10830,"50":27901,"83":38,"9":152982},"Quality":0.99299,"UpgradeChance":0.048,"Infusions":16},"7":{"ID":4954354,"Name":"Heirloom Pendant +14 (2181)","IsEquipped":true,"Level":2181,"Rarity":6,"Slot":7,"Boosts":{"120":418,"3":7997,"4":8307,"45":20203,"47":18226,"7":8001},"Quality":0.99343,"UpgradeChance":0.03895,"Infusions":14},"8":{"ID":4921970,"Name":"Heirloom Ring +14 (2169)","IsEquipped":true,"Level":2169,"Rarity":6,"Slot":8,"Boosts":{"120":364,"4":7639,"40":23101,"47":19511,"5":8689,"7":7923,"86":39},"Quality":0.99264,"UpgradeChance":0.04351,"Infusions":14}}};
    const exampleMarketData = {"Buy":{"10":5100000,"11":4050000,"12":2250000,"13":40410105,"14":33000000,"15":39700001,"16":1902328816,"17":12000000000,"18":6060000009,"19":1402439508,"2":1091,"20":13072500002,"21":13261300010,"22":1800000000,"23":2049999999,"24":1040300000,"25":502000000,"26":2750000000,"27":431000000,"28":800000000,"29":6250000,"3":16000000105,"30":2400006,"31":3300000,"32":7777778,"33":30500009,"34":11250000,"35":6920016671,"36":17220500000,"37":40150000000,"39":25000009,"4":11000009,"40":980000,"41":999500,"44":27500000015,"45":313000000000,"46":796001001,"47":7885373010,"5":12625009,"50":4500000000000,"6":8010009,"7":407,"8":377,"9":387},"Sell":{"10":15000000,"11":37000000,"12":17641798,"13":41550000,"14":39589994,"15":42000000,"16":2000000000,"17":14199000000,"18":25000000000,"19":4257000000,"2":1232,"20":1000000000000,"21":99000000000,"22":4514801227,"23":2305430421,"24":1900000000,"25":790000000,"26":7920000000,"27":633977685,"28":1300000000,"29":21000000,"3":16416671000,"30":10500000,"31":14900000,"32":41250000,"33":74979999,"34":35000000,"35":8035830000,"36":19999999990,"37":57247631000,"39":673200000,"4":69000000,"40":1127114,"41":1000000,"44":38999999999,"45":361000000000,"46":835000000,"47":8612000000,"5":60000000,"50":21900000000000,"6":66000000,"7":503,"8":409,"9":402}};
    let displayExampleData = false;

    if(globalPlayerData == null){
        globalPlayerData = examplePlayerData;
        displayExampleData = true;

    }
    if(globalMarketData == null){
        globalMarketData = exampleMarketData;
        displayExampleData = true;
    }

    displayData(globalPlayerData, globalMarketData);

    if(displayExampleData){
        showMessage('显示示例数据', 'success');
    } else {
        showMessage('加载已保存的数据 用户名: '+globalPlayerData.Name, 'success');
    }

}


function showMessage(message, type) {
    const messageDiv = document.getElementById('message');
    messageDiv.innerHTML = \`<div class="\${type}">\${message}</div>\`;
}

// region show data
function displayData(playerData, marketData) {
    document.getElementById('playerData').style.display = 'block';
    

    document.getElementById('basicInfo').innerHTML = \`
        <div class="stat-row"><span class="stat-label">玩家名:</span> <span class="stat-value">\${playerData.Name}</span></div>
        <div class="stat-row"><span class="stat-label">当前敌人:</span> <input type="number" class="stat-input" value="\${playerData.Enemy || 0}" id="currentEnemy"></div>
        <div class="stat-row"><span class="stat-label">战斗等级:</span> <input type="number" class="stat-input" value="\${playerData.Level || 0}" id="battleLevel"></div>
        <div class="stat-row"><span class="stat-label">挖矿等级:</span> <input type="number" class="stat-input" value="\${playerData.MiningLevel || 0}" id="miningLevel"></div>
        <div class="stat-row"><span class="stat-label">钓鱼等级:</span> <input type="number" class="stat-input" value="\${playerData.FishingLevel || 0}" id="fishingLevel"></div>
        <div class="stat-row"><span class="stat-label">伐木等级:</span> <input type="number" class="stat-input" value="\${playerData.WoodcuttingLevel || 0}" id="woodcuttingLevel"></div>
    \`;

    // 采集加成
    document.getElementById('gatheringBoosts').innerHTML = \`
        <div class="stat-row"><span class="stat-label">挖矿:</span> <input type="number" class="stat-input" value="\${((playerData.TotalBoosts['30'] - 1 || 0) * 100).toFixed(2)}" id="miningBoost"><span style="margin-left: 4px;">%</span></div>
        <div class="stat-row"><span class="stat-label">钓鱼:</span> <input type="number" class="stat-input" value="\${((playerData.TotalBoosts['31'] - 1 || 0) * 100).toFixed(2)}" id="fishingBoost"><span style="margin-left: 4px;">%</span></div>
        <div class="stat-row"><span class="stat-label">伐木:</span> <input type="number" class="stat-input" value="\${((playerData.TotalBoosts['32'] - 1 || 0) * 100).toFixed(2)}" id="woodcuttingBoost"><span style="margin-left: 4px;">%</span></div>
        <div class="stat-row"><span class="stat-label">基础资源量:</span> <input type="number" class="stat-input" value="\${((playerData.TotalBoosts['124'] || 0) /100).toFixed(2)}" id="baseResourceBoost"></div>
    \`;
    
    // 法典加成
    document.getElementById('codexBoosts').innerHTML = \`
        <div class="stat-row"><span class="stat-label">魔法尘:</span> <input type="number" class="stat-input" value="\${playerData.TotalBoosts['101'] || 0}" id="codexManaDust"><span style="margin-left: 4px;">%</span></div>
        <div class="stat-row"><span class="stat-label">基础资源量:</span> <input type="number" class="stat-input" value="\${playerData.TotalBoosts['106'] || 0}" id="codexBaseResource"><span style="margin-left: 4px;">%</span></div>
        <div class="stat-row"><span class="stat-label">掉落加成:</span> <input type="number" class="stat-input" value="\${playerData.TotalBoosts['102'] || 0}" id="codexDropBoost"><span style="margin-left: 4px;">%</span></div>
    \`;
    
    // 其他装备加成
    document.getElementById('otherEquipmentBoosts').innerHTML = \`
        <div class="stat-row"><span class="stat-label">魔法尘:</span> <input type="number" class="stat-input" value="\${(playerData.TotalBoosts['121'] || 0)}" id="manaBoost"><span style="margin-left: 4px;">%</span></div>
        <div class="stat-row"><span class="stat-label">元素碎片:</span> <input type="number" class="stat-input" value="\${playerData.TotalBoosts['122'] || 0}" id="shardBoost"><span style="margin-left: 4px;">%</span></div>
        <div class="stat-row"><span class="stat-label">药水效果:</span> <input type="number" class="stat-input" value="\${playerData.TotalBoosts['108'] || 0}" id="potionBoost"><span style="margin-left: 4px;">%</span></div>
    \`;

    // 农场
    document.getElementById('farmBoosts').innerHTML = \`
        <div class="stat-row"><span class="stat-label">收获傀儡:</span> <input type="number" class="stat-input" value="\${playerData.TotalBoosts['130'] || 0}" id="harvestGolem"></div>
        <div class="stat-row"><span class="stat-label">肥料:</span> <input type="number" class="stat-input" value="\${playerData.TotalBoosts['131'] || 0}" id="fertilizer"></div>
        <div class="stat-row"><span class="stat-label">地块:</span> <input type="number" class="stat-input" value="\${playerData.TotalBoosts['132'] || 0}" id="farmPlots"></div>
        <div class="stat-row"><span class="stat-label">草药收获:</span> <input type="number" class="stat-input" value="\${(2.5 * (1 + playerData.TotalBoosts['130']/100)**0.9 * (1 + playerData.TotalBoosts['131']/100)**0.9 * (1 + playerData.TotalBoosts['132']/100)**0.9).toFixed(0) || 0}" id="farmHerbHarvest"><span style="margin-left: 4px;">/h</span></div>
        <div class="stat-row"><span class="stat-label">税收:</span> <input type="number" class="stat-input" value="\${(2.5 * (1 + playerData.TotalBoosts['130']/100)**0.9 * (1 + playerData.TotalBoosts['131']/100)**0.9 * (1 + playerData.TotalBoosts['132']/100)**0.9*200000).toFixed(0) || 0}" id="farmTax"><span style="margin-left: 4px;">/h</span></div>
    \`;
    
    document.getElementById('marketPrice').innerHTML = \`
        <div class="stat-row"><span class="stat-label">元素碎片:</span> <input type="number" class="stat-input" value="\${marketData.Sell['2'] || 0}" id="shardPrice"></div>
        <div class="stat-row"><span class="stat-label">法典:</span> <input type="number" class="stat-input" value="\${marketData.Sell['3'] || 0}" id="codexPrice"></div>
        <div class="stat-row"><span class="stat-label">鱼:</span> <input type="number" class="stat-input" value="\${marketData.Sell['7'] || 0}" id="fishPrice"></div>
        <div class="stat-row"><span class="stat-label">木:</span> <input type="number" class="stat-input" value="\${marketData.Sell['8'] || 0}" id="woodPrice"></div>
        <div class="stat-row"><span class="stat-label">铁:</span> <input type="number" class="stat-input" value="\${marketData.Sell['9'] || 0}" id="ironPrice"></div>
        <div class="stat-row"><span class="stat-label">智慧之根:</span> <input type="number" class="stat-input" value="\${marketData.Sell['40'] || 0}" id="sagerootPrice"></div>
        <div class="stat-row"><span class="stat-label">繁茂精华:</span> <input type="number" class="stat-input" value="\${marketData.Sell['41'] || 0}" id="bloomwellPrice"></div>
    \`;

    document.getElementById('needToSupplement').innerHTML = \`
        <div class="stat-row"><span class="stat-label">工会等级:</span> <input type="number" class="stat-input" value="\${values?.guild?.guildLevel || 100}" id="guildLevel"></div>
        <div class="stat-row"><span class="stat-label">连结水晶等级:</span> <input type="number" class="stat-input" value="\${values?.guild?.guildNexusCrystalLevel || 100}" id="guildNexusCrystalLevel"></div>
        <div class="stat-row"><span class="stat-label">工会魔法尘税率:</span> <input type="number" class="stat-input" value="\${values?.guild?.guildManaTax || 10}" id="guildManaTax"><span style="margin-left: 4px;">%</span></div>
        <div class="stat-row"><span class="stat-label">工会资源税率:</span> <input type="number" class="stat-input" value="\${values?.guild?.guildResonanceTax || 60}" id="guildResourceTax"><span style="margin-left: 4px;">%</span></div>
        <div class="stat-row"><span class="stat-label">工会碎片税率:</span> <input type="number" class="stat-input" value="\${values?.guild?.guildShardTax || 10}" id="guildShardTax"><span style="margin-left: 4px;">%</span></div>
        <div class="stat-row"><span class="stat-label">智慧药水等级:</span> <input type="number" class="stat-input" value="\${values?.guild?.wisdomPotionLevel || 10}" id="wisdomPotionLevel"></div>
        <div class="stat-row"><span class="stat-label">收获药水等级:</span> <input type="number" class="stat-input" value="\${values?.guild?.harvestingPotionLevel || 10}" id="harvestingPotionLevel"></div>
        <div class="stat-row"><span class="stat-label">回响药水等级:</span> <input type="number" class="stat-input" value="\${values?.guild?.resonancePotionLevel || 10}" id="resonancePotionLevel"></div>
    \`;
}

//#region getvalue
function getAllCurrentValues() {
    values = {
        basic: {
            battleLevel: getValue('battleLevel'),
            currentEnemy: getValue('currentEnemy'),
            miningLevel: getValue('miningLevel'),
            fishingLevel: getValue('fishingLevel'),
            woodcuttingLevel: getValue('woodcuttingLevel')
        },
        gathering: {
            miningBoost: getValue('miningBoost'),
            fishingBoost: getValue('fishingBoost'),
            woodcuttingBoost: getValue('woodcuttingBoost'),
            miningBaseBoost: globalPlayerData.BaseBoosts['30'],
            fishingBaseBoost: globalPlayerData.BaseBoosts['31'],
            woodcuttingBaseBoost: globalPlayerData.BaseBoosts['32'],
            baseResourceAmountTotal: getValue('baseResourceBoost'),
            baseResourceAmountBase: globalPlayerData.BaseBoosts['124']
        },
        codex: {
            codexManaDust: getValue('codexManaDust'),
            codexBaseResource: getValue('codexBaseResource'),
            codexDropBoost: getValue('codexDropBoost'),
            codexBaseResourceBase: globalPlayerData.BaseBoosts['106'],
            codexDropBoostBase: globalPlayerData.BaseBoosts['102']
        },
        equipment: {
            manaBoost: getValue('manaBoost'),
            shardBoost: getValue('shardBoost'),
            potionBoost: getValue('potionBoost'),
            potionBoostBase: globalPlayerData.BaseBoosts['108']
        },
        farm: {
            harvestGolem: getValue('harvestGolem'),
            fertilizer: getValue('fertilizer'),
            farmPlots: getValue('farmPlots'),
            farmHerbHarvest: getValue('farmHerbHarvest'),
            farmTax: getValue('farmTax')
        },
        market: {
            codexPrice: getValue('codexPrice'),
            fishPrice: getValue('fishPrice'),
            woodPrice: getValue('woodPrice'),
            ironPrice: getValue('ironPrice'),
            shardPrice: getValue('shardPrice'),
            sagerootPrice: getValue('sagerootPrice'),
            bloomwellPrice: getValue('bloomwellPrice')
        },
        guild: {
            guildLevel: getValue('guildLevel'),
            guildNexusCrystalLevel: getValue('guildNexusCrystalLevel'),
            guildManaTax: getValue('guildManaTax'),
            guildResonanceTax: getValue('guildResourceTax'),
            guildShardTax: getValue('guildShardTax'),
            wisdomPotionLevel: getValue('wisdomPotionLevel'),
            harvestingPotionLevel: getValue('harvestingPotionLevel'),
            resonancePotionLevel: getValue('resonancePotionLevel')
        }
    };
    
    document.getElementById('calcResults').innerHTML = \`
        <div class="calc-result">
            <h4>当前数据快照, 如有大出入,请检查这里的内容是否正确:</h4>
            <div style="font-family: monospace; background: #f5f5f5; padding: 10px; border-radius: 5px;">
                <strong>基础信息:</strong><br>
                战斗等级: \${values.basic.battleLevel}, 当前敌人: \${values.basic.currentEnemy}<br>
                技能等级: 挖矿\${values.basic.miningLevel} 钓鱼\${values.basic.fishingLevel} 伐木\${values.basic.woodcuttingLevel}<br><br>
                
                <strong>采集加成:</strong><br>
                挖矿: \${values.gathering.miningBoost}%, 钓鱼: \${values.gathering.fishingBoost}%, 伐木: \${values.gathering.woodcuttingBoost}%<br>
                基础资源量: \${values.gathering.baseResourceAmountTotal}<br><br>
                
                <strong>法典加成:</strong><br>
                魔法尘: \${values.codex.codexManaDust}%, 基础资源量: \${values.codex.codexBaseResource}%, 掉落加成: \${values.codex.codexDropBoost}%
                <br><br>
                
                <strong>装备加成:</strong><br>
                魔法尘: \${values.equipment.manaBoost}%, 元素碎片: \${values.equipment.shardBoost}%, 药水效果: \${values.equipment.potionBoost}%<br><br>
                
                <strong>农场系统:</strong><br>
                收获傀儡: \${values.farm.harvestGolem}, 肥料: \${values.farm.fertilizer}, 地块: \${values.farm.farmPlots}<br>
                草药收获: \${values.farm.farmHerbHarvest}/h, 税收: \${values.farm.farmTax}/h<br><br>
                
                <strong>市场价格:</strong><br>
                元素碎片: \${values.market.shardPrice}, 法典: \${values.market.codexPrice} <br>
                鱼: \${values.market.fishPrice}, 木: \${values.market.woodPrice}, 铁: \${values.market.ironPrice}<br>
                智慧之根: \${values.market.sagerootPrice}, 繁茂精华: \${values.market.bloomwellPrice}
                <br><br>
                
                <strong>手动输入信息:</strong><br>
                工会等级: \${values.guild.guildLevel}, 连结水晶等级: \${values.guild.guildNexusCrystalLevel}<br>
                工会魔法尘税率: \${values.guild.guildManaTax}%, 工会资源税率: \${values.guild.guildResonanceTax}%, 工会碎片税率: \${values.guild.guildShardTax}% <br>
                智慧药水等级: \${values.guild.wisdomPotionLevel}, 收获药水等级: \${values.guild.harvestingPotionLevel}
            </div>
        </div>
    \`;

    saveGlobalData();
}

function getValue(id) {
    const element = document.getElementById(id);
    return element ? (parseFloat(element.value) || 0) : 0;
}

function formatNumber(num) {
    if (num === 0) return '0.00';
    if (isNaN(num) || !isFinite(num)) return 'NaN';
    
    const isNegative = num < 0;
    const absNum = Math.abs(num);
    
    let result;
    if (absNum >= 1e15) {
        result = (absNum / 1e15).toFixed(2) + 'P';
    } else if (absNum >= 1e12) {
        result = (absNum / 1e12).toFixed(2) + 'T';  
    } else if (absNum >= 1e9) {
        result = (absNum / 1e9).toFixed(2) + 'B';   
    } else if (absNum >= 1e6) {
        result = (absNum / 1e6).toFixed(2) + 'M';  
    } else if (absNum >= 1e3) {
        result = (absNum / 1e3).toFixed(2) + 'K'; 
    } else {
        result = absNum.toFixed(2);
    }
    
    return isNegative ? '-' + result : result;
}

//#region shards
function calculateShards(){
    const totalLevel = values.basic.battleLevel*3 + values.basic.miningLevel + values.basic.fishingLevel + values.basic.woodcuttingLevel;
    const MinBaseShard = 100*Math.pow(1+totalLevel/10, 1-0.3*(totalLevel/(totalLevel+20000)));
    const potionShardBoost = 5* (1 + values.equipment.potionBoost/100) * values.guild.resonancePotionLevel;
    const totalShardBoost = values.equipment.shardBoost +  potionShardBoost;
    const minShardPerActionAfterTax = MinBaseShard * (1 + totalShardBoost / 100) * (1 - values.guild.guildShardTax / 100);
    const shardPerActionAfterTax = 1.5 * MinBaseShard * (1 + totalShardBoost / 100) * (1 - values.guild.guildShardTax / 100);
    const shardsPerDayAfterTax = shardPerActionAfterTax * ((1+(values.codex.codexDropBoost/100))*(1/80)*28800);
    const shardDailyValue = shardsPerDayAfterTax * values.market.shardPrice;
    return [shardsPerDayAfterTax, shardDailyValue, minShardPerActionAfterTax];
}

//#region farm
function calculateFarmIncome(){
    const herbsHourHarvestTotal = values.farm.farmHerbHarvest;
    const sageRootHourHarvest = herbsHourHarvestTotal/2;
    const bloomHourHarvest = herbsHourHarvestTotal/2; 

    const wisdomPotionConsume = values.guild.wisdomPotionLevel * (1+values.guild.wisdomPotionLevel) / 2;
    const harvestingPotionConsume = values.guild.harvestingPotionLevel * (1+values.guild.harvestingPotionLevel) / 2;
    const resonancePotionConsume = values.guild.resonancePotionLevel * (1+values.guild.resonancePotionLevel) / 2;


    const netSageRootGain = sageRootHourHarvest - wisdomPotionConsume - resonancePotionConsume;
    const netBloomGain = bloomHourHarvest - harvestingPotionConsume - resonancePotionConsume;

    const sagePrice = values.market.sagerootPrice;
    const bloomPrice = values.market.bloomwellPrice;
    const sageProfitPerDay = netSageRootGain * sagePrice * 24;
    const bloomProfitPerDay = netBloomGain * bloomPrice * 24;

    // console.log(netSageRootGain,netBloomGain,sageProfitPerDay,bloomProfitPerDay);
    return [sageRootHourHarvest, bloomHourHarvest, (wisdomPotionConsume + resonancePotionConsume), (harvestingPotionConsume + resonancePotionConsume), netSageRootGain, netBloomGain, sageProfitPerDay, bloomProfitPerDay];
}

//#region combat
function calculateCombatEfficiency(display = true){

    const baseMana = 0.0001 * Math.pow((values.basic.currentEnemy+150), 2) + Math.pow((values.basic.currentEnemy+150), 1.2) + 10 * (values.basic.currentEnemy+150);
    const manaPerAction = baseMana * (1 + values.codex.codexManaDust / 100) * (1 + values.equipment.manaBoost / 100);
    const manaPerDay = manaPerAction * 28800;
    const manaPerDayAfterTax = manaPerDay * (1 - values.guild.guildManaTax / 100);
    const [shardPerActionAfterTax, shardDailyValue,minShardPerActionAfterTax] = calculateShards();
    const [sageRootHourHarvest, bloomHourHarvest, sageRootHourConsume, bloomHourConsume, netSageRootGain, netBloomGain, sageProfitPerDay, bloomProfitPerDay] = calculateFarmIncome();
    const farmProfitPerDay = sageProfitPerDay + bloomProfitPerDay;

    const profitPerDayTotal = manaPerDayAfterTax + shardDailyValue + farmProfitPerDay;

    if(display){
        document.getElementById('calcResults').innerHTML = \`
            <div class="calc-result">
                <div style="font-family: monospace; background: #f5f5f5; padding: 10px; border-radius: 5px;">
                    魔法尘每天 \${formatNumber(manaPerDayAfterTax)}<br><br>

                    税后每动作碎片范围 \${formatNumber(minShardPerActionAfterTax)} ~ \${formatNumber(2*minShardPerActionAfterTax)}<br>
                    碎片每天 \${formatNumber(shardPerActionAfterTax)}<br>
                    碎片每天价值 \${formatNumber(shardDailyValue)}<br><br>

                    慧根每小时产出 \${formatNumber(sageRootHourHarvest)} 繁茂每小时产出 \${formatNumber(bloomHourHarvest)}<br>
                    慧根每小时消耗 \${formatNumber(sageRootHourConsume)} 繁茂每小时消耗 \${formatNumber(bloomHourConsume)}<br>
                    慧根每小时净产出 \${formatNumber(netSageRootGain)} 繁茂每小时净产出 \${formatNumber(netBloomGain)}<br>
                    慧根每日净利 \${formatNumber(sageProfitPerDay)} 繁茂每日净利 \${formatNumber(bloomProfitPerDay)}<br>
                    农场每天价值 \${formatNumber(farmProfitPerDay)}<br><br>

                    每日收入 \${formatNumber(profitPerDayTotal)}<br>
                </div>
            </div>
        \`;
    }

    return profitPerDayTotal;
}

//#region gathering
function calculateGatheringEfficiency(display = true, gatheringType = null){
    
    if (display && gatheringType === null) {
        const selectedType = document.getElementById('gatheringType').value;
        if (!values.ui) values.ui = {};
        values.ui.lastGatheringType = selectedType;
    }

    if(gatheringType === null){
        gatheringType = document.getElementById('gatheringType').value;
    }

    let level = 0;

    if (gatheringType === 'woodcutting') {
        level = values.basic.woodcuttingLevel;
    } else if (gatheringType === 'mining') {
        level = values.basic.miningLevel;
    } else if (gatheringType === 'fishing') {
        level = values.basic.fishingLevel;
    }
    const [shardPerActionAfterTax, shardDailyValue,minShardPerActionAfterTax] = calculateShards();

    // (1 + lvl * 0.03 + base_res_amount) * (100% + base_res%) * (100% + guild_lvl_res%) * (100% + skill_boost)
    const potionBaseResource = values.guild.harvestingPotionLevel * 0.1 * (1 + values.equipment.potionBoost/100);
    const baseResource = 1 + level * 0.03 + values.gathering.baseResourceAmountTotal + potionBaseResource; 
    const factor2 = 1 + values.codex.codexBaseResource/100; 
    const factor3 = 1 + values.guild.guildLevel/2/100; 
    const factor4 = 1 + values.gathering[gatheringType + 'Boost'] / 100;

    // console.log(level, baseResource, factor2, factor3, factor4);

    const resourcePerAction = baseResource * factor2 * factor3 * factor4;
    const resourcePerActionAfterTax = resourcePerAction * (1 - values.guild.guildResonanceTax / 100);
    const resourcePerDayAfterTax = resourcePerActionAfterTax * 28800;
    let resourcePrice = 0;
    if (gatheringType === 'woodcutting') {
        resourcePrice = values.market.woodPrice;
    } else if (gatheringType === 'mining') {
        resourcePrice = values.market.ironPrice;
    } else if (gatheringType === 'fishing') {
        resourcePrice = values.market.fishPrice;
    }
    let resourceProfitPerDay = resourcePerDayAfterTax * resourcePrice;

    const [sageRootHourHarvest, bloomHourHarvest, sageRootHourConsume, bloomHourConsume, netSageRootGain, netBloomGain, sageProfitPerDay, bloomProfitPerDay] = calculateFarmIncome();
    const farmProfitPerDay = sageProfitPerDay + bloomProfitPerDay;

    const profitPerDayTotal = resourceProfitPerDay + shardDailyValue + farmProfitPerDay;

    if(display){
        document.getElementById('calcResults').innerHTML = \`
            <div class="calc-result">
                <div style="font-family: monospace; background: #f5f5f5; padding: 10px; border-radius: 5px;">
                    资源每动作: \${formatNumber(resourcePerActionAfterTax)}<br>
                    资源每天: \${formatNumber(resourcePerDayAfterTax)}<br>
                    资源价格: \${formatNumber(resourcePrice)}<br>
                    资源每天价值: \${formatNumber(resourceProfitPerDay)}<br><br>
                    
                    税后每动作碎片范围 \${formatNumber(minShardPerActionAfterTax)} ~ \${formatNumber(2*minShardPerActionAfterTax)}<br>
                    碎片每天 \${formatNumber(shardPerActionAfterTax)}<br>
                    碎片每天价值 \${formatNumber(shardDailyValue)}<br><br>

                    慧根每小时产出 \${formatNumber(sageRootHourHarvest)} 繁茂每小时产出 \${formatNumber(bloomHourHarvest)}<br>
                    慧根每小时消耗 \${formatNumber(sageRootHourConsume)} 繁茂每小时消耗 \${formatNumber(bloomHourConsume)}<br>
                    慧根每小时净产出 \${formatNumber(netSageRootGain)} 繁茂每小时净产出 \${formatNumber(netBloomGain)}<br>
                    慧根每日净利 \${formatNumber(sageProfitPerDay)} 繁茂每日净利 \${formatNumber(bloomProfitPerDay)}<br>
                    农场每天价值 \${formatNumber(farmProfitPerDay)}<br><br>

                    每日收入 \${formatNumber(profitPerDayTotal)}<br>
                </div>
            </div>
        \`;
    }



    return profitPerDayTotal;

}

//#region ResonanceLevel
function calculateResonancePotionLevel(){
    // 我们要计算最佳的碎片药水等级
    // 具体说来就是,我们给定一个碎片药水等级 X,会有这个药水的农场每小时消耗,也会有这个药水可以额外带来的收益。
    // 我们要计算的首先就是这么一个函数,看一看函数具体是什么形状的。
    let resonancePotionLevelX = 0;

    function getResonancePotionConsume(resonancePotionLevelX) {
        const resonancePotionConsume = resonancePotionLevelX * (1+resonancePotionLevelX) / 2;
        const sageRootConsumePerDay = resonancePotionConsume * values.market.sagerootPrice * 24;
        const bloomConsumePerDay = resonancePotionConsume * values.market.bloomwellPrice * 24;
        const farmConsumePerDay = sageRootConsumePerDay + bloomConsumePerDay;
        return farmConsumePerDay;
    }

    function getResonancePotionExtraIncome(resonancePotionLevelX) {
        const totalLevel = values.basic.battleLevel*3 + values.basic.miningLevel + values.basic.fishingLevel + values.basic.woodcuttingLevel;
        const MinBaseShard = 100*Math.pow(1+totalLevel/10, 1-0.3*(totalLevel/(totalLevel+20000)));
        const potionShardBoost = 5* (1 + values.equipment.potionBoost/100) * resonancePotionLevelX;
        const shardPerActionAfterTax = 1.5 * MinBaseShard * (1 + potionShardBoost / 100) * (1 - values.guild.guildShardTax / 100);
        const shardsPerDayAfterTax = shardPerActionAfterTax * ((1+(values.codex.codexDropBoost/100))*(1/80)*28800);
        const shardDailyValue = shardsPerDayAfterTax * values.market.shardPrice;
        return shardDailyValue;
    }


    const totalLevel = values.basic.battleLevel * 3 + values.basic.miningLevel + values.basic.fishingLevel + values.basic.woodcuttingLevel;
    const MinBaseShard = 100 * Math.pow(1 + totalLevel/10, 1 - 0.3 * (totalLevel/(totalLevel + 20000)));
    const A = (values.market.sagerootPrice + values.market.bloomwellPrice) * 24;
    const B = 0.05 * (1 + values.equipment.potionBoost / 100);
    const C = 1.5 * MinBaseShard * (1 - values.guild.guildShardTax / 100) * 
            ((1 + values.codex.codexDropBoost / 100) * (1/80) * 28800) * 
            values.market.shardPrice;
    const optimalLevel = (C * B) / A - 0.5;
    const finalOptimalLevel = Math.max(0, optimalLevel);

    document.getElementById('calcResults').innerHTML = \`
    <div class="calc-result">
        <div style="font-family: monospace; background: #f5f5f5; padding: 10px; border-radius: 5px;">
            最佳的碎片药水等级: \${finalOptimalLevel.toFixed(2)}<br><br>
            相对0级药水<br>
            额外的农场消耗量: \${formatNumber(getResonancePotionConsume(finalOptimalLevel))}/day<br>
            额外的收益: \${formatNumber(getResonancePotionExtraIncome(finalOptimalLevel))}/day<br>
            提升的收益: \${formatNumber(getResonancePotionExtraIncome(finalOptimalLevel)-getResonancePotionConsume(finalOptimalLevel))}<br>
        </div>
    </div>\`;
}

// region Gather ROI
function calculateGatheringROI(){
    // 采集的投资回报率有以下几个方面的比较 0.0594 * 1000
    // 1 提升 1000 级 research boost
    // 2 提升 100 级 base resource amount
    // 3 提升 5 级 codex base resource
    // 4 提升 5 级 potion boost
    // 5 提升 5 级 codex drop rate
    // 6 总共提升 300 级 farm

    const gatheringType = document.getElementById('gatheringType2').value;

    const paths = {
        mining: { base: 'miningBaseBoost', total: 'miningBoost' },
        fishing: { base: 'fishingBaseBoost', total: 'fishingBoost' },
        woodcutting: { base: 'woodcuttingBaseBoost', total: 'woodcuttingBoost' }
    };

    // 1
    function calculateResearchBoost(incrementLevel) {
        const path = paths[gatheringType];
        const currentLevel = values.gathering[path.base];
        const oldBoostTotal = values.gathering[path.total];
        
        const shardsNeed = incrementLevel * (currentLevel + 1 + currentLevel + incrementLevel);
        const priceNeed = shardsNeed * values.market.shardPrice;
        
        const newBoostTotal = oldBoostTotal + incrementLevel * 0.02 * values.guild.guildNexusCrystalLevel / 100;
        
        values.gathering[path.total] = newBoostTotal;
        const newProfit = calculateGatheringEfficiency(false,gatheringType);
        values.gathering[path.total] = oldBoostTotal; 
        
        // console.log(\`research boost \${incrementLevel} level, \${shardsNeed} shards, \${formatNumber(priceNeed)} price, \${formatNumber(newProfit)} profit\`);
        return [priceNeed, newProfit];
    }

    // 2
    function calculateBaseResourceAmount(incrementLevel) {
        const currentLevel = values.gathering.baseResourceAmountBase;
        function sumOfSquares(n) {
            return n * (n + 1) * (2 * n + 1) / 6;
        }
        const priceNeed = (sumOfSquares(currentLevel+incrementLevel) - sumOfSquares(currentLevel))*100;
        const oldBaseResourceAmoutTotal = values.gathering.baseResourceAmountTotal;
        values.gathering.baseResourceAmountTotal += incrementLevel/100;
        const newProfit = calculateGatheringEfficiency(false);
        values.gathering.baseResourceAmountTotal = oldBaseResourceAmoutTotal;
        // console.log(\`base resource amount current Level \${currentLevel}, increment \${incrementLevel}, price need \${formatNumber(priceNeed)}, new profit \${formatNumber(newProfit)}\`);
        return [priceNeed, newProfit];
    }

    // 3
    function calculateCodexBaseResource(incrementLevel) {
        const currentLevel = values.codex.codexBaseResourceBase;
        function calculateCost(fromLevel, toLevel) {
            const startValue = fromLevel + 1;
            const endValue = toLevel;
            const n = endValue - startValue + 1; 
            const sum = n * (startValue + endValue) / 2;
            return sum;
        }
        const codexNeed = calculateCost(currentLevel, currentLevel+incrementLevel);
        const priceNeed = codexNeed * values.market.codexPrice;
        const oldCodexBaseResource = values.codex.codexBaseResource;
        values.codex.codexBaseResource += incrementLevel/100;
        const newProfit = calculateGatheringEfficiency(false);
        values.codex.codexBaseResource = oldCodexBaseResource;
        // console.log(\`codex base resource current Level \${currentLevel}, increment \${incrementLevel}, codex need \${codexNeed}, price need \${formatNumber(priceNeed)}, new profit \${formatNumber(newProfit)}\`);
        return [priceNeed, newProfit];
    }

    // 4
    function calculatePotionBoost(incrementLevel) {
        const currentLevel = values.equipment.potionBoostBase;
        function calculateCost(fromLevel, toLevel) {
            const baseCost = 10000000;
            const growthRate = 1.1;
            
            return Array.from({ length: toLevel - fromLevel }, (_, i) => fromLevel + i)
                .map(level => Math.floor(baseCost * Math.pow(growthRate, level)))
                .reduce((total, cost) => total + cost, 0);
        }
        const priceNeed = calculateCost(currentLevel, currentLevel+incrementLevel);
        const oldPotionBoost = values.equipment.potionBoost;
        values.equipment.potionBoost += incrementLevel/100;
        const newProfit = calculateGatheringEfficiency(false);
        values.equipment.potionBoost = oldPotionBoost;
        // console.log(\`potion boost current Level \${currentLevel}, increment \${incrementLevel}, price need \${formatNumber(priceNeed)}, new profit \${formatNumber(newProfit)}\`);
        return [priceNeed, newProfit];
    }

    // 5
    function calculateCodexDropRate(incrementLevel) {
        const currentLevel = values.codex.codexDropBoostBase;
        function calculateCost(fromLevel, toLevel) {
            const startValue = fromLevel + 1;
            const endValue = toLevel;
            const n = endValue - startValue + 1; 
            const sum = n * (startValue + endValue) / 2;
            return sum;
        }
        const codexNeed = calculateCost(currentLevel, currentLevel+incrementLevel);
        const priceNeed = codexNeed * values.market.codexPrice;
        const oldCodexDropRate = values.codex.codexDropBoost;
        values.codex.codexDropBoost += incrementLevel/100;
        const newProfit = calculateGatheringEfficiency(false);
        values.codex.codexDropBoost = oldCodexDropRate;
        // console.log(\`codex drop rate current Level \${currentLevel}, increment \${incrementLevel}, codex need \${codexNeed}, price need \${formatNumber(priceNeed)}, new profit \${formatNumber(newProfit)}\`);
        return [priceNeed, newProfit];
    }
    
    // 6
    function calculateFarmLevel(incrementLevel) {
        function calculateCost(fromLevel, toLevel) {
            function sumOfSquares(n) {
                return n * (n + 1) * (2 * n + 1) / 6;
            }
            return sumOfSquares(toLevel) - sumOfSquares(fromLevel);
        }

        const currentLevels = {
            harvestGolem: values.farm.harvestGolem,
            fertilizer: values.farm.fertilizer,
            farmPlots: values.farm.farmPlots
        };

        function optimizedAllocation(incrementLevel) {
            const projects = ['harvestGolem', 'fertilizer', 'farmPlots'];
            const levels = [currentLevels.harvestGolem, currentLevels.fertilizer, currentLevels.farmPlots];
            const allocations = [0, 0, 0];

            let remaining = incrementLevel;

            while (remaining > 0) {
                let minLevel = Math.min(...levels);
                let minIndices = [];
                
                for (let i = 0; i < levels.length; i++) {
                    if (levels[i] === minLevel) {
                        minIndices.push(i);
                    }
                }

                let nextHigherLevel = Math.min(...levels.filter(l => l > minLevel));
                if (!isFinite(nextHigherLevel)) {
                    const avgAllocation = Math.floor(remaining / minIndices.length);
                    const extraLevels = remaining % minIndices.length;

                    for (let i = 0; i < minIndices.length; i++) {
                        const idx = minIndices[i];
                        const allocation = avgAllocation + (i < extraLevels ? 1 : 0);
                        allocations[idx] += allocation;
                        levels[idx] += allocation;
                    }
                    remaining = 0;
                } else {
                    const levelGap = nextHigherLevel - minLevel;
                    const totalNeeded = levelGap * minIndices.length;

                    if (totalNeeded <= remaining) {
                        for (const idx of minIndices) {
                            allocations[idx] += levelGap;
                            levels[idx] += levelGap;
                        }
                        remaining -= totalNeeded;
                    } else {
                        const avgAllocation = Math.floor(remaining / minIndices.length);
                        const extraLevels = remaining % minIndices.length;

                        for (let i = 0; i < minIndices.length; i++) {
                            const idx = minIndices[i];
                            const allocation = avgAllocation + (i < extraLevels ? 1 : 0);
                            allocations[idx] += allocation;
                            levels[idx] += allocation;
                        }
                        remaining = 0;
                    }
                }
            }

            return {
                harvestGolem: allocations[0],
                fertilizer: allocations[1],
                farmPlots: allocations[2]
            };
        }

        const allocations = optimizedAllocation(incrementLevel);
        const costs = {
            harvestGolem: calculateCost(currentLevels.harvestGolem, currentLevels.harvestGolem + allocations.harvestGolem),
            fertilizer: calculateCost(currentLevels.fertilizer, currentLevels.fertilizer + allocations.fertilizer),
            farmPlots: calculateCost(currentLevels.farmPlots, currentLevels.farmPlots + allocations.farmPlots)
        };
        const priceNeed = costs.harvestGolem * values.market.ironPrice + costs.fertilizer * values.market.fishPrice + costs.farmPlots * values.market.woodPrice;
        const oldfarmHerbHarvest = values.farm.farmHerbHarvest;
        const newHarvestGolemLevel = currentLevels.harvestGolem + allocations.harvestGolem;
        const newFertilizerLevel = currentLevels.fertilizer + allocations.fertilizer;
        const newFarmPlotsLevel = currentLevels.farmPlots + allocations.farmPlots;
        values.farm.farmHerbHarvest = 2.5 * 
            Math.pow(1 + newHarvestGolemLevel/100, 0.9) * 
            Math.pow(1 + newFertilizerLevel/100, 0.9) * 
            Math.pow(1 + newFarmPlotsLevel/100, 0.9);
        const newProfit = calculateGatheringEfficiency(false);
        values.farm.farmHerbHarvest = oldfarmHerbHarvest;
        // console.log(\`farm level current Level \${currentLevels.harvestGolem}, \${currentLevels.fertilizer}, \${currentLevels.farmPlots}, increment \${incrementLevel}, price need \${formatNumber(priceNeed)}, new profit \${formatNumber(newProfit)}\`);
        return [priceNeed, newProfit];
    }

    const currentProfit = calculateGatheringEfficiency(false);
    // console.log(\`current profit \${currentProfit}\`);

    const research = calculateResearchBoost(3000);
    const baseResource = calculateBaseResourceAmount(100);
    const codexBase = calculateCodexBaseResource(5);
    const potion = calculatePotionBoost(5);
    const codexDrop = calculateCodexDropRate(5);
    const farm = calculateFarmLevel(300);

    const investments = [
        { name: "研究加成3000级", cost: research[0], profit: research[1]-currentProfit },
        { name: "基础资源100级", cost: baseResource[0], profit: baseResource[1]-currentProfit },
        { name: "法典基础5级", cost: codexBase[0], profit: codexBase[1]-currentProfit },
        { name: "药水加成5级", cost: potion[0], profit: potion[1]-currentProfit },
        { name: "法典掉落5级", cost: codexDrop[0], profit: codexDrop[1]-currentProfit },
        { name: "农场总共提升300级", cost: farm[0], profit: farm[1]-currentProfit }
    ];
    
    // console.log(farm.priceNeed, farm.newProfit);

    investments.forEach(item => {
        item.roi = item.cost > 0 ? (item.profit / item.cost * 10000) : 0;
    });
    investments.sort((a, b) => b.roi - a.roi);

    let resultHTML = \`
        <div class="calc-result">
            <div style="font-family: monospace; background: #f5f5f5; padding: 10px; border-radius: 5px;">
                <strong>\${gatheringType} 投资回报率对比:</strong><br><br>
    \`;
    
    investments.forEach((item, index) => {
        resultHTML += \`\${index + 1}. \${item.name}<br>\`;
        resultHTML += \`&nbsp;&nbsp;&nbsp;成本: \${formatNumber(item.cost)} | 额外日收益: \${formatNumber(item.profit)}<br>\`;
        resultHTML += \`&nbsp;&nbsp;&nbsp;ROI: \${item.roi.toFixed(2)}<br><br>\`;
    });
    
    resultHTML += \`</div></div>\`;
    
    document.getElementById('calcResults').innerHTML = resultHTML;

    const selectedType = document.getElementById('gatheringType2').value;
    if (!values.ui) values.ui = {};
    values.ui.lastGatheringType2 = selectedType;
}

// #region GatherEquip
function calculateGatherEquipReplace(){
    // 采集装备替换
    // 采集装备替换逻辑:
    // 1. 得到当前装备信息,当前使用的收获药水等级
    // 2. 每次点击按钮检查可以替换多少 base amount。

    function findLowestTypeBoostEquip(playerData) {
        const equipment = playerData.Equipment;
        let lowestEquip = null;
        let lowestBoost = Infinity;
        Object.values(equipment).forEach(item => {
            if (item.Slot == 1) {
                return;
            }
            const boosts = item.Boosts;
            const boostKeys = Object.keys(boosts);
            const lastBoostType = boostKeys[boostKeys.length - 1];
            if (lastBoostType === '124') {
                const infusions = item.Infusions || 0;
                const infusionMultiplier = 1 + (infusions * 0.05);
                const gatherBaseResourceAmout = boosts['124'] * infusionMultiplier / 100;
                if (gatherBaseResourceAmout < lowestBoost) {
                    lowestBoost = gatherBaseResourceAmout;
                    lowestEquip = item;
                }
            }
        });
        return lowestEquip ? lowestEquip: null;
    }

    function calculateHarvestingPotionCost(Level){
        const HarvestingPotionConsume = Level * (1+Level) / 2;
        const bloomwellPrice = values.market.bloomwellPrice;
        return HarvestingPotionConsume*bloomwellPrice*24;
    }

    const lowestEquip =  findLowestTypeBoostEquip(globalPlayerData);

    if (lowestEquip === null) {
        document.getElementById('calcResults').innerHTML = \`
            <div class="calc-result">
                <div style="font-family: monospace; background: #f5f5f5; padding: 10px; border-radius: 5px;">
                    采集装备替换说明<br>
                    检查当前身上的装备,目前使用的收获药水等级,计算是否有基础资源装备可以被替换为元素碎片装备(每次只会计算最小数值的装备)<br><br>
                    当前没有找到基础资源加成装备,结束<br>
                </div>
            </div>\`;
        return;
    }

    const baseResourceAmoutLose = lowestEquip.Boosts['124'] * (1 + (lowestEquip.Infusions * 0.05)) / 100;
    const currentHarvestingPotionLevel = values.guild.harvestingPotionLevel;
    function findMinHarvestingPotionLevel(baseResourceAmountLose, currentHarvestingPotionLevel) {
        function potionBaseResource(level) {
            return level * 0.1 * (1 + values.equipment.potionBoost / 100);
        }
        const currentPotionResource = potionBaseResource(currentHarvestingPotionLevel);
        const targetResource = currentPotionResource + baseResourceAmountLose;
        const targetLevel = targetResource / (0.1 * (1 + values.equipment.potionBoost / 100));
        return Math.ceil(targetLevel);
    }
    const minHarvestingPotionLevel = findMinHarvestingPotionLevel(baseResourceAmoutLose, currentHarvestingPotionLevel);

    const oldProfit = calculateGatheringEfficiency(false);
    const OldShardBoost = values.equipment.shardBoost;
    values.equipment.shardBoost += baseResourceAmoutLose*40;
    const newProfit = calculateGatheringEfficiency(false);
    values.equipment.shardBoost = OldShardBoost;

    const potionPriceDiffer = calculateHarvestingPotionCost(minHarvestingPotionLevel) - calculateHarvestingPotionCost(currentHarvestingPotionLevel);
    
    let resultHTML = \`
        <div class="calc-result">
            <div style="font-family: monospace; background: #f5f5f5; padding: 10px; border-radius: 5px;">
                采集装备替换说明<br>
                检查当前身上的装备,目前使用的收获药水等级,计算是否有基础资源装备可以被替换为元素碎片装备(每次只会计算最小数值的装备)<br>
                注意:根据【计算采集效率】按钮前面的框的值决定采集类型<br><br>
                当前使用的药水等级:\${currentHarvestingPotionLevel}。替换后使用的药水等级:\${minHarvestingPotionLevel}<br><br>
    \`;

    if(newProfit - oldProfit > potionPriceDiffer){
        resultHTML += \`
            当前基础资源加成装备:\${lowestEquip.Name} 可以被替换为 elemental shard 装备<br>
            当前基础资源加成装备基础资源量: \${baseResourceAmoutLose} 可以被替换为元素碎片加成 \${(baseResourceAmoutLose*40).toFixed(2)}%<br>
            替换后每日魔法尘增加 \${formatNumber(newProfit - oldProfit)}<br>
            替换后每日农场支出增加 \${formatNumber(calculateHarvestingPotionCost(minHarvestingPotionLevel) - calculateHarvestingPotionCost(currentHarvestingPotionLevel))}<br>
            替换后每日收入增加 \${formatNumber((newProfit - oldProfit) - (calculateHarvestingPotionCost(minHarvestingPotionLevel) - calculateHarvestingPotionCost(currentHarvestingPotionLevel)))}<br><br>
        \`;
    } else {
        resultHTML += \`看起来现在的药水等级+基础资源装情况,替换不了呢。结束<br>\`;
    }
    
    resultHTML += \`</div></div>\`;
    document.getElementById('calcResults').innerHTML = resultHTML;
}

// #region battlerEquip
function calculateBattlerEquipReplace(){

    const BOOST_TYPES = {
        120: "BATTLE_EXPERIENCE_BOOST",
        121: "MANA_DUST_BOOST", 
        122: "ELEMENTAL_SHARD_BOOST",
        123: "STAT_DROP"
    };

    function cheakReplaceEquip(playerData) {
        // region find lowest
        function findLowestTypeBoostEquip(playerData) {
            const equipment = playerData.Equipment;
            let lowestEquip = null;
            let lowestBoost = Infinity;
            Object.values(equipment).forEach(item => {
                const boosts = item.Boosts;
                const boostKeys = Object.keys(boosts);
                const lastBoostType = boostKeys[boostKeys.length - 1];
                if (lastBoostType === '120') {
                    const infusions = item.Infusions || 0;
                    const infusionMultiplier = 1 + (infusions * 0.05);
                    const battleExpBoost = boosts['120'] * infusionMultiplier;
                    if (battleExpBoost < lowestBoost) {
                        lowestBoost = battleExpBoost;
                        lowestEquip = item;
                    }
                }
            });
            return lowestEquip ? lowestEquip: null;
        }
        // region analyze all equip
        function analyzeCurrentEquipment(playerData) {
            const equipment = playerData.Equipment;
            const typeCount = {};
            const typeBoosts = {};
            
            Object.keys(BOOST_TYPES).forEach(type => {
                typeCount[type] = 0;
                typeBoosts[type] = 0;
            });

            Object.values(equipment).forEach(item => {
                const boosts = item.Boosts;
                const infusions = item.Infusions || 0;
                const infusionMultiplier = 1 + (infusions * 0.05);

                const boostKeys = Object.keys(boosts);
                const lastBoostType = boostKeys[boostKeys.length - 1];
                
                if (BOOST_TYPES[lastBoostType]) {
                    typeCount[lastBoostType]++;
                    let enhancedBoosts = {};
                    Object.entries(boosts).forEach(([boostId, baseValue]) => {
                        if (boostId !== lastBoostType) {
                            const enhancedValue = baseValue * infusionMultiplier;
                            enhancedBoosts[boostId] = enhancedValue;
                        } else {
                            typeBoosts[lastBoostType] += baseValue * infusionMultiplier;
                        }
                    });
                }
            });

            if(typeCount[121] > 1){
                typeBoosts[121] = typeBoosts[121] * (1-(typeCount[121]-1)*0.05);
            }
            return { typeCount, typeBoosts};
        }
        const lowestEquip =  findLowestTypeBoostEquip(playerData);
        
        if (lowestEquip === null) {
            document.getElementById('calcResults').innerHTML = \`
                <div class="calc-result">
                    <div style="font-family: monospace; background: #f5f5f5; padding: 10px; border-radius: 5px;">
                        战斗装备替换说明<br>
                        检查当前身上的装备,目前使用的智慧药水等级,计算是否有经验装备可以被替换为魔法尘/元素碎片装备(每次只会计算最小数值的装备)<br><br>
                        当前没有找到经验加成装备,结束<br>
                    </div>
                </div>\`;
            return null;
        }

        const EXPLost = lowestEquip.Boosts['120'] * (1 + (lowestEquip.Infusions * 0.05));

        let { typeCount, typeBoosts } = analyzeCurrentEquipment(playerData);

        // region to mana
        if(typeCount[121] > 1){
            typeBoosts[121] = typeBoosts[121] / (1-(typeCount[121]-1)*0.05);
        }
        typeBoosts[121] += EXPLost;
        typeCount[121]++;
        typeCount[120]--;
        if(typeCount[121] > 1){
            typeBoosts[121] = typeBoosts[121] * (1-(typeCount[121]-1)*0.05);
        }

        const oldProfit = calculateCombatEfficiency(false);
        const OldManaBoost = values.equipment.manaBoost;
        values.equipment.manaBoost = typeBoosts[121];
        let newProfit = calculateCombatEfficiency(false);
        values.equipment.manaBoost = OldManaBoost;

        function findMinTargetLevel(currentWisdomPotionLevel, EXPLost) {
            const potionBoostMultiplier = 1 + values.equipment.potionBoost/100;
            const currentPotionEXP = currentWisdomPotionLevel * 5 * potionBoostMultiplier;
            const minTargetLevel = (EXPLost + currentPotionEXP) / (5 * potionBoostMultiplier);
            const targetLevel = Math.ceil(minTargetLevel);
            return targetLevel;
        }
        function calculateWisdomPotionCost(Level){
            const wisdomPotionConsume = Level * (1+Level) / 2;
            const sageRootPrice = values.market.sagerootPrice;
            return wisdomPotionConsume*sageRootPrice*24;
        }
        const currentWisdomPotionLevel = values.guild.wisdomPotionLevel;
        const targetWisdomPotionLevel = findMinTargetLevel(currentWisdomPotionLevel, EXPLost);

        let resultHTML = \`
            <div class="calc-result">
                <div style="font-family: monospace; background: #f5f5f5; padding: 10px; border-radius: 5px;">
                    战斗装备替换说明<br>
                    检查当前身上的装备,目前使用的智慧药水等级,计算是否有经验装备可以被替换为魔法尘装备(每次只会计算最小数值的装备)<br><br>
                    当前使用的药水等级:\${currentWisdomPotionLevel}。替换后使用的药水等级:\${targetWisdomPotionLevel}<br><br>
        \`;

        let replaceEquip = 0;
        if ((newProfit - oldProfit) > (calculateWisdomPotionCost(targetWisdomPotionLevel) - calculateWisdomPotionCost(currentWisdomPotionLevel))) {
            resultHTML += \`
                当前经验加成装备:\${lowestEquip.Name} 可以被替换为 mana dust 装备<br>
                替换后每日魔法尘增加 \${formatNumber(newProfit - oldProfit)}<br>
                替换后每日农场支出增加 \${formatNumber(calculateWisdomPotionCost(targetWisdomPotionLevel) - calculateWisdomPotionCost(currentWisdomPotionLevel))}<br>
                替换后每日收入增加 \${formatNumber((newProfit - oldProfit) - (calculateWisdomPotionCost(targetWisdomPotionLevel) - calculateWisdomPotionCost(currentWisdomPotionLevel)))}<br><br>
            \`;
            replaceEquip = 1;
        }

        // region to shards
        ({ typeCount, typeBoosts } = analyzeCurrentEquipment(globalPlayerData));
        typeBoosts[122] += EXPLost;
        const OldShardBoost = values.equipment.shardBoost;
        values.equipment.shardBoost = typeBoosts[122];
        newProfit = calculateCombatEfficiency(false);
        values.equipment.shardBoost = OldShardBoost;
        if ((newProfit - oldProfit) > (calculateWisdomPotionCost(targetWisdomPotionLevel) - calculateWisdomPotionCost(currentWisdomPotionLevel))) {
            resultHTML += \`
                当前经验加成装备:\${lowestEquip.Name} 可以被替换为 elemental shard 装备<br>
                替换后每日魔法尘增加 \${formatNumber(newProfit - oldProfit)}<br>
                替换后每日农场支出增加 \${formatNumber(calculateWisdomPotionCost(targetWisdomPotionLevel) - calculateWisdomPotionCost(currentWisdomPotionLevel))}<br>
                替换后每日收入增加 \${formatNumber((newProfit - oldProfit) - (calculateWisdomPotionCost(targetWisdomPotionLevel) - calculateWisdomPotionCost(currentWisdomPotionLevel)))}<br><br>
            \`;
        } else if(replaceEquip === 0) {
            resultHTML += \`看起来现在的药水等级+经验装情况,替换不了呢。结束<br>\`;
        }

        resultHTML += \`</div></div>\`;
        document.getElementById('calcResults').innerHTML = resultHTML;
    }

    cheakReplaceEquip(globalPlayerData);
}

window.onload = function() {
    showMessage('点击"获取数据"按钮获取最新玩家数据,或查看下方示例数据', 'success');
    loadGlobalData();
    showExampleData();
};

window.addEventListener('beforeunload', function() {
    saveGlobalData();
});


</script>
</body>
</html>`; }

    // 按钮点击处理
    function handleButtonClick() {
        console.log("Button clicked!");
        
        // 检查是否已存在面板
        let panel = document.getElementById('manarion-calculator-panel');
        if (panel) {
            panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
            return;
        }
        
        // 创建浮动面板
        panel = document.createElement('div');
        panel.id = 'manarion-calculator-panel';
        panel.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 90%;
            max-width: 1200px;
            height: 80vh;
            background: white;
            border-radius: 15px;
            box-shadow: 0 20px 60px rgba(0,0,0,0.3);
            z-index: 1000000;
            overflow: auto;
        `;
        
        const iframe = document.createElement('iframe');
        iframe.style.cssText = 'width: 100%; height: 100%; border: none; border-radius: 15px;';
        panel.appendChild(iframe);
        
        document.body.appendChild(panel);
        
        const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
        iframeDoc.open();
        iframeDoc.write(getFullHTMLContent());
        iframeDoc.close();

        iframe.contentWindow.fetchDataWithGM = async function(url) {
            return new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                    method: 'GET',
                    url: url,
                    headers: {
                        'Accept': 'application/json',
                        'User-Agent': 'Mozilla/5.0'
                    },
                    onload: function(response) {
                        try {
                            resolve(JSON.parse(response.responseText));
                        } catch (e) {
                            reject(e);
                        }
                    },
                    onerror: reject
                });
            });
        };
        
        const closeBtn = document.createElement('button');
        closeBtn.innerHTML = '✕';
        closeBtn.style.cssText = `
            position: absolute;
            top: 10px;
            right: 10px;
            width: 40px;
            height: 40px;
            border-radius: 50%;
            border: none;
            background: #ff4444;
            color: white;
            font-size: 24px;
            cursor: pointer;
            z-index: 1000001;
        `;
        closeBtn.onclick = () => panel.style.display = 'none';
        panel.appendChild(closeBtn);
    }

    function initHelper() {
        createDraggableButton();
    }

    function createDraggableButton() {
        if (document.getElementById('manarion-helper-button')) return;

        const button = document.createElement('div');
        button.id = 'manarion-helper-button';
        button.innerHTML = `
            <svg width="40" height="40" fill="white" viewBox="0 0 24 24">
                <path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
            </svg>
        `;

        Object.assign(button.style, {
            position: 'fixed',
            top: '50%',
            right: '20px',
            transform: 'translateY(-50%)',
            width: '80px',
            height: '80px',
            background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
            borderRadius: '50%',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            cursor: 'move',
            boxShadow: '0 8px 25px rgba(0,0,0,0.3)',
            zIndex: '999999',
            transition: 'all 0.3s ease',
            border: '4px solid rgba(255,255,255,0.2)',
            userSelect: 'none'
        });

        // 拖拽功能
        let isDragging = false;
        let hasMoved = false;
        let startX = 0;
        let startY = 0;
        let initialX = 0;
        let initialY = 0;

        button.addEventListener('mousedown', (e) => {
            isDragging = true;
            hasMoved = false;
            startX = e.clientX;
            startY = e.clientY;
            
            const rect = button.getBoundingClientRect();
            initialX = rect.left;
            initialY = rect.top;
            
            button.style.transition = 'none';
            button.style.cursor = 'grabbing';
            e.preventDefault();
        });

        document.addEventListener('mousemove', (e) => {
            if (!isDragging) return;
            
            const deltaX = e.clientX - startX;
            const deltaY = e.clientY - startY;
            
            // 检查是否真的移动了(移动超过5像素才算拖拽)
            if (Math.abs(deltaX) > 5 || Math.abs(deltaY) > 5) {
                hasMoved = true;
            }
            
            if (hasMoved) {
                const newX = initialX + deltaX;
                const newY = initialY + deltaY;
                
                // 限制在窗口内
                const limitedX = Math.max(0, Math.min(newX, window.innerWidth - 80));
                const limitedY = Math.max(0, Math.min(newY, window.innerHeight - 80));
                
                button.style.left = limitedX + 'px';
                button.style.top = limitedY + 'px';
                button.style.right = 'auto';
                button.style.transform = 'none';
            }
        });

        document.addEventListener('mouseup', () => {
            if (isDragging) {
                if (!hasMoved) {
                    handleButtonClick();
                }
                
                isDragging = false;
                hasMoved = false;
                button.style.transition = 'all 0.3s ease';
                button.style.cursor = 'move';
            }
        });

        // 悬停效果
        button.addEventListener('mouseenter', () => {
            if (!isDragging) {
                button.style.transform = button.style.transform === 'translateY(-50%)' ? 
                    'translateY(-50%) scale(1.1)' : 'scale(1.1)';
                button.style.boxShadow = '0 12px 35px rgba(0,0,0,0.4)';
            }
        });

        button.addEventListener('mouseleave', () => {
            if (!isDragging) {
                button.style.transform = button.style.transform.includes('translateY(-50%)') ? 
                    'translateY(-50%)' : 'none';
                button.style.boxShadow = '0 8px 25px rgba(0,0,0,0.3)';
            }
        });

        document.body.appendChild(button);
        console.log('Manarion Helper Button created!');
    }

    // 初始化
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initHelper);
    } else {
        setTimeout(initHelper, 1000);
    }

})();