您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Automates crimes (neighborhood + car robbery). Clean GUI and fixed loop.
当前为
// ==UserScript== // @name Ortenskung crime bot - fixed (1.8.1) // @namespace http://tampermonkey.net/ // @version 1.8.1 // @description Automates crimes (neighborhood + car robbery). Clean GUI and fixed loop. // @match https://www.ortenskung.com/en/* // @grant none // ==/UserScript== (function () { 'use strict'; // ---------------- KEEP-ALIVE (optional) ---------------- try { setInterval(() => { /* heartbeat */ }, 30000); const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); const osc = audioCtx.createOscillator(); osc.frequency.value = 0.0001; // near-silent (avoid 0 to reduce some errors) osc.connect(audioCtx.destination); osc.start(); } catch (e) { /* audio context may be blocked, ignore */ } // ---------------- State ---------------- let running = false; let loopTimer = null; let selectedCrimeId = 1; let autoClose = true; // If the UI already exists (script re-run), remove it before creating new one const existing = document.getElementById('__ortens_crime_bot_panel'); if (existing) existing.remove(); // ---------------- Create GUI ---------------- const panel = document.createElement('div'); panel.id = '__ortens_crime_bot_panel'; Object.assign(panel.style, { position: 'fixed', top: '60px', right: '40px', width: '320px', background: '#131313', color: '#eaeaea', borderRadius: '10px', boxShadow: '0 6px 18px rgba(0,0,0,0.6)', fontFamily: 'Inter, Roboto, sans-serif', zIndex: 999999, userSelect: 'none', padding: '0', overflow: 'hidden' }); panel.innerHTML = ` <div id="__header" style="display:flex;align-items:center;justify-content:space-between;padding:8px 10px;background:#0f0f0f;border-bottom:1px solid rgba(255,255,255,0.04);cursor:move"> <div style="font-weight:600">Crime Bot</div> <div style="display:flex;gap:6px;align-items:center"> <button id="__minBtn" title="Minimize" style="background:transparent;border:none;color:#aaa;cursor:pointer;font-size:14px">—</button> <button id="__closeBtn" title="Close" style="background:transparent;border:none;color:#aaa;cursor:pointer;font-size:14px">✕</button> </div> </div> <div id="__body" style="padding:10px;display:block"> <div style="display:flex;gap:8px;margin-bottom:8px"> <button class="__tab" data-tab="main" style="flex:1;padding:6px;border-radius:6px;border:0;background:#1b1b1b;color:#fff;cursor:pointer">Main</button> <button class="__tab" data-tab="settings" style="flex:1;padding:6px;border-radius:6px;border:0;background:#121212;color:#888;cursor:pointer">Settings</button> </div> <div id="__tab_main" class="__tabpanel"> <label style="font-size:13px">Crime Type</label> <select id="__crimeType" style="width:100%;padding:6px;margin:6px 0 10px;border-radius:6px;border:1px solid rgba(255,255,255,0.06);background:#0b0b0b;color:#fff"> <option value="neighborhood">Neighborhood</option> <option value="car">Car Robbery</option> </select> <label style="font-size:13px">Crime ID</label> <select id="__crimeId" style="width:100%;padding:6px;margin:6px 0 10px;border-radius:6px;border:1px solid rgba(255,255,255,0.06);background:#0b0b0b;color:#fff"> ${Array.from({length:30}, (_,i)=>i+1).map(n=>`<option value="${n}">${n}</option>`).join('')} </select> <div style="display:flex;align-items:center;gap:8px;margin-bottom:10px"> <label style="font-size:13px;display:flex;align-items:center;gap:6px"> <input type="checkbox" id="__autoClose" checked /> <span style="font-size:13px">Close dialogs</span> </label> </div> <button id="__startBtn" style="width:100%;padding:8px;border-radius:8px;border:0;background:linear-gradient(180deg,#2fa84f,#208f3a);color:#fff;font-weight:600;cursor:pointer">Start</button> </div> <div id="__tab_settings" class="__tabpanel" style="display:none"> <p style="font-size:13px;color:#bbb;margin:0 0 8px">Settings</p> <p style="font-size:12px;color:#999;margin:0 0 8px">Loop delay (ms)</p> <input id="__loopDelay" type="number" value="4000" style="width:100%;padding:6px;border-radius:6px;border:1px solid rgba(255,255,255,0.06);background:#0b0b0b;color:#fff" /> <p style="font-size:12px;color:#999;margin:10px 0 0">If something breaks, stop and inspect the selectors in the script.</p> </div> </div> <div id="__footer" style="font-size:11px;padding:6px 10px;background:#0f0f0f;border-top:1px solid rgba(255,255,255,0.03);color:#9a9a9a"> Status: <span id="__status">Idle</span> </div> `; document.body.appendChild(panel); // ---------------- UI helpers ---------------- const header = panel.querySelector('#__header'); const body = panel.querySelector('#__body'); const closeBtn = panel.querySelector('#__closeBtn'); const minBtn = panel.querySelector('#__minBtn'); const tabs = panel.querySelectorAll('.__tab'); const tabMain = panel.querySelector('#__tab_main'); const tabSettings = panel.querySelector('#__tab_settings'); const startBtn = panel.querySelector('#__startBtn'); const crimeIdEl = panel.querySelector('#__crimeId'); const crimeTypeEl = panel.querySelector('#__crimeType'); const autoCloseEl = panel.querySelector('#__autoClose'); const statusEl = panel.querySelector('#__status'); const loopDelayEl = panel.querySelector('#__loopDelay'); // Dragging (pointer-friendly) (function makeDraggable(el) { let dragging = false, sx = 0, sy = 0, ox = 0, oy = 0; header.addEventListener('pointerdown', (ev) => { dragging = true; sx = ev.clientX; sy = ev.clientY; const rect = el.getBoundingClientRect(); ox = rect.left; oy = rect.top; header.setPointerCapture(ev.pointerId); }); document.addEventListener('pointermove', (ev) => { if (!dragging) return; const dx = ev.clientX - sx; const dy = ev.clientY - sy; el.style.left = (ox + dx) + 'px'; el.style.top = (oy + dy) + 'px'; el.style.right = 'auto'; el.style.position = 'fixed'; }); document.addEventListener('pointerup', (ev) => { dragging = false; }); })(panel); // Tabs tabs.forEach(t => t.addEventListener('click', () => { tabs.forEach(x => x.style.background = '#121212'); t.style.background = '#1b1b1b'; const tab = t.dataset.tab; if (tab === 'main') { tabMain.style.display = 'block'; tabSettings.style.display = 'none'; } else { tabMain.style.display = 'none'; tabSettings.style.display = 'block'; } })); // Minimize / close // --- Replace the existing minBtn.addEventListener('click', ...) handler with this block --- minBtn.addEventListener('click', () => { // Use a data attribute to track minimized state (reliable across style changes) const isMinimized = panel.getAttribute('data-minimized') === 'true'; if (!isMinimized) { // Minimize: hide body & footer, shrink panel for a compact header-only look body.style.display = 'none'; footer.style.display = 'none'; // Keep header visible and reduce width so it looks tidy when minimized panel.style.width = '160px'; panel.style.height = 'auto'; panel.setAttribute('data-minimized', 'true'); // Update button visuals & tooltip for clarity minBtn.textContent = '▢'; // restore icon minBtn.title = 'Restore'; } else { // Restore: show body & footer and return panel sizing body.style.display = 'block'; footer.style.display = 'block'; panel.style.width = '320px'; // original width used in your script panel.style.height = 'auto'; panel.setAttribute('data-minimized', 'false'); minBtn.textContent = '—'; // minimize icon minBtn.title = 'Minimize'; } }); // ---------------- Core automation ---------------- function setStatus(text) { statusEl.textContent = text; } function stopLoop() { running = false; if (loopTimer) { clearTimeout(loopTimer); loopTimer = null; } startBtn.textContent = 'Start'; setStatus('Stopped'); } async function startLoop() { if (running) return; running = true; startBtn.textContent = 'Stop'; setStatus('Running'); // sync UI values selectedCrimeId = parseInt(crimeIdEl.value, 10); autoClose = autoCloseEl.checked; await performCrime(); // start immediately } startBtn.addEventListener('click', () => { if (!running) startLoop(); else stopLoop(); }); // Utility: safe query with timeout (optional) function sleep(ms) { return new Promise(r => setTimeout(r, ms)); } // Attempt to robustly find and click elements. The exact selectors depend on the game's DOM; // this function uses plausible selectors and falls back gracefully. async function performCrime() { if (!running) return; try { const delay = Math.max(50, parseInt(loopDelayEl.value, 10) || 4000); // 0) Check timers area if available (best-effort) const timerEl = document.querySelector('#my_timers > div.val') || document.querySelector('.timers .val'); if (timerEl) { const txt = timerEl.textContent.trim(); const m = txt.match(/(\d+)\s*\/\s*(\d+)/); if (m) { const used = parseInt(m[1], 10), total = parseInt(m[2], 10); const avail = total - used; if (avail <= 0) { setStatus('No timers left — waiting'); loopTimer = setTimeout(performCrime, 5000); return; } } } const mode = (crimeTypeEl.value || 'neighborhood'); // 1) Ensure relevant dialog is open if (mode === 'neighborhood') { // Try to open crimes dialog if not present if (!document.querySelector('#go_crimes_dialog') && document.querySelector('#go_crimes')) { document.querySelector('#go_crimes').click(); await sleep(300); } // Switch to Neighborhood tab/button if needed const nbBtn = Array.from(document.querySelectorAll('.crimes_button, .crimes_button_small, .crimes-tab, .crimes_button')) .find(el => /neighborhood/i.test(el.textContent || el.innerText || '')); if (nbBtn && !document.querySelector('#neighborhood_crimes')) { try { nbBtn.click(); } catch (e) {} await sleep(250); } } else if (mode === 'car') { // Try to open cars dialog if (!document.querySelector('#dialog_cars') && document.querySelector('#go_cars')) { document.querySelector('#go_cars').click(); await sleep(300); } else { // sometimes the button text is 'Cars' or 'Car Robbery' or '#go_rob_car' const carOpener = Array.from(document.querySelectorAll('a,button')) .find(el => /(car|cars|vehicle|rob)/i.test(el.textContent || el.getAttribute('title') || '')); if (carOpener && !document.querySelector('#dialog_cars')) { try { carOpener.click(); } catch (e) {} await sleep(300); } } } // 2) Find commit/click button for the selected crime let commitBtn = null; if (mode === 'neighborhood') { // Buttons often have onclick including "'id':'N'" or "id: N" const btns = Array.from(document.querySelectorAll('.crime_button_small, .crime_button, a, button')) .filter(el => el.getAttribute && (el.getAttribute('onclick') || '').toString().length > 0); commitBtn = btns.find(el => { const on = (el.getAttribute('onclick') || ''); return new RegExp(`['"]?id['"]?\\s*[:=]\\s*['"]?${selectedCrimeId}['"]?`).test(on); }) || btns.find(el => (el.getAttribute('onclick') || '').includes(`'id':'${selectedCrimeId}'`)); // fallback: match by visible label containing the id (rare) if (!commitBtn) { const byText = Array.from(document.querySelectorAll('.crime_button_small, .crime_button')) .find(el => (el.textContent || '').includes(String(selectedCrimeId))); if (byText) commitBtn = byText; } // final fallback: first available small crime button if (!commitBtn) { commitBtn = document.querySelector('.crime_button_small, .crime_button'); } } else if (mode === 'car') { // Car robbery buttons may live under #dialog_cars or have onclick with 'robbing:perform' or 'robbing' commitBtn = Array.from(document.querySelectorAll('#dialog_cars .crime_button_small, #dialog_cars a, #dialog_cars button, .car_list a, .car_list button')) .find(el => { const on = el.getAttribute('onclick') || ''; return /robbing:perform|robbing|car|vehicle/i.test(on + ' ' + (el.textContent || '')); }); if (!commitBtn) { // broader search commitBtn = Array.from(document.querySelectorAll('a,button')) .find(el => { const on = (el.getAttribute('onclick') || '') + ' ' + (el.textContent || ''); return /robbing:perform|rob car|rob car|car robbery|rob car/i.test(on); }); } // last fallback: any clickable inside dialog_cars if (!commitBtn) { commitBtn = document.querySelector('#dialog_cars .crime_button_small') || document.querySelector('#dialog_cars a') || document.querySelector('#dialog_cars button'); } } if (!commitBtn) { setStatus('No crime button found — retrying'); loopTimer = setTimeout(performCrime, 5000); return; } // Click commit try { commitBtn.scrollIntoView({block:'center', behavior:'auto'}); } catch (e) {} try { commitBtn.click(); setStatus(`Clicked ${mode} button`); } catch (e) { try { commitBtn.dispatchEvent(new MouseEvent('click', {bubbles:true,cancelable:true})); setStatus('Dispatched click'); } catch (err) { console.error('click failed', err); setStatus('Click failed'); } } // 3) After clicking, attempt to close dialogs / notifications setTimeout(() => { try { if (typeof close_dialog === 'function') { // best-effort closes try { close_dialog('social'); } catch {} try { close_dialog('levelup'); } catch {} if (autoClose) try { close_dialog('crimes'); } catch {} if (autoClose) try { close_dialog('cars'); } catch {} } } catch (err) { /* ignore */ } // click primary notification button if present const notif = document.querySelector('.button.first, .ui-button.primary, .ui-dialog .button'); if (notif) { try { notif.click(); } catch (e) {} } }, 800); // 4) Schedule next run loopTimer = setTimeout(performCrime, Math.max(500, delay)); } catch (err) { console.error('performCrime error', err); setStatus('Error — retrying'); loopTimer = setTimeout(performCrime, 5000); } } // Expose stop for debugging from console window.__ortensCrimeBot = { stop: stopLoop, start: startLoop, status: () => ({ running, selectedCrimeId, autoClose }) }; // set initial selectedCrimeId selectedCrimeId = parseInt(crimeIdEl.value, 10); })();