您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a toggle-able side bar to estimate War End for a given faction.
// ==UserScript== // @name War End // @version Alpha1.4 // @namespace https://greasyfork.org/ // @description Adds a toggle-able side bar to estimate War End for a given faction. // @author Gravity0000 // @supportURL https://www.torn.com/profiles.php?XID=2131364 // @license MIT // @match https://www.torn.com/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @connect api.torn.com // ==/UserScript== (function () { 'use strict'; const styleTag = document.createElement('style'); document.head.appendChild(styleTag); const isDarkMode = document.body.classList.contains('dark-mode'); let placeholderColor = isDarkMode ? '#bbbbbb' : '#555555'; function updatePlaceholderStyle() { styleTag.textContent = ` .inputBox::placeholder, .apiBox::placeholder, .leadBox::placeholder { color: ${placeholderColor} !important; } `; } function applyThemeColors(isDark) { const textColor = isDark ? 'white' : 'black'; const bgColor = isDark ? 'black' : 'white'; const containerBg = isDark ? '#A9A9A9' : '#D3D3D3'; const buttonBg = isDark ? '#009407' : '#98f59b'; const borderColor = isDark ? 'white' : 'black'; [apiBox, infoBox, textBox, leadBox, toggleButton, updateButton].forEach(el => { el.style.color = textColor; }); [apiBox, infoBox, textBox, leadBox].forEach(el => { el.style.backgroundColor = bgColor; }); [toggleButton, updateButton].forEach(el => { el.style.border = `1px solid ${borderColor}`; el.style.backgroundColor = buttonBg; }); container.style.backgroundColor = containerBg; placeholderColor = isDark ? '#FFFFFF' : '#000000'; updatePlaceholderStyle(); } const container = document.createElement('div'); container.id = 'myScriptContainer'; container.style.display = 'none'; document.body.appendChild(container); const apiBox = document.createElement('input'); apiBox.type = 'text'; apiBox.id = 'myAPIBox'; apiBox.placeholder = 'Enter API Here'; container.appendChild(apiBox); const infoBox = document.createElement('div'); infoBox.id = 'myInfoBox'; infoBox.innerHTML = 'Initial Info'; container.appendChild(infoBox); const textBox = document.createElement('input'); textBox.type = 'number'; textBox.id = 'myTextBox'; textBox.placeholder = 'Faction ID or Blank.'; container.appendChild(textBox); const leadBox = document.createElement('input'); leadBox.type = 'number'; leadBox.id = 'myLeadBox'; leadBox.placeholder = 'Est. Lead or Blank.'; container.appendChild(leadBox); [textBox, leadBox].forEach(box => { box.addEventListener('keypress', event => { const key = event.keyCode || event.which; if (!((key >= 48 && key <= 57) || key === 8)) event.preventDefault(); }); }); const toggleButton = document.createElement('button'); toggleButton.innerText = 'WarEnd'; toggleButton.id = 'myToggleButton'; Object.assign(toggleButton.style, { position: 'fixed', top: '65%', right: '0%', zIndex: '9999', cursor: 'pointer' }); document.body.appendChild(toggleButton); toggleButton.addEventListener('click', () => { container.style.display = container.style.display === 'none' ? '' : 'none'; }); const savedAPI = localStorage.getItem('savedAPIValue'); if (savedAPI) apiBox.value = savedAPI; const savedFaction = localStorage.getItem('savedFactionValue'); if (savedFaction) textBox.value = savedFaction; const savedLead = localStorage.getItem('savedLeadValue'); if (savedLead) leadBox.value = savedLead; const updateButton = document.createElement('button'); updateButton.id = 'myUpdateButton'; updateButton.textContent = 'Update'; container.appendChild(updateButton); [textBox, apiBox, leadBox].forEach((el, i) => el.classList.add(['inputBox', 'apiBox', 'leadBox'][i])); applyThemeColors(isDarkMode); const observer = new MutationObserver(() => { applyThemeColors(document.body.classList.contains('dark-mode')); }); observer.observe(document.body, { attributes: true, attributeFilter: ['class'] }); updateButton.addEventListener('click', () => { const faction_id = textBox.value; const apiKey = apiBox.value; localStorage.setItem('savedAPIValue', apiKey); localStorage.setItem('savedFactionValue', faction_id); localStorage.setItem('savedLeadValue', leadBox.value); GM_xmlhttpRequest({ method: 'GET', url: `https://api.torn.com/v2/faction/${faction_id}/wars/?selections=basic&key=${apiKey}&comment=warend`, onload: response => { if (response.status !== 200) { infoBox.innerHTML = 'ERROR'; return; } const data = JSON.parse(response.responseText); if (data.error?.code === 2) { infoBox.innerHTML = 'Invalid API Key'; return; } if (!data.wars || !data.wars.ranked) { infoBox.innerHTML = 'Invalid Waring Faction ID'; return; } const start = data.wars.ranked.start; const now = Date.now(); const [f1, f2] = data.wars.ranked.factions; const diff = Math.abs(f1.score - f2.score); const target = data.wars.ranked.target; const passedMs = Math.abs(now - (start * 1000)); const hoursPassed = Math.floor(passedMs / (1000 * 60 * 60)); let onePercent = hoursPassed < 24 ? target / 100 : Math.round(target / (100 - (hoursPassed - 24))); let newLead = parseInt(leadBox.value, 10); let remaining = (leadBox.value && newLead > 0 && newLead <= target) ? target - newLead : target - diff; if (leadBox.value && (newLead > target || newLead <= 0)) { infoBox.innerHTML = `Error Max lead = ${target}`; return; } let hrsLeft = 0; while (remaining > 0) { remaining -= onePercent; hrsLeft++; } let minLeft = 0; if (!data.wars.ranked.end) { minLeft = Math.floor(60 - ((passedMs / (1000 * 60)) - (hoursPassed * 60))); } if (hrsLeft < 24) { infoBox.innerHTML = `${hrsLeft}H ${minLeft}M<br>Until WarEnd.`; } else { const daysLeft = Math.floor(hrsLeft / 24); hrsLeft %= 24; infoBox.innerHTML = `${daysLeft}D ${hrsLeft}H ${minLeft}M<br>Until WarEnd.`; } }, onerror: err => { console.error('Network Error:', err); infoBox.innerHTML = 'NETWORK ERROR'; } }); }); GM_addStyle(` #myScriptContainer { position: fixed; width: 135px; top: 70%; right: 0%; background-color: #f0f0f0; border: 1px solid #ccc; padding: 10px; z-index: 9999; display: flex; flex-direction: column; gap: 5px; } #myAPIBox, #myTextBox, #myLeadBox { padding: 5px; border: 1px solid #ddd; } #myInfoBox { color: black; padding: 5px; text-align: center; background-color: #f2f2f2; } #myUpdateButton, #myToggleButton { padding: 5px 10px; cursor: pointer; } `); })();