Lazy Crimes

Adds a spam crime button for everybody that should've stayed on crimes 1.0

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Lazy Crimes
// @namespace    http://tampermonkey.net/
// @version      1.0.2
// @description  Adds a spam crime button for everybody that should've stayed on crimes 1.0
// @author       Heartflower [2626587]
// @match        https://www.torn.com/loader.php?sid=crimes*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=torn.com
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    console.log('[HF] Lazy Crimes script running');

    // Variables to overwrite later on
    let nerve = 0;
    let currentHref = window.location.href;

    // See if there's any previously saved settings
    let settings = {};
    let savedSettings = JSON.parse(localStorage.getItem('hf-lazy-crimes-settings'));
    if (savedSettings) settings = savedSettings;

    function crimePage(retries = 30) {
        let titleBar = document.body.querySelector('.currentCrime___MN0T1 .titleBar___Cci85');
        let list = document.body.querySelector('.virtualList___noLef');
        let items = list?.querySelectorAll('.virtual-item');

        // If DOM isn't fully loaded, try again
        if (!titleBar || !list || !items || items.length < 2) {
            if (retries > 0) {
                setTimeout(() => crimePage(retries - 1), 100);
            } else {
                console.warn('[HF] Gave up looking for Crime Page items after 30 retries.');
            }
            return;
        }

        // Set variable for mobile to use later
        let mobile = document.body.querySelector('.area-mobile___BH0Ku');

        // If there's no button container yet, create it
        let btnContainer = document.body.querySelector('.hf-lazy-crimes-btn-container');
        if (!btnContainer) {
            btnContainer = createButtonContainer(titleBar);
        } else {
            // Don't keep adding buttons
            return;
        }

        // Create the "Lazy Crimes" button and check nerve value
        let button = createLazyButton();
        btnContainer.appendChild(button);
        disableButtons(nerve);

        // Variable to use later for certain crimes
        let ignoreNextClick = false;

        // If mobile scamming, make sure the icons stay up even if clicking the button
        if (mobile && window.location.href.includes('scamming')) {
            button.addEventListener('mousedown', (e) => {
                e.preventDefault(); // prevent focus shift
                e.stopImmediatePropagation(); // prevent other click handlers
                ignoreNextClick = true;
                button.click(); // trigger the actual click
            });
        }

        button.addEventListener('click', function () {
            // If already clicked with mousedown or other, then don't double click!
            if (ignoreNextClick) {
                ignoreNextClick = false;
                return;
            }

            // Find all "subcrimes"/items
            items = list.querySelectorAll('.virtual-item');
            let bestItem = null;

            // Different ways of finding the item to be clicked depending on the crime
            if (window.location.href.includes('searchforcash')) {
                bestItem = searchForCash(items);
            } else if (window.location.href.includes('shoplifting')) {
                bestItem = shoplifting(items);
            } else if (window.location.href.includes('pickpocketing')) {
                button.style.background = 'var(--default-blue-dark-color)';
                bestItem = pickpocketing(items);
            } else if (window.location.href.includes('hustling')) {
                bestItem = hustling(items);
            } else if (window.location.href.includes('cracking')) {
                bestItem = cracking(items);
            } else if (window.location.href.includes('forgery')) {
                forgery(items, false);
                return; // All the clicking is done in the forgery() function
            } else if (window.location.href.includes('scamming')) {
                scamming(items);
                return; // All the clicking is done in the scamming() function
            } else {
                bestItem = items[0];
            }

            // If no item found, then return
            if (bestItem === null) {
                if (window.location.href.includes('pickpocketing')) {
                    button.title = 'No target found on last click';
                    button.style.background = 'var(--default-base-important-color)';
                }

                return;
            }

            // Click the commit crime button if it exists and isn't disabled
            let commitButton = bestItem.querySelector('.commit-button');

            if (window.location.href.includes('hustling') && commitButton.classList.contains('disabled') && nerve >= 2) {
                button.title = `You don't have enough money on hand!`;
                button.style.background = 'var(--default-base-important-color)';
            } else {
                button.title = '';
            }

            if (commitButton && !commitButton.classList.contains('disabled')) commitButton.click();
        });

        // For shoplifting, create a Notorious button if enabled in settings
        if (window.location.href.includes('shoplifting') && settings.Notorious) {
            let notoriousBtn = createLazyButton();
            notoriousBtn.textContent = 'Notorious';
            notoriousBtn.style.marginLeft = '8px';
            if (mobile) notoriousBtn.textContent = '100%';

            btnContainer.appendChild(notoriousBtn);
            disableButtons(nerve);

            notoriousBtn.addEventListener('click', function() {
                let item = shoplifting(items, true);
                let commitButton = item.querySelector('.commit-button');
                if (commitButton && !commitButton.classList.contains('disabled')) commitButton.click();
            });
        }

        // For mobile search for cash, make the "search for cash" smaller so the icons can actually appear
        if (mobile && window.location.href.includes('searchforcash')) {
            let title = document.body.querySelector('.title___uzsf7');
            title.style.fontSize = 'small';
        }

        // For scamming, check if the morale script is installed - if not, prompt user to do so
        if (window.location.href.includes('scamming')) {
            setTimeout(function() {
                let moraleScript = document.body.querySelector('.cm-sc-settings');
                if (!moraleScript) {
                    let icon = document.body.querySelector('.hf-lazy-crimes-icon');
                    if (icon) {
                        icon.title = `Please install tobytorn [1617955]'s Crime Morale Script`;
                        icon.style.cursor = 'pointer';
                        icon.addEventListener('click', function() {
                            window.open(`https://www.torn.com/forums.php#/p=threads&f=67&t=16430177&b=0&a=0rh=82&`, '_blank', 'noopener');
                        });
                    }

                    button.style.background = 'var(--default-tabs-disabled-color)';
                    button.title = `Please install tobytorn [1617955]'s Crime Morale Script`;
                    button.addEventListener('click', function(e) {
                        e.preventDefault(); // prevent focus shift
                        e.stopImmediatePropagation(); // prevent other click handlers
                        ignoreNextClick = true;

                        window.open(`https://www.torn.com/forums.php#/p=threads&f=67&t=16430177&b=0&a=0rh=82&`, '_blank', 'noopener');
                    });
                    button.classList.add('hf-no-crime-morale');
                }
            }, 500);
        }
    }

    // HELPER function to create a container for the buttons
    function createButtonContainer(titleBar) {
        let div = document.createElement('div');
        div.classList.add('hf-lazy-crimes-btn-container');
        div.style.display = 'flex';
        div.style.alignItems = 'center';
        div.style.height = '20px';
        div.style.marginRight = 'auto';
        div.style.marginLeft = '8px';

        titleBar.insertBefore(div, titleBar.children[1]);

        return div;
    }

    // HELPER function to create "lazy crimes" or even merit buttons
    function createLazyButton() {
        let button = document.createElement('button');
        button.classList.add('hf-lazy-crimes-button');
        button.textContent = `I AM LAZY`;
        button.style.background = 'var(--default-blue-dark-color)';
        button.style.color = 'var(--btn-color)';
        button.style.borderRadius = '8px';
        button.style.cursor = 'pointer';
        button.style.fontWeight = 'bold';

        let mobile = document.body.querySelector('.area-mobile___BH0Ku');
        if (mobile) {
            button.textContent = 'LAZY';
            button.style.fontSize = 'smaller';
        }

        return button;
    }

    // HELPER function to find best item for SEARCH FOR CASH
    function searchForCash(items) {
        let highestPercentage = -Infinity;
        let bestItem = null;

        for (let item of items) {
            let percentageElement = item.querySelector('.densityTooltipTrigger___VG9Wy');
            let percentage = percentageElement.getAttribute('aria-label');

            let match = percentage.match(/\((\d+)%\)/);
            if (match) {
                let number = parseInt(match[1], 10);

                if (number > highestPercentage) {
                    highestPercentage = number;
                    bestItem = item;
                }
            }
        }

        return bestItem;
    }

    // MAIN function for BOOTLEGGING page
    function bootlegging(retries = 30) {
        let titleBar = document.body.querySelector('.currentCrime___MN0T1 .titleBar___Cci85');
        let genres = document.body.querySelectorAll('.genreStock___IT7ld');

        // If DOM hasn't fully loaded yet, try again
        if (!titleBar || !genres || genres.length < 2) {
            if (retries > 0) {
                setTimeout(() => bootlegging(retries - 1), 100);
            } else {
                console.warn('[HF] Gave up looking for Bootlegging to load after 30 retries.');
            }
            return;
        }

        // Set variable to check if mobile user or not
        let mobile = document.body.querySelector('.area-mobile___BH0Ku');

        // Create a button container of one doesn't exist yet
        let btnContainer = document.body.querySelector('.hf-lazy-crimes-btn-container');
        if (!btnContainer) {
            btnContainer = createButtonContainer(titleBar);
        } else {
            // Don't keep adding buttons
            return;
        }

        // Create lazy crimes button and check nerve
        let button = createLazyButton();
        btnContainer.appendChild(button);
        disableButtons(nerve);

        button.addEventListener('click', function () {
            let count = document.body.querySelector('.count___hBmtm');

            // If no blank DVDs, enlarge the button to add them
            if (Number(count.textContent) === 0) {
                count.parentNode.click();

                // Make the icon extra big so you can't miss it
                setTimeout(function() {
                    let selectItemBtn = document.body.querySelector('.popover___KwcuU .buttonWrap___h7dcO');
                    selectItemBtn.style.position = 'fixed';
                    selectItemBtn.style.zIndex = 99999;
                    selectItemBtn.style.scale = '2000%';
                    selectItemBtn.style.top = '0px';
                }, 500);

                return;
            }

            let commitButtons = document.body.querySelectorAll('.commit-button');
            let needStockElement = null;
            let needCopyingElement = null;

            // Ratio as per Emforus' guide
            let info = {
                'Action': 10 * 5,
                'Fantasy': 7 * 5,
                'Comedy': 7 * 5,
                'Drama': 5.5 * 5,
                'Thriller': 4 * 5,
                'Horror': 3 * 5,
                'Romance': 3 * 5,
                'Sci-Fi': 2 * 5,
            }

            // Loop through all genres until you find one that doesn't have enough stock yet
            for (let genre of genres) {
                let name = genre.querySelector('.genreName___kBqTz').textContent;
                let stock = Number(genre.querySelector('.currentStock___Bh9_b').textContent);
                let currentlyBusy = Number(genre.querySelector('.statusText___fRZso').textContent.replace('copying', '').trim());

                if (info[name] !== undefined && stock < info[name]) {
                    needStockElement = genre;
                }

                if (info[name] !== undefined && currentlyBusy < info[name]) {
                    needCopyingElement = genre;
                    break;
                }
            }

            if (needCopyingElement || needStockElement) {
                if (needCopyingElement) needStockElement = needCopyingElement;

                // Copy more of the needed stock!
                let selected = needStockElement.classList.contains('selected___UvibX');

                if (!selected) {
                    // If already selected, copy
                    needStockElement.click();
                } else {
                    // If not already selected, select
                    if (!commitButtons[0].classList.contains('disabled')) commitButtons[0].click();
                }
            } else {
                // Sell stock
                if (!commitButtons[1].classList.contains('disabled')) commitButtons[1].click();
            }
        });

        // Add "Online Entrepreneur" merit button if enabled
        if (settings['Online Entrepreneur']) {
            let onlineBtn = createLazyButton();
            onlineBtn.textContent = 'Online Entrepreneur';
            onlineBtn.style.marginLeft = '8px';
            if (mobile) onlineBtn.textContent = 'ON';

            btnContainer.appendChild(onlineBtn);
            disableButtons(nerve);

            onlineBtn.addEventListener('click', function () {
                let commitButtons = document.body.querySelectorAll('.commit-button');

                if (!commitButtons[2].textContent.includes('Collect') || !document.body.querySelector('.input___Pgrid')) {
                    console.warn('[HF Lazy Crimes] Online store does not exist yet');
                    commitButtons[2].click();
                    return;
                } else {
                    console.log('[HF Lazy Crimes] Online store exists');

                    // If the online store is disabled, enable
                    let input = document.body.querySelector('.input___Pgrid');
                    let onlineEnabled = input.checked;
                    if (!onlineEnabled) input.click();

                    return;
                }

                let needStockElement = null;
                let needCopyingElement = null;

                let info = {
                    'Action': (10 * 482) + (10 * 5),
                    'Fantasy': (7 * 482) + (7 * 5),
                    'Comedy': (7 * 482) + (7 * 5),
                    'Drama': (5.5 * 482) + (5.5 * 5),
                    'Thriller': (4 * 482) + (4 * 5),
                    'Horror': (3 * 482) + (3 * 5),
                    'Romance': (3 * 482) + (3 * 5),
                    'Sci-Fi': (2 * 482) + (2 * 5),
                }

                for (let genre of genres) {
                    let name = genre.querySelector('.genreName___kBqTz').textContent;
                    let stock = Number(genre.querySelector('.currentStock___Bh9_b').textContent);
                    let currentlyBusy = Number(genre.querySelector('.statusText___fRZso').textContent.replace('copying', '').trim());

                    if (info[name] !== undefined && stock < info[name]) {
                        needStockElement = genre;
                    }

                    if (info[name] !== undefined && currentlyBusy < info[name]) {
                        needCopyingElement = genre;
                        break;
                    }
                }

                if (needCopyingElement || needStockElement) {
                    if (needCopyingElement) needStockElement = needCopyingElement;

                    // Copy more of the needed stock!
                    let selected = needStockElement.classList.contains('selected___UvibX');

                    if (!selected) {
                        // If already selected, copy
                        needStockElement.click();
                    } else {
                        // If not already selected, select
                        commitButtons[0].click();
                    }
                } else {
                    // Sell stock
                    commitButtons[1].click();
                }
            });
        }

        // Add "Cinephile" merit button if enabled
        if (settings.Cinephile) {
            let cineBtn = createLazyButton();
            cineBtn.textContent = 'Cinephile';
            cineBtn.style.marginLeft = '8px';
            if (mobile) cineBtn.textContent = '10K';

            btnContainer.appendChild(cineBtn);
            disableButtons(nerve);

            cineBtn.addEventListener('click', function () {
                let count = document.body.querySelector('.count___hBmtm');
                if (Number(count.textContent) === 0) {
                    count.parentNode.click();

                    setTimeout(function() {
                        let selectItemBtn = document.body.querySelector('.popover___KwcuU .buttonWrap___h7dcO');
                        selectItemBtn.style.position = 'fixed';
                        selectItemBtn.style.zIndex = 99999;
                        selectItemBtn.style.scale = '2000%';
                        selectItemBtn.style.top = '0px';
                    }, 500);

                    return;
                }

                let preferredGenre = null;

                let statistics = document.body.querySelectorAll('.statistic___YkyjL');
                for (let statistic of statistics) {
                    let label = statistic.querySelector('.label___gPPwp');
                    label = label.textContent.toLowerCase();

                    if (!label.includes('dvds sold')) continue;

                    let value = statistic.querySelector('.value___S0RNN');
                    value = Number(value.textContent.replace(/,/g, ''));

                    if (value < 10000) {
                        label = label.replace(' dvds sold', '').trim();
                        preferredGenre = label;
                        break;
                    }
                }

                return;

                let commitButtons = document.body.querySelectorAll('.commit-button');

                let needStockElement = null;
                let needCopyingElement = null;

                let info = {
                    'Action': 10 * 5,
                    'Fantasy': 7 * 5,
                    'Comedy': 7 * 5,
                    'Drama': 5.5 * 5,
                    'Thriller': 4 * 5,
                    'Horror': 3 * 5,
                    'Romance': 3 * 5,
                    'Sci-Fi': 2 * 5,
                }

                for (let genre of genres) {
                    let name = genre.querySelector('.genreName___kBqTz').textContent;
                    let stock = Number(genre.querySelector('.currentStock___Bh9_b').textContent);
                    let currentlyBusy = Number(genre.querySelector('.statusText___fRZso').textContent.replace('copying', '').trim());

                    if (info[name] !== undefined && stock < info[name]) {
                        needStockElement = genre;
                    }

                    if (info[name] !== undefined && currentlyBusy < info[name]) {
                        needCopyingElement = genre;
                        break;
                    }
                }

                if (needCopyingElement || needStockElement) {
                    if (needCopyingElement) needStockElement = needCopyingElement;

                    // Copy more of the needed stock!
                    let selected = needStockElement.classList.contains('selected___UvibX');

                    if (!selected) {
                        // If already selected, copy
                        needStockElement.click();
                    } else {
                        // If not already selected, select
                        if (!commitButtons[0].classList.contains('disabled')) commitButtons[0].click();
                    }
                } else {
                    // Sell stock
                    if (!commitButtons[1].classList.contains('disabled')) commitButtons[1].click();
                }
            });
        }

    }

    // MAIN function for the GRAFFITI page
    function graffiti(retries = 30) {
        let titleBar = document.body.querySelector('.currentCrime___MN0T1 .titleBar___Cci85');
        let list = document.body.querySelector('.virtualList___noLef');
        let items = list?.querySelectorAll('.virtual-item');

        // If DOM hasn't fully loaded yet, try again
        if (!titleBar || !list || !items || items.length < 2) {
            if (retries > 0) {
                setTimeout(() => graffiti(retries - 1), 100);
            } else {
                console.warn('[HF] Gave up looking for Crime Page items after 30 retries.');
            }
            return;
        }

        // Create button container if it doesn't exist yet
        let btnContainer = document.body.querySelector('.hf-lazy-crimes-btn-container');
        if (!btnContainer) {
            btnContainer = createButtonContainer(titleBar);
        } else {
            // Don't keep adding buttons
            return;
        }

        // Create the lazy crimes button
        let button = createLazyButton();
        btnContainer.appendChild(button);
        disableButtons(nerve);

        let icon = document.body.querySelector('.hf-lazy-crimes-icon');

        button.addEventListener('click', function (event) {
            for (let item of items) {
                let tags = Number(item.querySelector('.tagsCount___meTI4').textContent);

                if (tags < 500) {
                    // Do the first one it finds below 500
                    let sprayCanButton = item.querySelector('.sprayCanButton___URxYK');
                    let unselected = sprayCanButton.querySelector('.dim___AtLY0');

                    // If no can selected, make black spray can EXTRA big
                    if (unselected) {
                        sprayCanButton.click();

                        setTimeout(function() {
                            let rect = button.getBoundingClientRect();
                            let selectCanButton = document.body.querySelector('.buttonWrap___h7dcO');
                            selectCanButton.style.position = 'fixed';
                            selectCanButton.style.zIndex = 99999;
                            selectCanButton.style.scale = '2000%';
                            selectCanButton.style.top = '0px';
                        }, 500);

                        break;
                    } else {
                        // Do the graffiti
                        let commitButton = item.querySelector('.commit-button');
                        if (!commitButton.classList.contains('disabled')) commitButton.click();
                        break;
                    }
                }
            }
        });
    }

    // MAIN function for the SEARCH FOR CASH merits
    function searchForCashMerits(retries = 30) {
        let titleBar = document.body.querySelector('.currentCrime___MN0T1 .titleBar___Cci85');
        let list = document.body.querySelector('.virtualList___noLef');
        let items = list?.querySelectorAll('.virtual-item');

        // If DOM isn't fully loaded, try again
        if (!titleBar || !list || !items || items.length < 2) {
            if (retries > 0) {
                setTimeout(() => searchForCashMerits(retries - 1), 100);
            } else {
                console.warn('[HF] Gave up looking for Crime Page items after 30 retries.');
            }
            return;
        }

        // Variable to check if mobile user or bit
        let mobile = document.body.querySelector('.area-mobile___BH0Ku');

        // Find button container or add if it doesn't exist
        let btnContainer = document.body.querySelector('.hf-lazy-crimes-btn-container');
        if (!btnContainer) btnContainer = createButtonContainer(titleBar);

        // Create the spoiled rotten button if enabled
        if (settings['Spoiled Rotten']) {
            let spoiledBtn = createLazyButton();
            spoiledBtn.textContent = 'Spoiled Rotten';
            if (mobile) spoiledBtn.textContent = 'R';
            spoiledBtn.style.marginLeft = '8px';
            btnContainer.appendChild(spoiledBtn);
            disableButtons(nerve);

            spoiledBtn.addEventListener('click', function () {
                items = list.querySelectorAll('.virtual-item');

                let trash = items[0];
                let commitButton = trash.querySelector('.commit-button');
                if (commitButton && !commitButton.classList.contains('disabled')) commitButton.click();
            });
        }

        // Create the shorte thing button if enabled
        if (settings['Shore Thing']) {
            let sandBtn = createLazyButton();
            sandBtn.textContent = 'Shore Thing';
            if (mobile) sandBtn.textContent = 'S';
            sandBtn.style.marginLeft = '8px';
            btnContainer.appendChild(sandBtn);
            disableButtons(nerve);

            sandBtn.addEventListener('click', function () {
                items = list.querySelectorAll('.virtual-item');

                let sand = items[3];
                let commitButton = sand.querySelector('.commit-button');
                if (commitButton) commitButton.click();
            });
        }
    }

    // HELPER function to decide best item in SHOPLIFTING crime
    function shoplifting(items, notorious) {
        let highestDisabled = 0;
        let safestCrime = null;
        let sweetNotoriety = 0;
        let bobNotoriety = 0;

        for (let item of items) {
            let disabled = 0;

            let securities = item.querySelectorAll('.securityMeasure___Zhpzp');
            for (let security of securities) {
                if (security.classList.contains('blank___L7Z5b')) continue;
                if (!security.classList.contains('disabled___Enrnq')) continue;
                disabled++;
            }

            let notorietyElement = item.querySelector('.notorietyBar___hikrJ');
            let notoriety = notorietyElement.getAttribute('aria-label');
            if (notoriety !== 'No notoriety') {
                notoriety = Math.ceil(Number(notoriety.replace('Notoriety: ', '').replace('%', '')));
            } else {
                notoriety = 0;
            }

            if (notorious) {
                if (notoriety === 100) continue;
                safestCrime = item;
                break;
            } else {
                if (item === items[0]) sweetNotoriety = notoriety;
                if (item === items[1]) bobNotoriety = notoriety;

                if (disabled > highestDisabled && notoriety < 90) {
                    highestDisabled = disabled;
                    safestCrime = item;
                }
            }
        }

        if (!safestCrime) {
            if (sweetNotoriety < 90) {
                safestCrime = items[0]; // sweet shop
            } else if (bobNotoriety < 90) {
                safestCrime = items[1]; // bits n bob
            } else {
                safestCrime = items[0]; // sweet shop
            }
        }

        return safestCrime;
    }

    // HELPER function to decide best item for PICKPOCKETING crime
    function pickpocketing(items) {
        // Variable to check if mobile user or bit
        let mobile = document.body.querySelector('.area-mobile___BH0Ku');

        let availableTarget = null;

        let skillElement = document.body.querySelector('.progressFill___zsgNm');
        let skill = Number(skillElement.getAttribute('aria-label').replace('Crime skill: ', ''));

        let targets = {
            'Drunk man': { minskill: 1, maxskill: 20, avoidphsyical: 'Muscular', avoidactivity: 'Distracted' },
            'Drunk woman': { minskill: 1, maxskill: 20, avoidphysical: null, avoidactivity: 'Distracted' },
            'Elderly man': { minskill: 1, maxskill: 20, avoidphysical: null, avoidactivity: null },
            'Elderly woman': { minskill: 1, maxskill: 20, avoidphysical: null, avoidactivity: null },
            'Homeless person': { minskill: 1, maxskill: 20, avoidphysical: null, avoidactivity: 'Loitering' },
            'Junkie': { minskill: 1, maxskill: 25, avoidphysical: 'Muscular', avoidactivity: 'Loitering' },
            'Young man': { minskill: 20, maxskill: 70, avoidphysical: null, avoidactivity: null },
            'Young woman': { minskill: 20, maxskill: 70, avoidphysical: null, avoidactivity: null },
            'Student': { minskill: 20, maxskill: 70, avoidphysical: 'Athletic', avoidactivity: null },
            'Laborer': { minskill: 20, maxskill: 70, avoidphysical: null, avoidactivity: 'Distracted' },
            'Postal worker': { minskill: 20, maxskill: 70, avoidphysical: null, avoidactivity: null },
            'Rich kid': { minskill: 40, maxskill: 90, avoidphysical: null, avoidactivity: null },
            'Sex worker': { minskill: 40, maxskill: 90, avoidphysical: null, avoidactivity: null },
            'Thug': { minskill: 40, maxskill: 90, avoidphysical: null, avoidactivity: null },
            'Businessman': { minskill: 65, maxskill: 100, avoidphysical: 'Skinny', avoidactivity: 'Walking' },
            'Businesswoman': { minskill: 65, maxskill: 100, avoidphysical: 'Heavy', avoidactivity: 'Walking' },
            'Gang member': { minskill: 65, maxskill: 100, avoidphysical: 'Muscular', avoidactivity: null },
            'Jogger': { minskill: 65, maxskill: 100, avoidphysical: null, avoidactivity: null },
            'Cyclist': { minskill: 90, maxskill: 100, avoidphysical: null, avoidactivity: null },
        }

        let activityIcons = {
            'Cycling': 0,
            'Distracted': -34,
            'Music': -102,
            'Loitering': -136,
            'Phone': -170,
            'Running': -204,
            'Soliciting': -238,
            'Stumbling': -272,
            'Walking': -306,
            'Begging': -340
        };

        for (let item of items) {
            let story = item.querySelector('.story___GmRvQ');
            if (story) continue;

            if (item.textContent === '') continue;
            let titleAndProps = item.querySelector('.titleAndProps___DdeVu div').textContent; // e.g. Young Man, Cyclist
            titleAndProps = titleAndProps.split(' (')[0]; // removes " (Moderately Unsafe)" and similar

            let physicalProps = item.querySelector('.physicalProps___E5YrR').textContent; // e.g. Athletic (info), Skinny (info)
            let activity = item.querySelector('.activity___e7mdA').textContent; // e.g. Walking, Distracted
            let commitButton = item.querySelector('.commit-button');

            if (mobile) {
                let activityIcon = item.querySelector('.icon___VfCk2');
                let background = Number(getComputedStyle(activityIcon).backgroundPositionY.replace('px', '').trim());
                activity = Object.keys(activityIcons).find(key => activityIcons[key] === background);
            }

            if (commitButton.classList.contains('disabled')) continue;
            if (!targets[titleAndProps]) continue;
            if (physicalProps.includes(targets[titleAndProps].avoidphysical)) continue;
            if (activity.includes(targets[titleAndProps].avoidactivity)) continue;
            if (skill < targets[titleAndProps].minskill) continue;

            availableTarget = item;
            break;
        }

        return availableTarget;
    }

    // MAIN function for the BURGLARY page
    function burglary(retries = 30) {
        let titleBar = document.body.querySelector('.currentCrime___MN0T1 .titleBar___Cci85');
        let categories = document.body.querySelectorAll('.targetCategoryButton___Rjnpf');

        // If page hasn't fully loaded yet, try again
        if (!titleBar || !categories || categories.length < 3) {
            if (retries > 0) {
                setTimeout(() => burglary(retries - 1), 100);
            } else {
                console.warn('[HF] Gave up looking for Burglary categories after 30 retries.');
            }
            return;
        }

        // Variable to check if user is mobile user or not
        let mobile = document.body.querySelector('.area-mobile___BH0Ku');

        // Add button container if it doesn't exist yet
        let btnContainer = document.body.querySelector('.hf-lazy-crimes-btn-container');
        if (!btnContainer) {
            btnContainer = createButtonContainer(titleBar);
        } else {
            // Don't keep adding buttons
            return;
        }

        // Create button
        let button = createLazyButton();
        btnContainer.appendChild(button);
        disableButtons(nerve);

        button.addEventListener('click', function () {
            let list = document.body.querySelector('.virtualList___noLef');
            let items = list?.querySelectorAll('.virtual-item');

            if (items.length > 1) {
                for (let item of items) {
                    if (item === items[0]) continue;

                    let progressBar = Number(item.querySelector('.progressBar___JhMrP').getAttribute('aria-label').replace('Confidence ', '').replace('%', ''));
                    let commitButtons = item.querySelectorAll('.commit-button');

                    // Make sure you scout until you've reached 80 confidence
                    if (progressBar < 80 && !commitButtons[0].classList.contains('disabled')) {
                        commitButtons[0].click();
                        return;
                    } else if (progressBar >= 80 && !commitButtons[1].classList.contains('disabled')) {
                        commitButtons[1].click();
                        return;
                    }
                }
            }

            // Scout any residential
            categories = document.body.querySelectorAll('.targetCategoryButton___Rjnpf');
            if (!categories[0].classList.contains('selected___m5crj')) {
                categories[0].click();
                return;
            }

            let scoutButton = document.body.querySelector('.commit-button');
            scoutButton.click();
        });

        // Add "key to the city" button if enabled
        if (settings['Key to the City']) {
            let targets = {
                'Tool Shed': 'Residential',
                'Beach Hut': 'Residential',
                'Mobile Home': 'Residential',
                'Bungalow': 'Residential',
                'Cottage': 'Residential',
                'Apartment': 'Residential',
                'Suburban Home': 'Residential',
                'Secluded Cabin': 'Residential',
                'Farmhouse': 'Residential',
                'Lake House': 'Residential',
                'Luxury Villa': 'Residential',
                'Manor House': 'Residential',
                'Self Storage Facility': 'Commercial',
                'Postal Office': 'Commercial',
                'Funeral Directors': 'Commercial',
                'Market': 'Commercial',
                'Cleaning Agency': 'Commercial',
                'Barbershop': 'Commercial',
                'Liquor Store': 'Commercial',
                'Dentists Office': 'Commercial',
                'Chiropractors': 'Commercial',
                'Recruitment Agency': 'Commercial',
                'Advertising Agency': 'Commercial',
                'Shipyard': 'Industrial',
                'Dockside Warehouse': 'Industrial',
                'Farm Storage Unit': 'Industrial',
                'Printing Works': 'Industrial',
                'Brewery': 'Industrial',
                'Truckyard': 'Industrial',
                'Old Factory': 'Industrial',
                'Slaughterhouse': 'Industrial',
                'Paper Mill': 'Industrial',
                'Foundry': 'Industrial',
                'Fertilizer Plant': 'Industrial'
            }

            let keyBtn = createLazyButton();
            keyBtn.textContent = 'Key to the City';
            if (mobile) keyBtn.textContent = 'KEY';
            keyBtn.style.marginLeft = '8px';
            btnContainer.appendChild(keyBtn);
            disableButtons(nerve);

            keyBtn.addEventListener('click', function () {
                let done = false;

                // Check amount already burgled out of 10k
                for (let target in targets) {
                    let statistics = document.body.querySelectorAll('.statistic___YkyjL');
                    for (let statistic of statistics) {
                        let label = statistic.querySelector('.label___gPPwp').textContent.replace('burgled', '').trim();
                        let value = statistic.querySelector('.value___S0RNN').textContent;
                        value = parseInt(value.split('/')[0].trim(), 10);

                        if (target === label && value > 0) {
                            delete targets[target];
                        }
                    }
                }

                // User has already gotten the merit
                if (Object.keys(targets).length === 0) {
                    done = true;
                    return;
                }

                categories = document.body.querySelectorAll('.targetCategoryButton___Rjnpf');
                let list = document.body.querySelector('.virtualList___noLef');
                let items = list?.querySelectorAll('.virtual-item');

                for (let target in targets) {
                    for (let item of items) {
                        let itemName = item.querySelector('.crimeOptionSection___hslpu').textContent;

                        // Scout and burgle the still required targets for the merit
                        if (itemName.includes(target)) {
                            let progressBar = Number(item.querySelector('.progressBar___JhMrP').getAttribute('aria-label').replace('Confidence ', '').replace('%', ''));
                            let commitButtons = item.querySelectorAll('.commit-button');

                            if (progressBar < 80 && !commitButtons[0].classList.contains('disabled')) {
                                commitButtons[0].click();
                                done = true;
                                break;
                            } else if (progressBar >= 80 && !commitButtons[1].classList.contains('disabled')) {
                                commitButtons[1].click();
                                done = true;
                                break;
                            }
                        }
                    }

                    if (done) return;

                    // If none available, then turn on the category of what still needs to be done
                    let categoryIndex = {
                        'Residential': 0,
                        'Commercial': 1,
                        'Industrial': 2
                    };

                    let type = targets[target];
                    let index = categoryIndex[type];

                    if (index !== undefined) {
                        if (!categories[index].classList.contains('selected___m5crj')) {
                            let disabled = categories[index].getAttribute('aria-disabled');
                            if (disabled == false) continue;

                            categories[index].click();
                            done = true;
                            break;
                        } else {
                            let scoutButton = document.body.querySelector('.commit-button');

                            let disabled = scoutButton.getAttribute('aria-disabled');
                            if (disabled == false) continue;

                            scoutButton.click();
                            done = true;
                            break;
                        }
                    }

                    if (done) return;
                }
            });
        }
    }

    // HELPER function to find best item for HUSTLING crime
    function hustling(items) {
        let preferredCrime = null;

        for (let item of items) {
            let audience = item.querySelector('.audienceSection___f3jVs');
            if (audience) {
                let info = audience.querySelector('.srOnly___Nqywa').textContent;

                // If no audience, gather audience
                if (info && info === 'No audience') {
                    let commitButton = item.querySelector('.commit-button');
                    commitButton.click();
                    return;
                }
            }

            let technique = item.querySelector('.techniqueBar___JaXl6');
            if (!technique) continue;
            technique = technique.getAttribute('aria-label').replace('Technique: ', '');

            // Unlock all techniques first
            let [ currentTech, maxTech ] = technique.match(/\d+/g).map(Number);
            if (currentTech === maxTech) continue;

            preferredCrime = item;
            break;
        }

        // If all techniques unlocked
        if (!preferredCrime) preferredCrime = items[1]; // Cornhole

        return preferredCrime;
    }

    // MAIN function for the DISPOSAL crime
    function disposal(retries = 30) {
        let info = {
            'Biological Waste': 'Sink',
            'Body Part': 'Dissolve',
            'Building Debris': 'Sink',
            'Dead Body': 'Bury',
            'Document': 'Burn',
            'Firearm': 'Sink',
            'General Waste': 'Bury',
            'Industrial Waste': 'Sink',
            'Murder Weapon': 'Sink',
            'Old Furniture': 'Burn',
            'Broken Appliance': 'Sink',
            'Vehicle': 'Burn',
        };

        let titleBar = document.body.querySelector('.currentCrime___MN0T1 .titleBar___Cci85');
        let list = document.body.querySelector('.virtualList___noLef');
        let items = list?.querySelectorAll('.virtual-item');

        // If DOM isn't fully loaded, try again
        if (!titleBar || !list || !items || items.length < 2) {
            if (retries > 0) {
                setTimeout(() => disposal(retries - 1), 100);
            } else {
                console.warn('[HF] Gave up looking for Disposal items after 30 retries.');
            }
            return;
        }

        // Variable to check if mobile user
        let mobile = document.body.querySelector('.area-mobile___BH0Ku');

        // Add button container if it doesn't exist yet
        let btnContainer = document.body.querySelector('.hf-lazy-crimes-btn-container');
        if (!btnContainer) {
            btnContainer = createButtonContainer(titleBar);
        } else {
            // Don't keep adding buttons
            return;
        }

        // Create lazy crimes button
        let button = createLazyButton();
        btnContainer.appendChild(button);
        disableButtons(nerve);

        button.addEventListener('click', function () {
            items = list.querySelectorAll('.virtual-item');
            let firstItem = items[1];
            let stop = false;

            for (let item of items) {
                let methods = item.querySelectorAll('.methodButton___lCgpf');
                if (!methods || methods.length < 2) continue;

                let name = item.querySelector('.crimeOptionSection___hslpu').firstChild.textContent.trim();

                for (let method of methods) {
                    let type = method.getAttribute('aria-label');
                    let commitButton = item.querySelector('.commit-button');

                    // If preferred method isn't selected yet, select it - else do the crime
                    if (info[name] && info[name] === type) {
                        if (!method.classList.contains('selected___TKH3R')) {
                            method.click();
                        } else {
                            if (commitButton.classList.contains('disabled')) continue;
                            commitButton.click();
                        }

                        stop = true;
                        break;
                    }
                }

                if (stop) break;
            }
        });

        // Add dissolving agent button if enabled
        if (settings['Dissolving Agent']) {
            let dissolvingBtn = createLazyButton();
            dissolvingBtn.textContent = 'Dissolving Agent';
            if (mobile) dissolvingBtn.textContent = 'ACID';
            dissolvingBtn.style.marginLeft = '8px';
            btnContainer.appendChild(dissolvingBtn);
            disableButtons(nerve);

            let deadBody = false;
            for (let item of items) {
                let name = item.querySelector('.crimeOptionSection___hslpu');
                if (!name) continue;

                name = name.firstChild;
                name = name.textContent.trim();

                if (name === 'Dead Body') {
                    deadBody = true;
                }
            }

            // If no dead body, then add a warning for it
            if (!deadBody || deadBody === false) {
                setTimeout(function() {
                    dissolvingBtn.style.background = 'var(--default-tabs-disabled-color)';
                    dissolvingBtn.title = 'No Dead Body in sight!';
                    dissolvingBtn.classList.add('hf-no-body');
                }, 10);

                dissolvingBtn.style.background = 'var(--default-tabs-disabled-color)';
                dissolvingBtn.title = 'No Dead Body in sight!';

                return;
            }

            dissolvingBtn.addEventListener('click', function() {
                items = list.querySelectorAll('.virtual-item');

                for (let item of items) {
                    let methods = item.querySelectorAll('.methodButton___lCgpf');
                    if (!methods || methods.length < 2) continue;

                    let name = item.querySelector('.crimeOptionSection___hslpu').firstChild.textContent.trim();

                    // Dissolve the dead body if found
                    if (name === 'Dead Body') {
                        let commitButton = item.querySelector('.commit-button');
                        let method = methods[4];

                        if (!method.classList.contains('selected___TKH3R')) {
                            method.click();
                            return;
                        } else {
                            if (commitButton.classList.contains('disabled')) continue;
                            commitButton.click();
                            return;
                        }
                    }
                }
            });
        }
    }

    // HELPER function to find the best item for the CRACKING crime
    function cracking(items) {
        let leastSlots = -Infinity;
        let bestItem = null;

        for (let item of items) {

            let commitButton = item.querySelector('.commit-button');
            if (!commitButton) continue;

            if (commitButton.classList.contains('disabled')) continue;

            let type = item.querySelector('.title___kEtkc');

            // Finish started crackings first
            if (type) type = type.textContent;

            if (!type) {
                let nerveNeeded = item.querySelector('.nerve___i4mpF')
                if (!nerveNeeded) continue;

                nerveNeeded = nerve.textContent;
                if (Number(nerveNeeded) === 5) type = 'crack';
            }

            if (type && type == 'crack') {
                bestItem = item;
                return bestItem;
            }

            let slotDummies = item.querySelectorAll('.charSlotDummy___s11h5');
            let amount = slotDummies.length;

            if (amount > leastSlots) {
                leastSlots = amount;
                bestItem = item;
            }
        }

        return bestItem;
    }

    // HELPER function to find and click the best item in the FORGERY crime
    function forgery(items, forced) {
        let done = false;

        if (items.length < 2 || forced) {
            let item = items[0];
            let dropdown = item.querySelector('.dropdownMainWrapper___PjDiT');
            if (dropdown) {
                let current = dropdown.querySelector('.optionWithLevelRequirement___cHH35').textContent;

                if (current.includes('Parking Permit')) {
                    // Begin project
                    let commitButton = item.querySelector('.commit-button');
                    commitButton.click();
                    return null;
                } else {
                    // Select parking permit
                    let dropdownLI = item.querySelector('#option-Parking-Permit-212');
                    dropdownLI.click();
                    return null;
                }
            }
        } else {
            for (let item of items) {
                let dropdown = item.querySelector('.dropdownMainWrapper___PjDiT');
                if (dropdown) continue;

                let materials = item.querySelectorAll('.itemCell___aZaUE');

                // If some material is unavailable, then select it
                for (let material of materials) {
                    if (!material) continue;

                    let amountLeft = material.querySelector('span')?.textContent?.replace('%', '');
                    if (amountLeft == 0) {
                        let consume = material.querySelector('.consume___VXIEH');
                        if (consume) continue;

                        let unavailable = item.classList.contains('hf-unavailable-inventory');
                        if (unavailable) continue;

                        material.parentNode.click();

                        let selectItemBtn = null;

                        setTimeout(function() {
                            selectItemBtn = document.body.querySelector('.importItemPopover___ACpCG .buttonWrap___h7dcO');
                            if (!selectItemBtn) {
                                item.classList.add('hf-unavailable-inventory');

                                return;
                            }

                            selectItemBtn.style.position = 'fixed';
                            selectItemBtn.style.zIndex = 99999;
                            selectItemBtn.style.scale = '2000%';
                            selectItemBtn.style.top = '0px';
                        }, 500);

                        done = true;
                        break;
                    }
                }

                if (done) break;

                let commitButton = item.querySelector('.commit-button');
                if (commitButton.classList.contains('disabled')) continue;

                commitButton.click();
                done = true;
                break;
            }

            if (!done) forgery(items, true);
            return null;
        }
    }

    // HELPER function to find and click the best item in the SCAMMING crime
    function scamming(items, forcespam) {
        let done = false;

        let mobile = document.body.querySelector('.area-mobile___BH0Ku');

        let commitButtons = document.body.querySelectorAll('.commit-button');

        // If emails less than 20k, farm emails
        let emails = Number(document.body.querySelector('.count___dBcR7').textContent.replace(',', ''));
        if (emails < 20000 && !commitButtons[0].classList.contains('disabled')) {
            commitButtons[0].click();
            done = true;
            return;
        }

        if (done) return;

        let scraperPhisher = document.body.querySelectorAll('.scraperPhisher___oy1Wn');

        // If scraper wanted and not available, try to get it
        if (settings.Scraper) {
            if (!scraperPhisher || scraperPhisher.length < 1) {
                commitButtons[0].click();
                done = true;
                return;
            } else {
                let found = false;

                for (let icon of scraperPhisher) {
                    let ariaLabel = icon.getAttribute('aria-label');
                    if (ariaLabel === "Scraper active") found = true;
                }

                if (found === false && !commitButtons[0].classList.contains('disabled')) {
                    commitButtons[0].click();
                    done = true;
                    return;
                }
            }
        }

        if (done) return;

        // If phisher wanted and not available, try to get it
        if (settings.Phisher) {
            if (!scraperPhisher || scraperPhisher.length < 1) {
                commitButtons[0].click();
                done = true;
                return;
            } else {
                let found = false;

                for (let icon of scraperPhisher) {
                    let ariaLabel = icon.getAttribute('aria-label');
                    if (ariaLabel === "Phisher active") found = true;
                }

                if (found === false && !commitButtons[0].classList.contains('disabled')) {
                    commitButtons[0].click();
                    done = true;
                    return;
                }
            }
        }

        if (done) return;

        if (items.length < 4 || forcespam) {
            // fetch selected dropdown
            let selectedDropdown = document.body.querySelector('.dropdownMainWrapper___PjDiT');

            let dropdown = document.body.querySelector('.dropdown-additional-content');

            // Reverse array to start high to low
            let options = Array.from(dropdown.querySelectorAll('li')).reverse();

            // If diminished, then find not-diminished options
            for (let option of options) {
                if (option.classList.contains('diminished')) continue;

                if (option.getAttribute('aria-disabled') == 'true') continue;

                let optionName = [...option.querySelector('.optionWithLevelRequirement___cHH35').childNodes]
                .find(node => node.nodeType === Node.TEXT_NODE)?.textContent.trim() || '';

                let selectedName = [...selectedDropdown.querySelector('.optionWithLevelRequirement___cHH35').childNodes]
                .find(node => node.nodeType === Node.TEXT_NODE)?.textContent.trim() || '';

                if (optionName === selectedName) {
                    let diminished = selectedDropdown.querySelector('button .diminishedIconWrapper___ntun9');
                    if (!diminished && !commitButtons[1].classList.contains('disabled')) {
                        commitButtons[1].click();
                        done = true;
                        return;
                    }
                }

                option.click();
                done = true;
                return;
            }
        }

        if (done) return;


        let options = ['strong', 'soft', 'back', 'accelerate', 'capitalize'];


        for (let item of items) {
            let emails = item.querySelector('.emailAddresses___ky_qG');
            if (emails) continue;

            let dropdown = item.querySelector('.dropdownMainWrapper___PjDiT');
            if (dropdown) continue;

            let abandonInfo = item.querySelector('.abandon-confirmation');
            if (abandonInfo && !abandonInfo.classList.contains('hidden___omYpZ')) {
                abandonInfo.querySelector('button').click();
                done = true;
                return;
            }

            let commitButton = item.querySelector('.commit-button');
            if (!commitButton) continue;

            let hesitation = item.querySelector('.hesitation___Hk0Ed');
            if (hesitation) continue;

            let buttonLabel = commitButton.getAttribute('aria-label');
            if (buttonLabel === 'You have already scammed this target') continue;

            let read = commitButton.querySelector('.noNerveCost___BCwZI');
            if (mobile && !read) read = commitButton.querySelector('#iconmonstr-eye-6-2');

            if (read && !commitButton.classList.contains('disabled')) {
                commitButton.click();
                done = true;
                return;
            }

            let crime = item.querySelector('.crime-option');
            let moraleInfo = crime.getAttribute('data-cm-action');
            if (!moraleInfo) continue;

            if (moraleInfo === "abandon" && !mobile) {
                let quitButton = item.querySelector('.avatarButton___AQjYM');
                if (quitButton) {
                    quitButton.click();
                    done = true;
                    return;
                }
            }

            if (buttonLabel === 'Resolve, 3 nerve') {
                commitButton.click();
                done = true;
                return;
            }

            let index = options.findIndex(option => moraleInfo === option);
            if (index < 0) continue;

            // Different layout for mobile
            if (mobile) {
                let unselected = item.querySelector('.responseToggleQuestionMark___eHwpF');
                let responseWrapper = item.querySelector('.tabletResponseSelector___pEUzk');

                if (responseWrapper && !unselected) {
                    // If no response selected yet, select response in responsewrapper

                    let selected = item.querySelector('.selectedTabletResponseTypeCircle___pY4g4 g').id;

                    let responses = item.querySelectorAll('.response-type-button');
                    let recommended = responses[index].querySelector('g').id;

                    if (recommended === selected) {
                        if (commitButton.classList.contains('disabled')) continue;

                        commitButton.click();
                        done = true;
                        return;
                    } else {
                        responses[index].click();
                        done = true;
                        return;
                    }

                } else if (!responseWrapper && unselected) {
                    // If no response selected yet and responsewrapper not available, open responsewrapper

                    let expandButton = item.querySelector('.expandResponseTypeButton___RQkvW');
                    expandButton.click();
                    done = true;
                    return;
                } else if (!unselected) {
                    // If response selected, do crime

                    if (commitButton.classList.contains('disabled')) continue;

                    commitButton.click();
                    done = true;
                    return;
                } else {
                    // If no response selected, select response

                    let responses = item.querySelectorAll('.response-type-button');

                    responses[index].click();
                    done = true;
                    return;
                }
            } else {
                // Not mobile, but desktop

                let responses = item.querySelectorAll('.response-type-button');

                if (!responses[index].classList.contains('selected___jDOCY')) {
                    // If no response selected, select it
                    responses[index].click();
                    done = true;
                    return;
                } else {
                    // If response selected, do the crime
                    if (commitButton.classList.contains('disabled')) continue;

                    commitButton.click();
                    done = true;
                    return;
                }
            }
        }

        if (!done) {
            // If no available items, spam some instead
            scamming(items, true);
        }
    }

    // Add the information button to the title bar
    function addInfoButton(info, retries = 30) {
        let titleBar = document.body.querySelector('.currentCrime___MN0T1 .titleBar___Cci85');

        // If DOM isn't fully loaded, try again
        if (!titleBar) {
            if (retries > 0) {
                setTimeout(() => addInfoButton(info, retries - 1), 100);
            } else {
                console.warn('[HF] Gave up looking for Crime Page items after 30 retries.');
            }
            return;
        }

        let icon = document.createElement('div');
        icon.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
  <circle cx="12" cy="12" r="10" stroke="var(--default-base-navy-color)" stroke-width="2" fill="none" />
  <text x="12" y="13" text-anchor="middle" dominant-baseline="middle" font-size="8" fill="var(--default-base-navy-color)" font-family="Arial, sans-serif">
    LC
  </text>
</svg>`;
        icon.classList.add('hf-lazy-crimes-icon');
        icon.style.marginLeft = '6px';
        icon.style.cursor = 'help';
        icon.title = info;

        // Different icon size on mobile due to size issues
        let mobile = document.body.querySelector('.area-mobile___BH0Ku');
        if (mobile) {
            icon.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
  <circle cx="12" cy="12" r="10" stroke="var(--default-base-navy-color)" stroke-width="2" fill="none" />
  <text x="12" y="13" text-anchor="middle" dominant-baseline="middle" font-size="8" fill="var(--default-base-navy-color)" font-family="Arial, sans-serif">
    LC
  </text>
</svg>`;

            icon.style.marginRight = '6px';
            icon.style.marginTop = '2px';
        }

        let btnContainer = document.body.querySelector('.hf-lazy-crimes-btn-container');
        if (!btnContainer) btnContainer = createButtonContainer(titleBar);

        btnContainer.appendChild(icon);
        disableButtons(nerve);

        return icon;
    }

    // Check the nerve bar to see if nerve is running out and give warning if it is
    function checkNerveBar(retries = 30) {
        let nerveBar = document.body.querySelector('.nerve___AyYv_');

        // If DOM isn't fully loaded, try again
        if (!nerveBar) {
            if (retries > 0) {
                setTimeout(() => checkNerveBar(retries - 1), 100);
            } else {
                console.warn('[HF] Gave up looking for nerve bar after 30 retries.');
            }
            return;
        }

        let barValue = nerveBar.querySelector('.bar-value___NTdce');
        let nerveValue = barValue.childNodes[0];
        nerve = Number(nerveValue.textContent);

        disableButtons(nerve);

        // Keep checking nerve
        createObserver(nerveValue);
    }

    // HELPER function to create a mutation observer and check nerve
    function createObserver(element) {
        let target;
        target = element;

        if (!target) {
            console.error(`[HF] Mutation Observer target not found.`);
            return;
        }

        let observer = new MutationObserver(function(mutationsList, observer) {
            for (let mutation of mutationsList) {
                if (mutation.type === 'characterData') {
                    // Disable buttons if nerve goes down
                    nerve = Number(mutation.target.textContent);
                    disableButtons(nerve);
                }
            }
        });

        let config = { attributes: true, childList: true, subtree: true, characterData: true };
        observer.observe(target, config);
    }

    // HELPER function to disable buttons and give a warning if (running) out of nerve
    function disableButtons(currentNerve) {
        let buttons = document.body.querySelectorAll('.hf-lazy-crimes-button');

        const config = {
            searchforcash: [{ min: 2, message: "You don't have enough nerve" }],
            bootlegging: [
                { min: 2, message: "You don't have enough nerve" },
                { min: 5, message: "You're running out of nerve" },
            ],
            graffiti: [{ min: 3, message: "You don't have enough nerve" }],
            shoplifting: [{ min: 4, message: "You don't have enough nerve" }],
            pickpocketing: [{ min: 5, message: "You don't have enough nerve" }],
            burglary: [
                { min: 2, message: "You don't have enough nerve" },
                { min: 6, message: "You're running out of nerve" },
            ],
            hustling: [
                { min: 2, message: "You don't have enough nerve" },
                { min: 4, message: "You're running out of nerve" },
            ],
            disposal: [
                { min: 6, message: "You don't have enough nerve" },
                { min: 14, message: "You're running out of nerve" },
            ],
            cracking: [{ min: 7, message: "You don't have enough nerve" }],
            forgery: [{ min: 5, message: "You don't have enough nerve" }],
            scamming: [
                { min: 3, message: "You don't have enough nerve" },
                { min: 8, message: "You're running out of nerve" },
            ],
        };

        for (let key in config) {
            if (window.location.href.includes(key)) {
                const requirement = config[key].find(r => currentNerve < r.min);
                const disabled = Boolean(requirement);
                const title = requirement?.message || '';

                for (let button of buttons) {
                    if (button.classList.contains('hf-no-body')) continue;
                    if (button.classList.contains('hf-no-crime-morale')) continue;

                    button.style.background = disabled
                        ? 'var(--default-tabs-disabled-color)'
                    : 'var(--default-blue-dark-color)';
                    button.title = title;

                    // Disable click events if message is "You don't have enough nerve"
                    if (title === "You don't have enough nerve") {
                        if (!button.dataset.eventsDisabled) {
                            // Store existing click handler, if needed
                            button.dataset.eventsDisabled = "true";
                            button.addEventListener('click', preventClick, true);
                        }
                    } else {
                        // Re-enable if previously disabled
                        if (button.dataset.eventsDisabled) {
                            button.removeEventListener('click', preventClick, true);
                            delete button.dataset.eventsDisabled;
                        }
                    }
                }
                break;
            }
        }

        function preventClick(e) {
            e.stopImmediatePropagation();
            e.preventDefault();
        }
    }

    // Add settings button to the crime hub
    function addSettings(retries = 30) {
        let headerElement = document.body.querySelector('.crimes-app-header');
        if (!headerElement) {
            if (retries > 0) {
                setTimeout(() => addSettings(retries - 1), 100);
            } else {
                console.warn('[HF] Gave up looking for the crime hub after 30 retries.');
            }
            return;
        }

        let icon = document.createElement('div');
        icon.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
  <circle cx="12" cy="12" r="10" stroke="var(--default-base-navy-color)" stroke-width="2" fill="none" />
  <text x="12" y="13" text-anchor="middle" dominant-baseline="middle" font-size="8" fill="var(--default-base-navy-color)" font-family="Arial, sans-serif">
    LC
  </text>
</svg>`;
        icon.classList.add('hf-lazy-crimes-icon');
        icon.style.cursor = 'pointer';
        icon.addEventListener('click', function() {
            createModal();
        });

        let link = headerElement.querySelector('.link___bH5rN');

        headerElement.insertBefore(icon, link);

        return;
    }

    // HELPER function to create the SETTINGS modal
    function createModal() {
        let mobile = document.body.querySelector('.area-mobile___BH0Ku');

        let cachedSettings = settings;

        let modal = document.createElement('div');
        modal.style.position = 'fixed';
        modal.style.top = '50%';
        modal.style.left = '50%';
        modal.style.transform = 'translate(-50%, -50%)';
        modal.style.padding = '20px';
        modal.style.backgroundColor = 'var(--sidebar-area-bg-attention)';
        modal.style.border = '2px solid var(--default-tabs-color)';
        modal.style.borderRadius = '15px';
        modal.style.maxWidth = '400px';
        modal.style.zIndex = '9999';
        modal.style.maxHeight = '60vh';
        modal.style.overflow = 'hidden';
        modal.style.display = 'flex';
        modal.style.flexDirection = 'column';
        modal.style.lineHeight = 'normal';

        let titleContainer = document.createElement('div');
        titleContainer.textContent = 'Lazy Crimes Settings';
        titleContainer.style.fontSize = 'x-large';
        titleContainer.style.fontWeight = 'bolder';
        titleContainer.style.paddingBottom = '8px';

        let scrollContainer = document.createElement('div');
        scrollContainer.style.maxHeight = '100%';
        scrollContainer.style.flex = '1'; // Fill remaining space
        scrollContainer.style.overflowY = 'auto';
        scrollContainer.style.marginTop = '10px';

        let mainContainer = document.createElement('div');
        mainContainer.style.display = 'flex';
        mainContainer.style.flexDirection = 'column';
        scrollContainer.appendChild(mainContainer);

        let creditSpan = document.createElement('span');
        creditSpan.innerHTML = `Powered by <a href="https://www.torn.com/profiles.php?XID=2626587" target="_blank" rel="noopener noreferrer" style="color: var(--default-blue-color);">Heartflower [2626587]</a>
        and <a href="https://www.torn.com/profiles.php?XID=2535044" target="_blank" rel="noopener noreferrer" style="color: var(--default-blue-color);">Emforus [2535044]</a>'s guides.
        Requires the <a href="https://www.torn.com/forums.php#/p=threads&f=67&t=16430177&b=0&a=0rh=82&" target="_blank" rel="noopener noreferrer" style="color: var(--default-blue-color);">Crime Morale Script</a>
        by <a href="https://www.torn.com/profiles.php?XID=1617955" target="_blank" rel="noopener noreferrer" style="color: var(--default-blue-color);">tobytorn [1617955]</a> for Scamming to work.
        Requires the <a href="https://www.torn.com/forums.php#/p=threads&f=67&t=16382463&b=0&a=0" target="_blank" rel="noopener noreferrer" style="color: var(--default-blue-color);">Crime Profitability Script</a>
        by <a href="https://www.torn.com/profiles.php?XID=2626587" target="_blank" rel="noopener noreferrer" style="color: var(--default-blue-color);">Heartflower [2626587]</a> for Search For Cash and Cracking to work.`;
        creditSpan.style.paddingBottom = '8px';
        mainContainer.appendChild(creditSpan);

        let checkboxDiv = document.createElement('div');
        checkboxDiv.style.display = 'flex';
        checkboxDiv.style.flexDirection = 'column';
        checkboxDiv.style.paddingTop = '15px';

        let infoSpan = document.createElement('span');
        infoSpan.textContent = 'Enable/disable which crimes you want the Lazy Crimes button and/or merit button(s) to appear for here.';
        checkboxDiv.appendChild(infoSpan);

        let crimes = {
            'Enable All': [],
            'Search For Cash': ['Spoiled Rotten', 'Shore Thing'],
            'Bootlegging': ['Cinephile', 'Online Entrepreneur'],
            'Graffiti': [],
            'Shoplifting': ['Notorious'],
            'Pickpocketing': [],
            'Card Skimming': [],
            'Burglary': ['Key to the City'],
            'Hustling': [],
            'Disposal': ['Dissolving Agent'],
            'Cracking': [],
            'Forgery': [],
            'Scamming': ['Scraper', 'Phisher'],
        }

        for (let crime in crimes) {
            // Create container for the crime
            let crimeContainer = document.createElement('div');
            crimeContainer.style.display = 'flex';

            if (mobile) crimeContainer.style.flexDirection = 'column';

            // Add toggle for the main crime
            addToggle(crimeContainer, crime);

            // If there are subitems, add toggles for each
            if (crimes[crime].length > 0) {
                for (let item of crimes[crime]) {
                    let toggle = addToggle(crimeContainer, item, crimes[crime]);
                    toggle.style.marginLeft = '20px';
                }
            }

            // Append container to the page (adjust target parent as needed)
            checkboxDiv.appendChild(crimeContainer);
        }

        createToggleStyleSheet();

        mainContainer.appendChild(checkboxDiv);

        // Create a container for "Done" and "Cancel" buttons
        let buttonContainer = document.createElement('div');
        buttonContainer.style.display = 'flex';
        buttonContainer.style.justifyContent = 'space-between';
        buttonContainer.style.paddingTop = '15px';

        let cancelButton = document.createElement('button');
        cancelButton.textContent = 'Cancel';
        cancelButton.style.color = 'black';
        cancelButton.style.border = '1px solid black';
        cancelButton.style.borderRadius = '5px';
        cancelButton.style.backgroundColor = '#ccc';
        cancelButton.addEventListener('click', function () {
            settings = cachedSettings;

            localStorage.setItem('hf-lazy-crimes-settings', JSON.stringify(settings));

            modal.style.display = 'none';
        });
        buttonContainer.appendChild(cancelButton);

        // Add style for hover effect
        cancelButton.style.cursor = 'pointer';

        // Add event listeners for hover effect
        cancelButton.addEventListener('mouseover', function () {
            cancelButton.style.fontWeight = 'bold';
        });

        cancelButton.addEventListener('mouseout', function () {
            cancelButton.style.fontWeight = '';
        });

        let doneButton = document.createElement('button');
        doneButton.textContent = 'Done';
        doneButton.style.color = 'black';
        doneButton.style.border = '1px solid black';
        doneButton.style.borderRadius = '5px';
        doneButton.style.backgroundColor = '#ccc';
        doneButton.addEventListener('click', function () {
            location.reload();
            modal.style.display = 'none';
        });
        buttonContainer.appendChild(doneButton);

        // Add style for hover effect
        doneButton.style.cursor = 'pointer';

        // Add event listeners for hover effect
        doneButton.addEventListener('mouseover', function () {
            doneButton.style.fontWeight = 'bold';
        });

        doneButton.addEventListener('mouseout', function () {
            doneButton.style.fontWeight = '';
        });

        modal.appendChild(titleContainer);
        modal.appendChild(scrollContainer);
        modal.appendChild(buttonContainer);

        document.body.appendChild(modal);

        return modal;
    }

    // HELPER function to add the checkbox toggle in the SETTINGS modal
    function addToggle(container, labelText, mainCrime) {
        let toggleContainer = document.createElement('div');
        toggleContainer.classList.add('hf-toggle-container');
        toggleContainer.style.paddingTop = '5px';

        let text = document.createElement('span');
        text.textContent = labelText;
        text.style.paddingLeft = '5px';

        let label = document.createElement('label');
        label.classList.add('switch');

        let input = document.createElement('input');
        input.type = 'checkbox';
        input.classList.add('hf-checkbox');

        input.checked = true; // Check on by default

        let span = document.createElement('span');
        span.classList.add('slider', 'round');

        let savedInfo = settings[labelText];

        if (savedInfo === true) input.checked = true;
        if (savedInfo === false) input.checked = false;

        if (labelText === 'Enable All') input.checked = false;

        settings[labelText] = input.checked;
        localStorage.setItem('hf-lazy-crimes-settings', JSON.stringify(settings));

        toggleContainer.appendChild(label);
        toggleContainer.appendChild(text);
        label.appendChild(input);
        label.appendChild(span);
        container.appendChild(toggleContainer);

        // Add event listener to detect changes in the checkbox state
        input.addEventListener('change', function() {
            if (input.checked) {
                if (labelText === 'Enable All') {
                    let inputs = document.body.querySelectorAll('.hf-checkbox');
                    for (let input of inputs) {
                        input.checked = true;
                        let event = new Event('change', { bubbles: true });
                        input.dispatchEvent(event);
                    }

                    text.textContent = 'Disable All';
                    return;
                }

                if (mainCrime) {
                    let input = container.querySelector('.hf-checkbox');
                    input.checked = true;
                    let event = new Event('change', { bubbles: true });
                    input.dispatchEvent(event);
                }

                settings[labelText] = true;
                localStorage.setItem('hf-lazy-crimes-settings', JSON.stringify(settings));
            } else {
                if (labelText === 'Enable All' || labelText === 'Disable All') {
                    let inputs = document.body.querySelectorAll('.hf-checkbox');
                    for (let input of inputs) {
                        input.checked = false;
                        let event = new Event('change', { bubbles: true });
                        input.dispatchEvent(event);
                    }

                    text.textContent = 'Enable All';
                    return;
                }

                settings[labelText] = false;
                localStorage.setItem('hf-lazy-crimes-settings', JSON.stringify(settings));
            }
        });

        return toggleContainer;
    }

    // HELPER FUNCTION to create a style sheet to make the fancier toggles work
    function createToggleStyleSheet() {
        let styles = `
        .switch {
          position: relative;
          display: inline-block;
          width: 20px;
          height: 10px;
          top: 1px;
        }
        .switch input {
          opacity: 0;
          width: 0;
          height: 0;
        }
        .slider {
          position: absolute;
          cursor: pointer;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
          background-color: #ccc;
          transition: .4s;
        }
        .slider:before {
          position: absolute;
          content: "";
          height: 10px;
          width: 10px;
          background-color: white;
          transition: .4s;
        }
        input:checked + .slider {
          background-color: #2196F3;
        }
        input:focus + .slider {
          box-shadow: 0 0 1px #2196F3;
        }
        input:checked + .slider:before {
          transform: translateX(10px);
        }
        .slider.round {
          border-radius: 34px;
        }
        .slider.round:before {
          border-radius: 50%;
        }
        `;

        // Add the styles to a <style> tag in the document head
        let styleSheet = document.createElement("style");
        styleSheet.type = "text/css";
        styleSheet.innerText = styles;
        document.head.appendChild(styleSheet);
    }


    // Check if there's a page chance - if yes, rerun script
    function handlePageChange() {
        if (window.location.href === currentHref) return;

        let existingButton = document.body.querySelector('.hf-lazy-crimes-icon');
        if (existingButton) existingButton.remove();

        findHref();

        currentHref = window.location.href;
    }

    // run if button click
    function handleButtonClick(event) {
        setTimeout(() => {
            handlePageChange();
        }, 500);
    }

    function findHref() {
        checkNerveBar();

        let href = window.location.href;
        currentHref = href;

        let crimes = ['Search for Cash', 'Spoiled Rotten', 'Shore Thing', 'Bootlegging', 'Cinephile', 'Online Entrepreneur',
                      'Graffiti', 'Shoplifting', 'Notorious', 'Pickpocketing', 'Card Skimming', 'Burglary', 'Key to the City',
                      'Hustling', 'Disposal', 'Dissolving Agent', 'Cracking', 'Forgery', 'Scamming', 'Scraper', 'Phisher'];


        if (!settings || Object.keys(settings).length === 0) {
            settings = {};

            for (let crime of crimes) {
                settings[crime] = true;
            }
        }

        if (href.includes('searchforcash')) {
            if (settings['Search For Cash']) {
                crimePage();
                searchForCashMerits(); // merits - trash & sand
                if (settings['Spoiled Rotten'] && settings['Shore Thing']) {
                    addInfoButton(`The spam button chooses the highest percentage crime.<br><b>Shore Thing</b> looks for sand at the beach.<br><b>Spoiled Rotten</b> looks for rotten food in the trash.`);
                } else if (settings['Spoiled Rotten']) {
                    addInfoButton(`The spam button chooses the highest percentage crime.<br><b>Spoiled Rotten</b> looks for rotten food in the trash.`);
                } else if (settings['Shore Thing']) {
                    addInfoButton(`The spam button chooses the highest percentage crime.<br><b>Shore Thing</b> looks for sand at the beach.`);
                } else {
                    addInfoButton(`The spam button chooses the highest percentage crime.`);
                }
            }
        } else if (href.includes('bootlegging')) {
            if (settings.Bootlegging) {
                bootlegging();
                if (settings.Cinephile && settings['Online Entrepreneur']) {
                    addInfoButton(`The spam button copies DVDs per Emforus [2535044]'s ratio and once enough DVDs are copied, sells them.*<br><b>Cinephile</b> copies DVDs for any crime not yet at 10,000 DVDs.*
                <br>Online Entrepreneur</b> sets up an online shop and turns it on in order to work on the customers needed for this merit.<br>*Please note that this does not keep in mind the currently queued DVDs.`);
                } else if (settings.Cinephile) {
                    addInfoButton(`The spam button copies DVDs per Emforus [2535044]'s ratio and once enough DVDs are copied, sells them.*<br><b>Cinephile</b> copies DVDs for any crime not yet at 10,000 DVDs.*
                <br>*Please note that this does not keep in mind the currently queued DVDs.`);
                } else if (settings['Online Entrepreneur']) {
                    addInfoButton(`The spam button copies DVDs per Emforus [2535044]'s ratio and once enough DVDs are copied, sells them.*
                <br>Online Entrepreneur</b> sets up an online shop and turns it on in order to work on the customers needed for this merit.<br>*Please note that this does not keep in mind the currently queued DVDs.`);
                } else {
                    addInfoButton(`The spam button copies DVDs per Emforus [2535044]'s ratio and once enough DVDs are copied, sells them.*
                <br>*Please note that this does not keep in mind the currently queued DVDs.`);
                }
            }
        } else if (href.includes('graffiti')) {
            if (settings.Graffiti) {
                graffiti();
                addInfoButton(`The spam button brings each district to 500 first before moving to the next and thus should also work if you aim for both merits.`);
            }
        } else if (href.includes('shoplifting')) {
            if (settings.Shoplifting) {
                crimePage();
                if (settings.Notorious) {
                    addInfoButton(`The spam button redirects to:<br>(1) Any disabled securities with < 80 notoriety<br>(2) Sweet Shop or Bits 'n' Bobs with < 80 notoriety<br>(3) Sweet Shop<br><br>
                For the <b>Notorious</b> merit please have a LOT of nerve on standby.`);
                } else {
                    addInfoButton(`The spam button redirects to:<br>(1) Any disabled securities with < 80 notoriety<br>(2) Sweet Shop or Bits 'n' Bobs with < 80 notoriety<br>(3) Sweet Shop`);
                }
            }
        } else if (href.includes('pickpocketing')) {
            if (settings.Pickpocketing) {
                crimePage();
                addInfoButton(`The spam button redirects to the earliest safe target based on Emforus [2535044]'s guide.<br><br>
            For the <b>Pig Rustler</b> merit, just wait for a running cop to appear and try pickpocketing him. Be aware this might lose you a lot of CS in a lot of tries.`);
            }
        } else if (href.includes ('cardskimming')) {
            if (settings['Card Skimming']) addInfoButton(`Just take a moment to spam Bus Stations, forget about it for a month, then spam collect.`);
        } else if (href.includes('burglary')) {
            if (settings.Burglary) {
                burglary();
                if (settings['Key to the City']) {
                    addInfoButton(`The spam button scouts any residential, then cases it to about 80% and then collects it.<br><br><b>Key to the City</b> spawns, cases and burgles whichever target you've not burgled yet.`);
                } else {
                    addInfoButton(`The spam button scouts any residential, then cases it to about 80% and then collects it.`);
                }
            }
        } else if (href.includes('hustling')) {
            if (settings.Hustling) {
                crimePage();
                addInfoButton(`The spam button gathers 1 audience and keeps spamming lose until nerve is empty. It works on whichever technique you haven't completed yet, so should technically work for the <b>Tekkers</b> merit.
                <span style="color:var(--default-base-important-color)"> PLEASE NOTE THIS WILL MAKE YOU LOSE MONEY! Remember to keep enough money on hand at all times!</span>`);
            }
        } else if (href.includes('disposal')) {
            if (settings.Disposal) {
                disposal();
                if (settings['Dissolving Agent']) {
                    addInfoButton(`The spam button selects the proposed method for the first available crime as per Emforus [2535044]'s guide and then finishes the crime. <span style="color:var(--default-base-important-color)">You need to make sure you have the required item available in order for the crime to be possible.</span><br><br>
            <b>Dissolving Agent</b> attempts to dissolve a dead body in acid when available (and visible on the page!)`);
                } else {
                    addInfoButton(`The spam button selects the proposed method for the first available crime as per Emforus [2535044]'s guide and then finishes the crime.`);
                }
            }
        } else if (href.includes('cracking')) {
            if (settings.Cracking) {
                crimePage();
                addInfoButton(`The spam button chooses:<br>(1) Any finished crackings<br>(2) The cracking with the lowest amount of characters<br><br>The <b>Character Assassination</b> merit is simply not possible by spamming, sorry!`);
            }
        } else if (href.includes('forgery')) {
            if (settings.Forgery) {
                crimePage();
                addInfoButton(`The spam button spams parking permits.<span style="color:var(--default-base-important-color)"> Please make sure you have enough Cardstock and Adhesive Plastic in your inventory.</span>
            You should be able to get the <b>Assembly Line</b> merit by simply spamming enough crimes at once.`);
            }
        } else if (href.includes('scamming')) {
            if (settings.Scamming) {
                crimePage();
                addInfoButton(`The spam button:<br>(1) Farms e-mails up to 20k<br>(2) Launches spam waves if no available targets<br>(3) Finishes targets based on tobytorn [1617955]'s Crime Morale Script info.<br><br>
                Merits should be doable with the Crime Morale script as well.<br><br><span style="color:var(--default-base-important-color)">Be sure to disable scraper/phisher if you haven't done the educations yet.</span>`);
            }
        } else {
            addSettings();
        }
    }

    if (!window.lazyCrimesInjected) {
        window.lazyCrimesInjected = true;

        findHref();

        // Checking arrows and document click handler only work like half of the time, so interval
        setInterval(handlePageChange, 200);

        // Attach click event listener
        document.body.addEventListener('click', handleButtonClick);
    }


})();