您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A bot that automatically fights for you in battledome
// ==UserScript== // @name Neopets - Karla's Battledome Bot // @namespace karla@neopointskarla // @license GPL3 // @version 0.1.3 // @description A bot that automatically fights for you in battledome // @author Karla // @match *://*.neopets.com/dome/fight* // @match *://*.neopets.com/dome/arena* // @match *://*.neopets.com/dome/barracks* // @icon https://github.com/karlaneo/neopets-scripts/blob/main/favicon-32x32.png?raw=true // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // ==/UserScript== const MIN_WAIT = 700; const MAX_WAIT = 1200; GM_addStyle("#QuestLogStreakRewards { display: block !important; }") let battleType = GM_getValue('battle_type') || 'fixed'; let fixedCount = GM_getValue('fixed_count') || 1; let battlesLeft = GM_getValue('battles_left') || 0; let rewardsNp = GM_getValue('rewards_np') || false; let rewardsItems = GM_getValue('rewards_items') || false; let rewardsPlot = GM_getValue('rewards_plot') || false; let infiniteCount = GM_getValue('infinite_count') || 1; let infiniteWait = GM_getValue('infinite_wait') || 1; let battlesDone = GM_getValue('battles_done') || 0; const random_in_range = (start, end) => { return Math.floor(Math.random() * (end - start + 1) + start); }; const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time)); function extractVarObject(html, varName) { const assignIndex = html.indexOf(`var ${varName} =`); if (assignIndex === -1) return null; // Find the first '{' after the variable name const start = html.indexOf('{', assignIndex); if (start === -1) return null; let braceCount = 0; let inString = false; let stringChar = ''; let escaped = false; let end = -1; for (let i = start; i < html.length; i++) { const char = html[i]; if (inString) { if (!escaped && char === stringChar) { inString = false; } escaped = char === '\\' && !escaped; } else { if (char === '"' || char === "'") { inString = true; stringChar = char; escaped = false; } else if (char === '{') { braceCount++; } else if (char === '}') { braceCount--; if (braceCount === 0) { end = i; break; } } } } if (end === -1) return null; const objectString = html.slice(start, end + 1); return eval(`(${objectString})`); // safe only if source is trusted } function addRound(el, weapons, abilities, n, weaponSetting = {}) { const div = document.createElement('div'); div.style.display = 'flex'; div.className = 'round_row'; const round = document.createElement('div'); round.style.marginRight = '12px'; round.style.width = '65px'; round.style.textAlign = 'left'; round.innerHTML = n === 0 ? 'Cycle' : `Step`; const weapon1 = document.createElement('select'); weapon1.className = 'weapon1'; weapon1.style.width = '25%'; weapon1.innerHTML = "<option value=\"\">Select Weapon 1</option>"; weapons.forEach(function(weapon) { const option = document.createElement('option'); option.value = weapon; option.innerHTML = weapon; weapon1.appendChild(option); }); weapon1.value = weaponSetting.weapon1; const weapon2 = document.createElement('select'); weapon2.className = 'weapon2'; weapon2.style.width = '25%'; weapon2.innerHTML = "<option value=\"\">Select Weapon 2</option>"; weapons.forEach(function(weapon) { const option = document.createElement('option'); option.value = weapon; option.innerHTML = weapon; weapon2.appendChild(option); }); weapon2.value = weaponSetting.weapon2; div.appendChild(round); div.appendChild(weapon1); div.appendChild(weapon2); if (abilities.length > 0) { const ability1 = document.createElement('select'); ability1.className = 'ability1'; ability1.style.width = '25%'; ability1.innerHTML = "<option value=\"\">Select Ability</option>"; abilities.forEach(function(ability) { const option = document.createElement('option'); option.value = ability; option.innerHTML = ability; ability1.appendChild(option); }); ability1.value = weaponSetting.ability1; div.appendChild(ability1); } const removeButton = document.createElement('button'); removeButton.innerHTML = '-'; removeButton.className = 'remove_button'; if (n > 0) { div.appendChild(removeButton); } el.appendChild(div); return div; } function parseWeaponSetting(roundsPanel) { try { const rows = roundsPanel.querySelectorAll('.round_row'); return Array.from(rows).map(row => ({ weapon1: row.querySelector('.weapon1').value, weapon2: row.querySelector('.weapon2').value, ability1: row.querySelector('.ability1')?.value || '', })); } catch (e) { console.log(e); } } async function insertButtons (target, stamp) { const settingButton = document.createElement('button'); settingButton.style.display = 'flex'; settingButton.style.alignItems = 'center'; settingButton.style.background = '#fcc604'; settingButton.style.color = '#fff'; settingButton.style.fontWeight = 'bold'; settingButton.style.padding = '8px'; settingButton.style.border = '1px solid black'; settingButton.style.cursor = 'pointer'; settingButton.innerHTML = '<section style="background-image: url(https://images.neopets.com/themes/h5/basic/images/v3/settings-icon.svg); width: 20px; height: 20px; background-size: contain; margin-right: 6px;"></section>Settings'; const panel = document.querySelector('div'); panel.className = 'togglePopup__2020 movePopup__2020'; panel.id = 'bd_setting_popup'; panel.style.display = 'none'; panel.style.transform = 'translate(-50%, -50%)'; panel.style.margin = '0 !important'; panel.innerHTML = `<div class="popup-header__2020"> <button tabindex="0" class="popup-exit button-default__2020 button-red__2020"> <div class="popup-exit-icon"></div> </button> <h3>Battledome Bot Settings</h3> <div class="popup-header-pattern__2020"></div> </div> <div class="popup-body__2020" style="max-height: 679.9px; padding-left: 20px; padding-right: 20px;"> <div> <div style="display: flex; align-items: center;"> <label style="margin-right: 5px" for="fixed" class="settings-label">Fixed</label> <input class="settings-radio" id="fixed" name="battle_type" title="Fixed" type="radio" value="fixed" style="margin: 0"> </div> <div id="fixed_panel" style="text-align: left; padding-left: 16px; display: none;"> <label style="margin-right: 5px" for="fixed_count" class="settings-label">Number of rounds:</label> <input id="fixed_count" type="number" min="1"> </div> <div style="display: flex; align-items: center;"> <label style="margin-right: 5px" for="rewards" class="settings-label">For rewards</label> <input class="settings-radio" id="rewards" name="battle_type" title="Fixed number of rounds" type="radio" value="rewards" style="margin: 0"> </div> <div id="rewards_panel" style="display: none;"> <div style="text-align: left; padding-left: 16px;"> <label style="margin-right: 5px" for="rewards_np" class="settings-label">Neopoints</label> <input id="rewards_np" type="checkbox"> </div> <div style="text-align: left; padding-left: 16px;"> <label style="margin-right: 5px" for="rewards_items" class="settings-label">Items</label> <input id="rewards_items" type="checkbox"> </div> <div style="text-align: left; padding-left: 16px;"> <label style="margin-right: 5px" for="rewards_plot" class="settings-label">Plot points</label> <input id="rewards_plot" type="checkbox"> </div> </div> <div style="display: flex; align-items: center;"> <label style="margin-right: 5px" for="infinite" class="settings-label">Infinite</label> <input class="settings-radio" id="infinite" name="battle_type" title="Fixed number of rounds" type="radio" value="rewards" style="margin: 0"> </div> <div id="infinite_panel" style="display: none;"> <div id="fixed_panel" style="text-align: left; padding-left: 16px;"> <label style="margin-right: 5px" for="infinite_count" class="settings-label">After X Battles:</label> <input id="infinite_count" type="number" min="1"> </div> <div id="fixed_panel" style="text-align: left; padding-left: 16px;"> <label style="margin-right: 5px" for="infinite_count" class="settings-label">Wait for X (+/-20)s:</label> <input id="infinite_wait" type="number" min="1"> </div> </div> <div style="margin-top: 16px;"> <div style="text-align: left;">Battle Settings - <span id="pet_name_slot"></span></div> <div id="loading_state">Loading...</div> <div id="rounds_panel"> </div> <div id="rounds_panel_cycle"> </div> </div> </div> </div> <div class="popup-footer__2020 popup-grid3__2020"> <div></div> <div style="text-align:center; font-weight: bold;">Settings is auto saved</div> <div class="popup-footer-pattern__2020"></div> </div>` const fixedToggle = panel.querySelector('#fixed'); const rewardsToggle = panel.querySelector('#rewards'); const infiniteToggle = panel.querySelector('#infinite'); const fixedPanel = panel.querySelector('#fixed_panel'); const rewardsPanel = panel.querySelector('#rewards_panel'); const infinitePanel = panel.querySelector('#infinite_panel'); const fixedCountInput = panel.querySelector('#fixed_count'); const rewardsNpInput = panel.querySelector('#rewards_np'); const rewardsItemsInput = panel.querySelector('#rewards_items'); const rewardsPlotInput = panel.querySelector('#rewards_plot'); const infiniteCountInput = panel.querySelector('#infinite_count'); const infiniteWaitInput = panel.querySelector('#infinite_wait'); const roundsPanel = panel.querySelector('#rounds_panel'); const roundsPanelCycle = panel.querySelector('#rounds_panel_cycle'); switch(battleType) { case 'fixed': fixedToggle.checked = true; fixedPanel.style.display = 'block'; break; case 'rewards': rewardsToggle.checked = true; rewardsPanel.style.display = 'block'; break; case 'infinite': infiniteToggle.checked = true; infinitePanel.style.display = 'block'; break; default: } fixedCountInput.value = fixedCount; rewardsNpInput.checked = rewardsNp; rewardsItemsInput.checked = rewardsItems; rewardsPlotInput.checked = rewardsPlot; infiniteCountInput.value = infiniteCount; infiniteWaitInput.value = infiniteWait; fixedToggle.addEventListener('change', function(event) { if (event.target.checked) { fixedPanel.style.display = 'block'; rewardsPanel.style.display = 'none'; infinitePanel.style.display = 'none'; GM_setValue('battle_type', 'fixed'); } }); rewardsToggle.addEventListener('change', function(event) { if (event.target.checked) { fixedPanel.style.display = 'none'; rewardsPanel.style.display = 'block'; infinitePanel.style.display = 'none'; GM_setValue('battle_type', 'rewards'); } }); infiniteToggle.addEventListener('change', function(event) { if (event.target.checked) { fixedPanel.style.display = 'none'; rewardsPanel.style.display = 'none'; infinitePanel.style.display = 'block'; GM_setValue('battle_type', 'infinite'); } }); fixedCountInput.addEventListener('change', function(event) { GM_setValue('fixed_count', Number(event.target.value)); fixedCount = Number(event.target.value); }); rewardsNpInput.addEventListener('change', function(event) { GM_setValue('rewards_np', event.target.checked); }); rewardsItemsInput.addEventListener('change', function(event) { GM_setValue('rewards_items', event.target.checked); }); rewardsPlotInput.addEventListener('change', function(event) { GM_setValue('rewards_plot', event.target.checked); }); infiniteCountInput.addEventListener('change', function(event) { GM_setValue('infinite_count', Number(event.target.value)); }); infiniteWaitInput.addEventListener('change', function(event) { GM_setValue('infinite_wait', Number(event.target.value)); }); settingButton.innerHTML = 'Loading'; settingButton.disabled = true; if (document.querySelector('.npcContainer')) { document.querySelector('.npcContainer').style.position = 'relative'; settingButton.style.bottom = '14px'; settingButton.style.left = '125px'; settingButton.style.position = 'absolute'; document.querySelector('.npcContainer').appendChild(settingButton); } else if (document.querySelector('#rbfightStep2')) { settingButton.style.margin = 'auto'; document.querySelector('#rbfightStep2').appendChild(settingButton); } const htmlWeapon = await fetch('https://www.neopets.com/dome/neopets.phtml').then(function(res) { return res.text(); }); const htmlAbility = await fetch('https://www.neopets.com/dome/abilities.phtml').then(function(res) { return res.text(); }); settingButton.addEventListener('click', function() { panel.style.display = 'block'; const activePet = typeof BDFight !== 'undefined' ? BDFight.selectedPet : Array.from(document.querySelectorAll('.rb-fight_petNameLabel')).find(n => n.style.display === 'grid')?.dataset?.name; document.querySelector('#pet_name_slot').innerHTML = activePet; let weaponSetting = JSON.parse(GM_getValue(`${activePet}_weapon`) || '[]'); const divWeapon = new DOMParser().parseFromString(htmlWeapon, "text/html").querySelector("#bdStatus"); const counts = {}; const weapons = Array.from(divWeapon.querySelectorAll(`[data-name="${activePet}"] .equipTable .equipFrame`)).map(el => el.textContent.trim()).map(item => { counts[item] = (counts[item] || 0) + 1; return counts[item] > 1 ? `${item} ${counts[item]}` : item; }).filter(n => n !== '' && !n.startsWith(' ')); const abilityData = extractVarObject(htmlAbility, 'BDAbilities'); const abilities = Object.keys(abilityData.pets[activePet].abilities).map(function(n) { return abilityData.abilities[n].name; }); document.querySelector('#loading_state').style.display = 'none'; function getWeaponSetting() { weaponSetting = parseWeaponSetting(roundsPanel); GM_setValue(`${activePet}_weapon`, JSON.stringify(weaponSetting)); } function addRow(ws) { const div = addRound(roundsPanel, weapons, abilities, weaponSetting.length, ws); div.querySelector('.remove_button').addEventListener('click', function () { event.target.parentNode.remove(); getWeaponSetting(); }); Array.from(div.querySelectorAll('select')).forEach(select => { select.addEventListener('change', getWeaponSetting); }); } weaponSetting.forEach((ws, i) => { addRow(ws); }); const weaponCycleSetting = JSON.parse(GM_getValue(`${activePet}_weapon_cycle`) || '{"weapon1":"","weapon2":"","ability1":""}'); const divCycle = addRound(roundsPanelCycle, weapons, abilities, 0, weaponCycleSetting); Array.from(divCycle.querySelectorAll('select')).forEach(select => { select.addEventListener('change', function() { weaponCycleSetting[select.className] = select.value; GM_setValue(`${activePet}_weapon_cycle`, JSON.stringify(weaponCycleSetting)); }); }); const addRoundButton = document.createElement('button'); addRoundButton.innerHTML = '+ Add Round'; addRoundButton.addEventListener('click', function() { weaponSetting.push({ weapon1: '', weapon2: '', ability1: '', }); GM_setValue(`${activePet}_weapon`, JSON.stringify(weaponSetting)); addRow(); if (weaponSetting.length >= 10) { addRoundButton.disabled = true; } }); roundsPanelCycle.appendChild(addRoundButton); }); panel.querySelector('.popup-exit').addEventListener('click', function() { panel.style.display = 'none'; roundsPanel.innerHTML = ''; roundsPanelCycle.innerHTML = ''; }); settingButton.innerHTML = 'Battle Bot Settings'; settingButton.disabled = false; document.querySelector('body').appendChild(panel); document.querySelector('#bdFightStep3FightButton, #BattleContinueButton').addEventListener('click', function() { GM_setValue('battles_left', fixedCount); GM_setValue('battles_done', 0); }); } function getCurrentEquippedWeapon(id) { const weaponImages = Array.from(document.querySelectorAll('#p1usedequipment .item, #p1equipment .item')).reduce((acc, el) => ({ ...acc, [el.src]: el.title || el.alt }), {}); const selectedWeaponImage = document.querySelector(`#p1e${id}m.p1.selected.menu div`); if (!selectedWeaponImage) { return ''; } const selectedWeapon = weaponImages[selectedWeaponImage.style.backgroundImage.replace('url("', '').replace('")', '')] return selectedWeapon; } function getCurrentEquippedAbility() { const abilityImages = Array.from(document.querySelectorAll('#p1ability td')).reduce((acc, el) => ({ ...acc, [el.querySelector('img')?.src]: el.title || el.alt }), {}); const selectedAbilityImage = document.querySelector('#p1am div').style.backgroundImage; if (!selectedAbilityImage) { return ''; } const selectedAbility = abilityImages[selectedAbilityImage.replace('url("', '').replace('")', '')] return selectedAbility; } (async function() { 'use strict'; // Your code here... try { if (document.querySelector('.npcContainer, #rbfightStep2')) { await insertButtons(); } else { const div = document.createElement('div'); div.id = 'battle_status'; document.querySelector('#arenacontainer').appendChild(div); div.style.position = 'absolute'; div.style.bottom = '100%'; if (battleType === 'fixed') { div.innerHTML = `${battlesLeft} / ${fixedCount} battles`; } else if (battleType === 'infinite') { div.innerHTML = `${battlesDone} battles done`; } let pet = ''; let weaponSetting; let weaponCycleSetting; let round = 0; async function battle(n) { try { while (document.querySelector('#p1e1m').style.cursor !== 'auto' && document.querySelector('#p1e1m').style.cursor !== 'pointer') { await sleep(MAX_WAIT); } if (weaponSetting && weaponCycleSetting) { const { weapon1, weapon2, ability1 } = (n < weaponSetting.length) ? weaponSetting[n] : weaponCycleSetting; const weaponsToEquip = [weapon1, weapon2].map(n => n.replace(/\s\d+$/, "")) ; let usedId = ''; for (let i = 1; i <= 2; i += 1) { const equippedItemInSlot = getCurrentEquippedWeapon(i); if (weaponsToEquip.indexOf(equippedItemInSlot) > -1) { weaponsToEquip.splice(weaponsToEquip.indexOf(equippedItemInSlot), 1); continue; } const weaponToEquip = weaponsToEquip.shift(); if (!weaponToEquip) { break; } if (document.querySelector(`p1e${i}m.selected`)) { document.querySelector(`#p1e${i}m`).click(); await sleep(random_in_range(MIN_WAIT, MAX_WAIT)); } document.querySelector(`#p1e${i}m`).click(); await sleep(random_in_range(MIN_WAIT, MAX_WAIT)); const lis = document.querySelectorAll(`#p1equipment li`); for (let j = 0; j < lis.length; j += 1) { const li = lis[j]; if (li.style.display !== 'none' && li.querySelector(`[title="${weaponToEquip}"], [alt="${weaponToEquip}"]`)) { if (li.querySelector(`[title="${weaponToEquip}"], [alt="${weaponToEquip}"]`).id === usedId) { continue; } li.querySelector(`[title="${weaponToEquip}"], [alt="${weaponToEquip}"]`).click(); usedId = li.querySelector(`[title="${weaponToEquip}"], [alt="${weaponToEquip}"]`).id break; } } await sleep(random_in_range(MIN_WAIT, MAX_WAIT)); } await sleep(random_in_range(MIN_WAIT, MAX_WAIT)); if (ability1) { const currentSelectedAbility = getCurrentEquippedAbility(); if (currentSelectedAbility && currentSelectedAbility !== ability1) { document.querySelector('#p1am').click(); await sleep(random_in_range(MIN_WAIT, MAX_WAIT)); } if (!document.querySelector(`#p1ability [title="${ability1}"] .cooldown.act`)) { document.querySelector('#p1am').click(); await sleep(random_in_range(MIN_WAIT, MAX_WAIT)); document.querySelector(`#p1ability [title="${ability1}"] .ability`)?.click(); } } while (document.querySelector('#fight .inactive')) { await sleep(random_in_range(MIN_WAIT, MAX_WAIT)); } await sleep(random_in_range(MIN_WAIT, MAX_WAIT)); document.querySelector('#fight').click(); while (!document.querySelector('#skipreplay:not(.replay')) { await sleep(random_in_range(MIN_WAIT, MAX_WAIT)); } while (!document.querySelector('.replay')) { await sleep(random_in_range(MIN_WAIT, MAX_WAIT)); document.querySelector('#skipreplay:not(.replay').click(); } await sleep(random_in_range(MIN_WAIT, MAX_WAIT)); while (!document.querySelector('#fight') && !document.querySelector('#start') && !document.querySelector('.end_ack.collect')) { console.log(1); await sleep(random_in_range(MIN_WAIT, MAX_WAIT)); } // #playground .end_game if (document.querySelector('#p2hp').textContent === '0') { await sleep(random_in_range(MIN_WAIT, MAX_WAIT)); const itemLimit = document.querySelector('#bd_rewards').textContent.includes('You have reached the item limit for today'); const npLimit = document.querySelector('#bd_rewards').textContent.includes('You have reached the NP limit for today'); const plotLimit = !document.querySelector('#bd_rewards').textContent.includes('Plot') || document.querySelector('#bd_rewards').textContent.includes('You have reached the Plot Points limit'); switch (battleType) { case 'fixed': if (battlesLeft > 1) { document.querySelector('#bdplayagain').click(); GM_setValue('battles_left', battlesLeft - 1); } break; case 'rewards': document.querySelector('.end_ack.collect').click(); if ((rewardsNp && !npLimit) || (rewardsItems && !itemLimit) || (rewardsPlot && !plotLimit)) { document.querySelector('#bdplayagain').click(); } break; case 'infinite': if (battlesDone % infiniteCount === 0 && battlesDone > 0) { infiniteWait += random_in_range(0, 20); await new Promise(function(resolve) { const interval = setInterval(function() { infiniteWait -= 1; document.querySelector('#battle_status').innerHTML = `Waiting... ${infiniteWait}s left`; if (infiniteWait <= 0) { clearInterval(interval); resolve(); } }, 1000); }); } GM_setValue('battles_done', battlesDone + 1); document.querySelector('#bdplayagain').click(); break; default: } } else { battle(n + 1); } } } catch (e) { console.log(e); } } async function loop() { if (document.querySelector('#start')) { await sleep(random_in_range(MIN_WAIT, MAX_WAIT)); document.querySelector('#start').click(); } if (document.querySelector('#p1name')) { pet = document.querySelector('#p1name').textContent; if (!weaponSetting) { weaponSetting = JSON.parse(GM_getValue(`${pet}_weapon`) || '[]'); } if (!weaponCycleSetting) { weaponCycleSetting = JSON.parse(GM_getValue(`${pet}_weapon_cycle`) || '{"weapon1":"","weapon2":"","ability1":""}'); } battle(0); return; } setTimeout(loop, MIN_WAIT); } loop(); } } catch (e) { console.log(e); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址