您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A heavily modified and intelligent version based on Keith's original work. Features a task scheduler, conflict avoidance, and highly automated gameplay loops.
// ==UserScript== // @name TheresMore Modifier - Gemini Enhanced Edition // @name:zh-CN TheresMore 修改器 - Gemini 增强版 // @namespace https://github.com/VincentHDLee // @version 6.0.0 // @description A heavily modified and intelligent version based on Keith's original work. Features a task scheduler, conflict avoidance, and highly automated gameplay loops. // @description:zh-CN 在Keith的原版基础上进行了大量重构和智能化升级。拥有任务调度器、冲突规避、智能黑白名单等功能,实现高度自动化的游戏体验。 // @author VincentHDLee (Original by Keith, Co-authored by Gemini) // @match https://theresmoregame.g8hh.com.cn/* // @match https://theresmore.thpatch.net/* // @grant none // @license MIT // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // ==/UserScript== (function () { 'use strict'; // --- 1. 最终版全局配置与知识库 --- const ids = { resources: ['research','food','wood','stone','gold','tools','copper','iron','cow','horse','luck','mana','building_material','faith','supplies','crystal','steel','saltpetre','natronite', 'lumix'], prestige: ['legacy'], special: ['relic','coin','tome_wisdom','gem','titan_gift','light'] }; const houseList = ['房屋', '市政厅', '宅邸', '住宅区', '发展部', '定居点大厅']; const universalBlacklist = ['神殿', '雕像']; // [v5.3 最终版] 危险研究关键词黑名单 const dangerousResearchKeywords = [ '结束时代', '结束本局游戏', '进入一个新时代', '开启新纪元', '新世界', '结束当前周目', '发射', '光荣退休', '点亮亡者之门', '无智之恶','富甲天下' ]; // [v5.3 最终版] 安全主题白名单 const safeThemePrefixes = ['青铜', '铁', '钢', '精金', '秘银', '经济', '宗教', '战争', '内部', '地窖', '黑暗', '神圣', '召唤', '信号', '长矛', '黄金', '纳红石']; // [v5.3 最终版] 已知选择组黑名单 const knownChoiceGroups = [ ['赢得民心', '说服贵族'], ['信仰的灯塔', '军事定居点', '生产中心'], ['保护之力', '增量之力'], ['展示火焰', '注入火焰'], ['驱逐德鲁伊', '接纳德鲁伊'], ['召唤窃魂者', '修建堡垒'], ['专注于发展', '专注于魔法', '专注于研究'], ['召唤尼哈鲁尔', '重建堡垒'], ['渴望神谕', '渴望魔法', '渴望战斗'], ['泽尼克斯的统御者', '泽尼克斯的训战官'], ['泽尼克斯的大法师', '泽尼克斯的铸金使'], ['黄金工厂', '法力工厂'], ['月明之夜', '全日庆祝活动'], ['光荣退休', '光荣游行'] ]; const mainSchedulerInterval = 500; const TASK_LEASE_DURATION = 3000; const BUILD_CLICKS_BEFORE_SWITCH = 5; let autoResearchOn = false, autoUpdateOn = false, autoMagicOn = false, infiniteResourcesOn = false; let mainSchedulerTimer = null, infiniteResourcesTimer = null; let taskLeaseHolder = null, taskLeaseEndTime = 0, schedulerTurn = 0; let buildCounter = 0, buildBlackList = [], isCurseTurn = true; // --- 2. UI 渲染 --- const link = document.createElement('link'); link.href = 'https://fonts.googleapis.com/css2?family=Cinzel:wght@700&display=swap'; link.rel = 'stylesheet'; document.head.appendChild(link); const style = ` #mod-ui { position: fixed; top: 10px; right: 10px; background: #000; color: #ddd; border: 1px solid #333; padding: 10px; z-index: 10000; width: 320px; box-shadow: 0 0 10px rgba(0,0,0,0.4); font-family: Arial, sans-serif; } #mod-ui h3 { margin: 10 0 10px 0; font-size: 18px; color: #d4af37; cursor: move; font-family: 'Cinzel', serif; text-shadow: 1px 1px 2px #000; } #mod-ui h4 { margin: 10px 0 5px 0; font-size: 14px; color: #ccc; } #mod-ui button { padding: 8px 10px; width: 100%; background-color: #004499; color: #ddd; border: none; cursor: pointer; box-sizing: border-box; margin-bottom: 10px; } #mod-ui button.toggle-btn { position: absolute; top: 10px; right: 10px; width: 30px; height: 30px; background-color: #1d1e20; border: none; border-radius: 30%; cursor: pointer; z-index: 10001; } #mod-ui button:hover { background-color: #002266; } #mod-ui button.toggle-btn:hover { background-color: #333; } #mod-ui .function-row { display: flex; flex-direction: column; align-items: stretch; gap: 5px; margin-top: 8px; margin-bottom: 5px; } #mod-ui .function-row > button { width: 100%; padding: 5px 10px; margin:0; } #mod-ui .locations-container { display: flex; justify-content: space-around; padding: 5px 0 5px 0; background-color: #111; border-radius: 4px; margin-top: 8px; margin-bottom: 5px;} #mod-ui .locations-container label { display: flex; align-items: center; gap: 4px; color: #ccc; font-size: 12px;} #mod-ui .locations-container input[type=checkbox] { margin: 0; } `; const styleElement = document.createElement('style'); styleElement.innerText = style; document.head.appendChild(styleElement); const uiElement = document.createElement('div'); uiElement.id = 'mod-ui'; uiElement.innerHTML = ` <h3>TheresMore Modifier</h3> <button id="togglebtn" class="toggle-btn"></button> <div id="mod-ui-content"> <h4>资源修改</h4> <button id="toggle-infinite-resources-btn">无限资源: 已关闭</button> <h4>功能开关</h4> <div class="function-row"><button id="toggleSpeed">瞬间完成: 已关闭</button></div> <div id="build-locations" class="locations-container"> <label><input type="checkbox" name="build-location" value="城市" checked>城市</label> <label><input type="checkbox" name="build-location" value="定居点" checked>定居点</label> <label><input type="checkbox" name="build-location" value="深渊" checked>深渊</label> </div> <div class="function-row"><button id="toggleAutoUpdate">自动建造: 已关闭</button></div> <div class="function-row"><button id="toggleAutoResearch">自动研究: 已关闭</button></div> <div class="function-row"><button id="toggleAutoMagic">自动魔法: 已关闭</button></div> </div> `; document.body.appendChild(uiElement); // --- 3. 辅助函数定义 --- function toggleBtnText(id, text) { const btn = document.getElementById(id); if (btn) btn.textContent = text; } function getGameData() { const r = document.getElementById('root'), k = r ? Object.keys(r).find(k => k.startsWith('__reactContainer$')) : null; return k ? r[k]?.stateNode?.current?.child?.memoizedProps?.MainStore : null; } function setAllResourcesToMax() { const MAX_AMOUNT = 9999999999999999; const gameData = getGameData(); if (!gameData?.run?.resources) return; const allResourceIds = [...Object.values(ids).flat()]; gameData.run.resources.forEach(resource => { if (allResourceIds.includes(resource.id)) { resource.value = MAX_AMOUNT; } }); } function hasSharedSubstring(strA, strB, length = 2) { const [shortStr, longStr] = strA.length < strB.length ? [strA, strB] : [strB, strA]; for (let i = 0; i <= shortStr.length - length; i++) { const substring = shortStr.substring(i, i + length); if (longStr.includes(substring)) return true; } return false; } // [v5.3 最终版] 三层智能审查函数 function findSafeButtons(buttons) { const whitelistedButtons = new Set(buttons.filter(b => safeThemePrefixes.some(prefix => b.textContent.trim().startsWith(prefix)))); const nonWhitelisted = buttons.filter(b => !whitelistedButtons.has(b)); const toSkip = new Set(); const nonWhitelistedTexts = nonWhitelisted.map(b => b.textContent.trim()); for (const group of knownChoiceGroups) { const foundItems = group.filter(item => nonWhitelistedTexts.includes(item)); if (foundItems.length > 1) { foundItems.forEach(itemText => { const btn = nonWhitelisted.find(b => b.textContent.trim() === itemText); if(btn) toSkip.add(btn); }); } } const remainingForFinalCheck = nonWhitelisted.filter(b => !toSkip.has(b)); const remainingTexts = remainingForFinalCheck.map(b => b.textContent.trim()); for (let i = 0; i < remainingTexts.length; i++) { for (let j = i + 1; j < remainingTexts.length; j++) { if (hasSharedSubstring(remainingTexts[i], remainingTexts[j])) { toSkip.add(remainingForFinalCheck[i]); toSkip.add(remainingForFinalCheck[j]); } } } const safeStandaloneButtons = remainingForFinalCheck.filter(b => !toSkip.has(b)); return [...whitelistedButtons, ...safeStandaloneButtons]; } // --- 4. 任务调度器核心 --- function checkSchedulerState() { const anyTaskOn = autoResearchOn || autoUpdateOn || autoMagicOn; if (anyTaskOn && !mainSchedulerTimer) { mainSchedulerTimer = setInterval(runTasks, mainSchedulerInterval); } else if (!anyTaskOn && mainSchedulerTimer) { clearInterval(mainSchedulerTimer); mainSchedulerTimer = null; } } function patrolAndClosePopup() { const d = document.querySelector('#headlessui-portal-root'); if (d && d.innerHTML !== '') { const b = d.querySelector('button.absolute') || Array.from(d.querySelectorAll('button')).find(btn => btn.textContent.includes('取消') || btn.textContent.includes('关闭')) || (d.querySelector('.sr-only') && d.querySelector('.sr-only').parentElement); if (b) { b.click(); return true; } } return false; } function runTasks() { if (patrolAndClosePopup()) { taskLeaseHolder = 'build'; taskLeaseEndTime = Date.now() + TASK_LEASE_DURATION; if (autoUpdateOn) autoClickBuilding(); schedulerTurn = 1; return; } if (taskLeaseHolder && Date.now() > taskLeaseEndTime) { taskLeaseHolder = null; } if (taskLeaseHolder) { if (taskLeaseHolder === 'research' && autoResearchOn) autoClickResearch(); else if (taskLeaseHolder === 'build' && autoUpdateOn) autoClickBuilding(); else if (taskLeaseHolder === 'magic' && autoMagicOn) autoClickMagic(); return; } const taskOrder = [{ name: 'research', enabled: autoResearchOn, func: autoClickResearch }, { name: 'build', enabled: autoUpdateOn, func: autoClickBuilding }, { name: 'magic', enabled: autoMagicOn, func: autoClickMagic }]; for (let i = 0; i < taskOrder.length; i++) { let currentIndex = (schedulerTurn + i) % taskOrder.length; const task = taskOrder[currentIndex]; if (task.enabled) { if (task.func()) { taskLeaseHolder = task.name; taskLeaseEndTime = Date.now() + TASK_LEASE_DURATION; schedulerTurn = (currentIndex + 1) % taskOrder.length; return; } } } schedulerTurn = (schedulerTurn + 1) % taskOrder.length; } // --- 5. 各功能模块逻辑 --- function autoResearchChanger() { autoResearchOn = !autoResearchOn; toggleBtnText('toggleAutoResearch', `自动研究: ${autoResearchOn ? '已开启' : '已关闭'}`); checkSchedulerState(); } function autoClickResearch() { const researchTabButton = Array.from(document.querySelectorAll('#main-tabs > div[role=tablist] > button')).find(tab => tab.textContent.includes('研究')); if (!researchTabButton) return false; if (researchTabButton.getAttribute('aria-selected') === 'false') { researchTabButton.click(); return true; } const panel = document.getElementById(researchTabButton.getAttribute('aria-controls')); if (!panel) return false; const researchSubTab = Array.from(panel.querySelectorAll('button[role="tab"]')).find(t => t.textContent.includes('研究')); if(researchSubTab && researchSubTab.getAttribute('aria-selected') === 'false') { researchSubTab.click(); return true; } let availableButtons = Array.from(panel.querySelectorAll('button.btn:not(.btn-off)')); availableButtons = availableButtons.filter(b => { const text = b.textContent.trim(); return !universalBlacklist.some(keyword => text.includes(keyword)) && !dangerousResearchKeywords.some(keyword => text.includes(keyword)); }); if (availableButtons.length === 0) return false; const buttonsToClick = findSafeButtons(availableButtons); if (buttonsToClick.length > 0) { buttonsToClick.forEach(button => button.click()); return true; } return false; } function autoUpdateChanger() { autoUpdateOn = !autoUpdateOn; toggleBtnText('toggleAutoUpdate', `自动建造: ${autoUpdateOn ? '已开启' : '已关闭'}`); buildCounter = 0; checkSchedulerState(); } function autoClickBuilding() { const buildTab = document.querySelector('#main-tabs > div[role=tablist] > button'); if (!buildTab) return false; if (buildTab.getAttribute('aria-selected') === 'false') { buildTab.click(); buildCounter = 0; return true; } const panel = document.getElementById(buildTab.getAttribute('aria-controls')); if (!panel) return false; const enabledLocations = Array.from(document.querySelectorAll('#build-locations input:checked')).map(cb => cb.value); if (enabledLocations.length === 0) return false; const subTabsContainer = panel.querySelector('div[role=tablist]'); const hasMultipleSubTabs = subTabsContainer && subTabsContainer.children.length > 1; const currentSubTab = subTabsContainer?.querySelector('button[aria-selected=true]'); if (hasMultipleSubTabs && currentSubTab && !enabledLocations.includes(currentSubTab.textContent.trim())) { const firstValidTab = Array.from(subTabsContainer.children).find(t => enabledLocations.includes(t.textContent.trim())); if (firstValidTab) { firstValidTab.click(); buildCounter = 0; return true; } } buildBlackList = universalBlacklist.concat(judgeFood()); const upgradeables = Array.from(panel.querySelectorAll('button.btn')).filter(n => { if (n.classList.contains('btn-off')) return false; const text = n.textContent.trim(); return !buildBlackList.some(w => text.includes(w)); }); let didSomeAction = false; if (upgradeables.length > 0) { upgradeables.forEach(n => n.click()); buildCounter++; didSomeAction = true; } if (hasMultipleSubTabs && (buildCounter >= BUILD_CLICKS_BEFORE_SWITCH || (didSomeAction === false && upgradeables.length === 0))) { if (currentSubTab) { const allSubTabs = Array.from(subTabsContainer.children); const validSubTabs = allSubTabs.filter(t => enabledLocations.includes(t.textContent.trim())); if (validSubTabs.length > 0) { const currentIndexInValid = validSubTabs.indexOf(currentSubTab); const nextIndex = (currentIndexInValid + 1) % validSubTabs.length; validSubTabs[nextIndex].click(); buildCounter = 0; didSomeAction = true; } } } return didSomeAction; } function judgeFood() { const foodTable = document.querySelector('table'); if (!foodTable) return []; const r = Array.from(foodTable.querySelectorAll('tr')).find(n => n.innerText.includes('食物')); if (!r) return []; const c = r.childNodes[2]; if (!c) return []; const v = Number(c.innerText.split('/')[0]); return v < 5 ? houseList : []; } function autoMagicChanger() { autoMagicOn = !autoMagicOn; toggleBtnText('toggleAutoMagic', `自动魔法: ${autoMagicOn ? '已开启' : '已关闭'}`); checkSchedulerState(); } function autoClickMagic() { const magicTabButton = Array.from(document.querySelectorAll('#main-tabs > div[role=tablist] > button')).find(tab => tab.textContent.includes('魔法')); if (!magicTabButton) return false; if (magicTabButton.getAttribute('aria-selected') === 'false') { magicTabButton.click(); return true; } const panel = document.getElementById(magicTabButton.getAttribute('aria-controls')); if (!panel) return false; const subTabsContainer = panel.querySelector('div[role=tablist]'); if (!subTabsContainer) return false; let didWork = false; if (isCurseTurn) { const curseTab = Array.from(subTabsContainer.children).find(t => t.textContent.includes('咒语')); if (curseTab) { if (curseTab.getAttribute('aria-selected') === 'false') { curseTab.click(); return true; } const cursePanel = document.getElementById(curseTab.getAttribute('aria-controls')); if(!cursePanel) return false; const curseButtons = Array.from(cursePanel.querySelectorAll('button')).filter(b => b.textContent.includes('施放咒语')); if (curseButtons.length > 0) { curseButtons.forEach(b => b.click()); didWork = true; } } } else { const prayerTab = Array.from(subTabsContainer.children).find(t => t.textContent.includes('祈祷')); if (prayerTab) { if (prayerTab.getAttribute('aria-selected') === 'false') { prayerTab.click(); return true; } const prayerPanel = document.getElementById(prayerTab.getAttribute('aria-controls')); if(!prayerPanel) return false; let prayerButtons = Array.from(prayerPanel.querySelectorAll('button.btn:not(.btn-off)')); prayerButtons = prayerButtons.filter(b => !universalBlacklist.some(keyword => b.textContent.includes(keyword))); if(prayerButtons.length > 0) { const buttonsToClick = findSafeButtons(prayerButtons); if (buttonsToClick.length > 0) { buttonsToClick.forEach(b => b.click()); didWork = true; } } } } isCurseTurn = !isCurseTurn; return didWork; } let speedOn = false, game; function toggleInstantComplete() { speedOn = !speedOn; toggleBtnText('toggleSpeed', `瞬间完成: ${speedOn ? '已开启' : '已关闭'}`); if (!game) game = getGameData(); if (!game) { return; } if (!game.ArmyStore.originalWaitTime) game.ArmyStore.originalWaitTime = game.ArmyStore.waitTime; if (!game.ArmyStore.realDestroyArmy) game.ArmyStore.realDestroyArmy = game.ArmyStore.destroyArmy; if (speedOn) { game.ArmyStore.waitTime = 1; game.ArmyStore.destroyArmy = function (...args) { if (!(args[2] == 'army' && args[3] != !0)) return this.realDestroyArmy(...args); }; } else { game.ArmyStore.waitTime = game.ArmyStore.originalWaitTime; game.ArmyStore.destroyArmy = game.ArmyStore.realDestroyArmy; } } function toggleInfiniteResources() { infiniteResourcesOn = !infiniteResourcesOn; toggleBtnText('toggle-infinite-resources-btn', `无限资源: ${infiniteResourcesOn ? '已开启' : '已关闭'}`); if (infiniteResourcesOn) { setAllResourcesToMax(); infiniteResourcesTimer = setInterval(setAllResourcesToMax, 1500); } else { clearInterval(infiniteResourcesTimer); infiniteResourcesTimer = null; } } // --- 6. 事件监听器绑定 --- function init() { const upIcon = `<svg width="12" height="12" viewBox="0 0 24 24"><path fill="none" stroke="#ddd" stroke-width="4" d="M4 16l8-8 8 8"/></svg>`; const downIcon = `<svg width="12" height="12" viewBox="0 0 24 24"><path fill="none" stroke="#ddd" stroke-width="4" d="M4 8l8 8 8-8"/></svg>`; const findAndBind = (id, handler) => document.getElementById(id)?.addEventListener('click', handler); findAndBind('toggleAutoResearch', autoResearchChanger); findAndBind('toggleAutoUpdate', autoUpdateChanger); findAndBind('toggleSpeed', toggleInstantComplete); findAndBind('toggle-infinite-resources-btn', toggleInfiniteResources); findAndBind('toggleAutoMagic', autoMagicChanger); const toggleVisibilityBtn = document.getElementById('togglebtn'); toggleVisibilityBtn.innerHTML = upIcon; findAndBind('togglebtn', () => { const c = document.querySelector('#mod-ui-content'), i = c.style.display === 'none'; c.style.display = i ? 'block' : 'none'; toggleVisibilityBtn.innerHTML = i ? upIcon : downIcon; }); let drag_pos1 = 0, drag_pos2 = 0, drag_pos3 = 0, drag_pos4 = 0; uiElement.querySelector('h3').onmousedown = (e) => { e = e || window.event; e.preventDefault(); drag_pos3 = e.clientX; drag_pos4 = e.clientY; document.onmouseup = () => { document.onmouseup = null; document.onmousemove = null; }; document.onmousemove = (ev) => { ev = ev || window.event; ev.preventDefault(); drag_pos1 = drag_pos3 - ev.clientX; drag_pos2 = drag_pos4 - ev.clientY; drag_pos3 = ev.clientX; drag_pos4 = ev.clientY; uiElement.style.top = (uiElement.offsetTop - drag_pos2) + "px"; uiElement.style.left = (uiElement.offsetLeft - drag_pos1) + "px"; }; }; } setTimeout(init, 2000); })();