您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add NPC attack time to the news ticker using Loot Rangers for Torn
- // ==UserScript==
- // @name Torn NPC Attack Time Newsfeed
- // @namespace npc.timing
- // @version v1.1.5
- // @description Add NPC attack time to the news ticker using Loot Rangers for Torn
- // @author IceBlueFire [776]
- // @license MIT
- // @match https://www.torn.com/*
- // @exclude https://www.torn.com/newspaper.php
- // @exclude https://www.torn.com/item.php
- // @icon https://www.google.com/s2/favicons?sz=64&domain=torn.com
- // @grant unsafeWindow
- // @grant GM_xmlhttpRequest
- // @require https://code.jquery.com/jquery-1.8.2.min.js
- // @connect api.lzpt.io
- // ==/UserScript==
- /******************** CONFIG SETTINGS ********************/
- const color = "#8abeef"; // Any hex-code for the color to appear in the news feed as
- const format = 24; // Time format. 12 = 12:00 AM format; 24 = 23:59 format
- const local = false; // Adjust the timer to be local time or not. true = local; false = UTC
- /****************** END CONFIG SETTINGS *******************/
- const lzpt = getAttackTimes();
- const { fetch: originalFetch } = unsafeWindow;
- unsafeWindow.fetch = async (...args) => {
- var [resource, config] = args;
- var response = await originalFetch(resource, config);
- if(response.url.indexOf('?sid=newsTicker') === -1) return response;
- const json = () => response.clone().json()
- .then((data) => {
- data = { ...data };
- lzpt.then(function(result) {
- var attackOrder = '';
- var attackString = '';
- var attackLink = '';
- var attackTarget = 0;
- // If there's no clear time set
- if(result.time.clear == 0 && result.time.attack === false) {
- attackString = result.time.reason ? 'NPC attacking will resume after '+result.time.reason : 'No attack currently set.';
- } else {
- // Build the string for the attack order
- $.each(result.order, function(key, value) {
- if(result.npcs[value].next){
- // If there's an attack happening right now, cross out NPCs that are in the hospital
- if(result.time.attack === true) {
- if(result.npcs[value].hosp_out >= result.time.current) {
- attackOrder += '<span style="text-decoration: line-through">'+result.npcs[value].name+'</span>, ';
- } else {
- attackOrder += result.npcs[value].name+', ';
- }
- } else {
- attackOrder += result.npcs[value].name+', ';
- }
- }
- // Adjust the current target based on if an attack is going and who isn't in the hospital yet
- if(result.time.attack === true) {
- if(result.npcs[value].hosp_out <= result.time.current) { // Check if the NPC is currently out of the hospital
- if(attackTarget == 0) {
- attackTarget = value;
- }
- }
- }
- });
- // Check if target has been set, otherwise default to first in attack order
- if(attackTarget == 0) {
- attackTarget = result.order[0];
- }
- // Clean up the attack order string
- attackOrder = attackOrder.slice(0, -2)+'.';
- // Check if an attack is currently happening and adjust the message accordingly
- if(result.time.attack === true) {
- attackString = 'NPC attack is underway! Get in there and get some loot!';
- attackLink = 'loader.php?sid=attack&user2ID='+attackTarget;
- } else {
- attackString = 'NPC attack set for '+utcformat(result.time.clear)+'. Order is: '+attackOrder;
- attackLink = 'loader.php?sid=attack&user2ID='+attackTarget;
- }
- }
- // Insert the custom news item into the news ticker
- let attackItem = {ID: 0, headline: '<span style="color:'+color+'; font-weight: bold;" id="icey-npctimer">'+attackString+'</span>', countdown: true, endTime: result.time.clear, link: attackLink, isGlobal: true, type: 'generalMessage'};
- data.headlines.unshift(attackItem);
- }, function(err) {
- console.log(err); // Error: "It broke"
- });
- return data
- })
- response.json = json;
- response.text = async () =>JSON.stringify(await json());
- return response;
- };
- function modifyContent() {
- return new Promise((resolve, reject) => {
- var ticker = document.querySelector('.news-ticker-countdown');
- ticker.style.color = color;
- var wrap = ticker.parentNode.parentNode.parentNode;
- var svg = wrap.children[0];
- svg.setAttribute('fill', color);
- svg.setAttribute('viewBox', "0 0 24 24");
- svg.setAttribute('height', '14');
- svg.setAttribute('width', '14');
- svg.children[0].setAttribute('d', 'M17.457 3L21 3.003l.002 3.523-5.467 5.466 2.828 2.829 1.415-1.414 1.414 1.414-2.474 2.475 2.828 2.829-1.414 1.414-2.829-2.829-2.475 2.475-1.414-1.414 1.414-1.415-2.829-2.828-2.828 2.828 1.415 1.415-1.414 1.414-2.475-2.475-2.829 2.829-1.414-1.414 2.829-2.83-2.475-2.474 1.414-1.414 1.414 1.413 2.827-2.828-5.46-5.46L3 3l3.546.003 5.453 5.454L17.457 3zm-7.58 10.406L7.05 16.234l.708.707 2.827-2.828-.707-.707zm9.124-8.405h-.717l-4.87 4.869.706.707 4.881-4.879v-.697zm-14 0v.7l11.241 11.241.707-.707L5.716 5.002l-.715-.001z');
- // console.log(svg);
- resolve('Content updated');
- });
- }
- const newstickerObserver = new MutationObserver((mutationsList, observer) => {
- if ($(".news-ticker-slide #icey-npctimer").length == 1) { // If it's showing the slide for NPCs
- // Once changes are observed, disconnect the observer to avoid infinite loop
- newstickerObserver.disconnect();
- // Modify the content of .news-ticker-wrapper
- modifyContent()
- .then(() => {
- // Re-observe the element after modifications and asynchronous operations are complete
- startNewstickerObserver();
- })
- .catch(error => console.error('Error updating content:', error));
- }
- });
- function startNewstickerObserver() {
- const target = document.querySelector('.news-ticker-slider-wrapper');
- if (target) {
- newstickerObserver.observe(target, {
- childList: true, // Set true if children of the target node are being added or removed.
- attributes: false, // Set true if attributes of the target node are being modified.
- subtree: true, // Set true if changes to descendants of the target node are to be observed.
- characterData: false // Set true if data of the target node itself is being modified.
- });
- }
- }
- /******************** HELPER FUNCTIONS ********************/
- function waitForElm(selector) {
- return new Promise(resolve => {
- if (document.querySelector(selector)) {
- return resolve(document.querySelector(selector));
- }
- const observer = new MutationObserver(mutations => {
- if (document.querySelector(selector)) {
- observer.disconnect();
- resolve(document.querySelector(selector));
- }
- });
- // If you get "parameter 1 is not of type 'Node'" error, see https://stackoverflow.com/a/77855838/492336
- observer.observe(document.body, {
- childList: true,
- subtree: true
- });
- });
- }
- // Make sure the news ticker with the injected div is loaded
- waitForElm('#icey-npctimer').then((elm) => {
- startNewstickerObserver();
- //console.log('Element is ready');
- });
- // Format the time in the appropriate fashion
- function utcformat(d){
- d= new Date(d * 1000);
- if(local) {
- var tail= ' LT', D= [d.getFullYear(), d.getMonth()+1, d.getDate()],
- T= [d.getHours(), d.getMinutes(), d.getSeconds()];
- } else {
- var tail= ' TCT', D= [d.getUTCFullYear(), d.getUTCMonth()+1, d.getUTCDate()],
- T= [d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds()];
- }
- if(format == 12) {
- /* 12 hour format */
- if(+T[0]> 12){
- T[0]-= 12;
- tail= 'PM '+tail;
- }
- else tail= 'AM '+tail;
- }
- var i= 3;
- while(i){
- --i;
- if(D[i]<10) D[i]= '0'+D[i];
- if(T[i]<10) T[i]= '0'+T[i];
- }
- return T.join(':')+ tail;
- }
- // Fetch the NPC details from Loot Rangers
- async function getAttackTimes() {
- return new Promise(resolve => {
- const request_url = `https://api.lzpt.io/loot`;
- GM_xmlhttpRequest ({
- method: "GET",
- url: request_url,
- headers: {
- "Content-Type": "application/json"
- },
- onload: response => {
- try {
- const data = JSON.parse(response.responseText);
- if(!data) {
- console.log('No response from Loot Rangers');
- } else {
- return resolve(data)
- }
- }
- catch (e) {
- console.error(e);
- }
- },
- onerror: (e) => {
- console.error(e);
- }
- })
- });
- }