Move Start Button (Torn)

Moves "Start Fight", forces profile attacks, strips heavy elements, and supports Torn PDA mobile app.

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Advertisement:

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

Advertisement:

// ==UserScript==
// @name         Move Start Button (Torn)
// @namespace    https://github.com/0xymandias
// @version      3.41
// @description  Moves "Start Fight", forces profile attacks, strips heavy elements, and supports Torn PDA mobile app.
// @author       smokey_ [2492729] & Fixed
// @match        https://www.torn.com/*
// @grant        GM_addStyle
// ==/UserScript==

(function () {
    'use strict';

    // ========================================================================
    // SETTINGS
    // ========================================================================
    
    // Change this value to 'Temp', 'Primary', 'Secondary', or 'Melee'
    const BUTTON_LOCATION = 'Primary'; 
    
    // Performance Toggles
    const ULTRA_PERFORMANCE_MODE = true;
    const HIDE_ENEMY_COMPLETELY = false;

    // ========================================================================
    // PERFORMANCE INJECTIONS
    // ========================================================================
    if (ULTRA_PERFORMANCE_MODE) {
        let perfCSS = `
            /* Instantly hide heavy graphics before they render */
            canvas, img[src*="models"], [class*="modelWrap"], .custom-bg-desktop {
                display: none !important;
            }
        `;
        if (HIDE_ENEMY_COMPLETELY) {
            perfCSS += `#defender { display: none !important; }`;
        }
        GM_addStyle(perfCSS);
    }

    // ========================================================================
    // FEATURE 1: Move the "Start Fight" Button
    // ========================================================================
    
    // Smart Locator to handle Desktop, Mobile, and Torn PDA layouts
    function getWeaponBox(locationName) {
        let targetText = locationName.toLowerCase();
        if (targetText === 'temp') targetText = 'temporary';

        // METHOD 1: Text Search (Standard Desktop UI)
        const allText = document.querySelectorAll('div, span, p');
        for (let el of allText) {
            if (el.children.length === 0) {
                const text = (el.textContent || '').trim().toLowerCase();
                if (text === targetText) {
                    const rect = el.getBoundingClientRect();
                    // Ensure it's on the left side (attacker side)
                    if (rect.left >= 0 && rect.left < window.innerWidth / 2) {
                        let parent = el.parentElement;
                        for (let i = 0; i < 6; i++) {
                            if (parent && parent.querySelector('img[src*="/items/"]')) {
                                return { wrapper: parent, image: parent.querySelector('img[src*="/items/"]') };
                            }
                            if (parent) parent = parent.parentElement;
                        }
                    }
                }
            }
        }

        // METHOD 2: Aria-Labels (Modern Accessibility UI)
        const ariaEls = document.querySelectorAll(`[aria-label*="${targetText}" i]`);
        for (let el of ariaEls) {
            const rect = el.getBoundingClientRect();
            if (rect.left >= 0 && rect.left < window.innerWidth / 2) {
                const img = el.querySelector('img[src*="/items/"]');
                if (img) return { wrapper: el, image: img };
            }
        }

        // METHOD 3: Vertical Position Geometry (Torn PDA / Mobile UI)
        // Primary=0, Secondary=1, Melee=2, Temp=3
        const leftImages = [];
        const allItemImages = document.querySelectorAll('img[src*="/items/"]');
        for (let img of allItemImages) {
            const rect = img.getBoundingClientRect();
            if (rect.left >= 0 && rect.left < window.innerWidth / 2) {
                leftImages.push({ img: img, top: rect.top });
            }
        }
        
        // Sort them top-to-bottom as they appear on your physical screen
        leftImages.sort((a, b) => a.top - b.top);

        if (leftImages.length > 0) {
            let targetIndex = 0;
            if (targetText === 'secondary') targetIndex = 1;
            if (targetText === 'melee') targetIndex = 2;
            if (targetText === 'temporary') targetIndex = 3;

            // Clamp index just in case you have empty weapon slots
            if (targetIndex >= leftImages.length) {
                targetIndex = leftImages.length - 1; 
            }
            
            const targetImg = leftImages[targetIndex].img;
            
            // Climb up the HTML tree to find the weapon's outer box (Height is usually between 50 and 250px)
            let parent = targetImg.parentElement;
            let bestWrapper = parent;
            for (let i = 0; i < 5; i++) {
                if (!parent) break;
                if (parent.tagName === 'DIV') {
                    const height = parent.getBoundingClientRect().height;
                    if (height > 50 && height < 250) {
                        bestWrapper = parent;
                    }
                }
                parent = parent.parentElement;
            }
            
            return { wrapper: bestWrapper, image: targetImg };
        }

        return { wrapper: null, image: null };
    }

    function moveStartFightButton() {
        if (document.querySelector('.button-wrapper')) return;

        let startFightButton = null;
        const allButtons = document.querySelectorAll('button, [role="button"], a');
        for (let el of allButtons) {
            const text = (el.innerText || el.textContent || '').toUpperCase();
            if (text.includes('START FIGHT') && text.length < 30) {
                startFightButton = el;
                break;
            }
        }

        if (!startFightButton) return;

        const weaponData = getWeaponBox(BUTTON_LOCATION);
        
        if (startFightButton && weaponData.wrapper && weaponData.image && !document.querySelector('.button-wrapper')) {
            const buttonWrapper = document.createElement('div'); 
            buttonWrapper.classList.add('button-wrapper');
            
            buttonWrapper.appendChild(startFightButton); 
            
            // Append it securely over the entire weapon box
            weaponData.wrapper.appendChild(buttonWrapper);

            buttonWrapper.style.position = 'absolute';
            buttonWrapper.style.top = '0';
            buttonWrapper.style.left = '0';
            buttonWrapper.style.width = '100%';
            buttonWrapper.style.height = '100%';
            buttonWrapper.style.display = 'flex';
            buttonWrapper.style.alignItems = 'center';
            buttonWrapper.style.justifyContent = 'center';
            buttonWrapper.style.zIndex = '99999';
            buttonWrapper.style.backgroundColor = 'rgba(0,0,0,0.5)';
            
            // Force the parent to contain the button overlay
            if (window.getComputedStyle(weaponData.wrapper).position === 'static') {
                weaponData.wrapper.style.position = 'relative';
            }

            startFightButton.addEventListener('click', function() {
                buttonWrapper.remove();
            });
        }
    }

    // ========================================================================
    // FEATURE 2: Force Attack Button on Profile Pages
    // ========================================================================
    function fixProfileAttackButton() {
        const urlParams = new URLSearchParams(window.location.search);
        const userId = urlParams.get('XID');
        if (!userId) return;

        const potentialBtns = new Set([
            ...document.querySelectorAll('a[aria-label*="Attack" i], a[title*="Attack" i]'),
            ...Array.from(document.querySelectorAll('i[class*="attack" i], svg[class*="attack" i]')).map(icon => icon.closest('a') || icon.closest('button'))
        ]);

        for (let btn of potentialBtns) {
            if (!btn) continue;
            
            const currentHref = btn.getAttribute('href') || '';
            const targetUrl = `https://www.torn.com/page.php?sid=attack&user2ID=${userId}`;
            
            if (!currentHref.includes('user2ID=') || btn.className.includes('disabled') || window.getComputedStyle(btn).opacity < 1) {
                btn.classList.remove('disabled');
                btn.style.opacity = '1';
                btn.style.cursor = 'pointer';
                btn.style.pointerEvents = 'auto'; 
                
                btn.setAttribute('href', targetUrl);
                
                btn.addEventListener('click', function(e) {
                    e.stopPropagation(); 
                }, true);
            }
        }
    }

    // ========================================================================
    // MAIN BACKGROUND LOOP (Runs 10x a second)
    // ========================================================================
    setInterval(function () {
        const url = window.location.href;
        
        if (url.includes('attack')) {
            moveStartFightButton();
            
            if (ULTRA_PERFORMANCE_MODE) {
                // Permanently delete rendering models to free CPU
                const models = document.querySelectorAll('canvas, img[src*="models"]');
                for (const element of models) {
                    element.remove();
                }
            }
        } else if (url.includes('profiles.php')) {
            fixProfileAttackButton();
        }
    }, 100);

})();