Pendoria - Chance to die

Implements some extra information per finished fight in the battle view on pendoria.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Pendoria - Chance to die
// @description  Implements some extra information per finished fight in the battle view on pendoria.
// @namespace    http://pendoria.net/
// @version      0.0.33
// @author       Xortrox
// @contributor  Tester: euphone
// @contributor  Tester: fourkade
// @contributor  Coder: Kidel
// @match        http://pendoria.net/game
// @match        https://pendoria.net/game
// @match        http://www.pendoria.net/game
// @match        https://www.pendoria.net/game
// @grant        none
// ==/UserScript==

(function () {
    function showChanceToDie(data) {
        let playerHealth = $('#php-value')[0];

        if (!playerHealth) {
            return console.log('playerHealth element was not found.');
        }

        let fightDiv = $('#fight')[0];

        if (!fightDiv) {
            return console.log('fightDiv element was not found.');
        }

        let playerHPBackground = $('#php-background')[0];

        if (!playerHPBackground) {
            return console.log('playerHPBackground element was not found.');
        }

        function createHistoricallyLowestHealthTrackerIfNotExists() {
            let historicallyLowestHPTracker = $('#ctdInfoHistoriallyLowestDiv')[0];

            if(!historicallyLowestHPTracker) {
                let infoDiv = document.createElement('div');
                infoDiv.id = 'ctdInfoHistoriallyLowestDiv';
                playerHPBackground.parentElement.prepend(infoDiv);
            }

            return historicallyLowestHPTracker;
        }

        function createInfoDivIfNotExists() {
            let ctdInfoDiv = $('#ctdInfoDiv')[0];

            if (!ctdInfoDiv) {
                let infoDiv = document.createElement('div');
                infoDiv.id = 'ctdInfoDiv';
                fightDiv.parentElement.appendChild(infoDiv);
            }

            return ctdInfoDiv;
        }

        let enemyHitChanceFactor = data.monsterChanceToHit / 100.0;

        let playerMaxHealth = data.playerMaxLife;
        let enemyAverageDamage = data.damageTaken / data.hitsTaken;

        let enemyHitsToKill = Math.ceil(playerMaxHealth / enemyAverageDamage);

        let playerChanceFactorDeath = enemyHitChanceFactor ** enemyHitsToKill;

        let playerHitChanceFactor = data.playerChanceToHit / 100.0;


        let playerAverageDamage = data.damageDone / data.timesHit;

        let enemyMaxHealth = data.monsterMaxLife;

        let enemyMaxHealthWithChanceFactor = (enemyMaxHealth / playerHitChanceFactor);
        let playerHitsToKillEnemy = Math.ceil(enemyMaxHealthWithChanceFactor / playerAverageDamage);
        let playerHitsToKillEnemyNoChanceFactor = Math.ceil(enemyMaxHealth / playerAverageDamage);

        // console.log('enemyHitsToKill:', enemyHitsToKill);
        // console.log('playerHitChanceFactor:', playerHitChanceFactor);
        // console.log('(1 - (1 - playerHitChanceFactor) ** enemyHitsToKill) * 100');
        // let playerWinChance = (1 - (1 - playerHitChanceFactor) ** playerHitsToKillEnemyNoChanceFactor) * 100

        let enemyChanceFactorDeath = playerHitChanceFactor ** playerHitsToKillEnemy;

        let likelinessPrediction = ``;

        // TODO: Make this based on some amount of % within proximity of max healths and damages.
        if (playerHitsToKillEnemy < enemyHitsToKill) {
            likelinessPrediction +=
                `It seems <b style="color:lightgreen">unlikely</b> that you will die as the enemy is required to hit you ${enemyHitsToKill} times, but you need to hit it roughly ${playerHitsToKillEnemy} times.<br>
                <br>
                `;
        } else if (playerHitsToKillEnemy >= enemyHitsToKill){
            likelinessPrediction +=
                `It seems <b style="color:red">likely</b> that you will die as the enemy needs to hit you ${enemyHitsToKill} times, but you need to hit it roughly ${playerHitsToKillEnemy} times.<br>
                <br>
                `;
        }

        let ctdInfoDiv = createInfoDivIfNotExists();

        let diffHits = enemyHitsToKill - playerHitsToKillEnemy;

        if (ctdInfoDiv){
            ctdInfoDiv.innerHTML =
                `
                <div style="border-bottom: 1px solid white; margin-bottom: 3px;">
                  Chance to die<button id="ctdClearHistoricalTracker" style="padding-top: 0; padding-bottom: 0; height:21px; border: 1px solid white; background: transparent; border-radius: 0; float:right; line-height: 21px;">Reset lowest health tracker</button>
                </div>
                ${likelinessPrediction}
                You would die after <b style="color:red;">${enemyHitsToKill}</b>~ rounds of battle if the enemy is still alive.<br>
                You would win after <b style="color:lightgreen;">${playerHitsToKillEnemy}</b>~ rounds of battle.<br>
                <br>
                You have a chance of ${(((1 - playerHitChanceFactor) ** diffHits) * 100).toPrecision(3)}%~ to miss enough in order to receive ${enemyHitsToKill} hits from this enemy, which would kill you.<br>
                `
        }

        /**
         * Bind click event of ctdClearHistoricalTracker
         * */
        $('#ctdClearHistoricalTracker').click(() => {
            let pendCtdSettings = window.localStorage.getItem('PendoriaChanceToDie');
            if (pendCtdSettings) {
               pendCtdSettings = JSON.parse(pendCtdSettings);
            }

            delete(pendCtdSettings.historiallyLowestHealth);

            localStorage.setItem('PendoriaChanceToDie', JSON.stringify(pendCtdSettings));
        });

        playerCurrentHealth = data.playerLife;
        if (playerCurrentHealth < 0) {
            playerCurrentHealth = 0;
        }

        // console.log('playerCurrentHealth:', playerCurrentHealth);

        let ctdInfoHistoriallyLowestDiv = createHistoricallyLowestHealthTrackerIfNotExists();

        // TODO: Also show how many hits you took and for what average damage the hits were, in the tooltip
        if(ctdInfoHistoriallyLowestDiv) {
            let pendCtdSettings = window.localStorage.getItem('PendoriaChanceToDie');
            if (!pendCtdSettings) {
                pendCtdSettings = {
                    historiallyLowestHealth: playerCurrentHealth
                };

                localStorage.setItem('PendoriaChanceToDie', JSON.stringify(pendCtdSettings));
            } else {
                pendCtdSettings = JSON.parse(pendCtdSettings);

                if (pendCtdSettings.historiallyLowestHealth === undefined) {
                    pendCtdSettings.historiallyLowestHealth = playerCurrentHealth
                    localStorage.setItem('PendoriaChanceToDie', JSON.stringify(pendCtdSettings));
                }
            }

            if (playerCurrentHealth < pendCtdSettings.historiallyLowestHealth) {
                pendCtdSettings.historiallyLowestHealth = playerCurrentHealth;
                localStorage.setItem('PendoriaChanceToDie', JSON.stringify(pendCtdSettings))
            }

            let playerHealthPercentage = (pendCtdSettings.historiallyLowestHealth / playerMaxHealth * 100);

            /**
             * Only update qtip if the contents changed.
             **/
            if (ctdInfoHistoriallyLowestDiv.innerText !== commarize(pendCtdSettings.historiallyLowestHealth)) {
                setTimeout(() => {
                    $('#php-value').qtip({
                        style: {
                            classes: 'qtip-dark'
                        },
                        position: {
                            target: $('#ctdInfoHistoriallyLowestDiv'),
                            at: 'bottom left'
                        },
                        content: {
                            text: pendCtdSettings.historiallyLowestHealth,
                            // title: 'Historically lowest health'
                        }
                    });
                })
            }

            ctdInfoHistoriallyLowestDiv.innerText = commarize(pendCtdSettings.historiallyLowestHealth);
            ctdInfoHistoriallyLowestDiv.style =
                `
                z-index: 9999;
                position: absolute;
                background-color: #14723c;
                height: 25px;
                line-height: 26px;
                padding-left: 5px;
                border-radius: 10px;
                font-size: 12px;
                width: ${playerHealthPercentage}%;
                `;

            playerHealth.style.zIndex = '9999';
        }
    }

    $(function () {
        function load() {
            if(window.socket) {
                socket.on('battle data', (data) => {
                    showChanceToDie(data);
                });
            } else {
                setTimeout(load, 500);
            }
        }
        load();
    });


    /**
     * Appends a suffix to the number and shortens it generally.
     * */
    function commarize(number) {
        if(number < 999999) { return number; }
        var sizes = [
            '',
            '',
            'Mill',
            'Bill',
            'Trill',
            'Quad',
            'Quint',
            'Sext',
            'Sept',
            'Oct'
        ];
        if (number == 0) return '0 Byte';
        var i = parseInt(Math.floor(Math.log(number) / Math.log(1000)));
        return (number / Math.pow(1000, i)).toPrecision(4) + ' ' + sizes[i];
    }

    /**
     * Shows the full precision of a number up to 100 digits.
     * */
    function fullZeroes(number) {
        return number.toFixed(100).replace(/.?0+$/,"")     // 0.0000005
    }

    /**
     * Takes a number string
     * */
    function fourLastDigits(numberString) {
        let index = 0;
        let theValAfterDot = numberString.substr(numberString.indexOf('.') + 1);

        while(theValAfterDot[index] === '0'){
            index++;
        }
        return '0.' + theValAfterDot.substr(0, index + 3)
    }
}());