Torn - Display Stats on Attack Screen

Get TornStats spies or personal stats information on the attack page.

当前为 2024-01-24 提交的版本,查看 最新版本

// ==UserScript==
// @name         Torn - Display Stats on Attack Screen
// @namespace    https://www.torn.com/profiles.php?XID=2834135#/
// @version      1.0
// @description  Get TornStats spies or personal stats information on the attack page.
// @author       echotte [2834135]
// @match        https://www.torn.com/loader.php*
// @grant        GM_xmlhttpRequest
// @connect      www.tornstats.com
// @license      MIT
// ==/UserScript==




(function attack() {
    'use strict';

    let api = "API_KEY_GOES_HERE";
    let url = window.location.href;

    var colorgreen = "#98FB98";
    var colorred = "#EE4B2B";

    let bsCache = localStorage["finally.torn.bs"] !== undefined ? JSONparse(localStorage["finally.torn.bs"]) : {};
    let stats = [0, 0, 0, 0, 0];
    let units = ["K", "M", "B", "T", "Q"];

    //bsCache = {};

    let enemystats = {};

    if(url.includes("sid=attack"))
    {
        url = new URL(url);
        let attackId = url.searchParams.get("user2ID");

        var enemydata, companydata, spydata, owndata;

        var jobstr = "";
        var statstr = "default";
        var footerstr = "";
        var ff;

        Promise.all([
            fetch(`https://api.torn.com/user/${attackId}?selections=profile,personalstats&key=${api}&comment=attack_stats`),
            fetch(`https://api.torn.com/user/?selections=battlestats,profile,personalstats&key=${api}&comment=attack_stats`)
        ]).then(responses => {
            return Promise.all(responses.map(function (response) {
                return response.json();
            }));
        }).then(function (data) {

            enemydata = data[0];
            owndata = data[1];

            if (attackId in bsCache) {

                console.log("Exisitng ID found");
                stats[0] = bsCache[attackId].total;
                stats[1] = bsCache[attackId].strength;
                stats[2] = bsCache[attackId].defense;
                stats[3] = bsCache[attackId].speed;
                stats[4] = bsCache[attackId].dexterity;

                for (let i = 0; i < stats.length; i++) {
                    let stat = Number.parseInt(stats[i]);
                    if (Number.isNaN(stat) || stat == 0) continue;
                    let originalStat = stat;

                    for (let j = 0; j < units.length; j++) {
                        stat = stat / 1000;
                        if (stat > 1000) continue;

                        stat = stat.toFixed(i == 0 ? (stat >= 100 ? 0 : 1) : 2);
                        stats[i] = `${stat}${units[j]}`;
                        break;
                    }
                }


                if ("ff" in bsCache[attackId]) { 
                    ff = bsCache[attackId].ff;
                } else {
                    ff = 0;
                }

                statstr = (`<br />TOTAL STATS: <strong><font color='${bsCache[attackId].total > owndata.total ? colorred : colorgreen}'>${stats[0]}</font></strong><br />`) +
                        (bsCache[attackId].strength>0 ? `STR: <font color='${bsCache[attackId].strength > owndata.strength ? colorred : colorgreen}'>${stats[1]}</font><br />` : "") +
                        (bsCache[attackId].defense>0 ? `DEF: <font color='${bsCache[attackId].defense > owndata.defense ? colorred : colorgreen}'>${stats[2]}</font><br />` : "") +
                        (bsCache[attackId].speed>0 ? `SPD: <font color='${bsCache[attackId].speed > owndata.speed ? colorred : colorgreen}'>${stats[3]}</font><br />` : "") +
                        (bsCache[attackId].dexterity>0 ? `DEX: <font color='${bsCache[attackId].dexterity > owndata.dexterity ? colorred : colorgreen}'>${stats[4]}</font><br />` : "") +
                        `<br />Fair Fight: <strong><font color='${ff<2 ? colorred : colorgreen}'>${ff.toFixed(2)}</font></strong><br />`;


            } else {   
                console.log("Exisitng ID not found");
                
                statstr = `<br />Xan: <b><font color='${owndata.personalstats.xantaken<enemydata.personalstats.xantaken ? colorred : colorgreen}'>${parseInt(enemydata.personalstats.xantaken) || 0}</font></b>    
                    &nbsp;&nbsp;&nbsp;  
                    Refills: <strong><font color='${owndata.personalstats.refills<enemydata.personalstats.refills ? colorred : colorgreen}'>${parseInt(enemydata.personalstats.refills) || 0}</font></strong>
                    <br />Cans: <strong><font color='${owndata.personalstats.energydrinkused<enemydata.personalstats.energydrinkused ? colorred : colorgreen}'>${parseInt(enemydata.personalstats.energydrinkused) || 0}</font></strong>   
                    &nbsp;&nbsp;&nbsp;   
                    SE: <strong><font color='${owndata.personalstats.statenhancersused<enemydata.personalstats.statenhancersused ? colorred : colorgreen}'>${parseInt(enemydata.personalstats.statenhancersused) || 0}</font></strong>
                    <br />`;
            }


            jobstr = enemydata.job.company_type==0 ? enemydata.job.job : companies[enemydata.job.company_type];
            footerstr = `<br />Last action: <strong>${enemydata.last_action.relative}</strong>
            <br />
            <br />Faction: <strong>${enemydata.faction.faction_name}</strong>
            <br />Job: <strong>${jobstr}</strong>`;

            addButton(statstr + footerstr);

            // get stars of the company job
            
            if (enemydata.job.company_type!=0) {
                fetch(`https://api.torn.com/company/${enemydata.job.company_id}?selections=profile&key=${api}`)
                .then(function (response) {
                    // Get a JSON object from the response
                    return response.json();
                }).then(function (data) {
                    // Cache the data to a variable
                    companydata = data;

                    let companystars = companydata.company.rating;
                    let companytype = enemydata.job.company_type;
                    jobstr = `${companystars}* ${companies[companytype]}`;

                    footerstr = `<br />Last action: <strong>${enemydata.last_action.relative}</strong>
                        <br />
                        <br />Faction: <strong>${enemydata.faction.faction_name}</strong>
                        <br />Job: <strong>${jobstr}</strong>`;

                    updateText(statstr + footerstr);
                });
            }

                // === next feature --- update cache with spy data, if exists. 
                
                GM_xmlhttpRequest({
                    method: "GET",
                    url: `https://www.tornstats.com/api/v1/${api}/spy/${attackId}`,
                    onload: (r) => {
                        spydata = JSON.parse(r.responseText);

                        // Now that you have both APIs back, you can do something with the data
                        // assemble stats information
                        if (spydata.spy.status == true) {

                            enemystats = {
                                total       : spydata.spy.total,
                                strength    : spydata.spy.strength,
                                defense     : spydata.spy.defense,
                                speed       : spydata.spy.speed,
                                dexterity   : spydata.spy.dexterity,
                                ff          : spydata.spy.fair_fight_bonus,
                                timestamp   :  spydata.spy.timestamp,
                            };

                            bsCache[attackId] = enemystats;

                            stats[0] = spydata.spy.total;
                            stats[1] = spydata.spy.strength;
                            stats[2] = spydata.spy.defense;
                            stats[3] = spydata.spy.speed;
                            stats[4] = spydata.spy.dexterity;
            
                            for (let i = 0; i < stats.length; i++) {
                                let stat = Number.parseInt(stats[i]);
                                if (Number.isNaN(stat) || stat == 0) continue;
                                let originalStat = stat;
            
                                for (let j = 0; j < units.length; j++) {
                                    stat = stat / 1000;
                                    if (stat > 1000) continue;
            
                                    stat = stat.toFixed(i == 0 ? (stat >= 100 ? 0 : 1) : 2);
                                    stats[i] = `${stat}${units[j]}`;
                                    break;
                                }
                            }
            
                            statstr = `<br /> TOTAL STATS: <strong><font color='${spydata.spy.deltaTotal<0 ? colorred : colorgreen}'>${stats[0]}</font></strong><br />` +
                                (stats[1]!="N/A" ? `STR: <font color='${spydata.spy.deltaStrength<0 ? colorred : colorgreen}'>${stats[1]}</font><br />` : "") +
                                (stats[2]!="N/A" ? `DEF: <font color='${spydata.spy.deltaDefense<0 ? colorred : colorgreen}'>${stats[2]}</font><br />` : "") +
                                (stats[3]!="N/A" ? `SPD: <font color='${spydata.spy.deltaSpeed<0 ? colorred : colorgreen}'>${stats[3]}</font><br />` : "") +
                                (stats[4]!="N/A" ? `DEX: <font color='${spydata.spy.deltaDexterity<0 ? colorred : colorgreen}'>${stats[4]}</font><br />` : "") +
                                `<br />Fair Fight: <strong><font color='${spydata.spy.fair_fight_bonus<2 ? colorred : colorgreen}'>${spydata.spy.fair_fight_bonus.toFixed(2)}</font></strong><br />`;

                            console.log("Finished with spy scenario - " + statstr);

                            updateText(statstr + footerstr);

                            localStorage.setItem("finally.torn.bs", JSON.stringify(bsCache));
                        }
                    }
                });
    
            }).catch(function (error) {
                // if there's an error, log it
                alert(error);
                console.log(error);
            });
    }
})();

