您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
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 += \` 成本: \${formatNumber(item.cost)} | 额外日收益: \${formatNumber(item.profit)}<br>\`; resultHTML += \` 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); } })();