OutcomeDB

Captures crime outcome & skill gain for analysis

目前为 2024-04-24 提交的版本。查看 最新版本

// ==UserScript==
// @name         OutcomeDB
// @namespace    de.sabbasofa.outcomedb
// @version      1.3.2
// @description  Captures crime outcome & skill gain for analysis
// @author       Hemicopter [2780600], Lazerpent [2112641]
// @match        https://www.torn.com/loader.php?sid=crimes*
// @match        https://torn.com/loader.php?sid=crimes*
// @grant        GM_xmlhttpRequest
// @connect      api.lzpt.io

// ==/UserScript==

(function () {
    'use strict';

    const isTampermonkeyEnabled = typeof unsafeWindow !== 'undefined';
    const win = isTampermonkeyEnabled ? unsafeWindow : window;
    const {fetch: originalFetch} = win;

    win.fetch = async (...args) => {
        let [resource, config] = args;
        return originalFetch(resource, config).then(response => handleFetchResponse(resource, response));
    };
    console.log("[OutcomeDB] Watching for crime.");

    function handleFetchResponse(resource, response) {
        if (!(resource.includes("sid=crimesData") && resource.includes("step=attempt"))) return response;
        console.log("[OutcomeDB] Found crime attempt.");
        console.log("[OutcomeDB] url:", resource);
        response.clone().text().then(body => handleCrimeAttempt(body, resource));
        console.log("[OutcomeDB] End of crime attempt.");
        return response;
    }

    function handleCrimeAttempt(body, resource) {
        try {
            let data = JSON.parse(body);
            if (data.error) {
                console.log("[OutcomeDB] Failed crime attempt: " + data.error);
                console.log(JSON.stringify(data));
                return;
            }
            if (!(data.DB && data.DB.outcome)) return;
            if(data.DB.outcome.result === "error") {
                console.log("[OutcomeDB] Failed crime attempt.");
                console.log(JSON.stringify(data));
                return;
            }
            console.log("[OutcomeDB] Found outcome.");
            console.log("[OutcomeDB] Preparing bundle.");
            let bundle = {};
            bundle.outcome = data.DB.outcome;
            bundle.typeID = resource.split("typeID=")[1].split("&")[0];
            bundle.crimeID = resource.split("crimeID=")[1].split("&")[0];

            bundle.skillBefore = getStat("Skill");
            bundle.skillAfter = data.DB.currentUserStatistics[0].value;
            bundle.progressionBonus = getStat("Progression bonus");

            console.log("[OutcomeDB] Ready to send bundle.", bundle);
            sendBundleToAPI(bundle);

        } catch (e) {
            console.error("[OutcomeDB] Error parsing data:", body, e);
            alert("OutcomeDB error #68. Please check console and report this to Lazerpent [2112641] or Hemicopter [2780600].");
        }
    }

    function sendBundleToAPI(bundle) {
        GM_xmlhttpRequest({
            method: "POST",
            url: "https://api.lzpt.io/outcomedb",
            headers: {"Content-Type": "application/json"},
            data: JSON.stringify(bundle),
            onload: function (response) {
                if(!response) return; // because pda doesn't know how to network i guess
                console.log("[OutcomeDB] Bundle successfully sent to API:", response.responseText);

                const json = JSON.parse(response.responseText);
                if (json.error) {
                    alert("OutcomeDB error #84. Please check console and report this to Lazerpent [2112641] or Hemicopter [2780600]: " + response.responseText);
                }
            },
            onerror: function (error) {
                console.error("[OutcomeDB] Error sending bundle to API:", error);
                alert("OutcomeDB error #89. Please check console and report this to Lazerpent [2112641] or Hemicopter [2780600]: " + error);
            }
        });
    }

    function getStat(name) {
        let allStatisticButtons = Array.from(win.document.querySelectorAll('button[class^="statistic___"]'));

        let statButton = allStatisticButtons.find(button => {
            return Array.from(button.querySelectorAll('span')).some(span => span.textContent.trim() === name);
        });

        if (statButton) {
            let valueSpan = statButton.querySelector('span[class^="value___"]');
            if (valueSpan) {
                console.log(`[OutcomeDB] Found stat (${name}): '${valueSpan.textContent}'`);
                return valueSpan.textContent;
            }
        }
        console.error(`[OutcomeDB] Could not find stat ${name}`);
    }
})();