您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Settings tab & quickly assigns Narcos to a selected production. Reloads when you press ''OK''
// ==UserScript== // @name Jari's Quick Assign Narcos Script // @namespace http://tampermonkey.net/ // @version 1.0 // @description Settings tab & quickly assigns Narcos to a selected production. Reloads when you press ''OK'' // @author Jari [409], Baccy [12578] // @match https://cartelempire.online/settings // @match https://cartelempire.online/Production* // @icon https://i.ibb.co/67cBgvHQ/QNA.png // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // ==/UserScript== (function() { 'use strict'; // --- Configuration --- const SETTINGS_KEY_ENABLED = 'jari_script_enabled'; const SETTINGS_KEY_TARGET = 'jari_auto_allocate_target'; const PRODUCTION_TARGETS = { /* IDs from v1.7 */ "Street Crimes": "6", "Doctors Office": "5", "Weed Field": "2", "Alcohol Still": "1", "Cocaine Factory": "3" }; const PRODUCTION_TARGET_NAMES = Object.keys(PRODUCTION_TARGETS); // !! CRITICAL !! DOUBLE-CHECK THIS SELECTOR !! // This MUST point *ONLY* to the element displaying the number of *IDLE* narcos. // Use Developer Tools (F12 -> Inspector) on the Production page. // If this points to the wrong number (e.g., Total Narcos, or Street Crimes count), // the script WILL assign the wrong amount! const IDLE_NARCO_SELECTOR = '.idleNarcos'; // <--- *** VERIFY THIS SELECTOR IS CORRECT!!! *** // --- CSS --- GM_addStyle(` /* Styles copied from v1.8 */ .jari-switch-label { position: relative; display: inline-block; width: 40px; height: 22px; vertical-align: middle; margin-left: 5px; } .jari-switch-input { opacity: 0; width: 0; height: 0; } .jari-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #212529; border: 1px solid #495057; transition: .4s; border-radius: 22px; } .jari-slider:before { position: absolute; content: ""; height: 16px; width: 16px; left: 2px; bottom: 2px; background-color: #595C5F; transition: .4s; border-radius: 50%; } .jari-switch-input:checked + .jari-slider { background-color: #0D6EFD; border-color: #0D6EFD; } .jari-switch-input:checked + .jari-slider:before { background-color: #FFFFFF; transform: translateX(18px); } .jari-setting-row { display: flex; align-items: center; margin-bottom: 15px; } .jari-confirm-overlay-v17 { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.7); display: flex; justify-content: center; align-items: center; z-index: 10000; } .jari-confirm-box-v17 { background-color: #212529; color: #dee2e6; padding: 20px 25px; border-radius: 6px; border: 1px solid #444; box-shadow: 0 8px 25px rgba(0, 0, 0, 0.5); min-width: 300px; max-width: 450px; z-index: 10001; overflow: hidden; } .jari-confirm-box-v17 p { margin-top: 0; margin-bottom: 25px; font-size: 1rem; line-height: 1.6; text-align: left; color: #fff; } .jari-confirm-buttons-v17 { text-align: right; margin-top: 15px; } .jari-confirm-buttons-v17 button { color: white; border: none; padding: 8px 18px; border-radius: 5px; cursor: pointer; font-size: 0.95em; font-weight: 500; margin-left: 10px; transition: background-color 0.2s ease, box-shadow 0.2s ease; } .jari-confirm-ok-v17 { background-color: #0d6efd; box-shadow: 0 2px 5px rgba(13, 110, 253, 0.3); } .jari-confirm-cancel-v17 { background-color: #dc3545; box-shadow: 0 2px 5px rgba(220, 53, 69, 0.3); } .jari-confirm-buttons-v17 button:hover { filter: brightness(110%); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); } `); // --- Helper Functions --- function getSetting(key, defaultValue) { return GM_getValue(key, defaultValue); } function setSetting(key, value) { GM_setValue(key, value); } // --- Settings Page Logic (Identical to v1.8) --- function setupSettingsPage() { console.log("Jari's Settings Script v1.9 (Fixes & Debug): Initializing on /settings page..."); // ... (Settings UI setup code is exactly the same as v1.8) ... const settingsContentSelector = '.tab-content'; const settingsNavSelector = '.nav-tabs'; const settingsContent = document.querySelector(settingsContentSelector); const settingsNav = document.querySelector(settingsNavSelector); if (!settingsContent || !settingsNav) { console.error("Jari's Script: Could not find settings containers."); return; } if (document.querySelector('a[href="#jaris-userscripts-content"]')) { console.log("Jari's Script: Settings tab already exists."); return; } const newTab = document.createElement('li'); newTab.className = 'nav-item'; newTab.innerHTML = `<a class="nav-link" data-bs-toggle="tab" href="#jaris-userscripts-content">Jari's Userscripts</a>`; settingsNav.appendChild(newTab); const newPane = document.createElement('div'); newPane.className = 'tab-pane fade'; newPane.id = 'jaris-userscripts-content'; newPane.style.padding = '15px'; const toggleDiv = document.createElement('div'); toggleDiv.className = 'jari-setting-row'; const toggleLabel = document.createElement('label'); toggleLabel.htmlFor = 'jari-script-enable-checkbox'; toggleLabel.textContent = 'Enable Quick Narco Assignment:'; toggleLabel.style.marginRight = '10px'; toggleLabel.style.fontWeight = 'bold'; const switchLabel = document.createElement('label'); switchLabel.className = 'jari-switch-label'; switchLabel.innerHTML = `<input type="checkbox" id="jari-script-enable-checkbox" class="jari-switch-input"><span class="jari-slider"></span>`; toggleDiv.appendChild(toggleLabel); toggleDiv.appendChild(switchLabel); newPane.appendChild(toggleDiv); const dropdownDiv = document.createElement('div'); dropdownDiv.className = 'jari-setting-row'; const label = document.createElement('label'); label.htmlFor = 'jari-auto-allocate-select'; label.textContent = 'Select Quick Allocation Target:'; label.className = 'form-label'; label.style.fontWeight = 'bold'; label.style.marginRight = '10px'; const select = document.createElement('select'); select.id = 'jari-auto-allocate-select'; select.className = 'form-select'; select.style.maxWidth = '250px'; PRODUCTION_TARGET_NAMES.forEach(target => { const option = document.createElement('option'); option.value = target; option.textContent = target; select.appendChild(option); }); dropdownDiv.appendChild(label); dropdownDiv.appendChild(select); newPane.appendChild(dropdownDiv); const saveButtonDiv = document.createElement('div'); saveButtonDiv.style.marginTop = '20px'; const saveButton = document.createElement('button'); saveButton.id = 'jari-save-settings'; saveButton.textContent = 'Save Settings'; saveButton.className = 'btn btn-primary'; saveButtonDiv.appendChild(saveButton); newPane.appendChild(saveButtonDiv); settingsContent.appendChild(newPane); console.log("Jari's Script: Settings tab and content added."); const savedEnabled = getSetting(SETTINGS_KEY_ENABLED, false); const savedTarget = getSetting(SETTINGS_KEY_TARGET, PRODUCTION_TARGET_NAMES[0]); const enableCheckbox = document.getElementById('jari-script-enable-checkbox'); const targetSelect = document.getElementById('jari-auto-allocate-select'); if (enableCheckbox) enableCheckbox.checked = savedEnabled; if (targetSelect) targetSelect.value = savedTarget; console.log("Jari's Script: Loaded settings.", { enabled: savedEnabled, target: savedTarget }); saveButton.addEventListener('click', () => { const currentEnabled = enableCheckbox ? enableCheckbox.checked : false; const currentTarget = targetSelect ? targetSelect.value : PRODUCTION_TARGET_NAMES[0]; setSetting(SETTINGS_KEY_ENABLED, currentEnabled); setSetting(SETTINGS_KEY_TARGET, currentTarget); saveButton.textContent = 'Saved!'; saveButton.classList.remove('btn-primary'); saveButton.classList.add('btn-success'); setTimeout(() => { saveButton.textContent = 'Save Settings'; saveButton.classList.remove('btn-success'); saveButton.classList.add('btn-primary'); }, 1500); console.log("Jari's Script: Settings saved.", { enabled: currentEnabled, target: currentTarget }); }); } // End of setupSettingsPage // --- Custom Confirmation Box Function (v1.7 logic) --- function showStyledConfirm(message, yesCallback, noCallback) { /* Identical to v1.8 */ const existingDialog = document.getElementById('jari-confirm-dialog-v17'); if (existingDialog) { existingDialog.remove(); } const overlay = document.createElement('div'); overlay.id = 'jari-confirm-dialog-v17'; overlay.className = 'jari-confirm-overlay-v17'; const box = document.createElement('div'); box.className = 'jari-confirm-box-v17'; const p = document.createElement('p'); p.textContent = message; const buttonDiv = document.createElement('div'); buttonDiv.className = 'jari-confirm-buttons-v17'; const cancelButton = document.createElement('button'); cancelButton.textContent = 'Cancel'; cancelButton.className = 'jari-confirm-cancel-v17'; cancelButton.onclick = () => { overlay.remove(); if (noCallback) noCallback(); }; const okButton = document.createElement('button'); okButton.textContent = 'OK'; okButton.className = 'jari-confirm-ok-v17'; okButton.onclick = () => { overlay.remove(); if (yesCallback) yesCallback(); }; buttonDiv.appendChild(cancelButton); buttonDiv.appendChild(okButton); box.appendChild(p); box.appendChild(buttonDiv); overlay.appendChild(box); document.body.appendChild(overlay); } // --- Production Page Logic --- function getIdleNarcoCount() { const element = document.querySelector(IDLE_NARCO_SELECTOR); if (!element) { console.error("AutoAssign DEBUG: Idle narco element NOT FOUND using selector:", IDLE_NARCO_SELECTOR); alert("AutoAssign Error: Idle narco element not found. Please check the script's IDLE_NARCO_SELECTOR configuration."); return null; } const countText = element.textContent.trim(); // DEBUG: Log the raw text found console.log("AutoAssign DEBUG: Raw text found for idle count:", countText); const count = parseInt(countText.replace(/,/g, ''), 10); // Remove commas before parsing if (isNaN(count)) { console.error("AutoAssign DEBUG: FAILED to parse idle narco count from text:", countText); alert("AutoAssign Error: Cannot parse idle narco count from page element."); return null; } // DEBUG: Log the parsed count console.log("AutoAssign DEBUG: Parsed idle narco count as:", count); return count; } // MODIFIED: Added window.location.reload() on success function assignNarcos(targetId, targetName, amount) { const url = `/Production/Assign/${targetId}`; const postData = `toAssign=${encodeURIComponent(amount)}`; // DEBUG: Log exactly what is being sent console.log(`AutoAssign DEBUG: Sending POST to ${url} with body: ${postData}`); fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: postData }) .then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status} ${response.statusText}`); } return response.json(); }) .then(data => { console.log(`AutoAssign (Fetch): Assignment successful for ${targetName}. Resp:`, data); // RELOAD PAGE on success window.location.reload(); }) .catch(error => { console.error(`AutoAssign (Fetch): Assignment failed for ${targetName}. Error:`, error); alert(`AutoAssign Error: Failed to assign narcos to ${targetName}. ${error.message}. Check console.`); }); } // MODIFIED: Added extra debug logs function runAutoAssignLogic() { console.log("AutoAssign (Styled Confirm / Debug): Running on /Production page."); const isEnabled = getSetting(SETTINGS_KEY_ENABLED, false); if (!isEnabled) { console.log("AutoAssign: Script disabled."); return; } const targetName = getSetting(SETTINGS_KEY_TARGET, null); const targetId = targetName ? PRODUCTION_TARGETS[targetName] : null; if (!targetId) { console.log("AutoAssign: No valid target."); return; } // --- Idle Count Retrieval --- const idleNarcos = getIdleNarcoCount(); // --- if (idleNarcos === null) { console.log("AutoAssign: Cannot get idle count. Exiting."); return; } // DEBUG: Log the retrieved idle count before confirmation console.log(`AutoAssign DEBUG: Using idle narco count: ${idleNarcos} for target: ${targetName} (ID: ${targetId})`); const targetElement = [...document.querySelectorAll('.card-title.text-center.mb-1')].find(el => el.textContent === targetName); const currentNarcos = parseInt(targetElement.parentElement.querySelector('.assignNarcoInput').value); let maxCapacity; if (targetName !== 'Street Crimes') maxCapacity = parseInt(targetElement.parentElement.querySelector('.maxCapacity').textContent); else maxCapacity = 3000; if (currentNarcos === maxCapacity) return; let newNarcos; newNarcos = idleNarcos + currentNarcos; if (newNarcos > maxCapacity) newNarcos = maxCapacity; let displayedNarcos = newNarcos - currentNarcos; if (idleNarcos > 0) { showStyledConfirm( `Are you sure you want to quickly assign your Narcos? (${displayedNarcos} to ${targetName})`, () => { // OK Callback // DEBUG: Log count just before assignment call console.log(`AutoAssign DEBUG: OK confirmed. Calling assignNarcos with ID: ${targetId}, Name: ${targetName}, Amount: ${idleNarcos}`); assignNarcos(targetId, targetName, newNarcos); }, () => { // Cancel Callback console.log("AutoAssign DEBUG: User cancelled assignment (Cancel)."); } ); } else { console.log("AutoAssign DEBUG: No idle narcos found (count is 0 or less)."); } } // --- Main Execution --- const currentPath = window.location.pathname; if (currentPath.includes('/settings')) { setTimeout(setupSettingsPage, 1000); } else if (currentPath.startsWith('/Production')) { runAutoAssignLogic(); } })();