// ==UserScript== // @name Better BiteFight // @namespace https://lobby.bitefight.gameforge.com/ // @version 1.0.0 // @description Adds an healthbar, energybar, links and other QOL to BiteFight // @author Spychopat // @match https://*.bitefight.gameforge.com/* // @exclude https://lobby.bitefight.gameforge.com/* // @exclude https://forum.bitefight.gameforge.com/* // @icon https://lobby.bitefight.gameforge.com/favicon.ico // @run-at document-start // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_addStyle // @downloadURL none // ==/UserScript== (function () { 'use strict'; // hide the page at the start, to avoid seeing the page jumping (it's then showed again after the script is loaded) const style = document.createElement('style'); style.textContent = `body {visibility: hidden;}`; // hardcore if(document.head)document.head.appendChild(style); // Script storage keys const KEY_SERVER_DOMAIN = window.location.hostname; const pageLoadTime = Date.now(); // Define character object const CHARACTER = GM_getValue(KEY_SERVER_DOMAIN, { health: 0, maxHealth: 0, regenHealth: 0, energy: 0, maxEnergy: 0, regenEnergy: 4, potionCooldownEnd: 0, energyPotionCooldownEnd: 0, churchCooldownEnd: 0, jobCooldownEnd: 0, autoRedirectGrotte: true, autoGrotto: [false, false, false], autoGrottoInstant: false, lastGrottoClick: -1, highlightChurch: false, highlightPotion: true, highlightEnergyPotion: true, highlightJob: 2, healthRefreshRate: 200, showTotalStat: false, hideBuddies: true, hideCharisma: true }); const GROTTO_STATS = GM_getValue(KEY_SERVER_DOMAIN+"/grotto_stats", { goldEarned: { 0: [], 1: [], 2: [] }, dmgTaken: { 0: [], 1: [], 2: [] }, xpEarned: { 0: [], 1: [], 2: [] } }); // used to store the health refresh interval, so we can dynamically change it in the settings let healthRefreshInterval; let maxHealthString; let maxEnergyString; //console.log(parseInt(formatNumber(document.getElementsByClassName("gold")[1].firstChild.textContent.split("\n")[1]))); var mainScriptRunned = false; window.addEventListener('load', function() { main(); },false); // sometime, the previous event isn't triggered for some reason (pretty rare), but when it happens, it's bad. so, i run the script after 2 seconds anyway, as a failsafe setTimeout(() => { main(); }, 2000); function main(){ if(mainScriptRunned)return; mainScriptRunned = true; redirectAfterGrotteFight(); // run it first, because it has chances to redirect, so we don't work uselessly // early, to avoid the page jump as much as possible insertCSS(); addAdditionnalLink(); extractCharacterStats(); insertHealthEnergyBars(); // Insert progress bars after updating the character startHealthRegeneration(); // Start health regeneration on page load startEnergyRegeneration(); if (window.location.pathname.contains('/profile')){ if (window.location.hash=='#potion')autoUseBestPotion(); if (window.location.hash=='#energy-potion')autoUseBestEnergyPotion(); moveGameEventDiv(); // move down the game event div updateRegenHealthEnergy(); updatePotionTimer(); updateEnergyPotionTimer(); hideCharisma(); } else if (window.location.pathname.contains('/city/church')){ updateChurchCooldownTimer(); } else if (window.location.pathname.contains('/user/working')){ updateJobCooldownTimer(); } else if (window.location.pathname.contains('/user/settings')){ settingsMenu(); } else if (window.location.pathname.contains('/city/graveyard')){ CHARACTER.jobCooldownEnd = 0; //the job can't be in progress if we're on this page, meaning that user may have canceled it updateJobCooldownDisplay(); } else if (window.location.pathname.contains('/city/grotte')){ addGrottoAutoRedirectButton(); addAutoGrottoButton(); autoFightGrotto(); } else if (window.location.pathname.contains('/city/shop')){ defaultNonPremiumShop(); } updateCharacter(); //console.log(CHARACTER); if(CHARACTER.hideBuddies){ hideBuddies(); } // (si pas sur un rapport de grotte OU si aucun des auto fight n'est actif) ET si pas sur #potion if ((!(window.location.href.includes('report/fightreport/') && window.location.href.includes('/grotte')) || (!CHARACTER.autoRedirectGrotte && !CHARACTER.autoGrotto[0] && !CHARACTER.autoGrotto[1] && !CHARACTER.autoGrotto[2])) && !(window.location.hash=='#energy-potion') && !(window.location.hash=='#potion')){ style.textContent = `body {visibility: visible;}`; // we loaded everything, so now we're showing the page again, we avoided the page jumping } } function insertCSS() { GM_addStyle(` #upgrademsg { display: none; } #premium > img { display: none; } #mmonetbar { display: none !important; visibility: hidden; } .premiumButton { color: #FFCC33 !important; font-weight: bold !important; background-position: 0 -184px !important; text-shadow: 0 0 5px #000 !important; } input:disabled{ background-color: #50323200 !important; } `); } function hideCharisma(){ if(CHARACTER.hideCharisma){ const element = document.querySelector('a[href*="/profile/training/5"]'); if(!element)return; element.style.visibility = "hidden"; } } function extractCharacterStats(){ // Get Stats //var allStatsElement = document.getElementsByClassName("gold")[0]; var allStatsElement = document.querySelector("#infobar > div.wrap-left.clearfix > div > div.gold") var statsValues = allStatsElement.textContent.split("\n"); statsValues = statsValues.map(value => value.trim()); statsValues.shift(); // Extract energy, fragments, gold, health, and hellStones var energy = statsValues[3].trim(); var currentEnergy = energy.split("/")[0]; var maxEnergy = energy.split("/")[1]; if (currentEnergy && maxEnergy) { CHARACTER.energy = parseInt(currentEnergy); // Use parseFloat to preserve decimals CHARACTER.maxEnergy = parseInt(maxEnergy); // Use parseFloat to preserve decimals } var health = statsValues[4].trim(); var currentHealth = formatNumber(health.split("/")[0]); var maxHealth = formatNumber(health.split("/")[1]); if (currentHealth && maxHealth) { CHARACTER.health = parseInt(currentHealth); CHARACTER.maxHealth = parseInt(maxHealth); } // used in case the user wants to display the total for health and energy, i do it now to avoid doing it every 200 ms maxHealthString = " / "+(CHARACTER.maxHealth > 999 ? CHARACTER.maxHealth.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.'): CHARACTER.maxHealth); maxEnergyString = " / "+(CHARACTER.maxEnergy > 999 ? CHARACTER.maxEnergy.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.'): CHARACTER.maxEnergy); // Now remove the parts containing health and energy // Update the text content by filtering out the specific lines var elements = allStatsElement.innerHTML.split("\n"); elements.splice(4, 2); // Removes the energy (index 4) and health (index 5) values // Create two new div elements var div1 = document.createElement('div'); var div2 = document.createElement('div'); var div3 = document.createElement('div'); // Fill div1 with elements 1, 2, 3 div1.innerHTML = elements.slice(1, 4).join(""); // Fill div2 with elements 4, 5 div2.innerHTML = elements.slice(4).join(""); div1.style.minWidth = "193px"; div2.style.minWidth = "193px"; div3.appendChild(div1); div3.appendChild(div2); div3.style.paddingRight = '104px'; div3.style.display = 'flex'; div3.style.justifyContent = 'space-between'; // Clear the existing content and append the two divs allStatsElement.innerHTML = ''; allStatsElement.appendChild(div3); allStatsElement.style.display = 'block'; } // Format texts to return as numbers (no thousand separators) function formatNumber(value) { while (value.indexOf(".") > 0) value = value.replace(".", ""); return value; } function updateRegenHealthEnergy() { //if (!window.location.pathname.endsWith('/profile/index')) return; const healthRegenElement = document.querySelector("#skillmodis_tab > div.wrap-left.clearfix > div > div > table > tbody div.triggerTooltip"); if(healthRegenElement){ CHARACTER.regenHealth = parseInt(healthRegenElement.textContent.match(/\d+/g)); } const energyRegenElement = document.getElementById('actionpointRegeneration'); if(energyRegenElement){ CHARACTER.regenEnergy = parseInt(energyRegenElement.parentElement.lastChild.textContent.match(/\d+/g)); } } // Update character in local storage function updateCharacter() { GM_setValue(KEY_SERVER_DOMAIN, CHARACTER); } function updateGrottoStats(){ GM_setValue(KEY_SERVER_DOMAIN+"/grotto_stats", GROTTO_STATS); } function updateEnergyPotionTimer() { const timerElement = document.querySelector("#item_temp_active_2_17 > span"); const buttonElement = document.querySelector('a[href*="/profile/useItem/2/17?"]'); if(!timerElement){ // couldn't find the potion timer, it means player is out of potions, or the potion is already ready if(buttonElement){ CHARACTER.energyPotionCooldownEnd = 1; // the potion is ready to use ! } else { CHARACTER.energyPotionCooldownEnd = -1; // i put -1 so i can display later that that no more potions } updateEnergyPotionCooldownDisplay(); } else { // Get the current time and add the potion cooldown to get the end time const currentTime = pageLoadTime / 1000; // Current time in seconds const cooldownTime = timeToSeconds(timerElement.textContent); // Convert cooldown time to seconds const endTime = currentTime + cooldownTime; // Calculate the end time // Save the end time to the character object CHARACTER.energyPotionCooldownEnd = endTime; updateEnergyPotionCooldownDisplay(); //refresh } } function updatePotionTimer() { var timerElement = document.querySelector("#item_cooldown2_20 > span"); if(!timerElement){ timerElement = document.querySelector("#item_cooldown2_1 > span"); } if(!timerElement){ timerElement = document.querySelector("#item_cooldown2_2 > span"); } if(!timerElement){ // couldn't find the potion timer, it means player is out of potions, or the potion is already ready if(getUseHealthPotionButtons().length>0){ CHARACTER.potionCooldownEnd = 1; // the potion is ready to use ! } else { CHARACTER.potionCooldownEnd = -1; // i put -1 so i can display later that that no more potions } updatePotionCooldownDisplay(); } else { // Get the current time and add the potion cooldown to get the end time const currentTime = pageLoadTime / 1000; // Current time in seconds const cooldownTime = timeToSeconds(timerElement.textContent); // Convert cooldown time to seconds const endTime = currentTime + cooldownTime; // Calculate the end time // Save the end time to the character object CHARACTER.potionCooldownEnd = endTime; updatePotionCooldownDisplay(); //refresh } } function autoUseBestPotion(){ const hpPotions = getUseHealthPotionButtons(); if (hpPotions.length > 0) { hpPotions[hpPotions.length-1].click(); } else { // si plus de potion, ou si potion en cours de cooldown window.location.href = '/city/shop/potions/&page=1&premiumfilter=nonpremium'; } } function autoUseBestEnergyPotion(){ const energyPotionButton = document.querySelector('a[href*="/profile/useItem/2/17?"]'); if (energyPotionButton) { energyPotionButton.click(); } else { // si plus de potion, ou si potion en cours de cooldown window.location.href = '/city/shop/potions/&page=1&premiumfilter=nonpremium'; } } function getUseHealthPotionButtons(){ // returns a table containing all (if any) buttons to use the health potions return Array.from(document.querySelectorAll("#accordion > div > table > tbody > tr > td > div > div > a")).filter(button => button.href.includes("useItem/2/1?") || button.href.includes("useItem/2/2?") || button.href.includes("useItem/2/20?") ); } function timeToSeconds(timeStr) { const [hours, minutes, seconds] = timeStr.split(':').map(Number); return (hours * 3600) + (minutes * 60) + seconds; } function insertHealthEnergyBars() { if (document.getElementById('progressBarsTimersContainer')) { return; } let mainContainer = document.createElement('div'); mainContainer.id = 'progressBarsTimersContainer'; mainContainer.style.display = 'flex'; mainContainer.style.flexDirection = 'column'; // Stack the bars and timers vertically mainContainer.style.alignItems = 'center'; mainContainer.style.marginTop = '3px'; let progressBarsContainer = document.createElement('div'); progressBarsContainer.style.display = 'flex'; // Changed to row to place bars side by side progressBarsContainer.style.flexDirection = 'row'; // Set to row for horizontal alignment progressBarsContainer.style.alignItems = 'center'; // Align items vertically in the middle progressBarsContainer.style.paddingBottom = '8px'; progressBarsContainer.style.gap = '60px'; // Added gap between the bars // Health Bar let healthBarContainer = document.createElement('div'); healthBarContainer.style.width = '250px'; healthBarContainer.style.position = 'relative'; healthBarContainer.style.background = 'linear-gradient(to right, #1a1a1a, #333)'; healthBarContainer.style.borderImage = 'linear-gradient(to right, #ff4d4d, #b80000) 1'; healthBarContainer.style.borderRadius = '6px'; healthBarContainer.style.boxShadow = 'inset 0 10px 5px rgba(0, 0, 0, 0.5), 0 0 10px rgba(255, 77, 77, 1)'; healthBarContainer.style.overflow = 'hidden'; healthBarContainer.id = 'healthProgressBar'; let healthBar = document.createElement('div'); healthBar.style.height = '20px'; healthBar.style.width = `${(CHARACTER.health / CHARACTER.maxHealth) * 100}%`; healthBar.style.background = 'linear-gradient(to right, #ff4d4d, #b80000)'; healthBar.style.transition = 'width 0.3s ease-in-out'; healthBar.style.boxShadow = 'inset 0 10px 5px rgba(0, 0, 0, 0.5)'; let healthText = document.createElement('div'); healthText.textContent = `${CHARACTER.health > 999 ? CHARACTER.health.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.') : CHARACTER.health}`; if(CHARACTER.showTotalStat)healthText.textContent += maxHealthString; healthText.style.position = 'absolute'; healthText.style.top = '50%'; healthText.style.left = '50%'; healthText.style.transform = 'translate(-50%, -50%)'; healthText.style.color = 'white'; healthText.style.fontSize = '12px'; healthText.style.fontFamily = 'monospace'; healthBarContainer.appendChild(healthBar); healthBarContainer.appendChild(healthText); // Energy Bar let energyBarContainer = document.createElement('div'); energyBarContainer.style.width = '250px'; energyBarContainer.style.position = 'relative'; energyBarContainer.style.background = 'linear-gradient(to right, #1a1a1a, #333)'; energyBarContainer.style.borderImage = 'linear-gradient(to right, #4d94ff, #0000a4) 1'; energyBarContainer.style.borderRadius = '6px'; energyBarContainer.style.boxShadow = 'inset 0 10px 5px rgba(0, 0, 0, 0.5), 0 0 10px rgba(77, 148, 255, 1)'; energyBarContainer.style.overflow = 'hidden'; energyBarContainer.id = 'energyProgressBar'; let energyBar = document.createElement('div'); energyBar.style.height = '20px'; energyBar.style.width = `${(CHARACTER.energy / CHARACTER.maxEnergy) * 100}%`; energyBar.style.background = 'linear-gradient(to right, #4d94ff, #0000a4)'; energyBar.style.transition = 'width 0.3s ease-in-out'; energyBar.style.boxShadow = 'inset 0 10px 5px rgba(0, 0, 0, 0.5)'; let energyText = document.createElement('div'); energyText.textContent = `${CHARACTER.energy}`; if(CHARACTER.showTotalStat)energyText.textContent += maxEnergyString; energyText.style.position = 'absolute'; energyText.style.top = '50%'; energyText.style.left = '50%'; energyText.style.transform = 'translate(-50%, -50%)'; energyText.style.color = 'white'; energyText.style.fontSize = '12px'; energyText.style.fontFamily = 'monospace'; energyBarContainer.appendChild(energyBar); energyBarContainer.appendChild(energyText); progressBarsContainer.appendChild(healthBarContainer); progressBarsContainer.appendChild(energyBarContainer); mainContainer.appendChild(progressBarsContainer); document.querySelector("#infobar > div.wrap-left.clearfix > div > div.gold").appendChild(mainContainer); } function calculateCurrentEnergy(){ const regenPerSecond = CHARACTER.regenEnergy / 3600; // Convert regenHealth from per hour to per second // Calculate the total health regenerated since the page loaded const elapsedSeconds = (Date.now() - pageLoadTime) / 1000; // Time elapsed in seconds const regeneratedEnergy = regenPerSecond * elapsedSeconds; // Calculate the updated health, without modifying the original CHARACTER.health const updatedEnergy = Math.min( CHARACTER.energy + regeneratedEnergy, CHARACTER.maxEnergy ); return updatedEnergy; } function calculateCurrentHealth(){ const regenPerSecond = CHARACTER.regenHealth / 3600; // Convert regenHealth from per hour to per second // Calculate the total health regenerated since the page loaded const elapsedSeconds = (Date.now() - pageLoadTime) / 1000; // Time elapsed in seconds const regeneratedHealth = regenPerSecond * elapsedSeconds; // Calculate the updated health, without modifying the original CHARACTER.health const updatedHealth = Math.min( CHARACTER.health + regeneratedHealth, CHARACTER.maxHealth ); return updatedHealth; } // Start real-time health regeneration function startHealthRegeneration() { // Update every 200ms by default healthRefreshInterval = setInterval(() => { // Update the progress bar with the calculated health updateHealthBars(calculateCurrentHealth()); }, CHARACTER.healthRefreshRate); } function startEnergyRegeneration() { const regenInterval = 10000; // Update every 10s setInterval(() => { // Update the progress bar with the calculated health updateEnergyBars(calculateCurrentEnergy()); }, regenInterval); } // Update the existing progress bars function updateHealthBars(calculatedHealth) { // Update Health Progress Bar const healthBar = document.getElementById('healthProgressBar').children[0]; healthBar.style.width = `${(calculatedHealth / CHARACTER.maxHealth) * 100}%`; const healthText = document.getElementById('healthProgressBar').children[1]; // Format the health value with thousands separators let healthWithoutDecimals = Math.floor(calculatedHealth); healthText.textContent = `${healthWithoutDecimals > 999 ? healthWithoutDecimals.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.'): healthWithoutDecimals}`; if(CHARACTER.showTotalStat)healthText.textContent += maxHealthString; } function updateEnergyBars(calculatedEnergy) { // Update Health Progress Bar const energyBar = document.getElementById('energyProgressBar').children[0]; energyBar.style.width = `${(calculatedEnergy / CHARACTER.maxEnergy) * 100}%`; const energyText = document.getElementById('energyProgressBar').children[1]; // Format the health value with thousands separators let energyWithoutDecimals = Math.floor(calculatedEnergy); energyText.textContent = `${energyWithoutDecimals > 999 ? energyWithoutDecimals.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.'): energyWithoutDecimals}`; if(CHARACTER.showTotalStat)energyText.textContent += maxEnergyString; } // Function to update the timer display function updatePotionCooldownDisplay() { const timerButton = document.getElementById('potionCooldownTimer'); const currentTime = new Date().getTime() / 1000; // Current time in seconds if (CHARACTER.potionCooldownEnd > currentTime) { const remainingTime = CHARACTER.potionCooldownEnd - currentTime; // Remaining time in seconds const hours = Math.floor(remainingTime / 3600); const minutes = Math.floor((remainingTime % 3600) / 60); const seconds = Math.round(remainingTime % 60); //timerElement.textContent = `Potion : ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; timerButton.textContent = `Health : ${hours > 0 ? hours.toString().padStart(2, '0') + ':' : ''}${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; timerButton.className = ""; } else if (CHARACTER.potionCooldownEnd < 0) { timerButton.textContent = 'Out of potions'; if(CHARACTER.highlightPotion){ timerButton.className = "premiumButton"; } else { timerButton.className = ""; } } else { timerButton.textContent = 'Health Potion'; if(CHARACTER.highlightPotion)timerButton.className = "premiumButton"; } } function updateEnergyPotionCooldownDisplay() { const timerButton = document.getElementById('energyPotionCooldownTimer'); const currentTime = new Date().getTime() / 1000; // Current time in seconds if (CHARACTER.energyPotionCooldownEnd > currentTime) { const remainingTime = CHARACTER.energyPotionCooldownEnd - currentTime; // Remaining time in seconds const hours = Math.floor(remainingTime / 3600); const minutes = Math.floor((remainingTime % 3600) / 60); const seconds = Math.round(remainingTime % 60); //timerElement.textContent = `Potion : ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; timerButton.textContent = `Energy : ${hours > 0 ? hours.toString().padStart(2, '0') + ':' : ''}${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; timerButton.className = ""; } else if (CHARACTER.energyPotionCooldownEnd < 0) { timerButton.textContent = 'Out of potions'; if(CHARACTER.highlightEnergyPotion){ timerButton.className = "premiumButton"; } else { timerButton.className = ""; } } else { timerButton.textContent = 'Energy Potion'; if(CHARACTER.highlightEnergyPotion)timerButton.className = "premiumButton"; } } function updateChurchCooldownTimer() { const churchCountdownElement = document.querySelector("#church_healing_countdown > span"); if (churchCountdownElement) { const cooldownTime = churchCountdownElement.textContent.trim(); const currentTime = new Date().getTime() / 1000; // Current time in seconds const cooldownSeconds = timeToSeconds(cooldownTime); // Convert cooldown time to seconds const endTime = currentTime + cooldownSeconds; // Calculate the end time // Save the end time to the character object CHARACTER.churchCooldownEnd = endTime; updateCharacter(); // Save updated character data updateChurchCooldownDisplay(); //refresh } } function updateJobCooldownTimer() { const jobCountdownElement = document.querySelector("#graveyardCount > span"); if (jobCountdownElement) { const cooldownTime = jobCountdownElement.textContent.trim(); const currentTime = new Date().getTime() / 1000; // Current time in seconds const cooldownSeconds = timeToSeconds(cooldownTime); // Convert cooldown time to seconds const endTime = currentTime + cooldownSeconds; // Calculate the end time // Save the end time to the character object CHARACTER.jobCooldownEnd = endTime; updateCharacter(); // Save updated character data updateJobCooldownDisplay(); //refresh } } function updateJobCooldownDisplay() { const timerElement = document.getElementById('jobCooldownTimer'); const currentTime = new Date().getTime() / 1000; // Current time in seconds if (CHARACTER.jobCooldownEnd > currentTime) { const remainingTime = CHARACTER.jobCooldownEnd - currentTime; // Remaining time in seconds const hours = Math.floor(remainingTime / 3600); const minutes = Math.floor((remainingTime % 3600) / 60); const seconds = Math.round(remainingTime % 60); //timerElement.textContent = `Church : ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; timerElement.textContent = `Job : ${hours > 0 ? hours.toString().padStart(2, '0') + ':' : ''}${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; if (CHARACTER.highlightJob == 1){ timerElement.className = "premiumButton"; timerElement.style.lineHeight = "37px"; } else if (window.location.pathname.contains('/city/graveyard') || window.location.pathname.contains('/user/working')){ timerElement.className = "active"; timerElement.style.lineHeight = "44px"; } else { timerElement.className = ""; } } else { timerElement.textContent = 'Graveyard'; if (CHARACTER.highlightJob == 2){ timerElement.className = "premiumButton"; timerElement.style.lineHeight = "37px"; } else{ if (window.location.pathname.contains('/city/graveyard') || window.location.pathname.contains('/user/working')){ timerElement.className = "active"; } else { timerElement.className = ""; } } } } // Function to update the church cooldown display function updateChurchCooldownDisplay() { const timerElement = document.getElementById('churchCooldownTimer'); const currentTime = new Date().getTime() / 1000; // Current time in seconds if (CHARACTER.churchCooldownEnd > currentTime) { const remainingTime = CHARACTER.churchCooldownEnd - currentTime; // Remaining time in seconds const hours = Math.floor(remainingTime / 3600); const minutes = Math.floor((remainingTime % 3600) / 60); const seconds = Math.round(remainingTime % 60); //timerElement.textContent = `Church : ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; timerElement.textContent = `Church : ${hours > 0 ? hours.toString().padStart(2, '0') + ':' : ''}${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; timerElement.className = ""; } else { timerElement.textContent = 'Church'; if(CHARACTER.highlightChurch)timerElement.className = "premiumButton"; } } function hideBuddies(){ const buddiesElement = document.querySelector("#buddyTrigger"); if(CHARACTER.hideBuddies){ buddiesElement.style.visibility = "hidden"; } else { buddiesElement.style.visibility = ""; } } function addAdditionnalLink() { // make the overview link open the attributes by default if (!window.location.pathname.contains('/profile'))document.querySelectorAll('#menuHead li a')[1].href="/profile/index#tabs-2"; // make the voodoo shop less flashy document.getElementById("premium").querySelector("img").remove(); document.getElementById("premium").removeAttribute("id"); //translation of all the menu in english, so everything is the same document.querySelectorAll('#menuHead li a')[0].textContent="News"; document.querySelectorAll('#menuHead li a')[1].textContent="Overview"; document.querySelectorAll('#menuHead li a')[2].textContent="Messages"; document.querySelectorAll('#menuHead li a')[3].textContent="Hideout"; document.querySelectorAll('#menuHead li a')[4].textContent="City"; document.querySelectorAll('#menuHead li a')[5].textContent="Hunt"; document.querySelectorAll('#menuHead li a')[6].textContent="Voodoo Shop"; document.querySelectorAll('#menuHead li a')[7].textContent="Clan"; document.querySelectorAll('#menuHead li a')[8].textContent="Buddy list"; document.querySelectorAll('#menuHead li a')[9].textContent="Notepad"; if(document.querySelector('a[href*="/robbery/robberystats"]')){ // if the player is premium, there's an additionnal button document.querySelectorAll('#menuHead li a')[10].textContent="Statistics"; document.querySelectorAll('#menuHead li a')[11].textContent="Settings"; document.querySelectorAll('#menuHead li a')[12].textContent="Forum"; document.querySelectorAll('#menuHead li a')[13].textContent="Highscore"; document.querySelectorAll('#menuHead li a')[14].textContent="Search"; document.querySelectorAll('#menuHead li a')[15].textContent="Support"; document.querySelectorAll('#menuHead li a')[16].textContent="Leave game"; } else { document.querySelectorAll('#menuHead li a')[10].textContent="Settings"; document.querySelectorAll('#menuHead li a')[11].textContent="Forum"; document.querySelectorAll('#menuHead li a')[12].textContent="Highscore"; document.querySelectorAll('#menuHead li a')[13].textContent="Search"; document.querySelectorAll('#menuHead li a')[14].textContent="Support"; document.querySelectorAll('#menuHead li a')[15].textContent="Leave game"; } // Find the
  • containing the Chasse link const chasseListItem = document.querySelector('li.free-space > a[href$="/robbery/index"]'); if (chasseListItem) { // Navigate to the parent
  • element const chasseLi = chasseListItem.closest('li'); // Remove the class "free-space" chasseLi.removeAttribute('class'); if (window.location.pathname.contains('robbery')){ chasseLi.className = "active"; } // Create a new
  • for the Grotte link const grotteLi = document.createElement('li'); if (window.location.pathname.contains('/grotte')){ if (document.getElementsByClassName("active")[0])document.getElementsByClassName("active")[0].removeAttribute('class'); grotteLi.className = "active"; } grotteLi.innerHTML = 'Grotto'; const graveLi = document.createElement('li'); if (window.location.pathname.contains('/city/graveyard') || window.location.pathname.contains('/user/working')){ if (document.getElementsByClassName("active")[0])document.getElementsByClassName("active")[0].removeAttribute('class'); graveLi.className = "active"; } graveLi.innerHTML = 'Graveyard'; if (CHARACTER.highlightJob == 2){ //graveLi.className = "premiumButton"; //graveLi.style.lineHeight = "37px"; } const shopLi = document.createElement('li'); if (window.location.pathname.contains('/city/shop/')){ if (document.getElementsByClassName("active")[0])document.getElementsByClassName("active")[0].removeAttribute('class'); shopLi.className = "active"; } shopLi.innerHTML = 'Merchant'; const questsLi = document.createElement('li'); questsLi.className = "free-space"; if (window.location.pathname.contains('/city/missions')){ if (document.getElementsByClassName("active")[0])document.getElementsByClassName("active")[0].removeAttribute('class'); questsLi.className = "active free-space"; } questsLi.innerHTML = 'Quests'; const potionLi = document.createElement('li'); // instead of doing this, i prefer to to redirect to overview with the hash #potion, so i can use the best available potion from here //potionLi.innerHTML = CHARACTER.level > 74 ? 'Potion' : 'Potion'; potionLi.innerHTML = 'Health Potion'; potionLi.addEventListener('click', function(event) { if (window.location.pathname.contains('/profile'))autoUseBestPotion(); // i do this, so the button still works even if already on the profile }); const churchLi = document.createElement('li'); churchLi.innerHTML = 'Church'; const energyPotionLi = document.createElement('li'); energyPotionLi.innerHTML = 'Energy Potion'; energyPotionLi.addEventListener('click', function(event) { if (window.location.pathname.contains('/profile'))autoUseBestEnergyPotion(); // i do this, so the button still works even if already on the profile }); /* let potionTimer = document.createElement('a'); potionTimer.id = 'potionCooldownTimer'; potionTimer.style.color = 'white'; potionTimer.style.fontSize = '14px'; potionTimer.style.fontFamily = 'monospace'; potionTimer.style.margin = '0px'; potionTimer.href = CHARACTER.level > 74 ? '/profile/useItem/2/20' : '/profile/useItem/2/2'; potionTimer.textContent = 'Potion Cooldown: Calculating...'; let churchTimer = document.createElement('a'); churchTimer.id = 'churchCooldownTimer'; churchTimer.style.color = 'white'; churchTimer.style.fontSize = '14px'; churchTimer.style.fontFamily = 'monospace'; churchTimer.style.margin = '0px'; churchTimer.href = '/city/church'; churchTimer.textContent = 'Church Cooldown: Calculating...'; */ // Insert the new links (in reverse) chasseLi.insertAdjacentElement('afterend', churchLi); chasseLi.insertAdjacentElement('afterend', energyPotionLi); chasseLi.insertAdjacentElement('afterend', potionLi); chasseLi.insertAdjacentElement('afterend', questsLi); chasseLi.insertAdjacentElement('afterend', shopLi); chasseLi.insertAdjacentElement('afterend', graveLi); chasseLi.insertAdjacentElement('afterend', grotteLi); updatePotionCooldownDisplay(); setInterval(updatePotionCooldownDisplay, 1000); updateEnergyPotionCooldownDisplay(); setInterval(updateEnergyPotionCooldownDisplay, 1000); updateChurchCooldownDisplay(); setInterval(updateChurchCooldownDisplay, 1000); updateJobCooldownDisplay(); setInterval(updateJobCooldownDisplay, 1000); } } function moveGameEventDiv() { const gameEventDivs = document.querySelectorAll('[id=gameEvent]'); const itemsDiv = document.getElementById('items'); if (gameEventDivs.length > 0 && itemsDiv) { gameEventDivs.forEach(gameEventDiv => { itemsDiv.insertAdjacentElement('afterend', gameEventDiv); }); } // Scroll up after upgrading a skill if (window.location.hash === '#tabs-2') { window.scrollTo(0, 0); } } function defaultNonPremiumShop() { const links = document.querySelectorAll('a'); // Select all anchor elements links.forEach(link => { // Check if the link href contains '/city/shop/' if (link.href.includes('/city/shop')) { // If the URL doesn't already have a query string, add it if (!link.href.includes('&premiumfilter=nonpremium')) { link.href += '&premiumfilter=nonpremium'; } } }); /* var premiumfilter = document.querySelector('select[name="premiumfilter"]'); // Replace with the correct selector if necessary if (premiumfilter) { premiumfilter.value = 'nonpremium'; // Set default value to 'nonpremium' }*/ } function redirectAfterGrotteFight() { if (!(window.location.href.includes('report/fightreport/') && window.location.href.includes('/grotte')))return; //console.log("Current difficulty : "+CHARACTER.lastGrottoClick); if(CHARACTER.lastGrottoClick == 0 || CHARACTER.lastGrottoClick == 1 || CHARACTER.lastGrottoClick == 2){ saveGrottoStats(CHARACTER.lastGrottoClick); } // condition to redirect to last page if (CHARACTER.autoRedirectGrotte || CHARACTER.autoGrotto[0] || CHARACTER.autoGrotto[1] || CHARACTER.autoGrotto[2]) { // Redirect to '/city/grotte' console.log("Redirecting to grotto..."); window.location.href = '/city/grotte'; } } function saveGrottoStats(grottoDifficulty){ const element = document.querySelector("#reportResult > div.wrap-left.clearfix > div > p.gold"); if(!element)return; const rewards = element.textContent.split("\n")[1].split("+"); const goldEarned = parseInt(rewards[0].replace(/\D/g, '')); const xpEarned = parseInt(rewards[1].replace(/\D/g, '')); const dmgTaken = getGrottoHealthDamage(goldEarned); // ça veut dire que le joueur est mort ! on ne compte pas ce combat dans les stats pour éviter de les fausser if(dmgTaken == -1){ CHARACTER.lastGrottoClick = -1; updateCharacter(); return; } // Ensure the goldEarned array for the selected difficulty exists if (!GROTTO_STATS.goldEarned[grottoDifficulty]) { GROTTO_STATS.goldEarned[grottoDifficulty] = []; } // Push the new gold earned value into the array GROTTO_STATS.goldEarned[grottoDifficulty].push(goldEarned); // Keep only the last 20 entries for each difficulty if (GROTTO_STATS.goldEarned[grottoDifficulty].length > 20) { GROTTO_STATS.goldEarned[grottoDifficulty].shift(); // Remove the oldest entry } // Ensure the dmgTaken array for the selected difficulty exists if (!GROTTO_STATS.dmgTaken[grottoDifficulty]) { GROTTO_STATS.dmgTaken[grottoDifficulty] = []; } // Push the new dmg taken value into the array GROTTO_STATS.dmgTaken[grottoDifficulty].push(dmgTaken); // Keep only the last 20 entries for each difficulty if (GROTTO_STATS.dmgTaken[grottoDifficulty].length > 20) { GROTTO_STATS.dmgTaken[grottoDifficulty].shift(); // Remove the oldest entry } // Ensure the xpEarned array for the selected difficulty exists if (!GROTTO_STATS.xpEarned[grottoDifficulty]) { GROTTO_STATS.xpEarned[grottoDifficulty] = []; } // Push the new dmg taken value into the array GROTTO_STATS.xpEarned[grottoDifficulty].push(xpEarned); // Keep only the last 20 entries for each difficulty if (GROTTO_STATS.xpEarned[grottoDifficulty].length > 20) { GROTTO_STATS.xpEarned[grottoDifficulty].shift(); // Remove the oldest entry } // Update the grotto data with the new stats CHARACTER.lastGrottoClick = -1; updateGrottoStats(); updateCharacter(); } function addGrottoAutoRedirectButton(){ const buildingDescElement = document.getElementsByClassName('buildingDesc')[0]; if (!buildingDescElement) return; // add the button for auto redirection const buttonAutoRedirect = document.createElement("button"); if (CHARACTER.autoRedirectGrotte){ buttonAutoRedirect.textContent = "Redirect : ON"; buttonAutoRedirect.className = "btn-small left btn-redirectGrotto premiumButton"; } else { buttonAutoRedirect.textContent = "Redirect : OFF"; buttonAutoRedirect.className = "btn-small left btn-redirectGrotto"; } buttonAutoRedirect.style.margin = "0px"; buttonAutoRedirect.style.padding = "0 0 5px"; // Add a click event listener buttonAutoRedirect.addEventListener("click", function (event) { CHARACTER.autoRedirectGrotte = !CHARACTER.autoRedirectGrotte; updateCharacter(); if (CHARACTER.autoRedirectGrotte){ buttonAutoRedirect.textContent = "Redirect : ON"; buttonAutoRedirect.className = "btn-small left btn-redirectGrotto premiumButton"; } else { buttonAutoRedirect.textContent = "Redirect : OFF"; buttonAutoRedirect.className = "btn-small left btn-redirectGrotto"; } }); // Insert the button after the target element buildingDescElement.appendChild(buttonAutoRedirect); // add the button to reset stats const button = document.createElement("button"); button.textContent = "Reset stats"; button.className = "btn-small left btn-resetGrotto"; button.style.margin = "0px"; button.style.padding = "0 0 5px"; // Add a click event listener button.addEventListener("click", function (event) { console.log("Grotto stats reset"); GROTTO_STATS.goldEarned = {}; GROTTO_STATS.dmgTaken = {}; GROTTO_STATS.xpEarned = {}; updateGrottoStats(); location.reload(); }); // Insert the button after the target element buildingDescElement.appendChild(button); } function initiateGrottoStats(){ if (!GROTTO_STATS.goldEarned || !GROTTO_STATS.dmgTaken || !GROTTO_STATS.xpEarned) { GROTTO_STATS.goldEarned = {}; GROTTO_STATS.dmgTaken = {}; GROTTO_STATS.xpEarned = {}; updateGrottoStats(); } } function addAutoGrottoButton() { // make sure the variable is defined if (!Array.isArray(CHARACTER.autoGrotto)) { CHARACTER.autoGrotto = [false, false, false]; updateCharacter(); } // instantiate the variable for grotto stats if it isn't already initiateGrottoStats(); for (let difficulty = 0; difficulty < 3; difficulty++) { //const target = $(`table.noBackground form.clearfix div input`)[index]; const grottoButton = document.querySelectorAll('table.noBackground form.clearfix div input')[difficulty]; if (!grottoButton) return; grottoButton.addEventListener('click', (event) => { CHARACTER.lastGrottoClick = difficulty; updateCharacter(); }); // Create the button const button = document.createElement("button"); if(CHARACTER.autoGrotto[difficulty]){ button.textContent = "Auto : ON"; button.className = "btn-small left btn-autoGrotto premiumButton"; } else { button.textContent = "Auto : OFF"; button.className = "btn-small left btn-autoGrotto"; } button.style.margin = "10px"; button.style.padding = "0 0 5px"; // Add a click event listener button.addEventListener("click", function (event) { event.preventDefault(); // Prevent default button behavior if(!CHARACTER.autoGrotto[difficulty] && isReadyForGrotto(difficulty)){ grottoSetAllButtonsToOFF(); CHARACTER.autoGrotto[difficulty] = true; updateCharacter(); button.textContent = "Auto : ON"; button.className = "btn-small left btn-autoGrotto premiumButton"; document.querySelectorAll('table.noBackground form.clearfix div input')[difficulty].click(); } else { CHARACTER.autoGrotto[difficulty] = false; updateCharacter(); button.textContent = "Auto : OFF"; button.className = "btn-small left btn-autoGrotto"; } //console.log(`CHARACTER.autoGrotto[${index}] is now `, CHARACTER.autoGrotto); }); // Insert the button after the target element grottoButton.parentNode.insertBefore(button, grottoButton.nextSibling); displayStatsAverage(difficulty); } } function grottoSetAllButtonsToOFF(){ CHARACTER.autoGrotto[0] = false; CHARACTER.autoGrotto[1] = false; CHARACTER.autoGrotto[2] = false; const buttons = document.querySelectorAll('.btn-autoGrotto'); buttons.forEach(button => { button.textContent = 'Auto : OFF'; button.className = "btn-small left btn-autoGrotto"; }); } function autoFightGrotto() { if(!CHARACTER.autoGrotto[0] && !CHARACTER.autoGrotto[1] && !CHARACTER.autoGrotto[2]) return; var randomDelay = 10; if(!CHARACTER.autoGrottoInstant){ randomDelay = Math.random() * 1500 + 500; // wait between 500ms and 2000ms } //console.log(`Action will be executed after ${randomDelay.toFixed(0)}ms`); // Set the timeout setTimeout(() => { if(!isReadyForGrotto()){ grottoSetAllButtonsToOFF(); updateCharacter(); } else { if(!CHARACTER.autoGrotto[0] && !CHARACTER.autoGrotto[1] && !CHARACTER.autoGrotto[2]) return; if(CHARACTER.autoGrotto[0])document.querySelectorAll('table.noBackground form.clearfix div input')[0].click(); if(CHARACTER.autoGrotto[1])document.querySelectorAll('table.noBackground form.clearfix div input')[1].click(); if(CHARACTER.autoGrotto[2])document.querySelectorAll('table.noBackground form.clearfix div input')[2].click(); } }, randomDelay); } function isReadyForGrotto(difficulty) { //en cas d'abscence de données, on combat si plus de 9000 HP if (!GROTTO_STATS.dmgTaken[difficulty] || GROTTO_STATS.dmgTaken[difficulty].length < 1) return (calculateCurrentHealth() > 9000 && CHARACTER.energy > 0); // sinon, on chope les plus gros dégats qu'on s'est mangé dans cette difficulté, et on y ajoute 10% let highestValue = 0; for (let value of GROTTO_STATS.dmgTaken[difficulty]) { if (value > highestValue) { highestValue = value; } } console.log("gros degats : "+(highestValue*1.1)); return (calculateCurrentHealth() > (highestValue*1.1) && CHARACTER.energy > 0); } // This function calculates the average gold for a given difficulty function calculateGoldAverage(grottoDifficulty) { if (!GROTTO_STATS.goldEarned[grottoDifficulty] || GROTTO_STATS.goldEarned[grottoDifficulty].length < 1) return 0; let totalGold = 0; // Loop through the gold history for the given difficulty for (let i = 0; i < GROTTO_STATS.goldEarned[grottoDifficulty].length; i++) { totalGold += GROTTO_STATS.goldEarned[grottoDifficulty][i]; } return totalGold / GROTTO_STATS.goldEarned[grottoDifficulty].length; } function calculateDamageAverage(grottoDifficulty) { if (!GROTTO_STATS.dmgTaken[grottoDifficulty] || GROTTO_STATS.dmgTaken[grottoDifficulty].length < 1) return 0; let totalDmg = 0; // Loop through the gold history for the given difficulty for (let i = 0; i < GROTTO_STATS.dmgTaken[grottoDifficulty].length; i++) { totalDmg += GROTTO_STATS.dmgTaken[grottoDifficulty][i]; } return totalDmg / GROTTO_STATS.dmgTaken[grottoDifficulty].length; } function calculateXPAverage(grottoDifficulty) { if (!GROTTO_STATS.xpEarned[grottoDifficulty] || GROTTO_STATS.xpEarned[grottoDifficulty].length < 1) return 0; let totalGold = 0; // Loop through the gold history for the given difficulty for (let i = 0; i < GROTTO_STATS.xpEarned[grottoDifficulty].length; i++) { totalGold += GROTTO_STATS.xpEarned[grottoDifficulty][i]; } return totalGold / GROTTO_STATS.xpEarned[grottoDifficulty].length; } function calculateWinrate(grottoDifficulty) { if (!GROTTO_STATS.goldEarned[grottoDifficulty] || GROTTO_STATS.goldEarned[grottoDifficulty].length < 1) return 0; let totalwin = 0; // Loop through the gold history for the given difficulty for (let i = 0; i < GROTTO_STATS.goldEarned[grottoDifficulty].length; i++) { if(GROTTO_STATS.goldEarned[grottoDifficulty][i] > 0)totalwin += 1; } return (totalwin / GROTTO_STATS.goldEarned[grottoDifficulty].length * 100); } // Function to display the average gold under each button function displayStatsAverage(grottoDifficulty) { //console.log("Average gold for difficult "+grottoDifficulty+" : "+calculateGoldAverage(grottoDifficulty)); const button = document.querySelectorAll('.btn-autoGrotto')[grottoDifficulty]; if (!button) return; let avgGoldText = `${calculateGoldAverage(grottoDifficulty).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, '.')} `; let avgDmg = `${calculateDamageAverage(grottoDifficulty).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, '.')} `; let avgXP = `${calculateXPAverage(grottoDifficulty).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, '.')} `; let winrate = `${calculateWinrate(grottoDifficulty).toFixed(0)}% `; // Check if the display already exists, and update or create a new one let avgElement = button.querySelector('.gold-average'); avgElement = document.createElement('div'); avgElement.classList.add('gold-average'); avgElement.style.fontSize = '15px'; avgElement.style.marginLeft = '10px'; avgElement.style.textAlign = 'center'; // Center the text avgElement.style.display = 'block'; // Make sure it takes up the full width and goes below the button avgElement.style.width = '160px'; avgElement.style.textShadow = "0 0 4px #FF0000"; avgElement.style.fontFamily = 'monospace'; avgElement.style.fontWeight = 'bold'; avgElement.style.color = 'white'; avgElement.style.lineHeight = '25px'; button.parentNode.insertBefore(avgElement, button.nextSibling); avgElement.textContent = avgGoldText; // Create an image element and append it after the text let imgGold = document.createElement('img'); imgGold.src = '/img/symbols/res2.gif'; avgElement.appendChild(imgGold); imgGold.align = 'absmiddle'; // xp earned var lineBreak2 = document.createElement('br'); avgElement.appendChild(lineBreak2); var avgXPText = document.createTextNode(avgXP); avgElement.appendChild(avgXPText); let imgXP = document.createElement('img'); imgXP.src = '/img/symbols/level.gif'; avgElement.appendChild(imgXP); imgXP.align = 'absmiddle'; // health lost var lineBreak = document.createElement('br'); avgElement.appendChild(lineBreak); var avgDmgText = document.createTextNode(avgDmg); avgElement.appendChild(avgDmgText); let imgHealth = document.createElement('img'); imgHealth.src = '/img/symbols/herz.png'; avgElement.appendChild(imgHealth); imgHealth.align = 'absmiddle'; // winrate var lineBreak3 = document.createElement('br'); avgElement.appendChild(lineBreak3); var winrateText = document.createTextNode(winrate); avgElement.appendChild(winrateText); let imgWin = document.createElement('img'); imgWin.src = '/img/symbols/fightvalue.gif'; avgElement.appendChild(imgWin); imgWin.align = 'absmiddle'; } // if gold earned = 0, then it's lost,and the dmg taken is on left and not on right function getGrottoHealthDamage(goldEarned){ var win = 1; if(goldEarned == 0){ win = 0; } const wholeText = document.querySelectorAll('#reportResult div.wrap-left div.wrap-content p')[0].textContent; const extractedText = wholeText.match(/\(([^)]+)\)/); if(!extractedText)return -1; // si on trouve pas le texte, c'est que le joueur est mort, on renvoi -1 pour que ce resultat soit ignoré const numbers = extractedText[1].split(":"); return(parseInt(numbers[win])); } function settingsMenu(){ // Create the new div element const settingDiv = document.createElement('div'); settingDiv.id = 'betterBfSettings'; settingDiv.innerHTML = `

    Better BiteFight Settings

    `; // Locate the target div const charDescDiv = document.getElementById('discribeChar'); if (charDescDiv)charDescDiv.parentNode.insertBefore(settingDiv, charDescDiv); const settingContentDiv = document.querySelector("div#betterBfSettings div.wrap-left.clearfix div.wrap-content.wrap-right.clearfix"); const potionDiv = createSettingPotionHighlightDiv(); settingContentDiv.appendChild(potionDiv); const energyPotionDiv = createSettingEnergyPotionHighlightDiv(); settingContentDiv.appendChild(energyPotionDiv); const churchDiv = createSettingChurchHighlightDiv(); settingContentDiv.appendChild(churchDiv); const jobDiv = createSettingJobHighlightDiv(); settingContentDiv.appendChild(jobDiv); const healthRefreshRateDiv = createSettingHealthRefreshDiv(); settingContentDiv.appendChild(healthRefreshRateDiv); const grottoSpeedDiv = createSettingGrottoSpeedDiv(); settingContentDiv.appendChild(grottoSpeedDiv); const showTotalDiv = createSettingShowTotalDiv(); settingContentDiv.appendChild(showTotalDiv); const hideBuddiesDiv = createSettingHideBuddiesDiv(); settingContentDiv.appendChild(hideBuddiesDiv); const hideCharsimaDiv = createSettingHideCharsimaDiv(); settingContentDiv.appendChild(hideCharsimaDiv); const resetDataDiv = createSettingResetDataDiv(); settingContentDiv.appendChild(resetDataDiv); } function createSettingTextDiv(){ const newDiv = document.createElement('div') newDiv.style.minWidth = "355px"; newDiv.style.textAlign = "right"; newDiv.style.marginTop = "9px"; newDiv.style.textShadow = "0 0 4px #FF0000"; newDiv.style.fontSize = "16px"; return newDiv; } function createSettingChurchHighlightDiv(){ //create the setting line const mainDiv = document.createElement('div'); mainDiv.style.display = "flex"; //churchDiv.style.justifyContent = 'space-around'; const leftDiv = createSettingTextDiv(); mainDiv.appendChild(leftDiv); const rightDiv = document.createElement('div'); mainDiv.appendChild(rightDiv); // add the text let textChurchHighlight = document.createTextNode('Highlight CHURCH when ready : '); leftDiv.appendChild(textChurchHighlight); // add the button for church highlight const newButton = document.createElement("button"); newButton.className = "btn-small left"; if (CHARACTER.highlightChurch){ newButton.textContent = "Yes"; } else { newButton.textContent = "No"; } newButton.style.margin = "0px"; newButton.style.padding = "0 0 5px"; // Add a click event listener newButton.addEventListener("click", function (event) { event.preventDefault(); // Prevent default button behavior CHARACTER.highlightChurch = !CHARACTER.highlightChurch; updateCharacter(); if (CHARACTER.highlightChurch){ newButton.textContent = "Yes"; } else { newButton.textContent = "No"; document.getElementById('churchCooldownTimer').className = ""; // turning off instantly } }); // Insert the button after the target element rightDiv.appendChild(newButton); return mainDiv; } function createSettingPotionHighlightDiv(){ //create the setting line const mainDiv = document.createElement('div'); mainDiv.style.display = "flex"; //churchDiv.style.justifyContent = 'space-around'; const leftDiv = createSettingTextDiv(); mainDiv.appendChild(leftDiv); const rightDiv = document.createElement('div'); mainDiv.appendChild(rightDiv); // add the text let textChurchHighlight = document.createTextNode('Highlight POTION when ready : '); leftDiv.appendChild(textChurchHighlight); // add the button for church highlight const newButton = document.createElement("button"); newButton.className = "btn-small left"; if (CHARACTER.highlightPotion){ newButton.textContent = "Yes"; } else { newButton.textContent = "No"; } newButton.style.margin = "0px"; newButton.style.padding = "0 0 5px"; // Add a click event listener newButton.addEventListener("click", function (event) { event.preventDefault(); // Prevent default button behavior CHARACTER.highlightPotion = !CHARACTER.highlightPotion; updateCharacter(); if (CHARACTER.highlightPotion){ newButton.textContent = "Yes"; } else { newButton.textContent = "No"; document.getElementById('potionCooldownTimer').className = ""; // turning off instantly } }); // Insert the button after the target element rightDiv.appendChild(newButton); return mainDiv; } function createSettingEnergyPotionHighlightDiv(){ //create the setting line const mainDiv = document.createElement('div'); mainDiv.style.display = "flex"; //churchDiv.style.justifyContent = 'space-around'; const leftDiv = createSettingTextDiv(); mainDiv.appendChild(leftDiv); const rightDiv = document.createElement('div'); mainDiv.appendChild(rightDiv); // add the text let textChurchHighlight = document.createTextNode('Highlight ENERGY POTION when ready : '); leftDiv.appendChild(textChurchHighlight); // add the button for church highlight const newButton = document.createElement("button"); newButton.className = "btn-small left"; if (CHARACTER.highlightEnergyPotion){ newButton.textContent = "Yes"; } else { newButton.textContent = "No"; } newButton.style.margin = "0px"; newButton.style.padding = "0 0 5px"; // Add a click event listener newButton.addEventListener("click", function (event) { event.preventDefault(); // Prevent default button behavior CHARACTER.highlightEnergyPotion = !CHARACTER.highlightEnergyPotion; updateCharacter(); if (CHARACTER.highlightEnergyPotion){ newButton.textContent = "Yes"; } else { newButton.textContent = "No"; document.getElementById('energyPotionCooldownTimer').className = ""; // turning off instantly } }); // Insert the button after the target element rightDiv.appendChild(newButton); return mainDiv; } function createSettingJobHighlightDiv(){ //create the setting line const mainDiv = document.createElement('div'); mainDiv.style.display = "flex"; //churchDiv.style.justifyContent = 'space-around'; const leftDiv = createSettingTextDiv(); mainDiv.appendChild(leftDiv); const rightDiv = document.createElement('div'); mainDiv.appendChild(rightDiv); // add the text let textChurchHighlight = document.createTextNode('Highlight JOB : '); leftDiv.appendChild(textChurchHighlight); // add the button for church highlight const newButton = document.createElement("button"); newButton.className = "btn-small left"; if (CHARACTER.highlightJob == 0){ newButton.textContent = "Never"; } else if (CHARACTER.highlightJob == 1){ newButton.textContent = "In progress"; } else { newButton.textContent = "Finished"; } newButton.style.margin = "0px"; newButton.style.padding = "0 0 5px"; // Add a click event listener newButton.addEventListener("click", function (event) { event.preventDefault(); // Prevent default button behavior if (CHARACTER.highlightJob == 0){ CHARACTER.highlightJob = 1; } else if (CHARACTER.highlightJob == 1){ CHARACTER.highlightJob = 2; } else { CHARACTER.highlightJob = 0; } updateCharacter(); if (CHARACTER.highlightJob == 0){ newButton.textContent = "Never"; } else if (CHARACTER.highlightJob == 1){ newButton.textContent = "In progress"; } else { newButton.textContent = "Finished"; } updateJobCooldownDisplay(); }); // Insert the button after the target element rightDiv.appendChild(newButton); return mainDiv; } function createSettingHealthRefreshDiv(){ //create the setting line const mainDiv = document.createElement('div'); mainDiv.style.display = "flex"; //churchDiv.style.justifyContent = 'space-around'; const leftDiv = createSettingTextDiv(); mainDiv.appendChild(leftDiv); const rightDiv = document.createElement('div'); mainDiv.appendChild(rightDiv); // add the text let textChurchHighlight = document.createTextNode('Health refresh rate : '); leftDiv.appendChild(textChurchHighlight); // add the button for church highlight const newButton = document.createElement("button"); newButton.textContent = CHARACTER.healthRefreshRate+" ms"; newButton.className = "btn-small left"; newButton.style.margin = "0px"; newButton.style.padding = "0 0 5px"; // Add a click event listener newButton.addEventListener("click", function (event) { event.preventDefault(); // Prevent default button behavior if (CHARACTER.healthRefreshRate == 200){ CHARACTER.healthRefreshRate = 500; } else if (CHARACTER.healthRefreshRate == 500){ CHARACTER.healthRefreshRate = 1000; } else if (CHARACTER.healthRefreshRate == 1000){ CHARACTER.healthRefreshRate = 10000; } else if (CHARACTER.healthRefreshRate == 10000){ CHARACTER.healthRefreshRate = 25; } else if (CHARACTER.healthRefreshRate == 25){ CHARACTER.healthRefreshRate = 50; } else if (CHARACTER.healthRefreshRate == 50){ CHARACTER.healthRefreshRate = 100; } else { CHARACTER.healthRefreshRate = 200; } newButton.textContent = CHARACTER.healthRefreshRate+" ms"; updateCharacter(); if (healthRefreshInterval){ clearInterval(healthRefreshInterval); startHealthRegeneration(); } }); // Insert the button after the target element rightDiv.appendChild(newButton); return mainDiv; } function createSettingGrottoSpeedDiv(){ //create the setting line const mainDiv = document.createElement('div'); mainDiv.style.display = "flex"; //churchDiv.style.justifyContent = 'space-around'; const leftDiv = createSettingTextDiv(); mainDiv.appendChild(leftDiv); const rightDiv = document.createElement('div'); mainDiv.appendChild(rightDiv); // add the text let textChurchHighlight = document.createTextNode('Auto grotto speed : '); leftDiv.appendChild(textChurchHighlight); // add the button for church highlight const newButton = document.createElement("button"); if(CHARACTER.autoGrottoInstant){ newButton.textContent = "Instant"; } else { newButton.textContent = "Randomized"; } newButton.className = "btn-small left"; newButton.style.margin = "0px"; newButton.style.padding = "0 0 5px"; // Add a click event listener newButton.addEventListener("click", function (event) { event.preventDefault(); // Prevent default button behavior CHARACTER.autoGrottoInstant = !CHARACTER.autoGrottoInstant; updateCharacter(); if(CHARACTER.autoGrottoInstant){ newButton.textContent = "Instant"; } else { newButton.textContent = "Randomized"; } }); // Insert the button after the target element rightDiv.appendChild(newButton); return mainDiv; } function createSettingResetDataDiv(){ //create the setting line const mainDiv = document.createElement('div'); mainDiv.style.display = "flex"; //churchDiv.style.justifyContent = 'space-around'; const leftDiv = createSettingTextDiv(); mainDiv.appendChild(leftDiv); const rightDiv = document.createElement('div'); mainDiv.appendChild(rightDiv); // add the text let textChurchHighlight = document.createTextNode('Reset BBF data : '); leftDiv.appendChild(textChurchHighlight); // add the button for church highlight const newButton = document.createElement("button"); newButton.textContent = "Reset"; newButton.className = "btn-small left"; newButton.style.margin = "0px"; newButton.style.padding = "0 0 5px"; // Add a click event listener newButton.addEventListener("click", function (event) { event.preventDefault(); // Prevent default button behavior GM_deleteValue(KEY_SERVER_DOMAIN); GM_deleteValue(KEY_SERVER_DOMAIN+"/grotto_stats"); location.reload(); }); // Insert the button after the target element rightDiv.appendChild(newButton); return mainDiv; } function createSettingShowTotalDiv(){ //create the setting line const mainDiv = document.createElement('div'); mainDiv.style.display = "flex"; //churchDiv.style.justifyContent = 'space-around'; const leftDiv = createSettingTextDiv(); mainDiv.appendChild(leftDiv); const rightDiv = document.createElement('div'); mainDiv.appendChild(rightDiv); // add the text let textChurchHighlight = document.createTextNode('Show max health and max energy : '); leftDiv.appendChild(textChurchHighlight); // add the button for church highlight const newButton = document.createElement("button"); if(CHARACTER.showTotalStat){ newButton.textContent = "Yes"; } else { newButton.textContent = "No"; } newButton.className = "btn-small left"; newButton.style.margin = "0px"; newButton.style.padding = "0 0 5px"; // Add a click event listener newButton.addEventListener("click", function (event) { event.preventDefault(); // Prevent default button behavior CHARACTER.showTotalStat = !CHARACTER.showTotalStat; updateCharacter(); if(CHARACTER.showTotalStat){ newButton.textContent = "Yes"; } else { newButton.textContent = "No"; } updateHealthBars(calculateCurrentHealth()); updateEnergyBars(calculateCurrentEnergy()); }); // Insert the button after the target element rightDiv.appendChild(newButton); return mainDiv; } function createSettingHideBuddiesDiv(){ //create the setting line const mainDiv = document.createElement('div'); mainDiv.style.display = "flex"; //churchDiv.style.justifyContent = 'space-around'; const leftDiv = createSettingTextDiv(); mainDiv.appendChild(leftDiv); const rightDiv = document.createElement('div'); mainDiv.appendChild(rightDiv); // add the text let textChurchHighlight = document.createTextNode('Hide buddies button : '); leftDiv.appendChild(textChurchHighlight); // add the button for church highlight const newButton = document.createElement("button"); if(CHARACTER.hideBuddies){ newButton.textContent = "Yes"; } else { newButton.textContent = "No"; } newButton.className = "btn-small left"; newButton.style.margin = "0px"; newButton.style.padding = "0 0 5px"; // Add a click event listener newButton.addEventListener("click", function (event) { event.preventDefault(); // Prevent default button behavior CHARACTER.hideBuddies = !CHARACTER.hideBuddies; updateCharacter(); if(CHARACTER.hideBuddies){ newButton.textContent = "Yes"; } else { newButton.textContent = "No"; } hideBuddies(); }); // Insert the button after the target element rightDiv.appendChild(newButton); return mainDiv; } function createSettingHideCharsimaDiv(){ //create the setting line const mainDiv = document.createElement('div'); mainDiv.style.display = "flex"; //churchDiv.style.justifyContent = 'space-around'; const leftDiv = createSettingTextDiv(); mainDiv.appendChild(leftDiv); const rightDiv = document.createElement('div'); mainDiv.appendChild(rightDiv); // add the text let textChurchHighlight = document.createTextNode('Hide charisma button : '); leftDiv.appendChild(textChurchHighlight); // add the button for church highlight const newButton = document.createElement("button"); if(CHARACTER.hideCharisma){ newButton.textContent = "Yes"; } else { newButton.textContent = "No"; } newButton.className = "btn-small left"; newButton.style.margin = "0px"; newButton.style.padding = "0 0 5px"; // Add a click event listener newButton.addEventListener("click", function (event) { event.preventDefault(); // Prevent default button behavior CHARACTER.hideCharisma = !CHARACTER.hideCharisma; updateCharacter(); if(CHARACTER.hideCharisma){ newButton.textContent = "Yes"; } else { newButton.textContent = "No"; } }); // Insert the button after the target element rightDiv.appendChild(newButton); return mainDiv; } })();