您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Displays TornStats spied stats below the "Start Fight" button
当前为
// ==UserScript== // @name Torn City - Display Spies on the Attack Screen // @description Displays TornStats spied stats below the "Start Fight" button // @namespace https://www.torn.com/profiles.php?XID=2834135#/ // @version 1.0 // @author echotte [2834135] // @match https://www.torn.com/loader.php?sid=attack* // @grant GM_xmlhttpRequest // @connect www.tornstats.com // @license MIT // ==/UserScript== (function attack() { 'use strict'; let api = "API_KEY_HERE"; let url = window.location.href; if(url.includes("sid=attack")) { url = new URL(url); let attackId = url.searchParams.get("user2ID"); 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"]; let enemystats = {}; var enemydata, companydata, spydata, owndata; var jobstr, statstr, footerstr, 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(response => { return response.json(); })); }).then(data => { enemydata = data[0]; owndata = data[1]; if (attackId in bsCache) { 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; } } ff = "ff" in bsCache[attackId] ? ff = bsCache[attackId].ff : 0; // cache found, display stats from cache 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 { // no cache found, display personalstats statstr = `<br />Xan: <b><font color='${owndata.personalstats.xantaken<enemydata.personalstats.xantaken ? colorred : colorgreen}'>${parseInt(enemydata.personalstats.xantaken) || 0}</font></b> 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> SE: <strong><font color='${owndata.personalstats.statenhancersused<enemydata.personalstats.statenhancersused ? colorred : colorgreen}'>${parseInt(enemydata.personalstats.statenhancersused) || 0}</font></strong> <br />`; } // assemble job and current status 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; jobstr = `${companydata.company.rating}* ${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>`; updateText(statstr + footerstr); }); } // Call TornStats, update localSystem cache if results found GM_xmlhttpRequest({ method: "GET", url: `https://www.tornstats.com/api/v1/${api}/spy/${attackId}`, onload: (r) => { spydata = JSON.parse(r.responseText); 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; } } // new and updated battlestats 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 />`; 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; } 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或关注我们的公众号极客氢云获取最新地址