function addButton(newmsg) {
    let joinBtn = $("button:contains(\"Start fight\"), button:contains(\"Join fight\")").closest("button");
    if($(joinBtn).length) {
        $(joinBtn).after(`<div id='attackInfo'> ` + newmsg + `</div>`);
    }
}

function updateText(newmsg) {
    $("#attackInfo").html(newmsg);
}

function JSONparse(str) {
    try {
        return JSON.parse(str);
    } catch (e) { }
    return null;
}


function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

const companies = {
    1: "Hair Salon",
    2: "Law Firm",
    3: "Flower Shop",
    4: "Car Dealership",
    5: "Clothing Store",
    6: "Gun Shop",
    7: "Game Shop",
    8: "Candle Shop",
    9: "Toy Shop",
    10: "Adult Novelties",
    11: "Cyber Cafe",
    12: "Grocery Store",
    13: "Theater",
    14: "Sweet Shop",
    15: "Cruise Line",
    16: "Television Network",
    17: "",
    18: "Zoo",
    19: "Firework Stand",
    20: "Property Broker",
    21: "Furniture Store",
    22: "Gas Station",
    23: "Music Store",
    24: "Nightclub",
    25: "Pub",
    26: "Gents Strip Club",
    27: "Restaurant",
    28: "Oil Rig",
    29: "Fitness Center",
    30: "Mechanic Shop",
    31: "Amusement Park",
    32: "Lingerie Store",
    33: "Meat Warehouse",
    34: "Farm",
    35: "Software Corporation",
    36: "Ladies Strip Club",
    37: "Private Security Firm",
    38: "Mining Corporation",
    39: "Detective Agency",
    40: "Logistics Management",
};

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址