Greasy Fork

Greasy Fork is available in English.

BiteFight Healthbar

Adds an healthbar and energybar to BiteFight

当前为 2024-11-19 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         BiteFight Healthbar
// @namespace    https://lobby.bitefight.gameforge.com/
// @version      0.5.0
// @description  Adds an healthbar and energybar to BiteFight
// @author       Spychopat
// @match        https://*.bitefight.gameforge.com/*
// @icon         https://lobby.bitefight.gameforge.com/favicon.ico
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// ==/UserScript==

(function () {
    'use strict';

    // Script storage keys
    const KEY_CHARACTER = 'character';
    const pageLoadTime = Date.now();

    // Define character object
    const CHARACTER = GM_getValue(KEY_CHARACTER, {
        energy: 0,
        maxEnergy: 0,
        health: 0,
        maxHealth: 0,
        regenHealth: 0,
        potionCooldownEnd: 0,
        churchCooldownEnd: 0
    });

    // Get Stats
    var allStatsElement = document.getElementsByClassName("gold")[0];
    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);
    }

    addAdditionnalLink();
    updatePotionTimer();
    updateChurchCooldownTimer(); // Run the church cooldown update function if on the church page
    updateRegenHealth();
    updateCharacter();
    insertCSS();
    insertProgressBars(); // Insert progress bars after updating the character
    startHealthRegeneration(); // Start health regeneration on page load


    //console.log(CHARACTER);


    function insertCSS() {
        GM_addStyle(`
        #upgrademsg {
            display: none;
        }
        #premium > img {
            display: none;
        }
        #mmonetbar {
            display: none !important;
            visibility: hidden;
        }
    `);
    }

    // Format texts to return as numbers (no thousand separators)
    function formatNumber(value) {
        while (value.indexOf(".") > 0) value = value.replace(".", "");
        return value;
    }

    function updateRegenHealth() {
        if (!window.location.pathname.endsWith('/profile/index')) return;
        var elements = document.getElementsByClassName("triggerTooltip");

        // Loop through the elements
        for (let i = 0; i < elements.length; i++) {
            // Check if the inner text or inner HTML contains "/ h"
            if (elements[i].innerText.includes("/ h") || elements[i].innerHTML.includes("/ h")) {
                CHARACTER.regenHealth = parseInt(elements[i].textContent);
                //console.log("Regen per hour found : ", parseInt(elements[i].textContent));
                break; // Exit the loop once the element is found
            }
        }
    }

    // Update character in local storage
    function updateCharacter() {
        GM_setValue(KEY_CHARACTER, CHARACTER);
    }

    function updatePotionTimer() {
        if (!window.location.pathname.endsWith('/profile/index')) return; // Ensure this only runs on the right page
        // Get all elements with the class "inactive"
        const inactiveElements = document.getElementsByClassName('inactive');
        let targetElement = null;
        // Loop through each "inactive" element to find the target
        for (const inactiveElement of inactiveElements) {
            // Find elements with the class "countdown_row countdown_amount" within the current "inactive" element
            const matchingElements = inactiveElement.getElementsByClassName('countdown_row countdown_amount');
            if (matchingElements.length > 0) {
                targetElement = matchingElements[0]; // Take the first matching element
                break; // Stop once we find the target
            }
        }

        if (targetElement) {
            // Get the current time and add the potion cooldown to get the end time
            const currentTime = new Date().getTime() / 1000; // Current time in seconds
            const cooldownTime = timeToSeconds(targetElement.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;
            updateCharacter(); // Save updated character data
        }
    }


    function timeToSeconds(timeStr) {
        const [hours, minutes, seconds] = timeStr.split(':').map(Number);
        return (hours * 3600) + (minutes * 60) + seconds;
    }

    function insertProgressBars() {
        // Check if the layout container is already present
        if (document.getElementById('progressBarsTimersContainer')) {
            return;
        }

        // Create the main container for the layout
        let mainContainer = document.createElement('div');
        mainContainer.id = 'progressBarsTimersContainer';
        mainContainer.style.display = 'flex';
        mainContainer.style.justifyContent = 'space-between';
        mainContainer.style.alignItems = 'center';
        mainContainer.style.marginTop = '3px';

        // Left section for progress bars
        let progressBarsContainer = document.createElement('div');
        progressBarsContainer.style.display = 'flex';
        progressBarsContainer.style.flexDirection = 'column';
        progressBarsContainer.style.alignItems = 'flex-start';
        progressBarsContainer.style.paddingLeft = '50px';

        // Create Health Progress Bar
        let healthBarContainer = document.createElement('div');
        healthBarContainer.style.width = '250px';
        healthBarContainer.style.position = 'relative';
        healthBarContainer.id = 'healthProgressBar';
        healthBarContainer.style.backgroundColor = 'black'; // Black background
        healthBarContainer.style.border = '3px solid rgb(117, 117, 117)'; // White outline

        let healthBar = document.createElement('div');
        healthBar.style.height = '20px';
        healthBar.style.width = `${(CHARACTER.health / CHARACTER.maxHealth) * 100}%`;
        healthBar.style.backgroundColor = '#b80000';

        let healthText = document.createElement('div');
        healthText.textContent = `${CHARACTER.health > 999 ? CHARACTER.health.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.') : CHARACTER.health}`;
        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);

        // Create Energy Progress Bar
        let energyBarContainer = document.createElement('div');
        energyBarContainer.style.width = '250px';
        energyBarContainer.style.marginBottom = '5px';
        energyBarContainer.style.position = 'relative';
        energyBarContainer.id = 'energyProgressBar';
        energyBarContainer.style.backgroundColor = 'black'; // Black background
        energyBarContainer.style.borderLeft = '3px solid rgb(117, 117, 117)'; // White outline
        energyBarContainer.style.borderRight = '3px solid rgb(117, 117, 117)'; // White outline
        energyBarContainer.style.borderBottom = '3px solid rgb(117, 117, 117)'; // White outline

        let energyBar = document.createElement('div');
        energyBar.style.height = '20px';
        energyBar.style.width = `${(CHARACTER.energy / CHARACTER.maxEnergy) * 100}%`;
        energyBar.style.backgroundColor = '#0000a4';

        let energyText = document.createElement('div');
        energyText.textContent = `${CHARACTER.energy}`;
        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);

        // Right section for timers
        let timersContainer = document.createElement('div');
        timersContainer.style.textAlign = 'center';
        timersContainer.style.paddingRight = '50px';
        timersContainer.style.width = '256px';

        let potionTimer = document.createElement('div');
        potionTimer.id = 'potionCooldownTimer';
        potionTimer.style.color = 'white';
        potionTimer.style.fontSize = '14px';
        potionTimer.style.fontFamily = 'monospace';
        potionTimer.textContent = 'Potion Cooldown: Calculating...';
        potionTimer.textPadding = '0px';
        potionTimer.style.margin = '0px';

        let churchTimer = document.createElement('div');
        churchTimer.id = 'churchCooldownTimer';
        churchTimer.style.color = 'white';
        churchTimer.style.fontSize = '14px';
        churchTimer.style.fontFamily = 'monospace';
        churchTimer.style.margin = '0px';
        churchTimer.textPadding = '0px';
        churchTimer.textContent = 'Church Cooldown: Calculating...';

        timersContainer.appendChild(potionTimer);
        timersContainer.appendChild(churchTimer);

        // Add both sections to the main container
        mainContainer.appendChild(progressBarsContainer);
        mainContainer.appendChild(timersContainer);

        // Append the main container to the desired parent element
        document.getElementsByClassName("gold")[0].appendChild(mainContainer);

        // Start updating the timers
        updatePotionCooldownDisplay();
        setInterval(updatePotionCooldownDisplay, 1000);
        updateChurchCooldownDisplay();
        setInterval(updateChurchCooldownDisplay, 1000);
    }


    // Start real-time health regeneration
    function startHealthRegeneration() {
        const regenInterval = 200; // Update every 200 ms
        const regenPerSecond = CHARACTER.regenHealth / 3600; // Convert regenHealth from per hour to per second

        setInterval(() => {
            // 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
            );

            // Update the progress bar with the calculated health
            updateProgressBars(updatedHealth);
        }, regenInterval);
    }

    // Update the existing progress bars
    function updateProgressBars(calculatedHealth) {
        // Update Energy Progress Bar
        //const energyBar = document.getElementById('energyProgressBar').children[0];
        //energyBar.style.width = `${(CHARACTER.energy / CHARACTER.maxEnergy) * 100}%`;
        //const energyText = document.getElementById('energyProgressBar').children[1];
        //energyText.textContent = `${CHARACTER.energy}`;

        // 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}`;
    }


    // Function to update the timer display
    function updatePotionCooldownDisplay() {
        const timerElement = 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 Cooldown: ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
        } else {
            timerElement.textContent = 'Potion Ready!';
        }
    }


    // Add the church cooldown timer display
    function updateChurchCooldownTimer() {
        if (!window.location.pathname.contains('/city/church')) return; // Ensure this only runs on the church page

        const churchCountdownElement = document.getElementsByClassName('hasCountdown')[0];
        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
        }
    }


    // 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 Cooldown: ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
        } else {
            timerElement.textContent = 'Church Ready!';
        }
    }

    function addAdditionnalLink() {
        // Find the <li> containing the Chasse link
        const chasseListItem = document.querySelector('li.free-space > a[href$="/robbery/index"]');

        if (chasseListItem) {
            // Navigate to the parent <li> 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 <li> 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 = '<a href="/city/grotte" target="_top">Grotte</a>';


            const graveLi = document.createElement('li');
            graveLi.className = "free-space";
            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 free-space";
            }
            graveLi.innerHTML = '<a href="/city/graveyard" target="_top">Graveyard</a>';

            // Insert the new <li> after the Chasse <li>
            chasseLi.insertAdjacentElement('afterend', graveLi);
            chasseLi.insertAdjacentElement('afterend', grotteLi);
        }
    }


})();