IQRPG Battle Stats

Tracks various battle stats over multiple battles.

目前为 2021-12-08 提交的版本。查看 最新版本

// ==UserScript==
// @name         IQRPG Battle Stats
// @namespace    https://www.iqrpg.com/
// @version      0.1
// @description  Tracks various battle stats over multiple battles.
// @author       Coastis
// @match        http://iqrpg.com/game.php
// @match        https://iqrpg.com/game.php
// @match        http://www.iqrpg.com/game.php
// @match        https://www.iqrpg.com/game.php
// @match        http://test.iqrpg.com/game.php
// @match        https://test.iqrpg.com/game.php
// @require      http://code.jquery.com/jquery-latest.js
// @grant        GM_addStyle
// ==/UserScript==

//TODO add persistant storage between browser sessions
//TODO const track_abyss_battles = false; // to track abyss battles or not

///////////////////////////////////
/////////// config ////////////////
///////////////////////////////////

const track_boss_battles = false; // true or false
const track_clan_battles = false; // true or false

//////////////////////////////////////////////////////////////////
/////////// Don't change anything below this line ////////////////
//////////////////////////////////////////////////////////////////

/* globals jQuery, $ */

// init
var player_stats = { dmg:0, hits:0, misses:0 }; //TODO update from local storage
var enemy_stats = { dmg:0, hits:0, misses:0, dodges:0 }; //TODO update from local storage
var player_cache = '';
var enemy_cache = '';

// run every xxx ms updating stuffs
setInterval(iqrpgbs_loop, 100);

// main loop
function iqrpgbs_loop() {

    var we_battling = false;
    var display_needs_update = false;

    // check we're on the battle page
    if(document.getElementsByClassName("battle-container").length > 0) we_battling = true;

    // and not in a boss battle - Boss Tokens
    if(track_boss_battles!==true) {
        if($("div.game-grid > div.main-game-section > div.main-section__body:contains('Boss Tokens')").length > 0) {
            //console.log("skipping boss fight");
            return false;
        }
    }

    // and not in a dragon battle or clan battle - Clan Exp
    if(track_clan_battles!==true) {
        if($("div.game-grid > div.main-game-section > div.main-section__body:contains('Clan Exp')").length > 0) {
            //console.log("skipping clan fight");
            return false;
        }
    }

    // all good
    if(we_battling === true) {

        // Add the battle stat panel to dom, if not already there
        if(!document.getElementById("iqrpgbs_bs_panel")) {
            var iqrpg_body = $( "div.game-grid > div.main-game-section > div.main-section__body" );
            iqrpg_body[0].children[0].children[0].insertAdjacentHTML('beforeend', render_battle_stats_panel() );
            document.getElementById('igrpg_bs_reset').addEventListener('click', iqrpg_bs_reset_stats, false);
        }

        // get the players stat line & compare it to previous stored stats
        var player_sl = $("div.game-grid > div.main-game-section > div.main-section__body > div > div > div > div:nth-child(2)");
        if(player_sl.prop('innerHTML') !== player_cache) {
            player_cache = player_sl.prop('innerHTML');
            parse_player_stat_line(player_sl);
            display_needs_update = true;
        }

        // get the mobs stat line & compare it to previous stored stats
        var mobs_sl = $("div.game-grid > div.main-game-section > div.main-section__body > div > div > div > div:nth-child(3)");
        if(mobs_sl.prop('innerHTML') !== enemy_cache) {
            enemy_cache = mobs_sl.prop('innerHTML');
            parse_enemy_stat_line(mobs_sl);
            display_needs_update = true;
        }

        // update displayed values
        if(display_needs_update === true) {
            update_display();
        }

    }
}

function parse_player_stat_line(player_sl) {
    var hits = player_sl.find("p:nth-child(1) > span:nth-child(2)");
    if(hits.length > 0) {
        var actual_hits = hits.prop('innerHTML').replaceAll(" time(s)", "");
        player_stats.hits += parseInt(actual_hits);
    }
    var dmg = player_sl.find("p:nth-child(1) > span:nth-child(3)");
    if(dmg.length > 0 && hits.length > 0) {
        var actual_dmg = dmg.prop('innerHTML').replaceAll(" damage", "").replaceAll(",", "");
        player_stats.dmg += parseInt(actual_dmg) * parseInt(actual_hits);
    }
    var misses = player_sl.find("p:nth-child(2) > span:nth-child(1)");
    if(misses.length > 0) {
        var actual_misses = misses.prop('innerHTML').replaceAll(" time(s)", "");
        player_stats.misses += parseInt(actual_misses);
    }
}

