您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Makes an api request after 6:30pm TCT to check your current job, work stats and job points to see if you are able to upgrade to the next position, and displays a notice at the top of the page if you can upgrade. Click 'Fetch New Data' after upgrading to remove the notice. You may need to wait 30-60 seconds for the API to update with your new position. Toggle script button on job/company page.
// ==UserScript== // @name Torn - City Job Upgrade Notice // @namespace http://tampermonkey.net/ // @version 1.1 // @description Makes an api request after 6:30pm TCT to check your current job, work stats and job points to see if you are able to upgrade to the next position, and displays a notice at the top of the page if you can upgrade. Click 'Fetch New Data' after upgrading to remove the notice. You may need to wait 30-60 seconds for the API to update with your new position. Toggle script button on job/company page. // @author Baccy // @match https://www.torn.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=torn.com // @grant none // ==/UserScript== // An input for a minimal access API key will be displayed at the top of the in-game page if not found in storage (function() { 'use strict'; const jobRequirements = { army: [ { position: 'Private', manual_labor: 50, intelligence: 15, endurance: 20 }, { position: 'Corporal', manual_labor: 120, intelligence: 35, endurance: 50 }, { position: 'Sergeant', manual_labor: 325, intelligence: 60, endurance: 115 }, { position: 'Master Sergeant', manual_labor: 700, intelligence: 160, endurance: 300 }, { position: 'Warrant Officer', manual_labor: 1300, intelligence: 360, endurance: 595 }, { position: 'Lieutenant', manual_labor: 2550, intelligence: 490, endurance: 900 }, { position: 'Major', manual_labor: 4150, intelligence: 600, endurance: 1100 }, { position: 'Colonel', manual_labor: 7500, intelligence: 1350, endurance: 2530 }, { position: 'Brigadier', manual_labor: 10000, intelligence: 2000, endurance: 4000 }, { position: 'General', manual_labor: null, intelligence: null, endurance: null } ], grocer: [ { position: 'Bag Boy', manual_labor: 30, intelligence: 15, endurance: 50 }, { position: 'Price Labeller', manual_labor: 50, intelligence: 35, endurance: 120 }, { position: 'Cashier', manual_labor: 120, intelligence: 60, endurance: 225 }, { position: 'Food Delivery', manual_labor: 250, intelligence: 200, endurance: 500 }, { position: 'Manager', manual_labor: null, intelligence: null, endurance: null } ], casino: [ { position: 'Dealer', manual_labor: 35, intelligence: 50, endurance: 120 }, { position: 'Gaming Consultant', manual_labor: 60, intelligence: 115, endurance: 325 }, { position: 'Marketing Manager', manual_labor: 360, intelligence: 595, endurance: 1300 }, { position: 'Revenue Manager', manual_labor: 490, intelligence: 900, endurance: 2550 }, { position: 'Casino Manager', manual_labor: 755, intelligence: 1100, endurance: 4150 }, { position: 'Casino President', manual_labor: null, intelligence: null, endurance: null } ], medical: [ { position: 'Medical Student', manual_labor: 100, intelligence: 600, endurance: 150 }, { position: 'Houseman', manual_labor: 175, intelligence: 1000, endurance: 275 }, { position: 'Senior Houseman', manual_labor: 300, intelligence: 1500, endurance: 500 }, { position: 'GP', manual_labor: 600, intelligence: 2500, endurance: 1000 }, { position: 'Consultant', manual_labor: 1300, intelligence: 5000, endurance: 2000 }, { position: 'Surgeon', manual_labor: 2600, intelligence: 10000, endurance: 4000 }, { position: 'Brain Surgeon', manual_labor: null, intelligence: null, endurance: null } ], education: [ { position: 'Recess Supervisor', manual_labor: 300, intelligence: 750, endurance: 500 }, { position: 'Substitute Teacher', manual_labor: 600, intelligence: 1000, endurance: 700 }, { position: 'Elementary Teacher', manual_labor: 1000, intelligence: 1300, endurance: 1000 }, { position: 'Secondary Teacher', manual_labor: 1500, intelligence: 2000, endurance: 1500 }, { position: 'Professor', manual_labor: 1500, intelligence: 3000, endurance: 1500 }, { position: 'Vice Principal', manual_labor: 1500, intelligence: 5000, endurance: 1500 }, { position: 'Principal', manual_labor: null, intelligence: null, endurance: null } ], law: [ { position: 'Law Student', manual_labor: 1750, intelligence: 2500, endurance: 5000 }, { position: 'Paralegal', manual_labor: 2500, intelligence: 5000, endurance: 7500 }, { position: 'Probate Lawyer', manual_labor: 3500, intelligence: 6500, endurance: 7750 }, { position: 'Trial Lawyer', manual_labor: 4000, intelligence: 7250, endurance: 10000 }, { position: 'Circuit Court Judge', manual_labor: 6000, intelligence: 9000, endurance: 15000 }, { position: 'Federal Judge', manual_labor: null, intelligence: null, endurance: null } ] }; let apiKey; let scriptEnabled; let cityJobUpgradeData = {}; function checkTime() { const now = new Date(); const jobUpdateTime = new Date(now); jobUpdateTime.setUTCHours(18, 30, 0, 0); if (now < jobUpdateTime) jobUpdateTime.setUTCDate(jobUpdateTime.getUTCDate() - 1); const lastFetchedJobTime = cityJobUpgradeData.fetchTime ? new Date(cityJobUpgradeData.fetchTime) : null; if (!lastFetchedJobTime || lastFetchedJobTime < jobUpdateTime) fetchData(); else checkRequirements(); } function jobPage() { if ( window.location.href.toLowerCase().includes('https://www.torn.com/jobs.php') || window.location.href.toLowerCase().includes('https://www.torn.com/companies.php') ) { const toggleButton = document.createElement('button'); toggleButton.innerText = 'Toggle Job Upgrade Notice'; toggleButton.classList.add('city-job-upgrade'); toggleButton.style = scriptEnabled ? 'padding: 5px 10px; border-radius: 5px; background-color: #555555; color: lightgreen; border: none; cursor: pointer;' : 'padding: 5px 10px; border-radius: 5px; background-color: #555555; color: white; border: none; cursor: pointer;'; toggleButton.onclick = () => { scriptEnabled = !scriptEnabled; localStorage.setItem('cityJobUpgradeNoticeEnabled', scriptEnabled); if (scriptEnabled) toggleButton.style.color = 'lightgreen'; else toggleButton.style.color = 'white'; }; const pageTitle = document.querySelector('div.content-title > h4'); if (pageTitle && !document.querySelector('city-job-upgrade')) pageTitle.appendChild(toggleButton); } } function checkRequirements() { const positions = jobRequirements[cityJobUpgradeData.job_type.toLowerCase()]; if (!positions) return; const currentIndex = positions.findIndex(pos => pos.position === cityJobUpgradeData.job_position); if (currentIndex === -1 || currentIndex >= positions.length - 1) return; const nextPositionRequirements = positions[currentIndex]; const pointsRequired = (currentIndex + 1) * 5; const canUpgrade = cityJobUpgradeData.job_points >= pointsRequired && cityJobUpgradeData.manual_labor >= nextPositionRequirements.manual_labor && cityJobUpgradeData.intelligence >= nextPositionRequirements.intelligence && cityJobUpgradeData.endurance >= nextPositionRequirements.endurance; if (canUpgrade) displayNotice(`You can upgrade to ${positions[currentIndex + 1].position}.`); } function displayApiKeyInput() { const banner = document.querySelector('#topHeaderBanner'); if (banner && !document.querySelector('#minimal-api-key-message')) { const apiKeyInput = document.createElement('div'); apiKeyInput.innerHTML = `<div id="minimal-api-key-message" style="font-size: 16px; color: white; background-color: #222; text-align: center;"><p>Please enter your minimal access API key to continue.</p><input type="text" id="minimal-api-key-input" placeholder="Enter API Key" style="background-color: #333; color: white;"><button id="minimal-api-key-save" style="padding: 3px 10px; margin-left: 5px; background-color: #333; color: white; cursor: pointer;">Save API Key</button></div>`; banner.appendChild(apiKeyInput); const saveButton = document.querySelector('#minimal-api-key-save'); saveButton.addEventListener('click', () => { const inputField = document.querySelector('#minimal-api-key-input'); const apiKeyValue = inputField.value.trim(); if (apiKeyValue) { apiKey = apiKeyValue; localStorage.setItem('minimalAPIKey', apiKeyValue); checkTime(); apiKeyInput.remove(); } }); } } function displayNotice(message) { const banner = document.querySelector('#topHeaderBanner'); if (banner && !document.querySelector('#city-job-upgrade-notice')) { const jobNotice = document.createElement('div'); jobNotice.innerHTML = `<label id="city-job-upgrade-notice" style="font-size: 16px; color: white; background-color: #222; text-align: center;">${message}</label><button id="job-notice-fetch" style="padding: 3px 10px; margin-left: 5px; background-color: #333; color: white; cursor: pointer;">Fetch New Data</button>`; banner.appendChild(jobNotice); const fetchButton = document.querySelector('#job-notice-fetch'); fetchButton.addEventListener('click', () => { fetchData(); jobNotice.remove(); }); } } async function fetchData() { const response = await fetch(`https://api.torn.com/v2/user?key=${apiKey}&selections=jobpoints,profile,workstats&comment=JobUpgrade`); const result = await response.json(); if (result.error && (result.error.code === 2 || result.error.code === 16)) { await localStorage.removeItem('minimalAPIKey'); alert('Your API key is incorrect or access is not high enough. Please enter a new minimal access key.'); displayApiKeyInput(); return; } const job_points = result.jobpoints.jobs[result.job.job.toLowerCase()] || 0; cityJobUpgradeData = { manual_labor: result.manual_labor, intelligence: result.intelligence, endurance: result.endurance, job_type: result.job.job, job_position: result.job.position, job_points: job_points, fetchTime: new Date().toISOString(), }; await localStorage.setItem('cityJobUpgradeData', JSON.stringify(cityJobUpgradeData)); checkRequirements(); } async function init() { scriptEnabled = await JSON.parse(localStorage.getItem('cityJobUpgradeNoticeEnabled')) ?? true; jobPage(); if (scriptEnabled) { apiKey = await localStorage.getItem('minimalAPIKey') || ''; if (!apiKey) displayApiKeyInput(); else { cityJobUpgradeData = await JSON.parse(localStorage.getItem('cityJobUpgradeData')) || {}; checkTime(); } } } init(); })();