您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Mission finder script with retry logic for loading vehicles and retrying unit selection if the loading bar is visible. Includes dispatch box functionality, patient selection, and color change. Only runs on mission dispatch pages.
// ==UserScript== // @name Mission Finder (NEW) // @namespace http://tampermonkey.net/ // @version 5.5 // @description Mission finder script with retry logic for loading vehicles and retrying unit selection if the loading bar is visible. Includes dispatch box functionality, patient selection, and color change. Only runs on mission dispatch pages. // @author Martyblyth // @match https://www.missionchief.co.uk/* // @match https://police.missionchief.co.uk/* // @grant none // @run-at document-end // ==/UserScript== (function() { 'use strict'; // Function to detect if we are on a mission dispatch page function isMissionPage() { // Check if the page contains elements unique to the mission dispatch popup (modal) return document.querySelector('.vm--modal iframe') || document.querySelector('#mission_general_info'); } // Prevent double initialization by checking if the script has already run if (window.missionFinderInitialized) return; window.missionFinderInitialized = true; // Cross-reference list for item name replacements const crossReference = { // FIRE "Pumps": "Fire Engine R/PUMP x 1", "Pump": "Fire Engine R/PUMP x 1", "Aerial Appliance": "Fire Engine CARP", "Aerial Appliances": "Fire Engine CARP", "Breathing Apparatus Support Unit": "OSU", "Breathing Apparatus Support Units": "OSU", "HazMat Unit or CBRN Vehicle": "OSU", "HazMat Units or CBRN Vehicles": "OSU", "Welfare Vehicle": "OSU", "Welfare Vehicles": "OSU", "ICCU or Ambulance Control Unit": "ICCU/ACU", "ICCU or Ambulance Control Units": "ICCU/ACU", "ICCUs or Ambulance Control Units": "ICCU/ACU", "Fire Officers": "Fire Officer", "Fire Officer": "Fire Officer", "Rescue Support Unit or Rescue Pump": "Fire Engine R/PUMP x 1", "Rescue Support Units or Rescue Pumps": "Fire Engine R/PUMP x 1", "Fire Engines or Rescue Support Vehicles": "Fire Engine R/PUMP x 1", "Fire Engines, Rescue Support Vehicles or Aerial Appliance Trucks": "Fire Engine R/PUMP x 1", "Foam Unit": "RP CAFS", "Foam Units": "RP CAFS", "Water Carrier" : "Water Carrier", "Water Carriers": "Water Carrier", // POLICE "Police Cars": "Police Car", "Traffic Car": "Police ATC", "Traffic Cars": "Police ATC", "Dog Support Unit (DSU)": "Police DSU", "Dog Support Units (DSUs)": "Police DSU", "Police Cars or Armed Response Vehicles (ARVs)": "Police ATC", "Mounted Units": "Mounted Unit", "Police Helicopters or Drones": "Police Helicopter", // AMBULANCE "Ambulance": "Ambulance x 01", "Ambulances": "Ambulance x 01", "Primary Response Vehicle": "PRV", "Primary Response Vehicles": "PRV", "Secondary Response Vehicle": "SRV", "Secondary Response Vehicles": "SRV", "Operational Team Leader": "OTL", "Operational Team Leaders": "OTL", "Mass Casualty Equipment": "Mass Casualty Equipment", "ATV Carrier": "ATV Carrier", "RRV or Specialist Paramedic RRV": "Specialist Paramedic RRV", "Community Midwifes": "Community Midwife", "Community Midwife": "Community Midwife", // SAR "CRV": "CRV", "CRVs": "CRV", "Inland Rescue Boat (Trailer)": "Boat Trailer", "Coastguard Rescue Helicopter": "CG Rescue Helicopter (Large)", "Coastguard Rescue Helicopters": "CG Rescue Helicopter (Large)", "ILBs or ALBs": "ALB", "ILBs": "ILB", "Control Vans": "Control Van", "Control Van": "Control Van", "Operational Support Van": "Operational Support Van", "Operational Support Vans": "Operational Support Van", "Flood Rescue Unit": "Flood Rescue Unit (Trailer)", "4x4 Vehicles": "SAR 4x4", "4x4 Vehicle": "SAR 4x4", "Hovercraft (trailer)": "Hovercraft (trailer)", "Coastguard Mud Rescue Units": "CG Mud Rescue Unit", "Coastguard Mud Rescue Unit": "CG Mud Rescue Unit", "Mud Decontamination Unit": "Mud Decontamination Unit", "Mud Decontamination Units": "Mud Decontamination Unit", // AIRFIELD "Airfield Operations Vehicle": "Airfield Operations Vehicle", "Airfield Operations Vehicles": "Airfield Operations Vehicle", "Aerial Appliance Trucks or Rescue Stairs": "Rescue Stairs", "Fire Engines or RIVs": "RIV", "Major Foam Tenders": "Major Foam Tender", "RIVs or Major Foam Tenders": "Major Foam Tender", "Fire Engines, RIVs or Major Foam Tenders": "Major Foam Tender", "Fire Engines or Major Foam Tenders": "Major Foam Tender", "Airfield Operations Supervisors": "Airfield Operations Supervisors", "Airfield Firefighting Command Vehicle": "Airfield FF Command Vehicle", "ICCU or Ambulance Control Units or Airfield Firefighting Command Vehicles": "Airfield FF Command Vehicle", "Fire Officers or Airfield Firefighting Command Vehicles": "Fire Officer", }; // Only initialize if we are on a mission page if (!isMissionPage()) { console.log('Not on a mission page, exiting script.'); return; } // Create a unified control panel that is movable function createControlPanel() { const panel = document.createElement('div'); panel.id = 'control-panel'; // Get the saved position for the panel from localStorage const savedLeft = localStorage.getItem('panel-left') || '20px'; const savedTop = localStorage.getItem('panel-top') || '20px'; panel.style.position = 'fixed'; panel.style.left = savedLeft; panel.style.top = savedTop; panel.style.padding = '10px'; panel.style.backgroundColor = 'rgba(0, 0, 0, 0.8)'; panel.style.color = 'white'; panel.style.fontSize = '14px'; panel.style.zIndex = '9999'; panel.style.border = '2px solid white'; panel.style.borderRadius = '8px'; panel.style.width = '300px'; panel.style.cursor = 'move'; panel.style.display = 'flex'; panel.style.flexDirection = 'column'; panel.style.gap = '10px'; // Create the drag handle (panel title) const dragHandle = document.createElement('div'); dragHandle.textContent = 'Mission Control'; dragHandle.style.fontSize = '16px'; dragHandle.style.fontWeight = 'bold'; dragHandle.style.textAlign = 'center'; dragHandle.style.backgroundColor = '#555'; dragHandle.style.padding = '5px'; dragHandle.style.cursor = 'move'; panel.appendChild(dragHandle); // Create the status box for status updates const statusBox = document.createElement('div'); statusBox.id = 'status-box'; statusBox.textContent = 'Ready to start...'; statusBox.style.backgroundColor = '#444'; statusBox.style.padding = '8px'; statusBox.style.borderRadius = '5px'; panel.appendChild(statusBox); // Create Unit Finder button const unitFinderBtn = document.createElement('button'); unitFinderBtn.textContent = 'Unit Finder'; unitFinderBtn.style.padding = '8px'; unitFinderBtn.style.backgroundColor = 'orange'; unitFinderBtn.style.border = 'none'; unitFinderBtn.style.color = 'black'; unitFinderBtn.style.borderRadius = '5px'; unitFinderBtn.style.cursor = 'pointer'; unitFinderBtn.addEventListener('click', function() { updateStatusBox('Unit Finder clicked'); handleCombinedLogic(); }); panel.appendChild(unitFinderBtn); // Create Dispatch button const dispatchBtn = document.createElement('button'); dispatchBtn.id = 'dispatch-box'; dispatchBtn.textContent = 'Dispatch'; dispatchBtn.style.padding = '8px'; dispatchBtn.style.backgroundColor = 'grey'; dispatchBtn.style.border = 'none'; dispatchBtn.style.color = 'white'; dispatchBtn.style.borderRadius = '5px'; dispatchBtn.style.cursor = 'pointer'; dispatchBtn.addEventListener('click', function() { triggerDispatchClick(); }); panel.appendChild(dispatchBtn); document.body.appendChild(panel); // Make the panel draggable makePanelDraggable(panel, dragHandle); } // Function to make the panel draggable function makePanelDraggable(panel, dragHandle) { let isDragging = false; let startX, startY, initialLeft, initialTop; dragHandle.addEventListener('mousedown', function(e) { isDragging = true; startX = e.clientX; startY = e.clientY; initialLeft = parseInt(window.getComputedStyle(panel).left, 10); initialTop = parseInt(window.getComputedStyle(panel).top, 10); document.addEventListener('mousemove', onMouseMove); document.addEventListener('mouseup', onMouseUp); }); function onMouseMove(e) { if (isDragging) { const dx = e.clientX - startX; const dy = e.clientY - startY; panel.style.left = `${initialLeft + dx}px`; panel.style.top = `${initialTop + dy}px`; } } function onMouseUp() { isDragging = false; document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); // Save the new position in localStorage localStorage.setItem('panel-left', panel.style.left); localStorage.setItem('panel-top', panel.style.top); } } // Update the status box function updateStatusBox(message) { const statusBox = document.getElementById('status-box'); if (statusBox) { statusBox.textContent = message; } } // Change dispatch box color based on status function changeDispatchBoxColor(isComplete) { const dispatchBox = document.getElementById('dispatch-box'); if (dispatchBox) { if (isComplete) { dispatchBox.style.backgroundColor = 'green'; updateStatusBox('Units ready for dispatch.'); } else { dispatchBox.style.backgroundColor = 'grey'; } } } // Handle patient selection function handlePatientSelector() { updateStatusBox('Handling patient selection...'); const patientCount = findPatientCount(); if (patientCount > 0) { triggerAmbulanceClick(patientCount); triggerAmbulanceOfficerClick(); } } function findPatientCount() { const patientElement = Array.from(document.querySelectorAll('span.badge')).find(span => { return span.textContent.toLowerCase().includes("patient"); }); if (patientElement) { const textContent = patientElement.textContent.trim(); const numberMatch = textContent.match(/\d+/); return numberMatch ? parseInt(numberMatch[0], 10) : 0; } return 0; } function triggerAmbulanceOfficerClick() { const ambulanceOfficer = document.querySelector('a[search_attribute="Ambulance Officer"]'); if (ambulanceOfficer) { ambulanceOfficer.click(); } } function triggerAmbulanceClick(number) { const element = document.querySelector('a[search_attribute="Ambulance x 01"]'); if (element) { for (let i = 0; i < number; i++) { setTimeout(() => { element.click(); }, i * 100); } } } // Handle vehicles and retry logic function processVehicles(vehicleList) { const listItems = vehicleList.querySelectorAll('li.class-x'); let missingUnits = []; updateStatusBox('Processing vehicle list...'); listItems.forEach(item => { let unitText = [...item.childNodes] .filter(node => node.nodeType === Node.TEXT_NODE) .map(node => node.textContent.trim())[0]; if (!unitText) return; let requiredAmount = item.getAttribute('data-amount'); if (!requiredAmount) return; let replacedItemText = crossReference[unitText] || unitText; const anchorElement = document.querySelector(`a[search_attribute="${replacedItemText}"]`); if (anchorElement) { for (let i = 0; i < parseInt(requiredAmount); i++) { anchorElement.click(); console.log(`Clicked on: ${replacedItemText} (${i + 1}/${requiredAmount})`); } } else { missingUnits.push(unitText); } }); if (missingUnits.length > 0) { retryMissingUnits(missingUnits); } else { changeDispatchBoxColor(true); // All units assigned, turn dispatch box green } } function retryMissingUnits(missingUnits) { updateStatusBox('Retrying missing units...'); const loadingBar = document.querySelector('a.btn-warning.missing_vehicles_load'); if (loadingBar) { loadingBar.click(); console.log('Clicked the loading bar for missing units'); let intervalId = setInterval(() => { if (!isLoadingBarVisible()) { clearInterval(intervalId); updateStatusBox('Loading bar completed, retrying missing units...'); missingUnits.forEach(unit => { let replacedItemText = crossReference[unit] || unit; const anchorElement = document.querySelector(`a[search_attribute="${replacedItemText}"]`); if (anchorElement) { anchorElement.click(); console.log(`Retried and clicked unit: ${unit}`); } }); setTimeout(() => { const finalMissingUnits = missingUnits.filter(unit => { const anchorElement = document.querySelector(`a[search_attribute="${crossReference[unit] || unit}"]`); return !anchorElement; }); if (finalMissingUnits.length === 0) { changeDispatchBoxColor(true); // All units assigned, turn dispatch box green } else { alert(`Final missing units:\n\n${finalMissingUnits.join('\n')}`); } }, 1000); } }, 1000); } else { alert(`Missing units:\n\n${missingUnits.join('\n')}`); } } function isLoadingBarVisible() { const loadingBar = document.querySelector('a.missing_vehicles_load'); return loadingBar && getComputedStyle(loadingBar).display !== 'none'; } // Combined logic for both patients and vehicles function handleCombinedLogic() { updateStatusBox('Started combined logic...'); handlePatientSelector(); const vehicleHeadings = document.querySelectorAll('h4'); let vehicleList; for (let heading of vehicleHeadings) { if (heading.textContent.trim() === 'Vehicles') { let nextElem = heading.nextElementSibling; while (nextElem && nextElem.tagName !== 'UL') { nextElem = nextElem.nextElementSibling; } if (nextElem && nextElem.tagName === 'UL') { vehicleList = nextElem; break; } } } if (vehicleList) { updateStatusBox("Vehicle list found. Processing..."); processVehicles(vehicleList); } else { updateStatusBox("No vehicle list found."); } } function triggerDispatchClick() { const dispatchArrow = document.querySelector('span.glyphicon.glyphicon-arrow-right'); if (dispatchArrow) { dispatchArrow.click(); updateStatusBox('Dispatch arrow clicked'); } else { console.error('Dispatch arrow not found.'); } } function initialize() { createControlPanel(); clickVehicleDisplayBarImmediately(); } function clickVehicleDisplayBarImmediately() { const vehicleDisplayBar = document.querySelector('a.btn-warning.missing_vehicles_load'); if (vehicleDisplayBar) { vehicleDisplayBar.click(); updateStatusBox("Clicked the 'Vehicle Display Limited' bar immediately."); } else { updateStatusBox("No vehicle display bar found."); } } window.addEventListener('load', initialize); })();