function parse_enemy_stat_line(stat_line) {
    var hits = stat_line.find("p:nth-child(1) > span:nth-child(2)");
    if(hits.length > 0) {
        var actual_hits = hits.prop('innerHTML').replaceAll(" time(s)", "");
        enemy_stats.hits += parseInt(actual_hits);
    }
    var dmg = stat_line.find("p:nth-child(1) > span:nth-child(3)");
    if(dmg.length > 0 && hits.length > 0) {
        var actual_dmg = dmg.prop('innerHTML').replaceAll(" damage", "").replaceAll(",", "");
        enemy_stats.dmg += parseInt(actual_dmg) * parseInt(actual_hits);
    }
    var misses = stat_line.find("p:nth-child(2) > span:nth-child(2)");
    if(misses.length > 0) {
        var actual_misses = misses.prop('innerHTML').replaceAll(" time(s)", "");
        enemy_stats.misses += parseInt(actual_misses);
    }
    var dodges = stat_line.find("p:nth-child(2) > span:nth-child(3)");
    if(dodges.length > 0) {
        var actual_dodges = dodges.prop('innerHTML').replaceAll(" attack(s)", "");
        enemy_stats.dodges += parseInt(actual_dodges);
    }
    //console.log("hits :: "+hits);
    //console.log("misses :: "+actual_misses);
    //console.log(actual_dodges);
}

function iqrpg_bs_reset_stats() {
    player_stats.dmg = 0;
    player_stats.hits = 0;
    player_stats.misses = 0;
    enemy_stats.dmg = 0;
    enemy_stats.hits = 0;
    enemy_stats.misses = 0;
    enemy_stats.dodges = 0;
    update_display();
}

function update_display() {
    // players
    $("#iqrpgbs_pl_dmg").html(new Intl.NumberFormat().format(player_stats.dmg));
    $("#iqrpgbs_pl_hits").html(new Intl.NumberFormat().format(player_stats.hits));
    var avg = Math.round(player_stats.dmg / player_stats.hits);
    if(isNaN(avg)) avg = 0;
    $("#iqrpgbs_pl_avg").html(new Intl.NumberFormat().format(avg));
    var acc = (player_stats.hits / (player_stats.hits + player_stats.misses))*100;
    if(isNaN(acc)) acc = 0;
    $("#iqrpgbs_pl_acc").html(new Intl.NumberFormat().format(acc.toFixed(2)));
    // enemy
    var enemy_avg = Math.round(enemy_stats.dmg / enemy_stats.hits);
    if(isNaN(enemy_avg)) enemy_avg = 0;
    $("#iqrpgbs_enmy_avg").html(new Intl.NumberFormat().format(enemy_avg));
    var enemy_acc = ( (enemy_stats.hits + enemy_stats.dodges) / (enemy_stats.hits + enemy_stats.misses + enemy_stats.dodges))*100;
    if(isNaN(enemy_acc)) enemy_acc = 0;
    $("#iqrpgbs_enmy_acc").html(new Intl.NumberFormat().format(enemy_acc.toFixed(2)));
    var enemy_dodges = (enemy_stats.dodges / (enemy_stats.hits /*+ enemy_stats.misses*/ + enemy_stats.dodges))*100;
    if(isNaN(enemy_dodges)) enemy_dodges = 0;
    $("#iqrpgbs_enmy_dodges").html(new Intl.NumberFormat().format(enemy_dodges.toFixed(2)));
}

function render_battle_stats_panel() {
    var content = `
<div id="iqrpgbs_bs_panel" class="margin-top-large">
<div>Battle Stats <span>by Coastis</span></div>
<div>You dealt a total of <span id="iqrpgbs_pl_dmg">0</span> damage in <span id="iqrpgbs_pl_hits">0</span> hits,
with an average of <span id="iqrpgbs_pl_avg">0</span> per hit and <span id="iqrpgbs_pl_acc">0</span>% accuracy</div>
<div>Enemy dealt an average of <span id="iqrpgbs_enmy_avg">0</span> per hit
with an accuracy of <span id="iqrpgbs_enmy_acc">0</span>%, and you dodged <span id="iqrpgbs_enmy_dodges">0</span>% of attacks</div>
<div>[<a href=#" id="igrpg_bs_reset">Reset Battle Stats</a>]</div>
</div>
`;
    return content;
}

GM_addStyle ( `
    div#iqrpgbs_bs_panel div { text-align:center;padding:1px;}
    div#iqrpgbs_bs_panel div:nth-child(1) { font-weight:bold;}
    div#iqrpgbs_bs_panel div:nth-child(1) span { font-size:8px;font-weight:normal;}
` );